Add files using upload-large-folder tool
Browse files- .python_history +18 -0
- llm-awq/awq.egg-info/PKG-INFO +319 -0
- llm-awq/awq.egg-info/SOURCES.txt +81 -0
- llm-awq/awq.egg-info/dependency_links.txt +1 -0
- llm-awq/awq.egg-info/requires.txt +16 -0
- llm-awq/awq/kernels/csrc/w8a8/reduction_utils.cuh +170 -0
- llm-awq/awq/quantize/__pycache__/__init__.cpython-311.pyc +0 -0
- llm-awq/awq/utils/calib_data.py +32 -0
- llm-awq/examples/README.md +10 -0
- llm-awq/examples/chat_demo.ipynb +272 -0
- llm-awq/examples/convert_to_hf.py +69 -0
- llm-awq/examples/llava_demo.ipynb +0 -0
- llm-awq/figures/vila-logo.jpg +0 -0
- llm-awq/scripts/DeepSeek_R1_Distill_example.sh +25 -0
- llm-awq/scripts/llama_example.sh +25 -0
- llm-awq/scripts/llava_example.sh +12 -0
- llm-awq/scripts/nvila_example.sh +12 -0
- llm-awq/scripts/opt_example.sh +25 -0
- llm-awq/scripts/qwen_example.sh +25 -0
- llm-awq/scripts/starcoder_example.sh +25 -0
- llm-awq/scripts/vicuna_example.sh +25 -0
- llm-awq/scripts/vila15_example.sh +14 -0
- llm-awq/scripts/vila_example.sh +12 -0
- llm-awq/tinychat/README.md +526 -0
- llm-awq/tinychat/benchmark.py +379 -0
- llm-awq/tinychat/demo.py +283 -0
- llm-awq/tinychat/internvl_benchmark.py +167 -0
- llm-awq/tinychat/internvl_demo.py +270 -0
- llm-awq/tinychat/models/__init__.py +10 -0
- llm-awq/tinychat/models/internvl/configuration_internvl.py +204 -0
- llm-awq/tinychat/models/internvl/conversation.py +391 -0
- llm-awq/tinychat/models/internvl/internvit.py +425 -0
- llm-awq/tinychat/models/internvl/media.py +113 -0
- llm-awq/tinychat/models/llama.py +413 -0
- llm-awq/tinychat/models/llava_base/llava_arch.py +412 -0
- llm-awq/tinychat/models/llava_base/multimodal_encoder/builder.py +21 -0
- llm-awq/tinychat/models/llava_base/multimodal_encoder/clip_encoder.py +97 -0
- llm-awq/tinychat/models/llava_base/multimodal_projector/builder.py +72 -0
- llm-awq/tinychat/models/llava_llama.py +282 -0
- llm-awq/tinychat/models/mpt.py +304 -0
- llm-awq/tinychat/models/nvila/configuration_llava.py +89 -0
- llm-awq/tinychat/models/nvila_qwen2.py +157 -0
- llm-awq/tinychat/modules/__init__.py +9 -0
- llm-awq/tinychat/modules/fused_mlp.py +101 -0
- llm-awq/tinychat/nvila_benchmark.py +163 -0
- llm-awq/tinychat/nvila_demo.py +272 -0
- llm-awq/tinychat/offline-weight-repacker.py +157 -0
- llm-awq/tinychat/scripts/llama2_demo.sh +31 -0
- llm-awq/tinychat/split_ckpt.py +51 -0
- llm-awq/tinychat/vila15_demo.py +264 -0
.python_history
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
a=[4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2]
|
| 2 |
+
len(a)
|
| 3 |
+
a= " 1 "
|
| 4 |
+
int(a)
|
| 5 |
+
b=int(a)
|
| 6 |
+
b
|
| 7 |
+
type(b)
|
| 8 |
+
type(b)
|
| 9 |
+
type(b)
|
| 10 |
+
b
|
| 11 |
+
3584*3584*2+3584+51282
|
| 12 |
+
3584*18944*3
|
| 13 |
+
203685888/25744978
|
| 14 |
+
4096*4096*2+ 4096*1024*2
|
| 15 |
+
4096*14336*3
|
| 16 |
+
176160768/41943040
|
| 17 |
+
a=[29, 23, 24, 30, 18, 28, 26, 20, 16, 27, 25, 17, 19, 21]
|
| 18 |
+
len(a)
|
llm-awq/awq.egg-info/PKG-INFO
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.4
|
| 2 |
+
Name: awq
|
| 3 |
+
Version: 0.1.0
|
| 4 |
+
Summary: An efficient and accurate low-bit weight quantization(INT3/4) method for LLMs.
|
| 5 |
+
Classifier: Programming Language :: Python :: 3
|
| 6 |
+
Classifier: License :: OSI Approved :: Apache Software License
|
| 7 |
+
Requires-Python: >=3.8
|
| 8 |
+
Description-Content-Type: text/markdown
|
| 9 |
+
License-File: LICENSE
|
| 10 |
+
Requires-Dist: accelerate==0.34.2
|
| 11 |
+
Requires-Dist: sentencepiece
|
| 12 |
+
Requires-Dist: tokenizers>=0.12.1
|
| 13 |
+
Requires-Dist: torch==2.3.0
|
| 14 |
+
Requires-Dist: torchvision==0.18.0
|
| 15 |
+
Requires-Dist: transformers==4.46.0
|
| 16 |
+
Requires-Dist: lm_eval==0.3.0
|
| 17 |
+
Requires-Dist: texttable
|
| 18 |
+
Requires-Dist: toml
|
| 19 |
+
Requires-Dist: attributedict
|
| 20 |
+
Requires-Dist: protobuf
|
| 21 |
+
Requires-Dist: gradio==3.35.2
|
| 22 |
+
Requires-Dist: gradio_client==0.2.9
|
| 23 |
+
Requires-Dist: fastapi
|
| 24 |
+
Requires-Dist: uvicorn
|
| 25 |
+
Requires-Dist: pydantic==1.10.19
|
| 26 |
+
Dynamic: license-file
|
| 27 |
+
|
| 28 |
+
# AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration
|
| 29 |
+
[[Paper](https://arxiv.org/abs/2306.00978)][[Website](https://hanlab.mit.edu/projects/awq)]
|
| 30 |
+
|
| 31 |
+
**Efficient and accurate** low-bit weight quantization (INT3/4) for LLMs, supporting **instruction-tuned** models and **multi-modal** LMs.
|
| 32 |
+
|
| 33 |
+

|
| 34 |
+
|
| 35 |
+
The current release supports:
|
| 36 |
+
|
| 37 |
+
- AWQ search for accurate quantization.
|
| 38 |
+
- Pre-computed AWQ model zoo for LLMs (Llama-1/2/3, OPT, CodeLlama, StarCoder, Vicuna, VILA, LLaVA; load to generate quantized weights).
|
| 39 |
+
- Memory-efficient 4-bit Linear in PyTorch.
|
| 40 |
+
- Efficient CUDA kernel implementation for fast inference (support context and decoding stage).
|
| 41 |
+
- Examples on 4-bit inference of an instruction-tuned model (Vicuna) and **multi-modal LM** (VILA).
|
| 42 |
+
- Chunk prefilling for faster prefilling in multi-round Q&A setting.
|
| 43 |
+
- State-of-the-art prefilling speed of LLMs/VLMs on edge devices: [TinyChat 2.0](./tinychat).
|
| 44 |
+
|
| 45 |
+
**Thanks to AWQ, TinyChat can deliver more efficient responses with LLM/VLM chatbots through 4-bit inference.**
|
| 46 |
+
|
| 47 |
+
* TinyChat with LLaMA-3-8b on RTX 4090 (2.7x faster than FP16):
|
| 48 |
+
|
| 49 |
+

|
| 50 |
+
|
| 51 |
+
* TinyChat with LLaMA-3-8b on Jetson Orin (2.9x faster than FP16):
|
| 52 |
+
|
| 53 |
+

|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
**TinyChat also supports inference with vision language models (e.g., VILA, LLaVA). In the following examples, W4A16 quantized models from VILA family are launched with TinyChat.**
|
| 57 |
+
|
| 58 |
+
* TinyChat with NVILA-8B on RTX 4090 (single-image inputs):
|
| 59 |
+
|
| 60 |
+

|
| 61 |
+
|
| 62 |
+
* TinyChat with NVILA-8B on RTX 4090 (multi-image inputs):
|
| 63 |
+
|
| 64 |
+

|
| 65 |
+
|
| 66 |
+
<!-- Check out [TinyChat](tinychat), which delievers **30 tokens/second** inference performance (**3.2x faster** than FP16) for the **Llama2** chatbot on the resource-constrained NVIDIA Jetson Orin! -->
|
| 67 |
+
|
| 68 |
+
* TinyChat with video reasoning:
|
| 69 |
+
|
| 70 |
+
https://github.com/user-attachments/assets/b68a7a0d-5175-4030-985b-5ae0ae94f874
|
| 71 |
+
|
| 72 |
+
**Prompt:** What might be the next step according to the video?
|
| 73 |
+
|
| 74 |
+
**Answer:** The next step in the video could be to place the shaped dough onto a baking sheet and let it rise before baking.
|
| 75 |
+
|
| 76 |
+
**Online demo:** https://vila.hanlab.ai
|
| 77 |
+
|
| 78 |
+
Check out [TinyChat](tinychat), which offers a turn-key solution for **on-device inference** of LLMs and VLMs on **resource-constrained edge platforms**. With TinyChat, it is now possible to efficiently run **large** models on **small** and **low-power** devices even without Internet connection!
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
## News
|
| 82 |
+
- [2025/04] 🔥 AWQ now supports DeepSeek-R1-Distilled models. Try our example [here](https://github.com/mit-han-lab/llm-awq/blob/main/scripts/DeepSeek_R1_Distill_example.sh)!
|
| 83 |
+
- [2025/02] AWQ now supports BF16 precision. See example [here](https://github.com/mit-han-lab/llm-awq/blob/main/scripts/qwen_example.sh).
|
| 84 |
+
- [2024/10] 🔥⚡ Explore advancements in [TinyChat 2.0](./tinychat), the latest version with significant advancements in prefilling speed of Edge LLMs and VLMs, **1.5-1.7x** faster than the previous version of TinyChat. Please refer to the [README](./tinychat/README.md) and [blog](https://hanlab.mit.edu/blog/tinychat20) for more details.
|
| 85 |
+
- [2024/05] 🏆 AWQ receives the **Best Paper Award** at **MLSys 2024**. 🎉
|
| 86 |
+
- [2024/05] 🔥 The **VILA-1.5** model family which features **video understanding** is now supported in AWQ and TinyChat. Check out out online demo powered by TinyChat [here](https://vila.hanlab.ai). Example is [here](scripts/vila15_example.sh).
|
| 87 |
+
- [2024/05] 🔥 [AMD](https://community.amd.com/t5/ai/reduce-memory-footprint-and-improve-performance-running-llms-on/ba-p/686157) adopts AWQ to improve LLM serving efficiency.
|
| 88 |
+
- [2024/04] 🔥 We released AWQ and TinyChat support for The **Llama-3** model family! Check out our example [here](scripts/llama3_example.sh).
|
| 89 |
+
- [2024/02] 🔥 AWQ has been accepted to **MLSys 2024**!
|
| 90 |
+
- [2024/02] 🔥 We supported [VILA Vision Languague Models](https://arxiv.org/abs/2312.07533) in AWQ & TinyChat! Check our latest demos with multi-image inputs!
|
| 91 |
+
- [2024/02] 🔥 We released new version of quantized GEMM/GEMV kernels in [**TinyChat**](tinychat), leading to **38 tokens/second** inference speed on NVIDIA Jetson Orin!
|
| 92 |
+
- [2024/01] 🔥 AWQ has been integrated by [Google Vertex AI](https://console.cloud.google.com/vertex-ai/publishers/meta/model-garden/llama-2-quantized)!
|
| 93 |
+
- [2023/11] 🔥 AWQ has been integrated by [Amazon Sagemaker Containers](https://aws.amazon.com/blogs/machine-learning/boost-inference-performance-for-llms-with-new-amazon-sagemaker-containers/)!
|
| 94 |
+
- [2023/11] 🔥 We added AWQ support and pre-computed search results for CodeLlama, StarCoder, StableCode models. Checkout our model zoo [here](https://huggingface.co/datasets/mit-han-lab/awq-model-zoo)!
|
| 95 |
+
- [2023/11] 🔥 AWQ is now integrated natively in Hugging Face transformers through `from_pretrained`. You can either load quantized models from the Hub or your own HF quantized models.
|
| 96 |
+
- [2023/10] AWQ is integrated into NVIDIA [TensorRT-LLM](https://github.com/NVIDIA/TensorRT-LLM/)
|
| 97 |
+
- [2023/09] AWQ is integrated into [Intel Neural Compressor](https://github.com/intel/neural-compressor), [FastChat](https://github.com/lm-sys/FastChat/blob/main/docs/awq.md), [vLLM](https://github.com/vllm-project/vllm/blob/main/vllm/model_executor/layers/quantization/awq.py), [HuggingFace TGI](https://github.com/huggingface/text-generation-inference/pull/1054), and [LMDeploy](https://github.com/InternLM/lmdeploy).
|
| 98 |
+
- [2023/09] ⚡ Check out our latest [**TinyChat**](tinychat), which is ~2x faster than the first release on Orin!
|
| 99 |
+
- [2023/09] ⚡ Check out [**AutoAWQ**](https://github.com/casper-hansen/AutoAWQ), a third-party implementation to make AWQ easier to expand to new models, improve inference speed, and integrate into Huggingface.
|
| 100 |
+
- [2023/07] 🔥 We released **TinyChat**, an efficient and lightweight chatbot interface based on AWQ. TinyChat enables efficient LLM inference on both cloud and edge GPUs. Llama-2-chat models are supported! Check out our implementation [here](tinychat).
|
| 101 |
+
- [2023/07] 🔥 We added AWQ support and pre-computed search results for Llama-2 models (7B & 13B). Checkout our model zoo [here](https://huggingface.co/datasets/mit-han-lab/awq-model-zoo)!
|
| 102 |
+
- [2023/07] We extended the support for more LLM models including MPT, Falcon, and BLOOM.
|
| 103 |
+
|
| 104 |
+
## Contents
|
| 105 |
+
|
| 106 |
+
- [AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration](#awq-activation-aware-weight-quantization-for-llm-compression-and-acceleration)
|
| 107 |
+
- [News](#news)
|
| 108 |
+
- [Contents](#contents)
|
| 109 |
+
- [Helpful Links](#helpful-links)
|
| 110 |
+
- [Install](#install)
|
| 111 |
+
- [AWQ Model Zoo](#awq-model-zoo)
|
| 112 |
+
- [Examples](#examples)
|
| 113 |
+
- [Usage](#usage)
|
| 114 |
+
- [Results on Visual Language Models](#results-on-visual-language-models)
|
| 115 |
+
- [Reference](#reference)
|
| 116 |
+
- [Related Projects](#related-projects)
|
| 117 |
+
|
| 118 |
+
## Helpful Links
|
| 119 |
+
|
| 120 |
+
- [VILA online demo](vila.hanlab.ai): Visual Language Models efficiently supported by AWQ & TinyChat.
|
| 121 |
+
- [LLM on the Edge](https://github.com/mit-han-lab/llm-awq/tree/nv_laptop?tab=readme-ov-file#install): AWQ and TinyChat support edge GPUs such as NVIDIA Jetson Orin.
|
| 122 |
+
- [VLMs on Laptop](https://github.com/mit-han-lab/llm-awq/tree/nv_laptop?tab=readme-ov-file#run-vila-on-laptop): Follow the instructions to deploy VLMs on NVIDIA Laptops with TinyChat.
|
| 123 |
+
- [Gradio Server](https://github.com/mit-han-lab/llm-awq/tree/nv_laptop/tinychat/serve#gradio-demo-vila-with-tinychat): Try to build your own VLM online demo with AWQ and TinyChat!
|
| 124 |
+
- [QServe](https://github.com/mit-han-lab/qserve): 🔥 **[New]** Efficient and accurate serving system for large-scale LLM inference.
|
| 125 |
+
|
| 126 |
+
## Install
|
| 127 |
+
|
| 128 |
+
1. Clone this repository and navigate to AWQ folder
|
| 129 |
+
```
|
| 130 |
+
git clone https://github.com/mit-han-lab/llm-awq
|
| 131 |
+
cd llm-awq
|
| 132 |
+
```
|
| 133 |
+
|
| 134 |
+
2. Install Package
|
| 135 |
+
```
|
| 136 |
+
conda create -n awq python=3.10 -y
|
| 137 |
+
conda activate awq
|
| 138 |
+
pip install --upgrade pip # enable PEP 660 support
|
| 139 |
+
pip install -e .
|
| 140 |
+
```
|
| 141 |
+
|
| 142 |
+
* For **edge devices** like Orin, before running the commands above, please:
|
| 143 |
+
|
| 144 |
+
1. Modify [pyproject.toml](pyproject.toml) by commenting out [this line](https://github.com/mit-han-lab/llm-awq/blob/3fce69061682fdd528824e5da3d03a8a8b545f2a/pyproject.toml#L17).
|
| 145 |
+
2. Manually install precompiled PyTorch binaries (>=2.0.0) from [NVIDIA](https://forums.developer.nvidia.com/t/pytorch-for-jetson/72048). You also need to install torchvision from this website when running NVILA.
|
| 146 |
+
3. Set the appropriate Python version for conda environment (e.g., `conda create -n awq python=3.8 -y` for JetPack 5).
|
| 147 |
+
|
| 148 |
+
3. Install efficient W4A16 (4-bit weight, 16-bit activation) CUDA kernel and optimized FP16 kernels (e.g. layernorm, positional encodings).
|
| 149 |
+
```
|
| 150 |
+
cd awq/kernels
|
| 151 |
+
python setup.py install
|
| 152 |
+
```
|
| 153 |
+
|
| 154 |
+
4. Install Flash Attention
|
| 155 |
+
```
|
| 156 |
+
pip install flash-attn --no-build-isolation
|
| 157 |
+
```
|
| 158 |
+
|
| 159 |
+
We recommend starting an interactive python CLI interface and run `import flash_attn` to check whether FlashAttention-2 is installed successfully. If not, we recommend downloading pre-built wheels from [here](https://github.com/Dao-AILab/flash-attention/releases/tag/v2.5.8). Please notice:
|
| 160 |
+
|
| 161 |
+
- PyTorch version needs to exactly match with the version specified in the `.whl` name;
|
| 162 |
+
- Check out both `cxx11abiTRUE` and `cxx11abiFALSE` wheels if one of them does not work;
|
| 163 |
+
- It's recommended to match CUDA version specified in the `.whl` filename, but minor mismatches (e.g. 12.1 vs 12.2, or even 11.8 vs 12.2) usually do not matter.
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
5. [Optional] In order to run AWQ and TinyChat with NVILA model family, please install VILA:
|
| 167 |
+
|
| 168 |
+
```bash
|
| 169 |
+
git clone https://github.com/NVlabs/VILA.git
|
| 170 |
+
cd VILA
|
| 171 |
+
pip install -e .
|
| 172 |
+
```
|
| 173 |
+
|
| 174 |
+
## AWQ Model Zoo
|
| 175 |
+
|
| 176 |
+
We provide pre-computed AWQ search results for multiple model families, including LLaMA, OPT, Vicuna, and LLaVA. To get the pre-computed AWQ search results, run:
|
| 177 |
+
|
| 178 |
+
```bash
|
| 179 |
+
# git lfs install # install git lfs if not already
|
| 180 |
+
git clone https://huggingface.co/datasets/mit-han-lab/awq-model-zoo awq_cache
|
| 181 |
+
```
|
| 182 |
+
|
| 183 |
+
The detailed support list:
|
| 184 |
+
|
| 185 |
+
| Models | Sizes | INT4-g128 | INT3-g128 |
|
| 186 |
+
| ------ | --------------------------- | --------- | --------- |
|
| 187 |
+
| [DeepSeek-R1-Distill](/scripts/DeepSeek_R1_Distill_example.sh) | 1.5B/7B/8B | ✅ | |
|
| 188 |
+
| [Qwen-2.5](/scripts/qwen_example.sh) | 7B/72B | ✅ | |
|
| 189 |
+
| [NVILA](/scripts/nvila_example.sh) | 3B/8B | ✅ | |
|
| 190 |
+
| [VILA-1.5](/scripts/vila15_example.sh) | 3B/8B/13B/40B | ✅ | ✅ |
|
| 191 |
+
| [Llama3](/scripts/llama_example.sh) | 8B/70B | ✅ | ✅ |
|
| 192 |
+
| [VILA](/scripts/vila_example.sh) | 7B/13B | ✅ | |
|
| 193 |
+
| [Llama2](/scripts/llama_example.sh) | 7B/13B/70B | ✅ | ✅ |
|
| 194 |
+
| [LLaMA](/scripts/llama2_example.sh) | 7B/13B/30B/65B | ✅ | ✅ |
|
| 195 |
+
| [OPT](/scripts/opt_example.sh) | 125m/1.3B/2.7B/6.7B/13B/30B | ✅ | ✅ |
|
| 196 |
+
| [CodeLlama](/scripts/codellama_example.sh) | 7B/13B/34B | ✅ | ✅ |
|
| 197 |
+
| [StarCoder](/scripts/starcoder_example.sh) | 15.5B | ✅ | ✅ |
|
| 198 |
+
| [Vicuna-v1.1](/scripts/vicuna_example.sh) | 7B/13B | ✅ | |
|
| 199 |
+
| [LLaVA-v0](/scripts/llava_example.sh) | 13B | ✅ | |
|
| 200 |
+
|
| 201 |
+
Note: We only list models that we have prepare the [AWQ searching results](https://huggingface.co/datasets/mit-han-lab/awq-model-zoo/tree/main) in the table above. AWQ also supports models such as LLaVA-v1.5 7B, and you may need to run the [AWQ search](#usage) on your own to quantize these models. For our latest VLM NVILA, quantized weights are available [here](https://huggingface.co/Efficient-Large-Model/NVILA-AWQ).
|
| 202 |
+
|
| 203 |
+
## Examples
|
| 204 |
+
|
| 205 |
+
AWQ can be easily applied to various LMs thanks to its good generalization, including instruction-tuned models and multi-modal LMs. It provides an easy-to-use tool to reduce the serving cost of LLMs.
|
| 206 |
+
|
| 207 |
+
Here we provide two examples of AWQ application: Vicuna-7B (chatbot) and LLaVA-13B (visual reasoning) under `./examples` directory. AWQ can easily reduce the GPU memory of model serving and speed up token generation. It provides accurate quantization, providing reasoning outputs. You should be able to observe **memory savings** when running the models with 4-bit weights.
|
| 208 |
+
|
| 209 |
+
Note that we perform AWQ using only textual calibration data, depsite we are running on multi-modal input. Please refer to `./examples` for details.
|
| 210 |
+
|
| 211 |
+

|
| 212 |
+
|
| 213 |
+
## Usage
|
| 214 |
+
|
| 215 |
+
We provide several sample script to run AWQ (please refer to `./scripts`). We use Llama3-8B as an example.
|
| 216 |
+
|
| 217 |
+
1. Perform AWQ search and save search results (we already did it for you):
|
| 218 |
+
```bash
|
| 219 |
+
python -m awq.entry --model_path /PATH/TO/LLAMA3/llama3-8b \
|
| 220 |
+
--w_bit 4 --q_group_size 128 \
|
| 221 |
+
--run_awq --dump_awq awq_cache/llama3-8b-w4-g128.pt
|
| 222 |
+
```
|
| 223 |
+
|
| 224 |
+
2. Evaluate the AWQ quantized model on WikiText-2 (simulated pseudo quantization)
|
| 225 |
+
```bash
|
| 226 |
+
python -m awq.entry --model_path /PATH/TO/LLAMA3/llama3-8b \
|
| 227 |
+
--tasks wikitext \
|
| 228 |
+
--w_bit 4 --q_group_size 128 \
|
| 229 |
+
--load_awq awq_cache/llama3-8b-w4-g128.pt \
|
| 230 |
+
--q_backend fake
|
| 231 |
+
```
|
| 232 |
+
|
| 233 |
+
3. Generate real quantized weights (INT4)
|
| 234 |
+
```bash
|
| 235 |
+
mkdir quant_cache
|
| 236 |
+
python -m awq.entry --model_path /PATH/TO/LLAMA3/llama3-8b \
|
| 237 |
+
--w_bit 4 --q_group_size 128 \
|
| 238 |
+
--load_awq awq_cache/llama3-8b-w4-g128.pt \
|
| 239 |
+
--q_backend real --dump_quant quant_cache/llama3-8b-w4-g128-awq.pt
|
| 240 |
+
```
|
| 241 |
+
|
| 242 |
+
4. Load and evaluate the real quantized model (now you can see smaller gpu memory usage)
|
| 243 |
+
```bash
|
| 244 |
+
python -m awq.entry --model_path /PATH/TO/LLAMA3/llama3-8b \
|
| 245 |
+
--tasks wikitext \
|
| 246 |
+
--w_bit 4 --q_group_size 128 \
|
| 247 |
+
--load_quant quant_cache/llama3-8b-w4-g128-awq.pt
|
| 248 |
+
```
|
| 249 |
+
## Results on Visual Language Models
|
| 250 |
+
|
| 251 |
+
AWQ also seamlessly supports large multi-modal models (LMMs). Please refer to [TinyChat](./tinychat/README.md) for more details.
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
<!-- AWQ also seamlessly supports large multi-modal models (LMMs). We demonstrate the results on the recent [VILA-1.5](https://github.com/Efficient-Large-Model/VILA) model family. -->
|
| 255 |
+
|
| 256 |
+
<!--
|
| 257 |
+
| VILA-1.5-3B | VQA-v2 | GQA | VizWiz | ScienceQA | TextVQA | POPE | MME | MMBench | MMBench-CN | SEED |
|
| 258 |
+
| ----------- |:-----------------:|:-----------------:|:-------:|:-----------------:|:-----------------:|:-------:|:-------:|:-----------------:|:-------------:|:-------:|
|
| 259 |
+
| FP16 | 80.4 | 61.5 | 53.5 | 69.0 | 60.4 | 85.9 | 1442.4 | 63.4 | 52.7 | 60.9 |
|
| 260 |
+
| AWQ-INT4 | 80.0 | 61.1 | 53.8 | 67.8 | 60.4 | 85.9 | 1437.3 | 63.3 | 51.4 | 59.8 |
|
| 261 |
+
|
| 262 |
+
| VILA-1.5-8B | VQA-v2 | GQA | VizWiz | ScienceQA | TextVQA | POPE | MME | MMBench | MMBench-CN | SEED |
|
| 263 |
+
| ----------- |:-----------------:|:-----------------:|:-------:|:-----------------:|:-----------------:|:-------:|:-------:|:-----------------:|:-------------:|:-------:|
|
| 264 |
+
| FP16 | 80.9 | 61.9 | 58.7 | 79.9 | 66.3 | 84.4 | 1577.01 | 72.3 | 66.2 | 64.2 |
|
| 265 |
+
| AWQ-INT4 | 80.3 | 61.7 | 59.3 | 79.0 | 65.4 | 82.9 | 1593.65 | 71.0 | 64.9 | 64.0 |
|
| 266 |
+
|
| 267 |
+
| VILA-1.5-13B | VQA-v2 | GQA | VizWiz | ScienceQA | TextVQA | POPE | MME | MMBench | MMBench-CN | SEED |
|
| 268 |
+
| ----------- |:-----------------:|:-----------------:|:-------:|:-----------------:|:-----------------:|:-------:|:-------:|:-----------------:|:-------------:|:-------:|
|
| 269 |
+
| FP16 | 82.8 | 64.3 | 62.6 | 80.1 | 65.0 | 86.3 | 1569.55 | 74.9 | 66.3 | 65.1 |
|
| 270 |
+
| AWQ-INT4 | 82.7 | 64.5 | 63.3 | 79.7 | 64.7 | 86.7 | 1531.35 | 74.7 | 66.7 | 65.1 |
|
| 271 |
+
|
| 272 |
+
|
| 273 |
+
| VILA-1.5-40B | VQA-v2 | GQA | VizWiz | ScienceQA | TextVQA | POPE | MME | MMBench | MMBench-CN | SEED |
|
| 274 |
+
| ----------- |:-----------------:|:-----------------:|:-------:|:-----------------:|:-----------------:|:-------:|:-------:|:-----------------:|:-------------:|:-------:|
|
| 275 |
+
| FP16 | 84.3 | 64.6 | 62.2 | 87.2 | 73.6 | 87.3 | 1726.82 | 82.4 | 80.2 | 69.1 |
|
| 276 |
+
| AWQ-INT4 | 84.1 | 64.4 | 61.3 | 86.7 | 73.2 | 88.2 | 1714.79 | 83.2 | 79.6 | 68.9 |
|
| 277 |
+
|
| 278 |
+
|
| 279 |
+
## Inference speed ( Token/sec )
|
| 280 |
+
|
| 281 |
+
| $~~~~~~$ | Precision | A100 | 4090 | Orin |
|
| 282 |
+
| ---------------------- | --------- | ----- | ----- | ---- |
|
| 283 |
+
| VILA1.5-3B | fp16 | 104.6 | 137.6 | 25.4 |
|
| 284 |
+
| VILA1.5-3B-AWQ | int4 | 182.8 | 215.5 | 42.5 |
|
| 285 |
+
| VILA1.5-3B-S2 | fp16 | 104.3 | 137.2 | 24.6 |
|
| 286 |
+
| VILA1.5-3B-S2-AWQ | int4 | 180.2 | 219.3 | 40.1 |
|
| 287 |
+
| Llama-3-VILA1.5-8B | fp16 | 74.9 | 57.4 | 10.2 |
|
| 288 |
+
| Llama-3-VILA1.5-8B-AWQ | int4 | 168.9 | 150.2 | 28.7 |
|
| 289 |
+
| VILA1.5-13B | fp16 | 50.9 | OOM | 6.1 |
|
| 290 |
+
| VILA1.5-13B-AWQ | int4 | 115.9 | 105.7 | 20.6 |
|
| 291 |
+
| VILA1.5-40B | fp16 | OOM | OOM | -- |
|
| 292 |
+
| VILA1.5-40B-AWQ | int4 | 57.0 | OOM | -- | -->
|
| 293 |
+
|
| 294 |
+
|
| 295 |
+
## Reference
|
| 296 |
+
|
| 297 |
+
If you find AWQ useful or relevant to your research, please kindly cite our paper:
|
| 298 |
+
|
| 299 |
+
```
|
| 300 |
+
@inproceedings{lin2023awq,
|
| 301 |
+
title={AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration},
|
| 302 |
+
author={Lin, Ji and Tang, Jiaming and Tang, Haotian and Yang, Shang and Chen, Wei-Ming and Wang, Wei-Chen and Xiao, Guangxuan and Dang, Xingyu and Gan, Chuang and Han, Song},
|
| 303 |
+
booktitle={MLSys},
|
| 304 |
+
year={2024}
|
| 305 |
+
}
|
| 306 |
+
```
|
| 307 |
+
|
| 308 |
+
## Related Projects
|
| 309 |
+
|
| 310 |
+
[SmoothQuant: Accurate and Efficient Post-Training Quantization for Large Language Models](https://github.com/mit-han-lab/smoothquant)
|
| 311 |
+
|
| 312 |
+
[GPTQ: Accurate Post-training Compression for Generative Pretrained Transformers](https://arxiv.org/abs/2210.17323)
|
| 313 |
+
|
| 314 |
+
[Vicuna and FastChat](https://github.com/lm-sys/FastChat#readme)
|
| 315 |
+
|
| 316 |
+
[LLaVA: Large Language and Vision Assistant](https://github.com/haotian-liu/LLaVA)
|
| 317 |
+
|
| 318 |
+
[VILA: On Pre-training for Visual Language Models](https://github.com/Efficient-Large-Model/VILA)
|
| 319 |
+
|
llm-awq/awq.egg-info/SOURCES.txt
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
LICENSE
|
| 2 |
+
README.md
|
| 3 |
+
pyproject.toml
|
| 4 |
+
awq/entry.py
|
| 5 |
+
awq.egg-info/PKG-INFO
|
| 6 |
+
awq.egg-info/SOURCES.txt
|
| 7 |
+
awq.egg-info/dependency_links.txt
|
| 8 |
+
awq.egg-info/requires.txt
|
| 9 |
+
awq.egg-info/top_level.txt
|
| 10 |
+
awq/kernels/setup.py
|
| 11 |
+
awq/kernels/csrc/attention/setup.py
|
| 12 |
+
awq/quantize/__init__.py
|
| 13 |
+
awq/quantize/auto_clip.py
|
| 14 |
+
awq/quantize/auto_scale.py
|
| 15 |
+
awq/quantize/pre_quant.py
|
| 16 |
+
awq/quantize/qmodule.py
|
| 17 |
+
awq/quantize/quantizer.py
|
| 18 |
+
awq/quantize/smooth.py
|
| 19 |
+
awq/quantize/w8a8_linear.py
|
| 20 |
+
awq/utils/__init__.py
|
| 21 |
+
awq/utils/calib_data.py
|
| 22 |
+
awq/utils/lm_eval_adaptor.py
|
| 23 |
+
awq/utils/module.py
|
| 24 |
+
awq/utils/parallel.py
|
| 25 |
+
awq/utils/utils.py
|
| 26 |
+
tinychat/benchmark.py
|
| 27 |
+
tinychat/demo.py
|
| 28 |
+
tinychat/internvl_benchmark.py
|
| 29 |
+
tinychat/internvl_demo.py
|
| 30 |
+
tinychat/nvila_benchmark.py
|
| 31 |
+
tinychat/nvila_demo.py
|
| 32 |
+
tinychat/offline-weight-repacker.py
|
| 33 |
+
tinychat/split_ckpt.py
|
| 34 |
+
tinychat/vila10_demo.py
|
| 35 |
+
tinychat/vila15_demo.py
|
| 36 |
+
tinychat/models/__init__.py
|
| 37 |
+
tinychat/models/falcon.py
|
| 38 |
+
tinychat/models/internvl3.py
|
| 39 |
+
tinychat/models/llama.py
|
| 40 |
+
tinychat/models/llava_llama.py
|
| 41 |
+
tinychat/models/mpt.py
|
| 42 |
+
tinychat/models/nvila_qwen2.py
|
| 43 |
+
tinychat/models/qwen2.py
|
| 44 |
+
tinychat/models/vila_llama.py
|
| 45 |
+
tinychat/models/internvl/configuration_internvl.py
|
| 46 |
+
tinychat/models/internvl/conversation.py
|
| 47 |
+
tinychat/models/internvl/internvit.py
|
| 48 |
+
tinychat/models/internvl/media.py
|
| 49 |
+
tinychat/models/llava_base/llava_arch.py
|
| 50 |
+
tinychat/models/llava_base/multimodal_encoder/builder.py
|
| 51 |
+
tinychat/models/llava_base/multimodal_encoder/clip_encoder.py
|
| 52 |
+
tinychat/models/llava_base/multimodal_projector/builder.py
|
| 53 |
+
tinychat/models/nvila/builder.py
|
| 54 |
+
tinychat/models/nvila/configuration_llava.py
|
| 55 |
+
tinychat/models/nvila/llava_arch.py
|
| 56 |
+
tinychat/modules/__init__.py
|
| 57 |
+
tinychat/modules/fused_attn.py
|
| 58 |
+
tinychat/modules/fused_internencoder.py
|
| 59 |
+
tinychat/modules/fused_mlp.py
|
| 60 |
+
tinychat/modules/fused_norm.py
|
| 61 |
+
tinychat/modules/fused_siglipdecoder.py
|
| 62 |
+
tinychat/modules/fused_vision_attn.py
|
| 63 |
+
tinychat/serve/controller.py
|
| 64 |
+
tinychat/serve/gradio_web_server.py
|
| 65 |
+
tinychat/serve/llava_conv.py
|
| 66 |
+
tinychat/serve/model_worker.py
|
| 67 |
+
tinychat/serve/model_worker_new.py
|
| 68 |
+
tinychat/stream_generators/NVILA_stream_gen.py
|
| 69 |
+
tinychat/stream_generators/__init__.py
|
| 70 |
+
tinychat/stream_generators/internvl_stream_gen.py
|
| 71 |
+
tinychat/stream_generators/llava_stream_gen.py
|
| 72 |
+
tinychat/stream_generators/stream_gen.py
|
| 73 |
+
tinychat/utils/__init__.py
|
| 74 |
+
tinychat/utils/constants.py
|
| 75 |
+
tinychat/utils/conversation_utils.py
|
| 76 |
+
tinychat/utils/input_metadata.py
|
| 77 |
+
tinychat/utils/llava_image_processing.py
|
| 78 |
+
tinychat/utils/load_quant.py
|
| 79 |
+
tinychat/utils/log_utils.py
|
| 80 |
+
tinychat/utils/prompt_templates.py
|
| 81 |
+
tinychat/utils/tune.py
|
llm-awq/awq.egg-info/dependency_links.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
|
llm-awq/awq.egg-info/requires.txt
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
accelerate==0.34.2
|
| 2 |
+
sentencepiece
|
| 3 |
+
tokenizers>=0.12.1
|
| 4 |
+
torch==2.3.0
|
| 5 |
+
torchvision==0.18.0
|
| 6 |
+
transformers==4.46.0
|
| 7 |
+
lm_eval==0.3.0
|
| 8 |
+
texttable
|
| 9 |
+
toml
|
| 10 |
+
attributedict
|
| 11 |
+
protobuf
|
| 12 |
+
gradio==3.35.2
|
| 13 |
+
gradio_client==0.2.9
|
| 14 |
+
fastapi
|
| 15 |
+
uvicorn
|
| 16 |
+
pydantic==1.10.19
|
llm-awq/awq/kernels/csrc/w8a8/reduction_utils.cuh
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* Adapted from https://github.com/NVIDIA/FasterTransformer/blob/release/v5.3_tag/src/fastertransformer/kernels/reduce_kernel_utils.cuh
|
| 3 |
+
* Copyright (c) 2023, The vLLM team.
|
| 4 |
+
* Copyright (c) 2020-2023, NVIDIA CORPORATION. All rights reserved.
|
| 5 |
+
*
|
| 6 |
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
| 7 |
+
* you may not use this file except in compliance with the License.
|
| 8 |
+
* You may obtain a copy of the License at
|
| 9 |
+
*
|
| 10 |
+
* http://www.apache.org/licenses/LICENSE-2.0
|
| 11 |
+
*
|
| 12 |
+
* Unless required by applicable law or agreed to in writing, software
|
| 13 |
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
| 14 |
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 15 |
+
* See the License for the specific language governing permissions and
|
| 16 |
+
* limitations under the License.
|
| 17 |
+
*/
|
| 18 |
+
#pragma once
|
| 19 |
+
#define FINAL_MASK 0xffffffff
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
namespace vllm {
|
| 23 |
+
|
| 24 |
+
template<typename T>
|
| 25 |
+
__inline__ __device__ T warpReduceSum(T val) {
|
| 26 |
+
#pragma unroll
|
| 27 |
+
for (int mask = 16; mask > 0; mask >>= 1)
|
| 28 |
+
val += __shfl_xor_sync(0xffffffff, val, mask, 32);
|
| 29 |
+
return val;
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
template <typename T, int NUM>
|
| 33 |
+
__inline__ __device__ T warpReduceSumV2(T* val)
|
| 34 |
+
{
|
| 35 |
+
#pragma unroll
|
| 36 |
+
for (int i = 0; i < NUM; i++)
|
| 37 |
+
{
|
| 38 |
+
#pragma unroll
|
| 39 |
+
for (int mask = 16; mask > 0; mask >>= 1)
|
| 40 |
+
val[i] += __shfl_xor_sync(FINAL_MASK, val[i], mask, 32);
|
| 41 |
+
}
|
| 42 |
+
return (T) (0.0f);
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
/* Calculate the sum of all elements in a block */
|
| 46 |
+
template<typename T>
|
| 47 |
+
__inline__ __device__ T blockReduceSum(T val) {
|
| 48 |
+
static __shared__ T shared[32];
|
| 49 |
+
int lane = threadIdx.x & 0x1f;
|
| 50 |
+
int wid = threadIdx.x >> 5;
|
| 51 |
+
|
| 52 |
+
val = warpReduceSum<T>(val);
|
| 53 |
+
|
| 54 |
+
if (lane == 0)
|
| 55 |
+
shared[wid] = val;
|
| 56 |
+
|
| 57 |
+
__syncthreads();
|
| 58 |
+
|
| 59 |
+
// Modify from blockDim.x << 5 to blockDim.x / 32. to prevent
|
| 60 |
+
// blockDim.x is not divided by 32
|
| 61 |
+
val = (threadIdx.x < (blockDim.x / 32.f)) ? shared[lane] : (T)(0.0f);
|
| 62 |
+
val = warpReduceSum<T>(val);
|
| 63 |
+
return val;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
/* Calculate the sum of all elements in a block */
|
| 67 |
+
template<typename T>
|
| 68 |
+
__inline__ __device__ T blockAllReduceSum(T val) {
|
| 69 |
+
static __shared__ T shared[32];
|
| 70 |
+
int lane = threadIdx.x & 0x1f;
|
| 71 |
+
int wid = threadIdx.x >> 5;
|
| 72 |
+
|
| 73 |
+
val = warpReduceSum<T>(val);
|
| 74 |
+
|
| 75 |
+
if (lane == 0)
|
| 76 |
+
shared[wid] = val;
|
| 77 |
+
|
| 78 |
+
__syncthreads();
|
| 79 |
+
|
| 80 |
+
// Modify from blockDim.x << 5 to blockDim.x / 32. to prevent
|
| 81 |
+
// blockDim.x is not divided by 32
|
| 82 |
+
val = (lane < (blockDim.x / 32.f)) ? shared[lane] : (T)(0.0f);
|
| 83 |
+
val = warpReduceSum<T>(val);
|
| 84 |
+
return val;
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
template <typename T, int NUM>
|
| 88 |
+
__inline__ __device__ T blockReduceSumV2(T* val)
|
| 89 |
+
{
|
| 90 |
+
static __shared__ T shared[NUM][33];
|
| 91 |
+
int lane = threadIdx.x & 0x1f;
|
| 92 |
+
int wid = threadIdx.x >> 5;
|
| 93 |
+
|
| 94 |
+
warpReduceSumV2<T, NUM>(val);
|
| 95 |
+
|
| 96 |
+
if (lane == 0)
|
| 97 |
+
{
|
| 98 |
+
#pragma unroll
|
| 99 |
+
for (int i = 0; i < NUM; i++)
|
| 100 |
+
{
|
| 101 |
+
shared[i][wid] = val[i];
|
| 102 |
+
}
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
__syncthreads();
|
| 106 |
+
|
| 107 |
+
bool is_mask = threadIdx.x < (blockDim.x / 32.f);
|
| 108 |
+
#pragma unroll
|
| 109 |
+
for (int i = 0; i < NUM; i++)
|
| 110 |
+
{
|
| 111 |
+
val[i] = is_mask ? shared[i][lane] : (T) (0.0f);
|
| 112 |
+
}
|
| 113 |
+
warpReduceSumV2<T, NUM>(val);
|
| 114 |
+
return (T) 0.0f;
|
| 115 |
+
}
|
| 116 |
+
|
| 117 |
+
template<typename T>
|
| 118 |
+
__inline__ __device__ T warpReduceMax(T val)
|
| 119 |
+
{
|
| 120 |
+
#pragma unroll
|
| 121 |
+
for (int mask = 16; mask > 0; mask >>= 1)
|
| 122 |
+
val = max(val, __shfl_xor_sync(0xffffffff, val, mask, 32));
|
| 123 |
+
return val;
|
| 124 |
+
}
|
| 125 |
+
/* Calculate the maximum of all elements in a block */
|
| 126 |
+
template<typename T>
|
| 127 |
+
__inline__ __device__ T blockReduceMax(T val)
|
| 128 |
+
{
|
| 129 |
+
static __shared__ T shared[32];
|
| 130 |
+
int lane = threadIdx.x & 0x1f; // in-warp idx
|
| 131 |
+
int wid = threadIdx.x >> 5; // warp idx
|
| 132 |
+
val = warpReduceMax(val); // get maxx in each warp
|
| 133 |
+
if (lane == 0) // record in-warp maxx by warp Idx
|
| 134 |
+
shared[wid] = val;
|
| 135 |
+
__syncthreads();
|
| 136 |
+
// Modify from blockDim.x << 5 to blockDim.x / 32. to prevent
|
| 137 |
+
// blockDim.x is not divided by 32
|
| 138 |
+
val = (threadIdx.x < (blockDim.x / 32.f)) ? shared[lane] : -1e20f;
|
| 139 |
+
val = warpReduceMax(val);
|
| 140 |
+
return val;
|
| 141 |
+
}
|
| 142 |
+
|
| 143 |
+
/* Calculate the maximum of all elements in a block */
|
| 144 |
+
template <typename T>
|
| 145 |
+
__inline__ __device__ T blockAllReduceMax(T val)
|
| 146 |
+
{
|
| 147 |
+
static __shared__ T shared[32];
|
| 148 |
+
int lane = threadIdx.x & 0x1f; // in-warp idx
|
| 149 |
+
int wid = threadIdx.x >> 5; // warp idx
|
| 150 |
+
|
| 151 |
+
val = warpReduceMax(val); // get maxx in each warp
|
| 152 |
+
|
| 153 |
+
if (lane == 0) // record in-warp maxx by warp Idx
|
| 154 |
+
shared[wid] = val;
|
| 155 |
+
|
| 156 |
+
__syncthreads();
|
| 157 |
+
|
| 158 |
+
// Modify from blockDim.x << 5 to blockDim.x / 32. to prevent
|
| 159 |
+
// blockDim.x is not divided by 32
|
| 160 |
+
val = (lane < (blockDim.x / 32.f)) ? shared[lane] : -1e20f;
|
| 161 |
+
val = warpReduceMax(val);
|
| 162 |
+
|
| 163 |
+
return val;
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
} // namespace vllm
|
llm-awq/awq/quantize/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (246 Bytes). View file
|
|
|
llm-awq/awq/utils/calib_data.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
from datasets import load_dataset
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
def get_calib_dataset(data="pileval", tokenizer=None, n_samples=512, block_size=512):
|
| 6 |
+
if data == "pileval":
|
| 7 |
+
dataset = load_dataset("mit-han-lab/pile-val-backup", split="validation")
|
| 8 |
+
else:
|
| 9 |
+
raise NotImplementedError
|
| 10 |
+
dataset = dataset.shuffle(seed=42)
|
| 11 |
+
samples = []
|
| 12 |
+
n_run = 0
|
| 13 |
+
for data in dataset:
|
| 14 |
+
line = data["text"]
|
| 15 |
+
line = line.strip()
|
| 16 |
+
line_encoded = tokenizer.encode(line)
|
| 17 |
+
if len(line_encoded) > 512:
|
| 18 |
+
continue
|
| 19 |
+
sample = torch.tensor([line_encoded])
|
| 20 |
+
if sample.numel() == 0:
|
| 21 |
+
continue
|
| 22 |
+
samples.append(sample)
|
| 23 |
+
n_run += 1
|
| 24 |
+
if n_run == n_samples:
|
| 25 |
+
break
|
| 26 |
+
# now concatenate all samples and split according to block size
|
| 27 |
+
cat_samples = torch.cat(samples, dim=1)
|
| 28 |
+
n_split = cat_samples.shape[1] // block_size
|
| 29 |
+
print(f" * Split into {n_split} blocks")
|
| 30 |
+
return [
|
| 31 |
+
cat_samples[:, i * block_size : (i + 1) * block_size] for i in range(n_split)
|
| 32 |
+
]
|
llm-awq/examples/README.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# AWQ Examples
|
| 2 |
+
|
| 3 |
+
Here we provide two AWQ examples, applying to:
|
| 4 |
+
- [Vicuna-7B](https://github.com/lm-sys/FastChat), a chatbot with instruction-tuning
|
| 5 |
+
- [LLaVA-13B](https://github.com/lm-sys/FastChat), a visual LM for multi-modal applications like visual reasoning.
|
| 6 |
+
- [A simple conversion script](https://github.com/mit-han-lab/llm-awq/tree/main/examples/convert_to_hf.py) to convert llm-awq weights into HF format.
|
| 7 |
+
|
| 8 |
+
Here are some example output from the two demos. You should able to observe memory saving when running the demos in 4-bit. Please check the notebooks for details.
|
| 9 |
+
|
| 10 |
+

|
llm-awq/examples/chat_demo.ipynb
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {},
|
| 6 |
+
"source": [
|
| 7 |
+
"# AWQ on Vicuna"
|
| 8 |
+
]
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"cell_type": "markdown",
|
| 12 |
+
"metadata": {},
|
| 13 |
+
"source": [
|
| 14 |
+
"In this notebook, we use Vicuna model to demonstrate the performance of AWQ on instruction-tuned models. We implement AWQ real-INT4 inference kernels, which are wrapped as Pytorch modules and can be easily used by existing models. We also provide a simple example to show how to use AWQ to quantize a model and save/load the quantized model checkpoint."
|
| 15 |
+
]
|
| 16 |
+
},
|
| 17 |
+
{
|
| 18 |
+
"cell_type": "markdown",
|
| 19 |
+
"metadata": {},
|
| 20 |
+
"source": [
|
| 21 |
+
"In order to run this notebook, you need to install the following packages:\n",
|
| 22 |
+
"- [AWQ](https://github.com/mit-han-lab/llm-awq)\n",
|
| 23 |
+
"- [Pytorch](https://pytorch.org/)\n",
|
| 24 |
+
"- [Accelerate](https://github.com/huggingface/accelerate)\n",
|
| 25 |
+
"- [Transformers](https://github.com/huggingface/transformers)"
|
| 26 |
+
]
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
"cell_type": "code",
|
| 30 |
+
"execution_count": 1,
|
| 31 |
+
"metadata": {},
|
| 32 |
+
"outputs": [],
|
| 33 |
+
"source": [
|
| 34 |
+
"import torch\n",
|
| 35 |
+
"from accelerate import init_empty_weights, load_checkpoint_and_dispatch\n",
|
| 36 |
+
"from awq.quantize.quantizer import real_quantize_model_weight\n",
|
| 37 |
+
"from transformers import AutoModelForCausalLM, AutoTokenizer, AutoConfig\n",
|
| 38 |
+
"from tinychat.demo import gen_params, stream_output\n",
|
| 39 |
+
"from tinychat.stream_generators import StreamGenerator\n",
|
| 40 |
+
"from tinychat.modules import make_quant_norm, make_quant_attn, make_fused_mlp\n",
|
| 41 |
+
"from tinychat.utils.prompt_templates import get_prompter\n",
|
| 42 |
+
"import os\n",
|
| 43 |
+
"# This demo only support single GPU for now\n",
|
| 44 |
+
"os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"0\""
|
| 45 |
+
]
|
| 46 |
+
},
|
| 47 |
+
{
|
| 48 |
+
"cell_type": "markdown",
|
| 49 |
+
"metadata": {},
|
| 50 |
+
"source": [
|
| 51 |
+
"Please get the Vicuna model from [FastChat](https://github.com/lm-sys/FastChat) and run the following command to generate a quantized model checkpoint first.\n",
|
| 52 |
+
"\n",
|
| 53 |
+
"```bash\n",
|
| 54 |
+
"mkdir quant_cache\n",
|
| 55 |
+
"python -m awq.entry --model_path [vicuna-7b_model_path] \\\n",
|
| 56 |
+
" --w_bit 4 --q_group_size 128 \\\n",
|
| 57 |
+
" --load_awq awq_cache/vicuna-7b-w4-g128.pt \\\n",
|
| 58 |
+
" --q_backend real --dump_quant quant_cache/vicuna-7b-w4-g128-awq.pt\n",
|
| 59 |
+
"```"
|
| 60 |
+
]
|
| 61 |
+
},
|
| 62 |
+
{
|
| 63 |
+
"cell_type": "code",
|
| 64 |
+
"execution_count": 2,
|
| 65 |
+
"metadata": {},
|
| 66 |
+
"outputs": [],
|
| 67 |
+
"source": [
|
| 68 |
+
"# model_path = \"\" # the path of vicuna-7b model\n",
|
| 69 |
+
"# load_quant_path = \"quant_cache/vicuna-7b-w4-g128-awq.pt\"\n",
|
| 70 |
+
"model_path = \"/data/llm/checkpoints/vicuna-hf/vicuna-7b\"\n",
|
| 71 |
+
"load_quant_path = \"/data/llm/checkpoints/vicuna-hf/vicuna-7b-awq-w4g128.pt\""
|
| 72 |
+
]
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"cell_type": "markdown",
|
| 76 |
+
"metadata": {},
|
| 77 |
+
"source": [
|
| 78 |
+
"We first load a empty model and replace all the linear layers with WQLinear layers. Then we load the quantized weights from the checkpoint. "
|
| 79 |
+
]
|
| 80 |
+
},
|
| 81 |
+
{
|
| 82 |
+
"cell_type": "code",
|
| 83 |
+
"execution_count": 3,
|
| 84 |
+
"metadata": {},
|
| 85 |
+
"outputs": [
|
| 86 |
+
{
|
| 87 |
+
"data": {
|
| 88 |
+
"application/vnd.jupyter.widget-view+json": {
|
| 89 |
+
"model_id": "8b79a82b73ab4d9191ba54f5d0f8cb86",
|
| 90 |
+
"version_major": 2,
|
| 91 |
+
"version_minor": 0
|
| 92 |
+
},
|
| 93 |
+
"text/plain": [
|
| 94 |
+
"Loading checkpoint shards: 0%| | 0/2 [00:00<?, ?it/s]"
|
| 95 |
+
]
|
| 96 |
+
},
|
| 97 |
+
"metadata": {},
|
| 98 |
+
"output_type": "display_data"
|
| 99 |
+
},
|
| 100 |
+
{
|
| 101 |
+
"name": "stderr",
|
| 102 |
+
"output_type": "stream",
|
| 103 |
+
"text": [
|
| 104 |
+
"real weight quantization...(init only): 100%|███████████████████| 32/32 [00:11<00:00, 2.69it/s]\n",
|
| 105 |
+
"The model weights are not tied. Please use the `tie_weights` method before using the `infer_auto_device` function.\n",
|
| 106 |
+
"The model weights are not tied. Please use the `tie_weights` method before using the `infer_auto_device` function.\n"
|
| 107 |
+
]
|
| 108 |
+
}
|
| 109 |
+
],
|
| 110 |
+
"source": [
|
| 111 |
+
"config = AutoConfig.from_pretrained(model_path)\n",
|
| 112 |
+
"tokenizer = AutoTokenizer.from_pretrained(model_path, use_fast=False)\n",
|
| 113 |
+
"with init_empty_weights():\n",
|
| 114 |
+
" model = AutoModelForCausalLM.from_pretrained(model_path, config=config,\n",
|
| 115 |
+
" torch_dtype=torch.float16)\n",
|
| 116 |
+
"q_config = {\"zero_point\": True, \"q_group_size\": 128}\n",
|
| 117 |
+
"real_quantize_model_weight(\n",
|
| 118 |
+
" model, w_bit=4, q_config=q_config, init_only=True)\n",
|
| 119 |
+
"\n",
|
| 120 |
+
"model = load_checkpoint_and_dispatch(\n",
|
| 121 |
+
" model, load_quant_path,\n",
|
| 122 |
+
" device_map=\"auto\",\n",
|
| 123 |
+
" no_split_module_classes=[\"LlamaDecoderLayer\"]\n",
|
| 124 |
+
")"
|
| 125 |
+
]
|
| 126 |
+
},
|
| 127 |
+
{
|
| 128 |
+
"cell_type": "code",
|
| 129 |
+
"execution_count": 4,
|
| 130 |
+
"metadata": {},
|
| 131 |
+
"outputs": [
|
| 132 |
+
{
|
| 133 |
+
"name": "stdout",
|
| 134 |
+
"output_type": "stream",
|
| 135 |
+
"text": [
|
| 136 |
+
"[Warning] Calling a fake MLP fusion. But still faster than Huggingface Implimentation.\n"
|
| 137 |
+
]
|
| 138 |
+
},
|
| 139 |
+
{
|
| 140 |
+
"data": {
|
| 141 |
+
"text/plain": [
|
| 142 |
+
"LlamaForCausalLM(\n",
|
| 143 |
+
" (model): LlamaModel(\n",
|
| 144 |
+
" (embed_tokens): Embedding(32000, 4096, padding_idx=0)\n",
|
| 145 |
+
" (layers): ModuleList(\n",
|
| 146 |
+
" (0-31): 32 x LlamaDecoderLayer(\n",
|
| 147 |
+
" (self_attn): QuantLlamaAttention(\n",
|
| 148 |
+
" (qkv_proj): WQLinear(in_features=4096, out_features=12288, bias=False, w_bit=4, group_size=128)\n",
|
| 149 |
+
" (o_proj): WQLinear(in_features=4096, out_features=4096, bias=False, w_bit=4, group_size=128)\n",
|
| 150 |
+
" (rotary_emb): QuantLlamaRotaryEmbedding()\n",
|
| 151 |
+
" )\n",
|
| 152 |
+
" (mlp): QuantLlamaMLP(\n",
|
| 153 |
+
" (down_proj): WQLinear(in_features=11008, out_features=4096, bias=False, w_bit=4, group_size=128)\n",
|
| 154 |
+
" )\n",
|
| 155 |
+
" (input_layernorm): FTLlamaRMSNorm()\n",
|
| 156 |
+
" (post_attention_layernorm): FTLlamaRMSNorm()\n",
|
| 157 |
+
" )\n",
|
| 158 |
+
" )\n",
|
| 159 |
+
" (norm): FTLlamaRMSNorm()\n",
|
| 160 |
+
" )\n",
|
| 161 |
+
" (lm_head): Linear(in_features=4096, out_features=32000, bias=False)\n",
|
| 162 |
+
")"
|
| 163 |
+
]
|
| 164 |
+
},
|
| 165 |
+
"execution_count": 4,
|
| 166 |
+
"metadata": {},
|
| 167 |
+
"output_type": "execute_result"
|
| 168 |
+
}
|
| 169 |
+
],
|
| 170 |
+
"source": [
|
| 171 |
+
"make_quant_attn(model, \"cuda:0\")\n",
|
| 172 |
+
"make_quant_norm(model)\n",
|
| 173 |
+
"make_fused_mlp(model)"
|
| 174 |
+
]
|
| 175 |
+
},
|
| 176 |
+
{
|
| 177 |
+
"cell_type": "code",
|
| 178 |
+
"execution_count": 5,
|
| 179 |
+
"metadata": {},
|
| 180 |
+
"outputs": [
|
| 181 |
+
{
|
| 182 |
+
"name": "stdin",
|
| 183 |
+
"output_type": "stream",
|
| 184 |
+
"text": [
|
| 185 |
+
"USER: Show me some attractions in Boston.\n"
|
| 186 |
+
]
|
| 187 |
+
},
|
| 188 |
+
{
|
| 189 |
+
"name": "stdout",
|
| 190 |
+
"output_type": "stream",
|
| 191 |
+
"text": [
|
| 192 |
+
"ASSISTANT: 1. Boston Public Library\n",
|
| 193 |
+
"2. Fenway Park\n",
|
| 194 |
+
"3. Harvard Square\n",
|
| 195 |
+
"4. Boston Common\n",
|
| 196 |
+
"5. Freedom Trail\n",
|
| 197 |
+
"6. Museum of Fine Arts\n",
|
| 198 |
+
"7. Isabella Stewart Gardner Museum\n",
|
| 199 |
+
"8. Paul Revere House\n",
|
| 200 |
+
"9. New England Aquarium\n",
|
| 201 |
+
"10. Museum of Science\n",
|
| 202 |
+
"==================================================\n",
|
| 203 |
+
"Speed of Inference\n",
|
| 204 |
+
"--------------------------------------------------\n",
|
| 205 |
+
"Context Stage : 7.18 ms/token\n",
|
| 206 |
+
"Generation Stage : 9.49 ms/token\n",
|
| 207 |
+
"Average Speed : 8.53 ms/token\n",
|
| 208 |
+
"==================================================\n"
|
| 209 |
+
]
|
| 210 |
+
},
|
| 211 |
+
{
|
| 212 |
+
"name": "stdin",
|
| 213 |
+
"output_type": "stream",
|
| 214 |
+
"text": [
|
| 215 |
+
"USER: \n"
|
| 216 |
+
]
|
| 217 |
+
},
|
| 218 |
+
{
|
| 219 |
+
"name": "stdout",
|
| 220 |
+
"output_type": "stream",
|
| 221 |
+
"text": [
|
| 222 |
+
"EXIT...\n"
|
| 223 |
+
]
|
| 224 |
+
}
|
| 225 |
+
],
|
| 226 |
+
"source": [
|
| 227 |
+
"model_prompter = get_prompter(\"llama\", model_path)\n",
|
| 228 |
+
"stream_generator = StreamGenerator\n",
|
| 229 |
+
"count = 0\n",
|
| 230 |
+
"while True:\n",
|
| 231 |
+
" # Get input from the user\n",
|
| 232 |
+
" input_prompt = input(\"USER: \")\n",
|
| 233 |
+
" if input_prompt == \"\":\n",
|
| 234 |
+
" print(\"EXIT...\")\n",
|
| 235 |
+
" break\n",
|
| 236 |
+
" model_prompter.insert_prompt(input_prompt)\n",
|
| 237 |
+
" output_stream = stream_generator(model, tokenizer, model_prompter.model_input, gen_params, device=\"cuda:0\")\n",
|
| 238 |
+
" outputs = stream_output(output_stream) \n",
|
| 239 |
+
" model_prompter.update_template(outputs)\n",
|
| 240 |
+
" count += 1"
|
| 241 |
+
]
|
| 242 |
+
},
|
| 243 |
+
{
|
| 244 |
+
"cell_type": "code",
|
| 245 |
+
"execution_count": null,
|
| 246 |
+
"metadata": {},
|
| 247 |
+
"outputs": [],
|
| 248 |
+
"source": []
|
| 249 |
+
}
|
| 250 |
+
],
|
| 251 |
+
"metadata": {
|
| 252 |
+
"kernelspec": {
|
| 253 |
+
"display_name": "Python (awq)",
|
| 254 |
+
"language": "python",
|
| 255 |
+
"name": "awq"
|
| 256 |
+
},
|
| 257 |
+
"language_info": {
|
| 258 |
+
"codemirror_mode": {
|
| 259 |
+
"name": "ipython",
|
| 260 |
+
"version": 3
|
| 261 |
+
},
|
| 262 |
+
"file_extension": ".py",
|
| 263 |
+
"mimetype": "text/x-python",
|
| 264 |
+
"name": "python",
|
| 265 |
+
"nbconvert_exporter": "python",
|
| 266 |
+
"pygments_lexer": "ipython3",
|
| 267 |
+
"version": "3.10.11"
|
| 268 |
+
}
|
| 269 |
+
},
|
| 270 |
+
"nbformat": 4,
|
| 271 |
+
"nbformat_minor": 4
|
| 272 |
+
}
|
llm-awq/examples/convert_to_hf.py
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This script demonstrates how you can convert your model into HF format
|
| 2 |
+
# easily and push the quantized weights on the Hub using simple tools.
|
| 3 |
+
# Make sure to have transformers > 4.34 and that you have ran
|
| 4 |
+
# `huggingface-cli login` on your terminal before running this
|
| 5 |
+
# script
|
| 6 |
+
import os
|
| 7 |
+
import argparse
|
| 8 |
+
|
| 9 |
+
# This demo only support single GPU for now
|
| 10 |
+
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
|
| 11 |
+
|
| 12 |
+
from transformers import AutoConfig, AwqConfig, AutoTokenizer
|
| 13 |
+
from huggingface_hub import HfApi
|
| 14 |
+
|
| 15 |
+
api = HfApi()
|
| 16 |
+
|
| 17 |
+
parser = argparse.ArgumentParser()
|
| 18 |
+
parser.add_argument(
|
| 19 |
+
"--model_path", type=str, help="path of the original hf model", required=True
|
| 20 |
+
)
|
| 21 |
+
parser.add_argument(
|
| 22 |
+
"--quantized_model_path",
|
| 23 |
+
type=str,
|
| 24 |
+
help="path of the quantized AWQ model",
|
| 25 |
+
required=True,
|
| 26 |
+
)
|
| 27 |
+
parser.add_argument(
|
| 28 |
+
"--quantized_model_hub_path",
|
| 29 |
+
type=str,
|
| 30 |
+
help="path of the quantized AWQ model to push on the Hub",
|
| 31 |
+
required=True,
|
| 32 |
+
)
|
| 33 |
+
parser.add_argument("--w_bit", type=int, default=4, help="")
|
| 34 |
+
parser.add_argument("--q_group_size", default=128, type=int)
|
| 35 |
+
parser.add_argument("--no_zero_point", action="store_true")
|
| 36 |
+
|
| 37 |
+
args = parser.parse_args()
|
| 38 |
+
|
| 39 |
+
original_model_path = args.model_path
|
| 40 |
+
quantized_model_path = args.quantized_model_path
|
| 41 |
+
quantized_model_hub_path = args.quantized_model_hub_path
|
| 42 |
+
|
| 43 |
+
# Load the corresponding AWQConfig
|
| 44 |
+
quantization_config = AwqConfig(
|
| 45 |
+
bits=args.w_bit,
|
| 46 |
+
group_size=args.q_group_size,
|
| 47 |
+
zero_point=not args.no_zero_point,
|
| 48 |
+
backend="llm-awq",
|
| 49 |
+
version="gemv",
|
| 50 |
+
)
|
| 51 |
+
|
| 52 |
+
# Set the attribute `quantization_config` in model's config
|
| 53 |
+
config = AutoConfig.from_pretrained(original_model_path)
|
| 54 |
+
config.quantization_config = quantization_config
|
| 55 |
+
|
| 56 |
+
# Load tokenizer
|
| 57 |
+
tok = AutoTokenizer.from_pretrained(original_model_path)
|
| 58 |
+
|
| 59 |
+
# Push config and tokenizer
|
| 60 |
+
config.push_to_hub(quantized_model_hub_path)
|
| 61 |
+
tok.push_to_hub(quantized_model_hub_path)
|
| 62 |
+
|
| 63 |
+
# Upload model weights
|
| 64 |
+
api.upload_file(
|
| 65 |
+
path_or_fileobj=quantized_model_path,
|
| 66 |
+
path_in_repo="pytorch_model.bin",
|
| 67 |
+
repo_id=quantized_model_hub_path,
|
| 68 |
+
repo_type="model",
|
| 69 |
+
)
|
llm-awq/examples/llava_demo.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
llm-awq/figures/vila-logo.jpg
ADDED
|
llm-awq/scripts/DeepSeek_R1_Distill_example.sh
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MODEL=DeepSeek-R1-Distill-Llama-8B
|
| 2 |
+
|
| 3 |
+
# run AWQ search (optional; we provided the pre-computed results)
|
| 4 |
+
python -m awq.entry --model_path /dataset/models/$MODEL \
|
| 5 |
+
--w_bit 4 --q_group_size 128 \
|
| 6 |
+
--run_awq --dump_awq awq_cache/$MODEL-w4-g128.pt
|
| 7 |
+
|
| 8 |
+
# evaluate the AWQ quantize model (simulated pseudo quantization)
|
| 9 |
+
python -m awq.entry --model_path /dataset/models/$MODEL \
|
| 10 |
+
--tasks wikitext \
|
| 11 |
+
--w_bit 4 --q_group_size 128 \
|
| 12 |
+
--load_awq awq_cache/$MODEL-w4-g128.pt \
|
| 13 |
+
--q_backend fake
|
| 14 |
+
|
| 15 |
+
# generate real quantized weights (w4)
|
| 16 |
+
python -m awq.entry --model_path /dataset/models/$MODEL \
|
| 17 |
+
--w_bit 4 --q_group_size 128 \
|
| 18 |
+
--load_awq awq_cache/$MODEL-w4-g128.pt \
|
| 19 |
+
--q_backend real --dump_quant quant_cache/$MODEL-w4-g128-awq.pt
|
| 20 |
+
|
| 21 |
+
# load and evaluate the real quantized model (smaller gpu memory usage)
|
| 22 |
+
python -m awq.entry --model_path /dataset/models/$MODEL \
|
| 23 |
+
--tasks wikitext \
|
| 24 |
+
--w_bit 4 --q_group_size 128 \
|
| 25 |
+
--load_quant quant_cache/$MODEL-w4-g128-awq.pt
|
llm-awq/scripts/llama_example.sh
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MODEL=llama-7b
|
| 2 |
+
|
| 3 |
+
# run AWQ search (optional; we provided the pre-computed results)
|
| 4 |
+
python -m awq.entry --model_path /dataset/llama-hf/$MODEL \
|
| 5 |
+
--w_bit 4 --q_group_size 128 \
|
| 6 |
+
--run_awq --dump_awq awq_cache/$MODEL-w4-g128.pt
|
| 7 |
+
|
| 8 |
+
# evaluate the AWQ quantize model (simulated pseudo quantization)
|
| 9 |
+
python -m awq.entry --model_path /dataset/llama-hf/$MODEL \
|
| 10 |
+
--tasks wikitext \
|
| 11 |
+
--w_bit 4 --q_group_size 128 \
|
| 12 |
+
--load_awq awq_cache/$MODEL-w4-g128.pt \
|
| 13 |
+
--q_backend fake
|
| 14 |
+
|
| 15 |
+
# generate real quantized weights (w4)
|
| 16 |
+
python -m awq.entry --model_path /dataset/llama-hf/$MODEL \
|
| 17 |
+
--w_bit 4 --q_group_size 128 \
|
| 18 |
+
--load_awq awq_cache/$MODEL-w4-g128.pt \
|
| 19 |
+
--q_backend real --dump_quant quant_cache/$MODEL-w4-g128-awq.pt
|
| 20 |
+
|
| 21 |
+
# load and evaluate the real quantized model (smaller gpu memory usage)
|
| 22 |
+
python -m awq.entry --model_path /dataset/llama-hf/$MODEL \
|
| 23 |
+
--tasks wikitext \
|
| 24 |
+
--w_bit 4 --q_group_size 128 \
|
| 25 |
+
--load_quant quant_cache/$MODEL-w4-g128-awq.pt
|
llm-awq/scripts/llava_example.sh
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MODEL=llava-13b-v0
|
| 2 |
+
|
| 3 |
+
# run AWQ search (optional; we provided the pre-computed results)
|
| 4 |
+
python -m awq.entry --model_path /dataset/llava-hf/$MODEL \
|
| 5 |
+
--w_bit 4 --q_group_size 128 \
|
| 6 |
+
--run_awq --dump_awq awq_cache/$MODEL-w4-g128.pt
|
| 7 |
+
|
| 8 |
+
# generate real quantized weights (w4)
|
| 9 |
+
python -m awq.entry --model_path /dataset/llava-hf/$MODEL \
|
| 10 |
+
--w_bit 4 --q_group_size 128 \
|
| 11 |
+
--load_awq awq_cache/$MODEL-w4-g128.pt \
|
| 12 |
+
--q_backend real --dump_quant quant_cache/$MODEL-w4-g128-awq.pt
|
llm-awq/scripts/nvila_example.sh
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# run AWQ search
|
| 2 |
+
python -m awq.entry --model_path PATH/TO/NVILA \
|
| 3 |
+
--smooth_scale --media_path https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen2-VL/space_woaudio.mp4 \
|
| 4 |
+
--act_scale_path awq_cache/NVILA-VT-smooth-scale.pt --vila-20 \
|
| 5 |
+
--w_bit 4 --q_group_size 128 \
|
| 6 |
+
--run_awq --dump_awq awq_cache/NVILA.pt
|
| 7 |
+
|
| 8 |
+
# generate real quantized weights (w4)
|
| 9 |
+
python -m awq.entry --model_path PATH/TO/NVILA/llm \
|
| 10 |
+
--w_bit 4 --q_group_size 128 \
|
| 11 |
+
--load_awq awq_cache/NVILA.pt \
|
| 12 |
+
--q_backend real --dump_quant quant_cache/NVILA-w4-g128-awq.pt --vila-20
|
llm-awq/scripts/opt_example.sh
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MODEL=opt-6.7b
|
| 2 |
+
|
| 3 |
+
# run AWQ search (optional; we provided the pre-computed results)
|
| 4 |
+
python -m awq.entry --model_path /dataset/opt/$MODEL \
|
| 5 |
+
--w_bit 4 --q_group_size 128 \
|
| 6 |
+
--run_awq --dump_awq awq_cache/$MODEL-w4-g128.pt
|
| 7 |
+
|
| 8 |
+
# evaluate the AWQ quantize model (simulated pseudo quantization)
|
| 9 |
+
python -m awq.entry --model_path /dataset/opt/$MODEL \
|
| 10 |
+
--tasks wikitext \
|
| 11 |
+
--w_bit 4 --q_group_size 128 \
|
| 12 |
+
--load_awq awq_cache/$MODEL-w4-g128.pt \
|
| 13 |
+
--q_backend fake
|
| 14 |
+
|
| 15 |
+
# generate real quantized weights (w4)
|
| 16 |
+
python -m awq.entry --model_path /dataset/opt/$MODEL \
|
| 17 |
+
--w_bit 4 --q_group_size 128 \
|
| 18 |
+
--load_awq awq_cache/$MODEL-w4-g128.pt \
|
| 19 |
+
--q_backend real --dump_quant quant_cache/$MODEL-w4-g128-awq.pt
|
| 20 |
+
|
| 21 |
+
# load and evaluate the real quantized model (smaller gpu memory usage)
|
| 22 |
+
python -m awq.entry --model_path /dataset/opt/$MODEL \
|
| 23 |
+
--tasks wikitext \
|
| 24 |
+
--w_bit 4 --q_group_size 128 \
|
| 25 |
+
--load_quant quant_cache/$MODEL-w4-g128-awq.pt
|
llm-awq/scripts/qwen_example.sh
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MODEL=qwen2.5-7b
|
| 2 |
+
|
| 3 |
+
# run AWQ search (optional; we provided the pre-computed results)
|
| 4 |
+
python -m awq.entry --model_path /dataset/models/$MODEL \
|
| 5 |
+
--w_bit 4 --q_group_size 128 \
|
| 6 |
+
--run_awq --dump_awq awq_cache/$MODEL-w4-g128.pt
|
| 7 |
+
|
| 8 |
+
# evaluate the AWQ quantize model (simulated pseudo quantization)
|
| 9 |
+
python -m awq.entry --model_path /dataset/models/$MODEL \
|
| 10 |
+
--tasks wikitext \
|
| 11 |
+
--w_bit 4 --q_group_size 128 \
|
| 12 |
+
--load_awq awq_cache/$MODEL-w4-g128.pt \
|
| 13 |
+
--q_backend fake
|
| 14 |
+
|
| 15 |
+
# generate real quantized weights (w4)
|
| 16 |
+
python -m awq.entry --model_path /dataset/models/$MODEL \
|
| 17 |
+
--w_bit 4 --q_group_size 128 \
|
| 18 |
+
--load_awq awq_cache/$MODEL-w4-g128.pt \
|
| 19 |
+
--q_backend real --dump_quant quant_cache/$MODEL-w4-g128-awq.pt
|
| 20 |
+
|
| 21 |
+
# load and evaluate the real quantized model (smaller gpu memory usage)
|
| 22 |
+
python -m awq.entry --model_path /dataset/models/$MODEL \
|
| 23 |
+
--tasks wikitext \
|
| 24 |
+
--w_bit 4 --q_group_size 128 \
|
| 25 |
+
--load_quant quant_cache/$MODEL-w4-g128-awq.pt
|
llm-awq/scripts/starcoder_example.sh
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MODEL=starcoder
|
| 2 |
+
|
| 3 |
+
# run AWQ search (optional; we provided the pre-computed results)
|
| 4 |
+
python -m awq.entry --model_path /dataset/starcoder-hf/$MODEL \
|
| 5 |
+
--w_bit 4 --q_group_size 128 \
|
| 6 |
+
--run_awq --dump_awq awq_cache/$MODEL-w4-g128.pt
|
| 7 |
+
|
| 8 |
+
# evaluate the AWQ quantize model (simulated pseudo quantization)
|
| 9 |
+
python -m awq.entry --model_path /dataset/starcoder-hf/$MODEL \
|
| 10 |
+
--tasks wikitext \
|
| 11 |
+
--w_bit 4 --q_group_size 128 \
|
| 12 |
+
--load_awq awq_cache/$MODEL-w4-g128.pt \
|
| 13 |
+
--q_backend fake
|
| 14 |
+
|
| 15 |
+
# generate real quantized weights (w4)
|
| 16 |
+
python -m awq.entry --model_path /dataset/starcoder-hf/$MODEL \
|
| 17 |
+
--w_bit 4 --q_group_size 128 \
|
| 18 |
+
--load_awq awq_cache/$MODEL-w4-g128.pt \
|
| 19 |
+
--q_backend real --dump_quant quant_cache/$MODEL-w4-g128-awq.pt
|
| 20 |
+
|
| 21 |
+
# load and evaluate the real quantized model (smaller gpu memory usage)
|
| 22 |
+
python -m awq.entry --model_path /dataset/starcoder-hf/$MODEL \
|
| 23 |
+
--tasks wikitext \
|
| 24 |
+
--w_bit 4 --q_group_size 128 \
|
| 25 |
+
--load_quant quant_cache/$MODEL-w4-g128-awq.pt
|
llm-awq/scripts/vicuna_example.sh
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MODEL=vicuna-7b
|
| 2 |
+
|
| 3 |
+
# run AWQ search (optional; we provided the pre-computed results)
|
| 4 |
+
python -m awq.entry --model_path /dataset/vicuna-hf/$MODEL \
|
| 5 |
+
--w_bit 4 --q_group_size 128 \
|
| 6 |
+
--run_awq --dump_awq awq_cache/$MODEL-w4-g128.pt
|
| 7 |
+
|
| 8 |
+
# evaluate the AWQ quantize model (simulated pseudo quantization)
|
| 9 |
+
python -m awq.entry --model_path /dataset/vicuna-hf/$MODEL \
|
| 10 |
+
--tasks wikitext \
|
| 11 |
+
--w_bit 4 --q_group_size 128 \
|
| 12 |
+
--load_awq awq_cache/$MODEL-w4-g128.pt \
|
| 13 |
+
--q_backend fake
|
| 14 |
+
|
| 15 |
+
# generate real quantized weights (w4)
|
| 16 |
+
python -m awq.entry --model_path /dataset/vicuna-hf/$MODEL \
|
| 17 |
+
--w_bit 4 --q_group_size 128 \
|
| 18 |
+
--load_awq awq_cache/$MODEL-w4-g128.pt \
|
| 19 |
+
--q_backend real --dump_quant quant_cache/$MODEL-w4-g128-awq.pt
|
| 20 |
+
|
| 21 |
+
# load and evaluate the real quantized model (smaller gpu memory usage)
|
| 22 |
+
python -m awq.entry --model_path /dataset/vicuna-hf/$MODEL \
|
| 23 |
+
--tasks wikitext \
|
| 24 |
+
--w_bit 4 --q_group_size 128 \
|
| 25 |
+
--load_quant quant_cache/$MODEL-w4-g128-awq.pt
|
llm-awq/scripts/vila15_example.sh
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MODEL=VILA1.5-7b
|
| 2 |
+
|
| 3 |
+
# run AWQ search (optional; we provided the pre-computed results)
|
| 4 |
+
# Note: vila checkpoints are now stored in 3 parts.
|
| 5 |
+
# only llm folder will be quantized
|
| 6 |
+
python -m awq.entry --model_path /dataset/vila-hf/$MODEL/llm \
|
| 7 |
+
--w_bit 4 --q_group_size 128 --vila-15 \
|
| 8 |
+
--run_awq --dump_awq awq_cache/$MODEL-w4-g128.pt
|
| 9 |
+
|
| 10 |
+
# generate real quantized weights (w4)
|
| 11 |
+
python -m awq.entry --model_path /dataset/vila-hf/$MODEL/llm \
|
| 12 |
+
--w_bit 4 --q_group_size 128 --vila-15 \
|
| 13 |
+
--load_awq awq_cache/$MODEL-w4-g128.pt \
|
| 14 |
+
--q_backend real --dump_quant /dataset/vila-hf/$MODEL-awq/llm/$MODEL-w4-g128-awq.pt
|
llm-awq/scripts/vila_example.sh
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MODEL=vila-7b
|
| 2 |
+
|
| 3 |
+
# run AWQ search (optional; we provided the pre-computed results)
|
| 4 |
+
python -m awq.entry --model_path /dataset/vila-hf/$MODEL \
|
| 5 |
+
--w_bit 4 --q_group_size 128 \
|
| 6 |
+
--run_awq --dump_awq awq_cache/$MODEL-w4-g128.pt
|
| 7 |
+
|
| 8 |
+
# generate real quantized weights (w4)
|
| 9 |
+
python -m awq.entry --model_path /dataset/vila-hf/$MODEL \
|
| 10 |
+
--w_bit 4 --q_group_size 128 \
|
| 11 |
+
--load_awq awq_cache/$MODEL-w4-g128.pt \
|
| 12 |
+
--q_backend real --dump_quant quant_cache/$MODEL-w4-g128-awq.pt
|
llm-awq/tinychat/README.md
ADDED
|
@@ -0,0 +1,526 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# TinyChat 2.0: Efficient and Lightweight Chatbot with AWQ
|
| 2 |
+
|
| 3 |
+
We introduce TinyChat, a cutting-edge chatbot interface designed for lightweight resource consumption and fast inference speed on GPU platforms. It allows for seamless deployment on consumer-level GPUs such as 3090/4090 and low-power edge devices like the NVIDIA Jetson Orin, empowering users with a responsive conversational experience like never before.
|
| 4 |
+
|
| 5 |
+
The current release supports:
|
| 6 |
+
|
| 7 |
+
- DeepSeek-R1-Distill-Qwen-1.5B/7B
|
| 8 |
+
|
| 9 |
+
- DeepSeek-R1-Distill-Llama-8B
|
| 10 |
+
|
| 11 |
+
- Llama-3-8B/70B-instruct;
|
| 12 |
+
|
| 13 |
+
- NVILA-3B/8B;
|
| 14 |
+
|
| 15 |
+
- VILA-1.5-3B/8B/13B/40B;
|
| 16 |
+
|
| 17 |
+
- VILA-7B/13B;
|
| 18 |
+
|
| 19 |
+
- LLaVA-7B/13B;
|
| 20 |
+
|
| 21 |
+
- Llama-2-7B/13B-chat;
|
| 22 |
+
|
| 23 |
+
- Vicuna;
|
| 24 |
+
|
| 25 |
+
## Contents
|
| 26 |
+
|
| 27 |
+
- [Examples](#examples)
|
| 28 |
+
|
| 29 |
+
- [Benchmarks](#benchmarks)
|
| 30 |
+
|
| 31 |
+
- [Usage](#usage)
|
| 32 |
+
|
| 33 |
+
- [Reference](#reference)
|
| 34 |
+
|
| 35 |
+
## Examples
|
| 36 |
+
|
| 37 |
+
**Thanks to AWQ, TinyChat can now deliver more prompt responses through 4-bit inference. The following examples showcase that TinyChat's W4A16 generation is up to 2.7x faster on RTX 4090 and 2.9x faster on Jetson Orin, compared to the FP16 baselines. (Tested with LLaMA-3-8b model.)**
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
* TinyChat with LLaMA-3-8b on RTX 4090 (2.7x faster than FP16):
|
| 41 |
+
|
| 42 |
+

|
| 43 |
+
|
| 44 |
+
* TinyChat with LLaMA-3-8b on Jetson Orin (2.9x faster than FP16):
|
| 45 |
+
|
| 46 |
+

|
| 47 |
+
|
| 48 |
+
**TinyChat also supports inference with visual language models (e.g., VILA, LLaVA, NVILA). In the following examples, W4A16 quantized models from VILA family are launched with TinyChat.**
|
| 49 |
+
|
| 50 |
+
* TinyChat with NVILA-8B on RTX 4090 (single-image inputs):
|
| 51 |
+
|
| 52 |
+

|
| 53 |
+
|
| 54 |
+
* TinyChat with NVILA-8B on RTX 4090 (multi-image inputs):
|
| 55 |
+
|
| 56 |
+

|
| 57 |
+
|
| 58 |
+
* TinyChat with video reasoning:
|
| 59 |
+
|
| 60 |
+
https://github.com/user-attachments/assets/b68a7a0d-5175-4030-985b-5ae0ae94f874
|
| 61 |
+
|
| 62 |
+
**Prompt:** What might be the next step according to the video?
|
| 63 |
+
|
| 64 |
+
**Answer:** The next step in the video could be to place the shaped dough onto a baking sheet and let it rise before baking.
|
| 65 |
+
|
| 66 |
+
**Online demo:** https://vila.hanlab.ai
|
| 67 |
+
|
| 68 |
+
## Speed Benchmarks
|
| 69 |
+
|
| 70 |
+
We benchmark TinyChat on NVIDIA RTX 4090 (desktop GPU), Orin (edge GPU), and A100 (server-class GPU).
|
| 71 |
+
|
| 72 |
+
We use the default implementation from Huggingface for the FP16 baseline. The INT4 implementation applies AWQ and utilizes our fast W4A16 GPU kernel. We also apply additional optimization techniques in the latest release. For example, we fuse all the operations in MHA/GQA/MQA into a single kernel, and fuse positional embedding kernels into the attention kernel. We also pre-allocate key-value caches to avoid the online memory allocation overhead from Huggingface. For W4A16 GEMM, we introduce FP16 accumulation when applicable for higher throughputs.
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
### Decoding Speed
|
| 76 |
+
|
| 77 |
+
We benchmarked the per-token generation latency for the decoding stage in the following tables.
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
#### RTX 4090 Results
|
| 81 |
+
|
| 82 |
+
| Model | FP16 latency (ms) | INT4 latency (ms) | Speedup |
|
| 83 |
+
| ----------- |:-----------------:|:-----------------:|:-------:|
|
| 84 |
+
| LLaMA-3-8B | 17.07 | 6.39 | 2.69x |
|
| 85 |
+
| LLaMA-2-7B | 15.50 | 5.28 | 2.94x |
|
| 86 |
+
| LLaMA-2-13B | OOM | 9.19 | -- |
|
| 87 |
+
| Vicuna-7B | 15.81 | 5.33 | 2.97x |
|
| 88 |
+
| VILA-7B | 17.09 | 5.95 | 2.87x |
|
| 89 |
+
| VILA-13B | OOM | 10.01 | -- |
|
| 90 |
+
| NVILA-2B | 5.26 | 4.27 | 1.23x |
|
| 91 |
+
| NVILA-8B | 16.12 | 5.97 | 2.70x |
|
| 92 |
+
|
| 93 |
+
*: For the decoding speed of language models, we follow the benchmarking setting from exLLaMA (i.e. only 4 context tokens) for the sake of simplicity and fairness. For multi-modal LMs (VILA and [NVILA](https://arxiv.org/abs/2412.04468)), we benchmark the decoding speed with single image inputs. Specifically, for NVILA, we activate the lite mode during the benchmarking, where each image is correspond to 128 input tokens.
|
| 94 |
+
|
| 95 |
+
<!-- | Model | FP16 latency (ms) | INT4 latency (ms) | Speedup |
|
| 96 |
+
| ----------- |:-----------------:|:-----------------:|:-------:|
|
| 97 |
+
| LLaMA-3-8B | 17.07 | 6.66 | 2.56x |
|
| 98 |
+
| LLaMA-2-7B | 16.17 | 6.02* | 2.68x |
|
| 99 |
+
| LLaMA-2-13B | OOM | 10.35 | -- |
|
| 100 |
+
| Vicuna-7B | 15.81 | 5.33 | 2.97x |
|
| 101 |
+
| Vicuna-13B | OOM | 9.17 | -- |
|
| 102 |
+
| MPT-7B | 17.09 | 6.18 | 2.77x |
|
| 103 |
+
| MPT-30B | OOM | 20.60 | -- |
|
| 104 |
+
| Falcon-7B | 29.91 | 8.02 | 3.73x |
|
| 105 |
+
| VILA-7B | 17.09 | 5.95 | 2.87x |
|
| 106 |
+
| VILA-13B | OOM | 10.01 | -- | -->
|
| 107 |
+
|
| 108 |
+
<!-- *: The reason why LLaMA-2-7B is slower than Vicuna-7B is because we need a longer prompt (with > 500 tokens) to prevent the model from talking with itself. If we use the benchmarking strategy from exLLaMA (i.e. only 4 context tokens), our speed is around 195 tokens / second. -->
|
| 109 |
+
|
| 110 |
+
<!-- ### A6000 Results
|
| 111 |
+
| Model | FP16 latency (ms) | INT4 latency (ms) | Speedup |
|
| 112 |
+
| ----------- |:-----------------:|:-----------------:|:-------:|
|
| 113 |
+
| LLaMA-3-8B | 24.95 | 10.68 | 2.34x |
|
| 114 |
+
| LLaMA-2-7B | 22.75 | 8.71 | 2.61x |
|
| 115 |
+
| LLaMA-2-13B | 41.72 | 14.64 | 2.85x |
|
| 116 |
+
| Vicuna-7B | 22.03 | 8.39 | 2.63x |
|
| 117 |
+
| Vicuna-13B | 38.97 | 13.46 | 2.90x |
|
| 118 |
+
| MPT-7B | 22.79 | 7.99 | 2.85x |
|
| 119 |
+
| MPT-30B | OOM | 28.15 | -- |
|
| 120 |
+
| Falcon-7B | 39.44 | 11.71 | 3.37x |
|
| 121 |
+
| VILA-7B | 23.60 | 8.14 | 2.90x |
|
| 122 |
+
| VILA-13B | 46.58 | 13.74 | 3.39x | -->
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
#### Jetson Orin Results
|
| 126 |
+
|
| 127 |
+
| Model | FP16 latency (ms) | INT4 latency (ms) | Speedup |
|
| 128 |
+
| ----------- |:-----------------:|:-----------------:|:-------:|
|
| 129 |
+
| LLaMA-3-8B | 96.00 | 32.53 | 2.95x |
|
| 130 |
+
| LLaMA-2-7B | 83.95 | 25.94 | 3.24x |
|
| 131 |
+
| LLaMA-2-13B | 162.33 | 47.67 | 3.41x |
|
| 132 |
+
| Vicuna-7B | 84.77 | 26.34 | 3.22x |
|
| 133 |
+
| VILA-7B | 86.95 | 28.09 | 3.10x |
|
| 134 |
+
| VILA-13B | OOM | 57.14 | -- |
|
| 135 |
+
| NVILA-2B | 24.22 | 22.25 | 1.09x |
|
| 136 |
+
| NVILA-8B | 86.24 | 30.48 | 2.83x |
|
| 137 |
+
|
| 138 |
+
<!-- | Model | FP16 latency (ms) | INT4 latency (ms) | Speedup |
|
| 139 |
+
| ----------- |:-----------------:|:-----------------:|:-------:|
|
| 140 |
+
| LLaMA-3-8B | 96.24 | 32.55 | 2.96x |
|
| 141 |
+
| LLaMA-2-7B | 86.80 | 32.14* | 2.70x |
|
| 142 |
+
| LLaMA-2-13B | OOM | 58.20 | -- |
|
| 143 |
+
| Vicuna-7B | 84.77 | 30.73 | 2.76x |
|
| 144 |
+
| Vicuna-13B | OOM | 54.98 | -- |
|
| 145 |
+
| MPT-7B | 89.85 | 31.22 | 2.88x |
|
| 146 |
+
| Falcon-7B | 147.84 | 45.10 | 3.28x |
|
| 147 |
+
| VILA-7B | 86.95 | 28.09 | 3.10x |
|
| 148 |
+
| VILA-13B | OOM | 57.14 | -- |
|
| 149 |
+
|
| 150 |
+
*: We can similarly achieve 33 tokens / second on Orin if we use the benchmarking strategy from exLLaMA. -->
|
| 151 |
+
|
| 152 |
+
#### A100 Results
|
| 153 |
+
|
| 154 |
+
| Model | FP16 latency (ms) | INT4 latency (ms) | Speedup |
|
| 155 |
+
| ----------- |:-----------------:|:-----------------:|:-------:|
|
| 156 |
+
| LLaMA-3-8B | 12.37 | 6.29 | 1.96x |
|
| 157 |
+
| LLaMA-2-7B | 10.77 | 5.71 | 1.89x |
|
| 158 |
+
| LLaMA-2-13B | 19.08 | 7.90 | 2.41x |
|
| 159 |
+
| Vicuna-7B | 10.54 | 5.87 | 1.80x |
|
| 160 |
+
| VILA-7B | 13.35 | 5.92 | 2.26x |
|
| 161 |
+
| VILA-13B | 19.64 | 8.63 | 2.28x |
|
| 162 |
+
| NVILA-2B | 7.03 | 5.38 | 1.31x |
|
| 163 |
+
| NVILA-8B | 11.90 | 5.50 | 2.16x |
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
### Prefilling Speed
|
| 167 |
+
|
| 168 |
+
In TinyChat 2.0, we also introduce significant prefilling speed optimizations for Large Language Models (LLMs) and Visual Language Models (VLMs). Specifically, with the integration of latest flash attention and FP16 accumulation in GEMM kernels, TinyChat now achieves state-of-the-art prefilling speed on edge devices.
|
| 169 |
+
|
| 170 |
+
#### RTX 4090 Results
|
| 171 |
+
|
| 172 |
+
Time-To-First-Token (TTFT) of Llama-3-8B (Unit: Seconds):
|
| 173 |
+
|
| 174 |
+
| Seq Len | 256 | 512 | 1024 | 2048 | 3072 | 4096 |
|
| 175 |
+
| ----------- |:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|
|
| 176 |
+
| FP16 | 0.031 | 0.055 | 0.109 | 0.211 | 0.336 | 0.446 |
|
| 177 |
+
| TinyChat | 0.021 | 0.033 | 0.064 | 0.131 | 0.200 | 0.275 |
|
| 178 |
+
| Speedup | 1.52x | 1.68x | 1.69x | 1.61x | 1.68x | 1.62x |
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
Time-To-First-Token (TTFT) of Llama-2-7B (Unit: Seconds):
|
| 182 |
+
|
| 183 |
+
| Seq Len | 256 | 512 | 1024 | 2048 | 3072 | 4096 |
|
| 184 |
+
| ----------- |:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|
|
| 185 |
+
| FP16 | 0.029 | 0.058 | 0.100 | 0.211 | 0.329 | 0.441 |
|
| 186 |
+
| TinyChat | 0.018 | 0.031 | 0.060 | 0.124 | 0.193 | 0.265 |
|
| 187 |
+
| Speedup | 1.57x | 1.83x | 1.66x | 1.70x | 1.70x | 1.66x |
|
| 188 |
+
|
| 189 |
+
|
| 190 |
+
#### Jetson Orin Results
|
| 191 |
+
|
| 192 |
+
Time-To-First-Token (TTFT) of Llama-3-8B (Unit: Seconds):
|
| 193 |
+
|
| 194 |
+
| Seq Len | 256 | 512 | 1024 | 2048 | 3072 | 4096 |
|
| 195 |
+
| ----------- |:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|
|
| 196 |
+
| FP16 | 0.206 | 0.399 | 0.566 | 1.519 | 2.308 | 3.114 |
|
| 197 |
+
| TinyChat | 0.166 | 0.315 | 0.623 | 1.248 | 1.907 | 2.573 |
|
| 198 |
+
| Speedup | 1.24x | 1.26x | 0.91x | 1.22x | 1.21x | 1.21x |
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
#### Comparison with Other Systems
|
| 202 |
+
|
| 203 |
+
Time-To-First-Token (TTFT) of 4-bit weight-only quantized Llama3-8B on RTX 4090 across various systems (Unit: Seconds):
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
| Seq Len | 256 | 512 | 1024 | 2048 | 4096 |
|
| 207 |
+
|:-------------------:|:-----:|:-----:|:-----:|:-----:|:------:|
|
| 208 |
+
| TensorRT-LLM | 0.027 | 0.051 | 0.100 | 0.204 | 0.421 |
|
| 209 |
+
| MLC | 0.028 | 0.042 | 0.081 | 0.166 | 0.350 |
|
| 210 |
+
| llama.cpp | 0.026 | 0.045 | 0.086 | 0.175 | 0.375 |
|
| 211 |
+
| ExLlama v2 | 0.040 | 0.051 | 0.077 | 0.139 | 0.294 |
|
| 212 |
+
| TinyChat (Legacy) | 0.031 | 0.051 | 0.101 | 0.219 | 0.461 |
|
| 213 |
+
| TinyChat 2.0 | 0.021 | 0.033 | 0.065 | 0.132 | 0.278 |
|
| 214 |
+
|
| 215 |
+
Our approach outperforms all existing projects, achieving state-of-the-art speed.
|
| 216 |
+
|
| 217 |
+
### Context Streaming: Efficient Multi-round Dialogues
|
| 218 |
+
|
| 219 |
+
In TinyChat 2.0, we introduce chunk-prefilling optimization for multi-round dialogues. For multi-turn inputs, TinyChat will reuse the KV Cache from previous conversations without recomputing them. This optimization eliminates redundant computations and significantly reduce the Time To First Token (TTFT) for subsequent interaction rounds.
|
| 220 |
+
|
| 221 |
+
#### RTX 4090 Results
|
| 222 |
+
|
| 223 |
+
To evaluate Context Streaming, we measure the TTFT in multi-round conversations with a fixed question length of 32 tokens, and varying history lengths from 16 to 1024 tokens. Specifically, in TinyChat 2.0, all history tokens are already prefilled to the existing KV Cache when processing the current query, while baseline systems recompute the history tokens for each query.
|
| 224 |
+
|
| 225 |
+
<!-- To demonstrate the effectiveness of Context Streaming, we measure the TTFT in multi-round conversation with a fixed question length of 32 and varying history lengths ranging from 16 to 1024 tokens. This setup means that a number of history tokens (based on the specified history length) are already input into the model. In this round, the question tokens (32 tokens) are also input, and the model takes TTFT to process these question tokens, prefill the KV cache, and generate the first token. All the tables below follows this setting. The speedup ratio in all the tables below refer to the acceleration achieved by the new method compared to FP16 inference. -->
|
| 226 |
+
|
| 227 |
+
Time-To-First-Token (TTFT) of Llama-3-8B (Unit: ms):
|
| 228 |
+
|
| 229 |
+
| History length | 16 | 32 | 64 | 128 | 256 | 512 | 1024 |
|
| 230 |
+
|---------------------------|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|:------:|
|
| 231 |
+
| FP16 | 21.49 | 21.38 | 23.51 | 40.82 | 47.15 | 75.41 | 162.27 |
|
| 232 |
+
| TinyChat (Legacy) | 15.20 | 14.89 | 17.61 | 29.66 | 44.11 | 72.50 | 163.90 |
|
| 233 |
+
| TinyChat 2.0 | 14.30 | 14.05 | 14.05 | 14.43 | 14.38 | 14.35 | 14.49 |
|
| 234 |
+
| Speedup | 1.54x | 1.54x | 1.69x | 2.84x | 3.33x | 5.27x | 11.45x |
|
| 235 |
+
|
| 236 |
+
<!-- Time-To-First-Token (TTFT) of VILA-1.5-8B (Unit: ms):
|
| 237 |
+
|
| 238 |
+
| History length | 16 | 32 | 64 | 128 | 256 | 512 | 1024 |
|
| 239 |
+
|---------------------------|:-----:|:-----:|:-----:|:-----:|:-----:|:------:|:------:|
|
| 240 |
+
| FP16 TTFT (ms) | 22.20 | 22.00 | 24.17 | 41.85 | 62.97 | 101.84 | 217.57 |
|
| 241 |
+
| Legacy TinyChat TTFT (ms) | 16.14 | 15.98 | 18.28 | 30.72 | 59.67 | 98.52 | 219.19 |
|
| 242 |
+
| New TinyChat TTFT (ms) | 14.86 | 14.69 | 14.64 | 14.90 | 14.91 | 14.95 | 14.90 |
|
| 243 |
+
| New TinyChat Speedup | 1.49x | 1.50x | 1.65x | 2.81x | 4.22x | 6.81x | 14.60x |
|
| 244 |
+
|
| 245 |
+
NOTE: [TODO] @Yuming. The current setting is too complicated. Let's consider the case: each round, there is an image input. Baseline need to re-encode every image, while tinychat only need to encode 1 image.
|
| 246 |
+
|
| 247 |
+
*: For Visual Language Models, the speedup of Context Streaming is more significant, since the model only decodes images during the first round. In the experiment, We assume that approximately 75% of the history tokens represent images, leading to the number of images in the table being 0, 0, 0, 0, 1, 2, 4. This assumption is reasonable to some extent, considering that a single image is decoded into 196 tokens. -->
|
| 248 |
+
|
| 249 |
+
|
| 250 |
+
|
| 251 |
+
<!-- We have optimized the speed of the context stage and updated our code with several enhancements, including the adoption of FlashAttention and the elimination of redundant computations. The key optimizations include:
|
| 252 |
+
1. Adopting the FlashAttention kernel. (Currently we only support single-batch operations to achieve better results)
|
| 253 |
+
2. Computing only the last tokens in the final logits layer. (This method is used by default.)
|
| 254 |
+
3. Utilizing history KV caches in the context stage to speed up. (chunk prefilling) -->
|
| 255 |
+
|
| 256 |
+
<!-- These optimizations are orthogonal, enabling their combined application to achieve significant speedups. Under specific conditions, these enhancements can lead to up to an 14x speedup on 4090 GPUs and an 8x speedup on Orin GPUs in Time To First Token (TTFT) compared to the previous version of TinyChat and FP16. We conducted experiments using both Orin and 4090 GPUs, and detailed results are presented below. -->
|
| 257 |
+
|
| 258 |
+
|
| 259 |
+
<!-- ### Orin Results
|
| 260 |
+
We follow the setup above and the results are as below.
|
| 261 |
+
#### Llama-3-8B
|
| 262 |
+
| History length | 16 | 32 | 64 | 128 | 256 | 512 | 1024 |
|
| 263 |
+
|---------------------------|:------:|:------:|:------:|:------:|:------:|:------:|:-------:|
|
| 264 |
+
| FP16 TTFT (ms) | 107.10 | 108.81 | 114.07 | 224.78 | 343.95 | 582.54 | 1048.11 |
|
| 265 |
+
| Legacy TinyChat TTFT (ms) | 92.04 | 111.31 | 106.60 | 160.78 | 278.47 | 528.70 | 1145.35 |
|
| 266 |
+
| New TinyChat TTFT (ms) | 65.57 | 65.40 | 66.49 | 67.15 | 73.29 | 84.67 | 118.53 |
|
| 267 |
+
| New TinyChat Speedup | 1.52x | 1.65x | 1.70x | 3.30x | 4.51x | 6.75x | 8.65x | -->
|
| 268 |
+
|
| 269 |
+
|
| 270 |
+
## Accuracy Evaluation
|
| 271 |
+
|
| 272 |
+
|
| 273 |
+
AWQ also achieves decent performance on the Visual Language Models. We evaluate AWQ on VILA and the lastest NVILA models.
|
| 274 |
+
|
| 275 |
+
| NVILA-8B | AI2D | ChartQA | DocVQA | MMMU_val | SEED | TextVQA | VideoMME |
|
| 276 |
+
| ---------- |:----------:|:----------:|:----------:|:----------:|:----------:|:----------:|:----------:|
|
| 277 |
+
| FP16 | 91.0 | 84.8 | 91.7 | 50.7 | 76.3 | 78.1 | 63.9 |
|
| 278 |
+
| AWQ-INT4 | 90.9 | 83.3 | 89.2 | 49.3 | 76.2 | 78.2 | 62.1 |
|
| 279 |
+
|
| 280 |
+
<!--
|
| 281 |
+
| NVILA-8B | AI2D | ChartQA | DocVQA | MMMU_val | SEED | TextVQA | VideoMME-Short | VideoMME-Medium | VideoMME-Long | VideoMME-Overall |
|
| 282 |
+
| ---------- |:----------:|:----------:|:----------:|:----------:|:----------:|:----------:|:----------:|:----------:|:----------:|:----------:|
|
| 283 |
+
| FP16 | 91.0 | 84.8 | 91.7 | 50.7 | 76.3 | 78.1 | 74.9 | 62.1 | 54.7 | 63.9 |
|
| 284 |
+
| AWQ-INT4 | 90.9 | 83.3 | 89.2 | 49.3 | 76.2 | 78.2 | 73.2 | 61.3 | 51.6 | 62.1 | -->
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
|
| 288 |
+
| VILA-1.5-3B | VQA-v2 | GQA | VizWiz | ScienceQA | TextVQA | POPE | MME | MMBench | MMBench-CN | SEED |
|
| 289 |
+
| ----------- |:-----------------:|:-----------------:|:-------:|:-----------------:|:-----------------:|:-------:|:-------:|:-----------------:|:-------------:|:-------:|
|
| 290 |
+
| FP16 | 80.4 | 61.5 | 53.5 | 69.0 | 60.4 | 85.9 | 1442.4 | 63.4 | 52.7 | 60.9 |
|
| 291 |
+
| AWQ-INT4 | 80.0 | 61.1 | 53.8 | 67.8 | 60.4 | 85.9 | 1437.3 | 63.3 | 51.4 | 59.8 |
|
| 292 |
+
|
| 293 |
+
| VILA-1.5-8B | VQA-v2 | GQA | VizWiz | ScienceQA | TextVQA | POPE | MME | MMBench | MMBench-CN | SEED |
|
| 294 |
+
| ----------- |:-----------------:|:-----------------:|:-------:|:-----------------:|:-----------------:|:-------:|:-------:|:-----------------:|:-------------:|:-------:|
|
| 295 |
+
| FP16 | 80.9 | 61.9 | 58.7 | 79.9 | 66.3 | 84.4 | 1577.01 | 72.3 | 66.2 | 64.2 |
|
| 296 |
+
| AWQ-INT4 | 80.3 | 61.7 | 59.3 | 79.0 | 65.4 | 82.9 | 1593.65 | 71.0 | 64.9 | 64.0 |
|
| 297 |
+
|
| 298 |
+
| VILA-1.5-13B | VQA-v2 | GQA | VizWiz | ScienceQA | TextVQA | POPE | MME | MMBench | MMBench-CN | SEED |
|
| 299 |
+
| ----------- |:-----------------:|:-----------------:|:-------:|:-----------------:|:-----------------:|:-------:|:-------:|:-----------------:|:-------------:|:-------:|
|
| 300 |
+
| FP16 | 82.8 | 64.3 | 62.6 | 80.1 | 65.0 | 86.3 | 1569.55 | 74.9 | 66.3 | 65.1 |
|
| 301 |
+
| AWQ-INT4 | 82.7 | 64.5 | 63.3 | 79.7 | 64.7 | 86.7 | 1531.35 | 74.7 | 66.7 | 65.1 |
|
| 302 |
+
|
| 303 |
+
|
| 304 |
+
| VILA-1.5-40B | VQA-v2 | GQA | VizWiz | ScienceQA | TextVQA | POPE | MME | MMBench | MMBench-CN | SEED |
|
| 305 |
+
| ----------- |:-----------------:|:-----------------:|:-------:|:-----------------:|:-----------------:|:-------:|:-------:|:-----------------:|:-------------:|:-------:|
|
| 306 |
+
| FP16 | 84.3 | 64.6 | 62.2 | 87.2 | 73.6 | 87.3 | 1726.82 | 82.4 | 80.2 | 69.1 |
|
| 307 |
+
| AWQ-INT4 | 84.1 | 64.4 | 61.3 | 86.7 | 73.2 | 88.2 | 1714.79 | 83.2 | 79.6 | 68.9 |
|
| 308 |
+
|
| 309 |
+
AWQ has also demonstrated impressive performance on inference benchmarks, maintaining strong accuracy across a range of reasoning tasks.
|
| 310 |
+
|
| 311 |
+
| DeepSeek-R1-Distill-Llama-8B | WikiText perplexity | AIME 2024 | Math-500 |
|
| 312 |
+
| ---------------------------- |:-------------------:|:-------------------:|:-------------------:|
|
| 313 |
+
| FP16 | 13.13 | 43.33% | 83.00% |
|
| 314 |
+
| AWQ-INT4 | 13.84 | 43.33% | 84.40% |
|
| 315 |
+
|
| 316 |
+
| DeepSeek-R1-Distill-Qwen-7B | WikiText perplexity | AIME 2024 | Math-500 |
|
| 317 |
+
| --------------------------- |:-------------------:|:-------------------:|:-------------------:|
|
| 318 |
+
| FP16 | 25.06 | 53.33% | 91.40% |
|
| 319 |
+
| AWQ-INT4 | 27.45 | 53.33% | 89.60% |
|
| 320 |
+
|
| 321 |
+
## Usage
|
| 322 |
+
|
| 323 |
+
1. Please follow the [AWQ installation guidance](https://github.com/mit-han-lab/llm-awq#readme) to install AWQ and its dependencies. If you want to use FlashAttention, start by installing it with: ```pip install flash-attn --no-build-isolation```. However, for some GPUs such as Jetson Orin, there is no pre-built version available. You will need to build it from source. Follow these commands:
|
| 324 |
+
```bash
|
| 325 |
+
git clone https://github.com/Dao-AILab/flash-attention.git
|
| 326 |
+
cd flash-attention
|
| 327 |
+
sed -i '168 a\ cc_flag.append("-gencode")\n\ cc_flag.append("arch=compute_87,code=sm_87")' setup.py
|
| 328 |
+
python setup.py install
|
| 329 |
+
```
|
| 330 |
+
This process may take some time as it involves compiling the code. Additionally, please note that these commands are just for Jetson Orin GPUs, whose CUDA compute capability is 87. For other GPUs, you may use ```nvidia-smi --query-gpu=compute_cap --format=csv``` to get the compute capability and merely change '87' to that.
|
| 331 |
+
|
| 332 |
+
2. Download the pretrained instruction-tuned LLMs:
|
| 333 |
+
|
| 334 |
+
- For LLaMA-2-chat, please refer to [this link](https://huggingface.co/meta-llama/Llama-2-7b-chat-hf);
|
| 335 |
+
|
| 336 |
+
- For Vicuna, please refer to [this link](https://huggingface.co/lmsys/);
|
| 337 |
+
|
| 338 |
+
- For MPT-chat, please refer to [this link](https://huggingface.co/mosaicml/mpt-7b-chat);
|
| 339 |
+
|
| 340 |
+
- For Falcon-instruct, please refer to [this link](https://huggingface.co/tiiuae/falcon-7b-instruct).
|
| 341 |
+
|
| 342 |
+
3. Quantize instruction-tuned LLMs with AWQ:
|
| 343 |
+
- We provide pre-computed AWQ search results for multiple model families, including LLaMA, OPT, Vicuna, VILA, and LLaVA. To get the pre-computed AWQ search results, run:
|
| 344 |
+
|
| 345 |
+
```bash
|
| 346 |
+
# git lfs install # install git lfs if not already
|
| 347 |
+
git clone https://huggingface.co/datasets/mit-han-lab/awq-model-zoo awq_cache
|
| 348 |
+
```
|
| 349 |
+
|
| 350 |
+
- You may run a one-line starter below:
|
| 351 |
+
|
| 352 |
+
```bash
|
| 353 |
+
./scripts/llama2_demo.sh
|
| 354 |
+
```
|
| 355 |
+
|
| 356 |
+
Alternatively, you may go through the process step by step. We will demonstrate the quantization process with LLaMA-2. For all other models except Falcon, one only needs to change the `model_path` and saving locations. For Falcon-7B, we also need to change `q_group_size` from 128 to 64.
|
| 357 |
+
|
| 358 |
+
- Perform AWQ search and save search results (we already did it for you):
|
| 359 |
+
|
| 360 |
+
```bash
|
| 361 |
+
mkdir awq_cache
|
| 362 |
+
python -m awq.entry --model_path /PATH/TO/LLAMA2/llama-2-7b-chat \
|
| 363 |
+
--w_bit 4 --q_group_size 128 \
|
| 364 |
+
--run_awq --dump_awq awq_cache/llama-2-7b-chat-w4-g128.pt
|
| 365 |
+
```
|
| 366 |
+
|
| 367 |
+
- Generate real quantized weights (INT4):
|
| 368 |
+
|
| 369 |
+
```bash
|
| 370 |
+
mkdir quant_cache
|
| 371 |
+
python -m awq.entry --model_path /PATH/TO/LLAMA2/llama-2-7b-chat \
|
| 372 |
+
--w_bit 4 --q_group_size 128 \
|
| 373 |
+
--load_awq awq_cache/llama-2-7b-chat-w4-g128.pt \
|
| 374 |
+
--q_backend real --dump_quant quant_cache/llama-2-7b-chat-w4-g128-awq.pt
|
| 375 |
+
```
|
| 376 |
+
|
| 377 |
+
4. Run the TinyChat demo:
|
| 378 |
+
|
| 379 |
+
```bash
|
| 380 |
+
cd tinychat
|
| 381 |
+
python demo.py --model_type llama \
|
| 382 |
+
--model_path /PATH/TO/LLAMA2/llama-2-7b-chat \
|
| 383 |
+
--q_group_size 128 --load_quant quant_cache/llama-2-7b-chat-w4-g128-awq.pt \
|
| 384 |
+
--precision W4A16
|
| 385 |
+
```
|
| 386 |
+
|
| 387 |
+
Note: if you use Falcon-7B-instruct, please remember to also change `q_group_size` to 64. You may also run the following command to execute the chatbot in FP16 to compare the speed and quality of language generation:
|
| 388 |
+
|
| 389 |
+
```bash
|
| 390 |
+
python demo.py --model_type llama \
|
| 391 |
+
--model_path /PATH/TO/LLAMA2/llama-2-7b-chat \
|
| 392 |
+
--precision W16A16
|
| 393 |
+
```
|
| 394 |
+
You can now try using FlashAttention along with chunk prefilling. Use the following two arguments when running demo: ```
|
| 395 |
+
--flash --chunk_prefilling```.
|
| 396 |
+
|
| 397 |
+
The above command works well for most cloud and desktop GPUs, since their CPU and GPU memory space are separated. However, for edge GPUs with shared host and device memory, in order to run larger models (e.g. LLaMA-2-70B on 64GB Orin), it is necessary to break down the pretrained checkpoints into small pieces:
|
| 398 |
+
|
| 399 |
+
```bash
|
| 400 |
+
python split_ckpt.py --input_path quant_cache/llama-2-7b-chat-w4-g128-awq.pt \
|
| 401 |
+
--output_path quant_cache/llama-2-7b-chat-w4-g128-awq
|
| 402 |
+
```
|
| 403 |
+
|
| 404 |
+
Then, to run the demo, one can use the following command. The only changes compared with the demo command above are:
|
| 405 |
+
|
| 406 |
+
- We modify the `load_quant` argument;
|
| 407 |
+
|
| 408 |
+
- We introduce another flag `mem_efficient_load`.
|
| 409 |
+
|
| 410 |
+
```bash
|
| 411 |
+
cd tinychat
|
| 412 |
+
python demo.py --model_type llama \
|
| 413 |
+
--model_path /PATH/TO/LLAMA2/llama-2-7b-chat \
|
| 414 |
+
--q_group_size 128 --load_quant quant_cache/llama-2-7b-chat-w4-g128-awq \
|
| 415 |
+
--precision W4A16 --mem_efficient_load
|
| 416 |
+
```
|
| 417 |
+
|
| 418 |
+
5. (Optional) Run the benchmark script to get TTFT and decoding throughput:
|
| 419 |
+
|
| 420 |
+
```bash
|
| 421 |
+
cd tinychat
|
| 422 |
+
python benchmark.py --flash \
|
| 423 |
+
--context_length 16 32 64 128 256 512 1024 2048 \
|
| 424 |
+
--model_path /PATH/TO/LLAMA2/llama-2-7b-chat --precision W4A16
|
| 425 |
+
```
|
| 426 |
+
To benchmark chunk prefilling, use:
|
| 427 |
+
```bash
|
| 428 |
+
python benchmark.py --chunk_prefilling \
|
| 429 |
+
--model_path /PATH/TO/LLAMA2/llama-2-7b-chat \
|
| 430 |
+
--question_length 32 --context_length 16 32 64 128 256 512 1024 --precision W4A16
|
| 431 |
+
```
|
| 432 |
+
Note: The kv caches in the current implementation are pre-allocated. So if you run out of memory, it might be the case that the kv cache is too large. To solve the problem, you may pass in `--max_seq_len [a smaller number]`.
|
| 433 |
+
### Support Visual Language Models (VILA-1.5, VILA, LLaVA, NVILA)
|
| 434 |
+
|
| 435 |
+
Our TinyChat also supports visual language models. Follow the instructions below to run VLMs on your own devices!
|
| 436 |
+
|
| 437 |
+
Step 1-3 are same as the deployment for Language-only models.
|
| 438 |
+
|
| 439 |
+
1. Follow the [AWQ installation guidance](https://github.com/mit-han-lab/llm-awq#readme) to install AWQ and its dependencies.
|
| 440 |
+
|
| 441 |
+
2. Download the pretrained VLMs (VILA).
|
| 442 |
+
|
| 443 |
+
3. Quantize the VLMs with AWQ and get the quantized checkpoint in `quant_cache`. We also provide a [sample script](../scripts/vila_example.sh) for this step.
|
| 444 |
+
|
| 445 |
+
4. Run the TinyChat demo for VLMs (with vila15_demo.py for VILA-1.5, vila10_demo.py for VILA and LLaVA):
|
| 446 |
+
|
| 447 |
+
```bash
|
| 448 |
+
cd tinychat
|
| 449 |
+
python vila15_demo.py \
|
| 450 |
+
--model-path /PATH/TO/VILA/VILA-1.5-13B \
|
| 451 |
+
--quant-path quant_cache/vila-1.5-13b-w4-g128-awq.pt \
|
| 452 |
+
--precision W4A16 \
|
| 453 |
+
--image-file /PATH/TO/INPUT/IMAGE \
|
| 454 |
+
--vis-image #Optional
|
| 455 |
+
```
|
| 456 |
+
|
| 457 |
+
Alternatively, one may also skip the quantization process and directy download the quantized VILA-1.5 checkpoints from [here](https://huggingface.co/Efficient-Large-Model). Take VILA-1.5-13B as an example, after running:
|
| 458 |
+
|
| 459 |
+
```bash
|
| 460 |
+
cd tinychat
|
| 461 |
+
git clone https://huggingface.co/Efficient-Large-Model/VILA1.5-13b-AWQ
|
| 462 |
+
```
|
| 463 |
+
|
| 464 |
+
One may run:
|
| 465 |
+
```bash
|
| 466 |
+
python vila15_demo.py \
|
| 467 |
+
--model-path VILA1.5-13b-AWQ \
|
| 468 |
+
--quant-path VILA1.5-13b-AWQ/llm \
|
| 469 |
+
--precision W4A16 \
|
| 470 |
+
--image-file /PATH/TO/INPUT/IMAGE \
|
| 471 |
+
--vis-image #Optional
|
| 472 |
+
```
|
| 473 |
+
|
| 474 |
+
to run the terminal demo directly. You can also use``` --flash --chunk_prefilling``` to accelerate. We also support context stage benckmarking for VILA.
|
| 475 |
+
```bash
|
| 476 |
+
python benchmark_context.py --flash --chunk_prefilling \
|
| 477 |
+
--model_path PATH/TO/Llama-3-VILA1.5-8B \
|
| 478 |
+
--question_length 32 --context_length 16 32 64 128 256 512 1024 \
|
| 479 |
+
--model_type vila --quant
|
| 480 |
+
```
|
| 481 |
+
Note: if you enable `--vis-image` mode, TinyChat will print input images directly in your terminal. You may need to install [termvisage](https://github.com/AnonymouX47/termvisage) to enable this mode. A [terminal emulator](https://github.com/AnonymouX47/termvisage?tab=readme-ov-file#requirements) is also required.
|
| 482 |
+
|
| 483 |
+
Note: VILA model family supports multi-image inputs. You can input multiple images in `/PATH/TO/INPUT/IMAGE` above, each image should be seperated by `,`.
|
| 484 |
+
|
| 485 |
+
5. TinyChat support NVILA now! We adopt W8A8 SmoothQuant for VisionTower and W4A16 quantization for LLM, achieving 1.3x -3.3x speedup for prefiling satge and nearly 1.5x higher throughput. You can use the commands below to prepare the your model and try four basic tasks of NVILA-video model.
|
| 486 |
+
To prepared the needed act scale for awq and smoothquant, please run:
|
| 487 |
+
```bash
|
| 488 |
+
python -m awq.entry --model_path PATH/TO/NVILA \
|
| 489 |
+
--smooth_scale --media_path https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen2-VL/space_woaudio.mp4 \
|
| 490 |
+
--act_scale_path awq_cache/NVILA-VT-smooth-scale.pt --vila-20 \
|
| 491 |
+
--w_bit 4 --q_group_size 128 \
|
| 492 |
+
--run_awq --dump_awq awq_cache/NVILA.pt
|
| 493 |
+
```
|
| 494 |
+
Then, please generate real quantized LLM with:
|
| 495 |
+
```bash
|
| 496 |
+
python -m awq.entry --model_path PATH/TO/NVILA/llm \
|
| 497 |
+
--w_bit 4 --q_group_size 128 \
|
| 498 |
+
--load_awq awq_cache/NVILA.pt \
|
| 499 |
+
--q_backend real --dump_quant quant_cache/NVILA-w4-g128-awq.pt --vila-20
|
| 500 |
+
```
|
| 501 |
+
Next, try chatting with it using the command below to experience shorter Time To First Token (TTFT) and higher decoding throughput.
|
| 502 |
+
```bash
|
| 503 |
+
python nvila_demo.py --model-path EPATH/TO/NVILA \
|
| 504 |
+
--quant_path PATH/TO/NVILA-w4-g128-v2.pt \
|
| 505 |
+
--media PATH/TO/MEDIA \
|
| 506 |
+
--act_scale_path PATH/TO/NVILA-smooth-scale.pt \
|
| 507 |
+
--quant_llm --chunk --model_type nvila
|
| 508 |
+
```
|
| 509 |
+
|
| 510 |
+
|
| 511 |
+
## Team
|
| 512 |
+
|
| 513 |
+
TinyChat is developed by the following wonderful team:
|
| 514 |
+
|
| 515 |
+
- [Shang Yang](https://ys-2020.github.io/): Project Lead, TinyChat v1 and v2 Lead;
|
| 516 |
+
- [Haotian Tang](http://kentang.net): Project Lead, TinyChat v1 Lead, v2 Mentor;
|
| 517 |
+
- [Yuming Lou](<>): TinyChat v2 Lead;
|
| 518 |
+
- [Junxian Guo](<>): TinyChat v2 Contributor;
|
| 519 |
+
- [Song Han](https://hanlab.mit.edu/songhan): Project Advisor.
|
| 520 |
+
|
| 521 |
+
Credits also go to AWQ algorithm leads: [Ji Lin](https://www.linji.me/) and [Jiaming Tang](https://jiamingtang.me/).
|
| 522 |
+
|
| 523 |
+
## Reference
|
| 524 |
+
|
| 525 |
+
TinyChat is inspired by the following open-source projects: [FasterTransformer](https://github.com/NVIDIA/FasterTransformer), [FlashAttention](https://github.com/Dao-AILab/flash-attention), [vLLM](https://github.com/vllm-project/vllm), [FastChat](https://github.com/lm-sys/FastChat), [llama_cu_awq](https://github.com/ankan-ban/llama_cu_awq), [LLaVA](https://github.com/haotian-liu/LLaVA), [termvisage](https://github.com/AnonymouX47/termvisage).
|
| 526 |
+
|
llm-awq/tinychat/benchmark.py
ADDED
|
@@ -0,0 +1,379 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Usage:
|
| 2 |
+
# Please first install awq/kernels
|
| 3 |
+
# then directly run CUDA_VISIBLE_DEVICES=0 python benchmark.py
|
| 4 |
+
import argparse
|
| 5 |
+
import torch
|
| 6 |
+
import time
|
| 7 |
+
import numpy as np
|
| 8 |
+
from transformers import AutoTokenizer, AutoModelForCausalLM, AutoConfig, modeling_utils
|
| 9 |
+
import tinychat.utils.constants
|
| 10 |
+
from tinychat.utils.load_quant import load_awq_model
|
| 11 |
+
from awq.quantize.quantizer import real_quantize_model_weight
|
| 12 |
+
from tinychat.utils.tune import (
|
| 13 |
+
tune_all_wqlinears,
|
| 14 |
+
device_warmup,
|
| 15 |
+
tune_llava_patch_embedding,
|
| 16 |
+
)
|
| 17 |
+
from tinychat.modules import make_quant_norm, make_quant_attn, make_fused_mlp
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def skip(*args, **kwargs):
|
| 21 |
+
pass
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def main():
|
| 25 |
+
parser = argparse.ArgumentParser()
|
| 26 |
+
parser.add_argument(
|
| 27 |
+
"--model_type", type=str, default="LLaMa", help="type of the model"
|
| 28 |
+
)
|
| 29 |
+
parser.add_argument(
|
| 30 |
+
"--model_path",
|
| 31 |
+
type=str,
|
| 32 |
+
default="/data/llm/checkpoints/vicuna-hf/vicuna-7b",
|
| 33 |
+
help="path to the model",
|
| 34 |
+
)
|
| 35 |
+
parser.add_argument("--q_group_size", type=int, default=128)
|
| 36 |
+
parser.add_argument(
|
| 37 |
+
"--verbose",
|
| 38 |
+
default=False,
|
| 39 |
+
action="store_true",
|
| 40 |
+
help="Wheter to print more information.",
|
| 41 |
+
)
|
| 42 |
+
parser.add_argument(
|
| 43 |
+
"--max_seq_len",
|
| 44 |
+
type=int,
|
| 45 |
+
default=8192,
|
| 46 |
+
help="maximum sequence length for kv cache",
|
| 47 |
+
)
|
| 48 |
+
parser.add_argument(
|
| 49 |
+
"--max_batch_size", type=int, default=1, help="maximum batch size for kv cache"
|
| 50 |
+
)
|
| 51 |
+
parser.add_argument(
|
| 52 |
+
"--flash_attn",
|
| 53 |
+
action="store_true",
|
| 54 |
+
help="whether to use flash attention",
|
| 55 |
+
)
|
| 56 |
+
parser.add_argument(
|
| 57 |
+
"--chunk_prefilling",
|
| 58 |
+
action="store_true",
|
| 59 |
+
help="If used, in context stage, the history tokens will not be recalculated, greatly speeding up the calculation",
|
| 60 |
+
)
|
| 61 |
+
parser.add_argument(
|
| 62 |
+
"--context_length",
|
| 63 |
+
type=list,
|
| 64 |
+
nargs="+",
|
| 65 |
+
help="The length of input. And if chunk_prefilling used, this serves as the length of tokens from history rounds.",
|
| 66 |
+
)
|
| 67 |
+
parser.add_argument(
|
| 68 |
+
"--question_length",
|
| 69 |
+
type=list,
|
| 70 |
+
nargs="+",
|
| 71 |
+
help="The length of new input. Only useful and necessary when benchmarking chunk_prefilling method",
|
| 72 |
+
)
|
| 73 |
+
parser.add_argument(
|
| 74 |
+
"--precision", type=str, default="W4A16", help="compute precision"
|
| 75 |
+
)
|
| 76 |
+
args = parser.parse_args()
|
| 77 |
+
# some checks
|
| 78 |
+
assert (args.question_length is not None and args.chunk_prefilling) or (
|
| 79 |
+
not args.chunk_prefilling
|
| 80 |
+
), "If you want to benchmark chunk prefilling, you need specify the question length and context length"
|
| 81 |
+
assert args.precision in ["W4A16", "W16A16"], "We only support W4A16/W16A16 now"
|
| 82 |
+
token_num = 256
|
| 83 |
+
# We support fixing a certain kind of length
|
| 84 |
+
if args.chunk_prefilling:
|
| 85 |
+
if len(args.context_length) == 1 and len(args.question_length) > 1:
|
| 86 |
+
args.context_length = [
|
| 87 |
+
args.context_length[0] for _ in range(len(args.question_length))
|
| 88 |
+
]
|
| 89 |
+
elif len(args.question_length) == 1 and len(args.context_length) > 1:
|
| 90 |
+
args.question_length = [
|
| 91 |
+
args.question_length[0] for _ in range(len(args.context_length))
|
| 92 |
+
]
|
| 93 |
+
elif len(args.question_length) != len(args.context_length):
|
| 94 |
+
raise ValueError(
|
| 95 |
+
"The number of items in the question_length and context_length is expected to be either one or equal!"
|
| 96 |
+
)
|
| 97 |
+
tinychat.utils.constants.max_batch_size = args.max_batch_size
|
| 98 |
+
tinychat.utils.constants.max_seq_len = args.max_seq_len
|
| 99 |
+
from tinychat.models import FalconForCausalLM, LlamaForCausalLM, MPTForCausalLM
|
| 100 |
+
from tinychat.models.vila_llama import VilaLlamaForCausalLM
|
| 101 |
+
|
| 102 |
+
modeling_utils._init_weights = False
|
| 103 |
+
torch.nn.init.kaiming_uniform_ = skip
|
| 104 |
+
torch.nn.init.kaiming_normal_ = skip
|
| 105 |
+
torch.nn.init.uniform_ = skip
|
| 106 |
+
torch.nn.init.normal_ = skip
|
| 107 |
+
|
| 108 |
+
device = "cuda:0"
|
| 109 |
+
model_type_dict = {
|
| 110 |
+
"llama": LlamaForCausalLM,
|
| 111 |
+
"falcon": FalconForCausalLM,
|
| 112 |
+
"mpt": MPTForCausalLM,
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
config = AutoConfig.from_pretrained(args.model_path, trust_remote_code=True)
|
| 116 |
+
assert args.model_type.lower() in [
|
| 117 |
+
"llama",
|
| 118 |
+
"falcon",
|
| 119 |
+
"mpt",
|
| 120 |
+
"vila",
|
| 121 |
+
], "We only support llama & falcon & mpt & vila now"
|
| 122 |
+
if "vila" in args.model_type.lower():
|
| 123 |
+
model = VilaLlamaForCausalLM(config).half()
|
| 124 |
+
print(model)
|
| 125 |
+
if args.precision in ["W4A16"]:
|
| 126 |
+
real_quantize_model_weight(
|
| 127 |
+
model.llm,
|
| 128 |
+
w_bit=4,
|
| 129 |
+
q_config=dict(q_group_size=args.q_group_size, zero_point=True),
|
| 130 |
+
init_only=True,
|
| 131 |
+
)
|
| 132 |
+
make_quant_attn(model.llm, device, args.flash_attn)
|
| 133 |
+
make_quant_norm(model.llm)
|
| 134 |
+
make_fused_mlp(model.llm)
|
| 135 |
+
model = model.to(device)
|
| 136 |
+
device_warmup(device)
|
| 137 |
+
tune_llava_patch_embedding(model.get_vision_tower(), device=device)
|
| 138 |
+
if not args.chunk_prefilling:
|
| 139 |
+
image_num = [
|
| 140 |
+
int(int("".join(i)) * 1 / 196) for i in args.context_length
|
| 141 |
+
] # consider about three thirds of the history tokens are images
|
| 142 |
+
if sum(image_num) > 0:
|
| 143 |
+
image_tensor = 2 * torch.rand((max(image_num), 3, 384, 384)) - 1
|
| 144 |
+
image_tensor = image_tensor.half().to(device)
|
| 145 |
+
else:
|
| 146 |
+
image_tensor = None
|
| 147 |
+
|
| 148 |
+
print("huggingface ckpt loaded")
|
| 149 |
+
|
| 150 |
+
# warming up
|
| 151 |
+
input_ids = [1 for _ in range(2048)]
|
| 152 |
+
inputs = torch.as_tensor([input_ids], device=device)
|
| 153 |
+
out = model(
|
| 154 |
+
inputs, start_pos=0, chunk_prefilling=args.chunk_prefilling
|
| 155 |
+
) # warmup
|
| 156 |
+
|
| 157 |
+
if not args.chunk_prefilling:
|
| 158 |
+
for i, context_length in enumerate(args.context_length):
|
| 159 |
+
context_length = int("".join(context_length))
|
| 160 |
+
time_lis = []
|
| 161 |
+
if image_num[i]:
|
| 162 |
+
images = image_tensor[0 : image_num[i], :, :, :]
|
| 163 |
+
input_ids = [-200 for _ in range(image_num[i])] + [
|
| 164 |
+
1 for _ in range(context_length - 196 * image_num[i])
|
| 165 |
+
]
|
| 166 |
+
else:
|
| 167 |
+
images = None
|
| 168 |
+
input_ids = [1 for _ in range(context_length)]
|
| 169 |
+
print("-" * 80)
|
| 170 |
+
print(
|
| 171 |
+
"Context length: {} with {} pictures".format(
|
| 172 |
+
context_length, image_num[i]
|
| 173 |
+
)
|
| 174 |
+
)
|
| 175 |
+
with torch.inference_mode():
|
| 176 |
+
for i in range(10): # Run ten times and get the average value
|
| 177 |
+
start_pos = 0
|
| 178 |
+
torch.cuda.synchronize()
|
| 179 |
+
t_st = time.time()
|
| 180 |
+
inputs = torch.as_tensor([input_ids], device=device)
|
| 181 |
+
out = model(
|
| 182 |
+
inputs,
|
| 183 |
+
start_pos=start_pos,
|
| 184 |
+
chunk_prefilling=args.chunk_prefilling,
|
| 185 |
+
images=images,
|
| 186 |
+
)
|
| 187 |
+
start_pos += inputs.shape[1]
|
| 188 |
+
torch.cuda.synchronize()
|
| 189 |
+
t_ed = time.time()
|
| 190 |
+
token = out[:, -1].max(1)[1].unsqueeze(1)
|
| 191 |
+
time_lis.append(t_ed - t_st)
|
| 192 |
+
if args.verbose:
|
| 193 |
+
print(i, t_ed - t_st)
|
| 194 |
+
print(f"Time To First Token: {np.mean(time_lis):.5f} s.")
|
| 195 |
+
print("-" * 80)
|
| 196 |
+
else:
|
| 197 |
+
for i, (context_length, question_length) in enumerate(
|
| 198 |
+
zip(args.context_length, args.question_length)
|
| 199 |
+
):
|
| 200 |
+
context_length = int("".join(context_length))
|
| 201 |
+
question_length = int("".join(question_length))
|
| 202 |
+
input_ids_old = [1 for _ in range(context_length)]
|
| 203 |
+
images = None
|
| 204 |
+
input_ids_new = [1 for _ in range(question_length)]
|
| 205 |
+
time_lis = []
|
| 206 |
+
print("-" * 80)
|
| 207 |
+
print(
|
| 208 |
+
"History length: {} ; Question length: {}".format(
|
| 209 |
+
context_length, question_length
|
| 210 |
+
)
|
| 211 |
+
)
|
| 212 |
+
with torch.inference_mode():
|
| 213 |
+
for i in range(10): # Run ten times and get the average value
|
| 214 |
+
# history rounds
|
| 215 |
+
start_pos = 0
|
| 216 |
+
if context_length > question_length:
|
| 217 |
+
inputs = torch.as_tensor([input_ids_old], device=device)
|
| 218 |
+
out = model(
|
| 219 |
+
inputs,
|
| 220 |
+
start_pos=start_pos,
|
| 221 |
+
chunk_prefilling=args.chunk_prefilling,
|
| 222 |
+
images=None,
|
| 223 |
+
)
|
| 224 |
+
start_pos += context_length
|
| 225 |
+
|
| 226 |
+
# the present round
|
| 227 |
+
torch.cuda.synchronize()
|
| 228 |
+
t_st = time.time()
|
| 229 |
+
inputs = torch.as_tensor([input_ids_new], device=device)
|
| 230 |
+
out = model(
|
| 231 |
+
inputs,
|
| 232 |
+
start_pos=start_pos,
|
| 233 |
+
chunk_prefilling=args.chunk_prefilling,
|
| 234 |
+
)
|
| 235 |
+
start_pos += inputs.shape[1]
|
| 236 |
+
torch.cuda.synchronize()
|
| 237 |
+
t_ed = time.time()
|
| 238 |
+
|
| 239 |
+
token = out[:, -1].max(1)[1].unsqueeze(1)
|
| 240 |
+
time_lis.append(t_ed - t_st)
|
| 241 |
+
if args.verbose:
|
| 242 |
+
print(i, t_ed - t_st)
|
| 243 |
+
print(
|
| 244 |
+
f"Time To First Token of this round: {np.mean(time_lis):.5f} s."
|
| 245 |
+
)
|
| 246 |
+
print("-" * 80)
|
| 247 |
+
else:
|
| 248 |
+
model = model_type_dict[args.model_type.lower()](config).half()
|
| 249 |
+
if args.precision in ["W4A16"]:
|
| 250 |
+
real_quantize_model_weight(
|
| 251 |
+
model,
|
| 252 |
+
w_bit=4,
|
| 253 |
+
q_config=dict(q_group_size=args.q_group_size, zero_point=True),
|
| 254 |
+
init_only=True,
|
| 255 |
+
)
|
| 256 |
+
model = model.to(device)
|
| 257 |
+
|
| 258 |
+
if args.precision in ["W4A16"]:
|
| 259 |
+
# tune_all_wqlinears(model)
|
| 260 |
+
make_quant_attn(model, device, args.flash_attn)
|
| 261 |
+
make_quant_norm(model)
|
| 262 |
+
make_fused_mlp(model)
|
| 263 |
+
device_warmup(device)
|
| 264 |
+
|
| 265 |
+
print("huggingface ckpt loaded")
|
| 266 |
+
|
| 267 |
+
# warming up
|
| 268 |
+
input_ids = [1 for _ in range(2048)]
|
| 269 |
+
inputs = torch.as_tensor([input_ids], device=device)
|
| 270 |
+
out = model(
|
| 271 |
+
inputs,
|
| 272 |
+
start_pos=0,
|
| 273 |
+
chunk_prefilling=args.chunk_prefilling,
|
| 274 |
+
quant=args.precision in ["W4A16"],
|
| 275 |
+
) # warmup
|
| 276 |
+
|
| 277 |
+
if not args.chunk_prefilling:
|
| 278 |
+
for context_length in args.context_length:
|
| 279 |
+
context_length = int("".join(context_length))
|
| 280 |
+
input_ids = [1 for _ in range(context_length)]
|
| 281 |
+
time_lis = []
|
| 282 |
+
print("-" * 80)
|
| 283 |
+
print("Context length: {}".format(context_length))
|
| 284 |
+
with torch.inference_mode():
|
| 285 |
+
for i in range(10): # Run ten times and get the average value
|
| 286 |
+
start_pos = 0
|
| 287 |
+
torch.cuda.synchronize()
|
| 288 |
+
t_st = time.time()
|
| 289 |
+
inputs = torch.as_tensor([input_ids], device=device)
|
| 290 |
+
out = model(
|
| 291 |
+
inputs,
|
| 292 |
+
start_pos=start_pos,
|
| 293 |
+
chunk_prefilling=args.chunk_prefilling,
|
| 294 |
+
quant=args.precision in ["W4A16"],
|
| 295 |
+
)
|
| 296 |
+
start_pos += inputs.shape[1]
|
| 297 |
+
torch.cuda.synchronize()
|
| 298 |
+
t_ed = time.time()
|
| 299 |
+
token = torch.argmax(out, keepdim=True)[0]
|
| 300 |
+
time_lis.append(t_ed - t_st)
|
| 301 |
+
if args.verbose:
|
| 302 |
+
print(i, t_ed - t_st)
|
| 303 |
+
print(f"Time To First Token: {np.mean(time_lis):.5f} s.")
|
| 304 |
+
# decoing throughput
|
| 305 |
+
time_lis = []
|
| 306 |
+
start_pos = context_length
|
| 307 |
+
torch.cuda.synchronize()
|
| 308 |
+
t_st = time.time()
|
| 309 |
+
for i in range(token_num):
|
| 310 |
+
token = model(
|
| 311 |
+
token,
|
| 312 |
+
start_pos=start_pos,
|
| 313 |
+
chunk_prefilling=args.chunk_prefilling,
|
| 314 |
+
quant=args.precision in ["W4A16"],
|
| 315 |
+
)
|
| 316 |
+
start_pos += 1
|
| 317 |
+
token = torch.argmax(token, keepdim=True)[0]
|
| 318 |
+
torch.cuda.synchronize()
|
| 319 |
+
t_ed = time.time()
|
| 320 |
+
time_lis.append(t_ed - t_st)
|
| 321 |
+
print(
|
| 322 |
+
f"Decoding throughput: {token_num/sum(time_lis):.5f} token/s."
|
| 323 |
+
)
|
| 324 |
+
print("-" * 80)
|
| 325 |
+
else:
|
| 326 |
+
for context_length, question_length in zip(
|
| 327 |
+
args.context_length, args.question_length
|
| 328 |
+
):
|
| 329 |
+
context_length = int("".join(context_length))
|
| 330 |
+
question_length = int("".join(question_length))
|
| 331 |
+
input_ids_old = [1 for _ in range(context_length)]
|
| 332 |
+
input_ids_new = [1 for _ in range(question_length)]
|
| 333 |
+
time_lis = []
|
| 334 |
+
print("-" * 80)
|
| 335 |
+
print(
|
| 336 |
+
"History length: {} ; Question length: {}".format(
|
| 337 |
+
context_length, question_length
|
| 338 |
+
)
|
| 339 |
+
)
|
| 340 |
+
with torch.inference_mode():
|
| 341 |
+
for i in range(10): # Run ten times and get the average value
|
| 342 |
+
# history rounds
|
| 343 |
+
start_pos = 0
|
| 344 |
+
if context_length > question_length:
|
| 345 |
+
inputs = torch.as_tensor([input_ids_old], device=device)
|
| 346 |
+
out = model(
|
| 347 |
+
inputs,
|
| 348 |
+
start_pos=start_pos,
|
| 349 |
+
chunk_prefilling=args.chunk_prefilling,
|
| 350 |
+
quant=args.precision in ["W4A16"],
|
| 351 |
+
)
|
| 352 |
+
start_pos += inputs.shape[1]
|
| 353 |
+
|
| 354 |
+
# the present round
|
| 355 |
+
torch.cuda.synchronize()
|
| 356 |
+
t_st = time.time()
|
| 357 |
+
inputs = torch.as_tensor([input_ids_new], device=device)
|
| 358 |
+
out = model(
|
| 359 |
+
inputs,
|
| 360 |
+
start_pos=start_pos,
|
| 361 |
+
chunk_prefilling=args.chunk_prefilling,
|
| 362 |
+
quant=args.precision in ["W4A16"],
|
| 363 |
+
)
|
| 364 |
+
start_pos += inputs.shape[1]
|
| 365 |
+
torch.cuda.synchronize()
|
| 366 |
+
t_ed = time.time()
|
| 367 |
+
|
| 368 |
+
token = out[:, -1].max(1)[1].unsqueeze(1)
|
| 369 |
+
time_lis.append(t_ed - t_st)
|
| 370 |
+
if args.verbose:
|
| 371 |
+
print(i, t_ed - t_st)
|
| 372 |
+
print(
|
| 373 |
+
f"Time To First Token of this round: {np.mean(time_lis):.5f} s."
|
| 374 |
+
)
|
| 375 |
+
print("-" * 80)
|
| 376 |
+
|
| 377 |
+
|
| 378 |
+
if __name__ == "__main__":
|
| 379 |
+
main()
|
llm-awq/tinychat/demo.py
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import time
|
| 3 |
+
import numpy as np
|
| 4 |
+
import torch
|
| 5 |
+
import torch.nn as nn
|
| 6 |
+
from transformers import AutoTokenizer, AutoModelForCausalLM, AutoConfig, modeling_utils
|
| 7 |
+
from attributedict.collections import AttributeDict
|
| 8 |
+
from tinychat.stream_generators import StreamGenerator
|
| 9 |
+
import tinychat.utils.constants
|
| 10 |
+
from tinychat.utils.load_quant import load_awq_model, load_awq_llama_fast
|
| 11 |
+
from tinychat.utils.prompt_templates import get_prompter, get_stop_token_ids
|
| 12 |
+
from tinychat.utils.tune import device_warmup, tune_all_wqlinears
|
| 13 |
+
|
| 14 |
+
import os
|
| 15 |
+
|
| 16 |
+
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
|
| 17 |
+
|
| 18 |
+
# opt_params in TinyLLMEngine
|
| 19 |
+
gen_params = AttributeDict(
|
| 20 |
+
[
|
| 21 |
+
("seed", -1), # RNG seed
|
| 22 |
+
("n_threads", 1), # TODO: fix this
|
| 23 |
+
("n_predict", 512), # new tokens to predict
|
| 24 |
+
("n_parts", -1), # amount of model parts (-1: determine from model dimensions)
|
| 25 |
+
("n_ctx", 512), # context size
|
| 26 |
+
("n_batch", 512), # batch size for prompt processing (must be >=32 to use BLAS)
|
| 27 |
+
("n_keep", 0), # number of tokens to keep from initial prompt
|
| 28 |
+
("n_vocab", 50272), # vocabulary size
|
| 29 |
+
# sampling parameters
|
| 30 |
+
("logit_bias", dict()), # logit bias for specific tokens: <int, float>
|
| 31 |
+
("top_k", 40), # <= 0 to use vocab size
|
| 32 |
+
("top_p", 0.95), # 1.0 = disabled
|
| 33 |
+
("tfs_z", 1.00), # 1.0 = disabled
|
| 34 |
+
("typical_p", 1.00), # 1.0 = disabled
|
| 35 |
+
("temp", 0.70), # 1.0 = disabled
|
| 36 |
+
("repeat_penalty", 1.10), # 1.0 = disabled
|
| 37 |
+
(
|
| 38 |
+
"repeat_last_n",
|
| 39 |
+
64,
|
| 40 |
+
), # last n tokens to penalize (0 = disable penalty, -1 = context size)
|
| 41 |
+
("frequency_penalty", 0.00), # 0.0 = disabled
|
| 42 |
+
("presence_penalty", 0.00), # 0.0 = disabled
|
| 43 |
+
("mirostat", 0), # 0 = disabled, 1 = mirostat, 2 = mirostat 2.0
|
| 44 |
+
("mirostat_tau", 5.00), # target entropy
|
| 45 |
+
("mirostat_eta", 0.10), # learning rate
|
| 46 |
+
]
|
| 47 |
+
)
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def stream_output(output_stream):
|
| 51 |
+
print(f"ASSISTANT: ", end="", flush=True)
|
| 52 |
+
pre = 0
|
| 53 |
+
for outputs in output_stream:
|
| 54 |
+
output_text = outputs["text"]
|
| 55 |
+
output_text = output_text.strip().split(" ")
|
| 56 |
+
now = len(output_text) - 1
|
| 57 |
+
if now > pre:
|
| 58 |
+
print(" ".join(output_text[pre:now]), end=" ", flush=True)
|
| 59 |
+
pre = now
|
| 60 |
+
print(" ".join(output_text[pre:]), flush=True)
|
| 61 |
+
if "timing" in outputs and outputs["timing"] is not None:
|
| 62 |
+
timing = outputs["timing"]
|
| 63 |
+
context_tokens = timing["context_tokens"]
|
| 64 |
+
context_time = timing["context_time"]
|
| 65 |
+
total_tokens = timing["total_tokens"]
|
| 66 |
+
generation_time_list = timing["generation_time_list"]
|
| 67 |
+
generation_tokens = len(generation_time_list)
|
| 68 |
+
average_speed = (context_time + np.sum(generation_time_list)) / (
|
| 69 |
+
context_tokens + generation_tokens
|
| 70 |
+
)
|
| 71 |
+
print("=" * 50)
|
| 72 |
+
print("Speed of Inference")
|
| 73 |
+
print("-" * 50)
|
| 74 |
+
print(f"TTFT : { context_time:.3f} s for {context_tokens} tokens")
|
| 75 |
+
print(
|
| 76 |
+
f"Speed of Generation : {np.average(generation_time_list)*1000:.2f} ms/token"
|
| 77 |
+
)
|
| 78 |
+
print("=" * 50)
|
| 79 |
+
return " ".join(output_text), total_tokens
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
if __name__ == "__main__":
|
| 83 |
+
parser = argparse.ArgumentParser()
|
| 84 |
+
parser.add_argument(
|
| 85 |
+
"--model_type", type=str, default="LLaMa", help="type of the model"
|
| 86 |
+
)
|
| 87 |
+
parser.add_argument(
|
| 88 |
+
"--dtype", type=str, default="float16", choices=["float16", "bfloat16"]
|
| 89 |
+
)
|
| 90 |
+
parser.add_argument(
|
| 91 |
+
"--model_path",
|
| 92 |
+
type=str,
|
| 93 |
+
help="path to the model",
|
| 94 |
+
)
|
| 95 |
+
parser.add_argument(
|
| 96 |
+
"--precision", type=str, default="W4A16", help="compute precision"
|
| 97 |
+
)
|
| 98 |
+
parser.add_argument("--device", type=str, default="cuda:0")
|
| 99 |
+
parser.add_argument("--q_group_size", type=int, default=128)
|
| 100 |
+
parser.add_argument(
|
| 101 |
+
"--load_quant",
|
| 102 |
+
type=str,
|
| 103 |
+
help="path to the pre-quanted 4-bit weights",
|
| 104 |
+
)
|
| 105 |
+
parser.add_argument(
|
| 106 |
+
"--max_seq_len",
|
| 107 |
+
type=int,
|
| 108 |
+
default=2048,
|
| 109 |
+
help="maximum sequence length for kv cache",
|
| 110 |
+
)
|
| 111 |
+
parser.add_argument(
|
| 112 |
+
"--max_batch_size", type=int, default=1, help="maximum batch size for kv cache"
|
| 113 |
+
)
|
| 114 |
+
parser.add_argument(
|
| 115 |
+
"--mem_efficient_load",
|
| 116 |
+
action="store_true",
|
| 117 |
+
help="enable mem_efficient_load mod",
|
| 118 |
+
)
|
| 119 |
+
parser.add_argument(
|
| 120 |
+
"--single_round",
|
| 121 |
+
action="store_true",
|
| 122 |
+
help="whether to memorize previous conversations",
|
| 123 |
+
)
|
| 124 |
+
parser.add_argument(
|
| 125 |
+
"--flash_attn",
|
| 126 |
+
action="store_true",
|
| 127 |
+
help="whether to use flash attention",
|
| 128 |
+
)
|
| 129 |
+
parser.add_argument(
|
| 130 |
+
"--chunk_prefilling",
|
| 131 |
+
action="store_true",
|
| 132 |
+
help="If used, in context stage, the history tokens will not be recalculated, greatly speeding up the calculation",
|
| 133 |
+
)
|
| 134 |
+
|
| 135 |
+
args = parser.parse_args()
|
| 136 |
+
assert args.model_type.lower() in [
|
| 137 |
+
"llama",
|
| 138 |
+
"falcon",
|
| 139 |
+
"mpt",
|
| 140 |
+
"qwen",
|
| 141 |
+
], "We only support llama & falcon & mpt now"
|
| 142 |
+
assert args.precision in ["W4A16", "W16A16"], "We only support W4A16/W16A16 now"
|
| 143 |
+
|
| 144 |
+
gen_params.n_predict = 1024
|
| 145 |
+
gen_params.n_vocab = 32000
|
| 146 |
+
tinychat.utils.constants.max_batch_size = args.max_batch_size
|
| 147 |
+
tinychat.utils.constants.max_seq_len = args.max_seq_len
|
| 148 |
+
tinychat.utils.constants.mem_efficient_load = args.mem_efficient_load
|
| 149 |
+
if tinychat.utils.constants.mem_efficient_load:
|
| 150 |
+
print("=" * 80)
|
| 151 |
+
print(
|
| 152 |
+
"[Info] You have activated mem_efficient_load mode.\n Less on-chip memory will be consumed when loading the model.\n However, the loading process will take more time."
|
| 153 |
+
)
|
| 154 |
+
print("=" * 80)
|
| 155 |
+
# TODO (Haotian): a more elegant implementation here.
|
| 156 |
+
# We need to update these global variables before models use them.
|
| 157 |
+
from tinychat.models import (
|
| 158 |
+
FalconForCausalLM,
|
| 159 |
+
LlamaForCausalLM,
|
| 160 |
+
MPTForCausalLM,
|
| 161 |
+
Qwen2ForCausalLM,
|
| 162 |
+
)
|
| 163 |
+
|
| 164 |
+
def skip(*args, **kwargs):
|
| 165 |
+
pass
|
| 166 |
+
|
| 167 |
+
torch.nn.init.kaiming_uniform_ = skip
|
| 168 |
+
torch.nn.init.kaiming_normal_ = skip
|
| 169 |
+
torch.nn.init.uniform_ = skip
|
| 170 |
+
torch.nn.init.normal_ = skip
|
| 171 |
+
|
| 172 |
+
config = AutoConfig.from_pretrained(args.model_path, trust_remote_code=True)
|
| 173 |
+
if "mpt" in config.__class__.__name__.lower():
|
| 174 |
+
# config.init_device="meta"
|
| 175 |
+
tokenizer = AutoTokenizer.from_pretrained(
|
| 176 |
+
config.tokenizer_name, trust_remote_code=True
|
| 177 |
+
)
|
| 178 |
+
else:
|
| 179 |
+
tokenizer = AutoTokenizer.from_pretrained(
|
| 180 |
+
args.model_path, use_fast=False, trust_remote_code=True
|
| 181 |
+
)
|
| 182 |
+
torch_dtype = torch.float16 if args.dtype == "float16" else torch.bfloat16
|
| 183 |
+
modeling_utils._init_weights = False
|
| 184 |
+
torch.set_default_dtype(torch_dtype)
|
| 185 |
+
|
| 186 |
+
model_type_dict = {
|
| 187 |
+
"llama": LlamaForCausalLM,
|
| 188 |
+
"falcon": FalconForCausalLM,
|
| 189 |
+
"mpt": MPTForCausalLM,
|
| 190 |
+
"qwen": Qwen2ForCausalLM,
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
if args.precision == "W4A16":
|
| 194 |
+
if args.model_type.lower() == "llama":
|
| 195 |
+
model = model_type_dict["llama"](config).to(torch_dtype)
|
| 196 |
+
model = load_awq_llama_fast(
|
| 197 |
+
model, args.load_quant, 4, args.q_group_size, args.device
|
| 198 |
+
)
|
| 199 |
+
elif args.model_type.lower() == "qwen":
|
| 200 |
+
model = model_type_dict["qwen"](config).to(torch_dtype)
|
| 201 |
+
model = load_awq_llama_fast(
|
| 202 |
+
model, args.load_quant, 4, args.q_group_size, args.device
|
| 203 |
+
)
|
| 204 |
+
else:
|
| 205 |
+
model = model_type_dict[args.model_type.lower()](config).to(torch_dtype)
|
| 206 |
+
model = load_awq_model(
|
| 207 |
+
model, args.load_quant, 4, args.q_group_size, args.device
|
| 208 |
+
)
|
| 209 |
+
else:
|
| 210 |
+
loaded_model = AutoModelForCausalLM.from_pretrained(
|
| 211 |
+
args.model_path,
|
| 212 |
+
config=config,
|
| 213 |
+
torch_dtype=torch_dtype,
|
| 214 |
+
trust_remote_code=True,
|
| 215 |
+
)
|
| 216 |
+
model = (
|
| 217 |
+
model_type_dict[args.model_type.lower()](config)
|
| 218 |
+
.to(torch_dtype)
|
| 219 |
+
.to(args.device)
|
| 220 |
+
)
|
| 221 |
+
model.load_state_dict(loaded_model.state_dict())
|
| 222 |
+
# device warm up
|
| 223 |
+
device_warmup(args.device)
|
| 224 |
+
|
| 225 |
+
# autotune split_k_iters
|
| 226 |
+
# tune_all_wqlinears(model)
|
| 227 |
+
|
| 228 |
+
# TODO (Haotian): Verify if the StreamGenerator still works for the unmodified falcon impl.
|
| 229 |
+
stream_generator = StreamGenerator
|
| 230 |
+
|
| 231 |
+
# Optimize AWQ quantized model
|
| 232 |
+
if args.precision == "W4A16" and (
|
| 233 |
+
args.model_type.lower() == "llama" or args.model_type.lower() == "qwen"
|
| 234 |
+
):
|
| 235 |
+
from tinychat.modules import make_quant_norm, make_quant_attn
|
| 236 |
+
|
| 237 |
+
if args.flash_attn:
|
| 238 |
+
make_quant_attn(model, args.device, args.flash_attn)
|
| 239 |
+
else:
|
| 240 |
+
make_quant_attn(model, args.device)
|
| 241 |
+
make_quant_norm(model)
|
| 242 |
+
model(
|
| 243 |
+
torch.randint(0, 1000, (1, 512), dtype=torch.int, device="cuda:0"),
|
| 244 |
+
0,
|
| 245 |
+
quant=args.precision == "W4A16",
|
| 246 |
+
)
|
| 247 |
+
if args.max_seq_len <= 1024:
|
| 248 |
+
short_prompt = True
|
| 249 |
+
else:
|
| 250 |
+
short_prompt = False
|
| 251 |
+
model_prompter = get_prompter(args.model_type, args.model_path, short_prompt)
|
| 252 |
+
stop_token_ids = get_stop_token_ids(args.model_type, args.model_path)
|
| 253 |
+
count = 0
|
| 254 |
+
start_pos = 0
|
| 255 |
+
print("=" * 50)
|
| 256 |
+
while True:
|
| 257 |
+
# Get input from the user
|
| 258 |
+
input_prompt = input("USER: ")
|
| 259 |
+
if input_prompt == "":
|
| 260 |
+
print("EXIT...")
|
| 261 |
+
break
|
| 262 |
+
model_prompter.insert_prompt(input_prompt)
|
| 263 |
+
output_stream = stream_generator(
|
| 264 |
+
model,
|
| 265 |
+
tokenizer,
|
| 266 |
+
model_prompter.model_input,
|
| 267 |
+
start_pos,
|
| 268 |
+
gen_params,
|
| 269 |
+
device=args.device,
|
| 270 |
+
stop_token_ids=stop_token_ids,
|
| 271 |
+
chunk_prefilling=args.chunk_prefilling,
|
| 272 |
+
quant_llm=args.precision == "W4A16",
|
| 273 |
+
)
|
| 274 |
+
outputs, total_tokens = stream_output(output_stream)
|
| 275 |
+
if args.chunk_prefilling:
|
| 276 |
+
start_pos += total_tokens
|
| 277 |
+
else:
|
| 278 |
+
start_pos = 0
|
| 279 |
+
if (
|
| 280 |
+
args.single_round is not True and args.max_seq_len > 512
|
| 281 |
+
): # Only memorize previous conversations when kv_cache_size > 512
|
| 282 |
+
model_prompter.update_template(outputs, args.chunk_prefilling)
|
| 283 |
+
count += 1
|
llm-awq/tinychat/internvl_benchmark.py
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
|
| 3 |
+
from termcolor import colored
|
| 4 |
+
|
| 5 |
+
import llava
|
| 6 |
+
from llava import conversation as clib
|
| 7 |
+
from llava.media import Image, Video
|
| 8 |
+
import torch
|
| 9 |
+
from awq.quantize import fake_quant
|
| 10 |
+
from awq.quantize.quantizer import real_quantize_model_weight
|
| 11 |
+
from transformers import AutoConfig
|
| 12 |
+
import tinychat
|
| 13 |
+
|
| 14 |
+
from torchao.quantization import quantize_, Int4WeightOnlyConfig
|
| 15 |
+
|
| 16 |
+
import os
|
| 17 |
+
|
| 18 |
+
os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "expandable_segments:True"
|
| 19 |
+
|
| 20 |
+
def skip(*args, **kwargs):
|
| 21 |
+
pass
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def main() -> None:
|
| 25 |
+
parser = argparse.ArgumentParser()
|
| 26 |
+
parser.add_argument(
|
| 27 |
+
"--model-path",
|
| 28 |
+
"-m",
|
| 29 |
+
type=str,
|
| 30 |
+
default="/home/yuming/workspace/qwen/models/nvila-internal-8b-v1",
|
| 31 |
+
)
|
| 32 |
+
parser.add_argument(
|
| 33 |
+
"--quant_path",
|
| 34 |
+
type=str,
|
| 35 |
+
default="/PATH/TO/QUANT",
|
| 36 |
+
)
|
| 37 |
+
# parser.add_argument("--model-path", "-m", type=str, default="Efficient-Large-Model/J65")
|
| 38 |
+
# parser.add_argument("--quant_path", type=str, default="/home/yuming/workspace/qwen/models/J65/llm/vila2-J65-w4-g128-awq-v2.pt")
|
| 39 |
+
parser.add_argument("--conv-mode", "-c", type=str, default="auto")
|
| 40 |
+
# parser.add_argument("--media", type=str, default="/home/yuming/workspace/space_woaudio.mp4")
|
| 41 |
+
parser.add_argument("--device", type=str, default="cuda:0")
|
| 42 |
+
parser.add_argument(
|
| 43 |
+
"--act_scale_path",
|
| 44 |
+
type=str,
|
| 45 |
+
default="/PATH/TO/SCALE",
|
| 46 |
+
)
|
| 47 |
+
# quantization options
|
| 48 |
+
parser.add_argument("--quant_llm", action="store_true")
|
| 49 |
+
parser.add_argument("--quant_VT", action="store_true")
|
| 50 |
+
# Four basic tasks
|
| 51 |
+
parser.add_argument("--video_caption", action="store_true")
|
| 52 |
+
parser.add_argument("--video_QA", action="store_true")
|
| 53 |
+
parser.add_argument("--image_caption", action="store_true")
|
| 54 |
+
parser.add_argument("--image_QA", action="store_true")
|
| 55 |
+
|
| 56 |
+
parser.add_argument(
|
| 57 |
+
"--all",
|
| 58 |
+
action="store_true",
|
| 59 |
+
help="Whether to quantize visiontower and llm, and test all 4 tasks",
|
| 60 |
+
)
|
| 61 |
+
parser.add_argument(
|
| 62 |
+
"--fakequant_VT",
|
| 63 |
+
action="store_true",
|
| 64 |
+
help="Use fake quant or real quant for VisionTower",
|
| 65 |
+
)
|
| 66 |
+
parser.add_argument(
|
| 67 |
+
"--all_task", action="store_true", help="Whether to test all 4 tasks"
|
| 68 |
+
)
|
| 69 |
+
parser.add_argument(
|
| 70 |
+
"--video_path", type=str, default="../figures/nvila_demo_video.mp4"
|
| 71 |
+
)
|
| 72 |
+
parser.add_argument("--image_path", type=str, default="../figures/vila-logo.jpg")
|
| 73 |
+
parser.add_argument("--max_seq_len", type=int, default=8192)
|
| 74 |
+
args = parser.parse_args()
|
| 75 |
+
|
| 76 |
+
torch.nn.init.kaiming_uniform_ = skip
|
| 77 |
+
torch.nn.init.kaiming_normal_ = skip
|
| 78 |
+
torch.nn.init.uniform_ = skip
|
| 79 |
+
torch.nn.init.normal_ = skip
|
| 80 |
+
import tinychat.utils.constants
|
| 81 |
+
|
| 82 |
+
tinychat.utils.constants.max_seq_len = args.max_seq_len
|
| 83 |
+
from transformers import modeling_utils
|
| 84 |
+
|
| 85 |
+
modeling_utils._init_weights = False
|
| 86 |
+
|
| 87 |
+
# Load model
|
| 88 |
+
from tinychat.models import InternVL3
|
| 89 |
+
|
| 90 |
+
config = AutoConfig.from_pretrained(args.model_path, trust_remote_code=True)
|
| 91 |
+
config.resume_path = args.model_path
|
| 92 |
+
model = InternVL3(config).half()
|
| 93 |
+
model.language_model = model.language_model.eval()
|
| 94 |
+
if args.quant_llm or args.all:
|
| 95 |
+
from tinychat.modules import (
|
| 96 |
+
make_quant_norm,
|
| 97 |
+
make_quant_attn,
|
| 98 |
+
make_fused_mlp,
|
| 99 |
+
make_fused_vision_attn,
|
| 100 |
+
)
|
| 101 |
+
|
| 102 |
+
real_quantize_model_weight(
|
| 103 |
+
model.language_model,
|
| 104 |
+
w_bit=4,
|
| 105 |
+
q_config=dict(q_group_size=128, zero_point=True),
|
| 106 |
+
init_only=True,
|
| 107 |
+
)
|
| 108 |
+
make_quant_attn(model.language_model, "cuda", True)
|
| 109 |
+
make_quant_norm(model.language_model)
|
| 110 |
+
make_fused_mlp(model.language_model)
|
| 111 |
+
model = model.to("cuda")
|
| 112 |
+
model = model.to(args.device)
|
| 113 |
+
if args.quant_VT or args.all:
|
| 114 |
+
from tinychat.modules import QuantInternVisionEncoder
|
| 115 |
+
model.vision_model.encoder = QuantInternVisionEncoder(model.vision_model.encoder)
|
| 116 |
+
model.vision_model.encoder = torch.compile(model.vision_model.encoder)
|
| 117 |
+
|
| 118 |
+
model = model.cuda().eval()
|
| 119 |
+
|
| 120 |
+
if args.video_caption or args.all or args.all_task:
|
| 121 |
+
print("-" * 80)
|
| 122 |
+
print("Video_Caption")
|
| 123 |
+
# Set conversation mode
|
| 124 |
+
clib.default_conversation = clib.conv_templates[args.conv_mode].copy()
|
| 125 |
+
media = Video(args.video_path)
|
| 126 |
+
text = "Elaborate on the visual and narrative elements of the video in detail." # + "1"+" 1"*3069
|
| 127 |
+
prompt = [media, text]
|
| 128 |
+
# Generate response
|
| 129 |
+
with torch.no_grad():
|
| 130 |
+
response = model.benchmark(prompt, args.quant_llm)
|
| 131 |
+
if args.video_QA or args.all or args.all_task:
|
| 132 |
+
print("-" * 80)
|
| 133 |
+
print("Video_QA")
|
| 134 |
+
# Set conversation mode
|
| 135 |
+
clib.default_conversation = clib.conv_templates[args.conv_mode].copy()
|
| 136 |
+
media = Video(args.video_path)
|
| 137 |
+
text = "What is the person in the video doing? Select the option that best describes their action: A. Folding paper B. Playing computer games C. Sleeping." # + "1"+" 1"*3069
|
| 138 |
+
prompt = [media, text]
|
| 139 |
+
# Generate response
|
| 140 |
+
with torch.no_grad():
|
| 141 |
+
response = model.benchmark(prompt, args.quant_llm)
|
| 142 |
+
if args.image_caption or args.all or args.all_task:
|
| 143 |
+
print("-" * 80)
|
| 144 |
+
print("Image_Caption")
|
| 145 |
+
# Set conversation mode
|
| 146 |
+
clib.default_conversation = clib.conv_templates[args.conv_mode].copy()
|
| 147 |
+
media = Image(args.image_path)
|
| 148 |
+
text = "Describe the image in detail."
|
| 149 |
+
prompt = [media, text]
|
| 150 |
+
# Generate response
|
| 151 |
+
with torch.no_grad():
|
| 152 |
+
response = model.benchmark(prompt, args.quant_llm)
|
| 153 |
+
if args.image_QA or args.all or args.all_task:
|
| 154 |
+
print("-" * 80)
|
| 155 |
+
print("Image_QA")
|
| 156 |
+
# Set conversation mode
|
| 157 |
+
clib.default_conversation = clib.conv_templates[args.conv_mode].copy()
|
| 158 |
+
media = Image(args.image_path)
|
| 159 |
+
text = "What does the text in the image say? Choose the option that best matches: A. VILA B. AIIV C. ALIV."
|
| 160 |
+
prompt = [media, text]
|
| 161 |
+
# Generate response
|
| 162 |
+
with torch.no_grad():
|
| 163 |
+
response = model.benchmark(prompt, args.quant_llm)
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
if __name__ == "__main__":
|
| 167 |
+
main()
|
llm-awq/tinychat/internvl_demo.py
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
|
| 3 |
+
from termcolor import colored
|
| 4 |
+
|
| 5 |
+
import llava
|
| 6 |
+
from llava.media import Image, Video
|
| 7 |
+
import torch
|
| 8 |
+
from awq.quantize import fake_quant
|
| 9 |
+
from transformers import AutoConfig, AutoTokenizer
|
| 10 |
+
from tinychat.utils.load_quant import load_awq_model
|
| 11 |
+
from tinychat.utils.llava_image_processing import (
|
| 12 |
+
load_images,
|
| 13 |
+
vis_images,
|
| 14 |
+
)
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def skip(*args, **kwargs):
|
| 18 |
+
pass
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
from tinychat.utils.tune import (
|
| 22 |
+
device_warmup,
|
| 23 |
+
tune_all_wqlinears,
|
| 24 |
+
tune_llava_patch_embedding,
|
| 25 |
+
)
|
| 26 |
+
from tinychat.utils.prompt_templates import (
|
| 27 |
+
get_prompter,
|
| 28 |
+
get_stop_token_ids,
|
| 29 |
+
get_image_token,
|
| 30 |
+
)
|
| 31 |
+
from llava.utils.media import extract_media
|
| 32 |
+
import tinychat.utils.constants
|
| 33 |
+
from tinychat.stream_generators.internvl_stream_gen import InternVLStreamGenerator
|
| 34 |
+
from tinychat.utils.conversation_utils import gen_params, stream_output, TimeStats
|
| 35 |
+
|
| 36 |
+
import os
|
| 37 |
+
|
| 38 |
+
os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "expandable_segments:True"
|
| 39 |
+
|
| 40 |
+
def tune_intern_patch_embedding(vision_model, device):
|
| 41 |
+
patch_embedding = vision_model.embeddings.patch_embedding
|
| 42 |
+
patch_embedding = patch_embedding.to(device)
|
| 43 |
+
|
| 44 |
+
image = (
|
| 45 |
+
torch.randn((1, patch_embedding.in_channels, 336, 336))
|
| 46 |
+
.to(device)
|
| 47 |
+
.to(patch_embedding.weight.dtype)
|
| 48 |
+
)
|
| 49 |
+
for i in range(100):
|
| 50 |
+
patch_embedding(image)
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def main(args):
|
| 54 |
+
# Accelerate model initialization
|
| 55 |
+
setattr(torch.nn.Linear, "reset_parameters", lambda self: None)
|
| 56 |
+
setattr(torch.nn.LayerNorm, "reset_parameters", lambda self: None)
|
| 57 |
+
torch.nn.init.kaiming_uniform_ = skip
|
| 58 |
+
torch.nn.init.kaiming_normal_ = skip
|
| 59 |
+
torch.nn.init.uniform_ = skip
|
| 60 |
+
torch.nn.init.normal_ = skip
|
| 61 |
+
tinychat.utils.constants.max_seq_len = args.max_seq_len
|
| 62 |
+
|
| 63 |
+
# Prepare model
|
| 64 |
+
from tinychat.models import InternVL3
|
| 65 |
+
from tinychat.models.internvl.internvit import InternVisionModel
|
| 66 |
+
from transformers import AutoConfig
|
| 67 |
+
from tinychat.models.qwen2 import Qwen2ForCausalLM
|
| 68 |
+
|
| 69 |
+
config = AutoConfig.from_pretrained(args.model_path, trust_remote_code=True)
|
| 70 |
+
config.resume_path = args.model_path
|
| 71 |
+
if args.quant_llm or args.all:
|
| 72 |
+
model = InternVL3.from_pretrained(args.model_path, config=config).half()
|
| 73 |
+
else:
|
| 74 |
+
llm = Qwen2ForCausalLM.from_pretrained(args.model_path)
|
| 75 |
+
llm = llm.cpu()
|
| 76 |
+
tokenizer = AutoTokenizer.from_pretrained(
|
| 77 |
+
args.model_path, use_fast=False, trust_remote_code=True
|
| 78 |
+
)
|
| 79 |
+
llm.resize_token_embeddings(len(tokenizer))
|
| 80 |
+
model = InternVL3(config, language_model=llm).half()
|
| 81 |
+
|
| 82 |
+
if args.smooth_VT or args.all:
|
| 83 |
+
from awq.quantize import smooth_lm
|
| 84 |
+
|
| 85 |
+
act_scales = torch.load(args.act_scale_path)
|
| 86 |
+
smooth_lm(model.vision_tower, act_scales, 0.3)
|
| 87 |
+
if args.quant_llm or args.all:
|
| 88 |
+
from tinychat.modules import (
|
| 89 |
+
make_quant_norm,
|
| 90 |
+
make_quant_attn,
|
| 91 |
+
make_fused_mlp,
|
| 92 |
+
make_fused_vision_attn,
|
| 93 |
+
)
|
| 94 |
+
|
| 95 |
+
model = load_awq_model(model, args.quant_path, 4, 128, args.device)
|
| 96 |
+
make_quant_attn(model, args.device, True)
|
| 97 |
+
make_quant_norm(model)
|
| 98 |
+
model.cpu()
|
| 99 |
+
model.resize_token_embeddings(len(model.tokenizer))
|
| 100 |
+
pass
|
| 101 |
+
|
| 102 |
+
if args.quant_VT or args.all:
|
| 103 |
+
from tinychat.modules import QuantInternVisionEncoder
|
| 104 |
+
model.vision_model.encoder = QuantInternVisionEncoder(model.vision_model.encoder)
|
| 105 |
+
# model.vision_model.encoder = torch.compile(model.vision_model.encoder)
|
| 106 |
+
|
| 107 |
+
model = model.cuda().eval()
|
| 108 |
+
device_warmup(args.device)
|
| 109 |
+
# tune_intern_patch_embedding(model.vision_model, device=args.device)
|
| 110 |
+
|
| 111 |
+
# Pre-prepare media
|
| 112 |
+
prompt = []
|
| 113 |
+
media_files = []
|
| 114 |
+
if args.media is not None:
|
| 115 |
+
for media in args.media or []:
|
| 116 |
+
if any(media.endswith(ext) for ext in [".jpg", ".jpeg", ".png"]):
|
| 117 |
+
media = Image(media)
|
| 118 |
+
media_files.append(media)
|
| 119 |
+
media_prompt = "<image>"
|
| 120 |
+
elif any(media.endswith(ext) for ext in [".mp4", ".mkv", ".webm"]):
|
| 121 |
+
media = Video(media)
|
| 122 |
+
media_files.append(media)
|
| 123 |
+
media_prompt = "<vila/video>"
|
| 124 |
+
else:
|
| 125 |
+
raise ValueError(f"Unsupported media type: {media}")
|
| 126 |
+
prompt.append(media)
|
| 127 |
+
media_num = len(media_files)
|
| 128 |
+
if args.vis_image:
|
| 129 |
+
print("=" * 50)
|
| 130 |
+
print("Input Image:")
|
| 131 |
+
vis_images(args.media)
|
| 132 |
+
|
| 133 |
+
conversation = [{"from": "human", "value": prompt}]
|
| 134 |
+
media, media_cfg = model.prepare_media(conversation)
|
| 135 |
+
# Prepare streaming
|
| 136 |
+
stream_generator = InternVLStreamGenerator
|
| 137 |
+
# Prepare prompt
|
| 138 |
+
if args.max_seq_len <= 1024:
|
| 139 |
+
short_prompt = True
|
| 140 |
+
else:
|
| 141 |
+
short_prompt = False
|
| 142 |
+
model_prompter = get_prompter(
|
| 143 |
+
args.model_type, args.model_path, short_prompt, args.empty_prompt
|
| 144 |
+
)
|
| 145 |
+
stop_token_ids = get_stop_token_ids(args.model_type, args.model_path)
|
| 146 |
+
count = 0
|
| 147 |
+
|
| 148 |
+
if args.empty_prompt:
|
| 149 |
+
input_indicator = "Input: "
|
| 150 |
+
output_indicator = "Generated: "
|
| 151 |
+
else:
|
| 152 |
+
input_indicator = "USER: "
|
| 153 |
+
output_indicator = "ASSISTANT: "
|
| 154 |
+
|
| 155 |
+
count = 0
|
| 156 |
+
model.eval()
|
| 157 |
+
time_stats = TimeStats()
|
| 158 |
+
start_pos = 0
|
| 159 |
+
while True:
|
| 160 |
+
# Get input from the user
|
| 161 |
+
print("=" * 50)
|
| 162 |
+
input_prompt = input(input_indicator)
|
| 163 |
+
print("-" * 50)
|
| 164 |
+
if input_prompt == "":
|
| 165 |
+
print("EXIT...")
|
| 166 |
+
time_stats.show()
|
| 167 |
+
break
|
| 168 |
+
if count == 0: # Insert media here
|
| 169 |
+
if args.media is not None:
|
| 170 |
+
if media_prompt in input_prompt:
|
| 171 |
+
input_prompt = input_prompt
|
| 172 |
+
else:
|
| 173 |
+
if media_prompt == "<image>":
|
| 174 |
+
input_prompt = media_prompt * media_num + input_prompt
|
| 175 |
+
elif media_prompt == "<vila/video>":
|
| 176 |
+
video_prefix = ''.join([f'Frame{i+1}: <image>\n' for i in range(len(media_cfg))])
|
| 177 |
+
input_prompt = video_prefix + input_prompt
|
| 178 |
+
|
| 179 |
+
model_prompter.insert_prompt(input_prompt)
|
| 180 |
+
else:
|
| 181 |
+
model_prompter.insert_prompt(input_prompt)
|
| 182 |
+
if args.chunk_prefilling:
|
| 183 |
+
media = None
|
| 184 |
+
media_cfg = None
|
| 185 |
+
output_stream = stream_generator(
|
| 186 |
+
model,
|
| 187 |
+
gen_params,
|
| 188 |
+
model_prompter.model_input,
|
| 189 |
+
media,
|
| 190 |
+
media_cfg,
|
| 191 |
+
start_pos,
|
| 192 |
+
device=args.device,
|
| 193 |
+
stop_token_ids=stop_token_ids,
|
| 194 |
+
chunk_prefilling=args.chunk_prefilling,
|
| 195 |
+
quant_llm=args.quant_llm or args.all,
|
| 196 |
+
)
|
| 197 |
+
print(output_indicator, end="", flush=True)
|
| 198 |
+
if count == 0:
|
| 199 |
+
outputs, total_tokens = stream_output(output_stream, time_stats)
|
| 200 |
+
else:
|
| 201 |
+
outputs, total_tokens = stream_output(output_stream)
|
| 202 |
+
if args.chunk_prefilling:
|
| 203 |
+
start_pos += total_tokens
|
| 204 |
+
if (
|
| 205 |
+
args.single_round is not True and args.max_seq_len > 512
|
| 206 |
+
): # Only memorize previous conversations when kv_cache_size > 512
|
| 207 |
+
model_prompter.update_template(outputs, args.chunk_prefilling)
|
| 208 |
+
count += 1
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
if __name__ == "__main__":
|
| 212 |
+
parser = argparse.ArgumentParser()
|
| 213 |
+
parser.add_argument(
|
| 214 |
+
"--model_type", type=str, default="LLaMa", help="type of the model"
|
| 215 |
+
)
|
| 216 |
+
parser.add_argument(
|
| 217 |
+
"--model-path", type=str, default="/data/llm/checkpoints/llava/llava-v1.5-7b"
|
| 218 |
+
)
|
| 219 |
+
parser.add_argument(
|
| 220 |
+
"--quant_path",
|
| 221 |
+
type=str,
|
| 222 |
+
default="/data/llm/checkpoints/llava/llava-v1.5-7b-w4-g128-awq.pt",
|
| 223 |
+
)
|
| 224 |
+
parser.add_argument(
|
| 225 |
+
"--act_scale_path",
|
| 226 |
+
type=str,
|
| 227 |
+
default="/PATH/TO/SCALE",
|
| 228 |
+
)
|
| 229 |
+
parser.add_argument(
|
| 230 |
+
"--media", type=str, nargs="+", help="Multi-modal input (Video or image path)"
|
| 231 |
+
)
|
| 232 |
+
parser.add_argument("--device", type=str, default="cuda")
|
| 233 |
+
parser.add_argument("--max_seq_len", type=int, default=4098)
|
| 234 |
+
parser.add_argument(
|
| 235 |
+
"--single_round",
|
| 236 |
+
action="store_true",
|
| 237 |
+
help="whether to memorize previous conversations",
|
| 238 |
+
)
|
| 239 |
+
parser.add_argument(
|
| 240 |
+
"--vis-image",
|
| 241 |
+
action="store_true",
|
| 242 |
+
help="whether to visualize the image while chatting",
|
| 243 |
+
)
|
| 244 |
+
parser.add_argument(
|
| 245 |
+
"--empty-prompt",
|
| 246 |
+
action="store_true",
|
| 247 |
+
help="whether to use empty prompt template",
|
| 248 |
+
)
|
| 249 |
+
parser.add_argument(
|
| 250 |
+
"--flash_attn",
|
| 251 |
+
action="store_true",
|
| 252 |
+
help="whether to use flash attention",
|
| 253 |
+
)
|
| 254 |
+
parser.add_argument(
|
| 255 |
+
"--chunk_prefilling",
|
| 256 |
+
action="store_true",
|
| 257 |
+
help="If used, in context stage, the history tokens will not be recalculated, greatly speeding up the calculation",
|
| 258 |
+
)
|
| 259 |
+
# smooth and quantization options
|
| 260 |
+
parser.add_argument("--quant_llm", action="store_true")
|
| 261 |
+
parser.add_argument("--quant_VT", action="store_true")
|
| 262 |
+
parser.add_argument("--smooth_VT", action="store_true")
|
| 263 |
+
parser.add_argument("--all", action="store_true")
|
| 264 |
+
parser.add_argument(
|
| 265 |
+
"--fakequant_VT",
|
| 266 |
+
action="store_true",
|
| 267 |
+
help="Use fake quant or real quant for VisionTower",
|
| 268 |
+
)
|
| 269 |
+
args = parser.parse_args()
|
| 270 |
+
main(args)
|
llm-awq/tinychat/models/__init__.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .falcon import FalconForCausalLM
|
| 2 |
+
from .llama import LlamaForCausalLM
|
| 3 |
+
from .mpt import MPTForCausalLM
|
| 4 |
+
from .llava_llama import LlavaLlamaForCausalLM
|
| 5 |
+
from .qwen2 import Qwen2ForCausalLM
|
| 6 |
+
try:
|
| 7 |
+
from .internvl3 import InternVL3
|
| 8 |
+
except ImportError as e:
|
| 9 |
+
print("InternVL3 model import failure. To activate, please install VILA at https://github.com/NVlabs/VILA.")
|
| 10 |
+
|
llm-awq/tinychat/models/internvl/configuration_internvl.py
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# --------------------------------------------------------
|
| 2 |
+
# InternVL
|
| 3 |
+
# Copyright (c) 2024 OpenGVLab
|
| 4 |
+
# Licensed under The MIT License [see LICENSE for details]
|
| 5 |
+
# --------------------------------------------------------
|
| 6 |
+
|
| 7 |
+
import os
|
| 8 |
+
from typing import Union
|
| 9 |
+
import copy
|
| 10 |
+
|
| 11 |
+
from transformers.configuration_utils import PretrainedConfig
|
| 12 |
+
from transformers.utils import logging
|
| 13 |
+
from transformers import AutoConfig, LlamaConfig, Qwen2Config
|
| 14 |
+
|
| 15 |
+
logger = logging.get_logger(__name__)
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
class InternVisionConfig(PretrainedConfig):
|
| 19 |
+
r"""
|
| 20 |
+
This is the configuration class to store the configuration of a [`InternVisionModel`]. It is used to
|
| 21 |
+
instantiate a vision encoder according to the specified arguments, defining the model architecture.
|
| 22 |
+
|
| 23 |
+
Configuration objects inherit from [`PretrainedConfig`] and can be used to control the model outputs. Read the
|
| 24 |
+
documentation from [`PretrainedConfig`] for more information.
|
| 25 |
+
|
| 26 |
+
Args:
|
| 27 |
+
num_channels (`int`, *optional*, defaults to 3):
|
| 28 |
+
Number of color channels in the input images (e.g., 3 for RGB).
|
| 29 |
+
patch_size (`int`, *optional*, defaults to 14):
|
| 30 |
+
The size (resolution) of each patch.
|
| 31 |
+
image_size (`int`, *optional*, defaults to 224):
|
| 32 |
+
The size (resolution) of each image.
|
| 33 |
+
qkv_bias (`bool`, *optional*, defaults to `False`):
|
| 34 |
+
Whether to add a bias to the queries and values in the self-attention layers.
|
| 35 |
+
hidden_size (`int`, *optional*, defaults to 3200):
|
| 36 |
+
Dimensionality of the encoder layers and the pooler layer.
|
| 37 |
+
num_attention_heads (`int`, *optional*, defaults to 25):
|
| 38 |
+
Number of attention heads for each attention layer in the Transformer encoder.
|
| 39 |
+
intermediate_size (`int`, *optional*, defaults to 12800):
|
| 40 |
+
Dimensionality of the "intermediate" (i.e., feed-forward) layer in the Transformer encoder.
|
| 41 |
+
qk_normalization (`bool`, *optional*, defaults to `True`):
|
| 42 |
+
Whether to normalize the queries and keys in the self-attention layers.
|
| 43 |
+
num_hidden_layers (`int`, *optional*, defaults to 48):
|
| 44 |
+
Number of hidden layers in the Transformer encoder.
|
| 45 |
+
use_flash_attn (`bool`, *optional*, defaults to `True`):
|
| 46 |
+
Whether to use flash attention mechanism.
|
| 47 |
+
hidden_act (`str` or `function`, *optional*, defaults to `"gelu"`):
|
| 48 |
+
The non-linear activation function (function or string) in the encoder and pooler. If string, `"gelu"`,
|
| 49 |
+
`"relu"`, `"selu"` and `"gelu_new"` ``"gelu"` are supported.
|
| 50 |
+
layer_norm_eps (`float`, *optional*, defaults to 1e-6):
|
| 51 |
+
The epsilon used by the layer normalization layers.
|
| 52 |
+
dropout (`float`, *optional*, defaults to 0.0):
|
| 53 |
+
The dropout probability for all fully connected layers in the embeddings, encoder, and pooler.
|
| 54 |
+
drop_path_rate (`float`, *optional*, defaults to 0.0):
|
| 55 |
+
Dropout rate for stochastic depth.
|
| 56 |
+
attention_dropout (`float`, *optional*, defaults to 0.0):
|
| 57 |
+
The dropout ratio for the attention probabilities.
|
| 58 |
+
initializer_range (`float`, *optional*, defaults to 0.02):
|
| 59 |
+
The standard deviation of the truncated_normal_initializer for initializing all weight matrices.
|
| 60 |
+
initializer_factor (`float`, *optional*, defaults to 0.1):
|
| 61 |
+
A factor for layer scale.
|
| 62 |
+
"""
|
| 63 |
+
|
| 64 |
+
model_type = 'intern_vit_6b'
|
| 65 |
+
|
| 66 |
+
def __init__(
|
| 67 |
+
self,
|
| 68 |
+
num_channels=3,
|
| 69 |
+
patch_size=14,
|
| 70 |
+
image_size=224,
|
| 71 |
+
qkv_bias=False,
|
| 72 |
+
hidden_size=3200,
|
| 73 |
+
num_attention_heads=25,
|
| 74 |
+
intermediate_size=12800,
|
| 75 |
+
qk_normalization=True,
|
| 76 |
+
num_hidden_layers=48,
|
| 77 |
+
use_flash_attn=True,
|
| 78 |
+
hidden_act='gelu',
|
| 79 |
+
norm_type='rms_norm',
|
| 80 |
+
layer_norm_eps=1e-6,
|
| 81 |
+
dropout=0.0,
|
| 82 |
+
drop_path_rate=0.0,
|
| 83 |
+
attention_dropout=0.0,
|
| 84 |
+
initializer_range=0.02,
|
| 85 |
+
initializer_factor=0.1,
|
| 86 |
+
**kwargs,
|
| 87 |
+
):
|
| 88 |
+
super().__init__(**kwargs)
|
| 89 |
+
|
| 90 |
+
self.hidden_size = hidden_size
|
| 91 |
+
self.intermediate_size = intermediate_size
|
| 92 |
+
self.dropout = dropout
|
| 93 |
+
self.drop_path_rate = drop_path_rate
|
| 94 |
+
self.num_hidden_layers = num_hidden_layers
|
| 95 |
+
self.num_attention_heads = num_attention_heads
|
| 96 |
+
self.num_channels = num_channels
|
| 97 |
+
self.patch_size = patch_size
|
| 98 |
+
self.image_size = image_size
|
| 99 |
+
self.initializer_range = initializer_range
|
| 100 |
+
self.initializer_factor = initializer_factor
|
| 101 |
+
self.attention_dropout = attention_dropout
|
| 102 |
+
self.layer_norm_eps = layer_norm_eps
|
| 103 |
+
self.hidden_act = hidden_act
|
| 104 |
+
self.norm_type = norm_type
|
| 105 |
+
self.qkv_bias = qkv_bias
|
| 106 |
+
self.qk_normalization = qk_normalization
|
| 107 |
+
self.use_flash_attn = use_flash_attn
|
| 108 |
+
|
| 109 |
+
@classmethod
|
| 110 |
+
def from_pretrained(cls, pretrained_model_name_or_path: Union[str, os.PathLike], **kwargs) -> 'PretrainedConfig':
|
| 111 |
+
config_dict, kwargs = cls.get_config_dict(pretrained_model_name_or_path, **kwargs)
|
| 112 |
+
|
| 113 |
+
if 'vision_config' in config_dict:
|
| 114 |
+
config_dict = config_dict['vision_config']
|
| 115 |
+
|
| 116 |
+
if 'model_type' in config_dict and hasattr(cls, 'model_type') and config_dict['model_type'] != cls.model_type:
|
| 117 |
+
logger.warning(
|
| 118 |
+
f"You are using a model of type {config_dict['model_type']} to instantiate a model of type "
|
| 119 |
+
f'{cls.model_type}. This is not supported for all configurations of models and can yield errors.'
|
| 120 |
+
)
|
| 121 |
+
|
| 122 |
+
return cls.from_dict(config_dict, **kwargs)
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
class InternVLChatConfig(PretrainedConfig):
|
| 126 |
+
model_type = 'internvl_chat'
|
| 127 |
+
is_composition = True
|
| 128 |
+
|
| 129 |
+
def __init__(
|
| 130 |
+
self,
|
| 131 |
+
vision_config=None,
|
| 132 |
+
llm_config=None,
|
| 133 |
+
use_backbone_lora=0,
|
| 134 |
+
use_llm_lora=0,
|
| 135 |
+
select_layer=-1,
|
| 136 |
+
force_image_size=None,
|
| 137 |
+
downsample_ratio=0.5,
|
| 138 |
+
template=None,
|
| 139 |
+
dynamic_image_size=False,
|
| 140 |
+
use_thumbnail=False,
|
| 141 |
+
ps_version='v1',
|
| 142 |
+
min_dynamic_patch=1,
|
| 143 |
+
max_dynamic_patch=6,
|
| 144 |
+
**kwargs):
|
| 145 |
+
super().__init__(**kwargs)
|
| 146 |
+
|
| 147 |
+
if vision_config is None:
|
| 148 |
+
vision_config = {'architectures': ['InternVisionModel']}
|
| 149 |
+
logger.info('vision_config is None. Initializing the InternVisionConfig with default values.')
|
| 150 |
+
|
| 151 |
+
if llm_config is None:
|
| 152 |
+
llm_config = {'architectures': ['Qwen2ForCausalLM']}
|
| 153 |
+
logger.info('llm_config is None. Initializing the LlamaConfig config with default values (`LlamaConfig`).')
|
| 154 |
+
|
| 155 |
+
self.vision_config = InternVisionConfig(**vision_config)
|
| 156 |
+
if llm_config.get('architectures')[0] == 'LlamaForCausalLM':
|
| 157 |
+
self.llm_config = LlamaConfig(**llm_config)
|
| 158 |
+
elif llm_config.get('architectures')[0] == 'Qwen2ForCausalLM':
|
| 159 |
+
self.llm_config = Qwen2Config(**llm_config)
|
| 160 |
+
else:
|
| 161 |
+
raise ValueError('Unsupported architecture: {}'.format(llm_config.get('architectures')[0]))
|
| 162 |
+
self.use_backbone_lora = use_backbone_lora
|
| 163 |
+
self.use_llm_lora = use_llm_lora
|
| 164 |
+
self.select_layer = select_layer
|
| 165 |
+
self.force_image_size = force_image_size
|
| 166 |
+
self.downsample_ratio = downsample_ratio
|
| 167 |
+
self.template = template
|
| 168 |
+
self.dynamic_image_size = dynamic_image_size
|
| 169 |
+
self.use_thumbnail = use_thumbnail
|
| 170 |
+
self.ps_version = ps_version # pixel shuffle version
|
| 171 |
+
self.min_dynamic_patch = min_dynamic_patch
|
| 172 |
+
self.max_dynamic_patch = max_dynamic_patch
|
| 173 |
+
# By default, we use tie_word_embeddings=False for models of all sizes.
|
| 174 |
+
self.tie_word_embeddings = self.llm_config.tie_word_embeddings
|
| 175 |
+
|
| 176 |
+
logger.info(f'vision_select_layer: {self.select_layer}')
|
| 177 |
+
logger.info(f'ps_version: {self.ps_version}')
|
| 178 |
+
logger.info(f'min_dynamic_patch: {self.min_dynamic_patch}')
|
| 179 |
+
logger.info(f'max_dynamic_patch: {self.max_dynamic_patch}')
|
| 180 |
+
|
| 181 |
+
def to_dict(self):
|
| 182 |
+
"""
|
| 183 |
+
Serializes this instance to a Python dictionary. Override the default [`~PretrainedConfig.to_dict`].
|
| 184 |
+
|
| 185 |
+
Returns:
|
| 186 |
+
`Dict[str, any]`: Dictionary of all the attributes that make up this configuration instance,
|
| 187 |
+
"""
|
| 188 |
+
output = copy.deepcopy(self.__dict__)
|
| 189 |
+
output['vision_config'] = self.vision_config.to_dict()
|
| 190 |
+
output['llm_config'] = self.llm_config.to_dict()
|
| 191 |
+
output['model_type'] = self.__class__.model_type
|
| 192 |
+
output['use_backbone_lora'] = self.use_backbone_lora
|
| 193 |
+
output['use_llm_lora'] = self.use_llm_lora
|
| 194 |
+
output['select_layer'] = self.select_layer
|
| 195 |
+
output['force_image_size'] = self.force_image_size
|
| 196 |
+
output['downsample_ratio'] = self.downsample_ratio
|
| 197 |
+
output['template'] = self.template
|
| 198 |
+
output['dynamic_image_size'] = self.dynamic_image_size
|
| 199 |
+
output['use_thumbnail'] = self.use_thumbnail
|
| 200 |
+
output['ps_version'] = self.ps_version
|
| 201 |
+
output['min_dynamic_patch'] = self.min_dynamic_patch
|
| 202 |
+
output['max_dynamic_patch'] = self.max_dynamic_patch
|
| 203 |
+
|
| 204 |
+
return output
|
llm-awq/tinychat/models/internvl/conversation.py
ADDED
|
@@ -0,0 +1,391 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Conversation prompt templates.
|
| 3 |
+
|
| 4 |
+
We kindly request that you import fastchat instead of copying this file if you wish to use it.
|
| 5 |
+
If you have changes in mind, please contribute back so the community can benefit collectively and continue to maintain these valuable templates.
|
| 6 |
+
|
| 7 |
+
Modified from https://github.com/lm-sys/FastChat/blob/main/fastchat/conversation.py
|
| 8 |
+
"""
|
| 9 |
+
|
| 10 |
+
import dataclasses
|
| 11 |
+
from enum import IntEnum, auto
|
| 12 |
+
from typing import Dict, List, Tuple, Union
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
class SeparatorStyle(IntEnum):
|
| 16 |
+
"""Separator styles."""
|
| 17 |
+
|
| 18 |
+
ADD_COLON_SINGLE = auto()
|
| 19 |
+
ADD_COLON_TWO = auto()
|
| 20 |
+
ADD_COLON_SPACE_SINGLE = auto()
|
| 21 |
+
NO_COLON_SINGLE = auto()
|
| 22 |
+
NO_COLON_TWO = auto()
|
| 23 |
+
ADD_NEW_LINE_SINGLE = auto()
|
| 24 |
+
LLAMA2 = auto()
|
| 25 |
+
CHATGLM = auto()
|
| 26 |
+
CHATML = auto()
|
| 27 |
+
CHATINTERN = auto()
|
| 28 |
+
DOLLY = auto()
|
| 29 |
+
RWKV = auto()
|
| 30 |
+
PHOENIX = auto()
|
| 31 |
+
ROBIN = auto()
|
| 32 |
+
FALCON_CHAT = auto()
|
| 33 |
+
CHATGLM3 = auto()
|
| 34 |
+
INTERNVL_ZH = auto()
|
| 35 |
+
MPT = auto()
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
@dataclasses.dataclass
|
| 39 |
+
class Conversation:
|
| 40 |
+
"""A class that manages prompt templates and keeps all conversation history."""
|
| 41 |
+
|
| 42 |
+
# The name of this template
|
| 43 |
+
name: str
|
| 44 |
+
# The template of the system prompt
|
| 45 |
+
system_template: str = '{system_message}'
|
| 46 |
+
# The system message
|
| 47 |
+
system_message: str = ''
|
| 48 |
+
# The names of two roles
|
| 49 |
+
roles: Tuple[str] = ('USER', 'ASSISTANT')
|
| 50 |
+
# All messages. Each item is (role, message).
|
| 51 |
+
messages: List[List[str]] = ()
|
| 52 |
+
# The number of few shot examples
|
| 53 |
+
offset: int = 0
|
| 54 |
+
# The separator style and configurations
|
| 55 |
+
sep_style: SeparatorStyle = SeparatorStyle.ADD_COLON_SINGLE
|
| 56 |
+
sep: str = '\n'
|
| 57 |
+
sep2: str = None
|
| 58 |
+
# Stop criteria (the default one is EOS token)
|
| 59 |
+
stop_str: Union[str, List[str]] = None
|
| 60 |
+
# Stops generation if meeting any token in this list
|
| 61 |
+
stop_token_ids: List[int] = None
|
| 62 |
+
|
| 63 |
+
def get_prompt(self) -> str:
|
| 64 |
+
"""Get the prompt for generation."""
|
| 65 |
+
system_prompt = self.system_template.format(system_message=self.system_message)
|
| 66 |
+
if self.sep_style == SeparatorStyle.ADD_COLON_SINGLE:
|
| 67 |
+
ret = system_prompt + self.sep
|
| 68 |
+
for role, message in self.messages:
|
| 69 |
+
if message:
|
| 70 |
+
ret += role + ': ' + message + self.sep
|
| 71 |
+
else:
|
| 72 |
+
ret += role + ':'
|
| 73 |
+
return ret
|
| 74 |
+
elif self.sep_style == SeparatorStyle.ADD_COLON_TWO:
|
| 75 |
+
seps = [self.sep, self.sep2]
|
| 76 |
+
ret = system_prompt + seps[0]
|
| 77 |
+
for i, (role, message) in enumerate(self.messages):
|
| 78 |
+
if message:
|
| 79 |
+
ret += role + ': ' + message + seps[i % 2]
|
| 80 |
+
else:
|
| 81 |
+
ret += role + ':'
|
| 82 |
+
return ret
|
| 83 |
+
elif self.sep_style == SeparatorStyle.ADD_COLON_SPACE_SINGLE:
|
| 84 |
+
ret = system_prompt + self.sep
|
| 85 |
+
for role, message in self.messages:
|
| 86 |
+
if message:
|
| 87 |
+
ret += role + ': ' + message + self.sep
|
| 88 |
+
else:
|
| 89 |
+
ret += role + ': ' # must be end with a space
|
| 90 |
+
return ret
|
| 91 |
+
elif self.sep_style == SeparatorStyle.ADD_NEW_LINE_SINGLE:
|
| 92 |
+
ret = '' if system_prompt == '' else system_prompt + self.sep
|
| 93 |
+
for role, message in self.messages:
|
| 94 |
+
if message:
|
| 95 |
+
ret += role + '\n' + message + self.sep
|
| 96 |
+
else:
|
| 97 |
+
ret += role + '\n'
|
| 98 |
+
return ret
|
| 99 |
+
elif self.sep_style == SeparatorStyle.NO_COLON_SINGLE:
|
| 100 |
+
ret = system_prompt
|
| 101 |
+
for role, message in self.messages:
|
| 102 |
+
if message:
|
| 103 |
+
ret += role + message + self.sep
|
| 104 |
+
else:
|
| 105 |
+
ret += role
|
| 106 |
+
return ret
|
| 107 |
+
elif self.sep_style == SeparatorStyle.NO_COLON_TWO:
|
| 108 |
+
seps = [self.sep, self.sep2]
|
| 109 |
+
ret = system_prompt
|
| 110 |
+
for i, (role, message) in enumerate(self.messages):
|
| 111 |
+
if message:
|
| 112 |
+
ret += role + message + seps[i % 2]
|
| 113 |
+
else:
|
| 114 |
+
ret += role
|
| 115 |
+
return ret
|
| 116 |
+
elif self.sep_style == SeparatorStyle.RWKV:
|
| 117 |
+
ret = system_prompt
|
| 118 |
+
for i, (role, message) in enumerate(self.messages):
|
| 119 |
+
if message:
|
| 120 |
+
ret += (
|
| 121 |
+
role
|
| 122 |
+
+ ': '
|
| 123 |
+
+ message.replace('\r\n', '\n').replace('\n\n', '\n')
|
| 124 |
+
)
|
| 125 |
+
ret += '\n\n'
|
| 126 |
+
else:
|
| 127 |
+
ret += role + ':'
|
| 128 |
+
return ret
|
| 129 |
+
elif self.sep_style == SeparatorStyle.LLAMA2:
|
| 130 |
+
seps = [self.sep, self.sep2]
|
| 131 |
+
if self.system_message:
|
| 132 |
+
ret = system_prompt
|
| 133 |
+
else:
|
| 134 |
+
ret = '[INST] '
|
| 135 |
+
for i, (role, message) in enumerate(self.messages):
|
| 136 |
+
tag = self.roles[i % 2]
|
| 137 |
+
if message:
|
| 138 |
+
if i == 0:
|
| 139 |
+
ret += message + ' '
|
| 140 |
+
else:
|
| 141 |
+
ret += tag + ' ' + message + seps[i % 2]
|
| 142 |
+
else:
|
| 143 |
+
ret += tag
|
| 144 |
+
return ret
|
| 145 |
+
elif self.sep_style == SeparatorStyle.CHATGLM:
|
| 146 |
+
# source: https://huggingface.co/THUDM/chatglm-6b/blob/1d240ba371910e9282298d4592532d7f0f3e9f3e/modeling_chatglm.py#L1302-L1308
|
| 147 |
+
# source2: https://huggingface.co/THUDM/chatglm2-6b/blob/e186c891cf64310ac66ef10a87e6635fa6c2a579/modeling_chatglm.py#L926
|
| 148 |
+
round_add_n = 1 if self.name == 'chatglm2' else 0
|
| 149 |
+
if system_prompt:
|
| 150 |
+
ret = system_prompt + self.sep
|
| 151 |
+
else:
|
| 152 |
+
ret = ''
|
| 153 |
+
|
| 154 |
+
for i, (role, message) in enumerate(self.messages):
|
| 155 |
+
if i % 2 == 0:
|
| 156 |
+
ret += f'[Round {i//2 + round_add_n}]{self.sep}'
|
| 157 |
+
|
| 158 |
+
if message:
|
| 159 |
+
ret += f'{role}:{message}{self.sep}'
|
| 160 |
+
else:
|
| 161 |
+
ret += f'{role}:'
|
| 162 |
+
return ret
|
| 163 |
+
elif self.sep_style == SeparatorStyle.CHATML:
|
| 164 |
+
ret = '' if system_prompt == '' else system_prompt + self.sep + '\n'
|
| 165 |
+
for role, message in self.messages:
|
| 166 |
+
if message:
|
| 167 |
+
ret += role + '\n' + message + self.sep + '\n'
|
| 168 |
+
else:
|
| 169 |
+
ret += role + '\n'
|
| 170 |
+
return ret
|
| 171 |
+
elif self.sep_style == SeparatorStyle.CHATGLM3:
|
| 172 |
+
ret = ''
|
| 173 |
+
if self.system_message:
|
| 174 |
+
ret += system_prompt
|
| 175 |
+
for role, message in self.messages:
|
| 176 |
+
if message:
|
| 177 |
+
ret += role + '\n' + ' ' + message
|
| 178 |
+
else:
|
| 179 |
+
ret += role
|
| 180 |
+
return ret
|
| 181 |
+
elif self.sep_style == SeparatorStyle.CHATINTERN:
|
| 182 |
+
# source: https://huggingface.co/internlm/internlm-chat-7b-8k/blob/bd546fa984b4b0b86958f56bf37f94aa75ab8831/modeling_internlm.py#L771
|
| 183 |
+
seps = [self.sep, self.sep2]
|
| 184 |
+
ret = system_prompt
|
| 185 |
+
for i, (role, message) in enumerate(self.messages):
|
| 186 |
+
# if i % 2 == 0:
|
| 187 |
+
# ret += "<s>"
|
| 188 |
+
if message:
|
| 189 |
+
ret += role + ':' + message + seps[i % 2] + '\n'
|
| 190 |
+
else:
|
| 191 |
+
ret += role + ':'
|
| 192 |
+
return ret
|
| 193 |
+
elif self.sep_style == SeparatorStyle.DOLLY:
|
| 194 |
+
seps = [self.sep, self.sep2]
|
| 195 |
+
ret = system_prompt
|
| 196 |
+
for i, (role, message) in enumerate(self.messages):
|
| 197 |
+
if message:
|
| 198 |
+
ret += role + ':\n' + message + seps[i % 2]
|
| 199 |
+
if i % 2 == 1:
|
| 200 |
+
ret += '\n\n'
|
| 201 |
+
else:
|
| 202 |
+
ret += role + ':\n'
|
| 203 |
+
return ret
|
| 204 |
+
elif self.sep_style == SeparatorStyle.PHOENIX:
|
| 205 |
+
ret = system_prompt
|
| 206 |
+
for role, message in self.messages:
|
| 207 |
+
if message:
|
| 208 |
+
ret += role + ': ' + '<s>' + message + '</s>'
|
| 209 |
+
else:
|
| 210 |
+
ret += role + ': ' + '<s>'
|
| 211 |
+
return ret
|
| 212 |
+
elif self.sep_style == SeparatorStyle.ROBIN:
|
| 213 |
+
ret = system_prompt + self.sep
|
| 214 |
+
for role, message in self.messages:
|
| 215 |
+
if message:
|
| 216 |
+
ret += role + ':\n' + message + self.sep
|
| 217 |
+
else:
|
| 218 |
+
ret += role + ':\n'
|
| 219 |
+
return ret
|
| 220 |
+
elif self.sep_style == SeparatorStyle.FALCON_CHAT:
|
| 221 |
+
ret = ''
|
| 222 |
+
if self.system_message:
|
| 223 |
+
ret += system_prompt + self.sep
|
| 224 |
+
for role, message in self.messages:
|
| 225 |
+
if message:
|
| 226 |
+
ret += role + ': ' + message + self.sep
|
| 227 |
+
else:
|
| 228 |
+
ret += role + ':'
|
| 229 |
+
|
| 230 |
+
return ret
|
| 231 |
+
elif self.sep_style == SeparatorStyle.INTERNVL_ZH:
|
| 232 |
+
seps = [self.sep, self.sep2]
|
| 233 |
+
ret = self.system_message + seps[0]
|
| 234 |
+
for i, (role, message) in enumerate(self.messages):
|
| 235 |
+
if message:
|
| 236 |
+
ret += role + ': ' + message + seps[i % 2]
|
| 237 |
+
else:
|
| 238 |
+
ret += role + ':'
|
| 239 |
+
return ret
|
| 240 |
+
elif self.sep_style == SeparatorStyle.MPT:
|
| 241 |
+
ret = system_prompt + self.sep
|
| 242 |
+
for role, message in self.messages:
|
| 243 |
+
if message:
|
| 244 |
+
if type(message) is tuple:
|
| 245 |
+
message, _, _ = message
|
| 246 |
+
ret += role + message + self.sep
|
| 247 |
+
else:
|
| 248 |
+
ret += role
|
| 249 |
+
return ret
|
| 250 |
+
else:
|
| 251 |
+
raise ValueError(f'Invalid style: {self.sep_style}')
|
| 252 |
+
|
| 253 |
+
def set_system_message(self, system_message: str):
|
| 254 |
+
"""Set the system message."""
|
| 255 |
+
self.system_message = system_message
|
| 256 |
+
|
| 257 |
+
def append_message(self, role: str, message: str):
|
| 258 |
+
"""Append a new message."""
|
| 259 |
+
self.messages.append([role, message])
|
| 260 |
+
|
| 261 |
+
def update_last_message(self, message: str):
|
| 262 |
+
"""Update the last output.
|
| 263 |
+
|
| 264 |
+
The last message is typically set to be None when constructing the prompt,
|
| 265 |
+
so we need to update it in-place after getting the response from a model.
|
| 266 |
+
"""
|
| 267 |
+
self.messages[-1][1] = message
|
| 268 |
+
|
| 269 |
+
def to_gradio_chatbot(self):
|
| 270 |
+
"""Convert the conversation to gradio chatbot format."""
|
| 271 |
+
ret = []
|
| 272 |
+
for i, (role, msg) in enumerate(self.messages[self.offset :]):
|
| 273 |
+
if i % 2 == 0:
|
| 274 |
+
ret.append([msg, None])
|
| 275 |
+
else:
|
| 276 |
+
ret[-1][-1] = msg
|
| 277 |
+
return ret
|
| 278 |
+
|
| 279 |
+
def to_openai_api_messages(self):
|
| 280 |
+
"""Convert the conversation to OpenAI chat completion format."""
|
| 281 |
+
ret = [{'role': 'system', 'content': self.system_message}]
|
| 282 |
+
|
| 283 |
+
for i, (_, msg) in enumerate(self.messages[self.offset :]):
|
| 284 |
+
if i % 2 == 0:
|
| 285 |
+
ret.append({'role': 'user', 'content': msg})
|
| 286 |
+
else:
|
| 287 |
+
if msg is not None:
|
| 288 |
+
ret.append({'role': 'assistant', 'content': msg})
|
| 289 |
+
return ret
|
| 290 |
+
|
| 291 |
+
def copy(self):
|
| 292 |
+
return Conversation(
|
| 293 |
+
name=self.name,
|
| 294 |
+
system_template=self.system_template,
|
| 295 |
+
system_message=self.system_message,
|
| 296 |
+
roles=self.roles,
|
| 297 |
+
messages=[[x, y] for x, y in self.messages],
|
| 298 |
+
offset=self.offset,
|
| 299 |
+
sep_style=self.sep_style,
|
| 300 |
+
sep=self.sep,
|
| 301 |
+
sep2=self.sep2,
|
| 302 |
+
stop_str=self.stop_str,
|
| 303 |
+
stop_token_ids=self.stop_token_ids,
|
| 304 |
+
)
|
| 305 |
+
|
| 306 |
+
def dict(self):
|
| 307 |
+
return {
|
| 308 |
+
'template_name': self.name,
|
| 309 |
+
'system_message': self.system_message,
|
| 310 |
+
'roles': self.roles,
|
| 311 |
+
'messages': self.messages,
|
| 312 |
+
'offset': self.offset,
|
| 313 |
+
}
|
| 314 |
+
|
| 315 |
+
|
| 316 |
+
# A global registry for all conversation templates
|
| 317 |
+
conv_templates: Dict[str, Conversation] = {}
|
| 318 |
+
|
| 319 |
+
|
| 320 |
+
def register_conv_template(template: Conversation, override: bool = False):
|
| 321 |
+
"""Register a new conversation template."""
|
| 322 |
+
if not override:
|
| 323 |
+
assert (
|
| 324 |
+
template.name not in conv_templates
|
| 325 |
+
), f'{template.name} has been registered.'
|
| 326 |
+
|
| 327 |
+
conv_templates[template.name] = template
|
| 328 |
+
|
| 329 |
+
|
| 330 |
+
def get_conv_template(name: str) -> Conversation:
|
| 331 |
+
"""Get a conversation template."""
|
| 332 |
+
return conv_templates[name].copy()
|
| 333 |
+
|
| 334 |
+
|
| 335 |
+
# Both Hermes-2 and internlm2-chat are chatml-format conversation templates. The difference
|
| 336 |
+
# is that during training, the preprocessing function for the Hermes-2 template doesn't add
|
| 337 |
+
# <s> at the beginning of the tokenized sequence, while the internlm2-chat template does.
|
| 338 |
+
# Therefore, they are completely equivalent during inference.
|
| 339 |
+
register_conv_template(
|
| 340 |
+
Conversation(
|
| 341 |
+
name='Hermes-2',
|
| 342 |
+
system_template='<|im_start|>system\n{system_message}',
|
| 343 |
+
# note: The new system prompt was not used here to avoid changes in benchmark performance.
|
| 344 |
+
# system_message='我是书生·万象,英文名是InternVL,是由上海人工智能实验室、清华大学及多家合作单位联合开发的多模态大语言模型。',
|
| 345 |
+
system_message='你是由上海人工智能实验室联合商汤科技开发的书生多模态大模型,英文名叫InternVL, 是一个有用无害的人工智能助手。',
|
| 346 |
+
roles=('<|im_start|>user\n', '<|im_start|>assistant\n'),
|
| 347 |
+
sep_style=SeparatorStyle.MPT,
|
| 348 |
+
sep='<|im_end|>',
|
| 349 |
+
stop_str='<|endoftext|>',
|
| 350 |
+
)
|
| 351 |
+
)
|
| 352 |
+
|
| 353 |
+
|
| 354 |
+
register_conv_template(
|
| 355 |
+
Conversation(
|
| 356 |
+
name='internlm2-chat',
|
| 357 |
+
system_template='<|im_start|>system\n{system_message}',
|
| 358 |
+
# note: The new system prompt was not used here to avoid changes in benchmark performance.
|
| 359 |
+
# system_message='我是书生·万象,英文名是InternVL,是由上海人工智能实验室、清华大学及多家合作单位联合开发的多模态大语言模型。',
|
| 360 |
+
system_message='你是由上海人工智能实验室联合商汤科技开发的书生多模态大模型,英文名叫InternVL, 是一个有用无害的人工智能助手。',
|
| 361 |
+
roles=('<|im_start|>user\n', '<|im_start|>assistant\n'),
|
| 362 |
+
sep_style=SeparatorStyle.MPT,
|
| 363 |
+
sep='<|im_end|>',
|
| 364 |
+
)
|
| 365 |
+
)
|
| 366 |
+
|
| 367 |
+
|
| 368 |
+
register_conv_template(
|
| 369 |
+
Conversation(
|
| 370 |
+
name='phi3-chat',
|
| 371 |
+
system_template='<|system|>\n{system_message}',
|
| 372 |
+
# note: The new system prompt was not used here to avoid changes in benchmark performance.
|
| 373 |
+
# system_message='我是书生·万象,英文名是InternVL,是由上海人工智能实验室、清华大学及多家合作单位联合开发的多模态大语言模型。',
|
| 374 |
+
system_message='你是由上海人工智能实验室联合商汤科技开发的书生多模态大模型,英文名叫InternVL, 是一个有用无害的人工智能助手。',
|
| 375 |
+
roles=('<|user|>\n', '<|assistant|>\n'),
|
| 376 |
+
sep_style=SeparatorStyle.MPT,
|
| 377 |
+
sep='<|end|>',
|
| 378 |
+
)
|
| 379 |
+
)
|
| 380 |
+
|
| 381 |
+
|
| 382 |
+
register_conv_template(
|
| 383 |
+
Conversation(
|
| 384 |
+
name='internvl2_5',
|
| 385 |
+
system_template='<|im_start|>system\n{system_message}',
|
| 386 |
+
system_message='你是书生·万象,英文名是InternVL,是由上海人工智能实验室、清华大学及多家合作单位联合开发的多模态大语言模型。',
|
| 387 |
+
roles=('<|im_start|>user\n', '<|im_start|>assistant\n'),
|
| 388 |
+
sep_style=SeparatorStyle.MPT,
|
| 389 |
+
sep='<|im_end|>\n',
|
| 390 |
+
)
|
| 391 |
+
)
|
llm-awq/tinychat/models/internvl/internvit.py
ADDED
|
@@ -0,0 +1,425 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Optional, Tuple, Union
|
| 2 |
+
|
| 3 |
+
import torch
|
| 4 |
+
import torch.nn.functional as F
|
| 5 |
+
import torch.utils.checkpoint
|
| 6 |
+
from einops import rearrange
|
| 7 |
+
from timm.layers import DropPath
|
| 8 |
+
from torch import nn
|
| 9 |
+
from transformers.activations import ACT2FN
|
| 10 |
+
from transformers.modeling_outputs import (BaseModelOutput,
|
| 11 |
+
BaseModelOutputWithPooling)
|
| 12 |
+
from transformers.modeling_utils import PreTrainedModel
|
| 13 |
+
from transformers.utils import logging
|
| 14 |
+
|
| 15 |
+
from .configuration_internvl import InternVisionConfig
|
| 16 |
+
|
| 17 |
+
try:
|
| 18 |
+
from flash_attn.bert_padding import pad_input, unpad_input
|
| 19 |
+
from flash_attn.flash_attn_interface import \
|
| 20 |
+
flash_attn_varlen_qkvpacked_func
|
| 21 |
+
has_flash_attn = True
|
| 22 |
+
except:
|
| 23 |
+
print('FlashAttention2 is not installed.')
|
| 24 |
+
has_flash_attn = False
|
| 25 |
+
|
| 26 |
+
logger = logging.get_logger(__name__)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
class FlashAttention(nn.Module):
|
| 30 |
+
"""Implement the scaled dot product attention with softmax.
|
| 31 |
+
Arguments
|
| 32 |
+
---------
|
| 33 |
+
softmax_scale: The temperature to use for the softmax attention.
|
| 34 |
+
(default: 1/sqrt(d_keys) where d_keys is computed at
|
| 35 |
+
runtime)
|
| 36 |
+
attention_dropout: The dropout rate to apply to the attention
|
| 37 |
+
(default: 0.0)
|
| 38 |
+
"""
|
| 39 |
+
|
| 40 |
+
def __init__(self, softmax_scale=None, attention_dropout=0.0, device=None, dtype=None):
|
| 41 |
+
super().__init__()
|
| 42 |
+
self.softmax_scale = softmax_scale
|
| 43 |
+
self.dropout_p = attention_dropout
|
| 44 |
+
|
| 45 |
+
def forward(self, qkv, key_padding_mask=None, causal=False, cu_seqlens=None,
|
| 46 |
+
max_s=None, need_weights=False):
|
| 47 |
+
"""Implements the multihead softmax attention.
|
| 48 |
+
Arguments
|
| 49 |
+
---------
|
| 50 |
+
qkv: The tensor containing the query, key, and value. (B, S, 3, H, D) if key_padding_mask is None
|
| 51 |
+
if unpadded: (nnz, 3, h, d)
|
| 52 |
+
key_padding_mask: a bool tensor of shape (B, S)
|
| 53 |
+
"""
|
| 54 |
+
assert not need_weights
|
| 55 |
+
assert qkv.dtype in [torch.float16, torch.bfloat16]
|
| 56 |
+
assert qkv.is_cuda
|
| 57 |
+
|
| 58 |
+
if cu_seqlens is None:
|
| 59 |
+
batch_size = qkv.shape[0]
|
| 60 |
+
seqlen = qkv.shape[1]
|
| 61 |
+
if key_padding_mask is None:
|
| 62 |
+
qkv = rearrange(qkv, 'b s ... -> (b s) ...')
|
| 63 |
+
max_s = seqlen
|
| 64 |
+
cu_seqlens = torch.arange(0, (batch_size + 1) * seqlen, step=seqlen, dtype=torch.int32,
|
| 65 |
+
device=qkv.device)
|
| 66 |
+
output = flash_attn_varlen_qkvpacked_func(
|
| 67 |
+
qkv, cu_seqlens, max_s, self.dropout_p if self.training else 0.0,
|
| 68 |
+
softmax_scale=self.softmax_scale, causal=causal
|
| 69 |
+
)
|
| 70 |
+
output = rearrange(output, '(b s) ... -> b s ...', b=batch_size)
|
| 71 |
+
else:
|
| 72 |
+
nheads = qkv.shape[-2]
|
| 73 |
+
x = rearrange(qkv, 'b s three h d -> b s (three h d)')
|
| 74 |
+
x_unpad, indices, cu_seqlens, max_s = unpad_input(x, key_padding_mask)
|
| 75 |
+
x_unpad = rearrange(x_unpad, 'nnz (three h d) -> nnz three h d', three=3, h=nheads)
|
| 76 |
+
output_unpad = flash_attn_varlen_qkvpacked_func(
|
| 77 |
+
x_unpad, cu_seqlens, max_s, self.dropout_p if self.training else 0.0,
|
| 78 |
+
softmax_scale=self.softmax_scale, causal=causal
|
| 79 |
+
)
|
| 80 |
+
output = rearrange(pad_input(rearrange(output_unpad, 'nnz h d -> nnz (h d)'),
|
| 81 |
+
indices, batch_size, seqlen),
|
| 82 |
+
'b s (h d) -> b s h d', h=nheads)
|
| 83 |
+
else:
|
| 84 |
+
assert max_s is not None
|
| 85 |
+
output = flash_attn_varlen_qkvpacked_func(
|
| 86 |
+
qkv, cu_seqlens, max_s, self.dropout_p if self.training else 0.0,
|
| 87 |
+
softmax_scale=self.softmax_scale, causal=causal
|
| 88 |
+
)
|
| 89 |
+
|
| 90 |
+
return output, None
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
class InternRMSNorm(nn.Module):
|
| 94 |
+
def __init__(self, hidden_size, eps=1e-6):
|
| 95 |
+
super().__init__()
|
| 96 |
+
self.weight = nn.Parameter(torch.ones(hidden_size))
|
| 97 |
+
self.variance_epsilon = eps
|
| 98 |
+
|
| 99 |
+
def forward(self, hidden_states):
|
| 100 |
+
input_dtype = hidden_states.dtype
|
| 101 |
+
hidden_states = hidden_states.to(torch.float32)
|
| 102 |
+
variance = hidden_states.pow(2).mean(-1, keepdim=True)
|
| 103 |
+
hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
|
| 104 |
+
return self.weight * hidden_states.to(input_dtype)
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
try:
|
| 108 |
+
from apex.normalization import FusedRMSNorm
|
| 109 |
+
|
| 110 |
+
InternRMSNorm = FusedRMSNorm # noqa
|
| 111 |
+
|
| 112 |
+
logger.info('Discovered apex.normalization.FusedRMSNorm - will use it instead of InternRMSNorm')
|
| 113 |
+
except ImportError:
|
| 114 |
+
# using the normal InternRMSNorm
|
| 115 |
+
pass
|
| 116 |
+
except Exception:
|
| 117 |
+
logger.warning('discovered apex but it failed to load, falling back to InternRMSNorm')
|
| 118 |
+
pass
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
NORM2FN = {
|
| 122 |
+
'rms_norm': InternRMSNorm,
|
| 123 |
+
'layer_norm': nn.LayerNorm,
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
class InternVisionEmbeddings(nn.Module):
|
| 128 |
+
def __init__(self, config: InternVisionConfig):
|
| 129 |
+
super().__init__()
|
| 130 |
+
self.config = config
|
| 131 |
+
self.embed_dim = config.hidden_size
|
| 132 |
+
self.image_size = config.image_size
|
| 133 |
+
self.patch_size = config.patch_size
|
| 134 |
+
|
| 135 |
+
self.class_embedding = nn.Parameter(
|
| 136 |
+
torch.randn(1, 1, self.embed_dim),
|
| 137 |
+
)
|
| 138 |
+
|
| 139 |
+
self.patch_embedding = nn.Conv2d(
|
| 140 |
+
in_channels=3, out_channels=self.embed_dim, kernel_size=self.patch_size, stride=self.patch_size
|
| 141 |
+
)
|
| 142 |
+
|
| 143 |
+
self.num_patches = (self.image_size // self.patch_size) ** 2
|
| 144 |
+
self.num_positions = self.num_patches + 1
|
| 145 |
+
|
| 146 |
+
self.position_embedding = nn.Parameter(torch.randn(1, self.num_positions, self.embed_dim))
|
| 147 |
+
|
| 148 |
+
def _get_pos_embed(self, pos_embed, H, W):
|
| 149 |
+
target_dtype = pos_embed.dtype
|
| 150 |
+
pos_embed = pos_embed.float().reshape(
|
| 151 |
+
1, self.image_size // self.patch_size, self.image_size // self.patch_size, -1).permute(0, 3, 1, 2)
|
| 152 |
+
pos_embed = F.interpolate(pos_embed, size=(H, W), mode='bicubic', align_corners=False). \
|
| 153 |
+
reshape(1, -1, H * W).permute(0, 2, 1).to(target_dtype)
|
| 154 |
+
return pos_embed
|
| 155 |
+
|
| 156 |
+
def forward(self, pixel_values: torch.FloatTensor) -> torch.Tensor:
|
| 157 |
+
target_dtype = self.patch_embedding.weight.dtype
|
| 158 |
+
patch_embeds = self.patch_embedding(pixel_values) # shape = [*, channel, width, height]
|
| 159 |
+
batch_size, _, height, width = patch_embeds.shape
|
| 160 |
+
patch_embeds = patch_embeds.flatten(2).transpose(1, 2)
|
| 161 |
+
class_embeds = self.class_embedding.expand(batch_size, 1, -1).to(target_dtype)
|
| 162 |
+
embeddings = torch.cat([class_embeds, patch_embeds], dim=1)
|
| 163 |
+
position_embedding = torch.cat([
|
| 164 |
+
self.position_embedding[:, :1, :],
|
| 165 |
+
self._get_pos_embed(self.position_embedding[:, 1:, :], height, width)
|
| 166 |
+
], dim=1)
|
| 167 |
+
embeddings = embeddings + position_embedding.to(target_dtype)
|
| 168 |
+
return embeddings
|
| 169 |
+
|
| 170 |
+
|
| 171 |
+
class InternAttention(nn.Module):
|
| 172 |
+
"""Multi-headed attention from 'Attention Is All You Need' paper"""
|
| 173 |
+
|
| 174 |
+
def __init__(self, config: InternVisionConfig):
|
| 175 |
+
super().__init__()
|
| 176 |
+
self.config = config
|
| 177 |
+
self.embed_dim = config.hidden_size
|
| 178 |
+
self.num_heads = config.num_attention_heads
|
| 179 |
+
self.use_flash_attn = config.use_flash_attn and has_flash_attn
|
| 180 |
+
if config.use_flash_attn and not has_flash_attn:
|
| 181 |
+
print('Warning: Flash Attention is not available, use_flash_attn is set to False.')
|
| 182 |
+
self.head_dim = self.embed_dim // self.num_heads
|
| 183 |
+
if self.head_dim * self.num_heads != self.embed_dim:
|
| 184 |
+
raise ValueError(
|
| 185 |
+
f'embed_dim must be divisible by num_heads (got `embed_dim`: {self.embed_dim} and `num_heads`:'
|
| 186 |
+
f' {self.num_heads}).'
|
| 187 |
+
)
|
| 188 |
+
|
| 189 |
+
self.scale = self.head_dim ** -0.5
|
| 190 |
+
self.qkv = nn.Linear(self.embed_dim, 3 * self.embed_dim, bias=config.qkv_bias)
|
| 191 |
+
self.attn_drop = nn.Dropout(config.attention_dropout)
|
| 192 |
+
self.proj_drop = nn.Dropout(config.dropout)
|
| 193 |
+
|
| 194 |
+
self.qk_normalization = config.qk_normalization
|
| 195 |
+
|
| 196 |
+
if self.qk_normalization:
|
| 197 |
+
self.q_norm = InternRMSNorm(self.embed_dim, eps=config.layer_norm_eps)
|
| 198 |
+
self.k_norm = InternRMSNorm(self.embed_dim, eps=config.layer_norm_eps)
|
| 199 |
+
|
| 200 |
+
if self.use_flash_attn:
|
| 201 |
+
self.inner_attn = FlashAttention(attention_dropout=config.attention_dropout)
|
| 202 |
+
self.proj = nn.Linear(self.embed_dim, self.embed_dim)
|
| 203 |
+
|
| 204 |
+
def _naive_attn(self, x):
|
| 205 |
+
B, N, C = x.shape
|
| 206 |
+
qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4)
|
| 207 |
+
q, k, v = qkv.unbind(0) # make torchscript happy (cannot use tensor as tuple)
|
| 208 |
+
|
| 209 |
+
if self.qk_normalization:
|
| 210 |
+
B_, H_, N_, D_ = q.shape
|
| 211 |
+
q = self.q_norm(q.transpose(1, 2).flatten(-2, -1)).view(B_, N_, H_, D_).transpose(1, 2)
|
| 212 |
+
k = self.k_norm(k.transpose(1, 2).flatten(-2, -1)).view(B_, N_, H_, D_).transpose(1, 2)
|
| 213 |
+
|
| 214 |
+
attn = ((q * self.scale) @ k.transpose(-2, -1))
|
| 215 |
+
attn = attn.softmax(dim=-1)
|
| 216 |
+
attn = self.attn_drop(attn)
|
| 217 |
+
|
| 218 |
+
x = (attn @ v).transpose(1, 2).reshape(B, N, C)
|
| 219 |
+
x = self.proj(x)
|
| 220 |
+
x = self.proj_drop(x)
|
| 221 |
+
return x
|
| 222 |
+
|
| 223 |
+
def _flash_attn(self, x, key_padding_mask=None, need_weights=False):
|
| 224 |
+
qkv = self.qkv(x)
|
| 225 |
+
qkv = rearrange(qkv, 'b s (three h d) -> b s three h d', three=3, h=self.num_heads)
|
| 226 |
+
|
| 227 |
+
if self.qk_normalization:
|
| 228 |
+
q, k, v = qkv.unbind(2)
|
| 229 |
+
q = self.q_norm(q.flatten(-2, -1)).view(q.shape)
|
| 230 |
+
k = self.k_norm(k.flatten(-2, -1)).view(k.shape)
|
| 231 |
+
qkv = torch.stack([q, k, v], dim=2)
|
| 232 |
+
|
| 233 |
+
context, _ = self.inner_attn(
|
| 234 |
+
qkv, key_padding_mask=key_padding_mask, need_weights=need_weights, causal=False
|
| 235 |
+
)
|
| 236 |
+
outs = self.proj(rearrange(context, 'b s h d -> b s (h d)'))
|
| 237 |
+
outs = self.proj_drop(outs)
|
| 238 |
+
return outs
|
| 239 |
+
|
| 240 |
+
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
| 241 |
+
x = self._naive_attn(hidden_states) if not self.use_flash_attn else self._flash_attn(hidden_states)
|
| 242 |
+
return x
|
| 243 |
+
|
| 244 |
+
|
| 245 |
+
class InternMLP(nn.Module):
|
| 246 |
+
def __init__(self, config: InternVisionConfig):
|
| 247 |
+
super().__init__()
|
| 248 |
+
self.config = config
|
| 249 |
+
self.act = ACT2FN[config.hidden_act]
|
| 250 |
+
self.fc1 = nn.Linear(config.hidden_size, config.intermediate_size)
|
| 251 |
+
self.fc2 = nn.Linear(config.intermediate_size, config.hidden_size)
|
| 252 |
+
|
| 253 |
+
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
| 254 |
+
hidden_states = self.fc1(hidden_states)
|
| 255 |
+
hidden_states = self.act(hidden_states)
|
| 256 |
+
hidden_states = self.fc2(hidden_states)
|
| 257 |
+
return hidden_states
|
| 258 |
+
|
| 259 |
+
|
| 260 |
+
class InternVisionEncoderLayer(nn.Module):
|
| 261 |
+
def __init__(self, config: InternVisionConfig, drop_path_rate: float):
|
| 262 |
+
super().__init__()
|
| 263 |
+
self.embed_dim = config.hidden_size
|
| 264 |
+
self.intermediate_size = config.intermediate_size
|
| 265 |
+
self.norm_type = config.norm_type
|
| 266 |
+
|
| 267 |
+
self.attn = InternAttention(config)
|
| 268 |
+
self.mlp = InternMLP(config)
|
| 269 |
+
self.norm1 = NORM2FN[self.norm_type](self.embed_dim, eps=config.layer_norm_eps)
|
| 270 |
+
self.norm2 = NORM2FN[self.norm_type](self.embed_dim, eps=config.layer_norm_eps)
|
| 271 |
+
|
| 272 |
+
self.ls1 = nn.Parameter(config.initializer_factor * torch.ones(self.embed_dim))
|
| 273 |
+
self.ls2 = nn.Parameter(config.initializer_factor * torch.ones(self.embed_dim))
|
| 274 |
+
self.drop_path1 = DropPath(drop_path_rate) if drop_path_rate > 0. else nn.Identity()
|
| 275 |
+
self.drop_path2 = DropPath(drop_path_rate) if drop_path_rate > 0. else nn.Identity()
|
| 276 |
+
|
| 277 |
+
def forward(
|
| 278 |
+
self,
|
| 279 |
+
hidden_states: torch.Tensor,
|
| 280 |
+
) -> Tuple[torch.FloatTensor, Optional[torch.FloatTensor], Optional[Tuple[torch.FloatTensor]]]:
|
| 281 |
+
"""
|
| 282 |
+
Args:
|
| 283 |
+
hidden_states (`Tuple[torch.FloatTensor, Optional[torch.FloatTensor]]`): input to the layer of shape `(batch, seq_len, embed_dim)`
|
| 284 |
+
"""
|
| 285 |
+
hidden_states = hidden_states + self.drop_path1(self.attn(self.norm1(hidden_states).to(hidden_states.dtype)) * self.ls1)
|
| 286 |
+
|
| 287 |
+
hidden_states = hidden_states + self.drop_path2(self.mlp(self.norm2(hidden_states).to(hidden_states.dtype)) * self.ls2)
|
| 288 |
+
|
| 289 |
+
return hidden_states
|
| 290 |
+
|
| 291 |
+
|
| 292 |
+
class InternVisionEncoder(nn.Module):
|
| 293 |
+
"""
|
| 294 |
+
Transformer encoder consisting of `config.num_hidden_layers` self attention layers. Each layer is a
|
| 295 |
+
[`InternEncoderLayer`].
|
| 296 |
+
|
| 297 |
+
Args:
|
| 298 |
+
config (`InternConfig`):
|
| 299 |
+
The corresponding vision configuration for the `InternEncoder`.
|
| 300 |
+
"""
|
| 301 |
+
|
| 302 |
+
def __init__(self, config: InternVisionConfig):
|
| 303 |
+
super().__init__()
|
| 304 |
+
self.config = config
|
| 305 |
+
# stochastic depth decay rule
|
| 306 |
+
dpr = [x.item() for x in torch.linspace(0, config.drop_path_rate, config.num_hidden_layers)]
|
| 307 |
+
self.layers = nn.ModuleList([
|
| 308 |
+
InternVisionEncoderLayer(config, dpr[idx]) for idx in range(config.num_hidden_layers)])
|
| 309 |
+
self.gradient_checkpointing = True
|
| 310 |
+
|
| 311 |
+
def forward(
|
| 312 |
+
self,
|
| 313 |
+
inputs_embeds,
|
| 314 |
+
output_hidden_states: Optional[bool] = None,
|
| 315 |
+
return_dict: Optional[bool] = None,
|
| 316 |
+
) -> Union[Tuple, BaseModelOutput]:
|
| 317 |
+
r"""
|
| 318 |
+
Args:
|
| 319 |
+
inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
|
| 320 |
+
Embedded representation of the inputs. Should be float, not int tokens.
|
| 321 |
+
output_hidden_states (`bool`, *optional*):
|
| 322 |
+
Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors
|
| 323 |
+
for more detail.
|
| 324 |
+
return_dict (`bool`, *optional*):
|
| 325 |
+
Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple.
|
| 326 |
+
"""
|
| 327 |
+
output_hidden_states = (
|
| 328 |
+
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
|
| 329 |
+
)
|
| 330 |
+
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
| 331 |
+
|
| 332 |
+
encoder_states = () if output_hidden_states else None
|
| 333 |
+
hidden_states = inputs_embeds
|
| 334 |
+
|
| 335 |
+
for idx, encoder_layer in enumerate(self.layers):
|
| 336 |
+
if output_hidden_states:
|
| 337 |
+
encoder_states = encoder_states + (hidden_states,)
|
| 338 |
+
if self.gradient_checkpointing and self.training:
|
| 339 |
+
layer_outputs = torch.utils.checkpoint.checkpoint(
|
| 340 |
+
encoder_layer,
|
| 341 |
+
hidden_states)
|
| 342 |
+
else:
|
| 343 |
+
layer_outputs = encoder_layer(
|
| 344 |
+
hidden_states,
|
| 345 |
+
)
|
| 346 |
+
hidden_states = layer_outputs
|
| 347 |
+
|
| 348 |
+
if output_hidden_states:
|
| 349 |
+
encoder_states = encoder_states + (hidden_states,)
|
| 350 |
+
|
| 351 |
+
if not return_dict:
|
| 352 |
+
return tuple(v for v in [hidden_states, encoder_states] if v is not None)
|
| 353 |
+
return BaseModelOutput(
|
| 354 |
+
last_hidden_state=hidden_states, hidden_states=encoder_states
|
| 355 |
+
)
|
| 356 |
+
|
| 357 |
+
|
| 358 |
+
class InternVisionModel(PreTrainedModel):
|
| 359 |
+
main_input_name = 'pixel_values'
|
| 360 |
+
_supports_flash_attn_2 = True
|
| 361 |
+
supports_gradient_checkpointing = True
|
| 362 |
+
config_class = InternVisionConfig
|
| 363 |
+
_no_split_modules = ['InternVisionEncoderLayer']
|
| 364 |
+
|
| 365 |
+
def __init__(self, config: InternVisionConfig):
|
| 366 |
+
super().__init__(config)
|
| 367 |
+
self.config = config
|
| 368 |
+
|
| 369 |
+
self.embeddings = InternVisionEmbeddings(config)
|
| 370 |
+
self.encoder = InternVisionEncoder(config)
|
| 371 |
+
|
| 372 |
+
def resize_pos_embeddings(self, old_size, new_size, patch_size):
|
| 373 |
+
pos_emb = self.embeddings.position_embedding
|
| 374 |
+
_, num_positions, embed_dim = pos_emb.shape
|
| 375 |
+
cls_emb = pos_emb[:, :1, :]
|
| 376 |
+
pos_emb = pos_emb[:, 1:, :].reshape(1, old_size // patch_size, old_size // patch_size, -1).permute(0, 3, 1, 2)
|
| 377 |
+
pos_emb = F.interpolate(pos_emb.float(), size=new_size // patch_size, mode='bicubic', align_corners=False)
|
| 378 |
+
pos_emb = pos_emb.to(cls_emb.dtype).reshape(1, embed_dim, -1).permute(0, 2, 1)
|
| 379 |
+
pos_emb = torch.cat([cls_emb, pos_emb], dim=1)
|
| 380 |
+
self.embeddings.position_embedding = nn.Parameter(pos_emb)
|
| 381 |
+
self.embeddings.image_size = new_size
|
| 382 |
+
logger.info('Resized position embeddings from {} to {}'.format(old_size, new_size))
|
| 383 |
+
|
| 384 |
+
def get_input_embeddings(self):
|
| 385 |
+
return self.embeddings
|
| 386 |
+
|
| 387 |
+
def forward(
|
| 388 |
+
self,
|
| 389 |
+
pixel_values: Optional[torch.FloatTensor] = None,
|
| 390 |
+
output_hidden_states: Optional[bool] = None,
|
| 391 |
+
return_dict: Optional[bool] = None,
|
| 392 |
+
pixel_embeds: Optional[torch.FloatTensor] = None,
|
| 393 |
+
) -> Union[Tuple, BaseModelOutputWithPooling]:
|
| 394 |
+
output_hidden_states = (
|
| 395 |
+
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
|
| 396 |
+
)
|
| 397 |
+
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
| 398 |
+
|
| 399 |
+
if pixel_values is None and pixel_embeds is None:
|
| 400 |
+
raise ValueError('You have to specify pixel_values or pixel_embeds')
|
| 401 |
+
|
| 402 |
+
if pixel_embeds is not None:
|
| 403 |
+
hidden_states = pixel_embeds
|
| 404 |
+
else:
|
| 405 |
+
if len(pixel_values.shape) == 4:
|
| 406 |
+
hidden_states = self.embeddings(pixel_values)
|
| 407 |
+
else:
|
| 408 |
+
raise ValueError(f'wrong pixel_values size: {pixel_values.shape}')
|
| 409 |
+
encoder_outputs = self.encoder(
|
| 410 |
+
inputs_embeds=hidden_states,
|
| 411 |
+
output_hidden_states=output_hidden_states,
|
| 412 |
+
return_dict=return_dict,
|
| 413 |
+
)
|
| 414 |
+
last_hidden_state = encoder_outputs.last_hidden_state
|
| 415 |
+
pooled_output = last_hidden_state[:, 0, :]
|
| 416 |
+
|
| 417 |
+
if not return_dict:
|
| 418 |
+
return (last_hidden_state, pooled_output) + encoder_outputs[1:]
|
| 419 |
+
|
| 420 |
+
return BaseModelOutputWithPooling(
|
| 421 |
+
last_hidden_state=last_hidden_state,
|
| 422 |
+
pooler_output=pooled_output,
|
| 423 |
+
hidden_states=encoder_outputs.hidden_states,
|
| 424 |
+
attentions=encoder_outputs.attentions,
|
| 425 |
+
)
|
llm-awq/tinychat/models/internvl/media.py
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import math
|
| 2 |
+
import numpy as np
|
| 3 |
+
import torch
|
| 4 |
+
import torchvision.transforms as T
|
| 5 |
+
from decord import VideoReader, cpu
|
| 6 |
+
from PIL import Image
|
| 7 |
+
from torchvision.transforms.functional import InterpolationMode
|
| 8 |
+
|
| 9 |
+
IMAGENET_MEAN = (0.485, 0.456, 0.406)
|
| 10 |
+
IMAGENET_STD = (0.229, 0.224, 0.225)
|
| 11 |
+
|
| 12 |
+
def build_transform(input_size):
|
| 13 |
+
MEAN, STD = IMAGENET_MEAN, IMAGENET_STD
|
| 14 |
+
transform = T.Compose([
|
| 15 |
+
T.Lambda(lambda img: img.convert('RGB') if img.mode != 'RGB' else img),
|
| 16 |
+
T.Resize((input_size, input_size), interpolation=InterpolationMode.BICUBIC),
|
| 17 |
+
T.ToTensor(),
|
| 18 |
+
T.Normalize(mean=MEAN, std=STD)
|
| 19 |
+
])
|
| 20 |
+
return transform
|
| 21 |
+
|
| 22 |
+
def find_closest_aspect_ratio(aspect_ratio, target_ratios, width, height, image_size):
|
| 23 |
+
best_ratio_diff = float('inf')
|
| 24 |
+
best_ratio = (1, 1)
|
| 25 |
+
area = width * height
|
| 26 |
+
for ratio in target_ratios:
|
| 27 |
+
target_aspect_ratio = ratio[0] / ratio[1]
|
| 28 |
+
ratio_diff = abs(aspect_ratio - target_aspect_ratio)
|
| 29 |
+
if ratio_diff < best_ratio_diff:
|
| 30 |
+
best_ratio_diff = ratio_diff
|
| 31 |
+
best_ratio = ratio
|
| 32 |
+
elif ratio_diff == best_ratio_diff:
|
| 33 |
+
if area > 0.5 * image_size * image_size * ratio[0] * ratio[1]:
|
| 34 |
+
best_ratio = ratio
|
| 35 |
+
return best_ratio
|
| 36 |
+
|
| 37 |
+
def dynamic_preprocess(image, min_num=1, max_num=12, image_size=448, use_thumbnail=False):
|
| 38 |
+
orig_width, orig_height = image.size
|
| 39 |
+
aspect_ratio = orig_width / orig_height
|
| 40 |
+
|
| 41 |
+
# calculate the existing image aspect ratio
|
| 42 |
+
target_ratios = set(
|
| 43 |
+
(i, j) for n in range(min_num, max_num + 1) for i in range(1, n + 1) for j in range(1, n + 1) if
|
| 44 |
+
i * j <= max_num and i * j >= min_num)
|
| 45 |
+
target_ratios = sorted(target_ratios, key=lambda x: x[0] * x[1])
|
| 46 |
+
|
| 47 |
+
# find the closest aspect ratio to the target
|
| 48 |
+
target_aspect_ratio = find_closest_aspect_ratio(
|
| 49 |
+
aspect_ratio, target_ratios, orig_width, orig_height, image_size)
|
| 50 |
+
|
| 51 |
+
# calculate the target width and height
|
| 52 |
+
target_width = image_size * target_aspect_ratio[0]
|
| 53 |
+
target_height = image_size * target_aspect_ratio[1]
|
| 54 |
+
blocks = target_aspect_ratio[0] * target_aspect_ratio[1]
|
| 55 |
+
|
| 56 |
+
# resize the image
|
| 57 |
+
resized_img = image.resize((target_width, target_height))
|
| 58 |
+
processed_images = []
|
| 59 |
+
for i in range(blocks):
|
| 60 |
+
box = (
|
| 61 |
+
(i % (target_width // image_size)) * image_size,
|
| 62 |
+
(i // (target_width // image_size)) * image_size,
|
| 63 |
+
((i % (target_width // image_size)) + 1) * image_size,
|
| 64 |
+
((i // (target_width // image_size)) + 1) * image_size
|
| 65 |
+
)
|
| 66 |
+
# split the image
|
| 67 |
+
split_img = resized_img.crop(box)
|
| 68 |
+
processed_images.append(split_img)
|
| 69 |
+
assert len(processed_images) == blocks
|
| 70 |
+
if use_thumbnail and len(processed_images) != 1:
|
| 71 |
+
thumbnail_img = image.resize((image_size, image_size))
|
| 72 |
+
processed_images.append(thumbnail_img)
|
| 73 |
+
return processed_images
|
| 74 |
+
|
| 75 |
+
def load_image(image_file, input_size=448, max_num=12):
|
| 76 |
+
image = Image.open(image_file).convert('RGB')
|
| 77 |
+
transform = build_transform(input_size=input_size)
|
| 78 |
+
images = dynamic_preprocess(image, image_size=input_size, use_thumbnail=True, max_num=max_num)
|
| 79 |
+
pixel_values = [transform(image) for image in images]
|
| 80 |
+
pixel_values = torch.stack(pixel_values)
|
| 81 |
+
return pixel_values
|
| 82 |
+
|
| 83 |
+
def get_index(bound, fps, max_frame, first_idx=0, num_segments=32):
|
| 84 |
+
if bound:
|
| 85 |
+
start, end = bound[0], bound[1]
|
| 86 |
+
else:
|
| 87 |
+
start, end = -100000, 100000
|
| 88 |
+
start_idx = max(first_idx, round(start * fps))
|
| 89 |
+
end_idx = min(round(end * fps), max_frame)
|
| 90 |
+
seg_size = float(end_idx - start_idx) / num_segments
|
| 91 |
+
frame_indices = np.array([
|
| 92 |
+
int(start_idx + (seg_size / 2) + np.round(seg_size * idx))
|
| 93 |
+
for idx in range(num_segments)
|
| 94 |
+
])
|
| 95 |
+
return frame_indices
|
| 96 |
+
|
| 97 |
+
def load_video(video_path, bound=None, input_size=448, max_num=1, num_segments=32):
|
| 98 |
+
vr = VideoReader(video_path, ctx=cpu(0), num_threads=1)
|
| 99 |
+
max_frame = len(vr) - 1
|
| 100 |
+
fps = float(vr.get_avg_fps())
|
| 101 |
+
|
| 102 |
+
pixel_values_list, num_patches_list = [], []
|
| 103 |
+
transform = build_transform(input_size=input_size)
|
| 104 |
+
frame_indices = get_index(bound, fps, max_frame, first_idx=0, num_segments=num_segments)
|
| 105 |
+
for frame_index in frame_indices:
|
| 106 |
+
img = Image.fromarray(vr[frame_index].asnumpy()).convert('RGB')
|
| 107 |
+
img = dynamic_preprocess(img, image_size=input_size, use_thumbnail=True, max_num=max_num)
|
| 108 |
+
pixel_values = [transform(tile) for tile in img]
|
| 109 |
+
pixel_values = torch.stack(pixel_values)
|
| 110 |
+
num_patches_list.append(pixel_values.shape[0])
|
| 111 |
+
pixel_values_list.append(pixel_values)
|
| 112 |
+
|
| 113 |
+
return pixel_values_list, num_patches_list
|
llm-awq/tinychat/models/llama.py
ADDED
|
@@ -0,0 +1,413 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
| 2 |
+
# This software may be used and distributed according to the terms of the GNU General Public License version 3.
|
| 3 |
+
|
| 4 |
+
from typing import Optional, Tuple
|
| 5 |
+
from dataclasses import dataclass
|
| 6 |
+
import math
|
| 7 |
+
|
| 8 |
+
import torch
|
| 9 |
+
from torch import nn
|
| 10 |
+
import torch.nn.functional as F
|
| 11 |
+
import awq_inference_engine
|
| 12 |
+
from transformers.models.llama.modeling_llama import LlamaRotaryEmbedding
|
| 13 |
+
|
| 14 |
+
# from flash_attn.flash_attn_interface import flash_attn_unpadded_func
|
| 15 |
+
|
| 16 |
+
import tinychat.utils.constants
|
| 17 |
+
|
| 18 |
+
max_batch_size = tinychat.utils.constants.max_batch_size
|
| 19 |
+
multiple_of = tinychat.utils.constants.llama_multiple_of
|
| 20 |
+
max_seq_len = tinychat.utils.constants.max_seq_len
|
| 21 |
+
from flash_attn import flash_attn_func
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class RMSNorm(torch.nn.Module):
|
| 25 |
+
def __init__(self, dim: int, eps: float = 1e-6):
|
| 26 |
+
super().__init__()
|
| 27 |
+
self.eps = eps
|
| 28 |
+
self.weight = nn.Parameter(torch.ones(dim))
|
| 29 |
+
|
| 30 |
+
def _norm(self, x):
|
| 31 |
+
return x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)
|
| 32 |
+
|
| 33 |
+
def forward(self, x):
|
| 34 |
+
output = torch.empty_like(x)
|
| 35 |
+
awq_inference_engine.layernorm_forward_cuda(x, self.weight, output, self.eps)
|
| 36 |
+
return output
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def precompute_freqs_cis(
|
| 40 |
+
dim: int, end: int, theta: float = 10000.0, scale: float = 1.0
|
| 41 |
+
):
|
| 42 |
+
freqs = 1.0 / (theta ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim))
|
| 43 |
+
t = torch.arange(end, device=freqs.device) # type: ignore
|
| 44 |
+
freqs = torch.outer(t * scale, freqs).float() # type: ignore
|
| 45 |
+
|
| 46 |
+
freqs_cis = torch.polar(torch.ones_like(freqs), freqs) # complex64
|
| 47 |
+
return freqs_cis
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def precompute_freqs(
|
| 51 |
+
dim: int, end: int, theta: float = 10000.0, scale: float = 1.0, device=None
|
| 52 |
+
):
|
| 53 |
+
inv_freq = 1.0 / (theta ** (torch.arange(0, dim, 2).float().to(device) / dim))
|
| 54 |
+
seq = torch.arange(end, dtype=inv_freq.dtype, device=device)
|
| 55 |
+
freqs = torch.einsum("i , j -> i j", seq, inv_freq)
|
| 56 |
+
freqs = freqs.reshape(freqs.shape[0], 1, 1, -1)
|
| 57 |
+
return torch.cat((freqs, freqs), dim=-1)
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def reshape_for_broadcast(freqs_cis: torch.Tensor, x: torch.Tensor):
|
| 61 |
+
ndim = x.ndim
|
| 62 |
+
assert 0 <= 1 < ndim
|
| 63 |
+
assert freqs_cis.shape == (x.shape[1], x.shape[-1])
|
| 64 |
+
shape = [d if i == 1 or i == ndim - 1 else 1 for i, d in enumerate(x.shape)]
|
| 65 |
+
return freqs_cis.view(*shape)
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
def apply_rotary_emb(
|
| 69 |
+
xq: torch.Tensor,
|
| 70 |
+
xk: torch.Tensor,
|
| 71 |
+
freqs_cis: torch.Tensor,
|
| 72 |
+
) -> Tuple[torch.Tensor, torch.Tensor]:
|
| 73 |
+
# xq_ = torch.view_as_complex(xq.float().reshape(*xq.shape[:-1], -1, 2))
|
| 74 |
+
# k_ = torch.view_as_complex(xk.float().reshape(*xk.shape[:-1], -1, 2))
|
| 75 |
+
xq_ = torch.view_as_complex(
|
| 76 |
+
xq.float().reshape(*xq.shape[:-1], 2, -1).transpose(-2, -1).contiguous()
|
| 77 |
+
)
|
| 78 |
+
xk_ = torch.view_as_complex(
|
| 79 |
+
xk.float().reshape(*xk.shape[:-1], 2, -1).transpose(-2, -1).contiguous()
|
| 80 |
+
)
|
| 81 |
+
freqs_cis = reshape_for_broadcast(freqs_cis, xq_)
|
| 82 |
+
xq_out = torch.view_as_real(xq_ * freqs_cis).transpose(-2, -1).flatten(3)
|
| 83 |
+
xk_out = torch.view_as_real(xk_ * freqs_cis).transpose(-2, -1).flatten(3)
|
| 84 |
+
return xq_out.type_as(xq), xk_out.type_as(xk)
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
class LlamaAttentionFused(nn.Module):
|
| 88 |
+
def __init__(self, args):
|
| 89 |
+
super().__init__()
|
| 90 |
+
self.args = args
|
| 91 |
+
self.n_local_heads = args.num_attention_heads
|
| 92 |
+
self.hidden_size = args.hidden_size
|
| 93 |
+
self.num_heads = args.num_attention_heads
|
| 94 |
+
self.head_dim = self.hidden_size // self.num_heads
|
| 95 |
+
|
| 96 |
+
self.num_key_value_heads = args.num_key_value_heads
|
| 97 |
+
self.num_key_value_groups = self.num_heads // self.num_key_value_heads
|
| 98 |
+
self.max_position_embeddings = args.max_position_embeddings
|
| 99 |
+
self.rope_theta = args.rope_theta
|
| 100 |
+
self.rope_scaling = args.rope_scaling
|
| 101 |
+
if self.rope_scaling is None:
|
| 102 |
+
self.rope_scaling = 1.0
|
| 103 |
+
else:
|
| 104 |
+
self.rope_scaling = 1.0 / self.rope_scaling["factor"]
|
| 105 |
+
self.kv_max_seq_len = min(max_seq_len, self.max_position_embeddings)
|
| 106 |
+
self.q_proj = nn.Linear(
|
| 107 |
+
self.hidden_size,
|
| 108 |
+
self.num_heads * self.head_dim,
|
| 109 |
+
bias=False,
|
| 110 |
+
)
|
| 111 |
+
self.k_proj = nn.Linear(
|
| 112 |
+
self.hidden_size,
|
| 113 |
+
self.num_key_value_heads * self.head_dim,
|
| 114 |
+
bias=False,
|
| 115 |
+
)
|
| 116 |
+
self.v_proj = nn.Linear(
|
| 117 |
+
self.hidden_size,
|
| 118 |
+
self.num_key_value_heads * self.head_dim,
|
| 119 |
+
bias=False,
|
| 120 |
+
)
|
| 121 |
+
self.o_proj = nn.Linear(
|
| 122 |
+
self.num_heads * self.head_dim,
|
| 123 |
+
self.hidden_size,
|
| 124 |
+
bias=False,
|
| 125 |
+
)
|
| 126 |
+
|
| 127 |
+
# following fastertransformer definition
|
| 128 |
+
self.cache_v = (
|
| 129 |
+
torch.zeros(
|
| 130 |
+
(
|
| 131 |
+
max_batch_size,
|
| 132 |
+
self.num_key_value_heads,
|
| 133 |
+
# args.max_position_embeddings,
|
| 134 |
+
self.kv_max_seq_len,
|
| 135 |
+
self.head_dim,
|
| 136 |
+
)
|
| 137 |
+
)
|
| 138 |
+
.cuda()
|
| 139 |
+
.half()
|
| 140 |
+
) # added to half
|
| 141 |
+
# 8: pack 8 fp16 in FT, if fp32 then use 4
|
| 142 |
+
self.cache_k = (
|
| 143 |
+
torch.zeros(
|
| 144 |
+
(
|
| 145 |
+
max_batch_size,
|
| 146 |
+
self.num_key_value_heads,
|
| 147 |
+
self.head_dim // 8,
|
| 148 |
+
# args.max_position_embeddings,
|
| 149 |
+
self.kv_max_seq_len,
|
| 150 |
+
8,
|
| 151 |
+
)
|
| 152 |
+
)
|
| 153 |
+
.cuda()
|
| 154 |
+
.half()
|
| 155 |
+
) # added to half
|
| 156 |
+
# dummy
|
| 157 |
+
self.rotary_emb = LlamaRotaryEmbedding(
|
| 158 |
+
self.head_dim, max_position_embeddings=2048, device="cuda:0"
|
| 159 |
+
)
|
| 160 |
+
|
| 161 |
+
def forward(
|
| 162 |
+
self,
|
| 163 |
+
x: torch.Tensor,
|
| 164 |
+
start_pos: int,
|
| 165 |
+
freqs_cis: torch.Tensor,
|
| 166 |
+
mask: Optional[torch.Tensor],
|
| 167 |
+
chunk_prefilling: bool,
|
| 168 |
+
):
|
| 169 |
+
bsz, seqlen, _ = x.shape
|
| 170 |
+
# xqkv = self.qkv_proj(x)
|
| 171 |
+
# xqkv = xqkv.view(bsz, seqlen, -1, self.n_local_heads, self.head_dim)
|
| 172 |
+
# xq = xqkv[:, :, 0]
|
| 173 |
+
# xk = xqkv[:, :, 1]
|
| 174 |
+
# xv = xqkv[:, :, 2]
|
| 175 |
+
|
| 176 |
+
xq, xk, xv = self.q_proj(x), self.k_proj(x), self.v_proj(x)
|
| 177 |
+
|
| 178 |
+
if seqlen > 1:
|
| 179 |
+
xq = xq.view(bsz, seqlen, self.n_local_heads, self.head_dim)
|
| 180 |
+
xk = xk.view(bsz, seqlen, self.num_key_value_heads, self.head_dim)
|
| 181 |
+
xv = xv.view(bsz, seqlen, self.num_key_value_heads, self.head_dim)
|
| 182 |
+
|
| 183 |
+
xq, xk = apply_rotary_emb(xq, xk, freqs_cis=freqs_cis)
|
| 184 |
+
|
| 185 |
+
self.cache_k = self.cache_k.to(xq)
|
| 186 |
+
self.cache_v = self.cache_v.to(xq)
|
| 187 |
+
|
| 188 |
+
values_store = xv.transpose(2, 1)
|
| 189 |
+
keys_store = (
|
| 190 |
+
xk.reshape(bsz, seqlen, self.num_key_value_heads, self.head_dim // 8, 8)
|
| 191 |
+
.permute(0, 2, 3, 1, 4)
|
| 192 |
+
.contiguous()
|
| 193 |
+
)
|
| 194 |
+
|
| 195 |
+
self.cache_v[:bsz, :, start_pos : start_pos + seqlen, :] = values_store
|
| 196 |
+
self.cache_k[:bsz, :, :, start_pos : start_pos + seqlen, :] = keys_store
|
| 197 |
+
|
| 198 |
+
if chunk_prefilling:
|
| 199 |
+
keys = self.cache_k[:, :, :, 0 : start_pos + seqlen, :]
|
| 200 |
+
keys = (
|
| 201 |
+
keys.permute(0, 3, 1, 2, 4)
|
| 202 |
+
.reshape(
|
| 203 |
+
bsz, start_pos + seqlen, self.num_key_value_heads, self.head_dim
|
| 204 |
+
)
|
| 205 |
+
.contiguous()
|
| 206 |
+
)
|
| 207 |
+
values = self.cache_v[:, :, 0 : start_pos + seqlen, :]
|
| 208 |
+
values = (
|
| 209 |
+
values.transpose(2, 1)
|
| 210 |
+
.reshape(
|
| 211 |
+
bsz, start_pos + seqlen, self.num_key_value_heads, self.head_dim
|
| 212 |
+
)
|
| 213 |
+
.contiguous()
|
| 214 |
+
)
|
| 215 |
+
else:
|
| 216 |
+
keys = xk
|
| 217 |
+
values = xv
|
| 218 |
+
output = flash_attn_func(
|
| 219 |
+
q=xq,
|
| 220 |
+
k=keys,
|
| 221 |
+
v=values,
|
| 222 |
+
causal=True,
|
| 223 |
+
)
|
| 224 |
+
output = output.contiguous().view(bsz, seqlen, -1)
|
| 225 |
+
else:
|
| 226 |
+
xq = xq.view(bsz, self.n_local_heads, self.head_dim)
|
| 227 |
+
xk = xk.view(bsz, self.num_key_value_heads, self.head_dim)
|
| 228 |
+
xv = xv.view(bsz, self.num_key_value_heads, self.head_dim)
|
| 229 |
+
|
| 230 |
+
output = awq_inference_engine.single_query_attention(
|
| 231 |
+
xq,
|
| 232 |
+
xk,
|
| 233 |
+
xv,
|
| 234 |
+
self.cache_k,
|
| 235 |
+
self.cache_v,
|
| 236 |
+
None,
|
| 237 |
+
# alibi position encodings
|
| 238 |
+
None,
|
| 239 |
+
start_pos,
|
| 240 |
+
self.head_dim,
|
| 241 |
+
self.rope_theta,
|
| 242 |
+
self.rope_scaling,
|
| 243 |
+
True,
|
| 244 |
+
)
|
| 245 |
+
output = output.reshape(bsz, 1, -1)
|
| 246 |
+
|
| 247 |
+
return self.o_proj(output)
|
| 248 |
+
|
| 249 |
+
|
| 250 |
+
class LlamaMLP(nn.Module):
|
| 251 |
+
def __init__(self, args):
|
| 252 |
+
super().__init__()
|
| 253 |
+
self.hidden_size = args.hidden_size
|
| 254 |
+
self.intermediate_size = args.intermediate_size
|
| 255 |
+
|
| 256 |
+
self.gate_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
|
| 257 |
+
self.up_proj = nn.Linear(self.hidden_size, self.intermediate_size, bias=False)
|
| 258 |
+
self.down_proj = nn.Linear(self.intermediate_size, self.hidden_size, bias=False)
|
| 259 |
+
|
| 260 |
+
def forward(self, x):
|
| 261 |
+
return self.down_proj(F.silu(self.gate_proj(x)) * self.up_proj(x))
|
| 262 |
+
|
| 263 |
+
|
| 264 |
+
class TransformerBlock(nn.Module):
|
| 265 |
+
def __init__(self, layer_id: int, args):
|
| 266 |
+
super().__init__()
|
| 267 |
+
self.n_heads = args.num_attention_heads
|
| 268 |
+
self.dim = args.hidden_size
|
| 269 |
+
self.head_dim = args.hidden_size // args.num_attention_heads
|
| 270 |
+
self.self_attn = LlamaAttentionFused(args)
|
| 271 |
+
self.mlp = LlamaMLP(args)
|
| 272 |
+
self.layer_id = layer_id
|
| 273 |
+
self.input_layernorm = RMSNorm(args.hidden_size, eps=args.rms_norm_eps)
|
| 274 |
+
self.post_attention_layernorm = RMSNorm(args.hidden_size, eps=args.rms_norm_eps)
|
| 275 |
+
|
| 276 |
+
def forward(
|
| 277 |
+
self,
|
| 278 |
+
x: torch.Tensor,
|
| 279 |
+
start_pos: int,
|
| 280 |
+
freqs_cis: torch.Tensor,
|
| 281 |
+
mask: Optional[torch.Tensor],
|
| 282 |
+
chunk_prefilling: bool,
|
| 283 |
+
):
|
| 284 |
+
h = x + self.self_attn.forward(
|
| 285 |
+
self.input_layernorm(x), start_pos, freqs_cis, mask, chunk_prefilling
|
| 286 |
+
)
|
| 287 |
+
out = h + self.mlp.forward(self.post_attention_layernorm(h))
|
| 288 |
+
return out
|
| 289 |
+
|
| 290 |
+
|
| 291 |
+
class Transformer(nn.Module):
|
| 292 |
+
def __init__(self, params):
|
| 293 |
+
super().__init__()
|
| 294 |
+
self.params = params
|
| 295 |
+
self.vocab_size = params.vocab_size
|
| 296 |
+
self.n_layers = params.num_hidden_layers
|
| 297 |
+
|
| 298 |
+
self.embed_tokens = nn.Embedding(params.vocab_size, params.hidden_size)
|
| 299 |
+
|
| 300 |
+
self.layers = torch.nn.ModuleList()
|
| 301 |
+
for layer_id in range(params.num_hidden_layers):
|
| 302 |
+
self.layers.append(TransformerBlock(layer_id, params))
|
| 303 |
+
|
| 304 |
+
self.norm = RMSNorm(params.hidden_size, eps=params.rms_norm_eps)
|
| 305 |
+
|
| 306 |
+
# Note (Haotian): rope_theta has to be defined here, otherwise context stage is wrong.
|
| 307 |
+
rope_scale = self.params.rope_scaling
|
| 308 |
+
if rope_scale is None:
|
| 309 |
+
rope_scale = 1.0
|
| 310 |
+
else:
|
| 311 |
+
rope_scale = 1.0 / rope_scale["factor"]
|
| 312 |
+
self.freqs = precompute_freqs(
|
| 313 |
+
self.params.hidden_size // self.params.num_attention_heads,
|
| 314 |
+
self.params.max_position_embeddings * 2,
|
| 315 |
+
self.params.rope_theta,
|
| 316 |
+
rope_scale,
|
| 317 |
+
)
|
| 318 |
+
self.freqs_cis = precompute_freqs_cis(
|
| 319 |
+
self.params.hidden_size // self.params.num_attention_heads,
|
| 320 |
+
self.params.max_position_embeddings * 2,
|
| 321 |
+
self.params.rope_theta,
|
| 322 |
+
rope_scale,
|
| 323 |
+
)
|
| 324 |
+
|
| 325 |
+
@torch.inference_mode()
|
| 326 |
+
def forward(
|
| 327 |
+
self,
|
| 328 |
+
tokens: torch.Tensor,
|
| 329 |
+
start_pos: int,
|
| 330 |
+
inputs_embeds: torch.Tensor = None,
|
| 331 |
+
chunk_prefilling: bool = False,
|
| 332 |
+
):
|
| 333 |
+
if tokens is not None:
|
| 334 |
+
_bsz, seqlen = tokens.shape
|
| 335 |
+
h = self.embed_tokens(tokens)
|
| 336 |
+
else:
|
| 337 |
+
h = inputs_embeds
|
| 338 |
+
seqlen = inputs_embeds.shape[1]
|
| 339 |
+
self.freqs = self.freqs.to(h.device)
|
| 340 |
+
freqs = self.freqs[start_pos : start_pos + seqlen]
|
| 341 |
+
|
| 342 |
+
mask = None
|
| 343 |
+
if seqlen > 1:
|
| 344 |
+
mask = torch.full((1, 1, seqlen, seqlen), float("-inf"), device=h.device)
|
| 345 |
+
mask = torch.triu(mask, diagonal=1).type_as(h)
|
| 346 |
+
if chunk_prefilling:
|
| 347 |
+
mask_history = torch.zeros(
|
| 348 |
+
(1, 1, seqlen, start_pos), dtype=torch.float16, device=h.device
|
| 349 |
+
).type_as(h)
|
| 350 |
+
mask = torch.cat((mask_history, mask), dim=-1)
|
| 351 |
+
for layer in self.layers:
|
| 352 |
+
h = layer(h, start_pos, freqs, mask, chunk_prefilling)
|
| 353 |
+
h = h[:, -1:, :] # Only the last token is useful
|
| 354 |
+
h = self.norm(h)
|
| 355 |
+
return h
|
| 356 |
+
|
| 357 |
+
@torch.inference_mode()
|
| 358 |
+
def forwardfp16(
|
| 359 |
+
self,
|
| 360 |
+
tokens: torch.Tensor,
|
| 361 |
+
start_pos: int,
|
| 362 |
+
inputs_embeds: torch.Tensor = None,
|
| 363 |
+
chunk_prefilling: bool = False,
|
| 364 |
+
):
|
| 365 |
+
if tokens is not None:
|
| 366 |
+
_bsz, seqlen = tokens.shape
|
| 367 |
+
h = self.embed_tokens(tokens)
|
| 368 |
+
else:
|
| 369 |
+
h = inputs_embeds
|
| 370 |
+
seqlen = inputs_embeds.shape[1]
|
| 371 |
+
self.freqs_cis = self.freqs_cis.to(h.device)
|
| 372 |
+
freqs_cis = self.freqs_cis[start_pos : start_pos + seqlen]
|
| 373 |
+
|
| 374 |
+
mask = None
|
| 375 |
+
if seqlen > 1:
|
| 376 |
+
mask = torch.full((1, 1, seqlen, seqlen), float("-inf"), device=h.device)
|
| 377 |
+
mask = torch.triu(mask, diagonal=1).type_as(h)
|
| 378 |
+
if chunk_prefilling:
|
| 379 |
+
mask_history = torch.zeros(
|
| 380 |
+
(1, 1, seqlen, start_pos), dtype=torch.float16, device=h.device
|
| 381 |
+
).type_as(h)
|
| 382 |
+
mask = torch.cat((mask_history, mask), dim=-1)
|
| 383 |
+
for layer in self.layers:
|
| 384 |
+
h = layer(h, start_pos, freqs_cis, mask, chunk_prefilling)
|
| 385 |
+
h = h[:, -1:, :] # Only the last token is useful
|
| 386 |
+
h = self.norm(h)
|
| 387 |
+
return h
|
| 388 |
+
|
| 389 |
+
|
| 390 |
+
class LlamaForCausalLM(nn.Module):
|
| 391 |
+
def __init__(self, params):
|
| 392 |
+
super().__init__()
|
| 393 |
+
self.config = params
|
| 394 |
+
self.model = Transformer(params)
|
| 395 |
+
self.lm_head = nn.Linear(params.hidden_size, params.vocab_size, bias=False)
|
| 396 |
+
|
| 397 |
+
@torch.inference_mode()
|
| 398 |
+
def forward(
|
| 399 |
+
self,
|
| 400 |
+
tokens: torch.Tensor,
|
| 401 |
+
start_pos: int,
|
| 402 |
+
inputs_embeds: torch.Tensor = None,
|
| 403 |
+
chunk_prefilling=False,
|
| 404 |
+
quant=True,
|
| 405 |
+
):
|
| 406 |
+
if quant:
|
| 407 |
+
h = self.model(tokens, start_pos, inputs_embeds, chunk_prefilling)
|
| 408 |
+
else:
|
| 409 |
+
h = self.model.forwardfp16(
|
| 410 |
+
tokens, start_pos, inputs_embeds, chunk_prefilling
|
| 411 |
+
)
|
| 412 |
+
output = self.lm_head(h) # only compute last logits
|
| 413 |
+
return output.float()
|
llm-awq/tinychat/models/llava_base/llava_arch.py
ADDED
|
@@ -0,0 +1,412 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Modified from https://github.com/haotian-liu/LLaVA
|
| 2 |
+
# Copyright 2023 Haotian Liu
|
| 3 |
+
#
|
| 4 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
# you may not use this file except in compliance with the License.
|
| 6 |
+
# You may obtain a copy of the License at
|
| 7 |
+
#
|
| 8 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
#
|
| 10 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
# See the License for the specific language governing permissions and
|
| 14 |
+
# limitations under the License.
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
from abc import ABC, abstractmethod
|
| 18 |
+
|
| 19 |
+
import torch
|
| 20 |
+
import torch.nn as nn
|
| 21 |
+
|
| 22 |
+
from .multimodal_encoder.builder import build_vision_tower
|
| 23 |
+
from .multimodal_projector.builder import build_vision_projector
|
| 24 |
+
|
| 25 |
+
from tinychat.utils.constants import (
|
| 26 |
+
LLAVA_IGNORE_INDEX,
|
| 27 |
+
LLAVA_DEFAULT_IMAGE_TOKEN_IDX,
|
| 28 |
+
LLAVA_DEFAULT_IMAGE_PATCH_TOKEN,
|
| 29 |
+
LLAVA_DEFAULT_IM_START_TOKEN,
|
| 30 |
+
LLAVA_DEFAULT_IM_END_TOKEN,
|
| 31 |
+
)
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
class LlavaMetaModel:
|
| 35 |
+
def __init__(self, config):
|
| 36 |
+
super(LlavaMetaModel, self).__init__(config)
|
| 37 |
+
|
| 38 |
+
if hasattr(config, "mm_vision_tower"):
|
| 39 |
+
self.vision_tower = build_vision_tower(config, delay_load=True)
|
| 40 |
+
self.mm_projector = build_vision_projector(config)
|
| 41 |
+
|
| 42 |
+
def get_vision_tower(self):
|
| 43 |
+
vision_tower = getattr(self, "vision_tower", None)
|
| 44 |
+
if type(vision_tower) is list:
|
| 45 |
+
vision_tower = vision_tower[0]
|
| 46 |
+
return vision_tower
|
| 47 |
+
|
| 48 |
+
def initialize_vision_modules(self, model_args, fsdp=None):
|
| 49 |
+
vision_tower = model_args.vision_tower
|
| 50 |
+
mm_vision_select_layer = model_args.mm_vision_select_layer
|
| 51 |
+
mm_vision_select_feature = model_args.mm_vision_select_feature
|
| 52 |
+
pretrain_mm_mlp_adapter = model_args.pretrain_mm_mlp_adapter
|
| 53 |
+
|
| 54 |
+
self.config.mm_vision_tower = vision_tower
|
| 55 |
+
|
| 56 |
+
if self.get_vision_tower() is None:
|
| 57 |
+
vision_tower = build_vision_tower(model_args)
|
| 58 |
+
|
| 59 |
+
if fsdp is not None and len(fsdp) > 0:
|
| 60 |
+
self.vision_tower = [vision_tower]
|
| 61 |
+
else:
|
| 62 |
+
self.vision_tower = vision_tower
|
| 63 |
+
else:
|
| 64 |
+
if fsdp is not None and len(fsdp) > 0:
|
| 65 |
+
vision_tower = self.vision_tower[0]
|
| 66 |
+
else:
|
| 67 |
+
vision_tower = self.vision_tower
|
| 68 |
+
vision_tower.load_model()
|
| 69 |
+
|
| 70 |
+
self.config.use_mm_proj = True
|
| 71 |
+
self.config.mm_projector_type = getattr(
|
| 72 |
+
model_args, "mm_projector_type", "linear"
|
| 73 |
+
)
|
| 74 |
+
self.config.mm_hidden_size = vision_tower.hidden_size
|
| 75 |
+
self.config.mm_vision_select_layer = mm_vision_select_layer
|
| 76 |
+
self.config.mm_vision_select_feature = mm_vision_select_feature
|
| 77 |
+
|
| 78 |
+
if getattr(self, "mm_projector", None) is None:
|
| 79 |
+
self.mm_projector = build_vision_projector(self.config)
|
| 80 |
+
else:
|
| 81 |
+
# In case it is frozen by LoRA
|
| 82 |
+
for p in self.mm_projector.parameters():
|
| 83 |
+
p.requires_grad = True
|
| 84 |
+
|
| 85 |
+
if pretrain_mm_mlp_adapter is not None:
|
| 86 |
+
mm_projector_weights = torch.load(
|
| 87 |
+
pretrain_mm_mlp_adapter, map_location="cpu"
|
| 88 |
+
)
|
| 89 |
+
|
| 90 |
+
def get_w(weights, keyword):
|
| 91 |
+
return {
|
| 92 |
+
k.split(keyword + ".")[1]: v
|
| 93 |
+
for k, v in weights.items()
|
| 94 |
+
if keyword in k
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
self.mm_projector.load_state_dict(
|
| 98 |
+
get_w(mm_projector_weights, "mm_projector")
|
| 99 |
+
)
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
class LlavaMetaForCausalLM(ABC):
|
| 103 |
+
@abstractmethod
|
| 104 |
+
def get_model(self):
|
| 105 |
+
pass
|
| 106 |
+
|
| 107 |
+
def get_vision_tower(self):
|
| 108 |
+
return self.get_model().get_vision_tower()
|
| 109 |
+
|
| 110 |
+
def encode_images(self, images):
|
| 111 |
+
vision_tower = self.get_model().get_vision_tower().half()
|
| 112 |
+
image_features = vision_tower(images)
|
| 113 |
+
image_features = self.get_model().mm_projector(image_features)
|
| 114 |
+
return image_features
|
| 115 |
+
|
| 116 |
+
def prepare_inputs_labels_for_multimodal(
|
| 117 |
+
self, input_ids, position_ids, attention_mask, past_key_values, labels, images
|
| 118 |
+
):
|
| 119 |
+
vision_tower = self.get_vision_tower()
|
| 120 |
+
if vision_tower is None or images is None or input_ids.shape[1] == 1:
|
| 121 |
+
if (
|
| 122 |
+
past_key_values is not None
|
| 123 |
+
and vision_tower is not None
|
| 124 |
+
and images is not None
|
| 125 |
+
and input_ids.shape[1] == 1
|
| 126 |
+
):
|
| 127 |
+
target_shape = past_key_values[-1][-1].shape[-2] + 1
|
| 128 |
+
attention_mask = torch.cat(
|
| 129 |
+
(
|
| 130 |
+
attention_mask,
|
| 131 |
+
torch.ones(
|
| 132 |
+
(
|
| 133 |
+
attention_mask.shape[0],
|
| 134 |
+
target_shape - attention_mask.shape[1],
|
| 135 |
+
),
|
| 136 |
+
dtype=attention_mask.dtype,
|
| 137 |
+
device=attention_mask.device,
|
| 138 |
+
),
|
| 139 |
+
),
|
| 140 |
+
dim=1,
|
| 141 |
+
)
|
| 142 |
+
position_ids = torch.sum(attention_mask, dim=1).unsqueeze(-1) - 1
|
| 143 |
+
return (
|
| 144 |
+
input_ids,
|
| 145 |
+
position_ids,
|
| 146 |
+
attention_mask,
|
| 147 |
+
past_key_values,
|
| 148 |
+
None,
|
| 149 |
+
labels,
|
| 150 |
+
)
|
| 151 |
+
|
| 152 |
+
if type(images) is list or images.ndim == 5:
|
| 153 |
+
concat_images = torch.cat([image for image in images], dim=0)
|
| 154 |
+
image_features = self.encode_images(concat_images)
|
| 155 |
+
split_sizes = [image.shape[0] for image in images]
|
| 156 |
+
image_features = torch.split(image_features, split_sizes, dim=0)
|
| 157 |
+
image_features = [x.flatten(0, 1).to(self.device) for x in image_features]
|
| 158 |
+
else:
|
| 159 |
+
image_features = self.encode_images(images).to(self.device)
|
| 160 |
+
|
| 161 |
+
# TODO: image start / end is not implemented here to support pretraining.
|
| 162 |
+
if getattr(self.config, "tune_mm_mlp_adapter", False) and getattr(
|
| 163 |
+
self.config, "mm_use_im_start_end", False
|
| 164 |
+
):
|
| 165 |
+
raise NotImplementedError
|
| 166 |
+
|
| 167 |
+
# Let's just add dummy tensors if they do not exist,
|
| 168 |
+
# it is a headache to deal with None all the time.
|
| 169 |
+
# But it is not ideal, and if you have a better idea,
|
| 170 |
+
# please open an issue / submit a PR, thanks.
|
| 171 |
+
_labels = labels
|
| 172 |
+
_position_ids = position_ids
|
| 173 |
+
_attention_mask = attention_mask
|
| 174 |
+
if attention_mask is None:
|
| 175 |
+
attention_mask = torch.ones_like(input_ids, dtype=torch.bool)
|
| 176 |
+
else:
|
| 177 |
+
attention_mask = attention_mask.bool()
|
| 178 |
+
if position_ids is None:
|
| 179 |
+
position_ids = torch.arange(
|
| 180 |
+
0, input_ids.shape[1], dtype=torch.long, device=input_ids.device
|
| 181 |
+
)
|
| 182 |
+
if labels is None:
|
| 183 |
+
labels = torch.full_like(input_ids, LLAVA_IGNORE_INDEX)
|
| 184 |
+
|
| 185 |
+
# remove the padding using attention_mask -- TODO: double check
|
| 186 |
+
input_ids = [
|
| 187 |
+
cur_input_ids[cur_attention_mask]
|
| 188 |
+
for cur_input_ids, cur_attention_mask in zip(input_ids, attention_mask)
|
| 189 |
+
]
|
| 190 |
+
labels = [
|
| 191 |
+
cur_labels[cur_attention_mask]
|
| 192 |
+
for cur_labels, cur_attention_mask in zip(labels, attention_mask)
|
| 193 |
+
]
|
| 194 |
+
|
| 195 |
+
new_input_embeds = []
|
| 196 |
+
new_labels = []
|
| 197 |
+
cur_image_idx = 0
|
| 198 |
+
for batch_idx, cur_input_ids in enumerate(input_ids):
|
| 199 |
+
num_images = (cur_input_ids == LLAVA_DEFAULT_IMAGE_TOKEN_IDX).sum()
|
| 200 |
+
if num_images == 0:
|
| 201 |
+
cur_image_features = image_features[cur_image_idx]
|
| 202 |
+
cur_input_embeds_1 = self.get_model().embed_tokens(cur_input_ids)
|
| 203 |
+
cur_input_embeds = torch.cat(
|
| 204 |
+
[cur_input_embeds_1, cur_image_features[0:0]], dim=0
|
| 205 |
+
)
|
| 206 |
+
new_input_embeds.append(cur_input_embeds)
|
| 207 |
+
new_labels.append(labels[batch_idx])
|
| 208 |
+
cur_image_idx += 1
|
| 209 |
+
continue
|
| 210 |
+
|
| 211 |
+
image_token_indices = (
|
| 212 |
+
[-1]
|
| 213 |
+
+ torch.where(cur_input_ids == LLAVA_DEFAULT_IMAGE_TOKEN_IDX)[
|
| 214 |
+
0
|
| 215 |
+
].tolist()
|
| 216 |
+
+ [cur_input_ids.shape[0]]
|
| 217 |
+
)
|
| 218 |
+
cur_input_ids_noim = []
|
| 219 |
+
cur_labels = labels[batch_idx]
|
| 220 |
+
cur_labels_noim = []
|
| 221 |
+
for i in range(len(image_token_indices) - 1):
|
| 222 |
+
cur_input_ids_noim.append(
|
| 223 |
+
cur_input_ids[
|
| 224 |
+
image_token_indices[i] + 1 : image_token_indices[i + 1]
|
| 225 |
+
]
|
| 226 |
+
)
|
| 227 |
+
cur_labels_noim.append(
|
| 228 |
+
cur_labels[image_token_indices[i] + 1 : image_token_indices[i + 1]]
|
| 229 |
+
)
|
| 230 |
+
split_sizes = [x.shape[0] for x in cur_labels_noim]
|
| 231 |
+
cur_input_embeds = self.get_model().embed_tokens(
|
| 232 |
+
torch.cat(cur_input_ids_noim)
|
| 233 |
+
)
|
| 234 |
+
cur_input_embeds_no_im = torch.split(cur_input_embeds, split_sizes, dim=0)
|
| 235 |
+
cur_new_input_embeds = []
|
| 236 |
+
cur_new_labels = []
|
| 237 |
+
|
| 238 |
+
for i in range(num_images + 1):
|
| 239 |
+
cur_new_input_embeds.append(cur_input_embeds_no_im[i])
|
| 240 |
+
cur_new_labels.append(cur_labels_noim[i])
|
| 241 |
+
if i < num_images:
|
| 242 |
+
cur_image_features = image_features[cur_image_idx]
|
| 243 |
+
cur_image_idx += 1
|
| 244 |
+
cur_new_input_embeds.append(cur_image_features)
|
| 245 |
+
cur_new_labels.append(
|
| 246 |
+
torch.full(
|
| 247 |
+
(cur_image_features.shape[0],),
|
| 248 |
+
LLAVA_IGNORE_INDEX,
|
| 249 |
+
device=cur_labels.device,
|
| 250 |
+
dtype=cur_labels.dtype,
|
| 251 |
+
)
|
| 252 |
+
)
|
| 253 |
+
|
| 254 |
+
cur_new_input_embeds = torch.cat(cur_new_input_embeds)
|
| 255 |
+
cur_new_labels = torch.cat(cur_new_labels)
|
| 256 |
+
|
| 257 |
+
new_input_embeds.append(cur_new_input_embeds)
|
| 258 |
+
new_labels.append(cur_new_labels)
|
| 259 |
+
|
| 260 |
+
# Truncate sequences to max length as image embeddings can make the sequence longer
|
| 261 |
+
tokenizer_model_max_length = getattr(
|
| 262 |
+
self.config, "tokenizer_model_max_length", None
|
| 263 |
+
)
|
| 264 |
+
if tokenizer_model_max_length is not None:
|
| 265 |
+
new_input_embeds = [
|
| 266 |
+
x[:tokenizer_model_max_length] for x in new_input_embeds
|
| 267 |
+
]
|
| 268 |
+
new_labels = [x[:tokenizer_model_max_length] for x in new_labels]
|
| 269 |
+
|
| 270 |
+
# Combine them
|
| 271 |
+
max_len = max(x.shape[0] for x in new_input_embeds)
|
| 272 |
+
batch_size = len(new_input_embeds)
|
| 273 |
+
|
| 274 |
+
new_input_embeds_padded = []
|
| 275 |
+
new_labels_padded = torch.full(
|
| 276 |
+
(batch_size, max_len),
|
| 277 |
+
LLAVA_IGNORE_INDEX,
|
| 278 |
+
dtype=new_labels[0].dtype,
|
| 279 |
+
device=new_labels[0].device,
|
| 280 |
+
)
|
| 281 |
+
attention_mask = torch.zeros(
|
| 282 |
+
(batch_size, max_len),
|
| 283 |
+
dtype=attention_mask.dtype,
|
| 284 |
+
device=attention_mask.device,
|
| 285 |
+
)
|
| 286 |
+
position_ids = torch.zeros(
|
| 287 |
+
(batch_size, max_len), dtype=position_ids.dtype, device=position_ids.device
|
| 288 |
+
)
|
| 289 |
+
|
| 290 |
+
for i, (cur_new_embed, cur_new_labels) in enumerate(
|
| 291 |
+
zip(new_input_embeds, new_labels)
|
| 292 |
+
):
|
| 293 |
+
cur_len = cur_new_embed.shape[0]
|
| 294 |
+
if getattr(self.config, "tokenizer_padding_side", "right") == "left":
|
| 295 |
+
new_input_embeds_padded.append(
|
| 296 |
+
torch.cat(
|
| 297 |
+
(
|
| 298 |
+
torch.zeros(
|
| 299 |
+
(max_len - cur_len, cur_new_embed.shape[1]),
|
| 300 |
+
dtype=cur_new_embed.dtype,
|
| 301 |
+
device=cur_new_embed.device,
|
| 302 |
+
),
|
| 303 |
+
cur_new_embed,
|
| 304 |
+
),
|
| 305 |
+
dim=0,
|
| 306 |
+
)
|
| 307 |
+
)
|
| 308 |
+
if cur_len > 0:
|
| 309 |
+
new_labels_padded[i, -cur_len:] = cur_new_labels
|
| 310 |
+
attention_mask[i, -cur_len:] = True
|
| 311 |
+
position_ids[i, -cur_len:] = torch.arange(
|
| 312 |
+
0, cur_len, dtype=position_ids.dtype, device=position_ids.device
|
| 313 |
+
)
|
| 314 |
+
else:
|
| 315 |
+
new_input_embeds_padded.append(
|
| 316 |
+
torch.cat(
|
| 317 |
+
(
|
| 318 |
+
cur_new_embed,
|
| 319 |
+
torch.zeros(
|
| 320 |
+
(max_len - cur_len, cur_new_embed.shape[1]),
|
| 321 |
+
dtype=cur_new_embed.dtype,
|
| 322 |
+
device=cur_new_embed.device,
|
| 323 |
+
),
|
| 324 |
+
),
|
| 325 |
+
dim=0,
|
| 326 |
+
)
|
| 327 |
+
)
|
| 328 |
+
if cur_len > 0:
|
| 329 |
+
new_labels_padded[i, :cur_len] = cur_new_labels
|
| 330 |
+
attention_mask[i, :cur_len] = True
|
| 331 |
+
position_ids[i, :cur_len] = torch.arange(
|
| 332 |
+
0, cur_len, dtype=position_ids.dtype, device=position_ids.device
|
| 333 |
+
)
|
| 334 |
+
|
| 335 |
+
new_input_embeds = torch.stack(new_input_embeds_padded, dim=0)
|
| 336 |
+
|
| 337 |
+
if _labels is None:
|
| 338 |
+
new_labels = None
|
| 339 |
+
else:
|
| 340 |
+
new_labels = new_labels_padded
|
| 341 |
+
|
| 342 |
+
if _attention_mask is None:
|
| 343 |
+
attention_mask = None
|
| 344 |
+
else:
|
| 345 |
+
attention_mask = attention_mask.to(dtype=_attention_mask.dtype)
|
| 346 |
+
|
| 347 |
+
if _position_ids is None:
|
| 348 |
+
position_ids = None
|
| 349 |
+
|
| 350 |
+
return (
|
| 351 |
+
None,
|
| 352 |
+
position_ids,
|
| 353 |
+
attention_mask,
|
| 354 |
+
past_key_values,
|
| 355 |
+
new_input_embeds,
|
| 356 |
+
new_labels,
|
| 357 |
+
)
|
| 358 |
+
|
| 359 |
+
def initialize_vision_tokenizer(self, model_args, tokenizer):
|
| 360 |
+
if model_args.mm_use_im_patch_token:
|
| 361 |
+
tokenizer.add_tokens([LLAVA_DEFAULT_IMAGE_PATCH_TOKEN], special_tokens=True)
|
| 362 |
+
self.resize_token_embeddings(len(tokenizer))
|
| 363 |
+
|
| 364 |
+
if model_args.mm_use_im_start_end:
|
| 365 |
+
num_new_tokens = tokenizer.add_tokens(
|
| 366 |
+
[LLAVA_DEFAULT_IM_START_TOKEN, LLAVA_DEFAULT_IM_END_TOKEN],
|
| 367 |
+
special_tokens=True,
|
| 368 |
+
)
|
| 369 |
+
self.resize_token_embeddings(len(tokenizer))
|
| 370 |
+
|
| 371 |
+
if num_new_tokens > 0:
|
| 372 |
+
input_embeddings = self.get_input_embeddings().weight.data
|
| 373 |
+
output_embeddings = self.get_output_embeddings().weight.data
|
| 374 |
+
|
| 375 |
+
input_embeddings_avg = input_embeddings[:-num_new_tokens].mean(
|
| 376 |
+
dim=0, keepdim=True
|
| 377 |
+
)
|
| 378 |
+
output_embeddings_avg = output_embeddings[:-num_new_tokens].mean(
|
| 379 |
+
dim=0, keepdim=True
|
| 380 |
+
)
|
| 381 |
+
|
| 382 |
+
input_embeddings[-num_new_tokens:] = input_embeddings_avg
|
| 383 |
+
output_embeddings[-num_new_tokens:] = output_embeddings_avg
|
| 384 |
+
|
| 385 |
+
if model_args.tune_mm_mlp_adapter:
|
| 386 |
+
for p in self.get_input_embeddings().parameters():
|
| 387 |
+
p.requires_grad = True
|
| 388 |
+
for p in self.get_output_embeddings().parameters():
|
| 389 |
+
p.requires_grad = False
|
| 390 |
+
|
| 391 |
+
if model_args.pretrain_mm_mlp_adapter:
|
| 392 |
+
mm_projector_weights = torch.load(
|
| 393 |
+
model_args.pretrain_mm_mlp_adapter, map_location="cpu"
|
| 394 |
+
)
|
| 395 |
+
embed_tokens_weight = mm_projector_weights["model.embed_tokens.weight"]
|
| 396 |
+
assert num_new_tokens == 2
|
| 397 |
+
if input_embeddings.shape == embed_tokens_weight.shape:
|
| 398 |
+
input_embeddings[-num_new_tokens:] = embed_tokens_weight[
|
| 399 |
+
-num_new_tokens:
|
| 400 |
+
]
|
| 401 |
+
elif embed_tokens_weight.shape[0] == num_new_tokens:
|
| 402 |
+
input_embeddings[-num_new_tokens:] = embed_tokens_weight
|
| 403 |
+
else:
|
| 404 |
+
raise ValueError(
|
| 405 |
+
f"Unexpected embed_tokens_weight shape. Pretrained: {embed_tokens_weight.shape}. Current: {input_embeddings.shape}. Numer of new tokens: {num_new_tokens}."
|
| 406 |
+
)
|
| 407 |
+
elif model_args.mm_use_im_patch_token:
|
| 408 |
+
if model_args.tune_mm_mlp_adapter:
|
| 409 |
+
for p in self.get_input_embeddings().parameters():
|
| 410 |
+
p.requires_grad = False
|
| 411 |
+
for p in self.get_output_embeddings().parameters():
|
| 412 |
+
p.requires_grad = False
|
llm-awq/tinychat/models/llava_base/multimodal_encoder/builder.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Modified from https://github.com/haotian-liu/LLaVA
|
| 2 |
+
|
| 3 |
+
import os
|
| 4 |
+
from .clip_encoder import CLIPVisionTower
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def build_vision_tower(vision_tower_cfg, **kwargs):
|
| 8 |
+
vision_tower = getattr(
|
| 9 |
+
vision_tower_cfg,
|
| 10 |
+
"mm_vision_tower",
|
| 11 |
+
getattr(vision_tower_cfg, "vision_tower", None),
|
| 12 |
+
)
|
| 13 |
+
is_absolute_path_exists = os.path.exists(vision_tower)
|
| 14 |
+
if (
|
| 15 |
+
is_absolute_path_exists
|
| 16 |
+
or vision_tower.startswith("openai")
|
| 17 |
+
or vision_tower.startswith("laion")
|
| 18 |
+
):
|
| 19 |
+
return CLIPVisionTower(vision_tower, args=vision_tower_cfg, **kwargs)
|
| 20 |
+
|
| 21 |
+
raise ValueError(f"Unknown vision tower: {vision_tower}")
|
llm-awq/tinychat/models/llava_base/multimodal_encoder/clip_encoder.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Modified from https://github.com/haotian-liu/LLaVA
|
| 2 |
+
|
| 3 |
+
import torch
|
| 4 |
+
import torch.nn as nn
|
| 5 |
+
|
| 6 |
+
from transformers import CLIPVisionModel, CLIPImageProcessor, CLIPVisionConfig
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class CLIPVisionTower(nn.Module):
|
| 10 |
+
def __init__(self, vision_tower, args, delay_load=False):
|
| 11 |
+
super().__init__()
|
| 12 |
+
|
| 13 |
+
self.is_loaded = False
|
| 14 |
+
|
| 15 |
+
self.vision_tower_name = vision_tower
|
| 16 |
+
self.select_layer = args.mm_vision_select_layer
|
| 17 |
+
self.select_feature = getattr(args, "mm_vision_select_feature", "patch")
|
| 18 |
+
|
| 19 |
+
if not delay_load:
|
| 20 |
+
self.load_model()
|
| 21 |
+
else:
|
| 22 |
+
self.cfg_only = CLIPVisionConfig.from_pretrained(self.vision_tower_name)
|
| 23 |
+
|
| 24 |
+
def load_model(self):
|
| 25 |
+
self.image_processor = CLIPImageProcessor.from_pretrained(
|
| 26 |
+
self.vision_tower_name
|
| 27 |
+
)
|
| 28 |
+
self.vision_tower = CLIPVisionModel.from_pretrained(self.vision_tower_name)
|
| 29 |
+
self.vision_tower.requires_grad_(False)
|
| 30 |
+
|
| 31 |
+
self.is_loaded = True
|
| 32 |
+
|
| 33 |
+
def feature_select(self, image_forward_outs):
|
| 34 |
+
image_features = image_forward_outs.hidden_states[self.select_layer]
|
| 35 |
+
if self.select_feature == "patch":
|
| 36 |
+
image_features = image_features[:, 1:]
|
| 37 |
+
elif self.select_feature == "cls_patch":
|
| 38 |
+
image_features = image_features
|
| 39 |
+
else:
|
| 40 |
+
raise ValueError(f"Unexpected select feature: {self.select_feature}")
|
| 41 |
+
return image_features
|
| 42 |
+
|
| 43 |
+
@torch.no_grad()
|
| 44 |
+
def forward(self, images):
|
| 45 |
+
if type(images) is list:
|
| 46 |
+
image_features = []
|
| 47 |
+
for image in images:
|
| 48 |
+
image_forward_out = self.vision_tower(
|
| 49 |
+
image.to(device=self.device, dtype=self.dtype).unsqueeze(0),
|
| 50 |
+
output_hidden_states=True,
|
| 51 |
+
)
|
| 52 |
+
image_feature = self.feature_select(image_forward_out).to(image.dtype)
|
| 53 |
+
image_features.append(image_feature)
|
| 54 |
+
else:
|
| 55 |
+
# import time
|
| 56 |
+
# torch.cuda.synchronize()
|
| 57 |
+
# image2 = images.to(self.dtype)
|
| 58 |
+
# print("model dtype:", self.dtype)
|
| 59 |
+
# print("image dtype:", images.dtype)
|
| 60 |
+
# st11 = time.time()
|
| 61 |
+
image_forward_outs = self.vision_tower(
|
| 62 |
+
images.to(device=self.device, dtype=self.dtype),
|
| 63 |
+
output_hidden_states=True,
|
| 64 |
+
)
|
| 65 |
+
# torch.cuda.synchronize()
|
| 66 |
+
# ed11 = time.time()
|
| 67 |
+
# print("hh2", (ed11 - st11)*1000)
|
| 68 |
+
image_features = self.feature_select(image_forward_outs).to(images.dtype)
|
| 69 |
+
|
| 70 |
+
return image_features
|
| 71 |
+
|
| 72 |
+
@property
|
| 73 |
+
def dummy_feature(self):
|
| 74 |
+
return torch.zeros(1, self.hidden_size, device=self.device, dtype=self.dtype)
|
| 75 |
+
|
| 76 |
+
@property
|
| 77 |
+
def dtype(self):
|
| 78 |
+
return self.vision_tower.dtype
|
| 79 |
+
|
| 80 |
+
@property
|
| 81 |
+
def device(self):
|
| 82 |
+
return self.vision_tower.device
|
| 83 |
+
|
| 84 |
+
@property
|
| 85 |
+
def config(self):
|
| 86 |
+
if self.is_loaded:
|
| 87 |
+
return self.vision_tower.config
|
| 88 |
+
else:
|
| 89 |
+
return self.cfg_only
|
| 90 |
+
|
| 91 |
+
@property
|
| 92 |
+
def hidden_size(self):
|
| 93 |
+
return self.config.hidden_size
|
| 94 |
+
|
| 95 |
+
@property
|
| 96 |
+
def num_patches(self):
|
| 97 |
+
return (self.config.image_size // self.config.patch_size) ** 2
|
llm-awq/tinychat/models/llava_base/multimodal_projector/builder.py
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Modified from https://github.com/haotian-liu/LLaVA
|
| 2 |
+
|
| 3 |
+
import torch
|
| 4 |
+
import torch.nn as nn
|
| 5 |
+
import re
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class IdentityMap(nn.Module):
|
| 9 |
+
def __init__(self):
|
| 10 |
+
super().__init__()
|
| 11 |
+
|
| 12 |
+
def forward(self, x, *args, **kwargs):
|
| 13 |
+
return x
|
| 14 |
+
|
| 15 |
+
@property
|
| 16 |
+
def config(self):
|
| 17 |
+
return {"mm_projector_type": "identity"}
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
class SimpleResBlock(nn.Module):
|
| 21 |
+
def __init__(self, channels):
|
| 22 |
+
super().__init__()
|
| 23 |
+
self.pre_norm = nn.LayerNorm(channels)
|
| 24 |
+
|
| 25 |
+
self.proj = nn.Sequential(
|
| 26 |
+
nn.Linear(channels, channels), nn.GELU(), nn.Linear(channels, channels)
|
| 27 |
+
)
|
| 28 |
+
|
| 29 |
+
def forward(self, x):
|
| 30 |
+
x = self.pre_norm(x)
|
| 31 |
+
return x + self.proj(x)
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def build_vision_projector(config, delay_load=False, **kwargs):
|
| 35 |
+
projector_type = getattr(config, "mm_projector_type", "linear")
|
| 36 |
+
|
| 37 |
+
if projector_type == "linear":
|
| 38 |
+
return nn.Linear(config.mm_hidden_size, config.hidden_size)
|
| 39 |
+
|
| 40 |
+
mlp_gelu_match = re.match(r"^mlp(\d+)x_gelu$", projector_type)
|
| 41 |
+
if mlp_gelu_match:
|
| 42 |
+
mlp_depth = int(mlp_gelu_match.group(1))
|
| 43 |
+
modules = [nn.Linear(config.mm_hidden_size, config.hidden_size)]
|
| 44 |
+
for _ in range(1, mlp_depth):
|
| 45 |
+
modules.append(nn.GELU())
|
| 46 |
+
modules.append(nn.Linear(config.hidden_size, config.hidden_size))
|
| 47 |
+
return nn.Sequential(*modules)
|
| 48 |
+
|
| 49 |
+
if projector_type == "identity":
|
| 50 |
+
return IdentityMap()
|
| 51 |
+
|
| 52 |
+
if projector_type == "linearclip":
|
| 53 |
+
# load min, max range
|
| 54 |
+
min_max_range = torch.load(config.min_max_range_path)
|
| 55 |
+
assert min_max_range is not None
|
| 56 |
+
|
| 57 |
+
class RangeClip(nn.Module): # actually KNN projector
|
| 58 |
+
def __init__(self, min, max) -> None:
|
| 59 |
+
super().__init__()
|
| 60 |
+
self.register_buffer("min", min.detach().view(1, -1))
|
| 61 |
+
self.register_buffer("max", max.detach().view(1, -1))
|
| 62 |
+
|
| 63 |
+
def forward(self, x):
|
| 64 |
+
# dimension broadcast auto done
|
| 65 |
+
return torch.clamp(x, self.min.detach(), self.max.detach())
|
| 66 |
+
|
| 67 |
+
return nn.Sequential(
|
| 68 |
+
nn.Linear(config.mm_hidden_size, config.hidden_size),
|
| 69 |
+
RangeClip(*min_max_range),
|
| 70 |
+
)
|
| 71 |
+
|
| 72 |
+
raise ValueError(f"Unknown projector type: {projector_type}")
|
llm-awq/tinychat/models/llava_llama.py
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Modified from https://github.com/haotian-liu/LLaVA
|
| 2 |
+
# Copyright 2023 Haotian Liu
|
| 3 |
+
#
|
| 4 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
+
# you may not use this file except in compliance with the License.
|
| 6 |
+
# You may obtain a copy of the License at
|
| 7 |
+
#
|
| 8 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
+
#
|
| 10 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 11 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
+
# See the License for the specific language governing permissions and
|
| 14 |
+
# limitations under the License.
|
| 15 |
+
|
| 16 |
+
import os
|
| 17 |
+
import warnings
|
| 18 |
+
import shutil
|
| 19 |
+
import torch
|
| 20 |
+
import torch.nn as nn
|
| 21 |
+
from typing import List, Optional, Tuple, Union
|
| 22 |
+
|
| 23 |
+
from transformers import CLIPVisionModel
|
| 24 |
+
|
| 25 |
+
from transformers.modeling_outputs import CausalLMOutputWithPast
|
| 26 |
+
|
| 27 |
+
from .llava_base.llava_arch import LlavaMetaModel, LlavaMetaForCausalLM
|
| 28 |
+
from .llama import LlamaForCausalLM, Transformer
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
class LlavaLlamaModel(LlavaMetaModel, Transformer):
|
| 32 |
+
def __init__(self, config):
|
| 33 |
+
super(LlavaLlamaModel, self).__init__(config)
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
class LlavaLlamaForCausalLM(LlamaForCausalLM, LlavaMetaForCausalLM):
|
| 37 |
+
def __init__(self, config, dev="cuda"):
|
| 38 |
+
super(LlavaLlamaForCausalLM, self).__init__(config)
|
| 39 |
+
self.model = LlavaLlamaModel(config)
|
| 40 |
+
self.pretraining_tp = config.pretraining_tp
|
| 41 |
+
self.vocab_size = config.vocab_size
|
| 42 |
+
self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
|
| 43 |
+
self.config = config
|
| 44 |
+
self.device = dev
|
| 45 |
+
|
| 46 |
+
def get_model(self):
|
| 47 |
+
return self.model
|
| 48 |
+
|
| 49 |
+
def default_inputs_embeds_for_multimodal(self, input_ids, inputs_embeds, images):
|
| 50 |
+
if inputs_embeds is None:
|
| 51 |
+
inputs_embeds = self.get_model().embed_tokens(input_ids)
|
| 52 |
+
vision_tower = self.get_vision_tower().vision_tower
|
| 53 |
+
from contextlib import nullcontext
|
| 54 |
+
|
| 55 |
+
if (
|
| 56 |
+
vision_tower is not None
|
| 57 |
+
and (input_ids.shape[1] != 1 or self.training)
|
| 58 |
+
and images is not None
|
| 59 |
+
):
|
| 60 |
+
from tinychat.utils.constants import LLAVA_DEFAULT_IMAGE_PATCH_TOKEN_IDX
|
| 61 |
+
|
| 62 |
+
with (
|
| 63 |
+
nullcontext()
|
| 64 |
+
if getattr(self.config, "tune_vision_encoder", False)
|
| 65 |
+
else torch.no_grad()
|
| 66 |
+
):
|
| 67 |
+
if type(images) is list:
|
| 68 |
+
images = [
|
| 69 |
+
image.unsqueeze(0) if len(image.shape) == 3 else image
|
| 70 |
+
for image in images
|
| 71 |
+
]
|
| 72 |
+
images = torch.cat(images, dim=0)
|
| 73 |
+
dtype = next(vision_tower.parameters()).dtype
|
| 74 |
+
if "visiontransformer" in vision_tower.__class__.__name__.lower():
|
| 75 |
+
image_features = vision_tower(images.to(dtype))
|
| 76 |
+
else:
|
| 77 |
+
image_forward_outs = vision_tower(
|
| 78 |
+
images.to(dtype), output_hidden_states=True
|
| 79 |
+
)
|
| 80 |
+
select_hidden_state_layer = getattr(
|
| 81 |
+
self.config, "mm_vision_select_layer", -1
|
| 82 |
+
)
|
| 83 |
+
if abs(select_hidden_state_layer) > 100: # TOOD: find a better impl
|
| 84 |
+
# -212 -> 12,
|
| 85 |
+
idx1, idx2 = abs(select_hidden_state_layer) % 100, -(
|
| 86 |
+
abs(select_hidden_state_layer) // 100
|
| 87 |
+
)
|
| 88 |
+
# print("selecting multiple indices", idx1, idx2)
|
| 89 |
+
image_features = torch.cat(
|
| 90 |
+
(
|
| 91 |
+
image_forward_outs.hidden_states[idx1],
|
| 92 |
+
image_forward_outs.hidden_states[idx2],
|
| 93 |
+
),
|
| 94 |
+
dim=-1,
|
| 95 |
+
)
|
| 96 |
+
else:
|
| 97 |
+
image_features = image_forward_outs.hidden_states[
|
| 98 |
+
select_hidden_state_layer
|
| 99 |
+
]
|
| 100 |
+
if isinstance(vision_tower, CLIPVisionModel): # clip case, not for sam
|
| 101 |
+
image_features = image_features[:, 1:].to(images.dtype) # (B, N, D)
|
| 102 |
+
|
| 103 |
+
image_features = self.model.mm_projector(image_features)
|
| 104 |
+
|
| 105 |
+
if hasattr(self.config, "neftune_alpha") and self.config.neftune_alpha > 0:
|
| 106 |
+
# print("using neftune tuning with alpha", self.config.neftune_alpha)
|
| 107 |
+
dims = torch.tensor(image_features.shape[-2] * image_features.shape[-1])
|
| 108 |
+
mag_norm = self.config.neftune_alpha / torch.sqrt(dims)
|
| 109 |
+
image_features = image_features + torch.zeros_like(
|
| 110 |
+
image_features
|
| 111 |
+
).uniform_(-mag_norm, mag_norm)
|
| 112 |
+
|
| 113 |
+
if self.config.mm_projector_type == "dsresampler":
|
| 114 |
+
dummy_feat_shape = (1, 1024, 1664)
|
| 115 |
+
elif self.config.mm_projector_type == "linear2":
|
| 116 |
+
dummy_feat_shape = (1, 256, self.config.mm_hidden_size * 2)
|
| 117 |
+
else:
|
| 118 |
+
dummy_feat_shape = (1, 256, self.config.mm_hidden_size)
|
| 119 |
+
|
| 120 |
+
dummy_image_features = torch.zeros(
|
| 121 |
+
*dummy_feat_shape,
|
| 122 |
+
device=inputs_embeds.device,
|
| 123 |
+
dtype=inputs_embeds.dtype,
|
| 124 |
+
)
|
| 125 |
+
dummy_image_features = self.model.mm_projector(dummy_image_features)[
|
| 126 |
+
0
|
| 127 |
+
] # (1, N, D)
|
| 128 |
+
|
| 129 |
+
new_input_embeds = []
|
| 130 |
+
cur_image_idx = 0
|
| 131 |
+
|
| 132 |
+
image_token_idx = []
|
| 133 |
+
|
| 134 |
+
num_patches = -1
|
| 135 |
+
for i_sample, (cur_input_ids, cur_input_embeds) in enumerate(
|
| 136 |
+
zip(input_ids, inputs_embeds)
|
| 137 |
+
):
|
| 138 |
+
if (cur_input_ids == LLAVA_DEFAULT_IMAGE_PATCH_TOKEN_IDX).sum() == 0:
|
| 139 |
+
# multimodal LLM, but the current sample is not multimodal
|
| 140 |
+
cur_input_embeds = (
|
| 141 |
+
cur_input_embeds + (0.0 * dummy_image_features).sum()
|
| 142 |
+
)
|
| 143 |
+
new_input_embeds.append(cur_input_embeds)
|
| 144 |
+
# cur_image_idx += 1
|
| 145 |
+
continue
|
| 146 |
+
# TODO: Need to fix if vision_tower.config.use_im_start_end == True
|
| 147 |
+
num_total_patches = (
|
| 148 |
+
(cur_input_ids == LLAVA_DEFAULT_IMAGE_PATCH_TOKEN_IDX).sum().item()
|
| 149 |
+
)
|
| 150 |
+
masked_indices = torch.where(
|
| 151 |
+
cur_input_ids == LLAVA_DEFAULT_IMAGE_PATCH_TOKEN_IDX
|
| 152 |
+
)[0]
|
| 153 |
+
|
| 154 |
+
while num_total_patches:
|
| 155 |
+
if cur_image_idx >= image_features.shape[0]: # SHOULD NOT HAPPEN!!!
|
| 156 |
+
if self.training:
|
| 157 |
+
print("%" * 20, "INDEXING ERROR!")
|
| 158 |
+
break
|
| 159 |
+
else:
|
| 160 |
+
raise ValueError("INDEXING ERROR!")
|
| 161 |
+
cur_image_features = image_features[cur_image_idx]
|
| 162 |
+
num_patches = cur_image_features.shape[0]
|
| 163 |
+
mask_index_start = masked_indices[0]
|
| 164 |
+
masked_indices = masked_indices[num_patches:]
|
| 165 |
+
|
| 166 |
+
image_token_idx.append(
|
| 167 |
+
(
|
| 168 |
+
i_sample,
|
| 169 |
+
mask_index_start.item(),
|
| 170 |
+
(mask_index_start + num_patches).item(),
|
| 171 |
+
)
|
| 172 |
+
)
|
| 173 |
+
|
| 174 |
+
orig_embeds_params = None
|
| 175 |
+
if orig_embeds_params is not None:
|
| 176 |
+
cur_input_embeds = torch.cat(
|
| 177 |
+
(
|
| 178 |
+
cur_input_embeds[:mask_index_start].detach(),
|
| 179 |
+
cur_image_features,
|
| 180 |
+
cur_input_embeds[
|
| 181 |
+
mask_index_start + num_patches :
|
| 182 |
+
].detach(),
|
| 183 |
+
),
|
| 184 |
+
dim=0,
|
| 185 |
+
)
|
| 186 |
+
else:
|
| 187 |
+
cur_input_embeds = torch.cat(
|
| 188 |
+
(
|
| 189 |
+
cur_input_embeds[:mask_index_start],
|
| 190 |
+
cur_image_features,
|
| 191 |
+
cur_input_embeds[mask_index_start + num_patches :],
|
| 192 |
+
),
|
| 193 |
+
dim=0,
|
| 194 |
+
)
|
| 195 |
+
num_total_patches -= num_patches
|
| 196 |
+
assert num_total_patches >= 0, (num_total_patches, num_patches)
|
| 197 |
+
cur_image_idx += 1
|
| 198 |
+
|
| 199 |
+
new_input_embeds.append(cur_input_embeds)
|
| 200 |
+
if self.training:
|
| 201 |
+
if not masked_indices.numel() == 0:
|
| 202 |
+
print("%" * 20, "ERROR! masked_indices not empty...")
|
| 203 |
+
else:
|
| 204 |
+
assert masked_indices.numel() == 0
|
| 205 |
+
|
| 206 |
+
inputs_embeds = torch.stack(new_input_embeds, dim=0)
|
| 207 |
+
|
| 208 |
+
return inputs_embeds
|
| 209 |
+
|
| 210 |
+
def forward(
|
| 211 |
+
self,
|
| 212 |
+
input_ids: torch.LongTensor = None,
|
| 213 |
+
start_pos: int = None,
|
| 214 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 215 |
+
position_ids: Optional[torch.LongTensor] = None,
|
| 216 |
+
past_key_values: Optional[List[torch.FloatTensor]] = None,
|
| 217 |
+
inputs_embeds: Optional[torch.FloatTensor] = None,
|
| 218 |
+
labels: Optional[torch.LongTensor] = None,
|
| 219 |
+
use_cache: Optional[bool] = None,
|
| 220 |
+
output_attentions: Optional[bool] = None,
|
| 221 |
+
output_hidden_states: Optional[bool] = None,
|
| 222 |
+
images: Optional[torch.FloatTensor] = None,
|
| 223 |
+
return_dict: Optional[bool] = None,
|
| 224 |
+
special_token: bool = False,
|
| 225 |
+
) -> Union[Tuple, CausalLMOutputWithPast]:
|
| 226 |
+
if inputs_embeds is None:
|
| 227 |
+
if special_token:
|
| 228 |
+
(
|
| 229 |
+
input_ids,
|
| 230 |
+
position_ids,
|
| 231 |
+
attention_mask,
|
| 232 |
+
past_key_values,
|
| 233 |
+
inputs_embeds,
|
| 234 |
+
labels,
|
| 235 |
+
) = self.prepare_inputs_labels_for_multimodal(
|
| 236 |
+
input_ids,
|
| 237 |
+
position_ids,
|
| 238 |
+
attention_mask,
|
| 239 |
+
past_key_values,
|
| 240 |
+
labels,
|
| 241 |
+
images,
|
| 242 |
+
)
|
| 243 |
+
else:
|
| 244 |
+
inputs_embeds = self.default_inputs_embeds_for_multimodal(
|
| 245 |
+
input_ids, inputs_embeds, images
|
| 246 |
+
)
|
| 247 |
+
input_ids = None
|
| 248 |
+
|
| 249 |
+
if start_pos == None:
|
| 250 |
+
out = super().forward(
|
| 251 |
+
input_ids=input_ids,
|
| 252 |
+
attention_mask=attention_mask,
|
| 253 |
+
position_ids=position_ids,
|
| 254 |
+
past_key_values=past_key_values,
|
| 255 |
+
inputs_embeds=inputs_embeds,
|
| 256 |
+
labels=labels,
|
| 257 |
+
use_cache=use_cache,
|
| 258 |
+
output_attentions=output_attentions,
|
| 259 |
+
output_hidden_states=output_hidden_states,
|
| 260 |
+
return_dict=return_dict,
|
| 261 |
+
)
|
| 262 |
+
else:
|
| 263 |
+
out = super().forward(
|
| 264 |
+
tokens=input_ids,
|
| 265 |
+
start_pos=start_pos,
|
| 266 |
+
inputs_embeds=inputs_embeds,
|
| 267 |
+
)
|
| 268 |
+
return out
|
| 269 |
+
|
| 270 |
+
def prepare_inputs_for_generation(
|
| 271 |
+
self, input_ids, past_key_values=None, inputs_embeds=None, **kwargs
|
| 272 |
+
):
|
| 273 |
+
images = kwargs.pop("images", None)
|
| 274 |
+
_inputs = super().prepare_inputs_for_generation(
|
| 275 |
+
input_ids,
|
| 276 |
+
past_key_values=past_key_values,
|
| 277 |
+
inputs_embeds=inputs_embeds,
|
| 278 |
+
**kwargs,
|
| 279 |
+
)
|
| 280 |
+
if images is not None:
|
| 281 |
+
_inputs["images"] = images
|
| 282 |
+
return _inputs
|
llm-awq/tinychat/models/mpt.py
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
| 2 |
+
# This software may be used and distributed according to the terms of the GNU General Public License version 3.
|
| 3 |
+
|
| 4 |
+
from typing import Optional, Tuple
|
| 5 |
+
from dataclasses import dataclass
|
| 6 |
+
import math
|
| 7 |
+
|
| 8 |
+
import torch
|
| 9 |
+
from torch import nn
|
| 10 |
+
import torch.nn.functional as F
|
| 11 |
+
import awq_inference_engine
|
| 12 |
+
from transformers.models.llama.modeling_llama import LlamaRotaryEmbedding
|
| 13 |
+
|
| 14 |
+
# from flash_attn.flash_attn_interface import flash_attn_unpadded_func
|
| 15 |
+
|
| 16 |
+
import tinychat.utils.constants
|
| 17 |
+
|
| 18 |
+
max_batch_size = tinychat.utils.constants.max_batch_size
|
| 19 |
+
global_max_seq_len = tinychat.utils.constants.max_seq_len
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def gen_slopes(n_heads, alibi_bias_max=8):
|
| 23 |
+
_n_heads = 2 ** math.ceil(math.log2(n_heads))
|
| 24 |
+
m = torch.arange(1, _n_heads + 1, dtype=torch.float32)
|
| 25 |
+
m = m.mul(alibi_bias_max / _n_heads)
|
| 26 |
+
slopes = 1.0 / torch.pow(2, m)
|
| 27 |
+
if _n_heads != n_heads:
|
| 28 |
+
slopes = torch.concat([slopes[1::2], slopes[::2]])[:n_heads]
|
| 29 |
+
return slopes.view(1, n_heads, 1, 1)
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def build_alibi_bias(
|
| 33 |
+
n_heads, seq_len, full=False, alibi_bias_max=8, dtype=torch.float32
|
| 34 |
+
):
|
| 35 |
+
alibi_bias = torch.arange(1 - seq_len, 1, dtype=torch.int32).view(1, 1, 1, seq_len)
|
| 36 |
+
if full:
|
| 37 |
+
alibi_bias = alibi_bias - torch.arange(1 - seq_len, 1, dtype=torch.int32).view(
|
| 38 |
+
1, 1, seq_len, 1
|
| 39 |
+
)
|
| 40 |
+
alibi_bias = alibi_bias.abs().mul(-1)
|
| 41 |
+
slopes = gen_slopes(n_heads, alibi_bias_max)
|
| 42 |
+
alibi_bias = alibi_bias * slopes
|
| 43 |
+
slopes = slopes.squeeze(0).squeeze(-1).squeeze(-1)
|
| 44 |
+
return slopes.to(dtype=dtype), alibi_bias.to(dtype=dtype)
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def _cast_if_autocast_enabled(tensor):
|
| 48 |
+
if torch.is_autocast_enabled():
|
| 49 |
+
if tensor.device.type == "cuda":
|
| 50 |
+
dtype = torch.get_autocast_gpu_dtype()
|
| 51 |
+
elif tensor.device.type == "cpu":
|
| 52 |
+
dtype = torch.get_autocast_cpu_dtype()
|
| 53 |
+
else:
|
| 54 |
+
raise NotImplementedError()
|
| 55 |
+
return tensor.to(dtype=dtype)
|
| 56 |
+
return tensor
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
class LPLayerNorm(torch.nn.LayerNorm):
|
| 60 |
+
def __init__(self, normalized_shape, eps=1e-05, elementwise_affine=True):
|
| 61 |
+
super().__init__(
|
| 62 |
+
normalized_shape=normalized_shape,
|
| 63 |
+
eps=eps,
|
| 64 |
+
elementwise_affine=elementwise_affine,
|
| 65 |
+
)
|
| 66 |
+
|
| 67 |
+
def forward(self, x):
|
| 68 |
+
module_device = x.device
|
| 69 |
+
downcast_x = _cast_if_autocast_enabled(x)
|
| 70 |
+
downcast_weight = (
|
| 71 |
+
_cast_if_autocast_enabled(self.weight)
|
| 72 |
+
if self.weight is not None
|
| 73 |
+
else self.weight
|
| 74 |
+
)
|
| 75 |
+
downcast_bias = (
|
| 76 |
+
_cast_if_autocast_enabled(self.bias) if self.bias is not None else self.bias
|
| 77 |
+
)
|
| 78 |
+
with torch.autocast(enabled=False, device_type=module_device.type):
|
| 79 |
+
return torch.nn.functional.layer_norm(
|
| 80 |
+
downcast_x,
|
| 81 |
+
self.normalized_shape,
|
| 82 |
+
downcast_weight,
|
| 83 |
+
downcast_bias,
|
| 84 |
+
self.eps,
|
| 85 |
+
)
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
class SharedEmbedding(nn.Embedding):
|
| 89 |
+
def forward(self, input: torch.Tensor, unembed: bool = False) -> torch.Tensor:
|
| 90 |
+
if unembed:
|
| 91 |
+
return F.linear(input, self.weight)
|
| 92 |
+
return super().forward(input)
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
class MPTAttentionFused(nn.Module):
|
| 96 |
+
def __init__(self, args):
|
| 97 |
+
super().__init__()
|
| 98 |
+
self.args = args
|
| 99 |
+
self.n_local_heads = args.n_heads
|
| 100 |
+
self.head_dim = args.d_model // args.n_heads
|
| 101 |
+
args.max_seq_len = min(args.max_seq_len, global_max_seq_len)
|
| 102 |
+
|
| 103 |
+
self.Wqkv = nn.Linear(
|
| 104 |
+
args.d_model,
|
| 105 |
+
args.n_heads * self.head_dim * 3,
|
| 106 |
+
bias=False,
|
| 107 |
+
)
|
| 108 |
+
|
| 109 |
+
self.out_proj = nn.Linear(
|
| 110 |
+
args.n_heads * self.head_dim,
|
| 111 |
+
args.d_model,
|
| 112 |
+
bias=False,
|
| 113 |
+
)
|
| 114 |
+
|
| 115 |
+
# following fastertransformer definition
|
| 116 |
+
|
| 117 |
+
self.cache_v = (
|
| 118 |
+
torch.zeros(
|
| 119 |
+
(
|
| 120 |
+
max_batch_size,
|
| 121 |
+
self.n_local_heads,
|
| 122 |
+
args.max_seq_len,
|
| 123 |
+
self.head_dim,
|
| 124 |
+
)
|
| 125 |
+
)
|
| 126 |
+
.cuda()
|
| 127 |
+
.half()
|
| 128 |
+
) # added to half
|
| 129 |
+
# 8: pack 8 fp16 in FT, if fp32 then use 4
|
| 130 |
+
self.cache_k = (
|
| 131 |
+
torch.zeros(
|
| 132 |
+
(
|
| 133 |
+
max_batch_size,
|
| 134 |
+
self.n_local_heads,
|
| 135 |
+
self.head_dim // 8,
|
| 136 |
+
args.max_seq_len,
|
| 137 |
+
8,
|
| 138 |
+
)
|
| 139 |
+
)
|
| 140 |
+
.cuda()
|
| 141 |
+
.half()
|
| 142 |
+
) # added to half
|
| 143 |
+
|
| 144 |
+
alibi_slopes, alibi_bias = build_alibi_bias(
|
| 145 |
+
self.n_local_heads, args.max_seq_len
|
| 146 |
+
)
|
| 147 |
+
# TODO (Haotian): fix device
|
| 148 |
+
self.alibi_slopes = alibi_slopes.float().to("cuda:0")
|
| 149 |
+
self.alibi_bias = alibi_bias.to("cuda:0")
|
| 150 |
+
|
| 151 |
+
def forward(
|
| 152 |
+
self,
|
| 153 |
+
x: torch.Tensor,
|
| 154 |
+
start_pos: int,
|
| 155 |
+
mask: Optional[torch.Tensor],
|
| 156 |
+
):
|
| 157 |
+
bsz, seqlen, _ = x.shape
|
| 158 |
+
xqkv = self.Wqkv(x)
|
| 159 |
+
xqkv = xqkv.view(bsz, seqlen, -1, self.n_local_heads, self.head_dim)
|
| 160 |
+
xq = xqkv[:, :, 0]
|
| 161 |
+
xk = xqkv[:, :, 1]
|
| 162 |
+
xv = xqkv[:, :, 2]
|
| 163 |
+
|
| 164 |
+
if seqlen > 1:
|
| 165 |
+
xq = xq.view(bsz, seqlen, self.n_local_heads, self.head_dim)
|
| 166 |
+
xk = xk.view(bsz, seqlen, self.n_local_heads, self.head_dim)
|
| 167 |
+
xv = xv.view(bsz, seqlen, self.n_local_heads, self.head_dim)
|
| 168 |
+
|
| 169 |
+
self.cache_k = self.cache_k.to(xq)
|
| 170 |
+
self.cache_v = self.cache_v.to(xq)
|
| 171 |
+
|
| 172 |
+
values_store = xv.transpose(2, 1)
|
| 173 |
+
keys_store = (
|
| 174 |
+
xk.reshape(bsz, seqlen, self.n_local_heads, self.head_dim // 8, 8)
|
| 175 |
+
.permute(0, 2, 3, 1, 4)
|
| 176 |
+
.contiguous()
|
| 177 |
+
)
|
| 178 |
+
|
| 179 |
+
self.cache_v[:bsz, :, start_pos : start_pos + seqlen, :] = values_store
|
| 180 |
+
self.cache_k[:bsz, :, :, start_pos : start_pos + seqlen, :] = keys_store
|
| 181 |
+
|
| 182 |
+
keys = xk
|
| 183 |
+
values = xv
|
| 184 |
+
|
| 185 |
+
xq = xq.transpose(1, 2)
|
| 186 |
+
keys = keys.transpose(1, 2)
|
| 187 |
+
values = values.transpose(1, 2)
|
| 188 |
+
scores = torch.matmul(xq, keys.transpose(2, 3)) / math.sqrt(self.head_dim)
|
| 189 |
+
scores += self.alibi_bias[..., :seqlen]
|
| 190 |
+
if mask is not None:
|
| 191 |
+
scores = scores + mask # (bs, n_local_heads, slen, cache_len + slen)
|
| 192 |
+
scores = F.softmax(scores.float(), dim=-1).type_as(xq)
|
| 193 |
+
output = torch.matmul(scores, values) # (bs, n_local_heads, slen, head_dim)
|
| 194 |
+
output = output.transpose(1, 2).contiguous().view(bsz, seqlen, -1)
|
| 195 |
+
else:
|
| 196 |
+
# xq = xq[:, 0, :, :]
|
| 197 |
+
# xk = xk[:, 0, :, :]
|
| 198 |
+
# xv = xv[:, 0, :, :]
|
| 199 |
+
xq = xq.view(bsz, self.n_local_heads, self.head_dim)
|
| 200 |
+
xk = xk.view(bsz, self.n_local_heads, self.head_dim)
|
| 201 |
+
xv = xv.view(bsz, self.n_local_heads, self.head_dim)
|
| 202 |
+
output = awq_inference_engine.single_query_attention(
|
| 203 |
+
xq,
|
| 204 |
+
xk,
|
| 205 |
+
xv,
|
| 206 |
+
self.cache_k,
|
| 207 |
+
self.cache_v,
|
| 208 |
+
None,
|
| 209 |
+
# with alibi embedding
|
| 210 |
+
self.alibi_slopes.float(),
|
| 211 |
+
start_pos,
|
| 212 |
+
# rotary embed dim = 0 => no rotary embedding
|
| 213 |
+
0,
|
| 214 |
+
10000,
|
| 215 |
+
1.0,
|
| 216 |
+
True,
|
| 217 |
+
)
|
| 218 |
+
output = output.reshape(bsz, 1, -1)
|
| 219 |
+
|
| 220 |
+
return self.out_proj(output)
|
| 221 |
+
|
| 222 |
+
|
| 223 |
+
class MPTMLP(nn.Module):
|
| 224 |
+
def __init__(self, d_model: int, expansion_ratio: int):
|
| 225 |
+
super().__init__()
|
| 226 |
+
self.up_proj = nn.Linear(d_model, expansion_ratio * d_model, bias=False)
|
| 227 |
+
self.act = nn.GELU(approximate="none")
|
| 228 |
+
self.down_proj = nn.Linear(expansion_ratio * d_model, d_model, bias=False)
|
| 229 |
+
self.down_proj._is_residual = True
|
| 230 |
+
|
| 231 |
+
def forward(self, x):
|
| 232 |
+
return self.down_proj(self.act(self.up_proj(x)))
|
| 233 |
+
|
| 234 |
+
|
| 235 |
+
class MPTBlock(nn.Module):
|
| 236 |
+
def __init__(self, layer_id: int, args):
|
| 237 |
+
super().__init__()
|
| 238 |
+
self.n_heads = args.n_heads
|
| 239 |
+
self.dim = args.d_model
|
| 240 |
+
self.head_dim = args.d_model // args.n_heads
|
| 241 |
+
self.attn = MPTAttentionFused(args)
|
| 242 |
+
self.ffn = MPTMLP(d_model=args.d_model, expansion_ratio=4)
|
| 243 |
+
self.layer_id = layer_id
|
| 244 |
+
self.norm_1 = LPLayerNorm(args.d_model, eps=1e-6)
|
| 245 |
+
self.norm_2 = LPLayerNorm(args.d_model, eps=1e-6)
|
| 246 |
+
|
| 247 |
+
def forward(
|
| 248 |
+
self,
|
| 249 |
+
x: torch.Tensor,
|
| 250 |
+
start_pos: int,
|
| 251 |
+
mask: Optional[torch.Tensor],
|
| 252 |
+
):
|
| 253 |
+
h = x + self.attn.forward(self.norm_1(x), start_pos, mask)
|
| 254 |
+
out = h + self.ffn.forward(self.norm_2(h))
|
| 255 |
+
return out
|
| 256 |
+
|
| 257 |
+
|
| 258 |
+
class Transformer(nn.Module):
|
| 259 |
+
def __init__(self, params):
|
| 260 |
+
super().__init__()
|
| 261 |
+
self.params = params
|
| 262 |
+
self.vocab_size = params.vocab_size
|
| 263 |
+
self.n_layers = params.n_layers
|
| 264 |
+
|
| 265 |
+
self.wte = SharedEmbedding(params.vocab_size, params.d_model)
|
| 266 |
+
|
| 267 |
+
self.blocks = torch.nn.ModuleList()
|
| 268 |
+
for layer_id in range(params.n_layers):
|
| 269 |
+
self.blocks.append(MPTBlock(layer_id, params))
|
| 270 |
+
|
| 271 |
+
self.norm_f = LPLayerNorm(params.d_model, eps=1e-6)
|
| 272 |
+
|
| 273 |
+
@torch.inference_mode()
|
| 274 |
+
def forward(self, tokens: torch.Tensor, start_pos: int):
|
| 275 |
+
_bsz, seqlen = tokens.shape
|
| 276 |
+
h = self.wte(tokens)
|
| 277 |
+
|
| 278 |
+
mask = None
|
| 279 |
+
if seqlen > 1:
|
| 280 |
+
mask = torch.full(
|
| 281 |
+
(1, 1, seqlen, seqlen), float("-inf"), device=tokens.device
|
| 282 |
+
)
|
| 283 |
+
mask = torch.triu(mask, diagonal=start_pos + 1).type_as(h)
|
| 284 |
+
for layer in self.blocks:
|
| 285 |
+
h = layer(h, start_pos, mask)
|
| 286 |
+
h = self.norm_f(h)
|
| 287 |
+
return h
|
| 288 |
+
|
| 289 |
+
|
| 290 |
+
class MPTForCausalLM(nn.Module):
|
| 291 |
+
def __init__(self, params):
|
| 292 |
+
super().__init__()
|
| 293 |
+
self.config = params
|
| 294 |
+
self.transformer = Transformer(params)
|
| 295 |
+
if params.no_bias:
|
| 296 |
+
for module in self.modules():
|
| 297 |
+
if hasattr(module, "bias") and isinstance(module.bias, nn.Parameter):
|
| 298 |
+
module.register_parameter("bias", None)
|
| 299 |
+
|
| 300 |
+
@torch.inference_mode()
|
| 301 |
+
def forward(self, tokens: torch.Tensor, start_pos: int):
|
| 302 |
+
h = self.transformer(tokens, start_pos)
|
| 303 |
+
output = self.transformer.wte(h, unembed=True) # only compute last logits
|
| 304 |
+
return output.float()
|
llm-awq/tinychat/models/nvila/configuration_llava.py
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 NVIDIA CORPORATION & AFFILIATES
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
#
|
| 15 |
+
# SPDX-License-Identifier: Apache-2.0
|
| 16 |
+
|
| 17 |
+
from typing import Optional
|
| 18 |
+
|
| 19 |
+
from transformers import PretrainedConfig
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
class LlavaConfig(PretrainedConfig):
|
| 23 |
+
model_type = "llava"
|
| 24 |
+
|
| 25 |
+
def __init__(
|
| 26 |
+
self,
|
| 27 |
+
llm_cfg=None,
|
| 28 |
+
vision_tower_cfg=None,
|
| 29 |
+
mm_projector_cfg=None,
|
| 30 |
+
architectures=None,
|
| 31 |
+
resume_path=None,
|
| 32 |
+
hidden_size=None,
|
| 33 |
+
mm_hidden_size=None,
|
| 34 |
+
image_aspect_ratio=None,
|
| 35 |
+
num_video_frames=None,
|
| 36 |
+
fps=None,
|
| 37 |
+
mm_vision_select_layer=None,
|
| 38 |
+
mm_vision_select_feature=None,
|
| 39 |
+
mm_use_im_start_end=False,
|
| 40 |
+
mm_use_im_patch_token=False,
|
| 41 |
+
mm_projector_lr=None,
|
| 42 |
+
vision_tower_lr=None,
|
| 43 |
+
vision_resolution=None,
|
| 44 |
+
interpolate_mode=None,
|
| 45 |
+
s2=None,
|
| 46 |
+
dynamic_s2=None,
|
| 47 |
+
s2_scales=None,
|
| 48 |
+
s2_max_split_size=None,
|
| 49 |
+
s2_resize_output_to_scale_idx=0,
|
| 50 |
+
min_tiles: Optional[int] = 1,
|
| 51 |
+
max_tiles: Optional[int] = 12,
|
| 52 |
+
num_time_tokens=None,
|
| 53 |
+
time_token_format=None,
|
| 54 |
+
image_encoder: str = '{"_target_": "llava.model.encoders.BasicImageEncoder"}',
|
| 55 |
+
video_encoder: str = '{"_target_": "llava.model.encoders.BasicVideoEncoder"}',
|
| 56 |
+
**kwargs,
|
| 57 |
+
):
|
| 58 |
+
super().__init__()
|
| 59 |
+
self.architectures = architectures
|
| 60 |
+
self.llm_cfg = llm_cfg
|
| 61 |
+
self.vision_tower_cfg = vision_tower_cfg
|
| 62 |
+
self.mm_projector_cfg = mm_projector_cfg
|
| 63 |
+
self.resume_path = resume_path
|
| 64 |
+
|
| 65 |
+
self.hidden_size = hidden_size
|
| 66 |
+
self.mm_hidden_size = mm_hidden_size
|
| 67 |
+
self.image_aspect_ratio = image_aspect_ratio
|
| 68 |
+
self.num_video_frames = num_video_frames
|
| 69 |
+
self.fps = fps
|
| 70 |
+
self.mm_vision_select_layer = mm_vision_select_layer
|
| 71 |
+
self.mm_vision_select_feature = mm_vision_select_feature
|
| 72 |
+
self.mm_use_im_start_end = mm_use_im_start_end
|
| 73 |
+
self.mm_use_im_patch_token = mm_use_im_patch_token
|
| 74 |
+
self.mm_projector_lr = mm_projector_lr
|
| 75 |
+
self.vision_tower_lr = vision_tower_lr
|
| 76 |
+
self.vision_resolution = vision_resolution
|
| 77 |
+
self.interpolate_mode = interpolate_mode
|
| 78 |
+
self.s2 = s2
|
| 79 |
+
self.dynamic_s2 = dynamic_s2
|
| 80 |
+
self.s2_scales = s2_scales
|
| 81 |
+
self.s2_max_split_size = s2_max_split_size
|
| 82 |
+
self.s2_resize_output_to_scale_idx = s2_resize_output_to_scale_idx
|
| 83 |
+
self.min_tiles = min_tiles
|
| 84 |
+
self.max_tiles = max_tiles
|
| 85 |
+
self.num_time_tokens = num_time_tokens
|
| 86 |
+
self.time_token_format = time_token_format
|
| 87 |
+
|
| 88 |
+
self.image_encoder = image_encoder
|
| 89 |
+
self.video_encoder = video_encoder
|
llm-awq/tinychat/models/nvila_qwen2.py
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023 Haotian Liu
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
# This file is modified from https://github.com/haotian-liu/LLaVA/
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
import os
|
| 19 |
+
from collections import defaultdict
|
| 20 |
+
from typing import Dict, List, Optional, Tuple, Union
|
| 21 |
+
|
| 22 |
+
import torch
|
| 23 |
+
from transformers import AutoConfig, AutoModel, PretrainedConfig, PreTrainedModel
|
| 24 |
+
from transformers.modeling_outputs import CausalLMOutputWithPast
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
from .nvila.configuration_llava import LlavaConfig
|
| 28 |
+
from .nvila.llava_arch import LlavaMetaForCausalLM, LlavaMetaModel
|
| 29 |
+
from .qwen2 import Qwen2ForCausalLM
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
def skip(*args, **kwargs):
|
| 33 |
+
pass
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
torch.nn.init.kaiming_uniform_ = skip
|
| 37 |
+
torch.nn.init.kaiming_normal_ = skip
|
| 38 |
+
torch.nn.init.uniform_ = skip
|
| 39 |
+
torch.nn.init.normal_ = skip
|
| 40 |
+
from transformers import modeling_utils
|
| 41 |
+
|
| 42 |
+
modeling_utils._init_weights = False
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
class LlavaLlamaConfig(LlavaConfig):
|
| 46 |
+
model_type = "llava_llama"
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
class NVILAQwen2(LlavaMetaModel, LlavaMetaForCausalLM, PreTrainedModel):
|
| 50 |
+
config_class = LlavaLlamaConfig
|
| 51 |
+
main_input_name = "input_embeds"
|
| 52 |
+
supports_gradient_checkpointing = True
|
| 53 |
+
_supports_flash_attn_2 = True
|
| 54 |
+
|
| 55 |
+
def __init__(
|
| 56 |
+
self, config: LlavaLlamaConfig = None, llm=True, *args, **kwargs
|
| 57 |
+
) -> None:
|
| 58 |
+
super().__init__(config)
|
| 59 |
+
self.init_vlm(config=config, *args, **kwargs)
|
| 60 |
+
# TODO: Skip the weight loading to save time
|
| 61 |
+
self.llm_cfg = AutoConfig.from_pretrained(self.llm_cfg, init_weights=False)
|
| 62 |
+
if llm:
|
| 63 |
+
self.llm = Qwen2ForCausalLM.from_pretrained(self.llm_cfg._name_or_path)
|
| 64 |
+
self.llm = self.llm.cpu()
|
| 65 |
+
self.llm.resize_token_embeddings(len(self.tokenizer))
|
| 66 |
+
else:
|
| 67 |
+
self.llm = None
|
| 68 |
+
|
| 69 |
+
@classmethod
|
| 70 |
+
def from_pretrained(
|
| 71 |
+
cls,
|
| 72 |
+
pretrained_model_name_or_path: Optional[Union[str, os.PathLike]],
|
| 73 |
+
*model_args,
|
| 74 |
+
config: Optional[Union[PretrainedConfig, str, os.PathLike]] = None,
|
| 75 |
+
cache_dir: Optional[Union[str, os.PathLike]] = None,
|
| 76 |
+
ignore_mismatched_sizes: bool = False,
|
| 77 |
+
force_download: bool = False,
|
| 78 |
+
local_files_only: bool = False,
|
| 79 |
+
token: Optional[Union[str, bool]] = None,
|
| 80 |
+
revision: str = "main",
|
| 81 |
+
use_safetensors: bool = None,
|
| 82 |
+
**kwargs,
|
| 83 |
+
):
|
| 84 |
+
if hasattr(cls, "load_pretrained"):
|
| 85 |
+
return cls.load_pretrained(
|
| 86 |
+
pretrained_model_name_or_path,
|
| 87 |
+
*model_args,
|
| 88 |
+
config=config,
|
| 89 |
+
cache_dir=cache_dir,
|
| 90 |
+
ignore_mismatched_sizes=ignore_mismatched_sizes,
|
| 91 |
+
force_download=force_download,
|
| 92 |
+
local_files_only=local_files_only,
|
| 93 |
+
token=token,
|
| 94 |
+
revision=revision,
|
| 95 |
+
use_safetensors=use_safetensors,
|
| 96 |
+
**kwargs,
|
| 97 |
+
)
|
| 98 |
+
return super(NVILAQwen2).from_pretrained(
|
| 99 |
+
pretrained_model_name_or_path,
|
| 100 |
+
*model_args,
|
| 101 |
+
config=config,
|
| 102 |
+
cache_dir=cache_dir,
|
| 103 |
+
ignore_mismatched_sizes=ignore_mismatched_sizes,
|
| 104 |
+
force_download=force_download,
|
| 105 |
+
local_files_only=local_files_only,
|
| 106 |
+
token=token,
|
| 107 |
+
revision=revision,
|
| 108 |
+
use_safetensors=use_safetensors,
|
| 109 |
+
**kwargs,
|
| 110 |
+
)
|
| 111 |
+
|
| 112 |
+
def forward(
|
| 113 |
+
self,
|
| 114 |
+
input_ids: torch.LongTensor = None,
|
| 115 |
+
media: Optional[Dict[str, List[torch.Tensor]]] = None,
|
| 116 |
+
images: Optional[torch.FloatTensor] = None,
|
| 117 |
+
media_config: Optional[List] = None,
|
| 118 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 119 |
+
position_ids: Optional[torch.LongTensor] = None,
|
| 120 |
+
past_key_values: Optional[List[torch.FloatTensor]] = None,
|
| 121 |
+
inputs_embeds: Optional[torch.FloatTensor] = None,
|
| 122 |
+
labels: Optional[torch.LongTensor] = None,
|
| 123 |
+
packing: bool = True,
|
| 124 |
+
seqlens_in_batch: Optional[torch.LongTensor] = None,
|
| 125 |
+
dpo_forward: bool = False,
|
| 126 |
+
**kwargs,
|
| 127 |
+
) -> Union[Tuple, CausalLMOutputWithPast]:
|
| 128 |
+
self.freezed_module_patch()
|
| 129 |
+
|
| 130 |
+
if images is not None:
|
| 131 |
+
if media is not None:
|
| 132 |
+
raise ValueError(
|
| 133 |
+
"Both 'media' and 'images' are provided. Please provide only one."
|
| 134 |
+
)
|
| 135 |
+
media = {"image": images}
|
| 136 |
+
|
| 137 |
+
if media_config is None:
|
| 138 |
+
media_config = defaultdict(dict)
|
| 139 |
+
|
| 140 |
+
if inputs_embeds is None:
|
| 141 |
+
inputs_embeds, labels, attention_mask = self._embed(
|
| 142 |
+
input_ids, media, media_config, labels, attention_mask
|
| 143 |
+
)
|
| 144 |
+
|
| 145 |
+
outputs = self.llm(
|
| 146 |
+
inputs_embeds=inputs_embeds,
|
| 147 |
+
attention_mask=attention_mask,
|
| 148 |
+
position_ids=position_ids,
|
| 149 |
+
past_key_values=past_key_values,
|
| 150 |
+
labels=labels,
|
| 151 |
+
**kwargs,
|
| 152 |
+
)
|
| 153 |
+
|
| 154 |
+
if dpo_forward:
|
| 155 |
+
return outputs.logits, labels
|
| 156 |
+
|
| 157 |
+
return outputs
|
llm-awq/tinychat/modules/__init__.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .fused_norm import *
|
| 2 |
+
from .fused_attn import *
|
| 3 |
+
from .fused_mlp import *
|
| 4 |
+
from .fused_vision_attn import *
|
| 5 |
+
try:
|
| 6 |
+
from .fused_siglipdecoder import *
|
| 7 |
+
from .fused_internencoder import *
|
| 8 |
+
except ImportError as e:
|
| 9 |
+
print("InternVL3 model import failure. To activate, please install VILA at https://github.com/NVlabs/VILA.")
|
llm-awq/tinychat/modules/fused_mlp.py
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
import torch
|
| 3 |
+
import torch.nn as nn
|
| 4 |
+
import torch.nn.functional as F
|
| 5 |
+
from torch.cuda.amp import custom_bwd, custom_fwd
|
| 6 |
+
from transformers.models.llama.modeling_llama import LlamaMLP
|
| 7 |
+
|
| 8 |
+
import awq_inference_engine
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class QuantLlamaMLP(nn.Module):
|
| 12 |
+
def __init__(
|
| 13 |
+
self,
|
| 14 |
+
gate_proj,
|
| 15 |
+
down_proj,
|
| 16 |
+
up_proj,
|
| 17 |
+
):
|
| 18 |
+
super().__init__()
|
| 19 |
+
self.register_buffer("gate_proj_qweight", gate_proj.qweight)
|
| 20 |
+
self.register_buffer("gate_proj_scales", gate_proj.scales)
|
| 21 |
+
self.register_buffer("gate_proj_scaled_zeros", gate_proj.scaled_zeros)
|
| 22 |
+
self.register_buffer("up_proj_qweight", up_proj.qweight)
|
| 23 |
+
self.register_buffer("up_proj_scales", up_proj.scales)
|
| 24 |
+
self.register_buffer("up_proj_scaled_zeros", up_proj.scaled_zeros)
|
| 25 |
+
|
| 26 |
+
self.in_features = gate_proj.in_features
|
| 27 |
+
self.intermediate_size = gate_proj.out_features
|
| 28 |
+
self.out_features = down_proj.out_features
|
| 29 |
+
self.w_bit = gate_proj.w_bit
|
| 30 |
+
self.down_proj = down_proj
|
| 31 |
+
self.split_k_iters = down_proj.split_k_iters
|
| 32 |
+
|
| 33 |
+
def forward(self, x):
|
| 34 |
+
return self.down_proj(self.our_llama_mlp(x))
|
| 35 |
+
|
| 36 |
+
def our_llama_mlp(self, x):
|
| 37 |
+
# out_shape = x.shape[:-1] + (self.intermediate_size,)
|
| 38 |
+
# x = x.reshape(-1, x.shape[-1])
|
| 39 |
+
if x.numel() // x.shape[-1] < 8:
|
| 40 |
+
gate_output = awq_inference_engine.gemv_forward_cuda_new(
|
| 41 |
+
x,
|
| 42 |
+
self.gate_proj_qweight,
|
| 43 |
+
self.gate_proj_scales,
|
| 44 |
+
self.gate_proj_scaled_zeros,
|
| 45 |
+
x.numel() // x.shape[-1],
|
| 46 |
+
self.intermediate_size,
|
| 47 |
+
self.in_features,
|
| 48 |
+
self.down_proj.group_size,
|
| 49 |
+
)
|
| 50 |
+
gate_output = F.silu(gate_output)
|
| 51 |
+
up_output = awq_inference_engine.gemv_forward_cuda_new(
|
| 52 |
+
x,
|
| 53 |
+
self.up_proj_qweight,
|
| 54 |
+
self.up_proj_scales,
|
| 55 |
+
self.up_proj_scaled_zeros,
|
| 56 |
+
x.numel() // x.shape[-1],
|
| 57 |
+
self.intermediate_size,
|
| 58 |
+
self.in_features,
|
| 59 |
+
self.down_proj.group_size,
|
| 60 |
+
)
|
| 61 |
+
else:
|
| 62 |
+
# num_mn_tiles = (x.shape[0] // 32) * (self.intermediate_size // 128)
|
| 63 |
+
# cuda_Semaphores_gate = torch.empty(num_mn_tiles).int().to(x.device)
|
| 64 |
+
# cuda_Semaphores_up = torch.empty(num_mn_tiles).int().to(x.device)
|
| 65 |
+
gate_output = awq_inference_engine.gemm_forward_cuda_new(
|
| 66 |
+
x,
|
| 67 |
+
self.gate_proj_qweight,
|
| 68 |
+
self.gate_proj_scales,
|
| 69 |
+
self.gate_proj_scaled_zeros - 8 * self.gate_proj_scales,
|
| 70 |
+
# self.gate_cuda_semaphores
|
| 71 |
+
)
|
| 72 |
+
up_output = awq_inference_engine.gemm_forward_cuda_new(
|
| 73 |
+
x,
|
| 74 |
+
self.up_proj_qweight,
|
| 75 |
+
self.up_proj_scales,
|
| 76 |
+
self.up_proj_scaled_zeros - 8 * self.up_proj_scales,
|
| 77 |
+
# self.up_cuda_semaphores
|
| 78 |
+
)
|
| 79 |
+
gate_output = F.silu(gate_output)
|
| 80 |
+
|
| 81 |
+
c = gate_output * up_output
|
| 82 |
+
# c = c.reshape(out_shape)
|
| 83 |
+
return c
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
def make_fused_mlp(m, parent_name=""):
|
| 87 |
+
if not hasattr(make_fused_mlp, "called"):
|
| 88 |
+
# print("[Warning] Calling a fake MLP fusion. But still faster than Huggingface Implimentation.")
|
| 89 |
+
make_fused_mlp.called = True
|
| 90 |
+
"""
|
| 91 |
+
Replace all LlamaMLP modules with QuantLlamaMLP modules, which fuses many of the operations.
|
| 92 |
+
"""
|
| 93 |
+
if m.__class__.__name__ in ["LlamaMLP"]:
|
| 94 |
+
return QuantLlamaMLP(m.gate_proj, m.down_proj, m.up_proj)
|
| 95 |
+
|
| 96 |
+
for name, child in m.named_children():
|
| 97 |
+
child = make_fused_mlp(child, parent_name=f"{parent_name}.{name}")
|
| 98 |
+
|
| 99 |
+
if isinstance(child, QuantLlamaMLP):
|
| 100 |
+
setattr(m, name, child)
|
| 101 |
+
return m
|
llm-awq/tinychat/nvila_benchmark.py
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
|
| 3 |
+
from termcolor import colored
|
| 4 |
+
|
| 5 |
+
import llava
|
| 6 |
+
from llava import conversation as clib
|
| 7 |
+
from llava.media import Image, Video
|
| 8 |
+
import torch
|
| 9 |
+
from awq.quantize import fake_quant
|
| 10 |
+
from awq.quantize.quantizer import real_quantize_model_weight
|
| 11 |
+
from transformers import AutoConfig
|
| 12 |
+
import tinychat
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def skip(*args, **kwargs):
|
| 16 |
+
pass
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def main() -> None:
|
| 20 |
+
parser = argparse.ArgumentParser()
|
| 21 |
+
parser.add_argument(
|
| 22 |
+
"--model-path",
|
| 23 |
+
"-m",
|
| 24 |
+
type=str,
|
| 25 |
+
default="/home/yuming/workspace/qwen/models/nvila-internal-8b-v1",
|
| 26 |
+
)
|
| 27 |
+
parser.add_argument(
|
| 28 |
+
"--quant_path",
|
| 29 |
+
type=str,
|
| 30 |
+
default="/PATH/TO/QUANT",
|
| 31 |
+
)
|
| 32 |
+
# parser.add_argument("--model-path", "-m", type=str, default="Efficient-Large-Model/J65")
|
| 33 |
+
# parser.add_argument("--quant_path", type=str, default="/home/yuming/workspace/qwen/models/J65/llm/vila2-J65-w4-g128-awq-v2.pt")
|
| 34 |
+
parser.add_argument("--conv-mode", "-c", type=str, default="auto")
|
| 35 |
+
# parser.add_argument("--media", type=str, default="/home/yuming/workspace/space_woaudio.mp4")
|
| 36 |
+
parser.add_argument("--device", type=str, default="cuda:0")
|
| 37 |
+
parser.add_argument(
|
| 38 |
+
"--act_scale_path",
|
| 39 |
+
type=str,
|
| 40 |
+
default="/PATH/TO/SCALE",
|
| 41 |
+
)
|
| 42 |
+
# quantization options
|
| 43 |
+
parser.add_argument("--quant_llm", action="store_true")
|
| 44 |
+
parser.add_argument("--quant_VT", action="store_true")
|
| 45 |
+
# Four basic tasks
|
| 46 |
+
parser.add_argument("--video_caption", action="store_true")
|
| 47 |
+
parser.add_argument("--video_QA", action="store_true")
|
| 48 |
+
parser.add_argument("--image_caption", action="store_true")
|
| 49 |
+
parser.add_argument("--image_QA", action="store_true")
|
| 50 |
+
|
| 51 |
+
parser.add_argument(
|
| 52 |
+
"--all",
|
| 53 |
+
action="store_true",
|
| 54 |
+
help="Whether to quantize visiontower and llm, and test all 4 tasks",
|
| 55 |
+
)
|
| 56 |
+
parser.add_argument(
|
| 57 |
+
"--fakequant_VT",
|
| 58 |
+
action="store_true",
|
| 59 |
+
help="Use fake quant or real quant for VisionTower",
|
| 60 |
+
)
|
| 61 |
+
parser.add_argument(
|
| 62 |
+
"--all_task", action="store_true", help="Whether to test all 4 tasks"
|
| 63 |
+
)
|
| 64 |
+
parser.add_argument(
|
| 65 |
+
"--video_path", type=str, default="../figures/nvila_demo_video.mp4"
|
| 66 |
+
)
|
| 67 |
+
parser.add_argument("--image_path", type=str, default="../figures/vila-logo.jpg")
|
| 68 |
+
parser.add_argument("--max_seq_len", type=int, default=8192)
|
| 69 |
+
args = parser.parse_args()
|
| 70 |
+
|
| 71 |
+
torch.nn.init.kaiming_uniform_ = skip
|
| 72 |
+
torch.nn.init.kaiming_normal_ = skip
|
| 73 |
+
torch.nn.init.uniform_ = skip
|
| 74 |
+
torch.nn.init.normal_ = skip
|
| 75 |
+
import tinychat.utils.constants
|
| 76 |
+
|
| 77 |
+
tinychat.utils.constants.max_seq_len = args.max_seq_len
|
| 78 |
+
from transformers import modeling_utils
|
| 79 |
+
|
| 80 |
+
modeling_utils._init_weights = False
|
| 81 |
+
|
| 82 |
+
# Load model
|
| 83 |
+
from tinychat.models.nvila_qwen2 import NVILAQwen2
|
| 84 |
+
|
| 85 |
+
config = AutoConfig.from_pretrained(args.model_path)
|
| 86 |
+
config.resume_path = args.model_path
|
| 87 |
+
model = NVILAQwen2(config).half()
|
| 88 |
+
model.llm = model.llm.eval()
|
| 89 |
+
if args.quant_llm or args.all:
|
| 90 |
+
from tinychat.modules import (
|
| 91 |
+
make_quant_norm,
|
| 92 |
+
make_quant_attn,
|
| 93 |
+
make_fused_mlp,
|
| 94 |
+
make_fused_vision_attn,
|
| 95 |
+
)
|
| 96 |
+
|
| 97 |
+
real_quantize_model_weight(
|
| 98 |
+
model.llm,
|
| 99 |
+
w_bit=4,
|
| 100 |
+
q_config=dict(q_group_size=128, zero_point=True),
|
| 101 |
+
init_only=True,
|
| 102 |
+
)
|
| 103 |
+
make_quant_attn(model.llm, "cuda", True)
|
| 104 |
+
make_quant_norm(model.llm)
|
| 105 |
+
make_fused_mlp(model.llm)
|
| 106 |
+
model = model.to("cuda")
|
| 107 |
+
model = model.to(args.device)
|
| 108 |
+
if args.quant_VT or args.all:
|
| 109 |
+
from tinychat.modules import QuantSiglipEncoder
|
| 110 |
+
|
| 111 |
+
model.vision_tower.vision_tower.vision_model.encoder = QuantSiglipEncoder(
|
| 112 |
+
model.vision_tower.vision_tower.vision_model.encoder
|
| 113 |
+
)
|
| 114 |
+
model = model.cuda().eval()
|
| 115 |
+
|
| 116 |
+
if args.video_caption or args.all or args.all_task:
|
| 117 |
+
print("-" * 80)
|
| 118 |
+
print("Video_Caption")
|
| 119 |
+
# Set conversation mode
|
| 120 |
+
clib.default_conversation = clib.conv_templates[args.conv_mode].copy()
|
| 121 |
+
media = Video(args.video_path)
|
| 122 |
+
text = "Elaborate on the visual and narrative elements of the video in detail." # + "1"+" 1"*3069
|
| 123 |
+
prompt = [media, text]
|
| 124 |
+
# Generate response
|
| 125 |
+
with torch.no_grad():
|
| 126 |
+
response = model.benchmark(prompt, args.quant_llm)
|
| 127 |
+
if args.video_QA or args.all or args.all_task:
|
| 128 |
+
print("-" * 80)
|
| 129 |
+
print("Video_QA")
|
| 130 |
+
# Set conversation mode
|
| 131 |
+
clib.default_conversation = clib.conv_templates[args.conv_mode].copy()
|
| 132 |
+
media = Video(args.video_path)
|
| 133 |
+
text = "What is the person in the video doing? Select the option that best describes their action: A. Folding paper B. Playing computer games C. Sleeping." # + "1"+" 1"*3069
|
| 134 |
+
prompt = [media, text]
|
| 135 |
+
# Generate response
|
| 136 |
+
with torch.no_grad():
|
| 137 |
+
response = model.benchmark(prompt, args.quant_llm)
|
| 138 |
+
if args.image_caption or args.all or args.all_task:
|
| 139 |
+
print("-" * 80)
|
| 140 |
+
print("Image_Caption")
|
| 141 |
+
# Set conversation mode
|
| 142 |
+
clib.default_conversation = clib.conv_templates[args.conv_mode].copy()
|
| 143 |
+
media = Image(args.image_path)
|
| 144 |
+
text = "Describe the image in detail."
|
| 145 |
+
prompt = [media, text]
|
| 146 |
+
# Generate response
|
| 147 |
+
with torch.no_grad():
|
| 148 |
+
response = model.benchmark(prompt, args.quant_llm)
|
| 149 |
+
if args.image_QA or args.all or args.all_task:
|
| 150 |
+
print("-" * 80)
|
| 151 |
+
print("Image_QA")
|
| 152 |
+
# Set conversation mode
|
| 153 |
+
clib.default_conversation = clib.conv_templates[args.conv_mode].copy()
|
| 154 |
+
media = Image(args.image_path)
|
| 155 |
+
text = "What does the text in the image say? Choose the option that best matches: A. VILA B. AIIV C. ALIV."
|
| 156 |
+
prompt = [media, text]
|
| 157 |
+
# Generate response
|
| 158 |
+
with torch.no_grad():
|
| 159 |
+
response = model.benchmark(prompt, args.quant_llm)
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
if __name__ == "__main__":
|
| 163 |
+
main()
|
llm-awq/tinychat/nvila_demo.py
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
|
| 3 |
+
from termcolor import colored
|
| 4 |
+
from huggingface_hub import hf_hub_download
|
| 5 |
+
import os
|
| 6 |
+
import llava
|
| 7 |
+
from llava import conversation as clib
|
| 8 |
+
from llava.media import Image, Video
|
| 9 |
+
import torch
|
| 10 |
+
from awq.quantize import fake_quant
|
| 11 |
+
from transformers import AutoConfig
|
| 12 |
+
from tinychat.utils.load_quant import load_awq_model
|
| 13 |
+
from tinychat.utils.llava_image_processing import (
|
| 14 |
+
load_images,
|
| 15 |
+
vis_images,
|
| 16 |
+
)
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def skip(*args, **kwargs):
|
| 20 |
+
pass
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
from tinychat.utils.tune import (
|
| 24 |
+
device_warmup,
|
| 25 |
+
tune_all_wqlinears,
|
| 26 |
+
tune_llava_patch_embedding,
|
| 27 |
+
)
|
| 28 |
+
from tinychat.utils.prompt_templates import (
|
| 29 |
+
get_prompter,
|
| 30 |
+
get_stop_token_ids,
|
| 31 |
+
get_image_token,
|
| 32 |
+
)
|
| 33 |
+
from llava.utils.media import extract_media
|
| 34 |
+
import tinychat.utils.constants
|
| 35 |
+
from tinychat.stream_generators.NVILA_stream_gen import NVILAStreamGenerator
|
| 36 |
+
from tinychat.utils.conversation_utils import gen_params, stream_output, TimeStats
|
| 37 |
+
|
| 38 |
+
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
|
| 39 |
+
|
| 40 |
+
def download_model_file(
|
| 41 |
+
repo_id: str = "Efficient-Large-Model/NVILA-AWQ",
|
| 42 |
+
filename: str = None,
|
| 43 |
+
local_dir: str = "./hf_cache",
|
| 44 |
+
force_download: bool = False,
|
| 45 |
+
) -> str:
|
| 46 |
+
os.makedirs(local_dir, exist_ok=True)
|
| 47 |
+
local_path = os.path.join(local_dir, filename)
|
| 48 |
+
if force_download or not os.path.exists(local_path):
|
| 49 |
+
print(f"Downloading {filename} from {repo_id}...")
|
| 50 |
+
hf_hub_download(
|
| 51 |
+
repo_id=repo_id,
|
| 52 |
+
filename=filename,
|
| 53 |
+
local_dir=local_dir,
|
| 54 |
+
local_dir_use_symlinks=False,
|
| 55 |
+
resume_download=True,
|
| 56 |
+
force_download=force_download,
|
| 57 |
+
)
|
| 58 |
+
print(f"File saved to: {local_path}")
|
| 59 |
+
|
| 60 |
+
return local_path
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def main(args):
|
| 65 |
+
# Accelerate model initialization
|
| 66 |
+
setattr(torch.nn.Linear, "reset_parameters", lambda self: None)
|
| 67 |
+
setattr(torch.nn.LayerNorm, "reset_parameters", lambda self: None)
|
| 68 |
+
torch.nn.init.kaiming_uniform_ = skip
|
| 69 |
+
torch.nn.init.kaiming_normal_ = skip
|
| 70 |
+
torch.nn.init.uniform_ = skip
|
| 71 |
+
torch.nn.init.normal_ = skip
|
| 72 |
+
tinychat.utils.constants.max_seq_len = args.max_seq_len
|
| 73 |
+
|
| 74 |
+
# Prepare model
|
| 75 |
+
from tinychat.models.nvila_qwen2 import NVILAQwen2
|
| 76 |
+
from transformers import AutoConfig
|
| 77 |
+
from tinychat.models.qwen2 import Qwen2ForCausalLM
|
| 78 |
+
|
| 79 |
+
config = AutoConfig.from_pretrained(args.model_path)
|
| 80 |
+
config.resume_path = args.model_path
|
| 81 |
+
if args.quant_llm or args.all:
|
| 82 |
+
model = NVILAQwen2(config, False).half()
|
| 83 |
+
else:
|
| 84 |
+
model = NVILAQwen2(config, True).half()
|
| 85 |
+
|
| 86 |
+
if args.smooth_VT or args.all:
|
| 87 |
+
from awq.quantize import smooth_lm
|
| 88 |
+
args.act_scale_path=download_model_file(filename=args.act_scale_path)
|
| 89 |
+
act_scales = torch.load(args.act_scale_path)
|
| 90 |
+
smooth_lm(model.vision_tower, act_scales, 0.3)
|
| 91 |
+
if args.quant_llm or args.all:
|
| 92 |
+
from tinychat.modules import (
|
| 93 |
+
make_quant_norm,
|
| 94 |
+
make_quant_attn,
|
| 95 |
+
make_fused_mlp,
|
| 96 |
+
make_fused_vision_attn,
|
| 97 |
+
)
|
| 98 |
+
args.quant_path=download_model_file(filename=args.quant_path)
|
| 99 |
+
model.llm = Qwen2ForCausalLM(model.llm_cfg).half()
|
| 100 |
+
model.llm = load_awq_model(model.llm, args.quant_path, 4, 128, args.device)
|
| 101 |
+
make_quant_attn(model.llm, args.device, True)
|
| 102 |
+
make_quant_norm(model.llm)
|
| 103 |
+
model.llm.cpu()
|
| 104 |
+
model.llm.resize_token_embeddings(len(model.tokenizer))
|
| 105 |
+
|
| 106 |
+
if args.quant_VT or args.all:
|
| 107 |
+
from tinychat.modules import QuantSiglipEncoder
|
| 108 |
+
|
| 109 |
+
if args.fakequant_VT:
|
| 110 |
+
fake_quant(model.vision_tower.vision_tower.vision_model.encoder)
|
| 111 |
+
else:
|
| 112 |
+
model.vision_tower.vision_tower.vision_model.encoder = QuantSiglipEncoder(
|
| 113 |
+
model.vision_tower.vision_tower.vision_model.encoder
|
| 114 |
+
)
|
| 115 |
+
model = model.cuda().eval()
|
| 116 |
+
device_warmup(args.device)
|
| 117 |
+
tune_llava_patch_embedding(model.vision_tower, device=args.device)
|
| 118 |
+
|
| 119 |
+
# Pre-prepare media
|
| 120 |
+
prompt = []
|
| 121 |
+
media_files = []
|
| 122 |
+
if args.media is not None:
|
| 123 |
+
for media in args.media or []:
|
| 124 |
+
if any(media.endswith(ext) for ext in [".jpg", ".jpeg", ".png"]):
|
| 125 |
+
media = Image(media)
|
| 126 |
+
media_files.append(media)
|
| 127 |
+
media_prompt = "<image>"
|
| 128 |
+
elif any(media.endswith(ext) for ext in [".mp4", ".mkv", ".webm"]):
|
| 129 |
+
media = Video(media)
|
| 130 |
+
media_files.append(media)
|
| 131 |
+
media_prompt = "<vila/video>"
|
| 132 |
+
else:
|
| 133 |
+
raise ValueError(f"Unsupported media type: {media}")
|
| 134 |
+
prompt.append(media)
|
| 135 |
+
media_num = len(media_files)
|
| 136 |
+
if args.vis_image:
|
| 137 |
+
print("=" * 50)
|
| 138 |
+
print("Input Image:")
|
| 139 |
+
vis_images(args.media)
|
| 140 |
+
conversation = [{"from": "human", "value": prompt}]
|
| 141 |
+
media, media_cfg = model.prepare_media(conversation)
|
| 142 |
+
# Prepare streaming
|
| 143 |
+
stream_generator = NVILAStreamGenerator
|
| 144 |
+
# Prepare prompt
|
| 145 |
+
if args.max_seq_len <= 1024:
|
| 146 |
+
short_prompt = True
|
| 147 |
+
else:
|
| 148 |
+
short_prompt = False
|
| 149 |
+
model_prompter = get_prompter(
|
| 150 |
+
args.model_type, args.model_path, short_prompt, args.empty_prompt
|
| 151 |
+
)
|
| 152 |
+
stop_token_ids = get_stop_token_ids(args.model_type, args.model_path)
|
| 153 |
+
count = 0
|
| 154 |
+
|
| 155 |
+
if args.empty_prompt:
|
| 156 |
+
input_indicator = "Input: "
|
| 157 |
+
output_indicator = "Generated: "
|
| 158 |
+
else:
|
| 159 |
+
input_indicator = "USER: "
|
| 160 |
+
output_indicator = "ASSISTANT: "
|
| 161 |
+
|
| 162 |
+
count = 0
|
| 163 |
+
model.eval()
|
| 164 |
+
time_stats = TimeStats()
|
| 165 |
+
start_pos = 0
|
| 166 |
+
while True:
|
| 167 |
+
# Get input from the user
|
| 168 |
+
print("=" * 50)
|
| 169 |
+
input_prompt = input(input_indicator)
|
| 170 |
+
print("-" * 50)
|
| 171 |
+
if input_prompt == "":
|
| 172 |
+
print("EXIT...")
|
| 173 |
+
time_stats.show()
|
| 174 |
+
break
|
| 175 |
+
if count == 0: # Insert media here
|
| 176 |
+
if args.media is not None:
|
| 177 |
+
if media_prompt in input_prompt:
|
| 178 |
+
input_prompt = input_prompt
|
| 179 |
+
else:
|
| 180 |
+
input_prompt = media_prompt * media_num + input_prompt
|
| 181 |
+
model_prompter.insert_prompt(input_prompt)
|
| 182 |
+
else:
|
| 183 |
+
model_prompter.insert_prompt(input_prompt)
|
| 184 |
+
if args.chunk_prefilling:
|
| 185 |
+
media = None
|
| 186 |
+
media_cfg = None
|
| 187 |
+
output_stream = stream_generator(
|
| 188 |
+
model,
|
| 189 |
+
gen_params,
|
| 190 |
+
model_prompter.model_input,
|
| 191 |
+
media,
|
| 192 |
+
media_cfg,
|
| 193 |
+
start_pos,
|
| 194 |
+
device=args.device,
|
| 195 |
+
stop_token_ids=stop_token_ids,
|
| 196 |
+
chunk_prefilling=args.chunk_prefilling,
|
| 197 |
+
quant_llm=args.quant_llm or args.all,
|
| 198 |
+
)
|
| 199 |
+
print(output_indicator, end="", flush=True)
|
| 200 |
+
if count == 0:
|
| 201 |
+
outputs, total_tokens = stream_output(output_stream, time_stats)
|
| 202 |
+
else:
|
| 203 |
+
outputs, total_tokens = stream_output(output_stream)
|
| 204 |
+
if args.chunk_prefilling:
|
| 205 |
+
start_pos += total_tokens
|
| 206 |
+
if (
|
| 207 |
+
args.single_round is not True and args.max_seq_len > 512
|
| 208 |
+
): # Only memorize previous conversations when kv_cache_size > 512
|
| 209 |
+
model_prompter.update_template(outputs, args.chunk_prefilling)
|
| 210 |
+
count += 1
|
| 211 |
+
|
| 212 |
+
|
| 213 |
+
if __name__ == "__main__":
|
| 214 |
+
parser = argparse.ArgumentParser()
|
| 215 |
+
parser.add_argument(
|
| 216 |
+
"--model_type", type=str, default="LLaMa", help="type of the model"
|
| 217 |
+
)
|
| 218 |
+
parser.add_argument(
|
| 219 |
+
"--model-path", type=str, default="/data/llm/checkpoints/llava/llava-v1.5-7b"
|
| 220 |
+
)
|
| 221 |
+
parser.add_argument(
|
| 222 |
+
"--quant_path",
|
| 223 |
+
type=str,
|
| 224 |
+
default="/data/llm/checkpoints/llava/llava-v1.5-7b-w4-g128-awq.pt",
|
| 225 |
+
)
|
| 226 |
+
parser.add_argument(
|
| 227 |
+
"--act_scale_path",
|
| 228 |
+
type=str,
|
| 229 |
+
default="/PATH/TO/SCALE",
|
| 230 |
+
)
|
| 231 |
+
parser.add_argument(
|
| 232 |
+
"--media", type=str, nargs="+", help="Multi-modal input (Video or image path)"
|
| 233 |
+
)
|
| 234 |
+
parser.add_argument("--device", type=str, default="cuda:0")
|
| 235 |
+
parser.add_argument("--max_seq_len", type=int, default=2048)
|
| 236 |
+
parser.add_argument(
|
| 237 |
+
"--single_round",
|
| 238 |
+
action="store_true",
|
| 239 |
+
help="whether to memorize previous conversations",
|
| 240 |
+
)
|
| 241 |
+
parser.add_argument(
|
| 242 |
+
"--vis-image",
|
| 243 |
+
action="store_true",
|
| 244 |
+
help="whether to visualize the image while chatting",
|
| 245 |
+
)
|
| 246 |
+
parser.add_argument(
|
| 247 |
+
"--empty-prompt",
|
| 248 |
+
action="store_true",
|
| 249 |
+
help="whether to use empty prompt template",
|
| 250 |
+
)
|
| 251 |
+
parser.add_argument(
|
| 252 |
+
"--flash_attn",
|
| 253 |
+
action="store_true",
|
| 254 |
+
help="whether to use flash attention",
|
| 255 |
+
)
|
| 256 |
+
parser.add_argument(
|
| 257 |
+
"--chunk_prefilling",
|
| 258 |
+
action="store_true",
|
| 259 |
+
help="If used, in context stage, the history tokens will not be recalculated, greatly speeding up the calculation",
|
| 260 |
+
)
|
| 261 |
+
# smooth and quantization options
|
| 262 |
+
parser.add_argument("--quant_llm", action="store_true")
|
| 263 |
+
parser.add_argument("--quant_VT", action="store_true")
|
| 264 |
+
parser.add_argument("--smooth_VT", action="store_true")
|
| 265 |
+
parser.add_argument("--all", action="store_true")
|
| 266 |
+
parser.add_argument(
|
| 267 |
+
"--fakequant_VT",
|
| 268 |
+
action="store_true",
|
| 269 |
+
help="Use fake quant or real quant for VisionTower",
|
| 270 |
+
)
|
| 271 |
+
args = parser.parse_args()
|
| 272 |
+
main(args)
|
llm-awq/tinychat/offline-weight-repacker.py
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import torch
|
| 3 |
+
import numpy as np
|
| 4 |
+
from typing import List
|
| 5 |
+
from collections import OrderedDict
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def qweight_unpack(qweight):
|
| 9 |
+
assert qweight.dtype == torch.int32
|
| 10 |
+
n = qweight.shape[0]
|
| 11 |
+
k = qweight.shape[1] * 8
|
| 12 |
+
unpacked_qweight = torch.zeros((n, k), dtype=torch.int32, device=qweight.device)
|
| 13 |
+
mask = 0x0000000F
|
| 14 |
+
for kk in range(k):
|
| 15 |
+
ele_offset = kk // 8
|
| 16 |
+
bit_offset = (kk % 8) * 4
|
| 17 |
+
unpacked_qweight[:, kk] = (qweight[:, ele_offset] >> bit_offset) & mask
|
| 18 |
+
|
| 19 |
+
return unpacked_qweight
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def packing_v2_from_unpacked(unpacked_qweight, interleave, kstride):
|
| 23 |
+
# unpacked_qweight: [N, K]
|
| 24 |
+
N = unpacked_qweight.shape[0]
|
| 25 |
+
K = unpacked_qweight.shape[1]
|
| 26 |
+
|
| 27 |
+
Packed_Kernel = unpacked_qweight.cpu().numpy().reshape(N, K // 32, 32)
|
| 28 |
+
# np.arange(32).reshape(4, 4, 2).transpose(1, 0, 2) => [0, 1, 8, 9, 16, 17, 24, 25, ...]
|
| 29 |
+
Packed_Kernel = Packed_Kernel.reshape(N, K // 32, 4, 4, 2).transpose(0, 1, 3, 2, 4)
|
| 30 |
+
Packed_Kernel = Packed_Kernel.reshape(N, K // 32, 32)
|
| 31 |
+
|
| 32 |
+
# reorder each 8 weights for fast dequantization
|
| 33 |
+
# [0, 1, 2, 3, 4, 5, 6, 7] => [0, 2, 4, 6, 1, 3, 5, 7]
|
| 34 |
+
Packed_Kernel = Packed_Kernel.reshape(N, K // 32, 4, 8)
|
| 35 |
+
Packed_Kernel = Packed_Kernel.reshape(N, K // 32, 4, 4, 2).transpose(0, 1, 2, 4, 3)
|
| 36 |
+
Packed_Kernel = Packed_Kernel.reshape(N, K)
|
| 37 |
+
|
| 38 |
+
# interleaving every four rows
|
| 39 |
+
Packed_Kernel = Packed_Kernel.reshape(
|
| 40 |
+
N // interleave, interleave, K // kstride, kstride
|
| 41 |
+
)
|
| 42 |
+
# N // 4, K // 64, 4, 64
|
| 43 |
+
Packed_Kernel = Packed_Kernel.transpose(0, 2, 1, 3)
|
| 44 |
+
Packed_Kernel = Packed_Kernel.reshape(
|
| 45 |
+
N // interleave, K // kstride, kstride, interleave
|
| 46 |
+
)
|
| 47 |
+
# Packing -> (N // 4, K // 64, 64)
|
| 48 |
+
Packed_Kernel = (
|
| 49 |
+
Packed_Kernel[..., 0]
|
| 50 |
+
| (Packed_Kernel[..., 1] << 4)
|
| 51 |
+
| (Packed_Kernel[..., 2] << 8)
|
| 52 |
+
| (Packed_Kernel[..., 3] << 12)
|
| 53 |
+
)
|
| 54 |
+
# reshape to (N // 4, K), FP16 format
|
| 55 |
+
Packed_Kernel = Packed_Kernel.reshape(N // interleave, K)
|
| 56 |
+
qweight_v2 = (
|
| 57 |
+
torch.tensor(Packed_Kernel.astype("int16"))
|
| 58 |
+
.to(unpacked_qweight.device)
|
| 59 |
+
.contiguous()
|
| 60 |
+
)
|
| 61 |
+
return qweight_v2
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def multiply_scale_qzero_negative(scales, qzeros, zp_shift=-8):
|
| 65 |
+
pack_size = 8
|
| 66 |
+
k_groups = scales.shape[1]
|
| 67 |
+
scaled_zeros = torch.zeros_like(scales)
|
| 68 |
+
for group_idx in range(k_groups):
|
| 69 |
+
zero_idx = group_idx // pack_size
|
| 70 |
+
zero_offset = group_idx % pack_size
|
| 71 |
+
zero = qzeros[:, zero_idx] >> (4 * zero_offset) & 0x0000000F
|
| 72 |
+
scaled_zeros[:, group_idx] = scales[:, group_idx] * zero.to(scales.dtype)
|
| 73 |
+
return -(scaled_zeros + (zp_shift * scales))
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def qweight_pack_v1_to_v2(qweight, interleave, kstride):
|
| 77 |
+
unpacked_qweight = qweight_unpack(qweight)
|
| 78 |
+
qweight_v2 = packing_v2_from_unpacked(unpacked_qweight, interleave, kstride)
|
| 79 |
+
return qweight_v2
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def ckpt_check():
|
| 83 |
+
parser = argparse.ArgumentParser()
|
| 84 |
+
parser.add_argument("--input1", type=str, default="./vicuna-7b-w4-g128-awq-v2-1.pt")
|
| 85 |
+
parser.add_argument("--input2", type=str, default="./vicuna-7b-w4-g128-awq-v2-2.pt")
|
| 86 |
+
args = parser.parse_args()
|
| 87 |
+
|
| 88 |
+
model_dict1 = torch.load(args.input1)
|
| 89 |
+
model_dict2 = torch.load(args.input2)
|
| 90 |
+
|
| 91 |
+
keys = model_dict1.keys()
|
| 92 |
+
for key in keys:
|
| 93 |
+
param = model_dict1[key]
|
| 94 |
+
assert type(param) == torch.Tensor
|
| 95 |
+
if (
|
| 96 |
+
"qweight" in key
|
| 97 |
+
or "scales" in key
|
| 98 |
+
or "qzeros" in key
|
| 99 |
+
or "scaled_zeros" in key
|
| 100 |
+
):
|
| 101 |
+
print("=" * 50)
|
| 102 |
+
print(key)
|
| 103 |
+
# print(model_dict1[key])
|
| 104 |
+
# print(model_dict2[key])
|
| 105 |
+
diff = torch.max(torch.abs(model_dict2[key] - model_dict1[key]))
|
| 106 |
+
print(diff)
|
| 107 |
+
assert diff < 1e-6
|
| 108 |
+
print("=" * 50)
|
| 109 |
+
|
| 110 |
+
|
| 111 |
+
def offline_repacker():
|
| 112 |
+
parser = argparse.ArgumentParser()
|
| 113 |
+
parser.add_argument("--input", type=str, default="./vicuna-7b-w4-g128-awq.pt")
|
| 114 |
+
parser.add_argument("--output", type=str, default="./vicuna-7b-w4-g128-awq-v2.pt")
|
| 115 |
+
args = parser.parse_args()
|
| 116 |
+
|
| 117 |
+
model_dict = torch.load(args.input)
|
| 118 |
+
model_dict_v2 = OrderedDict()
|
| 119 |
+
|
| 120 |
+
keys = model_dict.keys()
|
| 121 |
+
for key in keys:
|
| 122 |
+
param = model_dict[key]
|
| 123 |
+
assert type(param) == torch.Tensor
|
| 124 |
+
if "qweight" in key:
|
| 125 |
+
print("repacking:", key)
|
| 126 |
+
qweight = param
|
| 127 |
+
qweight_v2 = qweight_pack_v1_to_v2(qweight, interleave=4, kstride=64)
|
| 128 |
+
model_dict_v2[key] = qweight_v2
|
| 129 |
+
elif "scales" in key:
|
| 130 |
+
print("repacking:", key)
|
| 131 |
+
scales = param
|
| 132 |
+
# print(scales.shape)
|
| 133 |
+
scales_v2 = scales.transpose(1, 0).contiguous()
|
| 134 |
+
model_dict_v2[key] = scales_v2
|
| 135 |
+
|
| 136 |
+
# deal with corresponding zero points
|
| 137 |
+
zeros_key = key.replace("scales", "qzeros")
|
| 138 |
+
print("repacking:", zeros_key)
|
| 139 |
+
|
| 140 |
+
zeros_key_v2 = key.replace("scales", "scaled_zeros")
|
| 141 |
+
qzeros = model_dict[zeros_key]
|
| 142 |
+
scaled_zeros_v2 = multiply_scale_qzero_negative(scales, qzeros, zp_shift=0)
|
| 143 |
+
# K // G, N
|
| 144 |
+
scaled_zeros_v2 = scaled_zeros_v2.transpose(1, 0).contiguous()
|
| 145 |
+
model_dict_v2[zeros_key_v2] = scaled_zeros_v2
|
| 146 |
+
elif "qzeros" in key:
|
| 147 |
+
pass
|
| 148 |
+
else:
|
| 149 |
+
print("copying:", key)
|
| 150 |
+
model_dict_v2[key] = param
|
| 151 |
+
|
| 152 |
+
torch.save(model_dict_v2, args.output)
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
if __name__ == "__main__":
|
| 156 |
+
offline_repacker()
|
| 157 |
+
# ckpt_check()
|
llm-awq/tinychat/scripts/llama2_demo.sh
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MODEL_PATH=/data/llm/checkpoints/llama2-hf
|
| 2 |
+
MODEL_NAME=llama-2-7b-chat
|
| 3 |
+
|
| 4 |
+
# # Perform AWQ search and save search results (we already did it for you):
|
| 5 |
+
# mkdir -p awq_cache
|
| 6 |
+
# python -m awq.entry --model_path $MODEL_PATH/$MODEL_NAME \
|
| 7 |
+
# --w_bit 4 --q_group_size 128 \
|
| 8 |
+
# --run_awq --dump_awq awq_cache/llama-2-7b-chat-w4-g128.pt
|
| 9 |
+
|
| 10 |
+
# Generate real quantized weights (INT4):
|
| 11 |
+
mkdir -p quant_cache
|
| 12 |
+
python -m awq.entry --model_path $MODEL_PATH/$MODEL_NAME \
|
| 13 |
+
--w_bit 4 --q_group_size 128 \
|
| 14 |
+
--load_awq awq_cache/llama-2-7b-chat-w4-g128.pt \
|
| 15 |
+
--q_backend real --dump_quant quant_cache/llama-2-7b-chat-w4-g128-awq.pt
|
| 16 |
+
|
| 17 |
+
# Run the TinyChat demo:
|
| 18 |
+
python demo.py --model_type llama \
|
| 19 |
+
--model_path $MODEL_PATH/$MODEL_NAME \
|
| 20 |
+
--q_group_size 128 --load_quant quant_cache/llama-2-7b-chat-w4-g128-awq.pt \
|
| 21 |
+
--precision W4A16
|
| 22 |
+
|
| 23 |
+
# Split checkpoint into shards for mem-efficient loading:
|
| 24 |
+
python split_ckpt.py --input_path quant_cache/llama-2-7b-chat-w4-g128-awq.pt \
|
| 25 |
+
--output_path quant_cache/llama-2-7b-chat-w4-g128-awq
|
| 26 |
+
|
| 27 |
+
# Run the TinyChat demo in mem_efficient_load mode:
|
| 28 |
+
python demo.py --model_type llama \
|
| 29 |
+
--model_path $MODEL_PATH/$MODEL_NAME \
|
| 30 |
+
--q_group_size 128 --load_quant quant_cache/llama-2-7b-chat-w4-g128-awq \
|
| 31 |
+
--precision W4A16 --mem_efficient_load --flash --chunk_prefilling
|
llm-awq/tinychat/split_ckpt.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import re
|
| 3 |
+
import torch
|
| 4 |
+
import argparse
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def split(
|
| 8 |
+
ckpt_path: str,
|
| 9 |
+
out_folder_path: str,
|
| 10 |
+
):
|
| 11 |
+
os.system(f"mkdir -p {out_folder_path}")
|
| 12 |
+
ckpt = torch.load(ckpt_path)
|
| 13 |
+
count = 0
|
| 14 |
+
for key, value in ckpt.items():
|
| 15 |
+
output_dict = {key: value}
|
| 16 |
+
output_name = out_folder_path + "/" + key + ".pt"
|
| 17 |
+
torch.save(output_dict, output_name)
|
| 18 |
+
count += 1
|
| 19 |
+
print(f"Finished splitting the original checkpoint into {count} shards.")
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def ckpt_folder_reader(ckpt_folder_path: str):
|
| 23 |
+
file_list = [f for f in os.listdir(ckpt_folder_path) if f.endswith(".pt")]
|
| 24 |
+
for ckpt in file_list:
|
| 25 |
+
print(ckpt)
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
if __name__ == "__main__":
|
| 29 |
+
parser = argparse.ArgumentParser()
|
| 30 |
+
parser.add_argument(
|
| 31 |
+
"--input_path",
|
| 32 |
+
type=str,
|
| 33 |
+
default=None,
|
| 34 |
+
help="Path to the original checkpoint (ends with *.pt)",
|
| 35 |
+
)
|
| 36 |
+
parser.add_argument(
|
| 37 |
+
"--output_path",
|
| 38 |
+
type=str,
|
| 39 |
+
default=None,
|
| 40 |
+
help="Folder to store the splitted checkpoint shards",
|
| 41 |
+
)
|
| 42 |
+
|
| 43 |
+
args = parser.parse_args()
|
| 44 |
+
assert (
|
| 45 |
+
args.input_path is not None
|
| 46 |
+
), "Please specify the path to the original checkpoint."
|
| 47 |
+
if args.output_path is None:
|
| 48 |
+
suffix = r"\.pt$"
|
| 49 |
+
args.output_path = re.sub(suffix, "", args.input_path)
|
| 50 |
+
|
| 51 |
+
split(args.input_path, args.output_path)
|
llm-awq/tinychat/vila15_demo.py
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import torch
|
| 3 |
+
|
| 4 |
+
from PIL import Image
|
| 5 |
+
from tqdm import tqdm
|
| 6 |
+
|
| 7 |
+
from transformers import AutoConfig, AutoTokenizer
|
| 8 |
+
from accelerate import load_checkpoint_and_dispatch
|
| 9 |
+
|
| 10 |
+
from tinychat.utils.tune import (
|
| 11 |
+
device_warmup,
|
| 12 |
+
tune_all_wqlinears,
|
| 13 |
+
tune_llava_patch_embedding,
|
| 14 |
+
)
|
| 15 |
+
from tinychat.utils.prompt_templates import (
|
| 16 |
+
get_prompter,
|
| 17 |
+
get_stop_token_ids,
|
| 18 |
+
get_image_token,
|
| 19 |
+
)
|
| 20 |
+
from tinychat.utils.llava_image_processing import (
|
| 21 |
+
process_images,
|
| 22 |
+
load_images,
|
| 23 |
+
vis_images,
|
| 24 |
+
)
|
| 25 |
+
import tinychat.utils.constants
|
| 26 |
+
|
| 27 |
+
# from tinychat.models.llava_llama import LlavaLlamaForCausalLM
|
| 28 |
+
from tinychat.models.vila_llama import VilaLlamaForCausalLM
|
| 29 |
+
from tinychat.stream_generators.llava_stream_gen import LlavaStreamGenerator
|
| 30 |
+
from tinychat.utils.conversation_utils import gen_params, stream_output, TimeStats
|
| 31 |
+
|
| 32 |
+
import os
|
| 33 |
+
|
| 34 |
+
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def image_parser(args):
|
| 38 |
+
out = args.image_file.split(args.im_sep)
|
| 39 |
+
return out
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def skip(*args, **kwargs):
|
| 43 |
+
pass
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def main(args):
|
| 47 |
+
# Accelerate model initialization
|
| 48 |
+
setattr(torch.nn.Linear, "reset_parameters", lambda self: None)
|
| 49 |
+
setattr(torch.nn.LayerNorm, "reset_parameters", lambda self: None)
|
| 50 |
+
torch.nn.init.kaiming_uniform_ = skip
|
| 51 |
+
torch.nn.init.kaiming_normal_ = skip
|
| 52 |
+
torch.nn.init.uniform_ = skip
|
| 53 |
+
torch.nn.init.normal_ = skip
|
| 54 |
+
|
| 55 |
+
tokenizer = AutoTokenizer.from_pretrained(
|
| 56 |
+
os.path.join(args.model_path, "llm"), use_fast=False
|
| 57 |
+
)
|
| 58 |
+
tinychat.utils.constants.LLAVA_DEFAULT_IMAGE_PATCH_TOKEN_IDX = (
|
| 59 |
+
tokenizer.convert_tokens_to_ids(
|
| 60 |
+
[tinychat.utils.constants.LLAVA_DEFAULT_IMAGE_PATCH_TOKEN]
|
| 61 |
+
)[0]
|
| 62 |
+
)
|
| 63 |
+
config = AutoConfig.from_pretrained(args.model_path, trust_remote_code=True)
|
| 64 |
+
model = VilaLlamaForCausalLM(config).half()
|
| 65 |
+
tinychat.utils.constants.LLAVA_DEFAULT_IMAGE_PATCH_TOKEN_IDX = (
|
| 66 |
+
tokenizer.convert_tokens_to_ids(
|
| 67 |
+
[tinychat.utils.constants.LLAVA_DEFAULT_IMAGE_PATCH_TOKEN]
|
| 68 |
+
)[0]
|
| 69 |
+
)
|
| 70 |
+
vision_tower = model.get_vision_tower()
|
| 71 |
+
# if not vision_tower.is_loaded:
|
| 72 |
+
# vision_tower.load_model()
|
| 73 |
+
image_processor = vision_tower.image_processor
|
| 74 |
+
# vision_tower = vision_tower.half()
|
| 75 |
+
|
| 76 |
+
if args.precision == "W16A16":
|
| 77 |
+
pbar = tqdm(range(1))
|
| 78 |
+
pbar.set_description("Loading checkpoint shards")
|
| 79 |
+
for i in pbar:
|
| 80 |
+
model.llm = load_checkpoint_and_dispatch(
|
| 81 |
+
model.llm,
|
| 82 |
+
os.path.join(args.model_path, "llm"),
|
| 83 |
+
no_split_module_classes=[
|
| 84 |
+
"OPTDecoderLayer",
|
| 85 |
+
"LlamaDecoderLayer",
|
| 86 |
+
"BloomBlock",
|
| 87 |
+
"MPTBlock",
|
| 88 |
+
"DecoderLayer",
|
| 89 |
+
"CLIPEncoderLayer",
|
| 90 |
+
],
|
| 91 |
+
).to(args.device)
|
| 92 |
+
model = model.to(args.device)
|
| 93 |
+
|
| 94 |
+
elif args.precision == "W4A16":
|
| 95 |
+
from tinychat.utils.load_quant import load_awq_model
|
| 96 |
+
|
| 97 |
+
model.llm = load_awq_model(model.llm, args.quant_path, 4, 128, args.device)
|
| 98 |
+
from tinychat.modules import (
|
| 99 |
+
make_quant_norm,
|
| 100 |
+
make_quant_attn,
|
| 101 |
+
make_fused_mlp,
|
| 102 |
+
make_fused_vision_attn,
|
| 103 |
+
)
|
| 104 |
+
|
| 105 |
+
if args.flash_attn:
|
| 106 |
+
print("Enabling flash-attention!")
|
| 107 |
+
make_quant_attn(model.llm, args.device, 1)
|
| 108 |
+
else:
|
| 109 |
+
print("Disabling flash-attention!")
|
| 110 |
+
make_quant_attn(model.llm, args.device)
|
| 111 |
+
make_quant_norm(model.llm)
|
| 112 |
+
# make_fused_mlp(model)
|
| 113 |
+
# make_fused_vision_attn(model,args.device)
|
| 114 |
+
model = model.to(args.device)
|
| 115 |
+
|
| 116 |
+
else:
|
| 117 |
+
raise NotImplementedError(f"Precision {args.precision} is not supported.")
|
| 118 |
+
|
| 119 |
+
image_files = image_parser(args)
|
| 120 |
+
image_num = len(image_files)
|
| 121 |
+
images = load_images(image_files)
|
| 122 |
+
if args.vis_image:
|
| 123 |
+
print("=" * 50)
|
| 124 |
+
print("Input Image:")
|
| 125 |
+
vis_images(image_files)
|
| 126 |
+
# Similar operation in model_worker.py
|
| 127 |
+
image_tensor = process_images(images, image_processor, model.config)
|
| 128 |
+
if type(image_tensor) is list:
|
| 129 |
+
image_tensor = [
|
| 130 |
+
image.to(args.device, dtype=torch.float16) for image in image_tensor
|
| 131 |
+
]
|
| 132 |
+
else:
|
| 133 |
+
image_tensor = image_tensor.to(args.device, dtype=torch.float16)
|
| 134 |
+
|
| 135 |
+
device_warmup(args.device)
|
| 136 |
+
tune_llava_patch_embedding(vision_tower, device=args.device)
|
| 137 |
+
|
| 138 |
+
stream_generator = LlavaStreamGenerator
|
| 139 |
+
|
| 140 |
+
if args.max_seq_len <= 1024:
|
| 141 |
+
short_prompt = True
|
| 142 |
+
else:
|
| 143 |
+
short_prompt = False
|
| 144 |
+
model_prompter = get_prompter(
|
| 145 |
+
args.model_type, args.model_path, short_prompt, args.empty_prompt
|
| 146 |
+
)
|
| 147 |
+
stop_token_ids = get_stop_token_ids(args.model_type, args.model_path)
|
| 148 |
+
count = 0
|
| 149 |
+
|
| 150 |
+
if args.empty_prompt:
|
| 151 |
+
input_indicator = "Input: "
|
| 152 |
+
output_indicator = "Generated: "
|
| 153 |
+
else:
|
| 154 |
+
input_indicator = "USER: "
|
| 155 |
+
output_indicator = "ASSISTANT: "
|
| 156 |
+
|
| 157 |
+
model.eval()
|
| 158 |
+
time_stats = TimeStats()
|
| 159 |
+
start_pos = 0
|
| 160 |
+
while True:
|
| 161 |
+
# Get input from the user
|
| 162 |
+
print("=" * 50)
|
| 163 |
+
input_prompt = input(input_indicator)
|
| 164 |
+
print("-" * 50)
|
| 165 |
+
if input_prompt == "":
|
| 166 |
+
print("EXIT...")
|
| 167 |
+
time_stats.show()
|
| 168 |
+
break
|
| 169 |
+
if count == 0: # Insert image here
|
| 170 |
+
image_token = get_image_token(model, args.model_path)
|
| 171 |
+
image_token_holder = (
|
| 172 |
+
tinychat.utils.constants.LLAVA_DEFAULT_IM_TOKEN_PLACE_HOLDER
|
| 173 |
+
)
|
| 174 |
+
im_token_count = input_prompt.count(image_token_holder)
|
| 175 |
+
if im_token_count == 0:
|
| 176 |
+
model_prompter.insert_prompt(image_token * image_num + input_prompt)
|
| 177 |
+
else:
|
| 178 |
+
assert im_token_count == image_num
|
| 179 |
+
input_prompt = input_prompt.replace(image_token_holder, image_token)
|
| 180 |
+
model_prompter.insert_prompt(input_prompt)
|
| 181 |
+
else:
|
| 182 |
+
model_prompter.insert_prompt(input_prompt)
|
| 183 |
+
if args.chunk_prefilling:
|
| 184 |
+
image_tensor = None # Can insert more images in future
|
| 185 |
+
output_stream = stream_generator(
|
| 186 |
+
model,
|
| 187 |
+
tokenizer,
|
| 188 |
+
model_prompter.model_input,
|
| 189 |
+
start_pos,
|
| 190 |
+
gen_params,
|
| 191 |
+
device=args.device,
|
| 192 |
+
stop_token_ids=stop_token_ids,
|
| 193 |
+
image_tensor=image_tensor,
|
| 194 |
+
chunk_prefilling=args.chunk_prefilling,
|
| 195 |
+
)
|
| 196 |
+
print(output_indicator, end="", flush=True)
|
| 197 |
+
if count == 0:
|
| 198 |
+
outputs, total_tokens = stream_output(output_stream, time_stats)
|
| 199 |
+
else:
|
| 200 |
+
outputs, total_tokens = stream_output(output_stream)
|
| 201 |
+
if args.chunk_prefilling:
|
| 202 |
+
start_pos += total_tokens
|
| 203 |
+
if (
|
| 204 |
+
args.single_round is not True and args.max_seq_len > 512
|
| 205 |
+
): # Only memorize previous conversations when kv_cache_size > 512
|
| 206 |
+
model_prompter.update_template(outputs, args.chunk_prefilling)
|
| 207 |
+
count += 1
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
if __name__ == "__main__":
|
| 211 |
+
parser = argparse.ArgumentParser()
|
| 212 |
+
parser.add_argument(
|
| 213 |
+
"--model_type", type=str, default="LLaMa", help="type of the model"
|
| 214 |
+
)
|
| 215 |
+
parser.add_argument(
|
| 216 |
+
"--model-path", type=str, default="/data/llm/checkpoints/llava/llava-v1.5-7b"
|
| 217 |
+
)
|
| 218 |
+
parser.add_argument(
|
| 219 |
+
"--quant-path",
|
| 220 |
+
type=str,
|
| 221 |
+
default="/data/llm/checkpoints/llava/llava-v1.5-7b-w4-g128-awq.pt",
|
| 222 |
+
)
|
| 223 |
+
parser.add_argument(
|
| 224 |
+
"--precision", type=str, default="W4A16", help="compute precision"
|
| 225 |
+
)
|
| 226 |
+
parser.add_argument(
|
| 227 |
+
"--image-file",
|
| 228 |
+
type=str,
|
| 229 |
+
default="https://llava.hliu.cc/file=/nobackup/haotian/code/LLaVA/llava/serve/examples/extreme_ironing.jpg",
|
| 230 |
+
)
|
| 231 |
+
parser.add_argument(
|
| 232 |
+
"--im-sep",
|
| 233 |
+
type=str,
|
| 234 |
+
default=",",
|
| 235 |
+
)
|
| 236 |
+
parser.add_argument("--device", type=str, default="cuda")
|
| 237 |
+
parser.add_argument("--max_seq_len", type=int, default=2048)
|
| 238 |
+
parser.add_argument(
|
| 239 |
+
"--single_round",
|
| 240 |
+
action="store_true",
|
| 241 |
+
help="whether to memorize previous conversations",
|
| 242 |
+
)
|
| 243 |
+
parser.add_argument(
|
| 244 |
+
"--vis-image",
|
| 245 |
+
action="store_true",
|
| 246 |
+
help="whether to visualize the image while chatting",
|
| 247 |
+
)
|
| 248 |
+
parser.add_argument(
|
| 249 |
+
"--empty-prompt",
|
| 250 |
+
action="store_true",
|
| 251 |
+
help="whether to use empty prompt template",
|
| 252 |
+
)
|
| 253 |
+
parser.add_argument(
|
| 254 |
+
"--flash_attn",
|
| 255 |
+
action="store_true",
|
| 256 |
+
help="whether to use flash attention",
|
| 257 |
+
)
|
| 258 |
+
parser.add_argument(
|
| 259 |
+
"--chunk_prefilling",
|
| 260 |
+
action="store_true",
|
| 261 |
+
help="If used, in context stage, the history tokens will not be recalculated, greatly speeding up the calculation",
|
| 262 |
+
)
|
| 263 |
+
args = parser.parse_args()
|
| 264 |
+
main(args)
|