Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- DeepSeek-VL2/deepseek_vl2.egg-info/PKG-INFO +461 -0
- DeepSeek-VL2/deepseek_vl2.egg-info/SOURCES.txt +26 -0
- DeepSeek-VL2/deepseek_vl2.egg-info/dependency_links.txt +1 -0
- EAGLE/.gitignore +43 -0
- EAGLE/LICENSE +201 -0
- EAGLE/gradio_demo.py +334 -0
- EAGLE/predict_demo.py +78 -0
- EAGLE/setup.py +24 -0
- EAGLE/train.py +1201 -0
- Groma/README.md +268 -0
- VLM2Vec/evaluation/eval_utils.py +26 -0
- VLM2Vec/grad_cache/cachex/training.py +30 -0
- VLM2Vec/grad_cache/cachex/tree_utils.py +17 -0
- VLM2Vec/src/vlm_backbone/phi3_v/configuration_phi3_v.py +217 -0
- VLM2Vec/src/vlm_backbone/phi3_v/image_processing_phi3_v.py +286 -0
- VLM2Vec/src/vlm_backbone/phi3_v/modeling_phi3_v.py +1633 -0
- VLMEvalKit/LICENSE +203 -0
- a_distributed_notebook/temp/ddp_tutorial.py +169 -0
- a_distributed_notebook/temp/run.py +162 -0
- a_distributed_notebook/temp/run_5.py +41 -0
- groundingLMM/app.py +296 -0
- lightning-hydra-template/.github/PULL_REQUEST_TEMPLATE.md +22 -0
- lightning-hydra-template/.github/dependabot.yml +16 -0
- lightning-hydra-template/.github/workflows/code-quality-pr.yaml +36 -0
- lightning-hydra-template/configs/callbacks/default.yaml +22 -0
- lightning-hydra-template/configs/callbacks/early_stopping.yaml +15 -0
- lightning-hydra-template/configs/callbacks/model_checkpoint.yaml +17 -0
- lightning-hydra-template/configs/callbacks/model_summary.yaml +5 -0
- lightning-hydra-template/configs/callbacks/none.yaml +0 -0
- lightning-hydra-template/configs/callbacks/rich_progress_bar.yaml +4 -0
- lightning-hydra-template/configs/debug/default.yaml +35 -0
- lightning-hydra-template/configs/debug/fdr.yaml +9 -0
- lightning-hydra-template/configs/debug/limit.yaml +12 -0
- lightning-hydra-template/configs/debug/overfit.yaml +13 -0
- lightning-hydra-template/configs/debug/profiler.yaml +12 -0
- lightning-hydra-template/configs/experiment/example.yaml +41 -0
- lightning-hydra-template/configs/extras/default.yaml +8 -0
- lightning-hydra-template/configs/hydra/default.yaml +19 -0
- lightning-hydra-template/configs/logger/csv.yaml +7 -0
- lightning-hydra-template/configs/logger/many_loggers.yaml +9 -0
- lightning-hydra-template/configs/logger/tensorboard.yaml +10 -0
- lightning-hydra-template/configs/logger/wandb.yaml +16 -0
- lightning-hydra-template/configs/model/mnist.yaml +25 -0
- lightning-hydra-template/configs/paths/default.yaml +18 -0
- lightning-hydra-template/configs/trainer/cpu.yaml +5 -0
- lightning-hydra-template/configs/trainer/ddp.yaml +9 -0
- lightning-hydra-template/configs/trainer/ddp_sim.yaml +7 -0
- lightning-hydra-template/configs/trainer/default.yaml +19 -0
- lightning-hydra-template/configs/trainer/gpu.yaml +5 -0
- lightning-hydra-template/configs/trainer/mps.yaml +5 -0
DeepSeek-VL2/deepseek_vl2.egg-info/PKG-INFO
ADDED
|
@@ -0,0 +1,461 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.1
|
| 2 |
+
Name: deepseek_vl2
|
| 3 |
+
Version: 1.0.0
|
| 4 |
+
Summary: DeepSeek-VL2
|
| 5 |
+
Author: DeepSeek-AI
|
| 6 |
+
License: MIT License
|
| 7 |
+
|
| 8 |
+
Copyright (c) 2023 DeepSeek
|
| 9 |
+
|
| 10 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 11 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 12 |
+
in the Software without restriction, including without limitation the rights
|
| 13 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 14 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 15 |
+
furnished to do so, subject to the following conditions:
|
| 16 |
+
|
| 17 |
+
The above copyright notice and this permission notice shall be included in all
|
| 18 |
+
copies or substantial portions of the Software.
|
| 19 |
+
|
| 20 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 21 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 22 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 23 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 24 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 25 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 26 |
+
SOFTWARE.
|
| 27 |
+
|
| 28 |
+
Project-URL: homepage, https://github.com/deepseek-ai/DeepSeek-VL2
|
| 29 |
+
Requires-Python: >=3.8
|
| 30 |
+
Description-Content-Type: text/markdown
|
| 31 |
+
License-File: LICENSE-CODE
|
| 32 |
+
License-File: LICENSE-MODEL
|
| 33 |
+
Requires-Dist: torch>=2.0.1
|
| 34 |
+
Requires-Dist: transformers>=4.38.2
|
| 35 |
+
Requires-Dist: timm>=0.9.16
|
| 36 |
+
Requires-Dist: accelerate
|
| 37 |
+
Requires-Dist: sentencepiece
|
| 38 |
+
Requires-Dist: attrdict
|
| 39 |
+
Requires-Dist: einops
|
| 40 |
+
Provides-Extra: gradio
|
| 41 |
+
Requires-Dist: gradio==3.48.0; extra == "gradio"
|
| 42 |
+
Requires-Dist: gradio-client==0.6.1; extra == "gradio"
|
| 43 |
+
Requires-Dist: mdtex2html==1.3.0; extra == "gradio"
|
| 44 |
+
Requires-Dist: pypinyin==0.50.0; extra == "gradio"
|
| 45 |
+
Requires-Dist: tiktoken==0.5.2; extra == "gradio"
|
| 46 |
+
Requires-Dist: tqdm==4.64.0; extra == "gradio"
|
| 47 |
+
Requires-Dist: colorama==0.4.5; extra == "gradio"
|
| 48 |
+
Requires-Dist: Pygments==2.12.0; extra == "gradio"
|
| 49 |
+
Requires-Dist: markdown==3.4.1; extra == "gradio"
|
| 50 |
+
Requires-Dist: SentencePiece==0.1.96; extra == "gradio"
|
| 51 |
+
Provides-Extra: lint
|
| 52 |
+
Requires-Dist: isort; extra == "lint"
|
| 53 |
+
Requires-Dist: black[jupyter]>=22.6.0; extra == "lint"
|
| 54 |
+
Requires-Dist: pylint[spelling]>=2.15.0; extra == "lint"
|
| 55 |
+
Requires-Dist: flake8; extra == "lint"
|
| 56 |
+
Requires-Dist: flake8-bugbear; extra == "lint"
|
| 57 |
+
Requires-Dist: flake8-comprehensions; extra == "lint"
|
| 58 |
+
Requires-Dist: flake8-docstrings; extra == "lint"
|
| 59 |
+
Requires-Dist: flake8-pyi; extra == "lint"
|
| 60 |
+
Requires-Dist: flake8-simplify; extra == "lint"
|
| 61 |
+
Requires-Dist: ruff; extra == "lint"
|
| 62 |
+
Requires-Dist: pyenchant; extra == "lint"
|
| 63 |
+
Requires-Dist: pre-commit; extra == "lint"
|
| 64 |
+
|
| 65 |
+
<!-- markdownlint-disable first-line-h1 -->
|
| 66 |
+
<!-- markdownlint-disable html -->
|
| 67 |
+
<!-- markdownlint-disable no-duplicate-header -->
|
| 68 |
+
|
| 69 |
+
<div align="center">
|
| 70 |
+
<img src="images/logo.svg" width="60%" alt="DeepSeek LLM" />
|
| 71 |
+
</div>
|
| 72 |
+
<hr>
|
| 73 |
+
<div align="center">
|
| 74 |
+
|
| 75 |
+
<a href="https://www.deepseek.com/" target="_blank">
|
| 76 |
+
<img alt="Homepage" src="images/badge.svg" />
|
| 77 |
+
</a>
|
| 78 |
+
<a href="" target="_blank">
|
| 79 |
+
<img alt="Chat" src="https://img.shields.io/badge/🤖%20Chat-DeepSeek%20VL-536af5?color=536af5&logoColor=white" />
|
| 80 |
+
</a>
|
| 81 |
+
<a href="https://huggingface.co/deepseek-ai" target="_blank">
|
| 82 |
+
<img alt="Hugging Face" src="https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-DeepSeek%20AI-ffc107?color=ffc107&logoColor=white" />
|
| 83 |
+
</a>
|
| 84 |
+
|
| 85 |
+
</div>
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
<div align="center">
|
| 89 |
+
|
| 90 |
+
<a href="https://discord.gg/Tc7c45Zzu5" target="_blank">
|
| 91 |
+
<img alt="Discord" src="https://img.shields.io/badge/Discord-DeepSeek%20AI-7289da?logo=discord&logoColor=white&color=7289da" />
|
| 92 |
+
</a>
|
| 93 |
+
<a href="images/qr.jpeg" target="_blank">
|
| 94 |
+
<img alt="Wechat" src="https://img.shields.io/badge/WeChat-DeepSeek%20AI-brightgreen?logo=wechat&logoColor=white" />
|
| 95 |
+
</a>
|
| 96 |
+
<a href="https://twitter.com/deepseek_ai" target="_blank">
|
| 97 |
+
<img alt="Twitter Follow" src="https://img.shields.io/badge/Twitter-deepseek_ai-white?logo=x&logoColor=white" />
|
| 98 |
+
</a>
|
| 99 |
+
|
| 100 |
+
</div>
|
| 101 |
+
|
| 102 |
+
<div align="center">
|
| 103 |
+
|
| 104 |
+
<a href="LICENSE-CODE">
|
| 105 |
+
<img alt="Code License" src="https://img.shields.io/badge/Code_License-MIT-f5de53?&color=f5de53">
|
| 106 |
+
</a>
|
| 107 |
+
<a href="LICENSE-MODEL">
|
| 108 |
+
<img alt="Model License" src="https://img.shields.io/badge/Model_License-Model_Agreement-f5de53?&color=f5de53">
|
| 109 |
+
</a>
|
| 110 |
+
</div>
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
<p align="center">
|
| 114 |
+
<a href="https://github.com/deepseek-ai/DeepSeek-VL2/tree/main?tab=readme-ov-file#3-model-download"><b>📥 Model Download</b></a> |
|
| 115 |
+
<a href="https://github.com/deepseek-ai/DeepSeek-VL2/tree/main?tab=readme-ov-file#4-quick-start"><b>⚡ Quick Start</b></a> |
|
| 116 |
+
<a href="https://github.com/deepseek-ai/DeepSeek-VL2/tree/main?tab=readme-ov-file#5-license"><b>📜 License</b></a> |
|
| 117 |
+
<a href="https://github.com/deepseek-ai/DeepSeek-VL2/tree/main?tab=readme-ov-file#6-citation"><b>📖 Citation</b></a> <br>
|
| 118 |
+
<a href="./DeepSeek_VL2_paper.pdf"><b>📄 Paper Link</b></a> |
|
| 119 |
+
<a href="https://arxiv.org/abs/2412.10302"><b>📄 Arxiv Paper Link</b></a> |
|
| 120 |
+
<a href=""><b>👁️ Demo</b></a>
|
| 121 |
+
</p>
|
| 122 |
+
|
| 123 |
+
## 1. Introduction
|
| 124 |
+
|
| 125 |
+
Introducing DeepSeek-VL2, an advanced series of large Mixture-of-Experts (MoE) Vision-Language Models that significantly improves upon its predecessor, DeepSeek-VL. DeepSeek-VL2 demonstrates superior capabilities across various tasks, including but not limited to visual question answering, optical character recognition, document/table/chart understanding, and visual grounding. Our model series is composed of three variants: DeepSeek-VL2-Tiny, DeepSeek-VL2-Small and DeepSeek-VL2, with 1.0B, 2.8B and 4.5B activated parameters respectively.
|
| 126 |
+
DeepSeek-VL2 achieves competitive or state-of-the-art performance with similar or fewer activated parameters compared to existing open-source dense and MoE-based models.
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
[DeepSeek-VL2: Mixture-of-Experts Vision-Language Models for Advanced Multimodal Understanding]()
|
| 130 |
+
|
| 131 |
+
Zhiyu Wu*, Xiaokang Chen*, Zizheng Pan*, Xingchao Liu*, Wen Liu**, Damai Dai, Huazuo Gao, Yiyang Ma, Chengyue Wu, Bingxuan Wang, Zhenda Xie, Yu Wu, Kai Hu, Jiawei Wang, Yaofeng Sun, Yukun Li, Yishi Piao, Kang Guan, Aixin Liu, Xin Xie, Yuxiang You, Kai Dong, Xingkai Yu, Haowei Zhang, Liang Zhao, Yisong Wang, Chong Ruan*** (* Equal Contribution, ** Project Lead, *** Corresponding author)
|
| 132 |
+
|
| 133 |
+

|
| 134 |
+
|
| 135 |
+
## 2. Release
|
| 136 |
+
✅ <b>2024-12-25</b>: Gradio Demo Example, Incremental Prefilling and VLMEvalKit Support.
|
| 137 |
+
|
| 138 |
+
✅ <b>2024-12-13</b>: DeepSeek-VL2 family released, including <code>DeepSeek-VL2-tiny</code>, <code>DeepSeek-VL2-small</code>, <code>DeepSeek-VL2</code>.
|
| 139 |
+
|
| 140 |
+
## 3. Model Download
|
| 141 |
+
|
| 142 |
+
We release the DeepSeek-VL2 family, including <code>DeepSeek-VL2-tiny</code>, <code>DeepSeek-VL2-small</code>, <code>DeepSeek-VL2</code>.
|
| 143 |
+
To support a broader and more diverse range of research within both academic and commercial communities.
|
| 144 |
+
Please note that the use of this model is subject to the terms outlined in [License section](#5-license).
|
| 145 |
+
|
| 146 |
+
### Huggingface
|
| 147 |
+
|
| 148 |
+
| Model | Sequence Length | Download |
|
| 149 |
+
|--------------|-----------------|-----------------------------------------------------------------------------|
|
| 150 |
+
| DeepSeek-VL2-tiny | 4096 | [🤗 Hugging Face](https://huggingface.co/deepseek-ai/deepseek-vl2-tiny) |
|
| 151 |
+
| DeepSeek-VL2-small | 4096 | [🤗 Hugging Face](https://huggingface.co/deepseek-ai/deepseek-vl2-small) |
|
| 152 |
+
| DeepSeek-VL2 | 4096 | [🤗 Hugging Face](https://huggingface.co/deepseek-ai/deepseek-vl2) |
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
## 4. Quick Start
|
| 156 |
+
|
| 157 |
+
### Installation
|
| 158 |
+
|
| 159 |
+
On the basis of `Python >= 3.8` environment, install the necessary dependencies by running the following command:
|
| 160 |
+
|
| 161 |
+
```shell
|
| 162 |
+
pip install -e .
|
| 163 |
+
```
|
| 164 |
+
|
| 165 |
+
### Simple Inference Example with One Image
|
| 166 |
+
|
| 167 |
+
**Note: You may need 80GB GPU memory to run this script with deepseek-vl2-small and even larger for deepseek-vl2.**
|
| 168 |
+
|
| 169 |
+
```python
|
| 170 |
+
import torch
|
| 171 |
+
from transformers import AutoModelForCausalLM
|
| 172 |
+
|
| 173 |
+
from deepseek_vl2.models import DeepseekVLV2Processor, DeepseekVLV2ForCausalLM
|
| 174 |
+
from deepseek_vl2.utils.io import load_pil_images
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
# specify the path to the model
|
| 178 |
+
model_path = "deepseek-ai/deepseek-vl2-tiny"
|
| 179 |
+
vl_chat_processor: DeepseekVLV2Processor = DeepseekVLV2Processor.from_pretrained(model_path)
|
| 180 |
+
tokenizer = vl_chat_processor.tokenizer
|
| 181 |
+
|
| 182 |
+
vl_gpt: DeepseekVLV2ForCausalLM = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True)
|
| 183 |
+
vl_gpt = vl_gpt.to(torch.bfloat16).cuda().eval()
|
| 184 |
+
|
| 185 |
+
## single image conversation example
|
| 186 |
+
conversation = [
|
| 187 |
+
{
|
| 188 |
+
"role": "<|User|>",
|
| 189 |
+
"content": "<image>\n<|ref|>The giraffe at the back.<|/ref|>.",
|
| 190 |
+
"images": ["./images/visual_grounding_1.jpeg"],
|
| 191 |
+
},
|
| 192 |
+
{"role": "<|Assistant|>", "content": ""},
|
| 193 |
+
]
|
| 194 |
+
|
| 195 |
+
# load images and prepare for inputs
|
| 196 |
+
pil_images = load_pil_images(conversation)
|
| 197 |
+
prepare_inputs = vl_chat_processor(
|
| 198 |
+
conversations=conversation,
|
| 199 |
+
images=pil_images,
|
| 200 |
+
force_batchify=True,
|
| 201 |
+
system_prompt=""
|
| 202 |
+
).to(vl_gpt.device)
|
| 203 |
+
|
| 204 |
+
# run image encoder to get the image embeddings
|
| 205 |
+
inputs_embeds = vl_gpt.prepare_inputs_embeds(**prepare_inputs)
|
| 206 |
+
|
| 207 |
+
# run the model to get the response
|
| 208 |
+
outputs = vl_gpt.language.generate(
|
| 209 |
+
inputs_embeds=inputs_embeds,
|
| 210 |
+
attention_mask=prepare_inputs.attention_mask,
|
| 211 |
+
pad_token_id=tokenizer.eos_token_id,
|
| 212 |
+
bos_token_id=tokenizer.bos_token_id,
|
| 213 |
+
eos_token_id=tokenizer.eos_token_id,
|
| 214 |
+
max_new_tokens=512,
|
| 215 |
+
do_sample=False,
|
| 216 |
+
use_cache=True
|
| 217 |
+
)
|
| 218 |
+
|
| 219 |
+
answer = tokenizer.decode(outputs[0].cpu().tolist(), skip_special_tokens=False)
|
| 220 |
+
print(f"{prepare_inputs['sft_format'][0]}", answer)
|
| 221 |
+
```
|
| 222 |
+
|
| 223 |
+
And the output is something like:
|
| 224 |
+
```
|
| 225 |
+
<|User|>: <image>
|
| 226 |
+
<|ref|>The giraffe at the back.<|/ref|>.
|
| 227 |
+
|
| 228 |
+
<|Assistant|>: <|ref|>The giraffe at the back.<|/ref|><|det|>[[580, 270, 999, 900]]<|/det|><|end▁of▁sentence|>
|
| 229 |
+
```
|
| 230 |
+
|
| 231 |
+
### Simple Inference Example with Multiple Images
|
| 232 |
+
|
| 233 |
+
**Note: You may need 80GB GPU memory to run this script with deepseek-vl2-small and even larger for deepseek-vl2.**
|
| 234 |
+
|
| 235 |
+
```python
|
| 236 |
+
import torch
|
| 237 |
+
from transformers import AutoModelForCausalLM
|
| 238 |
+
|
| 239 |
+
from deepseek_vl2.models import DeepseekVLV2Processor, DeepseekVLV2ForCausalLM
|
| 240 |
+
from deepseek_vl2.utils.io import load_pil_images
|
| 241 |
+
|
| 242 |
+
|
| 243 |
+
# specify the path to the model
|
| 244 |
+
model_path = "deepseek-ai/deepseek-vl2-tiny"
|
| 245 |
+
vl_chat_processor: DeepseekVLV2Processor = DeepseekVLV2Processor.from_pretrained(model_path)
|
| 246 |
+
tokenizer = vl_chat_processor.tokenizer
|
| 247 |
+
|
| 248 |
+
vl_gpt: DeepseekVLV2ForCausalLM = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True)
|
| 249 |
+
vl_gpt = vl_gpt.to(torch.bfloat16).cuda().eval()
|
| 250 |
+
|
| 251 |
+
# multiple images/interleaved image-text
|
| 252 |
+
conversation = [
|
| 253 |
+
{
|
| 254 |
+
"role": "<|User|>",
|
| 255 |
+
"content": "This is image_1: <image>\n"
|
| 256 |
+
"This is image_2: <image>\n"
|
| 257 |
+
"This is image_3: <image>\n Can you tell me what are in the images?",
|
| 258 |
+
"images": [
|
| 259 |
+
"images/multi_image_1.jpeg",
|
| 260 |
+
"images/multi_image_2.jpeg",
|
| 261 |
+
"images/multi_image_3.jpeg",
|
| 262 |
+
],
|
| 263 |
+
},
|
| 264 |
+
{"role": "<|Assistant|>", "content": ""}
|
| 265 |
+
]
|
| 266 |
+
|
| 267 |
+
# load images and prepare for inputs
|
| 268 |
+
pil_images = load_pil_images(conversation)
|
| 269 |
+
prepare_inputs = vl_chat_processor(
|
| 270 |
+
conversations=conversation,
|
| 271 |
+
images=pil_images,
|
| 272 |
+
force_batchify=True,
|
| 273 |
+
system_prompt=""
|
| 274 |
+
).to(vl_gpt.device)
|
| 275 |
+
|
| 276 |
+
# run image encoder to get the image embeddings
|
| 277 |
+
inputs_embeds = vl_gpt.prepare_inputs_embeds(**prepare_inputs)
|
| 278 |
+
|
| 279 |
+
# run the model to get the response
|
| 280 |
+
outputs = vl_gpt.language.generate(
|
| 281 |
+
inputs_embeds=inputs_embeds,
|
| 282 |
+
attention_mask=prepare_inputs.attention_mask,
|
| 283 |
+
pad_token_id=tokenizer.eos_token_id,
|
| 284 |
+
bos_token_id=tokenizer.bos_token_id,
|
| 285 |
+
eos_token_id=tokenizer.eos_token_id,
|
| 286 |
+
max_new_tokens=512,
|
| 287 |
+
do_sample=False,
|
| 288 |
+
use_cache=True
|
| 289 |
+
)
|
| 290 |
+
|
| 291 |
+
answer = tokenizer.decode(outputs[0].cpu().tolist(), skip_special_tokens=False)
|
| 292 |
+
print(f"{prepare_inputs['sft_format'][0]}", answer)
|
| 293 |
+
```
|
| 294 |
+
|
| 295 |
+
And the output is something like:
|
| 296 |
+
```
|
| 297 |
+
<|User|>: This is image_1: <image>
|
| 298 |
+
This is image_2: <image>
|
| 299 |
+
This is image_3: <image>
|
| 300 |
+
Can you tell me what are in the images?
|
| 301 |
+
|
| 302 |
+
<|Assistant|>: The images show three different types of vegetables. Image_1 features carrots, which are orange with green tops. Image_2 displays corn cobs, which are yellow with green husks. Image_3 contains raw pork ribs, which are pinkish-red with some marbling.<|end▁of▁sentence|>
|
| 303 |
+
```
|
| 304 |
+
|
| 305 |
+
### Simple Inference Example with Incremental Prefilling
|
| 306 |
+
|
| 307 |
+
**Note: We use incremental prefilling to inference within 40GB GPU using deepseek-vl2-small.**
|
| 308 |
+
|
| 309 |
+
```python
|
| 310 |
+
import torch
|
| 311 |
+
from transformers import AutoModelForCausalLM
|
| 312 |
+
|
| 313 |
+
from deepseek_vl2.models import DeepseekVLV2Processor, DeepseekVLV2ForCausalLM
|
| 314 |
+
from deepseek_vl2.utils.io import load_pil_images
|
| 315 |
+
|
| 316 |
+
|
| 317 |
+
# specify the path to the model
|
| 318 |
+
model_path = "deepseek-ai/deepseek-vl2-small"
|
| 319 |
+
vl_chat_processor: DeepseekVLV2Processor = DeepseekVLV2Processor.from_pretrained(model_path)
|
| 320 |
+
tokenizer = vl_chat_processor.tokenizer
|
| 321 |
+
|
| 322 |
+
vl_gpt: DeepseekVLV2ForCausalLM = AutoModelForCausalLM.from_pretrained(model_path, trust_remote_code=True)
|
| 323 |
+
vl_gpt = vl_gpt.to(torch.bfloat16).cuda().eval()
|
| 324 |
+
|
| 325 |
+
# multiple images/interleaved image-text
|
| 326 |
+
conversation = [
|
| 327 |
+
{
|
| 328 |
+
"role": "<|User|>",
|
| 329 |
+
"content": "This is image_1: <image>\n"
|
| 330 |
+
"This is image_2: <image>\n"
|
| 331 |
+
"This is image_3: <image>\n Can you tell me what are in the images?",
|
| 332 |
+
"images": [
|
| 333 |
+
"images/multi_image_1.jpeg",
|
| 334 |
+
"images/multi_image_2.jpeg",
|
| 335 |
+
"images/multi_image_3.jpeg",
|
| 336 |
+
],
|
| 337 |
+
},
|
| 338 |
+
{"role": "<|Assistant|>", "content": ""}
|
| 339 |
+
]
|
| 340 |
+
|
| 341 |
+
# load images and prepare for inputs
|
| 342 |
+
pil_images = load_pil_images(conversation)
|
| 343 |
+
prepare_inputs = vl_chat_processor(
|
| 344 |
+
conversations=conversation,
|
| 345 |
+
images=pil_images,
|
| 346 |
+
force_batchify=True,
|
| 347 |
+
system_prompt=""
|
| 348 |
+
).to(vl_gpt.device)
|
| 349 |
+
|
| 350 |
+
with torch.no_grad():
|
| 351 |
+
# run image encoder to get the image embeddings
|
| 352 |
+
inputs_embeds = vl_gpt.prepare_inputs_embeds(**prepare_inputs)
|
| 353 |
+
|
| 354 |
+
# incremental_prefilling when using 40G GPU for vl2-small
|
| 355 |
+
inputs_embeds, past_key_values = vl_gpt.incremental_prefilling(
|
| 356 |
+
input_ids=prepare_inputs.input_ids,
|
| 357 |
+
images=prepare_inputs.images,
|
| 358 |
+
images_seq_mask=prepare_inputs.images_seq_mask,
|
| 359 |
+
images_spatial_crop=prepare_inputs.images_spatial_crop,
|
| 360 |
+
attention_mask=prepare_inputs.attention_mask,
|
| 361 |
+
chunk_size=512 # prefilling size
|
| 362 |
+
)
|
| 363 |
+
|
| 364 |
+
# run the model to get the response
|
| 365 |
+
outputs = vl_gpt.generate(
|
| 366 |
+
inputs_embeds=inputs_embeds,
|
| 367 |
+
input_ids=prepare_inputs.input_ids,
|
| 368 |
+
images=prepare_inputs.images,
|
| 369 |
+
images_seq_mask=prepare_inputs.images_seq_mask,
|
| 370 |
+
images_spatial_crop=prepare_inputs.images_spatial_crop,
|
| 371 |
+
attention_mask=prepare_inputs.attention_mask,
|
| 372 |
+
past_key_values=past_key_values,
|
| 373 |
+
|
| 374 |
+
pad_token_id=tokenizer.eos_token_id,
|
| 375 |
+
bos_token_id=tokenizer.bos_token_id,
|
| 376 |
+
eos_token_id=tokenizer.eos_token_id,
|
| 377 |
+
max_new_tokens=512,
|
| 378 |
+
|
| 379 |
+
do_sample=False,
|
| 380 |
+
use_cache=True,
|
| 381 |
+
)
|
| 382 |
+
|
| 383 |
+
answer = tokenizer.decode(outputs[0][len(prepare_inputs.input_ids[0]):].cpu().tolist(), skip_special_tokens=False)
|
| 384 |
+
|
| 385 |
+
print(f"{prepare_inputs['sft_format'][0]}", answer)
|
| 386 |
+
```
|
| 387 |
+
|
| 388 |
+
And the output is something like:
|
| 389 |
+
```
|
| 390 |
+
<|User|>: This is image_1: <image>
|
| 391 |
+
This is image_2: <image>
|
| 392 |
+
This is image_3: <image>
|
| 393 |
+
Can you tell me what are in the images?
|
| 394 |
+
|
| 395 |
+
<|Assistant|>: The first image contains carrots. The second image contains corn. The third image contains meat.<|end▁of▁sentence|>
|
| 396 |
+
```
|
| 397 |
+
|
| 398 |
+
### Full Inference Example
|
| 399 |
+
```shell
|
| 400 |
+
# without incremental prefilling
|
| 401 |
+
CUDA_VISIBLE_DEVICES=0 python inference.py --model_patn "deepseek-ai/deepseek-vl2"
|
| 402 |
+
|
| 403 |
+
# with incremental prefilling, when using 40G GPU for vl2-small
|
| 404 |
+
CUDA_VISIBLE_DEVICES=0 python inference.py --model_patn "deepseek-ai/deepseek-vl2-small" --chunck_size 512
|
| 405 |
+
|
| 406 |
+
```
|
| 407 |
+
|
| 408 |
+
|
| 409 |
+
### Gradio Demo
|
| 410 |
+
|
| 411 |
+
* Install the necessary dependencies:
|
| 412 |
+
```shell
|
| 413 |
+
pip install -e .[gradio]
|
| 414 |
+
```
|
| 415 |
+
|
| 416 |
+
* then run the following command:
|
| 417 |
+
|
| 418 |
+
```shell
|
| 419 |
+
# vl2-tiny, 3.37B-MoE in total, activated 1B, can be run on a single GPU < 40GB
|
| 420 |
+
CUDA_VISIBLE_DEVICES=2 python web_demo.py \
|
| 421 |
+
--model_name "deepseek-ai/deepseek-vl2-tiny" \
|
| 422 |
+
--port 37914
|
| 423 |
+
|
| 424 |
+
|
| 425 |
+
# vl2-small, 16.1B-MoE in total, activated 2.4B
|
| 426 |
+
# If run on A100 40GB GPU, you need to set the `--chunk_size 512` for incremental prefilling for saving memory and it might be slow.
|
| 427 |
+
# If run on > 40GB GPU, you can ignore the `--chunk_size 512` for faster response.
|
| 428 |
+
CUDA_VISIBLE_DEVICES=2 python web_demo.py \
|
| 429 |
+
--model_name "deepseek-ai/deepseek-vl2-small" \
|
| 430 |
+
--port 37914 \
|
| 431 |
+
--chunk_size 512
|
| 432 |
+
|
| 433 |
+
# # vl27.5-MoE in total, activated 4.2B
|
| 434 |
+
CUDA_VISIBLE_DEVICES=2 python web_demo.py \
|
| 435 |
+
--model_name "deepseek-ai/deepseek-vl2" \
|
| 436 |
+
--port 37914
|
| 437 |
+
```
|
| 438 |
+
|
| 439 |
+
* **Important**: This is a basic and native demo implementation without any deployment optimizations, which may result in slower performance. For production environments, consider using optimized deployment solutions, such as vllm, sglang, lmdeploy, etc. These optimizations will help achieve faster response times and better cost efficiency.
|
| 440 |
+
|
| 441 |
+
## 5. License
|
| 442 |
+
|
| 443 |
+
This code repository is licensed under [MIT License](./LICENSE-CODE). The use of DeepSeek-VL2 models is subject to [DeepSeek Model License](./LICENSE-MODEL). DeepSeek-VL2 series supports commercial use.
|
| 444 |
+
|
| 445 |
+
## 6. Citation
|
| 446 |
+
|
| 447 |
+
```
|
| 448 |
+
@misc{wu2024deepseekvl2mixtureofexpertsvisionlanguagemodels,
|
| 449 |
+
title={DeepSeek-VL2: Mixture-of-Experts Vision-Language Models for Advanced Multimodal Understanding},
|
| 450 |
+
author={Zhiyu Wu and Xiaokang Chen and Zizheng Pan and Xingchao Liu and Wen Liu and Damai Dai and Huazuo Gao and Yiyang Ma and Chengyue Wu and Bingxuan Wang and Zhenda Xie and Yu Wu and Kai Hu and Jiawei Wang and Yaofeng Sun and Yukun Li and Yishi Piao and Kang Guan and Aixin Liu and Xin Xie and Yuxiang You and Kai Dong and Xingkai Yu and Haowei Zhang and Liang Zhao and Yisong Wang and Chong Ruan},
|
| 451 |
+
year={2024},
|
| 452 |
+
eprint={2412.10302},
|
| 453 |
+
archivePrefix={arXiv},
|
| 454 |
+
primaryClass={cs.CV},
|
| 455 |
+
url={https://arxiv.org/abs/2412.10302},
|
| 456 |
+
}
|
| 457 |
+
```
|
| 458 |
+
|
| 459 |
+
## 7. Contact
|
| 460 |
+
|
| 461 |
+
If you have any questions, please raise an issue or contact us at [service@deepseek.com](mailto:service@deepseek.com).
|
DeepSeek-VL2/deepseek_vl2.egg-info/SOURCES.txt
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
LICENSE-CODE
|
| 2 |
+
LICENSE-MODEL
|
| 3 |
+
README.md
|
| 4 |
+
pyproject.toml
|
| 5 |
+
deepseek_vl2/__init__.py
|
| 6 |
+
deepseek_vl2.egg-info/PKG-INFO
|
| 7 |
+
deepseek_vl2.egg-info/SOURCES.txt
|
| 8 |
+
deepseek_vl2.egg-info/dependency_links.txt
|
| 9 |
+
deepseek_vl2.egg-info/requires.txt
|
| 10 |
+
deepseek_vl2.egg-info/top_level.txt
|
| 11 |
+
deepseek_vl2/models/__init__.py
|
| 12 |
+
deepseek_vl2/models/configuration_deepseek.py
|
| 13 |
+
deepseek_vl2/models/conversation.py
|
| 14 |
+
deepseek_vl2/models/modeling_deepseek.py
|
| 15 |
+
deepseek_vl2/models/modeling_deepseek_vl_v2.py
|
| 16 |
+
deepseek_vl2/models/processing_deepseek_vl_v2.py
|
| 17 |
+
deepseek_vl2/models/siglip_vit.py
|
| 18 |
+
deepseek_vl2/serve/__init__.py
|
| 19 |
+
deepseek_vl2/serve/inference.py
|
| 20 |
+
deepseek_vl2/serve/app_modules/__init__.py
|
| 21 |
+
deepseek_vl2/serve/app_modules/gradio_utils.py
|
| 22 |
+
deepseek_vl2/serve/app_modules/overwrites.py
|
| 23 |
+
deepseek_vl2/serve/app_modules/presets.py
|
| 24 |
+
deepseek_vl2/serve/app_modules/utils.py
|
| 25 |
+
deepseek_vl2/utils/__init__.py
|
| 26 |
+
deepseek_vl2/utils/io.py
|
DeepSeek-VL2/deepseek_vl2.egg-info/dependency_links.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
|
EAGLE/.gitignore
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Python
|
| 2 |
+
__pycache__
|
| 3 |
+
*.pyc
|
| 4 |
+
*.egg-info
|
| 5 |
+
dist
|
| 6 |
+
|
| 7 |
+
# Log
|
| 8 |
+
*.log
|
| 9 |
+
*.log.*
|
| 10 |
+
logs/
|
| 11 |
+
# *.json
|
| 12 |
+
*.jsonl
|
| 13 |
+
images/*
|
| 14 |
+
|
| 15 |
+
# Data
|
| 16 |
+
!**/alpaca-data-conversation.json
|
| 17 |
+
|
| 18 |
+
# Editor
|
| 19 |
+
.idea
|
| 20 |
+
*.swp
|
| 21 |
+
.github
|
| 22 |
+
.vscode
|
| 23 |
+
|
| 24 |
+
# Other
|
| 25 |
+
.DS_Store
|
| 26 |
+
wandb
|
| 27 |
+
output
|
| 28 |
+
examples/*
|
| 29 |
+
|
| 30 |
+
eagle/eval/table/*.json
|
| 31 |
+
eagle/eval/table/results/*.json
|
| 32 |
+
checkpoints
|
| 33 |
+
ckpts*
|
| 34 |
+
slurm_logs/*
|
| 35 |
+
|
| 36 |
+
datasets/*
|
| 37 |
+
playground/*
|
| 38 |
+
gradio_tmp/*
|
| 39 |
+
|
| 40 |
+
.ipynb_checkpoints
|
| 41 |
+
*.ipynb
|
| 42 |
+
|
| 43 |
+
unit_test*.*
|
EAGLE/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Apache License
|
| 2 |
+
Version 2.0, January 2004
|
| 3 |
+
http://www.apache.org/licenses/
|
| 4 |
+
|
| 5 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 6 |
+
|
| 7 |
+
1. Definitions.
|
| 8 |
+
|
| 9 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 10 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 11 |
+
|
| 12 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 13 |
+
the copyright owner that is granting the License.
|
| 14 |
+
|
| 15 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 16 |
+
other entities that control, are controlled by, or are under common
|
| 17 |
+
control with that entity. For the purposes of this definition,
|
| 18 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 19 |
+
direction or management of such entity, whether by contract or
|
| 20 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 21 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 22 |
+
|
| 23 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 24 |
+
exercising permissions granted by this License.
|
| 25 |
+
|
| 26 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 27 |
+
including but not limited to software source code, documentation
|
| 28 |
+
source, and configuration files.
|
| 29 |
+
|
| 30 |
+
"Object" form shall mean any form resulting from mechanical
|
| 31 |
+
transformation or translation of a Source form, including but
|
| 32 |
+
not limited to compiled object code, generated documentation,
|
| 33 |
+
and conversions to other media types.
|
| 34 |
+
|
| 35 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 36 |
+
Object form, made available under the License, as indicated by a
|
| 37 |
+
copyright notice that is included in or attached to the work
|
| 38 |
+
(an example is provided in the Appendix below).
|
| 39 |
+
|
| 40 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 41 |
+
form, that is based on (or derived from) the Work and for which the
|
| 42 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 43 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 44 |
+
of this License, Derivative Works shall not include works that remain
|
| 45 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 46 |
+
the Work and Derivative Works thereof.
|
| 47 |
+
|
| 48 |
+
"Contribution" shall mean any work of authorship, including
|
| 49 |
+
the original version of the Work and any modifications or additions
|
| 50 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 51 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 52 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 53 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 54 |
+
means any form of electronic, verbal, or written communication sent
|
| 55 |
+
to the Licensor or its representatives, including but not limited to
|
| 56 |
+
communication on electronic mailing lists, source code control systems,
|
| 57 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 58 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 59 |
+
excluding communication that is conspicuously marked or otherwise
|
| 60 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 61 |
+
|
| 62 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 63 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 64 |
+
subsequently incorporated within the Work.
|
| 65 |
+
|
| 66 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 67 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 68 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 69 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 70 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 71 |
+
Work and such Derivative Works in Source or Object form.
|
| 72 |
+
|
| 73 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 74 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 75 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 76 |
+
(except as stated in this section) patent license to make, have made,
|
| 77 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 78 |
+
where such license applies only to those patent claims licensable
|
| 79 |
+
by such Contributor that are necessarily infringed by their
|
| 80 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 81 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 82 |
+
institute patent litigation against any entity (including a
|
| 83 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 84 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 85 |
+
or contributory patent infringement, then any patent licenses
|
| 86 |
+
granted to You under this License for that Work shall terminate
|
| 87 |
+
as of the date such litigation is filed.
|
| 88 |
+
|
| 89 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 90 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 91 |
+
modifications, and in Source or Object form, provided that You
|
| 92 |
+
meet the following conditions:
|
| 93 |
+
|
| 94 |
+
(a) You must give any other recipients of the Work or
|
| 95 |
+
Derivative Works a copy of this License; and
|
| 96 |
+
|
| 97 |
+
(b) You must cause any modified files to carry prominent notices
|
| 98 |
+
stating that You changed the files; and
|
| 99 |
+
|
| 100 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 101 |
+
that You distribute, all copyright, patent, trademark, and
|
| 102 |
+
attribution notices from the Source form of the Work,
|
| 103 |
+
excluding those notices that do not pertain to any part of
|
| 104 |
+
the Derivative Works; and
|
| 105 |
+
|
| 106 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 107 |
+
distribution, then any Derivative Works that You distribute must
|
| 108 |
+
include a readable copy of the attribution notices contained
|
| 109 |
+
within such NOTICE file, excluding those notices that do not
|
| 110 |
+
pertain to any part of the Derivative Works, in at least one
|
| 111 |
+
of the following places: within a NOTICE text file distributed
|
| 112 |
+
as part of the Derivative Works; within the Source form or
|
| 113 |
+
documentation, if provided along with the Derivative Works; or,
|
| 114 |
+
within a display generated by the Derivative Works, if and
|
| 115 |
+
wherever such third-party notices normally appear. The contents
|
| 116 |
+
of the NOTICE file are for informational purposes only and
|
| 117 |
+
do not modify the License. You may add Your own attribution
|
| 118 |
+
notices within Derivative Works that You distribute, alongside
|
| 119 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 120 |
+
that such additional attribution notices cannot be construed
|
| 121 |
+
as modifying the License.
|
| 122 |
+
|
| 123 |
+
You may add Your own copyright statement to Your modifications and
|
| 124 |
+
may provide additional or different license terms and conditions
|
| 125 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 126 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 127 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 128 |
+
the conditions stated in this License.
|
| 129 |
+
|
| 130 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 131 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 132 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 133 |
+
this License, without any additional terms or conditions.
|
| 134 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 135 |
+
the terms of any separate license agreement you may have executed
|
| 136 |
+
with Licensor regarding such Contributions.
|
| 137 |
+
|
| 138 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 139 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 140 |
+
except as required for reasonable and customary use in describing the
|
| 141 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 142 |
+
|
| 143 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 144 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 145 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 146 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 147 |
+
implied, including, without limitation, any warranties or conditions
|
| 148 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 149 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 150 |
+
appropriateness of using or redistributing the Work and assume any
|
| 151 |
+
risks associated with Your exercise of permissions under this License.
|
| 152 |
+
|
| 153 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 154 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 155 |
+
unless required by applicable law (such as deliberate and grossly
|
| 156 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 157 |
+
liable to You for damages, including any direct, indirect, special,
|
| 158 |
+
incidental, or consequential damages of any character arising as a
|
| 159 |
+
result of this License or out of the use or inability to use the
|
| 160 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 161 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 162 |
+
other commercial damages or losses), even if such Contributor
|
| 163 |
+
has been advised of the possibility of such damages.
|
| 164 |
+
|
| 165 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 166 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 167 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 168 |
+
or other liability obligations and/or rights consistent with this
|
| 169 |
+
License. However, in accepting such obligations, You may act only
|
| 170 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 171 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 172 |
+
defend, and hold each Contributor harmless for any liability
|
| 173 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 174 |
+
of your accepting any such warranty or additional liability.
|
| 175 |
+
|
| 176 |
+
END OF TERMS AND CONDITIONS
|
| 177 |
+
|
| 178 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 179 |
+
|
| 180 |
+
To apply the Apache License to your work, attach the following
|
| 181 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 182 |
+
replaced with your own identifying information. (Don't include
|
| 183 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 184 |
+
comment syntax for the file format. We also recommend that a
|
| 185 |
+
file or class name and description of purpose be included on the
|
| 186 |
+
same "printed page" as the copyright notice for easier
|
| 187 |
+
identification within third-party archives.
|
| 188 |
+
|
| 189 |
+
Copyright [yyyy] [name of copyright owner]
|
| 190 |
+
|
| 191 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 192 |
+
you may not use this file except in compliance with the License.
|
| 193 |
+
You may obtain a copy of the License at
|
| 194 |
+
|
| 195 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 196 |
+
|
| 197 |
+
Unless required by applicable law or agreed to in writing, software
|
| 198 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 199 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 200 |
+
See the License for the specific language governing permissions and
|
| 201 |
+
limitations under the License.
|
EAGLE/gradio_demo.py
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
# This file is modified from https://huggingface.co/spaces/shi-labs/CuMo-7b-zero/blob/main/app.py
|
| 16 |
+
|
| 17 |
+
import gradio as gr
|
| 18 |
+
import os
|
| 19 |
+
import torch
|
| 20 |
+
import numpy as np
|
| 21 |
+
|
| 22 |
+
from eagle import conversation as conversation_lib
|
| 23 |
+
from eagle.constants import DEFAULT_IMAGE_TOKEN
|
| 24 |
+
|
| 25 |
+
from eagle.constants import IMAGE_TOKEN_INDEX, DEFAULT_IMAGE_TOKEN, DEFAULT_IM_START_TOKEN, DEFAULT_IM_END_TOKEN
|
| 26 |
+
from eagle.conversation import conv_templates, SeparatorStyle
|
| 27 |
+
from eagle.model.builder import load_pretrained_model
|
| 28 |
+
from eagle.utils import disable_torch_init
|
| 29 |
+
from eagle.mm_utils import tokenizer_image_token, get_model_name_from_path, process_images, KeywordsStoppingCriteria
|
| 30 |
+
|
| 31 |
+
from PIL import Image
|
| 32 |
+
|
| 33 |
+
from PIL import Image
|
| 34 |
+
import argparse
|
| 35 |
+
|
| 36 |
+
from transformers import TextIteratorStreamer
|
| 37 |
+
from threading import Thread
|
| 38 |
+
|
| 39 |
+
# os.environ['GRADIO_TEMP_DIR'] = './gradio_tmp'
|
| 40 |
+
no_change_btn = gr.Button()
|
| 41 |
+
enable_btn = gr.Button(interactive=True)
|
| 42 |
+
disable_btn = gr.Button(interactive=False)
|
| 43 |
+
|
| 44 |
+
argparser = argparse.ArgumentParser()
|
| 45 |
+
argparser.add_argument("--server_name", default="0.0.0.0", type=str)
|
| 46 |
+
argparser.add_argument("--port", default="6324", type=str)
|
| 47 |
+
argparser.add_argument("--model-path", default="NVEagle/Eagle-X5-13B-Chat", type=str)
|
| 48 |
+
argparser.add_argument("--model-base", type=str, default=None)
|
| 49 |
+
argparser.add_argument("--num-gpus", type=int, default=1)
|
| 50 |
+
argparser.add_argument("--conv-mode", type=str, default="vicuna_v1",)
|
| 51 |
+
argparser.add_argument("--temperature", type=float, default=0.2)
|
| 52 |
+
argparser.add_argument("--max-new-tokens", type=int, default=512)
|
| 53 |
+
argparser.add_argument("--num_frames", type=int, default=16)
|
| 54 |
+
argparser.add_argument("--load-8bit", action="store_true")
|
| 55 |
+
argparser.add_argument("--load-4bit", action="store_true")
|
| 56 |
+
argparser.add_argument("--debug", action="store_true")
|
| 57 |
+
|
| 58 |
+
args = argparser.parse_args()
|
| 59 |
+
model_path = args.model_path
|
| 60 |
+
conv_mode = args.conv_mode
|
| 61 |
+
filt_invalid="cut"
|
| 62 |
+
model_name = get_model_name_from_path(args.model_path)
|
| 63 |
+
tokenizer, model, image_processor, context_len = load_pretrained_model(args.model_path, args.model_base, model_name, args.load_8bit, args.load_4bit)
|
| 64 |
+
our_chatbot = None
|
| 65 |
+
|
| 66 |
+
def upvote_last_response(state):
|
| 67 |
+
return ("",) + (disable_btn,) * 3
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
def downvote_last_response(state):
|
| 71 |
+
return ("",) + (disable_btn,) * 3
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
def flag_last_response(state):
|
| 75 |
+
return ("",) + (disable_btn,) * 3
|
| 76 |
+
|
| 77 |
+
def clear_history():
|
| 78 |
+
state =conv_templates[conv_mode].copy()
|
| 79 |
+
return (state, state.to_gradio_chatbot(), "", None) + (disable_btn,) * 5
|
| 80 |
+
|
| 81 |
+
def add_text(state, imagebox, textbox, image_process_mode):
|
| 82 |
+
if state is None:
|
| 83 |
+
state = conv_templates[conv_mode].copy()
|
| 84 |
+
|
| 85 |
+
if imagebox is not None:
|
| 86 |
+
textbox = DEFAULT_IMAGE_TOKEN + '\n' + textbox
|
| 87 |
+
image = Image.open(imagebox).convert('RGB')
|
| 88 |
+
|
| 89 |
+
if imagebox is not None:
|
| 90 |
+
textbox = (textbox, image, image_process_mode)
|
| 91 |
+
|
| 92 |
+
state.append_message(state.roles[0], textbox)
|
| 93 |
+
state.append_message(state.roles[1], None)
|
| 94 |
+
|
| 95 |
+
yield (state, state.to_gradio_chatbot(), "", None) + (disable_btn, disable_btn, disable_btn, enable_btn, enable_btn)
|
| 96 |
+
|
| 97 |
+
def delete_text(state, image_process_mode):
|
| 98 |
+
state.messages[-1][-1] = None
|
| 99 |
+
prev_human_msg = state.messages[-2]
|
| 100 |
+
if type(prev_human_msg[1]) in (tuple, list):
|
| 101 |
+
prev_human_msg[1] = (*prev_human_msg[1][:2], image_process_mode)
|
| 102 |
+
yield (state, state.to_gradio_chatbot(), "", None) + (disable_btn, disable_btn, disable_btn, enable_btn, enable_btn)
|
| 103 |
+
|
| 104 |
+
def regenerate(state, image_process_mode):
|
| 105 |
+
state.messages[-1][-1] = None
|
| 106 |
+
prev_human_msg = state.messages[-2]
|
| 107 |
+
if type(prev_human_msg[1]) in (tuple, list):
|
| 108 |
+
prev_human_msg[1] = (*prev_human_msg[1][:2], image_process_mode)
|
| 109 |
+
state.skip_next = False
|
| 110 |
+
return (state, state.to_gradio_chatbot(), "", None) + (disable_btn,) * 5
|
| 111 |
+
|
| 112 |
+
# @spaces.GPU
|
| 113 |
+
def generate(state, imagebox, textbox, image_process_mode, temperature, top_p, max_output_tokens):
|
| 114 |
+
prompt = state.get_prompt()
|
| 115 |
+
images = state.get_images(return_pil=True)
|
| 116 |
+
#prompt, image_args = process_image(prompt, images)
|
| 117 |
+
|
| 118 |
+
ori_prompt = prompt
|
| 119 |
+
num_image_tokens = 0
|
| 120 |
+
|
| 121 |
+
if images is not None and len(images) > 0:
|
| 122 |
+
if len(images) > 0:
|
| 123 |
+
if len(images) != prompt.count(DEFAULT_IMAGE_TOKEN):
|
| 124 |
+
raise ValueError("Number of images does not match number of <image> tokens in prompt")
|
| 125 |
+
|
| 126 |
+
#images = [load_image_from_base64(image) for image in images]
|
| 127 |
+
image_sizes = [image.size for image in images]
|
| 128 |
+
images = process_images(images, image_processor, model.config)
|
| 129 |
+
|
| 130 |
+
if type(images) is list:
|
| 131 |
+
images = [image.to(model.device, dtype=torch.float16) for image in images]
|
| 132 |
+
else:
|
| 133 |
+
images = images.to(model.device, dtype=torch.float16)
|
| 134 |
+
else:
|
| 135 |
+
images = None
|
| 136 |
+
image_sizes = None
|
| 137 |
+
image_args = {"images": images, "image_sizes": image_sizes}
|
| 138 |
+
else:
|
| 139 |
+
images = None
|
| 140 |
+
image_args = {}
|
| 141 |
+
|
| 142 |
+
max_context_length = getattr(model.config, 'max_position_embeddings', 2048)
|
| 143 |
+
max_new_tokens = 512
|
| 144 |
+
do_sample = True if temperature > 0.001 else False
|
| 145 |
+
stop_str = state.sep if state.sep_style in [SeparatorStyle.SINGLE, SeparatorStyle.MPT] else state.sep2
|
| 146 |
+
|
| 147 |
+
input_ids = tokenizer_image_token(prompt, tokenizer, IMAGE_TOKEN_INDEX, return_tensors='pt').unsqueeze(0).to(model.device)
|
| 148 |
+
streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True, timeout=15)
|
| 149 |
+
|
| 150 |
+
max_new_tokens = min(max_new_tokens, max_context_length - input_ids.shape[-1] - num_image_tokens)
|
| 151 |
+
|
| 152 |
+
if max_new_tokens < 1:
|
| 153 |
+
# yield json.dumps({"text": ori_prompt + "Exceeds max token length. Please start a new conversation, thanks.", "error_code": 0}).encode() + b"\0"
|
| 154 |
+
return
|
| 155 |
+
|
| 156 |
+
thread = Thread(target=model.generate, kwargs=dict(
|
| 157 |
+
inputs=input_ids,
|
| 158 |
+
do_sample=do_sample,
|
| 159 |
+
temperature=temperature,
|
| 160 |
+
top_p=top_p,
|
| 161 |
+
max_new_tokens=max_new_tokens,
|
| 162 |
+
streamer=streamer,
|
| 163 |
+
use_cache=True,
|
| 164 |
+
pad_token_id=tokenizer.eos_token_id,
|
| 165 |
+
**image_args
|
| 166 |
+
))
|
| 167 |
+
thread.start()
|
| 168 |
+
generated_text = ''
|
| 169 |
+
for new_text in streamer:
|
| 170 |
+
generated_text += new_text
|
| 171 |
+
if generated_text.endswith(stop_str):
|
| 172 |
+
generated_text = generated_text[:-len(stop_str)]
|
| 173 |
+
state.messages[-1][-1] = generated_text
|
| 174 |
+
yield (state, state.to_gradio_chatbot(), "", None) + (disable_btn, disable_btn, disable_btn, enable_btn, enable_btn)
|
| 175 |
+
|
| 176 |
+
yield (state, state.to_gradio_chatbot(), "", None) + (enable_btn,) * 5
|
| 177 |
+
|
| 178 |
+
torch.cuda.empty_cache()
|
| 179 |
+
|
| 180 |
+
txt = gr.Textbox(
|
| 181 |
+
scale=4,
|
| 182 |
+
show_label=False,
|
| 183 |
+
placeholder="Enter text and press enter.",
|
| 184 |
+
container=False,
|
| 185 |
+
)
|
| 186 |
+
|
| 187 |
+
|
| 188 |
+
title_markdown = ("""
|
| 189 |
+
# Eagle: Exploring The Design Space for Multimodal LLMs with Mixture of Encoders
|
| 190 |
+
[[Code](https://github.com/NVlabs/EAGLE)] [[Model](https://huggingface.co/NVEagle)] | 📚 [[Arxiv](https://arxiv.org/pdf/2408.15998)]]
|
| 191 |
+
""")
|
| 192 |
+
|
| 193 |
+
tos_markdown = ("""
|
| 194 |
+
### Terms of use
|
| 195 |
+
By using this service, users are required to agree to the following terms:
|
| 196 |
+
The service is a research preview intended for non-commercial use only. It only provides limited safety measures and may generate offensive content. It must not be used for any illegal, harmful, violent, racist, or sexual purposes. The service may collect user dialogue data for future research.
|
| 197 |
+
Please click the "Flag" button if you get any inappropriate answer! We will collect those to keep improving our moderator.
|
| 198 |
+
For an optimal experience, please use desktop computers for this demo, as mobile devices may compromise its quality.
|
| 199 |
+
""")
|
| 200 |
+
|
| 201 |
+
|
| 202 |
+
learn_more_markdown = ("""
|
| 203 |
+
### License
|
| 204 |
+
The service is a research preview intended for non-commercial use only, subject to the. Please contact us if you find any potential violation.
|
| 205 |
+
""")
|
| 206 |
+
|
| 207 |
+
block_css = """
|
| 208 |
+
#buttons button {
|
| 209 |
+
min-width: min(120px,100%);
|
| 210 |
+
}
|
| 211 |
+
"""
|
| 212 |
+
|
| 213 |
+
textbox = gr.Textbox(show_label=False, placeholder="Enter text and press ENTER", container=False)
|
| 214 |
+
with gr.Blocks(title="Eagle", theme=gr.themes.Default(), css=block_css) as demo:
|
| 215 |
+
state = gr.State()
|
| 216 |
+
|
| 217 |
+
gr.Markdown(title_markdown)
|
| 218 |
+
|
| 219 |
+
with gr.Row():
|
| 220 |
+
with gr.Column(scale=3):
|
| 221 |
+
imagebox = gr.Image(label="Input Image", type="filepath")
|
| 222 |
+
image_process_mode = gr.Radio(
|
| 223 |
+
["Crop", "Resize", "Pad", "Default"],
|
| 224 |
+
value="Default",
|
| 225 |
+
label="Preprocess for non-square image", visible=False)
|
| 226 |
+
|
| 227 |
+
|
| 228 |
+
cur_dir = os.path.dirname(os.path.abspath(__file__))
|
| 229 |
+
gr.Examples(examples=[
|
| 230 |
+
[f"{cur_dir}/assets/health-insurance.png", "Under which circumstances do I need to be enrolled in mandatory health insurance if I am an international student?"],
|
| 231 |
+
[f"{cur_dir}/assets/leasing-apartment.png", "I don't have any 3rd party renter's insurance now. Do I need to get one for myself?"],
|
| 232 |
+
[f"{cur_dir}/assets/nvidia.jpeg", "Who is the person in the middle?"],
|
| 233 |
+
[f"{cur_dir}/assets/animal-compare.png", "Are these two pictures showing the same kind of animal?"],
|
| 234 |
+
[f"{cur_dir}/assets/georgia-tech.jpeg", "Where is this photo taken?"]
|
| 235 |
+
], inputs=[imagebox, textbox], cache_examples=False)
|
| 236 |
+
|
| 237 |
+
with gr.Accordion("Parameters", open=False) as parameter_row:
|
| 238 |
+
temperature = gr.Slider(minimum=0.0, maximum=1.0, value=0.2, step=0.1, interactive=True, label="Temperature",)
|
| 239 |
+
top_p = gr.Slider(minimum=0.0, maximum=1.0, value=0.7, step=0.1, interactive=True, label="Top P",)
|
| 240 |
+
max_output_tokens = gr.Slider(minimum=0, maximum=1024, value=512, step=64, interactive=True, label="Max output tokens",)
|
| 241 |
+
|
| 242 |
+
with gr.Column(scale=8):
|
| 243 |
+
chatbot = gr.Chatbot(
|
| 244 |
+
elem_id="chatbot",
|
| 245 |
+
label="Eagle Chatbot",
|
| 246 |
+
height=650,
|
| 247 |
+
layout="panel",
|
| 248 |
+
)
|
| 249 |
+
with gr.Row():
|
| 250 |
+
with gr.Column(scale=8):
|
| 251 |
+
textbox.render()
|
| 252 |
+
with gr.Column(scale=1, min_width=50):
|
| 253 |
+
submit_btn = gr.Button(value="Send", variant="primary")
|
| 254 |
+
with gr.Row(elem_id="buttons") as button_row:
|
| 255 |
+
upvote_btn = gr.Button(value="👍 Upvote", interactive=False)
|
| 256 |
+
downvote_btn = gr.Button(value="👎 Downvote", interactive=False)
|
| 257 |
+
flag_btn = gr.Button(value="⚠️ Flag", interactive=False)
|
| 258 |
+
#stop_btn = gr.Button(value="⏹️ Stop Generation", interactive=False)
|
| 259 |
+
regenerate_btn = gr.Button(value="🔄 Regenerate", interactive=False)
|
| 260 |
+
clear_btn = gr.Button(value="🗑️ Clear", interactive=False)
|
| 261 |
+
|
| 262 |
+
gr.Markdown(tos_markdown)
|
| 263 |
+
gr.Markdown(learn_more_markdown)
|
| 264 |
+
url_params = gr.JSON(visible=False)
|
| 265 |
+
|
| 266 |
+
# Register listeners
|
| 267 |
+
btn_list = [upvote_btn, downvote_btn, flag_btn, regenerate_btn, clear_btn]
|
| 268 |
+
upvote_btn.click(
|
| 269 |
+
upvote_last_response,
|
| 270 |
+
[state],
|
| 271 |
+
[textbox, upvote_btn, downvote_btn, flag_btn]
|
| 272 |
+
)
|
| 273 |
+
downvote_btn.click(
|
| 274 |
+
downvote_last_response,
|
| 275 |
+
[state],
|
| 276 |
+
[textbox, upvote_btn, downvote_btn, flag_btn]
|
| 277 |
+
)
|
| 278 |
+
flag_btn.click(
|
| 279 |
+
flag_last_response,
|
| 280 |
+
[state],
|
| 281 |
+
[textbox, upvote_btn, downvote_btn, flag_btn]
|
| 282 |
+
)
|
| 283 |
+
|
| 284 |
+
clear_btn.click(
|
| 285 |
+
clear_history,
|
| 286 |
+
None,
|
| 287 |
+
[state, chatbot, textbox, imagebox] + btn_list,
|
| 288 |
+
queue=False
|
| 289 |
+
)
|
| 290 |
+
|
| 291 |
+
regenerate_btn.click(
|
| 292 |
+
delete_text,
|
| 293 |
+
[state, image_process_mode],
|
| 294 |
+
[state, chatbot, textbox, imagebox] + btn_list,
|
| 295 |
+
).then(
|
| 296 |
+
generate,
|
| 297 |
+
[state, imagebox, textbox, image_process_mode, temperature, top_p, max_output_tokens],
|
| 298 |
+
[state, chatbot, textbox, imagebox] + btn_list,
|
| 299 |
+
)
|
| 300 |
+
textbox.submit(
|
| 301 |
+
add_text,
|
| 302 |
+
[state, imagebox, textbox, image_process_mode],
|
| 303 |
+
[state, chatbot, textbox, imagebox] + btn_list,
|
| 304 |
+
).then(
|
| 305 |
+
generate,
|
| 306 |
+
[state, imagebox, textbox, image_process_mode, temperature, top_p, max_output_tokens],
|
| 307 |
+
[state, chatbot, textbox, imagebox] + btn_list,
|
| 308 |
+
)
|
| 309 |
+
|
| 310 |
+
submit_btn.click(
|
| 311 |
+
add_text,
|
| 312 |
+
[state, imagebox, textbox, image_process_mode],
|
| 313 |
+
[state, chatbot, textbox, imagebox] + btn_list,
|
| 314 |
+
).then(
|
| 315 |
+
generate,
|
| 316 |
+
[state, imagebox, textbox, image_process_mode, temperature, top_p, max_output_tokens],
|
| 317 |
+
[state, chatbot, textbox, imagebox] + btn_list,
|
| 318 |
+
)
|
| 319 |
+
|
| 320 |
+
demo.queue(
|
| 321 |
+
status_update_rate=10,
|
| 322 |
+
api_open=False
|
| 323 |
+
).launch(share=True)
|
| 324 |
+
demo.queue()
|
| 325 |
+
|
| 326 |
+
# if __name__ == "__main__":
|
| 327 |
+
|
| 328 |
+
# # import pdb;pdb.set_trace()
|
| 329 |
+
# try:
|
| 330 |
+
# demo.launch(server_name=args.server_name, server_port=int(args.port), share=True)
|
| 331 |
+
# except Exception as e:
|
| 332 |
+
# args.port=int(args.port)+1
|
| 333 |
+
# print(f"Port {args.port} is occupied, try port {args.port}")
|
| 334 |
+
# demo.launch(server_name=args.server_name, server_port=int(args.port), share=True)
|
EAGLE/predict_demo.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
# A simple reference example of using eagle model
|
| 16 |
+
|
| 17 |
+
import os
|
| 18 |
+
import torch
|
| 19 |
+
import numpy as np
|
| 20 |
+
|
| 21 |
+
from eagle import conversation as conversation_lib
|
| 22 |
+
from eagle.constants import DEFAULT_IMAGE_TOKEN
|
| 23 |
+
|
| 24 |
+
from eagle.constants import IMAGE_TOKEN_INDEX, DEFAULT_IMAGE_TOKEN, DEFAULT_IM_START_TOKEN, DEFAULT_IM_END_TOKEN
|
| 25 |
+
from eagle.conversation import conv_templates, SeparatorStyle
|
| 26 |
+
from eagle.model.builder import load_pretrained_model
|
| 27 |
+
from eagle.utils import disable_torch_init
|
| 28 |
+
from eagle.mm_utils import tokenizer_image_token, get_model_name_from_path, process_images, KeywordsStoppingCriteria
|
| 29 |
+
|
| 30 |
+
from PIL import Image
|
| 31 |
+
import argparse
|
| 32 |
+
|
| 33 |
+
from transformers import TextIteratorStreamer
|
| 34 |
+
from threading import Thread
|
| 35 |
+
|
| 36 |
+
model_path = "NVEagle/Eagle-X5-13B-Chat"
|
| 37 |
+
conv_mode = "vicuna_v1"
|
| 38 |
+
image_path = "assets/georgia-tech.jpeg"
|
| 39 |
+
input_prompt = "Describe this image."
|
| 40 |
+
|
| 41 |
+
model_name = get_model_name_from_path(model_path)
|
| 42 |
+
tokenizer, model, image_processor, context_len = load_pretrained_model(model_path,
|
| 43 |
+
None,
|
| 44 |
+
model_name,
|
| 45 |
+
False,
|
| 46 |
+
False)
|
| 47 |
+
|
| 48 |
+
if model.config.mm_use_im_start_end:
|
| 49 |
+
input_prompt = DEFAULT_IM_START_TOKEN + DEFAULT_IMAGE_TOKEN + DEFAULT_IM_END_TOKEN + '\n' + input_prompt
|
| 50 |
+
else:
|
| 51 |
+
input_prompt = DEFAULT_IMAGE_TOKEN + '\n' + input_prompt
|
| 52 |
+
|
| 53 |
+
conv = conv_templates[conv_mode].copy()
|
| 54 |
+
conv.append_message(conv.roles[0], input_prompt)
|
| 55 |
+
conv.append_message(conv.roles[1], None)
|
| 56 |
+
prompt = conv.get_prompt()
|
| 57 |
+
|
| 58 |
+
image = Image.open(image_path).convert('RGB')
|
| 59 |
+
image_tensor = process_images([image], image_processor, model.config)[0]
|
| 60 |
+
input_ids = tokenizer_image_token(prompt, tokenizer, IMAGE_TOKEN_INDEX, return_tensors='pt')
|
| 61 |
+
|
| 62 |
+
input_ids = input_ids.to(device='cuda', non_blocking=True)
|
| 63 |
+
image_tensor = image_tensor.to(dtype=torch.float16, device='cuda', non_blocking=True)
|
| 64 |
+
|
| 65 |
+
with torch.inference_mode():
|
| 66 |
+
output_ids = model.generate(
|
| 67 |
+
input_ids.unsqueeze(0),
|
| 68 |
+
images=image_tensor.unsqueeze(0),
|
| 69 |
+
image_sizes=[image.size],
|
| 70 |
+
do_sample=True,
|
| 71 |
+
temperature=0.2,
|
| 72 |
+
top_p=0.5,
|
| 73 |
+
num_beams=1,
|
| 74 |
+
max_new_tokens=256,
|
| 75 |
+
use_cache=True)
|
| 76 |
+
|
| 77 |
+
outputs = tokenizer.batch_decode(output_ids, skip_special_tokens=True)[0].strip()
|
| 78 |
+
print(f"Image:{image_path} \nPrompt:{input_prompt} \nOutput:{outputs}")
|
EAGLE/setup.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from setuptools import setup, find_packages
|
| 2 |
+
|
| 3 |
+
setup(
|
| 4 |
+
name="eagle",
|
| 5 |
+
version="0.0.1",
|
| 6 |
+
packages=find_packages(include=["eagle", "eagle.*"]),
|
| 7 |
+
package_data={
|
| 8 |
+
"eagle": ["*"],
|
| 9 |
+
"eagle.model": ["*"],
|
| 10 |
+
"eagle.model.language_model": ["*"],
|
| 11 |
+
},
|
| 12 |
+
py_modules=[
|
| 13 |
+
"eagle.conversation",
|
| 14 |
+
"eagle.constants",
|
| 15 |
+
"eagle.model.builder",
|
| 16 |
+
"eagle.model.language_model",
|
| 17 |
+
"eagle.utils",
|
| 18 |
+
"eagle.mm_utils",
|
| 19 |
+
],
|
| 20 |
+
install_requires=[
|
| 21 |
+
# Add any dependencies required by the eagle module
|
| 22 |
+
],
|
| 23 |
+
include_package_data=True,
|
| 24 |
+
)
|
EAGLE/train.py
ADDED
|
@@ -0,0 +1,1201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
# This file is modified from https://github.com/haotian-liu/LLaVA/
|
| 16 |
+
|
| 17 |
+
# Adopted from https://github.com/lm-sys/FastChat. Below is the original copyright:
|
| 18 |
+
# Adopted from tatsu-lab@stanford_alpaca. Below is the original copyright:
|
| 19 |
+
# Copyright 2023 Rohan Taori, Ishaan Gulrajani, Tianyi Zhang, Yann Dubois, Xuechen Li
|
| 20 |
+
#
|
| 21 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 22 |
+
# you may not use this file except in compliance with the License.
|
| 23 |
+
# You may obtain a copy of the License at
|
| 24 |
+
#
|
| 25 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 26 |
+
#
|
| 27 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 28 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 29 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 30 |
+
# See the License for the specific language governing permissions and
|
| 31 |
+
# limitations under the License.
|
| 32 |
+
|
| 33 |
+
import os
|
| 34 |
+
import copy
|
| 35 |
+
from dataclasses import dataclass, field
|
| 36 |
+
import json
|
| 37 |
+
import logging
|
| 38 |
+
import pathlib
|
| 39 |
+
from typing import Dict, Optional, Sequence, List
|
| 40 |
+
|
| 41 |
+
import torch
|
| 42 |
+
import numpy as np
|
| 43 |
+
|
| 44 |
+
import transformers
|
| 45 |
+
import tokenizers
|
| 46 |
+
|
| 47 |
+
from eagle.constants import IGNORE_INDEX, IMAGE_TOKEN_INDEX, DEFAULT_IMAGE_TOKEN, DEFAULT_IM_START_TOKEN, DEFAULT_IM_END_TOKEN
|
| 48 |
+
from torch.utils.data import Dataset
|
| 49 |
+
from eagle.train.eagle_trainer import EagleTrainer
|
| 50 |
+
|
| 51 |
+
from eagle import conversation as conversation_lib
|
| 52 |
+
from eagle.model import *
|
| 53 |
+
from eagle.mm_utils import tokenizer_image_token
|
| 54 |
+
|
| 55 |
+
from PIL import Image
|
| 56 |
+
|
| 57 |
+
local_rank = None
|
| 58 |
+
|
| 59 |
+
def rank0_print(*args):
|
| 60 |
+
if local_rank == 0:
|
| 61 |
+
print(*args)
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
from packaging import version
|
| 65 |
+
IS_TOKENIZER_GREATER_THAN_0_14 = version.parse(tokenizers.__version__) >= version.parse('0.14')
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
@dataclass
|
| 69 |
+
class ModelArguments:
|
| 70 |
+
model_name_or_path: Optional[str] = field(default="facebook/opt-125m")
|
| 71 |
+
version: Optional[str] = field(default="v0")
|
| 72 |
+
freeze_backbone: bool = field(default=False)
|
| 73 |
+
tune_mm_mlp_adapter: bool = field(default=False)
|
| 74 |
+
vision_tower: Optional[str] = field(default=None)
|
| 75 |
+
mm_vision_select_layer: Optional[int] = field(default=-1) # default to the last layer
|
| 76 |
+
pretrain_mm_mlp_adapter: Optional[str] = field(default=None)
|
| 77 |
+
mm_projector_type: Optional[str] = field(default='linear')
|
| 78 |
+
mm_use_im_start_end: bool = field(default=False)
|
| 79 |
+
mm_use_im_patch_token: bool = field(default=True)
|
| 80 |
+
mm_patch_merge_type: Optional[str] = field(default='flat')
|
| 81 |
+
mm_vision_select_feature: Optional[str] = field(default="patch")
|
| 82 |
+
|
| 83 |
+
@dataclass
|
| 84 |
+
class DataArguments:
|
| 85 |
+
data_path: str = field(default=None,
|
| 86 |
+
metadata={"help": "Path to the training data."})
|
| 87 |
+
lazy_preprocess: bool = False
|
| 88 |
+
is_multimodal: bool = False
|
| 89 |
+
image_folder: Optional[str] = field(default=None)
|
| 90 |
+
image_aspect_ratio: str = 'square'
|
| 91 |
+
|
| 92 |
+
@dataclass
|
| 93 |
+
class TrainingArguments(transformers.TrainingArguments):
|
| 94 |
+
cache_dir: Optional[str] = field(default=None)
|
| 95 |
+
optim: str = field(default="adamw_torch")
|
| 96 |
+
remove_unused_columns: bool = field(default=False)
|
| 97 |
+
freeze_mm_mlp_adapter: bool = field(default=False)
|
| 98 |
+
mpt_attn_impl: Optional[str] = field(default="triton")
|
| 99 |
+
model_max_length: int = field(
|
| 100 |
+
default=512,
|
| 101 |
+
metadata={
|
| 102 |
+
"help":
|
| 103 |
+
"Maximum sequence length. Sequences will be right padded (and possibly truncated)."
|
| 104 |
+
},
|
| 105 |
+
)
|
| 106 |
+
double_quant: bool = field(
|
| 107 |
+
default=True,
|
| 108 |
+
metadata={"help": "Compress the quantization statistics through double quantization."}
|
| 109 |
+
)
|
| 110 |
+
quant_type: str = field(
|
| 111 |
+
default="nf4",
|
| 112 |
+
metadata={"help": "Quantization data type to use. Should be one of `fp4` or `nf4`."}
|
| 113 |
+
)
|
| 114 |
+
bits: int = field(
|
| 115 |
+
default=16,
|
| 116 |
+
metadata={"help": "How many bits to use."}
|
| 117 |
+
)
|
| 118 |
+
lora_enable: bool = False
|
| 119 |
+
lora_r: int = 64
|
| 120 |
+
lora_alpha: int = 16
|
| 121 |
+
lora_dropout: float = 0.05
|
| 122 |
+
lora_weight_path: str = ""
|
| 123 |
+
lora_bias: str = "none"
|
| 124 |
+
mm_projector_lr: Optional[float] = None
|
| 125 |
+
vision_tower_layer_decay: Optional[float] = None
|
| 126 |
+
vision_tower_lr: Optional[float] = None
|
| 127 |
+
group_by_modality_length: bool = field(default=False)
|
| 128 |
+
|
| 129 |
+
def maybe_zero_3(param, ignore_status=False, name=None):
|
| 130 |
+
from deepspeed import zero
|
| 131 |
+
from deepspeed.runtime.zero.partition_parameters import ZeroParamStatus
|
| 132 |
+
if hasattr(param, "ds_id"):
|
| 133 |
+
if param.ds_status == ZeroParamStatus.NOT_AVAILABLE:
|
| 134 |
+
if not ignore_status:
|
| 135 |
+
logging.warning(f"{name}: param.ds_status != ZeroParamStatus.NOT_AVAILABLE: {param.ds_status}")
|
| 136 |
+
with zero.GatheredParameters([param]):
|
| 137 |
+
param = param.data.detach().cpu().clone()
|
| 138 |
+
else:
|
| 139 |
+
param = param.detach().cpu().clone()
|
| 140 |
+
return param
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
# Borrowed from peft.utils.get_peft_model_state_dict
|
| 144 |
+
def get_peft_state_maybe_zero_3(named_params, bias):
|
| 145 |
+
if bias == "none":
|
| 146 |
+
to_return = {k: t for k, t in named_params if "lora_" in k}
|
| 147 |
+
elif bias == "all":
|
| 148 |
+
to_return = {k: t for k, t in named_params if "lora_" in k or "bias" in k}
|
| 149 |
+
elif bias == "lora_only":
|
| 150 |
+
to_return = {}
|
| 151 |
+
maybe_lora_bias = {}
|
| 152 |
+
lora_bias_names = set()
|
| 153 |
+
for k, t in named_params:
|
| 154 |
+
if "lora_" in k:
|
| 155 |
+
to_return[k] = t
|
| 156 |
+
bias_name = k.split("lora_")[0] + "bias"
|
| 157 |
+
lora_bias_names.add(bias_name)
|
| 158 |
+
elif "bias" in k:
|
| 159 |
+
maybe_lora_bias[k] = t
|
| 160 |
+
for k, t in maybe_lora_bias:
|
| 161 |
+
if bias_name in lora_bias_names:
|
| 162 |
+
to_return[bias_name] = t
|
| 163 |
+
else:
|
| 164 |
+
raise NotImplementedError
|
| 165 |
+
to_return = {k: maybe_zero_3(v, ignore_status=True) for k, v in to_return.items()}
|
| 166 |
+
return to_return
|
| 167 |
+
|
| 168 |
+
|
| 169 |
+
def get_peft_state_non_lora_maybe_zero_3(named_params, require_grad_only=True):
|
| 170 |
+
to_return = {k: t for k, t in named_params if "lora_" not in k}
|
| 171 |
+
if require_grad_only:
|
| 172 |
+
to_return = {k: t for k, t in to_return.items() if t.requires_grad}
|
| 173 |
+
to_return = {k: maybe_zero_3(v, ignore_status=True).cpu() for k, v in to_return.items()}
|
| 174 |
+
return to_return
|
| 175 |
+
|
| 176 |
+
|
| 177 |
+
def get_mm_adapter_state_maybe_zero_3(named_params, keys_to_match):
|
| 178 |
+
to_return = {k: t for k, t in named_params if any(key_match in k for key_match in keys_to_match)}
|
| 179 |
+
to_return = {k: maybe_zero_3(v, ignore_status=True).cpu() for k, v in to_return.items()}
|
| 180 |
+
return to_return
|
| 181 |
+
|
| 182 |
+
|
| 183 |
+
def find_all_linear_names(model):
|
| 184 |
+
cls = torch.nn.Linear
|
| 185 |
+
lora_module_names = set()
|
| 186 |
+
multimodal_keywords = ['mm_projector', 'vision_tower', 'vision_resampler']
|
| 187 |
+
for name, module in model.named_modules():
|
| 188 |
+
if any(mm_keyword in name for mm_keyword in multimodal_keywords):
|
| 189 |
+
continue
|
| 190 |
+
if isinstance(module, cls):
|
| 191 |
+
names = name.split('.')
|
| 192 |
+
lora_module_names.add(names[0] if len(names) == 1 else names[-1])
|
| 193 |
+
|
| 194 |
+
if 'lm_head' in lora_module_names: # needed for 16-bit
|
| 195 |
+
lora_module_names.remove('lm_head')
|
| 196 |
+
return list(lora_module_names)
|
| 197 |
+
|
| 198 |
+
|
| 199 |
+
def safe_save_model_for_hf_trainer(trainer: transformers.Trainer,
|
| 200 |
+
output_dir: str):
|
| 201 |
+
"""Collects the state dict and dump to disk."""
|
| 202 |
+
|
| 203 |
+
if getattr(trainer.args, "tune_mm_mlp_adapter", False):
|
| 204 |
+
# Only save Adapter
|
| 205 |
+
keys_to_match = ['mm_projector']
|
| 206 |
+
if getattr(trainer.args, "use_im_start_end", False):
|
| 207 |
+
keys_to_match.extend(['embed_tokens', 'embed_in'])
|
| 208 |
+
|
| 209 |
+
weight_to_save = get_mm_adapter_state_maybe_zero_3(trainer.model.named_parameters(), keys_to_match)
|
| 210 |
+
trainer.model.config.save_pretrained(output_dir)
|
| 211 |
+
|
| 212 |
+
current_folder = output_dir.split('/')[-1]
|
| 213 |
+
parent_folder = os.path.dirname(output_dir)
|
| 214 |
+
if trainer.args.local_rank == 0 or trainer.args.local_rank == -1:
|
| 215 |
+
if current_folder.startswith('checkpoint-'):
|
| 216 |
+
mm_projector_folder = os.path.join(parent_folder, "mm_projector")
|
| 217 |
+
os.makedirs(mm_projector_folder, exist_ok=True)
|
| 218 |
+
torch.save(weight_to_save, os.path.join(mm_projector_folder, f'{current_folder}.bin'))
|
| 219 |
+
else:
|
| 220 |
+
torch.save(weight_to_save, os.path.join(output_dir, f'mm_projector.bin'))
|
| 221 |
+
return
|
| 222 |
+
|
| 223 |
+
if trainer.deepspeed:
|
| 224 |
+
torch.cuda.synchronize()
|
| 225 |
+
trainer.save_model(output_dir)
|
| 226 |
+
return
|
| 227 |
+
|
| 228 |
+
state_dict = trainer.model.state_dict()
|
| 229 |
+
if trainer.args.should_save:
|
| 230 |
+
cpu_state_dict = {
|
| 231 |
+
key: value.cpu()
|
| 232 |
+
for key, value in state_dict.items()
|
| 233 |
+
}
|
| 234 |
+
del state_dict
|
| 235 |
+
trainer._save(output_dir, state_dict=cpu_state_dict) # noqa
|
| 236 |
+
|
| 237 |
+
|
| 238 |
+
def smart_tokenizer_and_embedding_resize(
|
| 239 |
+
special_tokens_dict: Dict,
|
| 240 |
+
tokenizer: transformers.PreTrainedTokenizer,
|
| 241 |
+
model: transformers.PreTrainedModel,
|
| 242 |
+
):
|
| 243 |
+
"""Resize tokenizer and embedding.
|
| 244 |
+
|
| 245 |
+
Note: This is the unoptimized version that may make your embedding size not be divisible by 64.
|
| 246 |
+
"""
|
| 247 |
+
num_new_tokens = tokenizer.add_special_tokens(special_tokens_dict)
|
| 248 |
+
model.resize_token_embeddings(len(tokenizer))
|
| 249 |
+
|
| 250 |
+
if num_new_tokens > 0:
|
| 251 |
+
input_embeddings = model.get_input_embeddings().weight.data
|
| 252 |
+
output_embeddings = model.get_output_embeddings().weight.data
|
| 253 |
+
|
| 254 |
+
input_embeddings_avg = input_embeddings[:-num_new_tokens].mean(
|
| 255 |
+
dim=0, keepdim=True)
|
| 256 |
+
output_embeddings_avg = output_embeddings[:-num_new_tokens].mean(
|
| 257 |
+
dim=0, keepdim=True)
|
| 258 |
+
|
| 259 |
+
input_embeddings[-num_new_tokens:] = input_embeddings_avg
|
| 260 |
+
output_embeddings[-num_new_tokens:] = output_embeddings_avg
|
| 261 |
+
|
| 262 |
+
|
| 263 |
+
def _tokenize_fn(strings: Sequence[str],
|
| 264 |
+
tokenizer: transformers.PreTrainedTokenizer) -> Dict:
|
| 265 |
+
"""Tokenize a list of strings."""
|
| 266 |
+
tokenized_list = [
|
| 267 |
+
tokenizer(
|
| 268 |
+
text,
|
| 269 |
+
return_tensors="pt",
|
| 270 |
+
padding="longest",
|
| 271 |
+
max_length=tokenizer.model_max_length,
|
| 272 |
+
truncation=True,
|
| 273 |
+
) for text in strings
|
| 274 |
+
]
|
| 275 |
+
input_ids = labels = [
|
| 276 |
+
tokenized.input_ids[0] for tokenized in tokenized_list
|
| 277 |
+
]
|
| 278 |
+
input_ids_lens = labels_lens = [
|
| 279 |
+
tokenized.input_ids.ne(tokenizer.pad_token_id).sum().item()
|
| 280 |
+
for tokenized in tokenized_list
|
| 281 |
+
]
|
| 282 |
+
return dict(
|
| 283 |
+
input_ids=input_ids,
|
| 284 |
+
labels=labels,
|
| 285 |
+
input_ids_lens=input_ids_lens,
|
| 286 |
+
labels_lens=labels_lens,
|
| 287 |
+
)
|
| 288 |
+
|
| 289 |
+
|
| 290 |
+
def _mask_targets(target, tokenized_lens, speakers):
|
| 291 |
+
# cur_idx = 0
|
| 292 |
+
cur_idx = tokenized_lens[0]
|
| 293 |
+
tokenized_lens = tokenized_lens[1:]
|
| 294 |
+
target[:cur_idx] = IGNORE_INDEX
|
| 295 |
+
for tokenized_len, speaker in zip(tokenized_lens, speakers):
|
| 296 |
+
if speaker == "human":
|
| 297 |
+
target[cur_idx+2:cur_idx + tokenized_len] = IGNORE_INDEX
|
| 298 |
+
cur_idx += tokenized_len
|
| 299 |
+
|
| 300 |
+
|
| 301 |
+
def _add_speaker_and_signal(header, source, get_conversation=True):
|
| 302 |
+
"""Add speaker and start/end signal on each round."""
|
| 303 |
+
BEGIN_SIGNAL = "### "
|
| 304 |
+
END_SIGNAL = "\n"
|
| 305 |
+
conversation = header
|
| 306 |
+
for sentence in source:
|
| 307 |
+
from_str = sentence["from"]
|
| 308 |
+
if from_str.lower() == "human":
|
| 309 |
+
from_str = conversation_lib.default_conversation.roles[0]
|
| 310 |
+
elif from_str.lower() == "gpt":
|
| 311 |
+
from_str = conversation_lib.default_conversation.roles[1]
|
| 312 |
+
else:
|
| 313 |
+
from_str = 'unknown'
|
| 314 |
+
sentence["value"] = (BEGIN_SIGNAL + from_str + ": " +
|
| 315 |
+
sentence["value"] + END_SIGNAL)
|
| 316 |
+
if get_conversation:
|
| 317 |
+
conversation += sentence["value"]
|
| 318 |
+
conversation += BEGIN_SIGNAL
|
| 319 |
+
return conversation
|
| 320 |
+
|
| 321 |
+
|
| 322 |
+
def preprocess_multimodal(
|
| 323 |
+
sources: Sequence[str],
|
| 324 |
+
data_args: DataArguments
|
| 325 |
+
) -> Dict:
|
| 326 |
+
is_multimodal = data_args.is_multimodal
|
| 327 |
+
if not is_multimodal:
|
| 328 |
+
return sources
|
| 329 |
+
|
| 330 |
+
# min shi: a temporal hack to fix some sample that does not contain <image> tokens
|
| 331 |
+
if DEFAULT_IMAGE_TOKEN not in sources[0][0]['value']:
|
| 332 |
+
sources[0][0]['value'] = DEFAULT_IMAGE_TOKEN + '\n' + sources[0][0]['value']
|
| 333 |
+
|
| 334 |
+
for source in sources:
|
| 335 |
+
for sentence in source:
|
| 336 |
+
if DEFAULT_IMAGE_TOKEN in sentence['value']:
|
| 337 |
+
sentence['value'] = sentence['value'].replace(DEFAULT_IMAGE_TOKEN, '').strip()
|
| 338 |
+
sentence['value'] = DEFAULT_IMAGE_TOKEN + '\n' + sentence['value']
|
| 339 |
+
sentence['value'] = sentence['value'].strip()
|
| 340 |
+
if "mmtag" in conversation_lib.default_conversation.version:
|
| 341 |
+
sentence['value'] = sentence['value'].replace(DEFAULT_IMAGE_TOKEN, '<Image>' + DEFAULT_IMAGE_TOKEN + '</Image>')
|
| 342 |
+
replace_token = DEFAULT_IMAGE_TOKEN
|
| 343 |
+
if data_args.mm_use_im_start_end:
|
| 344 |
+
replace_token = DEFAULT_IM_START_TOKEN + replace_token + DEFAULT_IM_END_TOKEN
|
| 345 |
+
sentence["value"] = sentence["value"].replace(DEFAULT_IMAGE_TOKEN, replace_token)
|
| 346 |
+
|
| 347 |
+
return sources
|
| 348 |
+
|
| 349 |
+
|
| 350 |
+
def preprocess_llama_2(
|
| 351 |
+
sources,
|
| 352 |
+
tokenizer: transformers.PreTrainedTokenizer,
|
| 353 |
+
has_image: bool = False
|
| 354 |
+
) -> Dict:
|
| 355 |
+
conv = conversation_lib.default_conversation.copy()
|
| 356 |
+
roles = {"human": conv.roles[0], "gpt": conv.roles[1]}
|
| 357 |
+
|
| 358 |
+
# Apply prompt templates
|
| 359 |
+
conversations = []
|
| 360 |
+
for i, source in enumerate(sources):
|
| 361 |
+
if roles[source[0]["from"]] != conv.roles[0]:
|
| 362 |
+
# Skip the first one if it is not from human
|
| 363 |
+
source = source[1:]
|
| 364 |
+
|
| 365 |
+
conv.messages = []
|
| 366 |
+
for j, sentence in enumerate(source):
|
| 367 |
+
role = roles[sentence["from"]]
|
| 368 |
+
assert role == conv.roles[j % 2], f"{i}"
|
| 369 |
+
conv.append_message(role, sentence["value"])
|
| 370 |
+
conversations.append(conv.get_prompt())
|
| 371 |
+
|
| 372 |
+
# Tokenize conversations
|
| 373 |
+
|
| 374 |
+
if has_image:
|
| 375 |
+
input_ids = torch.stack([tokenizer_image_token(prompt, tokenizer, return_tensors='pt') for prompt in conversations], dim=0)
|
| 376 |
+
else:
|
| 377 |
+
input_ids = tokenizer(
|
| 378 |
+
conversations,
|
| 379 |
+
return_tensors="pt",
|
| 380 |
+
padding="longest",
|
| 381 |
+
max_length=tokenizer.model_max_length,
|
| 382 |
+
truncation=True,
|
| 383 |
+
).input_ids
|
| 384 |
+
|
| 385 |
+
targets = input_ids.clone()
|
| 386 |
+
|
| 387 |
+
assert conv.sep_style == conversation_lib.SeparatorStyle.LLAMA_2
|
| 388 |
+
|
| 389 |
+
# Mask targets
|
| 390 |
+
sep = "[/INST] "
|
| 391 |
+
for conversation, target in zip(conversations, targets):
|
| 392 |
+
total_len = int(target.ne(tokenizer.pad_token_id).sum())
|
| 393 |
+
|
| 394 |
+
rounds = conversation.split(conv.sep2)
|
| 395 |
+
cur_len = 1
|
| 396 |
+
target[:cur_len] = IGNORE_INDEX
|
| 397 |
+
for i, rou in enumerate(rounds):
|
| 398 |
+
if rou == "":
|
| 399 |
+
break
|
| 400 |
+
|
| 401 |
+
parts = rou.split(sep)
|
| 402 |
+
if len(parts) != 2:
|
| 403 |
+
break
|
| 404 |
+
parts[0] += sep
|
| 405 |
+
|
| 406 |
+
if has_image:
|
| 407 |
+
round_len = len(tokenizer_image_token(rou, tokenizer))
|
| 408 |
+
instruction_len = len(tokenizer_image_token(parts[0], tokenizer)) - 2
|
| 409 |
+
else:
|
| 410 |
+
round_len = len(tokenizer(rou).input_ids)
|
| 411 |
+
instruction_len = len(tokenizer(parts[0]).input_ids) - 2
|
| 412 |
+
|
| 413 |
+
target[cur_len : cur_len + instruction_len] = IGNORE_INDEX
|
| 414 |
+
|
| 415 |
+
cur_len += round_len
|
| 416 |
+
target[cur_len:] = IGNORE_INDEX
|
| 417 |
+
|
| 418 |
+
if cur_len < tokenizer.model_max_length:
|
| 419 |
+
if cur_len != total_len:
|
| 420 |
+
target[:] = IGNORE_INDEX
|
| 421 |
+
print(
|
| 422 |
+
f"WARNING: tokenization mismatch: {cur_len} vs. {total_len}."
|
| 423 |
+
f" (ignored)"
|
| 424 |
+
)
|
| 425 |
+
|
| 426 |
+
return dict(
|
| 427 |
+
input_ids=input_ids,
|
| 428 |
+
labels=targets,
|
| 429 |
+
)
|
| 430 |
+
|
| 431 |
+
def preprocess_llama_3(
|
| 432 |
+
sources,
|
| 433 |
+
tokenizer: transformers.PreTrainedTokenizer,
|
| 434 |
+
has_image: bool = False
|
| 435 |
+
) -> Dict:
|
| 436 |
+
conv = conversation_lib.default_conversation.copy()
|
| 437 |
+
roles = {"human": conv.roles[0], "gpt": conv.roles[1]}
|
| 438 |
+
|
| 439 |
+
# Apply prompt templates
|
| 440 |
+
conversations = []
|
| 441 |
+
for i, source in enumerate(sources):
|
| 442 |
+
if roles[source[0]["from"]] != conv.roles[0]:
|
| 443 |
+
# Skip the first one if it is not from human
|
| 444 |
+
source = source[1:]
|
| 445 |
+
|
| 446 |
+
conv.messages = []
|
| 447 |
+
for j, sentence in enumerate(source):
|
| 448 |
+
role = roles[sentence["from"]]
|
| 449 |
+
assert role == conv.roles[j % 2], f"{i}"
|
| 450 |
+
conv.append_message(role, sentence["value"])
|
| 451 |
+
conversations.append(conv.get_prompt())
|
| 452 |
+
|
| 453 |
+
# Tokenize conversations
|
| 454 |
+
|
| 455 |
+
if has_image:
|
| 456 |
+
input_ids = torch.stack(
|
| 457 |
+
[tokenizer_image_token(prompt, tokenizer, return_tensors='pt') for prompt in conversations], dim=0)
|
| 458 |
+
else:
|
| 459 |
+
input_ids = tokenizer(
|
| 460 |
+
conversations,
|
| 461 |
+
return_tensors="pt",
|
| 462 |
+
padding="longest",
|
| 463 |
+
max_length=tokenizer.model_max_length,
|
| 464 |
+
truncation=True,
|
| 465 |
+
).input_ids
|
| 466 |
+
|
| 467 |
+
targets = input_ids.clone()
|
| 468 |
+
assert conv.sep_style == conversation_lib.SeparatorStyle.MPT
|
| 469 |
+
|
| 470 |
+
# Mask targets
|
| 471 |
+
sep = conv.sep + conv.roles[1]
|
| 472 |
+
for conversation, target in zip(conversations, targets):
|
| 473 |
+
total_len = int(target.ne(tokenizer.pad_token_id).sum())
|
| 474 |
+
|
| 475 |
+
rounds = conversation.split(conv.sep)
|
| 476 |
+
re_rounds = [conv.sep.join(rounds[:3])]
|
| 477 |
+
for conv_idx in range(3, len(rounds), 2):
|
| 478 |
+
re_rounds.append(conv.sep.join(rounds[conv_idx:conv_idx + 2]))
|
| 479 |
+
cur_len = 0
|
| 480 |
+
target[:cur_len] = IGNORE_INDEX
|
| 481 |
+
for i, rou in enumerate(re_rounds):
|
| 482 |
+
if rou == "":
|
| 483 |
+
break
|
| 484 |
+
|
| 485 |
+
parts = rou.split(sep)
|
| 486 |
+
if len(parts) != 2:
|
| 487 |
+
break
|
| 488 |
+
parts[0] += sep
|
| 489 |
+
|
| 490 |
+
if has_image:
|
| 491 |
+
round_len = len(tokenizer_image_token(rou, tokenizer)) + 1
|
| 492 |
+
instruction_len = len(tokenizer_image_token(parts[0], tokenizer))
|
| 493 |
+
else:
|
| 494 |
+
round_len = len(tokenizer(rou).input_ids) + 1
|
| 495 |
+
instruction_len = len(tokenizer(parts[0]).input_ids)
|
| 496 |
+
|
| 497 |
+
if i > 0:
|
| 498 |
+
round_len -= 1
|
| 499 |
+
instruction_len -= 1
|
| 500 |
+
|
| 501 |
+
target[cur_len: cur_len + instruction_len] = IGNORE_INDEX
|
| 502 |
+
|
| 503 |
+
cur_len += round_len
|
| 504 |
+
target[cur_len:] = IGNORE_INDEX
|
| 505 |
+
|
| 506 |
+
if cur_len < tokenizer.model_max_length:
|
| 507 |
+
if cur_len != total_len:
|
| 508 |
+
target[:] = IGNORE_INDEX
|
| 509 |
+
print(
|
| 510 |
+
f"WARNING: tokenization mismatch: {cur_len} vs. {total_len}."
|
| 511 |
+
f" (ignored)"
|
| 512 |
+
)
|
| 513 |
+
|
| 514 |
+
return dict(
|
| 515 |
+
input_ids=input_ids,
|
| 516 |
+
labels=targets,
|
| 517 |
+
)
|
| 518 |
+
|
| 519 |
+
|
| 520 |
+
def preprocess_v1(
|
| 521 |
+
sources,
|
| 522 |
+
tokenizer: transformers.PreTrainedTokenizer,
|
| 523 |
+
has_image: bool = False
|
| 524 |
+
) -> Dict:
|
| 525 |
+
conv = conversation_lib.default_conversation.copy()
|
| 526 |
+
roles = {"human": conv.roles[0], "gpt": conv.roles[1]}
|
| 527 |
+
|
| 528 |
+
# Apply prompt templates
|
| 529 |
+
conversations = []
|
| 530 |
+
for i, source in enumerate(sources):
|
| 531 |
+
if roles[source[0]["from"]] != conv.roles[0]:
|
| 532 |
+
# Skip the first one if it is not from human
|
| 533 |
+
source = source[1:]
|
| 534 |
+
|
| 535 |
+
conv.messages = []
|
| 536 |
+
for j, sentence in enumerate(source):
|
| 537 |
+
role = roles[sentence["from"]]
|
| 538 |
+
assert role == conv.roles[j % 2], f"{i}"
|
| 539 |
+
conv.append_message(role, sentence["value"])
|
| 540 |
+
conversations.append(conv.get_prompt())
|
| 541 |
+
|
| 542 |
+
# Tokenize conversations
|
| 543 |
+
if has_image:
|
| 544 |
+
input_ids = torch.stack([tokenizer_image_token(prompt, tokenizer, return_tensors='pt') for prompt in conversations], dim=0)
|
| 545 |
+
else:
|
| 546 |
+
input_ids = tokenizer(
|
| 547 |
+
conversations,
|
| 548 |
+
return_tensors="pt",
|
| 549 |
+
padding="longest",
|
| 550 |
+
max_length=tokenizer.model_max_length,
|
| 551 |
+
truncation=True,
|
| 552 |
+
).input_ids
|
| 553 |
+
|
| 554 |
+
targets = input_ids.clone()
|
| 555 |
+
|
| 556 |
+
assert conv.sep_style == conversation_lib.SeparatorStyle.TWO
|
| 557 |
+
|
| 558 |
+
# Mask targets
|
| 559 |
+
sep = conv.sep + conv.roles[1] + ": "
|
| 560 |
+
for conversation, target in zip(conversations, targets):
|
| 561 |
+
total_len = int(target.ne(tokenizer.pad_token_id).sum())
|
| 562 |
+
|
| 563 |
+
rounds = conversation.split(conv.sep2)
|
| 564 |
+
cur_len = 1
|
| 565 |
+
target[:cur_len] = IGNORE_INDEX
|
| 566 |
+
for i, rou in enumerate(rounds):
|
| 567 |
+
if rou == "":
|
| 568 |
+
break
|
| 569 |
+
|
| 570 |
+
parts = rou.split(sep)
|
| 571 |
+
if len(parts) != 2:
|
| 572 |
+
break
|
| 573 |
+
parts[0] += sep
|
| 574 |
+
|
| 575 |
+
if has_image:
|
| 576 |
+
round_len = len(tokenizer_image_token(rou, tokenizer))
|
| 577 |
+
instruction_len = len(tokenizer_image_token(parts[0], tokenizer)) - 2
|
| 578 |
+
else:
|
| 579 |
+
round_len = len(tokenizer(rou).input_ids)
|
| 580 |
+
instruction_len = len(tokenizer(parts[0]).input_ids) - 2 # till the last token of user input
|
| 581 |
+
|
| 582 |
+
if i != 0 and not tokenizer.legacy and IS_TOKENIZER_GREATER_THAN_0_14:
|
| 583 |
+
round_len -= 1
|
| 584 |
+
instruction_len -= 1
|
| 585 |
+
|
| 586 |
+
target[cur_len : cur_len + instruction_len] = IGNORE_INDEX
|
| 587 |
+
|
| 588 |
+
cur_len += round_len
|
| 589 |
+
target[cur_len:] = IGNORE_INDEX
|
| 590 |
+
|
| 591 |
+
if cur_len < tokenizer.model_max_length:
|
| 592 |
+
if cur_len != total_len:
|
| 593 |
+
target[:] = IGNORE_INDEX
|
| 594 |
+
print(
|
| 595 |
+
f"WARNING: tokenization mismatch: {cur_len} vs. {total_len}."
|
| 596 |
+
f" (ignored)"
|
| 597 |
+
)
|
| 598 |
+
|
| 599 |
+
return dict(
|
| 600 |
+
input_ids=input_ids,
|
| 601 |
+
labels=targets,
|
| 602 |
+
)
|
| 603 |
+
|
| 604 |
+
|
| 605 |
+
def preprocess_mpt(
|
| 606 |
+
sources,
|
| 607 |
+
tokenizer: transformers.PreTrainedTokenizer,
|
| 608 |
+
has_image: bool = False
|
| 609 |
+
) -> Dict:
|
| 610 |
+
conv = conversation_lib.default_conversation.copy()
|
| 611 |
+
roles = {"human": conv.roles[0], "gpt": conv.roles[1]}
|
| 612 |
+
|
| 613 |
+
# Apply prompt templates
|
| 614 |
+
conversations = []
|
| 615 |
+
for i, source in enumerate(sources):
|
| 616 |
+
if roles[source[0]["from"]] != conv.roles[0]:
|
| 617 |
+
# Skip the first one if it is not from human
|
| 618 |
+
source = source[1:]
|
| 619 |
+
|
| 620 |
+
conv.messages = []
|
| 621 |
+
for j, sentence in enumerate(source):
|
| 622 |
+
role = roles[sentence["from"]]
|
| 623 |
+
assert role == conv.roles[j % 2], f"{i}"
|
| 624 |
+
conv.append_message(role, sentence["value"])
|
| 625 |
+
conversations.append(conv.get_prompt())
|
| 626 |
+
|
| 627 |
+
# Tokenize conversations
|
| 628 |
+
|
| 629 |
+
if has_image:
|
| 630 |
+
input_ids = torch.stack([tokenizer_image_token(prompt, tokenizer, return_tensors='pt') for prompt in conversations], dim=0)
|
| 631 |
+
else:
|
| 632 |
+
input_ids = tokenizer(
|
| 633 |
+
conversations,
|
| 634 |
+
return_tensors="pt",
|
| 635 |
+
padding="longest",
|
| 636 |
+
max_length=tokenizer.model_max_length,
|
| 637 |
+
truncation=True,
|
| 638 |
+
).input_ids
|
| 639 |
+
|
| 640 |
+
targets = input_ids.clone()
|
| 641 |
+
assert conv.sep_style == conversation_lib.SeparatorStyle.MPT
|
| 642 |
+
|
| 643 |
+
# Mask targets
|
| 644 |
+
sep = conv.sep + conv.roles[1]
|
| 645 |
+
for conversation, target in zip(conversations, targets):
|
| 646 |
+
total_len = int(target.ne(tokenizer.pad_token_id).sum())
|
| 647 |
+
|
| 648 |
+
rounds = conversation.split(conv.sep)
|
| 649 |
+
re_rounds = [conv.sep.join(rounds[:3])] # system + user + gpt
|
| 650 |
+
for conv_idx in range(3, len(rounds), 2):
|
| 651 |
+
re_rounds.append(conv.sep.join(rounds[conv_idx:conv_idx+2])) # user + gpt
|
| 652 |
+
cur_len = 0
|
| 653 |
+
target[:cur_len] = IGNORE_INDEX
|
| 654 |
+
for i, rou in enumerate(re_rounds):
|
| 655 |
+
if rou == "":
|
| 656 |
+
break
|
| 657 |
+
|
| 658 |
+
parts = rou.split(sep)
|
| 659 |
+
if len(parts) != 2:
|
| 660 |
+
break
|
| 661 |
+
parts[0] += sep
|
| 662 |
+
|
| 663 |
+
if has_image:
|
| 664 |
+
round_len = len(tokenizer_image_token(rou, tokenizer))
|
| 665 |
+
instruction_len = len(tokenizer_image_token(parts[0], tokenizer)) - 1
|
| 666 |
+
else:
|
| 667 |
+
round_len = len(tokenizer(rou).input_ids)
|
| 668 |
+
instruction_len = len(tokenizer(parts[0]).input_ids) - 1
|
| 669 |
+
|
| 670 |
+
if i != 0 and getattr(tokenizer, 'legacy', False) and IS_TOKENIZER_GREATER_THAN_0_14:
|
| 671 |
+
round_len += 1
|
| 672 |
+
instruction_len += 1
|
| 673 |
+
|
| 674 |
+
target[cur_len : cur_len + instruction_len] = IGNORE_INDEX
|
| 675 |
+
|
| 676 |
+
cur_len += round_len
|
| 677 |
+
target[cur_len:] = IGNORE_INDEX
|
| 678 |
+
|
| 679 |
+
if cur_len < tokenizer.model_max_length:
|
| 680 |
+
if cur_len != total_len:
|
| 681 |
+
target[:] = IGNORE_INDEX
|
| 682 |
+
print(
|
| 683 |
+
f"WARNING: tokenization mismatch: {cur_len} vs. {total_len}."
|
| 684 |
+
f" (ignored)"
|
| 685 |
+
)
|
| 686 |
+
|
| 687 |
+
return dict(
|
| 688 |
+
input_ids=input_ids,
|
| 689 |
+
labels=targets,
|
| 690 |
+
)
|
| 691 |
+
|
| 692 |
+
|
| 693 |
+
def preprocess_yi34b_chatml(
|
| 694 |
+
sources,
|
| 695 |
+
tokenizer: transformers.PreTrainedTokenizer,
|
| 696 |
+
has_image: bool = False
|
| 697 |
+
) -> Dict:
|
| 698 |
+
conv = conversation_lib.default_conversation.copy()
|
| 699 |
+
roles = {"human": conv.roles[0], "gpt": conv.roles[1]}
|
| 700 |
+
|
| 701 |
+
# Apply prompt templates
|
| 702 |
+
conversations = []
|
| 703 |
+
for i, source in enumerate(sources):
|
| 704 |
+
if roles[source[0]["from"]] != conv.roles[0]:
|
| 705 |
+
# Skip the first one if it is not from human
|
| 706 |
+
source = source[1:]
|
| 707 |
+
|
| 708 |
+
conv.messages = []
|
| 709 |
+
for j, sentence in enumerate(source):
|
| 710 |
+
role = roles[sentence["from"]]
|
| 711 |
+
assert role == conv.roles[j % 2], f"{i}"
|
| 712 |
+
conv.append_message(role, sentence["value"])
|
| 713 |
+
conversations.append(conv.get_prompt())
|
| 714 |
+
|
| 715 |
+
# Tokenize conversations
|
| 716 |
+
|
| 717 |
+
if has_image:
|
| 718 |
+
input_ids = torch.stack([tokenizer_image_token(prompt, tokenizer, return_tensors='pt') for prompt in conversations], dim=0)
|
| 719 |
+
else:
|
| 720 |
+
input_ids = tokenizer(
|
| 721 |
+
conversations,
|
| 722 |
+
return_tensors="pt",
|
| 723 |
+
padding="longest",
|
| 724 |
+
max_length=tokenizer.model_max_length,
|
| 725 |
+
truncation=True,
|
| 726 |
+
).input_ids
|
| 727 |
+
|
| 728 |
+
targets = input_ids.clone()
|
| 729 |
+
assert conv.sep_style == conversation_lib.SeparatorStyle.MPT
|
| 730 |
+
|
| 731 |
+
# Mask targets
|
| 732 |
+
sep = conv.sep + conv.roles[1]
|
| 733 |
+
for conversation, target in zip(conversations, targets):
|
| 734 |
+
total_len = int(target.ne(tokenizer.pad_token_id).sum())
|
| 735 |
+
|
| 736 |
+
rounds = conversation.split(conv.sep)
|
| 737 |
+
re_rounds = [conv.sep.join(rounds[:3])] # system + user + gpt
|
| 738 |
+
for conv_idx in range(3, len(rounds), 2):
|
| 739 |
+
re_rounds.append(conv.sep.join(rounds[conv_idx:conv_idx+2])) # user + gpt
|
| 740 |
+
cur_len = 0
|
| 741 |
+
target[:cur_len] = IGNORE_INDEX
|
| 742 |
+
for i, rou in enumerate(re_rounds):
|
| 743 |
+
if rou == "":
|
| 744 |
+
break
|
| 745 |
+
|
| 746 |
+
parts = rou.split(sep)
|
| 747 |
+
if len(parts) != 2:
|
| 748 |
+
break
|
| 749 |
+
parts[0] += sep
|
| 750 |
+
|
| 751 |
+
if has_image:
|
| 752 |
+
round_len = len(tokenizer_image_token(rou, tokenizer))
|
| 753 |
+
instruction_len = len(tokenizer_image_token(parts[0], tokenizer)) - 1
|
| 754 |
+
else:
|
| 755 |
+
round_len = len(tokenizer(rou).input_ids)
|
| 756 |
+
instruction_len = len(tokenizer(parts[0]).input_ids) - 1
|
| 757 |
+
|
| 758 |
+
# minigemini
|
| 759 |
+
if getattr(tokenizer, 'legacy', False) and IS_TOKENIZER_GREATER_THAN_0_14:
|
| 760 |
+
# if i != 0 and getattr(tokenizer, 'legacy', False) and IS_TOKENIZER_GREATER_THAN_0_14:
|
| 761 |
+
round_len += 1
|
| 762 |
+
instruction_len += 1
|
| 763 |
+
|
| 764 |
+
target[cur_len : cur_len + instruction_len] = IGNORE_INDEX
|
| 765 |
+
|
| 766 |
+
cur_len += round_len
|
| 767 |
+
target[cur_len:] = IGNORE_INDEX
|
| 768 |
+
|
| 769 |
+
if cur_len < tokenizer.model_max_length:
|
| 770 |
+
if cur_len != total_len:
|
| 771 |
+
target[:] = IGNORE_INDEX
|
| 772 |
+
print(
|
| 773 |
+
f"WARNING: tokenization mismatch: {cur_len} vs. {total_len}."
|
| 774 |
+
f" (ignored)"
|
| 775 |
+
)
|
| 776 |
+
|
| 777 |
+
return dict(
|
| 778 |
+
input_ids=input_ids,
|
| 779 |
+
labels=targets,
|
| 780 |
+
)
|
| 781 |
+
|
| 782 |
+
|
| 783 |
+
def preprocess_plain(
|
| 784 |
+
sources: Sequence[str],
|
| 785 |
+
tokenizer: transformers.PreTrainedTokenizer,
|
| 786 |
+
) -> Dict:
|
| 787 |
+
# add end signal and concatenate together
|
| 788 |
+
conversations = []
|
| 789 |
+
for source in sources:
|
| 790 |
+
assert len(source) == 2
|
| 791 |
+
assert DEFAULT_IMAGE_TOKEN in source[0]['value']
|
| 792 |
+
source[0]['value'] = DEFAULT_IMAGE_TOKEN
|
| 793 |
+
conversation = source[0]['value'] + source[1]['value'] + conversation_lib.default_conversation.sep
|
| 794 |
+
conversations.append(conversation)
|
| 795 |
+
# tokenize conversations
|
| 796 |
+
input_ids = [tokenizer_image_token(prompt, tokenizer, return_tensors='pt') for prompt in conversations]
|
| 797 |
+
targets = copy.deepcopy(input_ids)
|
| 798 |
+
for target, source in zip(targets, sources):
|
| 799 |
+
tokenized_len = len(tokenizer_image_token(source[0]['value'], tokenizer))
|
| 800 |
+
target[:tokenized_len] = IGNORE_INDEX
|
| 801 |
+
|
| 802 |
+
return dict(input_ids=input_ids, labels=targets)
|
| 803 |
+
|
| 804 |
+
|
| 805 |
+
def preprocess(
|
| 806 |
+
sources: Sequence[str],
|
| 807 |
+
tokenizer: transformers.PreTrainedTokenizer,
|
| 808 |
+
has_image: bool = False
|
| 809 |
+
) -> Dict:
|
| 810 |
+
"""
|
| 811 |
+
Given a list of sources, each is a conversation list. This transform:
|
| 812 |
+
1. Add signal '### ' at the beginning each sentence, with end signal '\n';
|
| 813 |
+
2. Concatenate conversations together;
|
| 814 |
+
3. Tokenize the concatenated conversation;
|
| 815 |
+
4. Make a deepcopy as the target. Mask human words with IGNORE_INDEX.
|
| 816 |
+
"""
|
| 817 |
+
if conversation_lib.default_conversation.sep_style == conversation_lib.SeparatorStyle.PLAIN:
|
| 818 |
+
return preprocess_plain(sources, tokenizer)
|
| 819 |
+
if conversation_lib.default_conversation.sep_style == conversation_lib.SeparatorStyle.LLAMA_2:
|
| 820 |
+
return preprocess_llama_2(sources, tokenizer, has_image=has_image)
|
| 821 |
+
if conversation_lib.default_conversation.version.startswith("v1"):
|
| 822 |
+
return preprocess_v1(sources, tokenizer, has_image=has_image)
|
| 823 |
+
if conversation_lib.default_conversation.version == "llama3":
|
| 824 |
+
return preprocess_llama_3(sources, tokenizer, has_image=has_image)
|
| 825 |
+
if conversation_lib.default_conversation.version == "mpt-yi-34b":
|
| 826 |
+
return preprocess_yi34b_chatml(sources, tokenizer, has_image=has_image)
|
| 827 |
+
if conversation_lib.default_conversation.version == "mpt":
|
| 828 |
+
return preprocess_mpt(sources, tokenizer, has_image=has_image)
|
| 829 |
+
# add end signal and concatenate together
|
| 830 |
+
conversations = []
|
| 831 |
+
for source in sources:
|
| 832 |
+
header = f"{conversation_lib.default_conversation.system}\n\n"
|
| 833 |
+
conversation = _add_speaker_and_signal(header, source)
|
| 834 |
+
conversations.append(conversation)
|
| 835 |
+
# tokenize conversations
|
| 836 |
+
def get_tokenize_len(prompts):
|
| 837 |
+
return [len(tokenizer_image_token(prompt, tokenizer)) for prompt in prompts]
|
| 838 |
+
|
| 839 |
+
if has_image:
|
| 840 |
+
input_ids = [tokenizer_image_token(prompt, tokenizer, return_tensors='pt') for prompt in conversations]
|
| 841 |
+
else:
|
| 842 |
+
conversations_tokenized = _tokenize_fn(conversations, tokenizer)
|
| 843 |
+
input_ids = conversations_tokenized["input_ids"]
|
| 844 |
+
|
| 845 |
+
targets = copy.deepcopy(input_ids)
|
| 846 |
+
for target, source in zip(targets, sources):
|
| 847 |
+
if has_image:
|
| 848 |
+
tokenized_lens = get_tokenize_len([header] + [s["value"] for s in source])
|
| 849 |
+
else:
|
| 850 |
+
tokenized_lens = _tokenize_fn([header] + [s["value"] for s in source], tokenizer)["input_ids_lens"]
|
| 851 |
+
speakers = [sentence["from"] for sentence in source]
|
| 852 |
+
_mask_targets(target, tokenized_lens, speakers)
|
| 853 |
+
|
| 854 |
+
return dict(input_ids=input_ids, labels=targets)
|
| 855 |
+
|
| 856 |
+
|
| 857 |
+
class LazySupervisedDataset(Dataset):
|
| 858 |
+
"""Dataset for supervised fine-tuning."""
|
| 859 |
+
|
| 860 |
+
def __init__(self, data_path: str,
|
| 861 |
+
tokenizer: transformers.PreTrainedTokenizer,
|
| 862 |
+
data_args: DataArguments):
|
| 863 |
+
super(LazySupervisedDataset, self).__init__()
|
| 864 |
+
list_data_dict = json.load(open(data_path, "r"))
|
| 865 |
+
|
| 866 |
+
rank0_print("Formatting inputs...Skip in lazy mode")
|
| 867 |
+
self.tokenizer = tokenizer
|
| 868 |
+
self.list_data_dict = list_data_dict
|
| 869 |
+
self.data_args = data_args
|
| 870 |
+
|
| 871 |
+
def __len__(self):
|
| 872 |
+
return len(self.list_data_dict)
|
| 873 |
+
|
| 874 |
+
@property
|
| 875 |
+
def lengths(self):
|
| 876 |
+
length_list = []
|
| 877 |
+
for sample in self.list_data_dict:
|
| 878 |
+
img_tokens = 128 if 'image' in sample else 0
|
| 879 |
+
length_list.append(sum(len(conv['value'].split()) for conv in sample['conversations']) + img_tokens)
|
| 880 |
+
return length_list
|
| 881 |
+
|
| 882 |
+
@property
|
| 883 |
+
def modality_lengths(self):
|
| 884 |
+
length_list = []
|
| 885 |
+
for sample in self.list_data_dict:
|
| 886 |
+
cur_len = sum(len(conv['value'].split()) for conv in sample['conversations'])
|
| 887 |
+
cur_len = cur_len if 'image' in sample else -cur_len
|
| 888 |
+
length_list.append(cur_len)
|
| 889 |
+
return length_list
|
| 890 |
+
|
| 891 |
+
def __getitem__(self, i) -> Dict[str, torch.Tensor]:
|
| 892 |
+
sources = self.list_data_dict[i]
|
| 893 |
+
if isinstance(i, int):
|
| 894 |
+
sources = [sources]
|
| 895 |
+
assert len(sources) == 1, "Don't know why it is wrapped to a list" # FIXME
|
| 896 |
+
if 'image' in sources[0]:
|
| 897 |
+
image_file = self.list_data_dict[i]['image']
|
| 898 |
+
image_folder = self.data_args.image_folder
|
| 899 |
+
processor = self.data_args.image_processor
|
| 900 |
+
try:
|
| 901 |
+
image = Image.open(os.path.join(image_folder, image_file)).convert('RGB')
|
| 902 |
+
except:
|
| 903 |
+
print(f'image file {os.path.join(image_folder, image_file)} broken.., using a dummy black image instead')
|
| 904 |
+
image = Image.fromarray(np.zeros((224,224,3), dtype=np.uint8))
|
| 905 |
+
if self.data_args.image_aspect_ratio == 'pad':
|
| 906 |
+
def expand2square(pil_img, background_color):
|
| 907 |
+
width, height = pil_img.size
|
| 908 |
+
if width == height:
|
| 909 |
+
return pil_img
|
| 910 |
+
elif width > height:
|
| 911 |
+
result = Image.new(pil_img.mode, (width, width), background_color)
|
| 912 |
+
result.paste(pil_img, (0, (width - height) // 2))
|
| 913 |
+
return result
|
| 914 |
+
else:
|
| 915 |
+
result = Image.new(pil_img.mode, (height, height), background_color)
|
| 916 |
+
result.paste(pil_img, ((height - width) // 2, 0))
|
| 917 |
+
return result
|
| 918 |
+
image = expand2square(image, tuple(int(x*255) for x in processor.image_mean))
|
| 919 |
+
image = processor.preprocess(image, return_tensors='pt')['pixel_values'][0]
|
| 920 |
+
else:
|
| 921 |
+
image = processor.preprocess(image, return_tensors='pt')['pixel_values'][0]
|
| 922 |
+
sources = preprocess_multimodal(
|
| 923 |
+
copy.deepcopy([e["conversations"] for e in sources]),
|
| 924 |
+
self.data_args)
|
| 925 |
+
else:
|
| 926 |
+
sources = copy.deepcopy([e["conversations"] for e in sources])
|
| 927 |
+
data_dict = preprocess(
|
| 928 |
+
sources,
|
| 929 |
+
self.tokenizer,
|
| 930 |
+
has_image=('image' in self.list_data_dict[i]))
|
| 931 |
+
if isinstance(i, int):
|
| 932 |
+
data_dict = dict(input_ids=data_dict["input_ids"][0],
|
| 933 |
+
labels=data_dict["labels"][0])
|
| 934 |
+
|
| 935 |
+
# image exist in the data
|
| 936 |
+
if 'image' in self.list_data_dict[i]:
|
| 937 |
+
data_dict['image'] = image
|
| 938 |
+
elif self.data_args.is_multimodal:
|
| 939 |
+
# image does not exist in the data, but the model is multimodal
|
| 940 |
+
crop_size = self.data_args.image_processor.crop_size
|
| 941 |
+
data_dict['image'] = torch.zeros(3, crop_size['height'], crop_size['width'])
|
| 942 |
+
return data_dict
|
| 943 |
+
|
| 944 |
+
|
| 945 |
+
@dataclass
|
| 946 |
+
class DataCollatorForSupervisedDataset(object):
|
| 947 |
+
"""Collate examples for supervised fine-tuning."""
|
| 948 |
+
|
| 949 |
+
tokenizer: transformers.PreTrainedTokenizer
|
| 950 |
+
|
| 951 |
+
def __call__(self, instances: Sequence[Dict]) -> Dict[str, torch.Tensor]:
|
| 952 |
+
input_ids, labels = tuple([instance[key] for instance in instances]
|
| 953 |
+
for key in ("input_ids", "labels"))
|
| 954 |
+
input_ids = torch.nn.utils.rnn.pad_sequence(
|
| 955 |
+
input_ids,
|
| 956 |
+
batch_first=True,
|
| 957 |
+
padding_value=self.tokenizer.pad_token_id)
|
| 958 |
+
labels = torch.nn.utils.rnn.pad_sequence(labels,
|
| 959 |
+
batch_first=True,
|
| 960 |
+
padding_value=IGNORE_INDEX)
|
| 961 |
+
input_ids = input_ids[:, :self.tokenizer.model_max_length]
|
| 962 |
+
labels = labels[:, :self.tokenizer.model_max_length]
|
| 963 |
+
batch = dict(
|
| 964 |
+
input_ids=input_ids,
|
| 965 |
+
labels=labels,
|
| 966 |
+
attention_mask=input_ids.ne(self.tokenizer.pad_token_id),
|
| 967 |
+
)
|
| 968 |
+
|
| 969 |
+
if 'image' in instances[0]:
|
| 970 |
+
images = [instance['image'] for instance in instances]
|
| 971 |
+
if all(x is not None and x.shape == images[0].shape for x in images):
|
| 972 |
+
batch['images'] = torch.stack(images)
|
| 973 |
+
else:
|
| 974 |
+
batch['images'] = images
|
| 975 |
+
|
| 976 |
+
return batch
|
| 977 |
+
|
| 978 |
+
|
| 979 |
+
def make_supervised_data_module(tokenizer: transformers.PreTrainedTokenizer,
|
| 980 |
+
data_args) -> Dict:
|
| 981 |
+
"""Make dataset and collator for supervised fine-tuning."""
|
| 982 |
+
train_dataset = LazySupervisedDataset(tokenizer=tokenizer,
|
| 983 |
+
data_path=data_args.data_path,
|
| 984 |
+
data_args=data_args)
|
| 985 |
+
data_collator = DataCollatorForSupervisedDataset(tokenizer=tokenizer)
|
| 986 |
+
return dict(train_dataset=train_dataset,
|
| 987 |
+
eval_dataset=None,
|
| 988 |
+
data_collator=data_collator)
|
| 989 |
+
|
| 990 |
+
|
| 991 |
+
def train(attn_implementation=None):
|
| 992 |
+
global local_rank
|
| 993 |
+
|
| 994 |
+
parser = transformers.HfArgumentParser(
|
| 995 |
+
(ModelArguments, DataArguments, TrainingArguments))
|
| 996 |
+
model_args, data_args, training_args = parser.parse_args_into_dataclasses()
|
| 997 |
+
local_rank = training_args.local_rank
|
| 998 |
+
compute_dtype = (torch.float16 if training_args.fp16 else (torch.bfloat16 if training_args.bf16 else torch.float32))
|
| 999 |
+
|
| 1000 |
+
|
| 1001 |
+
bnb_model_from_pretrained_args = {}
|
| 1002 |
+
if training_args.bits in [4, 8]:
|
| 1003 |
+
from transformers import BitsAndBytesConfig
|
| 1004 |
+
bnb_model_from_pretrained_args.update(dict(
|
| 1005 |
+
device_map={"": training_args.device},
|
| 1006 |
+
load_in_4bit=training_args.bits == 4,
|
| 1007 |
+
load_in_8bit=training_args.bits == 8,
|
| 1008 |
+
quantization_config=BitsAndBytesConfig(
|
| 1009 |
+
load_in_4bit=training_args.bits == 4,
|
| 1010 |
+
load_in_8bit=training_args.bits == 8,
|
| 1011 |
+
llm_int8_skip_modules=["mm_projector"],
|
| 1012 |
+
llm_int8_threshold=6.0,
|
| 1013 |
+
llm_int8_has_fp16_weight=False,
|
| 1014 |
+
bnb_4bit_compute_dtype=compute_dtype,
|
| 1015 |
+
bnb_4bit_use_double_quant=training_args.double_quant,
|
| 1016 |
+
bnb_4bit_quant_type=training_args.quant_type # {'fp4', 'nf4'}
|
| 1017 |
+
)
|
| 1018 |
+
))
|
| 1019 |
+
|
| 1020 |
+
if model_args.vision_tower is not None:
|
| 1021 |
+
model = EagleLlamaForCausalLM.from_pretrained(
|
| 1022 |
+
model_args.model_name_or_path,
|
| 1023 |
+
cache_dir=training_args.cache_dir,
|
| 1024 |
+
attn_implementation=attn_implementation,
|
| 1025 |
+
torch_dtype=(torch.bfloat16 if training_args.bf16 else None),
|
| 1026 |
+
**bnb_model_from_pretrained_args
|
| 1027 |
+
)
|
| 1028 |
+
else:
|
| 1029 |
+
model = transformers.LlamaForCausalLM.from_pretrained(
|
| 1030 |
+
model_args.model_name_or_path,
|
| 1031 |
+
cache_dir=training_args.cache_dir,
|
| 1032 |
+
attn_implementation=attn_implementation,
|
| 1033 |
+
torch_dtype=(torch.bfloat16 if training_args.bf16 else None),
|
| 1034 |
+
**bnb_model_from_pretrained_args
|
| 1035 |
+
)
|
| 1036 |
+
model.config.use_cache = False
|
| 1037 |
+
|
| 1038 |
+
if model_args.freeze_backbone:
|
| 1039 |
+
model.model.requires_grad_(False)
|
| 1040 |
+
|
| 1041 |
+
if training_args.bits in [4, 8]:
|
| 1042 |
+
from peft import prepare_model_for_kbit_training
|
| 1043 |
+
model.config.torch_dtype=(torch.float32 if training_args.fp16 else (torch.bfloat16 if training_args.bf16 else torch.float32))
|
| 1044 |
+
model = prepare_model_for_kbit_training(model, use_gradient_checkpointing=training_args.gradient_checkpointing)
|
| 1045 |
+
|
| 1046 |
+
if training_args.gradient_checkpointing:
|
| 1047 |
+
if hasattr(model, "enable_input_require_grads"):
|
| 1048 |
+
model.enable_input_require_grads()
|
| 1049 |
+
else:
|
| 1050 |
+
def make_inputs_require_grad(module, input, output):
|
| 1051 |
+
output.requires_grad_(True)
|
| 1052 |
+
model.get_input_embeddings().register_forward_hook(make_inputs_require_grad)
|
| 1053 |
+
|
| 1054 |
+
if training_args.lora_enable:
|
| 1055 |
+
from peft import LoraConfig, get_peft_model
|
| 1056 |
+
lora_config = LoraConfig(
|
| 1057 |
+
r=training_args.lora_r,
|
| 1058 |
+
lora_alpha=training_args.lora_alpha,
|
| 1059 |
+
target_modules=find_all_linear_names(model),
|
| 1060 |
+
lora_dropout=training_args.lora_dropout,
|
| 1061 |
+
bias=training_args.lora_bias,
|
| 1062 |
+
task_type="CAUSAL_LM",
|
| 1063 |
+
)
|
| 1064 |
+
if training_args.bits == 16:
|
| 1065 |
+
if training_args.bf16:
|
| 1066 |
+
model.to(torch.bfloat16)
|
| 1067 |
+
if training_args.fp16:
|
| 1068 |
+
model.to(torch.float16)
|
| 1069 |
+
rank0_print("Adding LoRA adapters...")
|
| 1070 |
+
model = get_peft_model(model, lora_config)
|
| 1071 |
+
|
| 1072 |
+
if 'mpt' in model_args.model_name_or_path:
|
| 1073 |
+
tokenizer = transformers.AutoTokenizer.from_pretrained(
|
| 1074 |
+
model_args.model_name_or_path,
|
| 1075 |
+
cache_dir=training_args.cache_dir,
|
| 1076 |
+
model_max_length=training_args.model_max_length,
|
| 1077 |
+
padding_side="right"
|
| 1078 |
+
)
|
| 1079 |
+
else:
|
| 1080 |
+
tokenizer = transformers.AutoTokenizer.from_pretrained(
|
| 1081 |
+
model_args.model_name_or_path,
|
| 1082 |
+
cache_dir=training_args.cache_dir,
|
| 1083 |
+
model_max_length=training_args.model_max_length,
|
| 1084 |
+
padding_side="right",
|
| 1085 |
+
use_fast=False,
|
| 1086 |
+
)
|
| 1087 |
+
|
| 1088 |
+
if model_args.version == "v0":
|
| 1089 |
+
if tokenizer.pad_token is None:
|
| 1090 |
+
smart_tokenizer_and_embedding_resize(
|
| 1091 |
+
special_tokens_dict=dict(pad_token="[PAD]"),
|
| 1092 |
+
tokenizer=tokenizer,
|
| 1093 |
+
model=model,
|
| 1094 |
+
)
|
| 1095 |
+
elif model_args.version == "v0.5":
|
| 1096 |
+
tokenizer.pad_token = tokenizer.unk_token
|
| 1097 |
+
else:
|
| 1098 |
+
tokenizer.pad_token = tokenizer.unk_token
|
| 1099 |
+
if model_args.version in conversation_lib.conv_templates:
|
| 1100 |
+
conversation_lib.default_conversation = conversation_lib.conv_templates[model_args.version]
|
| 1101 |
+
else:
|
| 1102 |
+
conversation_lib.default_conversation = conversation_lib.conv_templates["vicuna_v1"]
|
| 1103 |
+
|
| 1104 |
+
# TODO, test here
|
| 1105 |
+
if tokenizer.pad_token is None:
|
| 1106 |
+
print(f"Adding pad token as '<pad>'")
|
| 1107 |
+
smart_tokenizer_and_embedding_resize(
|
| 1108 |
+
special_tokens_dict=dict(pad_token="<pad>"),
|
| 1109 |
+
tokenizer=tokenizer,
|
| 1110 |
+
model=model,
|
| 1111 |
+
)
|
| 1112 |
+
|
| 1113 |
+
if model_args.vision_tower is not None:
|
| 1114 |
+
model.get_model().initialize_vision_modules(
|
| 1115 |
+
model_args=model_args,
|
| 1116 |
+
fsdp=training_args.fsdp
|
| 1117 |
+
)
|
| 1118 |
+
|
| 1119 |
+
vision_tower = model.get_vision_tower()
|
| 1120 |
+
vision_tower.to(dtype=torch.bfloat16 if training_args.bf16 else torch.float16, device=training_args.device)
|
| 1121 |
+
|
| 1122 |
+
data_args.image_processor = vision_tower.image_processor
|
| 1123 |
+
data_args.is_multimodal = True
|
| 1124 |
+
|
| 1125 |
+
model.config.image_aspect_ratio = data_args.image_aspect_ratio
|
| 1126 |
+
model.config.tokenizer_padding_side = tokenizer.padding_side
|
| 1127 |
+
model.config.tokenizer_model_max_length = tokenizer.model_max_length
|
| 1128 |
+
|
| 1129 |
+
model.config.tune_mm_mlp_adapter = training_args.tune_mm_mlp_adapter = model_args.tune_mm_mlp_adapter
|
| 1130 |
+
if model_args.tune_mm_mlp_adapter:
|
| 1131 |
+
model.requires_grad_(False)
|
| 1132 |
+
for p in model.get_model().mm_projector.parameters():
|
| 1133 |
+
p.requires_grad = True
|
| 1134 |
+
|
| 1135 |
+
model.config.freeze_mm_mlp_adapter = training_args.freeze_mm_mlp_adapter
|
| 1136 |
+
if training_args.freeze_mm_mlp_adapter:
|
| 1137 |
+
for p in model.get_model().mm_projector.parameters():
|
| 1138 |
+
p.requires_grad = False
|
| 1139 |
+
|
| 1140 |
+
if training_args.bits in [4, 8]:
|
| 1141 |
+
model.get_model().mm_projector.to(dtype=compute_dtype, device=training_args.device)
|
| 1142 |
+
|
| 1143 |
+
model.config.mm_use_im_start_end = data_args.mm_use_im_start_end = model_args.mm_use_im_start_end
|
| 1144 |
+
model.config.mm_projector_lr = training_args.mm_projector_lr
|
| 1145 |
+
training_args.use_im_start_end = model_args.mm_use_im_start_end
|
| 1146 |
+
model.config.mm_use_im_patch_token = model_args.mm_use_im_patch_token
|
| 1147 |
+
model.initialize_vision_tokenizer(model_args, tokenizer=tokenizer)
|
| 1148 |
+
|
| 1149 |
+
for name, param in model.named_parameters():
|
| 1150 |
+
if 'align_stages' in name:
|
| 1151 |
+
param.requires_grad = True
|
| 1152 |
+
|
| 1153 |
+
if training_args.bits in [4, 8]:
|
| 1154 |
+
from peft.tuners.lora import LoraLayer
|
| 1155 |
+
for name, module in model.named_modules():
|
| 1156 |
+
if isinstance(module, LoraLayer):
|
| 1157 |
+
if training_args.bf16:
|
| 1158 |
+
module = module.to(torch.bfloat16)
|
| 1159 |
+
if 'norm' in name:
|
| 1160 |
+
module = module.to(torch.float32)
|
| 1161 |
+
if 'lm_head' in name or 'embed_tokens' in name:
|
| 1162 |
+
if hasattr(module, 'weight'):
|
| 1163 |
+
if training_args.bf16 and module.weight.dtype == torch.float32:
|
| 1164 |
+
module = module.to(torch.bfloat16)
|
| 1165 |
+
|
| 1166 |
+
|
| 1167 |
+
data_module = make_supervised_data_module(tokenizer=tokenizer,
|
| 1168 |
+
data_args=data_args)
|
| 1169 |
+
trainer = EagleTrainer(model=model,
|
| 1170 |
+
tokenizer=tokenizer,
|
| 1171 |
+
args=training_args,
|
| 1172 |
+
**data_module)
|
| 1173 |
+
|
| 1174 |
+
if list(pathlib.Path(training_args.output_dir).glob("checkpoint-*")):
|
| 1175 |
+
trainer.train(resume_from_checkpoint=True)
|
| 1176 |
+
else:
|
| 1177 |
+
trainer.train()
|
| 1178 |
+
trainer.save_state()
|
| 1179 |
+
|
| 1180 |
+
model.config.use_cache = True
|
| 1181 |
+
|
| 1182 |
+
# if training_args.lora_enable:
|
| 1183 |
+
# state_dict = get_peft_state_maybe_zero_3(
|
| 1184 |
+
# model.named_parameters(), training_args.lora_bias
|
| 1185 |
+
# )
|
| 1186 |
+
# non_lora_state_dict = get_peft_state_non_lora_maybe_zero_3(
|
| 1187 |
+
# model.named_parameters()
|
| 1188 |
+
# )
|
| 1189 |
+
# if training_args.local_rank == 0 or training_args.local_rank == -1:
|
| 1190 |
+
# model.config.save_pretrained(training_args.output_dir)
|
| 1191 |
+
# model.save_pretrained(training_args.output_dir, state_dict=state_dict)
|
| 1192 |
+
# torch.save(non_lora_state_dict, os.path.join(training_args.output_dir, 'non_lora_trainables.bin'))
|
| 1193 |
+
# else:
|
| 1194 |
+
# safe_save_model_for_hf_trainer(trainer=trainer,
|
| 1195 |
+
# output_dir=training_args.output_dir)
|
| 1196 |
+
safe_save_model_for_hf_trainer(trainer=trainer,
|
| 1197 |
+
output_dir=training_args.output_dir)
|
| 1198 |
+
|
| 1199 |
+
|
| 1200 |
+
if __name__ == "__main__":
|
| 1201 |
+
train()
|
Groma/README.md
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<div align="center">
|
| 2 |
+
<h1> Groma: Grounded Multimodal Assistant </h1>
|
| 3 |
+
|
| 4 |
+
> [**Groma: Localized Visual Tokenization for Grounding Multimodal Large Language Models**](https://arxiv.org/abs/2404.13013)
|
| 5 |
+
> **Chuofan Ma, Yi Jiang, Jiannan Wu, Zehuan Yuan, Xiaojuan Qi**
|
| 6 |
+
>
|
| 7 |
+
><a href="https://arxiv.org/abs/2404.13013"><img src='https://img.shields.io/badge/arXiv-Groma-red' alt='Paper PDF'></a>
|
| 8 |
+
><a href='https://groma-mllm.github.io/'><img src='https://img.shields.io/badge/Project_Page-Groma-green' alt='Project Page'></a>
|
| 9 |
+
><a href='https://huggingface.co/FoundationVision/groma-7b-finetune'><img src='https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Model-blue'></a>
|
| 10 |
+
><a href='https://huggingface.co/datasets/FoundationVision/groma_instruct'><img src='https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Dataset-yellow'></a>
|
| 11 |
+
|
| 12 |
+
<img src='docs/teaser.png' align="center" width="80%">
|
| 13 |
+
<p align="left">Groma is an MLLM with exceptional region understanding and visual grounding capabilities. It can take user-defined region inputs (boxes) as well as generate long-form responses that are grounded to visual context.</p>
|
| 14 |
+
|
| 15 |
+
<img src='docs/paradigm.png' align="center" width="80%">
|
| 16 |
+
<p align="left">Groma presents a novel paradigm of grounded MLLMs. (a) LLM for localization (e.g., Kosmos-2, Shikra); (b) External modules for localization (e.g., Lisa); and (c) <b>Visual tokenier for localization (Groma)</b>.
|
| 17 |
+
|
| 18 |
+
</div>
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
## Contents
|
| 22 |
+
- [Install](#installation)
|
| 23 |
+
- [Model](#model-weights)
|
| 24 |
+
- [Data](#prepare-data)
|
| 25 |
+
- [Training](#training)
|
| 26 |
+
- [Inference](#inference)
|
| 27 |
+
- [Evaluation](#evaluation)
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
## Performance
|
| 32 |
+
State-of-the-art performance on referring expression comprehension (REC) benchmarks among multimodal
|
| 33 |
+
large language models.
|
| 34 |
+
|
| 35 |
+
<table>
|
| 36 |
+
<thead>
|
| 37 |
+
<tr>
|
| 38 |
+
<th rowspan="2">Method</th>
|
| 39 |
+
<th colspan="3">RefCOCO</th>
|
| 40 |
+
<th colspan="3">RefCOCO+</th>
|
| 41 |
+
<th colspan="2">RefCOCOg</th>
|
| 42 |
+
<th rowspan="2">Avergae</th>
|
| 43 |
+
</tr>
|
| 44 |
+
<tr>
|
| 45 |
+
<th>val</th>
|
| 46 |
+
<th>testA</th>
|
| 47 |
+
<th>testB</th>
|
| 48 |
+
<th>val</th>
|
| 49 |
+
<th>testA</th>
|
| 50 |
+
<th>testB</th>
|
| 51 |
+
<th>val</th>
|
| 52 |
+
<th>test</th>
|
| 53 |
+
</tr>
|
| 54 |
+
</thead>
|
| 55 |
+
<tbody>
|
| 56 |
+
<tr align="center">
|
| 57 |
+
<td>Shikra</td>
|
| 58 |
+
<td>87.01</td>
|
| 59 |
+
<td>90.61</td>
|
| 60 |
+
<td>80.24</td>
|
| 61 |
+
<td>81.60</td>
|
| 62 |
+
<td>87.36</td>
|
| 63 |
+
<td>72.12</td>
|
| 64 |
+
<td>82.27</td>
|
| 65 |
+
<td>82.19</td>
|
| 66 |
+
<td>82.93</td>
|
| 67 |
+
</tr>
|
| 68 |
+
<tr align="center">
|
| 69 |
+
<td>Ferret</td>
|
| 70 |
+
<td>87.49</td>
|
| 71 |
+
<td>91.35</td>
|
| 72 |
+
<td>82.45</td>
|
| 73 |
+
<td>80.78</td>
|
| 74 |
+
<td>87.38</td>
|
| 75 |
+
<td>73.14</td>
|
| 76 |
+
<td>83.93</td>
|
| 77 |
+
<td>84.76</td>
|
| 78 |
+
<td>83.91</td>
|
| 79 |
+
</tr>
|
| 80 |
+
<tr align="center">
|
| 81 |
+
<td>MiniGPT-v2</td>
|
| 82 |
+
<td>88.69</td>
|
| 83 |
+
<td>91.65</td>
|
| 84 |
+
<td>85.33</td>
|
| 85 |
+
<td>79.97</td>
|
| 86 |
+
<td>85.12</td>
|
| 87 |
+
<td>74.45</td>
|
| 88 |
+
<td>84.44</td>
|
| 89 |
+
<td>84.66</td>
|
| 90 |
+
<td>84.29</td>
|
| 91 |
+
</tr>
|
| 92 |
+
<tr align="center">
|
| 93 |
+
<td>Qwen-VL</td>
|
| 94 |
+
<td>89.36</td>
|
| 95 |
+
<td>92.26</td>
|
| 96 |
+
<td>85.34</td>
|
| 97 |
+
<td>83.12</td>
|
| 98 |
+
<td>88.25</td>
|
| 99 |
+
<td>77.21</td>
|
| 100 |
+
<td>85.58</td>
|
| 101 |
+
<td>85.48</td>
|
| 102 |
+
<td>85.83</td>
|
| 103 |
+
</tr>
|
| 104 |
+
<tr style="background-color: #ADD8E6;">
|
| 105 |
+
<th>Groma</th>
|
| 106 |
+
<th>89.53</th>
|
| 107 |
+
<th>92.09</th>
|
| 108 |
+
<th>86.26</th>
|
| 109 |
+
<th>83.90</th>
|
| 110 |
+
<th>88.91</th>
|
| 111 |
+
<th>78.05</th>
|
| 112 |
+
<th>86.37</th>
|
| 113 |
+
<th>87.01</th>
|
| 114 |
+
<th>86.52</th>
|
| 115 |
+
</tr>
|
| 116 |
+
</tbody>
|
| 117 |
+
</table>
|
| 118 |
+
|
| 119 |
+
## Installation
|
| 120 |
+
Clone the repository
|
| 121 |
+
~~~
|
| 122 |
+
git clone https://github.com/FoundationVision/Groma.git
|
| 123 |
+
cd Groma
|
| 124 |
+
~~~
|
| 125 |
+
|
| 126 |
+
Create the conda environment and install dependencies
|
| 127 |
+
~~~
|
| 128 |
+
conda create -n groma python=3.9 -y
|
| 129 |
+
conda activate groma
|
| 130 |
+
conda install pytorch==2.1.0 torchvision==0.16.0 torchaudio==2.1.0 pytorch-cuda=11.8 -c pytorch -c nvidia
|
| 131 |
+
pip install --upgrade pip # enable PEP 660 support
|
| 132 |
+
pip install -e .
|
| 133 |
+
|
| 134 |
+
cd mmcv
|
| 135 |
+
MMCV_WITH_OPS=1 pip install -e .
|
| 136 |
+
cd ..
|
| 137 |
+
~~~
|
| 138 |
+
|
| 139 |
+
Install falsh-attention for training
|
| 140 |
+
~~~
|
| 141 |
+
pip install ninja
|
| 142 |
+
pip install flash-attn --no-build-isolation
|
| 143 |
+
~~~
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
## Model Weights
|
| 147 |
+
To play with Groma, please download the [model weights](https://huggingface.co/FoundationVision/groma-7b-finetune) from huggingface.
|
| 148 |
+
|
| 149 |
+
We additionally provide pretrained checkpoints from intermediate training stages.
|
| 150 |
+
You can start from any point to customize training.
|
| 151 |
+
|
| 152 |
+
| Training stage | Required checkpoints |
|
| 153 |
+
|:--------------:|:--------------------:|
|
| 154 |
+
| Detection pretraining | [DINOv2-L](https://huggingface.co/facebook/dinov2-large) |
|
| 155 |
+
| Alignment pretraining | [Vicuna-7b-v1.5](https://huggingface.co/lmsys/vicuna-7b-v1.5), [Groma-det-pretrain](https://huggingface.co/FoundationVision/groma-det-pretrain) |
|
| 156 |
+
| Instruction finetuning | [Groma-7b-pretrain](https://huggingface.co/FoundationVision/groma-7b-pretrain) |
|
| 157 |
+
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
## Prepare Data
|
| 161 |
+
We provide instructions to download datasets used at different training stages of Groma,
|
| 162 |
+
including [Groma Instruct](https://huggingface.co/datasets/FoundationVision/groma_instruct/),
|
| 163 |
+
a 30k viusally grounded conversation dataset constructed with GPT-4V.
|
| 164 |
+
You don't have to download all of them unless you want to train Groma from scratch.
|
| 165 |
+
Please follow instructions in [DATA.md](docs/DATA.md) to prepare datasets.
|
| 166 |
+
|
| 167 |
+
<table>
|
| 168 |
+
<tr>
|
| 169 |
+
<th align="left">Training stage</th>
|
| 170 |
+
<th align="left">Data types</th>
|
| 171 |
+
<th align="left">Datasets</th>
|
| 172 |
+
</tr>
|
| 173 |
+
<tr>
|
| 174 |
+
<td align="left">Detection pretraining</td>
|
| 175 |
+
<td align="left">Detection</td>
|
| 176 |
+
<td align="left">COCO, Objects365, OpenImages, V3Det, SA1B</td>
|
| 177 |
+
</tr>
|
| 178 |
+
<tr>
|
| 179 |
+
<td rowspan="4" align="left">Alignment pretraining</td>
|
| 180 |
+
<td align="left">Image caption</td>
|
| 181 |
+
<td align="left">ShareGPT-4V-PT</td>
|
| 182 |
+
</tr>
|
| 183 |
+
<tr>
|
| 184 |
+
<td align="left">Grounded caption</td>
|
| 185 |
+
<td align="left">Flickr30k Entities</td>
|
| 186 |
+
</tr>
|
| 187 |
+
<tr>
|
| 188 |
+
<td align="left">Region caption</td>
|
| 189 |
+
<td align="left">Visual Genome, RefCOCOg</td>
|
| 190 |
+
</tr>
|
| 191 |
+
<tr>
|
| 192 |
+
<td align="left">REC</td>
|
| 193 |
+
<td align="left">COCO, RefCOCO/g/+, Grit-20m</td>
|
| 194 |
+
</tr>
|
| 195 |
+
<tr>
|
| 196 |
+
<td rowspan="4" align="left">Instruction finetuning</td>
|
| 197 |
+
<td align="left">Grounded caption</td>
|
| 198 |
+
<td align="left">Flickr30k Entities</td>
|
| 199 |
+
</tr>
|
| 200 |
+
<tr>
|
| 201 |
+
<td align="left">Region caption</td>
|
| 202 |
+
<td align="left">Visual Genome, RefCOCOg</td>
|
| 203 |
+
</tr>
|
| 204 |
+
<tr>
|
| 205 |
+
<td align="left">REC</td>
|
| 206 |
+
<td align="left">COCO, RefCOCO/g/+</td>
|
| 207 |
+
</tr>
|
| 208 |
+
<tr>
|
| 209 |
+
<td align="left">Instruction following</td>
|
| 210 |
+
<td align="left">Groma Instruct, LLaVA Instruct, ShareGPT-4V</td>
|
| 211 |
+
</tr>
|
| 212 |
+
</table>
|
| 213 |
+
|
| 214 |
+
|
| 215 |
+
## Training
|
| 216 |
+
For detection pretraining, please run
|
| 217 |
+
~~~
|
| 218 |
+
bash scripts/det_pretrain.sh {path_to_dinov2_ckpt} {output_dir}
|
| 219 |
+
~~~
|
| 220 |
+
|
| 221 |
+
For alignment pretraining, please run
|
| 222 |
+
~~~
|
| 223 |
+
bash scripts/vl_pretrain.sh {path_to_vicuna_ckpt} {path_to_groma_det_pretrain_ckpt} {output_dir}
|
| 224 |
+
~~~
|
| 225 |
+
|
| 226 |
+
For instruction finetuning, please run
|
| 227 |
+
~~~
|
| 228 |
+
bash scripts/vl_finetune.sh {path_to_groma_7b_pretrain_ckpt} {output_dir}
|
| 229 |
+
~~~
|
| 230 |
+
|
| 231 |
+
|
| 232 |
+
## Inference
|
| 233 |
+
To test on single image, you can run
|
| 234 |
+
~~~
|
| 235 |
+
python -m groma.eval.run_groma \
|
| 236 |
+
--model-name {path_to_groma_7b_finetune} \
|
| 237 |
+
--image-file {path_to_img} \
|
| 238 |
+
--query {user_query} \
|
| 239 |
+
--quant_type 'none' # support ['none', 'fp16', '8bit', '4bit'] for inference
|
| 240 |
+
~~~
|
| 241 |
+
|
| 242 |
+
|
| 243 |
+
## Evaluation
|
| 244 |
+
For evaluation, please refer to [EVAL.md](docs/EVAL.md) for more details.
|
| 245 |
+
|
| 246 |
+
|
| 247 |
+
## Citation
|
| 248 |
+
If you find this repo useful for your research, feel free to give us a star ⭐ or cite our paper:
|
| 249 |
+
```
|
| 250 |
+
@article{ma2024groma,
|
| 251 |
+
title={Groma: Localized Visual Tokenization for Grounding Multimodal Large Language Models},
|
| 252 |
+
author={Ma, Chuofan and Jiang, Yi and Wu, Jiannan and Yuan, Zehuan and Qi, Xiaojuan},
|
| 253 |
+
journal={arXiv preprint arXiv:2404.13013},
|
| 254 |
+
year={2024}
|
| 255 |
+
}
|
| 256 |
+
```
|
| 257 |
+
|
| 258 |
+
|
| 259 |
+
## Acknowledgement
|
| 260 |
+
Groma is built upon the awesome works
|
| 261 |
+
[LLaVA](https://github.com/haotian-liu/LLaVA/) and
|
| 262 |
+
[GPT4ROI](https://github.com/jshilong/GPT4RoI).
|
| 263 |
+
|
| 264 |
+
|
| 265 |
+
|
| 266 |
+
## LICENSE
|
| 267 |
+
This project is licensed under the Apache License 2.0 -
|
| 268 |
+
see the [LICENSE](LICENSE) file for details.
|
VLM2Vec/evaluation/eval_utils.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
import os
|
| 3 |
+
import json
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
def get_pred(qry_t, tgt_t, normalization=False):
|
| 7 |
+
"""
|
| 8 |
+
Use L2 norms.
|
| 9 |
+
"""
|
| 10 |
+
if normalization:
|
| 11 |
+
qry_t_norm = np.linalg.norm(qry_t)
|
| 12 |
+
tgt_t_norms = np.linalg.norm(tgt_t, axis=1)
|
| 13 |
+
scores = np.dot(tgt_t, qry_t) / (tgt_t_norms * qry_t_norm)
|
| 14 |
+
else:
|
| 15 |
+
scores = np.dot(tgt_t, qry_t)
|
| 16 |
+
pred = np.argmax(scores)
|
| 17 |
+
return scores, pred
|
| 18 |
+
|
| 19 |
+
def save_results(results, model_args, data_args, train_args):
|
| 20 |
+
save_file = model_args.model_name + "_" + (model_args.model_type if model_args.model_type is not None else "") + "_" + data_args.embedding_type + "_results.json"
|
| 21 |
+
with open(os.path.join(data_args.encode_output_path, save_file), "w") as json_file:
|
| 22 |
+
json.dump(results, json_file, indent=4)
|
| 23 |
+
|
| 24 |
+
def print_results(results):
|
| 25 |
+
for dataset, acc in results.items():
|
| 26 |
+
print(dataset, ",", acc)
|
VLM2Vec/grad_cache/cachex/training.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from functools import partial
|
| 2 |
+
|
| 3 |
+
import jax
|
| 4 |
+
import jax.numpy as jnp
|
| 5 |
+
|
| 6 |
+
from .functional import chunk_encode, cache_grad, unchunk_args
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def cache_train_step(loss_fn, state, ss, tt, axis='device'):
|
| 10 |
+
def encode_with_params(params, **kwargs):
|
| 11 |
+
return state.apply_fn(params=params, **kwargs)
|
| 12 |
+
|
| 13 |
+
encode_fn = chunk_encode(partial(encode_with_params, state.params))
|
| 14 |
+
grad_fn = cache_grad(encode_with_params)
|
| 15 |
+
|
| 16 |
+
s_reps = encode_fn(**ss)
|
| 17 |
+
t_reps = encode_fn(**tt)
|
| 18 |
+
|
| 19 |
+
@unchunk_args(axis=0, argnums=(0, 1))
|
| 20 |
+
def grad_cache_fn(xx, yy):
|
| 21 |
+
return jnp.mean(loss_fn(xx, yy, axis=axis))
|
| 22 |
+
loss, (s_grads, t_grads) = jax.value_and_grad(grad_cache_fn, argnums=(0, 1))(s_reps, t_reps)
|
| 23 |
+
|
| 24 |
+
grads = jax.tree_map(lambda v: jnp.zeros_like(v), state.params)
|
| 25 |
+
grads = grad_fn(state.params, grads, s_grads, **ss)
|
| 26 |
+
grads = grad_fn(state.params, grads, t_grads, **tt)
|
| 27 |
+
|
| 28 |
+
loss, grads = jax.lax.pmean([loss, grads], axis)
|
| 29 |
+
new_state = state.apply_gradients(grads=grads)
|
| 30 |
+
return loss, new_state
|
VLM2Vec/grad_cache/cachex/tree_utils.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Any
|
| 2 |
+
|
| 3 |
+
import jax
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
def tree_chunk(tree: Any, n_chunk: int, axis: int = 0) -> Any:
|
| 7 |
+
return jax.tree_map(
|
| 8 |
+
lambda v: v.reshape(v.shape[:axis] + (n_chunk, -1) + v.shape[axis + 1:]),
|
| 9 |
+
tree
|
| 10 |
+
)
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def tree_unchunk(tree: Any, axis: int = 0) -> Any:
|
| 14 |
+
return jax.tree_map(
|
| 15 |
+
lambda x: x.reshape(x.shape[:axis] + (-1,) + x.shape[axis + 2:]),
|
| 16 |
+
tree
|
| 17 |
+
)
|
VLM2Vec/src/vlm_backbone/phi3_v/configuration_phi3_v.py
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# coding=utf-8
|
| 2 |
+
# Copyright 2024 Microsoft and the HuggingFace Inc. team. All rights reserved.
|
| 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 |
+
""" Phi-3-V model configuration"""
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
from transformers.configuration_utils import PretrainedConfig
|
| 20 |
+
from transformers.utils import logging
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
logger = logging.get_logger(__name__)
|
| 24 |
+
|
| 25 |
+
PHI3V_PRETRAINED_CONFIG_ARCHIVE_MAP = {
|
| 26 |
+
"microsoft/Phi-3-vision-128k-instruct": "https://huggingface.co/microsoft/Phi-3-vision-128k-instruct/resolve/main/config.json",
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
class Phi3VConfig(PretrainedConfig):
|
| 31 |
+
r"""
|
| 32 |
+
This is the configuration class to store the configuration of a [`Phi3VModel`]. It is used to instantiate a Phi-3
|
| 33 |
+
model according to the specified arguments, defining the model architecture. Instantiating a configuration with the
|
| 34 |
+
defaults will yield a similar configuration to that of the
|
| 35 |
+
[microsoft/Phi-3-vision-128k-instruct](https://huggingface.co/microsoft/Phi-3-vision-128k-instruct).
|
| 36 |
+
|
| 37 |
+
Configuration objects inherit from [`PretrainedConfig`] and can be used to control the model outputs. Read the
|
| 38 |
+
documentation from [`PretrainedConfig`] for more information.
|
| 39 |
+
|
| 40 |
+
Args:
|
| 41 |
+
vocab_size (`int`, *optional*, defaults to 32064):
|
| 42 |
+
Vocabulary size of the Phi-3-V model. Defines the number of different tokens that can be represented by the
|
| 43 |
+
`inputs_ids` passed when calling [`Phi3VModel`].
|
| 44 |
+
hidden_size (`int`, *optional*, defaults to 3072):
|
| 45 |
+
Dimension of the hidden representations.
|
| 46 |
+
intermediate_size (`int`, *optional*, defaults to 8192):
|
| 47 |
+
Dimension of the MLP representations.
|
| 48 |
+
num_hidden_layers (`int`, *optional*, defaults to 32):
|
| 49 |
+
Number of hidden layers in the Transformer decoder.
|
| 50 |
+
num_attention_heads (`int`, *optional*, defaults to 32):
|
| 51 |
+
Number of attention heads for each attention layer in the Transformer decoder.
|
| 52 |
+
num_key_value_heads (`int`, *optional*):
|
| 53 |
+
This is the number of key_value heads that should be used to implement Grouped Query Attention. If
|
| 54 |
+
`num_key_value_heads=num_attention_heads`, the model will use Multi Head Attention (MHA), if
|
| 55 |
+
`num_key_value_heads=1 the model will use Multi Query Attention (MQA) otherwise GQA is used. When
|
| 56 |
+
converting a multi-head checkpoint to a GQA checkpoint, each group key and value head should be constructed
|
| 57 |
+
by meanpooling all the original heads within that group. For more details checkout [this
|
| 58 |
+
paper](https://arxiv.org/pdf/2305.13245.pdf). If it is not specified, will default to
|
| 59 |
+
`num_attention_heads`.
|
| 60 |
+
resid_pdrop (`float`, *optional*, defaults to 0.0):
|
| 61 |
+
Dropout probability for mlp outputs.
|
| 62 |
+
embd_pdrop (`int`, *optional*, defaults to 0.0):
|
| 63 |
+
The dropout ratio for the embeddings.
|
| 64 |
+
attention_dropout (`float`, *optional*, defaults to 0.0):
|
| 65 |
+
The dropout ratio after computing the attention scores.
|
| 66 |
+
hidden_act (`str` or `function`, *optional*, defaults to `"silu"`):
|
| 67 |
+
The non-linear activation function (function or string) in the decoder.
|
| 68 |
+
max_position_embeddings (`int`, *optional*, defaults to 4096):
|
| 69 |
+
The maximum sequence length that this model might ever be used with.
|
| 70 |
+
original_max_position_embeddings (`int`, *optional*, defaults to 4096):
|
| 71 |
+
The maximum sequence length that this model was trained with. This is used to determine the size of the
|
| 72 |
+
original RoPE embeddings when using long scaling.
|
| 73 |
+
initializer_range (`float`, *optional*, defaults to 0.02):
|
| 74 |
+
The standard deviation of the truncated_normal_initializer for initializing all weight matrices.
|
| 75 |
+
rms_norm_eps (`float`, *optional*, defaults to 1e-05):
|
| 76 |
+
The epsilon value used for the RMSNorm.
|
| 77 |
+
use_cache (`bool`, *optional*, defaults to `True`):
|
| 78 |
+
Whether or not the model should return the last key/values attentions (not used by all models). Only
|
| 79 |
+
relevant if `config.is_decoder=True`. Whether to tie weight embeddings or not.
|
| 80 |
+
tie_word_embeddings (`bool`, *optional*, defaults to `False`):
|
| 81 |
+
Whether to tie weight embeddings
|
| 82 |
+
rope_theta (`float`, *optional*, defaults to 10000.0):
|
| 83 |
+
The base period of the RoPE embeddings.
|
| 84 |
+
rope_scaling (`dict`, *optional*):
|
| 85 |
+
The scaling strategy for the RoPE embeddings. If `None`, no scaling is applied. If a dictionary, it must
|
| 86 |
+
contain the following keys: `type`, `short_factor` and `long_factor`. The `type` must be either `su` or `yarn` and
|
| 87 |
+
the `short_factor` and `long_factor` must be lists of numbers with the same length as the hidden size
|
| 88 |
+
divided by the number of attention heads divided by 2.
|
| 89 |
+
bos_token_id (`int`, *optional*, defaults to 1):
|
| 90 |
+
The id of the "beginning-of-sequence" token.
|
| 91 |
+
eos_token_id (`int`, *optional*, defaults to 32000):
|
| 92 |
+
The id of the "end-of-sequence" token.
|
| 93 |
+
pad_token_id (`int`, *optional*, defaults to 32000):
|
| 94 |
+
The id of the padding token.
|
| 95 |
+
sliding_window (`int`, *optional*):
|
| 96 |
+
Sliding window attention window size. If `None`, no sliding window is applied.
|
| 97 |
+
embd_layer (`str`, *optional*, defaults to `"default"`):
|
| 98 |
+
The embedding layer to use. Can be either `"default"` or `"image"`. "default" uses the standard embedding for text.
|
| 99 |
+
|
| 100 |
+
Example:
|
| 101 |
+
|
| 102 |
+
```python
|
| 103 |
+
>>> from transformers import Phi3VModel, Phi3VConfig
|
| 104 |
+
|
| 105 |
+
>>> # Initializing a Phi-3-V style configuration
|
| 106 |
+
>>> configuration = Phi3Config.from_pretrained("microsoft/Phi-3-vision-128k-instruct")
|
| 107 |
+
|
| 108 |
+
>>> # Initializing a model from the configuration
|
| 109 |
+
>>> model = Phi3VModel(configuration)
|
| 110 |
+
|
| 111 |
+
>>> # Accessing the model configuration
|
| 112 |
+
>>> configuration = model.config
|
| 113 |
+
```"""
|
| 114 |
+
|
| 115 |
+
model_type = "phi3_v"
|
| 116 |
+
keys_to_ignore_at_inference = ["past_key_values"]
|
| 117 |
+
|
| 118 |
+
def __init__(
|
| 119 |
+
self,
|
| 120 |
+
vocab_size=32064,
|
| 121 |
+
hidden_size=3072,
|
| 122 |
+
intermediate_size=8192,
|
| 123 |
+
num_hidden_layers=32,
|
| 124 |
+
num_attention_heads=32,
|
| 125 |
+
num_key_value_heads=None,
|
| 126 |
+
resid_pdrop=0.0,
|
| 127 |
+
embd_pdrop=0.0,
|
| 128 |
+
attention_dropout=0.0,
|
| 129 |
+
hidden_act="silu",
|
| 130 |
+
max_position_embeddings=4096,
|
| 131 |
+
original_max_position_embeddings=4096,
|
| 132 |
+
initializer_range=0.02,
|
| 133 |
+
rms_norm_eps=1e-5,
|
| 134 |
+
use_cache=True,
|
| 135 |
+
tie_word_embeddings=False,
|
| 136 |
+
rope_theta=10000.0,
|
| 137 |
+
rope_scaling=None,
|
| 138 |
+
bos_token_id=1,
|
| 139 |
+
eos_token_id=32000,
|
| 140 |
+
pad_token_id=32000,
|
| 141 |
+
sliding_window=None,
|
| 142 |
+
embd_layer: str = "default",
|
| 143 |
+
**kwargs,
|
| 144 |
+
):
|
| 145 |
+
self.vocab_size = vocab_size
|
| 146 |
+
self.hidden_size = hidden_size
|
| 147 |
+
self.intermediate_size = intermediate_size
|
| 148 |
+
self.num_hidden_layers = num_hidden_layers
|
| 149 |
+
self.num_attention_heads = num_attention_heads
|
| 150 |
+
|
| 151 |
+
if num_key_value_heads is None:
|
| 152 |
+
num_key_value_heads = num_attention_heads
|
| 153 |
+
|
| 154 |
+
self.num_key_value_heads = num_key_value_heads
|
| 155 |
+
self.resid_pdrop = resid_pdrop
|
| 156 |
+
self.embd_pdrop = embd_pdrop
|
| 157 |
+
self.attention_dropout = attention_dropout
|
| 158 |
+
self.hidden_act = hidden_act
|
| 159 |
+
self.max_position_embeddings = max_position_embeddings
|
| 160 |
+
self.original_max_position_embeddings = original_max_position_embeddings
|
| 161 |
+
self.initializer_range = initializer_range
|
| 162 |
+
self.rms_norm_eps = rms_norm_eps
|
| 163 |
+
self.use_cache = use_cache
|
| 164 |
+
self.rope_theta = rope_theta
|
| 165 |
+
self.rope_scaling = rope_scaling
|
| 166 |
+
self._rope_scaling_validation()
|
| 167 |
+
self.sliding_window = sliding_window
|
| 168 |
+
self.embd_layer = embd_layer
|
| 169 |
+
|
| 170 |
+
|
| 171 |
+
super().__init__(
|
| 172 |
+
bos_token_id=bos_token_id,
|
| 173 |
+
eos_token_id=eos_token_id,
|
| 174 |
+
pad_token_id=pad_token_id,
|
| 175 |
+
tie_word_embeddings=tie_word_embeddings,
|
| 176 |
+
**kwargs,
|
| 177 |
+
)
|
| 178 |
+
|
| 179 |
+
def _rope_scaling_validation(self):
|
| 180 |
+
"""
|
| 181 |
+
Validate the `rope_scaling` configuration.
|
| 182 |
+
"""
|
| 183 |
+
if self.rope_scaling is None:
|
| 184 |
+
return
|
| 185 |
+
|
| 186 |
+
if not isinstance(self.rope_scaling, dict) or len(self.rope_scaling) != 3:
|
| 187 |
+
raise ValueError(
|
| 188 |
+
"`rope_scaling` must be a dictionary with three fields, `type`, `short_factor` and `long_factor`, "
|
| 189 |
+
f"got {self.rope_scaling}"
|
| 190 |
+
)
|
| 191 |
+
rope_scaling_type = self.rope_scaling.get("type", None)
|
| 192 |
+
rope_scaling_short_factor = self.rope_scaling.get("short_factor", None)
|
| 193 |
+
rope_scaling_long_factor = self.rope_scaling.get("long_factor", None)
|
| 194 |
+
if rope_scaling_type is None or rope_scaling_type not in ["su", "yarn"]:
|
| 195 |
+
raise ValueError(f"`rope_scaling`'s type field must be one of ['su', 'yarn'], got {rope_scaling_type}")
|
| 196 |
+
if not (
|
| 197 |
+
isinstance(rope_scaling_short_factor, list)
|
| 198 |
+
and all(isinstance(x, (int, float)) for x in rope_scaling_short_factor)
|
| 199 |
+
):
|
| 200 |
+
raise ValueError(
|
| 201 |
+
f"`rope_scaling`'s short_factor field must be a list of numbers, got {rope_scaling_short_factor}"
|
| 202 |
+
)
|
| 203 |
+
if not len(rope_scaling_short_factor) == self.hidden_size // self.num_attention_heads // 2:
|
| 204 |
+
raise ValueError(
|
| 205 |
+
f"`rope_scaling`'s short_factor field must have length {self.hidden_size // self.num_attention_heads // 2}, got {len(rope_scaling_short_factor)}"
|
| 206 |
+
)
|
| 207 |
+
if not (
|
| 208 |
+
isinstance(rope_scaling_long_factor, list)
|
| 209 |
+
and all(isinstance(x, (int, float)) for x in rope_scaling_long_factor)
|
| 210 |
+
):
|
| 211 |
+
raise ValueError(
|
| 212 |
+
f"`rope_scaling`'s long_factor field must be a list of numbers, got {rope_scaling_long_factor}"
|
| 213 |
+
)
|
| 214 |
+
if not len(rope_scaling_long_factor) == self.hidden_size // self.num_attention_heads // 2:
|
| 215 |
+
raise ValueError(
|
| 216 |
+
f"`rope_scaling`'s long_factor field must have length {self.hidden_size // self.num_attention_heads // 2}, got {len(rope_scaling_long_factor)}"
|
| 217 |
+
)
|
VLM2Vec/src/vlm_backbone/phi3_v/image_processing_phi3_v.py
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# coding=utf-8
|
| 2 |
+
# Copyright 2024 Microsoft and the HuggingFace Inc. team. All rights reserved.
|
| 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 |
+
"""Image processor class for Phi3-V."""
|
| 17 |
+
|
| 18 |
+
from typing import List, Optional, Union
|
| 19 |
+
|
| 20 |
+
import numpy as np
|
| 21 |
+
|
| 22 |
+
from transformers.image_processing_utils import BaseImageProcessor, BatchFeature
|
| 23 |
+
from transformers.image_transforms import (
|
| 24 |
+
convert_to_rgb,
|
| 25 |
+
)
|
| 26 |
+
from transformers.image_utils import (
|
| 27 |
+
OPENAI_CLIP_MEAN,
|
| 28 |
+
OPENAI_CLIP_STD,
|
| 29 |
+
ImageInput,
|
| 30 |
+
make_list_of_images,
|
| 31 |
+
valid_images,
|
| 32 |
+
)
|
| 33 |
+
from transformers.utils import TensorType, is_vision_available, logging
|
| 34 |
+
|
| 35 |
+
from transformers import AutoImageProcessor
|
| 36 |
+
|
| 37 |
+
logger = logging.get_logger(__name__)
|
| 38 |
+
|
| 39 |
+
if is_vision_available():
|
| 40 |
+
from PIL import Image
|
| 41 |
+
|
| 42 |
+
import torch
|
| 43 |
+
import torchvision
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def padding_336(b):
|
| 47 |
+
width, height = b.size
|
| 48 |
+
tar = int(np.ceil(height / 336) * 336)
|
| 49 |
+
top_padding = int((tar - height) / 2)
|
| 50 |
+
bottom_padding = tar - height - top_padding
|
| 51 |
+
left_padding = 0
|
| 52 |
+
right_padding = 0
|
| 53 |
+
b = torchvision.transforms.functional.pad(b, [left_padding, top_padding, right_padding, bottom_padding],
|
| 54 |
+
fill=[255, 255, 255])
|
| 55 |
+
|
| 56 |
+
return b
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def calc_padded_size(width, height, padding_unit=336):
|
| 60 |
+
target_height = int(np.ceil(height / padding_unit) * padding_unit)
|
| 61 |
+
top_padding = int((target_height - height) / 2)
|
| 62 |
+
bottom_padding = target_height - height - top_padding
|
| 63 |
+
left_padding = 0
|
| 64 |
+
right_padding = 0
|
| 65 |
+
padded_width = width + left_padding + right_padding
|
| 66 |
+
padded_height = height + top_padding + bottom_padding
|
| 67 |
+
return padded_width, padded_height
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
def HD_transform(img, hd_num=16):
|
| 71 |
+
width, height = img.size
|
| 72 |
+
trans = False
|
| 73 |
+
if width < height:
|
| 74 |
+
img = img.transpose(Image.TRANSPOSE)
|
| 75 |
+
trans = True
|
| 76 |
+
width, height = img.size
|
| 77 |
+
ratio = (width / height)
|
| 78 |
+
scale = 1
|
| 79 |
+
while scale * np.ceil(scale / ratio) <= hd_num:
|
| 80 |
+
scale += 1
|
| 81 |
+
scale -= 1
|
| 82 |
+
new_w = int(scale * 336)
|
| 83 |
+
new_h = int(new_w / ratio)
|
| 84 |
+
|
| 85 |
+
img = torchvision.transforms.functional.resize(img, [new_h, new_w], )
|
| 86 |
+
img = padding_336(img)
|
| 87 |
+
width, height = img.size
|
| 88 |
+
if trans:
|
| 89 |
+
img = img.transpose(Image.TRANSPOSE)
|
| 90 |
+
|
| 91 |
+
return img
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def calc_hd_transform_size(width, height, hd_num=16):
|
| 95 |
+
transposed = False
|
| 96 |
+
if width < height:
|
| 97 |
+
width, height = height, width
|
| 98 |
+
transposed = True
|
| 99 |
+
|
| 100 |
+
ratio = width / height
|
| 101 |
+
scale = 1
|
| 102 |
+
while scale * np.ceil(scale / ratio) <= hd_num:
|
| 103 |
+
scale += 1
|
| 104 |
+
scale -= 1
|
| 105 |
+
|
| 106 |
+
new_width = int(scale * 336)
|
| 107 |
+
new_height = int(new_width / ratio)
|
| 108 |
+
|
| 109 |
+
padded_width, padded_height = calc_padded_size(new_width, new_height)
|
| 110 |
+
|
| 111 |
+
if transposed:
|
| 112 |
+
padded_width, padded_height = padded_height, padded_width
|
| 113 |
+
|
| 114 |
+
return padded_width, padded_height
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
def pad_to_max_num_crops_tensor(images, max_crops=5):
|
| 118 |
+
"""
|
| 119 |
+
images: B x 3 x H x W, B<=max_crops
|
| 120 |
+
"""
|
| 121 |
+
B, _, H, W = images.shape
|
| 122 |
+
if B < max_crops:
|
| 123 |
+
pad = torch.zeros(max_crops - B, 3, H, W, dtype=images.dtype, device=images.device)
|
| 124 |
+
images = torch.cat([images, pad], dim=0)
|
| 125 |
+
return images
|
| 126 |
+
|
| 127 |
+
|
| 128 |
+
class Phi3VImageProcessor(BaseImageProcessor):
|
| 129 |
+
r"""
|
| 130 |
+
Constructs a Phi3 image processor. Based on [`CLIPImageProcessor`] with incorporation of additional techniques
|
| 131 |
+
for processing high resolution images as explained in the [InternLM-XComposer2-4KHD](https://arxiv.org/pdf/2404.06512)
|
| 132 |
+
|
| 133 |
+
Args:
|
| 134 |
+
image_mean (`float` or `List[float]`, *optional*, defaults to `[0.48145466, 0.4578275, 0.40821073]`):
|
| 135 |
+
Mean to use if normalizing the image. This is a float or list of floats the length of the number of
|
| 136 |
+
channels in the image. Can be overridden by the `image_mean` parameter in the `preprocess` method.
|
| 137 |
+
image_std (`float` or `List[float]`, *optional*, defaults to `[0.26862954, 0.26130258, 0.27577711]`):
|
| 138 |
+
Standard deviation to use if normalizing the image. This is a float or list of floats the length of the
|
| 139 |
+
number of channels in the image. Can be overridden by the `image_std` parameter in the `preprocess` method.
|
| 140 |
+
Can be overridden by the `image_std` parameter in the `preprocess` method.
|
| 141 |
+
do_convert_rgb (`bool`, *optional*, defaults to `True`):
|
| 142 |
+
Whether to convert the image to RGB.
|
| 143 |
+
"""
|
| 144 |
+
|
| 145 |
+
model_input_names = ["pixel_values"]
|
| 146 |
+
|
| 147 |
+
def __init__(
|
| 148 |
+
self,
|
| 149 |
+
num_crops: int = 1,
|
| 150 |
+
image_mean: Optional[Union[float, List[float]]] = None,
|
| 151 |
+
image_std: Optional[Union[float, List[float]]] = None,
|
| 152 |
+
do_convert_rgb: bool = True,
|
| 153 |
+
**kwargs,
|
| 154 |
+
) -> None:
|
| 155 |
+
super().__init__(**kwargs)
|
| 156 |
+
self.num_crops = num_crops
|
| 157 |
+
self.image_mean = image_mean if image_mean is not None else OPENAI_CLIP_MEAN
|
| 158 |
+
self.image_std = image_std if image_std is not None else OPENAI_CLIP_STD
|
| 159 |
+
self.do_convert_rgb = do_convert_rgb
|
| 160 |
+
|
| 161 |
+
def calc_num_image_tokens(
|
| 162 |
+
self,
|
| 163 |
+
images: ImageInput
|
| 164 |
+
):
|
| 165 |
+
""" Calculate the number of image tokens for each image.
|
| 166 |
+
Args:
|
| 167 |
+
images (`ImageInput`):
|
| 168 |
+
Image to preprocess. Expects a single or batch of images with pixel values ranging from 0 to 255. If
|
| 169 |
+
passing in images with pixel values between 0 and 1, set `do_rescale=False`.
|
| 170 |
+
"""
|
| 171 |
+
images = make_list_of_images(images)
|
| 172 |
+
|
| 173 |
+
if not valid_images(images):
|
| 174 |
+
raise ValueError(
|
| 175 |
+
"Invalid image type. Must be of type PIL.Image.Image, numpy.ndarray, "
|
| 176 |
+
"torch.Tensor, tf.Tensor or jax.ndarray."
|
| 177 |
+
)
|
| 178 |
+
|
| 179 |
+
images = [image.convert('RGB') for image in images]
|
| 180 |
+
# (H, W, C)
|
| 181 |
+
elems = [HD_transform(im, hd_num=self.num_crops) for im in images]
|
| 182 |
+
shapes = [[im.size[1], im.size[0]] for im in elems]
|
| 183 |
+
num_img_tokens = [int((h // 336 * w // 336 + 1) * 144 + 1 + (h // 336 + 1) * 12) for h, w in shapes]
|
| 184 |
+
return num_img_tokens
|
| 185 |
+
|
| 186 |
+
def calc_num_image_tokens_from_image_size(self, width, height):
|
| 187 |
+
"""
|
| 188 |
+
Calculate the number of image tokens for a given image size.
|
| 189 |
+
Args:
|
| 190 |
+
width (`int`): Width of the image.
|
| 191 |
+
height (`int`): Height of the image.
|
| 192 |
+
"""
|
| 193 |
+
new_width, new_height = calc_hd_transform_size(width, height, hd_num=self.num_crops)
|
| 194 |
+
num_img_tokens = int((new_height // 336 * new_width // 336 + 1) * 144 + 1 + (new_height // 336 + 1) * 12)
|
| 195 |
+
return num_img_tokens
|
| 196 |
+
|
| 197 |
+
def preprocess(
|
| 198 |
+
self,
|
| 199 |
+
images: ImageInput,
|
| 200 |
+
image_mean: Optional[Union[float, List[float]]] = None,
|
| 201 |
+
image_std: Optional[Union[float, List[float]]] = None,
|
| 202 |
+
do_convert_rgb: bool = None,
|
| 203 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 204 |
+
):
|
| 205 |
+
"""
|
| 206 |
+
Args:
|
| 207 |
+
images (`ImageInput`):
|
| 208 |
+
Image to preprocess. Expects a single or batch of images with pixel values ranging from 0 to 255. If
|
| 209 |
+
passing in images with pixel values between 0 and 1, set `do_rescale=False`.
|
| 210 |
+
image_mean (`float` or `List[float]`, *optional*, defaults to `self.image_mean`):
|
| 211 |
+
Image mean to use for normalization. Only has an effect if `do_normalize` is set to `True`.
|
| 212 |
+
image_std (`float` or `List[float]`, *optional*, defaults to `self.image_std`):
|
| 213 |
+
Image standard deviation to use for normalization. Only has an effect if `do_normalize` is set to
|
| 214 |
+
`True`.
|
| 215 |
+
do_convert_rgb (`bool`, *optional*, defaults to `self.do_convert_rgb`):
|
| 216 |
+
Whether to convert the image to RGB.
|
| 217 |
+
return_tensors (`str` or `TensorType`, *optional*):
|
| 218 |
+
The type of tensors to return. Can be one of:
|
| 219 |
+
- Unset: Return a list of `np.ndarray`.
|
| 220 |
+
- `TensorType.TENSORFLOW` or `'tf'`: Return a batch of type `tf.Tensor`.
|
| 221 |
+
- `TensorType.PYTORCH` or `'pt'`: Return a batch of type `torch.Tensor`.
|
| 222 |
+
- `TensorType.NUMPY` or `'np'`: Return a batch of type `np.ndarray`.
|
| 223 |
+
- `TensorType.JAX` or `'jax'`: Return a batch of type `jax.numpy.ndarray`.
|
| 224 |
+
"""
|
| 225 |
+
image_mean = image_mean if image_mean is not None else self.image_mean
|
| 226 |
+
image_std = image_std if image_std is not None else self.image_std
|
| 227 |
+
do_convert_rgb = do_convert_rgb if do_convert_rgb is not None else self.do_convert_rgb
|
| 228 |
+
|
| 229 |
+
images = make_list_of_images(images)
|
| 230 |
+
|
| 231 |
+
if not valid_images(images):
|
| 232 |
+
raise ValueError(
|
| 233 |
+
"Invalid image type. Must be of type PIL.Image.Image, numpy.ndarray, "
|
| 234 |
+
"torch.Tensor, tf.Tensor or jax.ndarray."
|
| 235 |
+
)
|
| 236 |
+
|
| 237 |
+
if do_convert_rgb:
|
| 238 |
+
images = [convert_to_rgb(image) for image in images]
|
| 239 |
+
|
| 240 |
+
image_sizes = []
|
| 241 |
+
img_processor = torchvision.transforms.Compose([
|
| 242 |
+
torchvision.transforms.ToTensor(),
|
| 243 |
+
torchvision.transforms.Normalize(image_mean, image_std)
|
| 244 |
+
])
|
| 245 |
+
|
| 246 |
+
# PIL images
|
| 247 |
+
# HD_transform pad images to size of multiiply of 336, 336
|
| 248 |
+
# convert to RGB first
|
| 249 |
+
images = [image.convert('RGB') for image in images]
|
| 250 |
+
elems = [HD_transform(im, hd_num=self.num_crops) for im in images]
|
| 251 |
+
# tensor transform and normalize
|
| 252 |
+
hd_images = [img_processor(im) for im in elems]
|
| 253 |
+
# create global image
|
| 254 |
+
global_image = [
|
| 255 |
+
torch.nn.functional.interpolate(im.unsqueeze(0).float(), size=(336, 336), mode='bicubic', ).to(im.dtype) for
|
| 256 |
+
im in hd_images]
|
| 257 |
+
|
| 258 |
+
# [(3, h, w)], where h, w is multiple of 336
|
| 259 |
+
shapes = [[im.size(1), im.size(2)] for im in hd_images]
|
| 260 |
+
num_img_tokens = [int(((h // 336) * (w // 336) + 1) * 144 + 1 + (h // 336 + 1) * 12) for h, w in shapes]
|
| 261 |
+
# reshape to channel dimension -> (num_images, num_crops, 3, 336, 336)
|
| 262 |
+
# (1, 3, h//336, 336, w//336, 336) -> (1, h//336, w//336, 3, 336, 336) -> (h//336*w//336, 3, 336, 336)
|
| 263 |
+
hd_images_reshape = [
|
| 264 |
+
im.reshape(1, 3, h // 336, 336, w // 336, 336).permute(0, 2, 4, 1, 3, 5).reshape(-1, 3, 336,
|
| 265 |
+
336).contiguous() for
|
| 266 |
+
im, (h, w) in zip(hd_images, shapes)]
|
| 267 |
+
# concat global image and local image
|
| 268 |
+
hd_images_reshape = [torch.cat([_global_image] + [_im], dim=0) for _global_image, _im in
|
| 269 |
+
zip(global_image, hd_images_reshape)]
|
| 270 |
+
|
| 271 |
+
# pad to max_num_crops
|
| 272 |
+
image_transformed = [pad_to_max_num_crops_tensor(im, self.num_crops + 1) for im in hd_images_reshape]
|
| 273 |
+
image_transformed = torch.stack(image_transformed, dim=0)
|
| 274 |
+
image_sizes = [torch.LongTensor(_shapes) for _shapes in shapes]
|
| 275 |
+
padded_images = image_transformed
|
| 276 |
+
image_sizes = shapes
|
| 277 |
+
|
| 278 |
+
data = {"pixel_values": padded_images,
|
| 279 |
+
"image_sizes": image_sizes,
|
| 280 |
+
"num_img_tokens": num_img_tokens
|
| 281 |
+
}
|
| 282 |
+
|
| 283 |
+
return BatchFeature(data=data, tensor_type=return_tensors)
|
| 284 |
+
|
| 285 |
+
|
| 286 |
+
AutoImageProcessor.register("Phi3VImageProcessor", Phi3VImageProcessor)
|
VLM2Vec/src/vlm_backbone/phi3_v/modeling_phi3_v.py
ADDED
|
@@ -0,0 +1,1633 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# coding=utf-8
|
| 2 |
+
# Copyright 2024 Microsoft and the HuggingFace Inc. team. All rights reserved.
|
| 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 |
+
""" PyTorch Phi-3-V model."""
|
| 17 |
+
|
| 18 |
+
import inspect
|
| 19 |
+
import math
|
| 20 |
+
import warnings
|
| 21 |
+
from typing import List, Optional, Tuple, Union
|
| 22 |
+
|
| 23 |
+
import torch
|
| 24 |
+
import torch.nn.functional as F
|
| 25 |
+
import torch.utils.checkpoint
|
| 26 |
+
from torch import nn
|
| 27 |
+
from torch.nn import BCEWithLogitsLoss, CrossEntropyLoss, MSELoss
|
| 28 |
+
|
| 29 |
+
from transformers.activations import ACT2FN
|
| 30 |
+
from transformers.cache_utils import Cache, DynamicCache
|
| 31 |
+
from transformers.modeling_attn_mask_utils import _prepare_4d_causal_attention_mask
|
| 32 |
+
from transformers.modeling_outputs import (
|
| 33 |
+
BaseModelOutputWithPast,
|
| 34 |
+
CausalLMOutputWithPast,
|
| 35 |
+
SequenceClassifierOutputWithPast,
|
| 36 |
+
TokenClassifierOutput,
|
| 37 |
+
)
|
| 38 |
+
from transformers.modeling_utils import PreTrainedModel
|
| 39 |
+
from transformers.utils import (
|
| 40 |
+
add_code_sample_docstrings,
|
| 41 |
+
add_start_docstrings,
|
| 42 |
+
add_start_docstrings_to_model_forward,
|
| 43 |
+
is_flash_attn_greater_or_equal_2_10,
|
| 44 |
+
logging,
|
| 45 |
+
replace_return_docstrings,
|
| 46 |
+
)
|
| 47 |
+
from .configuration_phi3_v import Phi3VConfig
|
| 48 |
+
from .image_embedding_phi3_v import Phi3ImageEmbedding
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
try:
|
| 52 |
+
from flash_attn import flash_attn_func, flash_attn_varlen_func
|
| 53 |
+
from flash_attn.bert_padding import index_first_axis, pad_input, unpad_input # noqa
|
| 54 |
+
|
| 55 |
+
_flash_supports_window_size = "window_size" in list(inspect.signature(flash_attn_func).parameters)
|
| 56 |
+
except ImportError:
|
| 57 |
+
pass
|
| 58 |
+
|
| 59 |
+
logger = logging.get_logger(__name__)
|
| 60 |
+
|
| 61 |
+
_CHECKPOINT_FOR_DOC = "microsoft/Phi-3-vision-128k-instruct"
|
| 62 |
+
_CONFIG_FOR_DOC = "Phi3VConfig"
|
| 63 |
+
|
| 64 |
+
PHI3V_PRETRAINED_MODEL_ARCHIVE_LIST = [
|
| 65 |
+
"microsoft/Phi-3-vision-128k-instruct",
|
| 66 |
+
# See all Phi-3 models at https://huggingface.co/models?filter=Phi-3
|
| 67 |
+
]
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
# Copied from transformers.models.llama.modeling_llama.LlamaRMSNorm with Llama->Phi3
|
| 71 |
+
class Phi3RMSNorm(nn.Module):
|
| 72 |
+
def __init__(self, hidden_size, eps=1e-6):
|
| 73 |
+
"""
|
| 74 |
+
Phi3RMSNorm is equivalent to T5LayerNorm
|
| 75 |
+
"""
|
| 76 |
+
super().__init__()
|
| 77 |
+
self.weight = nn.Parameter(torch.ones(hidden_size))
|
| 78 |
+
self.variance_epsilon = eps
|
| 79 |
+
|
| 80 |
+
def forward(self, hidden_states):
|
| 81 |
+
input_dtype = hidden_states.dtype
|
| 82 |
+
hidden_states = hidden_states.to(torch.float32)
|
| 83 |
+
variance = hidden_states.pow(2).mean(-1, keepdim=True)
|
| 84 |
+
hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon)
|
| 85 |
+
return self.weight * hidden_states.to(input_dtype)
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
# Copied from transformers.models.llama.modeling_llama._get_unpad_data
|
| 89 |
+
def _get_unpad_data(attention_mask):
|
| 90 |
+
seqlens_in_batch = attention_mask.sum(dim=-1, dtype=torch.int32)
|
| 91 |
+
indices = torch.nonzero(attention_mask.flatten(), as_tuple=False).flatten()
|
| 92 |
+
max_seqlen_in_batch = seqlens_in_batch.max().item()
|
| 93 |
+
cu_seqlens = F.pad(torch.cumsum(seqlens_in_batch, dim=0, dtype=torch.int32), (1, 0))
|
| 94 |
+
return (
|
| 95 |
+
indices,
|
| 96 |
+
cu_seqlens,
|
| 97 |
+
max_seqlen_in_batch,
|
| 98 |
+
)
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
# Copied from transformers.models.gemma.modeling_gemma.GemmaRotaryEmbedding with gemma->phi3, Gemma->Phi3
|
| 102 |
+
class Phi3RotaryEmbedding(nn.Module):
|
| 103 |
+
def __init__(self, dim, max_position_embeddings=2048, base=10000, device=None):
|
| 104 |
+
super().__init__()
|
| 105 |
+
|
| 106 |
+
self.dim = dim
|
| 107 |
+
self.max_position_embeddings = max_position_embeddings
|
| 108 |
+
self.base = base
|
| 109 |
+
self.register_buffer("inv_freq", None, persistent=False)
|
| 110 |
+
|
| 111 |
+
@torch.no_grad()
|
| 112 |
+
def forward(self, x, position_ids, seq_len=None):
|
| 113 |
+
# x: [bs, num_attention_heads, seq_len, head_size]
|
| 114 |
+
if self.inv_freq is None:
|
| 115 |
+
self.inv_freq = 1.0 / (
|
| 116 |
+
self.base ** (torch.arange(0, self.dim, 2, dtype=torch.int64, device=x.device).float() / self.dim)
|
| 117 |
+
)
|
| 118 |
+
inv_freq_expanded = self.inv_freq[None, :, None].float().expand(position_ids.shape[0], -1, 1)
|
| 119 |
+
position_ids_expanded = position_ids[:, None, :].float()
|
| 120 |
+
# Force float32 since bfloat16 loses precision on long contexts
|
| 121 |
+
# See https://github.com/huggingface/transformers/pull/29285
|
| 122 |
+
device_type = x.device.type
|
| 123 |
+
device_type = device_type if isinstance(device_type, str) and device_type != "mps" else "cpu"
|
| 124 |
+
with torch.autocast(device_type=device_type, enabled=False):
|
| 125 |
+
freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(1, 2)
|
| 126 |
+
emb = torch.cat((freqs, freqs), dim=-1)
|
| 127 |
+
cos = emb.cos()
|
| 128 |
+
sin = emb.sin()
|
| 129 |
+
return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype)
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
class Phi3SuScaledRotaryEmbedding(Phi3RotaryEmbedding):
|
| 133 |
+
def __init__(self, dim, config, device=None):
|
| 134 |
+
super().__init__(dim, config.max_position_embeddings, config.rope_theta, device)
|
| 135 |
+
|
| 136 |
+
self.short_factor = config.rope_scaling["short_factor"]
|
| 137 |
+
self.long_factor = config.rope_scaling["long_factor"]
|
| 138 |
+
self.original_max_position_embeddings = config.original_max_position_embeddings
|
| 139 |
+
|
| 140 |
+
@torch.no_grad()
|
| 141 |
+
def forward(self, x, position_ids, seq_len=None):
|
| 142 |
+
seq_len = torch.max(position_ids) + 1
|
| 143 |
+
if seq_len > self.original_max_position_embeddings:
|
| 144 |
+
ext_factors = torch.tensor(self.long_factor, dtype=torch.float32, device=x.device)
|
| 145 |
+
else:
|
| 146 |
+
ext_factors = torch.tensor(self.short_factor, dtype=torch.float32, device=x.device)
|
| 147 |
+
|
| 148 |
+
inv_freq_shape = torch.arange(0, self.dim, 2, dtype=torch.int64, device=x.device).float() / self.dim
|
| 149 |
+
self.inv_freq = 1.0 / (ext_factors * self.base**inv_freq_shape)
|
| 150 |
+
|
| 151 |
+
inv_freq_expanded = self.inv_freq[None, :, None].float().expand(position_ids.shape[0], -1, 1)
|
| 152 |
+
position_ids_expanded = position_ids[:, None, :].float()
|
| 153 |
+
|
| 154 |
+
# Force float32 since bfloat16 loses precision on long contexts
|
| 155 |
+
# See https://github.com/huggingface/transformers/pull/29285
|
| 156 |
+
device_type = x.device.type
|
| 157 |
+
device_type = device_type if isinstance(device_type, str) and device_type != "mps" else "cpu"
|
| 158 |
+
with torch.autocast(device_type=device_type, enabled=False):
|
| 159 |
+
freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(1, 2)
|
| 160 |
+
emb = torch.cat((freqs, freqs), dim=-1)
|
| 161 |
+
|
| 162 |
+
scale = self.max_position_embeddings / self.original_max_position_embeddings
|
| 163 |
+
if scale <= 1.0:
|
| 164 |
+
scaling_factor = 1.0
|
| 165 |
+
else:
|
| 166 |
+
scaling_factor = math.sqrt(1 + math.log(scale) / math.log(self.original_max_position_embeddings))
|
| 167 |
+
|
| 168 |
+
cos = emb.cos() * scaling_factor
|
| 169 |
+
sin = emb.sin() * scaling_factor
|
| 170 |
+
return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype)
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
class Phi3YarnScaledRotaryEmbedding(Phi3RotaryEmbedding):
|
| 174 |
+
def __init__(self, dim, config, device=None):
|
| 175 |
+
super().__init__(dim, config.max_position_embeddings, config.rope_theta, device)
|
| 176 |
+
|
| 177 |
+
self.short_factor = config.rope_scaling["short_factor"]
|
| 178 |
+
self.long_factor = config.rope_scaling["long_factor"]
|
| 179 |
+
self.original_max_position_embeddings = config.original_max_position_embeddings
|
| 180 |
+
|
| 181 |
+
@torch.no_grad()
|
| 182 |
+
def forward(self, x, position_ids, seq_len=None):
|
| 183 |
+
seq_len = torch.max(position_ids) + 1
|
| 184 |
+
if seq_len > self.original_max_position_embeddings:
|
| 185 |
+
ext_factors = torch.tensor(self.long_factor, dtype=torch.float32, device=x.device)
|
| 186 |
+
else:
|
| 187 |
+
ext_factors = torch.tensor(self.short_factor, dtype=torch.float32, device=x.device)
|
| 188 |
+
|
| 189 |
+
inv_freq_shape = torch.arange(0, self.dim, 2, dtype=torch.int64, device=x.device).float() / self.dim
|
| 190 |
+
self.inv_freq = 1.0 / (ext_factors * self.base**inv_freq_shape)
|
| 191 |
+
|
| 192 |
+
inv_freq_expanded = self.inv_freq[None, :, None].float().expand(position_ids.shape[0], -1, 1)
|
| 193 |
+
position_ids_expanded = position_ids[:, None, :].float()
|
| 194 |
+
|
| 195 |
+
# Force float32 since bfloat16 loses precision on long contexts
|
| 196 |
+
# See https://github.com/huggingface/transformers/pull/29285
|
| 197 |
+
device_type = x.device.type
|
| 198 |
+
device_type = device_type if isinstance(device_type, str) and device_type != "mps" else "cpu"
|
| 199 |
+
with torch.autocast(device_type=device_type, enabled=False):
|
| 200 |
+
freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(1, 2)
|
| 201 |
+
emb = torch.cat((freqs, freqs), dim=-1)
|
| 202 |
+
|
| 203 |
+
scale = self.max_position_embeddings / self.original_max_position_embeddings
|
| 204 |
+
if scale <= 1.0:
|
| 205 |
+
scaling_factor = 1.0
|
| 206 |
+
else:
|
| 207 |
+
scaling_factor = 0.1 * math.log(scale) + 1.0
|
| 208 |
+
|
| 209 |
+
cos = emb.cos() * scaling_factor
|
| 210 |
+
sin = emb.sin() * scaling_factor
|
| 211 |
+
return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype)
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
# Copied from transformers.models.llama.modeling_llama.rotate_half
|
| 215 |
+
def rotate_half(x):
|
| 216 |
+
"""Rotates half the hidden dims of the input."""
|
| 217 |
+
x1 = x[..., : x.shape[-1] // 2]
|
| 218 |
+
x2 = x[..., x.shape[-1] // 2 :]
|
| 219 |
+
return torch.cat((-x2, x1), dim=-1)
|
| 220 |
+
|
| 221 |
+
|
| 222 |
+
# Copied from transformers.models.llama.modeling_llama.apply_rotary_pos_emb
|
| 223 |
+
def apply_rotary_pos_emb(q, k, cos, sin, position_ids=None, unsqueeze_dim=1):
|
| 224 |
+
"""Applies Rotary Position Embedding to the query and key tensors.
|
| 225 |
+
|
| 226 |
+
Args:
|
| 227 |
+
q (`torch.Tensor`): The query tensor.
|
| 228 |
+
k (`torch.Tensor`): The key tensor.
|
| 229 |
+
cos (`torch.Tensor`): The cosine part of the rotary embedding.
|
| 230 |
+
sin (`torch.Tensor`): The sine part of the rotary embedding.
|
| 231 |
+
position_ids (`torch.Tensor`, *optional*):
|
| 232 |
+
Deprecated and unused.
|
| 233 |
+
unsqueeze_dim (`int`, *optional*, defaults to 1):
|
| 234 |
+
The 'unsqueeze_dim' argument specifies the dimension along which to unsqueeze cos[position_ids] and
|
| 235 |
+
sin[position_ids] so that they can be properly broadcasted to the dimensions of q and k. For example, note
|
| 236 |
+
that cos[position_ids] and sin[position_ids] have the shape [batch_size, seq_len, head_dim]. Then, if q and
|
| 237 |
+
k have the shape [batch_size, heads, seq_len, head_dim], then setting unsqueeze_dim=1 makes
|
| 238 |
+
cos[position_ids] and sin[position_ids] broadcastable to the shapes of q and k. Similarly, if q and k have
|
| 239 |
+
the shape [batch_size, seq_len, heads, head_dim], then set unsqueeze_dim=2.
|
| 240 |
+
Returns:
|
| 241 |
+
`tuple(torch.Tensor)` comprising of the query and key tensors rotated using the Rotary Position Embedding.
|
| 242 |
+
"""
|
| 243 |
+
cos = cos.unsqueeze(unsqueeze_dim)
|
| 244 |
+
sin = sin.unsqueeze(unsqueeze_dim)
|
| 245 |
+
q_embed = (q * cos) + (rotate_half(q) * sin)
|
| 246 |
+
k_embed = (k * cos) + (rotate_half(k) * sin)
|
| 247 |
+
return q_embed, k_embed
|
| 248 |
+
|
| 249 |
+
|
| 250 |
+
class Phi3MLP(nn.Module):
|
| 251 |
+
def __init__(self, config):
|
| 252 |
+
super().__init__()
|
| 253 |
+
|
| 254 |
+
self.config = config
|
| 255 |
+
self.gate_up_proj = nn.Linear(config.hidden_size, 2 * config.intermediate_size, bias=False)
|
| 256 |
+
self.down_proj = nn.Linear(config.intermediate_size, config.hidden_size, bias=False)
|
| 257 |
+
|
| 258 |
+
self.activation_fn = ACT2FN[config.hidden_act]
|
| 259 |
+
|
| 260 |
+
def forward(self, hidden_states: torch.FloatTensor) -> torch.FloatTensor:
|
| 261 |
+
up_states = self.gate_up_proj(hidden_states)
|
| 262 |
+
|
| 263 |
+
gate, up_states = up_states.chunk(2, dim=-1)
|
| 264 |
+
up_states = up_states * self.activation_fn(gate)
|
| 265 |
+
|
| 266 |
+
return self.down_proj(up_states)
|
| 267 |
+
|
| 268 |
+
|
| 269 |
+
# Copied from transformers.models.llama.modeling_llama.repeat_kv with llama->phi
|
| 270 |
+
def repeat_kv(hidden_states: torch.Tensor, n_rep: int) -> torch.Tensor:
|
| 271 |
+
"""
|
| 272 |
+
This is the equivalent of torch.repeat_interleave(x, dim=1, repeats=n_rep). The hidden states go from (batch,
|
| 273 |
+
num_key_value_heads, seqlen, head_dim) to (batch, num_attention_heads, seqlen, head_dim)
|
| 274 |
+
"""
|
| 275 |
+
batch, num_key_value_heads, slen, head_dim = hidden_states.shape
|
| 276 |
+
if n_rep == 1:
|
| 277 |
+
return hidden_states
|
| 278 |
+
hidden_states = hidden_states[:, :, None, :, :].expand(batch, num_key_value_heads, n_rep, slen, head_dim)
|
| 279 |
+
return hidden_states.reshape(batch, num_key_value_heads * n_rep, slen, head_dim)
|
| 280 |
+
|
| 281 |
+
|
| 282 |
+
class Phi3Attention(nn.Module):
|
| 283 |
+
"""Multi-headed attention from 'Attention Is All You Need' paper"""
|
| 284 |
+
|
| 285 |
+
def __init__(self, config: Phi3VConfig, layer_idx: Optional[int] = None):
|
| 286 |
+
super().__init__()
|
| 287 |
+
self.config = config
|
| 288 |
+
self.layer_idx = layer_idx
|
| 289 |
+
if layer_idx is None:
|
| 290 |
+
logger.warning_once(
|
| 291 |
+
f"Instantiating {self.__class__.__name__} without passing a `layer_idx` is not recommended and will "
|
| 292 |
+
"lead to errors during the forward call if caching is used. Please make sure to provide a `layer_idx` "
|
| 293 |
+
"when creating this class."
|
| 294 |
+
)
|
| 295 |
+
|
| 296 |
+
self.attention_dropout = config.attention_dropout
|
| 297 |
+
self.hidden_size = config.hidden_size
|
| 298 |
+
self.num_heads = config.num_attention_heads
|
| 299 |
+
self.head_dim = self.hidden_size // self.num_heads
|
| 300 |
+
self.num_key_value_heads = config.num_key_value_heads
|
| 301 |
+
self.num_key_value_groups = self.num_heads // self.num_key_value_heads
|
| 302 |
+
self.max_position_embeddings = config.max_position_embeddings
|
| 303 |
+
self.original_max_position_embeddings = config.original_max_position_embeddings
|
| 304 |
+
self.rope_theta = config.rope_theta
|
| 305 |
+
self.rope_scaling = config.rope_scaling
|
| 306 |
+
self.is_causal = True
|
| 307 |
+
|
| 308 |
+
if (self.head_dim * self.num_heads) != self.hidden_size:
|
| 309 |
+
raise ValueError(
|
| 310 |
+
f"hidden_size must be divisible by num_heads (got `hidden_size`: {self.hidden_size}"
|
| 311 |
+
f" and `num_heads`: {self.num_heads})."
|
| 312 |
+
)
|
| 313 |
+
|
| 314 |
+
op_size = self.num_heads * self.head_dim + 2 * (self.num_key_value_heads * self.head_dim)
|
| 315 |
+
self.o_proj = nn.Linear(self.num_heads * self.head_dim, self.hidden_size, bias=False)
|
| 316 |
+
self.qkv_proj = nn.Linear(self.hidden_size, op_size, bias=False)
|
| 317 |
+
self._init_rope()
|
| 318 |
+
|
| 319 |
+
def _init_rope(self):
|
| 320 |
+
if self.rope_scaling is None:
|
| 321 |
+
self.rotary_emb = Phi3RotaryEmbedding(
|
| 322 |
+
self.head_dim,
|
| 323 |
+
max_position_embeddings=self.max_position_embeddings,
|
| 324 |
+
base=self.rope_theta,
|
| 325 |
+
)
|
| 326 |
+
else:
|
| 327 |
+
scaling_type = self.config.rope_scaling["type"]
|
| 328 |
+
if scaling_type == "su":
|
| 329 |
+
self.rotary_emb = Phi3SuScaledRotaryEmbedding(self.head_dim, self.config)
|
| 330 |
+
elif scaling_type == "yarn":
|
| 331 |
+
self.rotary_emb = Phi3YarnScaledRotaryEmbedding(self.head_dim, self.config)
|
| 332 |
+
else:
|
| 333 |
+
raise ValueError(f"Unknown RoPE scaling type {scaling_type}")
|
| 334 |
+
|
| 335 |
+
def forward(
|
| 336 |
+
self,
|
| 337 |
+
hidden_states: torch.Tensor,
|
| 338 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 339 |
+
position_ids: Optional[torch.LongTensor] = None,
|
| 340 |
+
past_key_value: Optional[Cache] = None,
|
| 341 |
+
output_attentions: bool = False,
|
| 342 |
+
use_cache: bool = False,
|
| 343 |
+
) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]:
|
| 344 |
+
logger.warning_once("You are not running the flash-attention implementation, expect numerical differences.")
|
| 345 |
+
|
| 346 |
+
bsz, q_len, _ = hidden_states.size()
|
| 347 |
+
|
| 348 |
+
qkv = self.qkv_proj(hidden_states)
|
| 349 |
+
query_pos = self.num_heads * self.head_dim
|
| 350 |
+
query_states = qkv[..., :query_pos]
|
| 351 |
+
key_states = qkv[..., query_pos : query_pos + self.num_key_value_heads * self.head_dim]
|
| 352 |
+
value_states = qkv[..., query_pos + self.num_key_value_heads * self.head_dim :]
|
| 353 |
+
|
| 354 |
+
query_states = query_states.view(bsz, q_len, self.num_heads, self.head_dim).transpose(1, 2)
|
| 355 |
+
key_states = key_states.view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
|
| 356 |
+
value_states = value_states.view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
|
| 357 |
+
|
| 358 |
+
kv_seq_len = key_states.shape[-2]
|
| 359 |
+
if past_key_value is not None:
|
| 360 |
+
if self.layer_idx is None:
|
| 361 |
+
raise ValueError(
|
| 362 |
+
f"The cache structure has changed since version v4.36. If you are using {self.__class__.__name__} "
|
| 363 |
+
"for auto-regressive decoding with k/v caching, please make sure to initialize the attention class "
|
| 364 |
+
"with a layer index."
|
| 365 |
+
)
|
| 366 |
+
kv_seq_len += past_key_value.get_usable_length(kv_seq_len, self.layer_idx)
|
| 367 |
+
cos, sin = self.rotary_emb(value_states, position_ids, seq_len=kv_seq_len)
|
| 368 |
+
|
| 369 |
+
query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin, position_ids)
|
| 370 |
+
|
| 371 |
+
if past_key_value is not None:
|
| 372 |
+
cache_kwargs = {"sin": sin, "cos": cos} # Specific to RoPE models
|
| 373 |
+
key_states, value_states = past_key_value.update(key_states, value_states, self.layer_idx, cache_kwargs)
|
| 374 |
+
|
| 375 |
+
# repeat k/v heads if n_kv_heads < n_heads
|
| 376 |
+
key_states = repeat_kv(key_states, self.num_key_value_groups)
|
| 377 |
+
value_states = repeat_kv(value_states, self.num_key_value_groups)
|
| 378 |
+
|
| 379 |
+
attn_weights = torch.matmul(query_states, key_states.transpose(2, 3)) / math.sqrt(self.head_dim)
|
| 380 |
+
|
| 381 |
+
if attn_weights.size() != (bsz, self.num_heads, q_len, kv_seq_len):
|
| 382 |
+
raise ValueError(
|
| 383 |
+
f"Attention weights should be of size {(bsz, self.num_heads, q_len, kv_seq_len)}, but is"
|
| 384 |
+
f" {attn_weights.size()}"
|
| 385 |
+
)
|
| 386 |
+
|
| 387 |
+
if attention_mask is not None:
|
| 388 |
+
if attention_mask.size() != (bsz, 1, q_len, kv_seq_len):
|
| 389 |
+
raise ValueError(
|
| 390 |
+
f"Attention mask should be of size {(bsz, 1, q_len, kv_seq_len)}, but is {attention_mask.size()}"
|
| 391 |
+
)
|
| 392 |
+
attn_weights = attn_weights + attention_mask
|
| 393 |
+
|
| 394 |
+
# upcast attention to fp32
|
| 395 |
+
attn_weights = nn.functional.softmax(attn_weights, dim=-1, dtype=torch.float32).to(value_states.dtype)
|
| 396 |
+
attn_weights = nn.functional.dropout(attn_weights, p=self.attention_dropout, training=self.training)
|
| 397 |
+
|
| 398 |
+
attn_output = torch.matmul(attn_weights, value_states)
|
| 399 |
+
|
| 400 |
+
if attn_output.size() != (bsz, self.num_heads, q_len, self.head_dim):
|
| 401 |
+
raise ValueError(
|
| 402 |
+
f"`attn_output` should be of size {(bsz, self.num_heads, q_len, self.head_dim)}, but is"
|
| 403 |
+
f" {attn_output.size()}"
|
| 404 |
+
)
|
| 405 |
+
|
| 406 |
+
attn_output = attn_output.transpose(1, 2).contiguous()
|
| 407 |
+
attn_output = attn_output.reshape(bsz, q_len, self.hidden_size)
|
| 408 |
+
|
| 409 |
+
attn_output = self.o_proj(attn_output)
|
| 410 |
+
|
| 411 |
+
if not output_attentions:
|
| 412 |
+
attn_weights = None
|
| 413 |
+
|
| 414 |
+
return attn_output, attn_weights, past_key_value
|
| 415 |
+
|
| 416 |
+
|
| 417 |
+
class Phi3FlashAttention2(Phi3Attention):
|
| 418 |
+
"""
|
| 419 |
+
Phi-3 flash attention module. This module inherits from `Phi3Attention` as the weights of the module stays
|
| 420 |
+
untouched. The only required change would be on the forward pass where it needs to correctly call the public API of
|
| 421 |
+
flash attention and deal with padding tokens in case the input contains any of them.
|
| 422 |
+
"""
|
| 423 |
+
|
| 424 |
+
# Copied from transformers.models.llama.modeling_llama.LlamaFlashAttention2.__init__
|
| 425 |
+
def __init__(self, *args, **kwargs):
|
| 426 |
+
super().__init__(*args, **kwargs)
|
| 427 |
+
|
| 428 |
+
# TODO: Should be removed once Flash Attention for RoCm is bumped to 2.1.
|
| 429 |
+
# flash_attn<2.1 generates top-left aligned causal mask, while what is needed here is bottom-right alignement, that was made default for flash_attn>=2.1. This attribute is used to handle this difference. Reference: https://github.com/Dao-AILab/flash-attention/releases/tag/v2.1.0.
|
| 430 |
+
# Beware that with flash_attn<2.1, using q_seqlen != k_seqlen (except for the case q_seqlen == 1) produces a wrong mask (top-left).
|
| 431 |
+
self._flash_attn_uses_top_left_mask = not is_flash_attn_greater_or_equal_2_10()
|
| 432 |
+
|
| 433 |
+
def forward(
|
| 434 |
+
self,
|
| 435 |
+
hidden_states: torch.Tensor,
|
| 436 |
+
attention_mask: Optional[torch.LongTensor] = None,
|
| 437 |
+
position_ids: Optional[torch.LongTensor] = None,
|
| 438 |
+
past_key_value: Optional[Cache] = None,
|
| 439 |
+
output_attentions: bool = False,
|
| 440 |
+
use_cache: bool = False,
|
| 441 |
+
**kwargs,
|
| 442 |
+
) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]:
|
| 443 |
+
# Phi3FlashAttention2 attention does not support output_attentions
|
| 444 |
+
|
| 445 |
+
if not _flash_supports_window_size:
|
| 446 |
+
logger.warning_once(
|
| 447 |
+
"The current flash attention version does not support sliding window attention. Please use `attn_implementation='eager'` or upgrade flash-attn library."
|
| 448 |
+
)
|
| 449 |
+
raise ValueError("The current flash attention version does not support sliding window attention.")
|
| 450 |
+
|
| 451 |
+
output_attentions = False
|
| 452 |
+
|
| 453 |
+
if "padding_mask" in kwargs:
|
| 454 |
+
warnings.warn(
|
| 455 |
+
"Passing `padding_mask` is deprecated and will be removed in v4.37. Please make sure use `attention_mask` instead.`"
|
| 456 |
+
)
|
| 457 |
+
|
| 458 |
+
# overwrite attention_mask with padding_mask
|
| 459 |
+
attention_mask = kwargs.pop("padding_mask")
|
| 460 |
+
|
| 461 |
+
bsz, q_len, _ = hidden_states.size()
|
| 462 |
+
|
| 463 |
+
qkv = self.qkv_proj(hidden_states)
|
| 464 |
+
query_pos = self.num_heads * self.head_dim
|
| 465 |
+
query_states = qkv[..., :query_pos]
|
| 466 |
+
key_states = qkv[..., query_pos : query_pos + self.num_key_value_heads * self.head_dim]
|
| 467 |
+
value_states = qkv[..., query_pos + self.num_key_value_heads * self.head_dim :]
|
| 468 |
+
|
| 469 |
+
# Flash attention requires the input to have the shape
|
| 470 |
+
# batch_size x seq_length x head_dim x hidden_dim
|
| 471 |
+
# therefore we just need to keep the original shape
|
| 472 |
+
query_states = query_states.view(bsz, q_len, self.num_heads, self.head_dim).transpose(1, 2)
|
| 473 |
+
key_states = key_states.view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
|
| 474 |
+
value_states = value_states.view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
|
| 475 |
+
|
| 476 |
+
kv_seq_len = key_states.shape[-2]
|
| 477 |
+
if past_key_value is not None:
|
| 478 |
+
if self.layer_idx is None:
|
| 479 |
+
raise ValueError(
|
| 480 |
+
f"The cache structure has changed since version v4.36. If you are using {self.__class__.__name__} "
|
| 481 |
+
"for auto-regressive decoding with k/v caching, please make sure to initialize the attention class "
|
| 482 |
+
"with a layer index."
|
| 483 |
+
)
|
| 484 |
+
kv_seq_len += past_key_value.get_usable_length(kv_seq_len, self.layer_idx)
|
| 485 |
+
|
| 486 |
+
# Because the input can be padded, the absolute sequence length depends on the max position id.
|
| 487 |
+
rotary_seq_len = max(kv_seq_len, position_ids[:, -1].max().item()) + 1
|
| 488 |
+
cos, sin = self.rotary_emb(value_states, position_ids, seq_len=rotary_seq_len)
|
| 489 |
+
|
| 490 |
+
query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin, position_ids)
|
| 491 |
+
|
| 492 |
+
use_sliding_windows = (
|
| 493 |
+
_flash_supports_window_size
|
| 494 |
+
and getattr(self.config, "sliding_window", None) is not None
|
| 495 |
+
and kv_seq_len > self.config.sliding_window
|
| 496 |
+
)
|
| 497 |
+
|
| 498 |
+
if past_key_value is not None:
|
| 499 |
+
# Activate slicing cache only if the config has a value `sliding_windows` attribute
|
| 500 |
+
cache_has_contents = past_key_value.get_seq_length(self.layer_idx) > 0
|
| 501 |
+
if (
|
| 502 |
+
getattr(self.config, "sliding_window", None) is not None
|
| 503 |
+
and kv_seq_len > self.config.sliding_window
|
| 504 |
+
and cache_has_contents
|
| 505 |
+
):
|
| 506 |
+
slicing_tokens = 1 - self.config.sliding_window
|
| 507 |
+
|
| 508 |
+
past_key = past_key_value[self.layer_idx][0]
|
| 509 |
+
past_value = past_key_value[self.layer_idx][1]
|
| 510 |
+
|
| 511 |
+
past_key = past_key[:, :, slicing_tokens:, :].contiguous()
|
| 512 |
+
past_value = past_value[:, :, slicing_tokens:, :].contiguous()
|
| 513 |
+
|
| 514 |
+
if past_key.shape[-2] != self.config.sliding_window - 1:
|
| 515 |
+
raise ValueError(
|
| 516 |
+
f"past key must have a shape of (`batch_size, num_heads, self.config.sliding_window-1, head_dim`), got"
|
| 517 |
+
f" {past_key.shape}"
|
| 518 |
+
)
|
| 519 |
+
|
| 520 |
+
if attention_mask is not None:
|
| 521 |
+
attention_mask = attention_mask[:, slicing_tokens:]
|
| 522 |
+
attention_mask = torch.cat([attention_mask, torch.ones_like(attention_mask[:, -1:])], dim=-1)
|
| 523 |
+
|
| 524 |
+
cache_kwargs = {"sin": sin, "cos": cos} # Specific to RoPE models
|
| 525 |
+
key_states, value_states = past_key_value.update(key_states, value_states, self.layer_idx, cache_kwargs)
|
| 526 |
+
|
| 527 |
+
# repeat k/v heads if n_kv_heads < n_heads
|
| 528 |
+
key_states = repeat_kv(key_states, self.num_key_value_groups)
|
| 529 |
+
value_states = repeat_kv(value_states, self.num_key_value_groups)
|
| 530 |
+
|
| 531 |
+
attn_dropout = self.attention_dropout if self.training else 0.0
|
| 532 |
+
|
| 533 |
+
# In PEFT, usually we cast the layer norms in float32 for training stability reasons
|
| 534 |
+
# therefore the input hidden states gets silently casted in float32. Hence, we need
|
| 535 |
+
# cast them back in the correct dtype just to be sure everything works as expected.
|
| 536 |
+
# This might slowdown training & inference so it is recommended to not cast the LayerNorms
|
| 537 |
+
# in fp32.
|
| 538 |
+
|
| 539 |
+
if query_states.dtype == torch.float32:
|
| 540 |
+
if torch.is_autocast_enabled():
|
| 541 |
+
target_dtype = torch.get_autocast_gpu_dtype()
|
| 542 |
+
# Handle the case where the model is quantized
|
| 543 |
+
elif hasattr(self.config, "_pre_quantization_dtype"):
|
| 544 |
+
target_dtype = self.config._pre_quantization_dtype
|
| 545 |
+
else:
|
| 546 |
+
target_dtype = self.qkv_proj.weight.dtype
|
| 547 |
+
|
| 548 |
+
logger.warning_once(
|
| 549 |
+
f"The input hidden states seems to be silently casted in float32, this might be related to"
|
| 550 |
+
f" the fact you have upcasted embedding or layer norm layers in float32. We will cast back the input in"
|
| 551 |
+
f" {target_dtype}."
|
| 552 |
+
)
|
| 553 |
+
|
| 554 |
+
query_states = query_states.to(target_dtype)
|
| 555 |
+
key_states = key_states.to(target_dtype)
|
| 556 |
+
value_states = value_states.to(target_dtype)
|
| 557 |
+
|
| 558 |
+
# Reashape to the expected shape for Flash Attention
|
| 559 |
+
query_states = query_states.transpose(1, 2)
|
| 560 |
+
key_states = key_states.transpose(1, 2)
|
| 561 |
+
value_states = value_states.transpose(1, 2)
|
| 562 |
+
|
| 563 |
+
attn_output = self._flash_attention_forward(
|
| 564 |
+
query_states,
|
| 565 |
+
key_states,
|
| 566 |
+
value_states,
|
| 567 |
+
attention_mask,
|
| 568 |
+
q_len,
|
| 569 |
+
dropout=attn_dropout,
|
| 570 |
+
use_sliding_windows=use_sliding_windows,
|
| 571 |
+
)
|
| 572 |
+
|
| 573 |
+
attn_output = attn_output.reshape(bsz, q_len, self.hidden_size).contiguous()
|
| 574 |
+
attn_output = self.o_proj(attn_output)
|
| 575 |
+
|
| 576 |
+
if not output_attentions:
|
| 577 |
+
attn_weights = None
|
| 578 |
+
|
| 579 |
+
return attn_output, attn_weights, past_key_value
|
| 580 |
+
|
| 581 |
+
# Copied from transformers.models.mistral.modeling_mistral.MistralFlashAttention2._flash_attention_forward
|
| 582 |
+
def _flash_attention_forward(
|
| 583 |
+
self,
|
| 584 |
+
query_states,
|
| 585 |
+
key_states,
|
| 586 |
+
value_states,
|
| 587 |
+
attention_mask,
|
| 588 |
+
query_length,
|
| 589 |
+
dropout=0.0,
|
| 590 |
+
softmax_scale=None,
|
| 591 |
+
use_sliding_windows=False,
|
| 592 |
+
):
|
| 593 |
+
"""
|
| 594 |
+
Calls the forward method of Flash Attention - if the input hidden states contain at least one padding token
|
| 595 |
+
first unpad the input, then computes the attention scores and pad the final attention scores.
|
| 596 |
+
|
| 597 |
+
Args:
|
| 598 |
+
query_states (`torch.Tensor`):
|
| 599 |
+
Input query states to be passed to Flash Attention API
|
| 600 |
+
key_states (`torch.Tensor`):
|
| 601 |
+
Input key states to be passed to Flash Attention API
|
| 602 |
+
value_states (`torch.Tensor`):
|
| 603 |
+
Input value states to be passed to Flash Attention API
|
| 604 |
+
attention_mask (`torch.Tensor`):
|
| 605 |
+
The padding mask - corresponds to a tensor of size `(batch_size, seq_len)` where 0 stands for the
|
| 606 |
+
position of padding tokens and 1 for the position of non-padding tokens.
|
| 607 |
+
dropout (`float`):
|
| 608 |
+
Attention dropout
|
| 609 |
+
softmax_scale (`float`, *optional*):
|
| 610 |
+
The scaling of QK^T before applying softmax. Default to 1 / sqrt(head_dim)
|
| 611 |
+
use_sliding_windows (`bool`, *optional*):
|
| 612 |
+
Whether to activate sliding window attention.
|
| 613 |
+
"""
|
| 614 |
+
if not self._flash_attn_uses_top_left_mask:
|
| 615 |
+
causal = self.is_causal
|
| 616 |
+
else:
|
| 617 |
+
# TODO: Remove the `query_length != 1` check once Flash Attention for RoCm is bumped to 2.1. For details, please see the comment in LlamaFlashAttention2 __init__.
|
| 618 |
+
causal = self.is_causal and query_length != 1
|
| 619 |
+
|
| 620 |
+
# Contains at least one padding token in the sequence
|
| 621 |
+
if attention_mask is not None:
|
| 622 |
+
batch_size = query_states.shape[0]
|
| 623 |
+
query_states, key_states, value_states, indices_q, cu_seq_lens, max_seq_lens = self._upad_input(
|
| 624 |
+
query_states, key_states, value_states, attention_mask, query_length
|
| 625 |
+
)
|
| 626 |
+
|
| 627 |
+
cu_seqlens_q, cu_seqlens_k = cu_seq_lens
|
| 628 |
+
max_seqlen_in_batch_q, max_seqlen_in_batch_k = max_seq_lens
|
| 629 |
+
|
| 630 |
+
if not use_sliding_windows:
|
| 631 |
+
attn_output_unpad = flash_attn_varlen_func(
|
| 632 |
+
query_states,
|
| 633 |
+
key_states,
|
| 634 |
+
value_states,
|
| 635 |
+
cu_seqlens_q=cu_seqlens_q,
|
| 636 |
+
cu_seqlens_k=cu_seqlens_k,
|
| 637 |
+
max_seqlen_q=max_seqlen_in_batch_q,
|
| 638 |
+
max_seqlen_k=max_seqlen_in_batch_k,
|
| 639 |
+
dropout_p=dropout,
|
| 640 |
+
softmax_scale=softmax_scale,
|
| 641 |
+
causal=causal,
|
| 642 |
+
)
|
| 643 |
+
else:
|
| 644 |
+
attn_output_unpad = flash_attn_varlen_func(
|
| 645 |
+
query_states,
|
| 646 |
+
key_states,
|
| 647 |
+
value_states,
|
| 648 |
+
cu_seqlens_q=cu_seqlens_q,
|
| 649 |
+
cu_seqlens_k=cu_seqlens_k,
|
| 650 |
+
max_seqlen_q=max_seqlen_in_batch_q,
|
| 651 |
+
max_seqlen_k=max_seqlen_in_batch_k,
|
| 652 |
+
dropout_p=dropout,
|
| 653 |
+
softmax_scale=softmax_scale,
|
| 654 |
+
causal=causal,
|
| 655 |
+
window_size=(self.config.sliding_window, self.config.sliding_window),
|
| 656 |
+
)
|
| 657 |
+
|
| 658 |
+
attn_output = pad_input(attn_output_unpad, indices_q, batch_size, query_length)
|
| 659 |
+
else:
|
| 660 |
+
if not use_sliding_windows:
|
| 661 |
+
attn_output = flash_attn_func(
|
| 662 |
+
query_states,
|
| 663 |
+
key_states,
|
| 664 |
+
value_states,
|
| 665 |
+
dropout,
|
| 666 |
+
softmax_scale=softmax_scale,
|
| 667 |
+
causal=causal,
|
| 668 |
+
)
|
| 669 |
+
else:
|
| 670 |
+
attn_output = flash_attn_func(
|
| 671 |
+
query_states,
|
| 672 |
+
key_states,
|
| 673 |
+
value_states,
|
| 674 |
+
dropout,
|
| 675 |
+
softmax_scale=softmax_scale,
|
| 676 |
+
causal=causal,
|
| 677 |
+
window_size=(self.config.sliding_window, self.config.sliding_window),
|
| 678 |
+
)
|
| 679 |
+
|
| 680 |
+
return attn_output
|
| 681 |
+
|
| 682 |
+
# Copied from transformers.models.mistral.modeling_mistral.MistralFlashAttention2._upad_input
|
| 683 |
+
def _upad_input(self, query_layer, key_layer, value_layer, attention_mask, query_length):
|
| 684 |
+
batch_size, kv_seq_len, num_heads, head_dim = key_layer.shape
|
| 685 |
+
|
| 686 |
+
# On the first iteration we need to properly re-create the padding mask
|
| 687 |
+
# by slicing it on the proper place
|
| 688 |
+
if kv_seq_len != attention_mask.shape[-1]:
|
| 689 |
+
attention_mask_num_tokens = attention_mask.shape[-1]
|
| 690 |
+
attention_mask = attention_mask[:, attention_mask_num_tokens - kv_seq_len :]
|
| 691 |
+
|
| 692 |
+
indices_k, cu_seqlens_k, max_seqlen_in_batch_k = _get_unpad_data(attention_mask)
|
| 693 |
+
|
| 694 |
+
key_layer = index_first_axis(key_layer.reshape(batch_size * kv_seq_len, num_heads, head_dim), indices_k)
|
| 695 |
+
value_layer = index_first_axis(value_layer.reshape(batch_size * kv_seq_len, num_heads, head_dim), indices_k)
|
| 696 |
+
|
| 697 |
+
if query_length == kv_seq_len:
|
| 698 |
+
query_layer = index_first_axis(
|
| 699 |
+
query_layer.reshape(batch_size * kv_seq_len, num_heads, head_dim), indices_k
|
| 700 |
+
)
|
| 701 |
+
cu_seqlens_q = cu_seqlens_k
|
| 702 |
+
max_seqlen_in_batch_q = max_seqlen_in_batch_k
|
| 703 |
+
indices_q = indices_k
|
| 704 |
+
elif query_length == 1:
|
| 705 |
+
max_seqlen_in_batch_q = 1
|
| 706 |
+
cu_seqlens_q = torch.arange(
|
| 707 |
+
batch_size + 1, dtype=torch.int32, device=query_layer.device
|
| 708 |
+
) # There is a memcpy here, that is very bad.
|
| 709 |
+
indices_q = cu_seqlens_q[:-1]
|
| 710 |
+
query_layer = query_layer.squeeze(1)
|
| 711 |
+
else:
|
| 712 |
+
# The -q_len: slice assumes left padding.
|
| 713 |
+
attention_mask = attention_mask[:, -query_length:]
|
| 714 |
+
query_layer, indices_q, cu_seqlens_q, max_seqlen_in_batch_q = unpad_input(query_layer, attention_mask)
|
| 715 |
+
|
| 716 |
+
return (
|
| 717 |
+
query_layer,
|
| 718 |
+
key_layer,
|
| 719 |
+
value_layer,
|
| 720 |
+
indices_q,
|
| 721 |
+
(cu_seqlens_q, cu_seqlens_k),
|
| 722 |
+
(max_seqlen_in_batch_q, max_seqlen_in_batch_k),
|
| 723 |
+
)
|
| 724 |
+
|
| 725 |
+
|
| 726 |
+
# copied from transformers.models.llama.modeling_llama.LlamaSdpaAttention with Llama->Phi3
|
| 727 |
+
# TODO @Arthur no longer copied from LLama after static cache
|
| 728 |
+
class Phi3SdpaAttention(Phi3Attention):
|
| 729 |
+
"""
|
| 730 |
+
Phi3 attention module using torch.nn.functional.scaled_dot_product_attention. This module inherits from
|
| 731 |
+
`Phi3Attention` as the weights of the module stays untouched. The only changes are on the forward pass to adapt to
|
| 732 |
+
SDPA API.
|
| 733 |
+
"""
|
| 734 |
+
|
| 735 |
+
# Adapted from Phi3Attention.forward
|
| 736 |
+
def forward(
|
| 737 |
+
self,
|
| 738 |
+
hidden_states: torch.Tensor,
|
| 739 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 740 |
+
position_ids: Optional[torch.LongTensor] = None,
|
| 741 |
+
past_key_value: Optional[Cache] = None,
|
| 742 |
+
output_attentions: bool = False,
|
| 743 |
+
use_cache: bool = False,
|
| 744 |
+
) -> Tuple[torch.Tensor, Optional[torch.Tensor], Optional[Tuple[torch.Tensor]]]:
|
| 745 |
+
if output_attentions:
|
| 746 |
+
# TODO: Improve this warning with e.g. `model.config.attn_implementation = "manual"` once this is implemented.
|
| 747 |
+
logger.warning_once(
|
| 748 |
+
"Phi3Model is using Phi3SdpaAttention, but `torch.nn.functional.scaled_dot_product_attention` does not support `output_attentions=True`. Falling back to the manual attention implementation, "
|
| 749 |
+
'but specifying the manual implementation will be required from Transformers version v5.0.0 onwards. This warning can be removed using the argument `attn_implementation="eager"` when loading the model.'
|
| 750 |
+
)
|
| 751 |
+
return super().forward(
|
| 752 |
+
hidden_states=hidden_states,
|
| 753 |
+
attention_mask=attention_mask,
|
| 754 |
+
position_ids=position_ids,
|
| 755 |
+
past_key_value=past_key_value,
|
| 756 |
+
output_attentions=output_attentions,
|
| 757 |
+
use_cache=use_cache,
|
| 758 |
+
)
|
| 759 |
+
|
| 760 |
+
bsz, q_len, _ = hidden_states.size()
|
| 761 |
+
|
| 762 |
+
qkv = self.qkv_proj(hidden_states)
|
| 763 |
+
query_pos = self.num_heads * self.head_dim
|
| 764 |
+
query_states = qkv[..., :query_pos]
|
| 765 |
+
key_states = qkv[..., query_pos : query_pos + self.num_key_value_heads * self.head_dim]
|
| 766 |
+
value_states = qkv[..., query_pos + self.num_key_value_heads * self.head_dim :]
|
| 767 |
+
|
| 768 |
+
query_states = query_states.view(bsz, q_len, self.num_heads, self.head_dim).transpose(1, 2)
|
| 769 |
+
key_states = key_states.view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
|
| 770 |
+
value_states = value_states.view(bsz, q_len, self.num_key_value_heads, self.head_dim).transpose(1, 2)
|
| 771 |
+
|
| 772 |
+
kv_seq_len = key_states.shape[-2]
|
| 773 |
+
if past_key_value is not None:
|
| 774 |
+
kv_seq_len += past_key_value.get_usable_length(kv_seq_len, self.layer_idx)
|
| 775 |
+
cos, sin = self.rotary_emb(value_states, position_ids, seq_len=kv_seq_len)
|
| 776 |
+
|
| 777 |
+
query_states, key_states = apply_rotary_pos_emb(query_states, key_states, cos, sin, position_ids)
|
| 778 |
+
|
| 779 |
+
if past_key_value is not None:
|
| 780 |
+
cache_kwargs = {"sin": sin, "cos": cos} # Specific to RoPE models
|
| 781 |
+
key_states, value_states = past_key_value.update(key_states, value_states, self.layer_idx, cache_kwargs)
|
| 782 |
+
|
| 783 |
+
key_states = repeat_kv(key_states, self.num_key_value_groups)
|
| 784 |
+
value_states = repeat_kv(value_states, self.num_key_value_groups)
|
| 785 |
+
|
| 786 |
+
if attention_mask is not None:
|
| 787 |
+
if attention_mask.size() != (bsz, 1, q_len, kv_seq_len):
|
| 788 |
+
raise ValueError(
|
| 789 |
+
f"Attention mask should be of size {(bsz, 1, q_len, kv_seq_len)}, but is {attention_mask.size()}"
|
| 790 |
+
)
|
| 791 |
+
|
| 792 |
+
# SDPA with memory-efficient backend is currently (torch==2.1.2) bugged with non-contiguous inputs with custom attn_mask,
|
| 793 |
+
# Reference: https://github.com/pytorch/pytorch/issues/112577.
|
| 794 |
+
if query_states.device.type == "cuda" and attention_mask is not None:
|
| 795 |
+
query_states = query_states.contiguous()
|
| 796 |
+
key_states = key_states.contiguous()
|
| 797 |
+
value_states = value_states.contiguous()
|
| 798 |
+
|
| 799 |
+
attn_output = torch.nn.functional.scaled_dot_product_attention(
|
| 800 |
+
query_states,
|
| 801 |
+
key_states,
|
| 802 |
+
value_states,
|
| 803 |
+
attn_mask=attention_mask,
|
| 804 |
+
dropout_p=self.attention_dropout if self.training else 0.0,
|
| 805 |
+
# The q_len > 1 is necessary to match with AttentionMaskConverter.to_causal_4d that does not create a causal mask in case q_len == 1.
|
| 806 |
+
is_causal=self.is_causal and attention_mask is None and q_len > 1,
|
| 807 |
+
)
|
| 808 |
+
|
| 809 |
+
attn_output = attn_output.transpose(1, 2).contiguous()
|
| 810 |
+
attn_output = attn_output.view(bsz, q_len, self.hidden_size)
|
| 811 |
+
|
| 812 |
+
attn_output = self.o_proj(attn_output)
|
| 813 |
+
|
| 814 |
+
return attn_output, None, past_key_value
|
| 815 |
+
|
| 816 |
+
|
| 817 |
+
PHI3_ATTENTION_CLASSES = {
|
| 818 |
+
"eager": Phi3Attention,
|
| 819 |
+
"flash_attention_2": Phi3FlashAttention2,
|
| 820 |
+
"sdpa": Phi3SdpaAttention,
|
| 821 |
+
}
|
| 822 |
+
|
| 823 |
+
|
| 824 |
+
class Phi3DecoderLayer(nn.Module):
|
| 825 |
+
def __init__(self, config: Phi3VConfig, layer_idx: int):
|
| 826 |
+
super().__init__()
|
| 827 |
+
|
| 828 |
+
self.config = config
|
| 829 |
+
self.self_attn = PHI3_ATTENTION_CLASSES[config._attn_implementation](config, layer_idx=layer_idx)
|
| 830 |
+
|
| 831 |
+
self.mlp = Phi3MLP(config)
|
| 832 |
+
self.input_layernorm = Phi3RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
| 833 |
+
|
| 834 |
+
self.resid_attn_dropout = nn.Dropout(config.resid_pdrop)
|
| 835 |
+
self.resid_mlp_dropout = nn.Dropout(config.resid_pdrop)
|
| 836 |
+
self.post_attention_layernorm = Phi3RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
| 837 |
+
|
| 838 |
+
def forward(
|
| 839 |
+
self,
|
| 840 |
+
hidden_states: torch.Tensor,
|
| 841 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 842 |
+
position_ids: Optional[torch.LongTensor] = None,
|
| 843 |
+
past_key_value: Optional[Tuple[torch.Tensor]] = None,
|
| 844 |
+
output_attentions: Optional[bool] = False,
|
| 845 |
+
use_cache: Optional[bool] = False,
|
| 846 |
+
**kwargs,
|
| 847 |
+
) -> Tuple[torch.FloatTensor, Optional[Tuple[torch.FloatTensor, torch.FloatTensor]]]:
|
| 848 |
+
if "padding_mask" in kwargs:
|
| 849 |
+
warnings.warn(
|
| 850 |
+
"Passing `padding_mask` is deprecated and will be removed in v4.37. Please make sure use `attention_mask` instead.`"
|
| 851 |
+
)
|
| 852 |
+
"""
|
| 853 |
+
Args:
|
| 854 |
+
hidden_states (`torch.FloatTensor`):
|
| 855 |
+
input to the layer of shape `(batch, seq_len, embed_dim)`
|
| 856 |
+
attention_mask (`torch.FloatTensor`, *optional*): attention mask of size
|
| 857 |
+
`(batch, 1, tgt_len, src_len)` where padding elements are indicated by very large negative values.
|
| 858 |
+
position_ids (`torch.LongTensor` of shape `({0})`, *optional*):
|
| 859 |
+
Indices of positions of each input sequence tokens in the position embeddings. Selected in the range
|
| 860 |
+
`[0, config.n_positions - 1]`. [What are position IDs?](../glossary#position-ids)
|
| 861 |
+
output_attentions (`bool`, *optional*):
|
| 862 |
+
Whether or not to return the attentions tensors of all attention layers. See `attentions` under
|
| 863 |
+
returned tensors for more detail.
|
| 864 |
+
use_cache (`bool`, *optional*):
|
| 865 |
+
If set to `True`, `past_key_values` key value states are returned and can be used to speed up decoding
|
| 866 |
+
(see `past_key_values`).
|
| 867 |
+
past_key_value (`Tuple(torch.FloatTensor)`, *optional*): cached past key and value projection states
|
| 868 |
+
"""
|
| 869 |
+
|
| 870 |
+
residual = hidden_states
|
| 871 |
+
|
| 872 |
+
hidden_states = self.input_layernorm(hidden_states)
|
| 873 |
+
|
| 874 |
+
# Self Attention
|
| 875 |
+
attn_outputs, self_attn_weights, present_key_value = self.self_attn(
|
| 876 |
+
hidden_states=hidden_states,
|
| 877 |
+
attention_mask=attention_mask,
|
| 878 |
+
position_ids=position_ids,
|
| 879 |
+
past_key_value=past_key_value,
|
| 880 |
+
output_attentions=output_attentions,
|
| 881 |
+
use_cache=use_cache,
|
| 882 |
+
)
|
| 883 |
+
|
| 884 |
+
hidden_states = residual + self.resid_attn_dropout(attn_outputs)
|
| 885 |
+
|
| 886 |
+
residual = hidden_states
|
| 887 |
+
hidden_states = self.post_attention_layernorm(hidden_states)
|
| 888 |
+
hidden_states = self.mlp(hidden_states)
|
| 889 |
+
hidden_states = residual + self.resid_mlp_dropout(hidden_states)
|
| 890 |
+
|
| 891 |
+
outputs = (hidden_states,)
|
| 892 |
+
|
| 893 |
+
if output_attentions:
|
| 894 |
+
outputs += (self_attn_weights,)
|
| 895 |
+
|
| 896 |
+
if use_cache:
|
| 897 |
+
outputs += (present_key_value,)
|
| 898 |
+
|
| 899 |
+
return outputs
|
| 900 |
+
|
| 901 |
+
|
| 902 |
+
PHI3V_START_DOCSTRING = r"""
|
| 903 |
+
This model inherits from [`PreTrainedModel`]. Check the superclass documentation for the generic methods the
|
| 904 |
+
library implements for all its model (such as downloading or saving, resizing the input embeddings, pruning heads
|
| 905 |
+
etc.)
|
| 906 |
+
|
| 907 |
+
This model is also a PyTorch [torch.nn.Module](https://pytorch.org/docs/stable/nn.html#torch.nn.Module) subclass.
|
| 908 |
+
Use it as a regular PyTorch Module and refer to the PyTorch documentation for all matter related to general usage
|
| 909 |
+
and behavior.
|
| 910 |
+
|
| 911 |
+
Parameters:
|
| 912 |
+
config ([`Phi3VConfig`]):
|
| 913 |
+
Model configuration class with all the parameters of the model. Initializing with a config file does not
|
| 914 |
+
load the weights associated with the model, only the configuration. Check out the
|
| 915 |
+
[`~PreTrainedModel.from_pretrained`] method to load the model weights.
|
| 916 |
+
"""
|
| 917 |
+
|
| 918 |
+
|
| 919 |
+
@add_start_docstrings(
|
| 920 |
+
"The bare Phi-3-V model outputting raw hidden-states without any specific head on top.",
|
| 921 |
+
PHI3V_START_DOCSTRING,
|
| 922 |
+
)
|
| 923 |
+
class Phi3VPreTrainedModel(PreTrainedModel):
|
| 924 |
+
config_class = Phi3VConfig
|
| 925 |
+
base_model_prefix = "model"
|
| 926 |
+
supports_gradient_checkpointing = True
|
| 927 |
+
_no_split_modules = ["Phi3DecoderLayer"]
|
| 928 |
+
_skip_keys_device_placement = "past_key_values"
|
| 929 |
+
_supports_flash_attn_2 = True
|
| 930 |
+
_supports_sdpa = False
|
| 931 |
+
_supports_cache_class = True
|
| 932 |
+
|
| 933 |
+
_version = "0.0.5"
|
| 934 |
+
|
| 935 |
+
def _init_weights(self, module):
|
| 936 |
+
std = self.config.initializer_range
|
| 937 |
+
if isinstance(module, nn.Linear):
|
| 938 |
+
module.weight.data.normal_(mean=0.0, std=std)
|
| 939 |
+
if module.bias is not None:
|
| 940 |
+
module.bias.data.zero_()
|
| 941 |
+
elif isinstance(module, nn.Embedding):
|
| 942 |
+
module.weight.data.normal_(mean=0.0, std=std)
|
| 943 |
+
if module.padding_idx is not None:
|
| 944 |
+
module.weight.data[module.padding_idx].zero_()
|
| 945 |
+
|
| 946 |
+
|
| 947 |
+
PHI3V_INPUTS_DOCSTRING = r"""
|
| 948 |
+
Args:
|
| 949 |
+
input_ids (`torch.LongTensor` of shape `(batch_size, sequence_length)`):
|
| 950 |
+
Indices of input sequence tokens in the vocabulary. Padding will be ignored by default should you provide
|
| 951 |
+
it.
|
| 952 |
+
|
| 953 |
+
Indices can be obtained using [`AutoTokenizer`]. See [`PreTrainedTokenizer.encode`] and
|
| 954 |
+
[`PreTrainedTokenizer.__call__`] for details.
|
| 955 |
+
|
| 956 |
+
[What are input IDs?](../glossary#input-ids)
|
| 957 |
+
attention_mask (`torch.Tensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 958 |
+
Mask to avoid performing attention on padding token indices. Mask values selected in `[0, 1]`:
|
| 959 |
+
|
| 960 |
+
- 1 for tokens that are **not masked**,
|
| 961 |
+
- 0 for tokens that are **masked**.
|
| 962 |
+
|
| 963 |
+
[What are attention masks?](../glossary#attention-mask)
|
| 964 |
+
|
| 965 |
+
Indices can be obtained using [`AutoTokenizer`]. See [`PreTrainedTokenizer.encode`] and
|
| 966 |
+
[`PreTrainedTokenizer.__call__`] for details.
|
| 967 |
+
|
| 968 |
+
If `past_key_values` is used, optionally only the last `input_ids` have to be input (see
|
| 969 |
+
`past_key_values`).
|
| 970 |
+
|
| 971 |
+
If you want to change padding behavior, you should read [`modeling_opt._prepare_decoder_attention_mask`]
|
| 972 |
+
and modify to your needs. See diagram 1 in [the paper](https://arxiv.org/abs/1910.13461) for more
|
| 973 |
+
information on the default strategy.
|
| 974 |
+
|
| 975 |
+
- 1 indicates the head is **not masked**,
|
| 976 |
+
- 0 indicates the head is **masked**.
|
| 977 |
+
position_ids (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 978 |
+
Indices of positions of each input sequence tokens in the position embeddings. Selected in the range `[0,
|
| 979 |
+
config.n_positions - 1]`.
|
| 980 |
+
|
| 981 |
+
[What are position IDs?](../glossary#position-ids)
|
| 982 |
+
past_key_values (`Cache` or `tuple(tuple(torch.FloatTensor))`, *optional*):
|
| 983 |
+
Pre-computed hidden-states (key and values in the self-attention blocks and in the cross-attention
|
| 984 |
+
blocks) that can be used to speed up sequential decoding. This typically consists in the `past_key_values`
|
| 985 |
+
returned by the model at a previous stage of decoding, when `use_cache=True` or `config.use_cache=True`.
|
| 986 |
+
|
| 987 |
+
Two formats are allowed:
|
| 988 |
+
- a [`~cache_utils.Cache`] instance;
|
| 989 |
+
- Tuple of `tuple(torch.FloatTensor)` of length `config.n_layers`, with each tuple having 2 tensors of
|
| 990 |
+
shape `(batch_size, num_heads, sequence_length, embed_size_per_head)`). This is also known as the legacy
|
| 991 |
+
cache format.
|
| 992 |
+
|
| 993 |
+
The model will output the same cache format that is fed as input. If no `past_key_values` are passed, the
|
| 994 |
+
legacy cache format will be returned.
|
| 995 |
+
|
| 996 |
+
If `past_key_values` are used, the user can optionally input only the last `input_ids` (those that don't
|
| 997 |
+
have their past key value states given to this model) of shape `(batch_size, 1)` instead of all `input_ids`
|
| 998 |
+
of shape `(batch_size, sequence_length)`.
|
| 999 |
+
inputs_embeds (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`, *optional*):
|
| 1000 |
+
Optionally, instead of passing `input_ids` you can choose to directly pass an embedded representation. This
|
| 1001 |
+
is useful if you want more control over how to convert `input_ids` indices into associated vectors than the
|
| 1002 |
+
model's internal embedding lookup matrix.
|
| 1003 |
+
pixel_values (`torch.FloatTensor` of shape `(batch_size, num_channels, image_size, image_size)):
|
| 1004 |
+
The tensors corresponding to the input images. Pixel values can be obtained using [`AutoImageProcessor`].
|
| 1005 |
+
See [`Phi3ImageProcessor.__call__`] for details.
|
| 1006 |
+
image_sizes (`torch.LongTensor` of shape `(batch_size, 2)`, *optional*):
|
| 1007 |
+
The sizes of the images in the batch, being (height, width) for each image.
|
| 1008 |
+
use_cache (`bool`, *optional*):
|
| 1009 |
+
If set to `True`, `past_key_values` key value states are returned and can be used to speed up decoding (see
|
| 1010 |
+
`past_key_values`).
|
| 1011 |
+
output_attentions (`bool`, *optional*):
|
| 1012 |
+
Whether or not to return the attentions tensors of all attention layers. See `attentions` under returned
|
| 1013 |
+
tensors for more detail.
|
| 1014 |
+
output_hidden_states (`bool`, *optional*):
|
| 1015 |
+
Whether or not to return the hidden states of all layers. See `hidden_states` under returned tensors for
|
| 1016 |
+
more detail.
|
| 1017 |
+
return_dict (`bool`, *optional*):
|
| 1018 |
+
Whether or not to return a [`~utils.ModelOutput`] instead of a plain tuple.
|
| 1019 |
+
"""
|
| 1020 |
+
|
| 1021 |
+
|
| 1022 |
+
@add_start_docstrings(
|
| 1023 |
+
"The bare Phi-3-V model outputting raw hidden-states without any specific head on top.",
|
| 1024 |
+
PHI3V_START_DOCSTRING,
|
| 1025 |
+
)
|
| 1026 |
+
class Phi3VModel(Phi3VPreTrainedModel):
|
| 1027 |
+
"""
|
| 1028 |
+
Transformer decoder consisting of *config.num_hidden_layers* layers. Each layer is a [`Phi3DecoderLayer`]
|
| 1029 |
+
|
| 1030 |
+
Args:
|
| 1031 |
+
config: Phi3Config
|
| 1032 |
+
"""
|
| 1033 |
+
|
| 1034 |
+
def __init__(self, config: Phi3VConfig):
|
| 1035 |
+
super().__init__(config)
|
| 1036 |
+
self.padding_idx = config.pad_token_id
|
| 1037 |
+
self.vocab_size = config.vocab_size
|
| 1038 |
+
|
| 1039 |
+
self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
|
| 1040 |
+
self.embed_dropout = nn.Dropout(config.embd_pdrop)
|
| 1041 |
+
|
| 1042 |
+
self.vision_embed_tokens = None
|
| 1043 |
+
if isinstance(config.embd_layer, dict):
|
| 1044 |
+
# vision embedding layer
|
| 1045 |
+
embedding_config = {
|
| 1046 |
+
'embedding_cls': config.embd_layer['embedding_cls'],
|
| 1047 |
+
**config.embd_layer
|
| 1048 |
+
}
|
| 1049 |
+
self.vision_embed_tokens = Phi3ImageEmbedding(config, wte=self.embed_tokens, **embedding_config)
|
| 1050 |
+
# # set wte the same for vision embedding
|
| 1051 |
+
# self.vision_embed_tokens.wte.weight = self.embed_tokens.weight
|
| 1052 |
+
|
| 1053 |
+
self.layers = nn.ModuleList(
|
| 1054 |
+
[Phi3DecoderLayer(config, layer_idx) for layer_idx in range(config.num_hidden_layers)]
|
| 1055 |
+
)
|
| 1056 |
+
self._attn_implementation = config._attn_implementation
|
| 1057 |
+
self.norm = Phi3RMSNorm(config.hidden_size, eps=config.rms_norm_eps)
|
| 1058 |
+
|
| 1059 |
+
self.gradient_checkpointing = False
|
| 1060 |
+
# Initialize weights and apply final processing
|
| 1061 |
+
self.post_init()
|
| 1062 |
+
|
| 1063 |
+
def get_input_embeddings(self):
|
| 1064 |
+
return self.embed_tokens
|
| 1065 |
+
|
| 1066 |
+
def set_input_embeddings(self, value):
|
| 1067 |
+
self.embed_tokens = value
|
| 1068 |
+
|
| 1069 |
+
@add_start_docstrings_to_model_forward(PHI3V_INPUTS_DOCSTRING)
|
| 1070 |
+
def forward(
|
| 1071 |
+
self,
|
| 1072 |
+
input_ids: torch.LongTensor = None,
|
| 1073 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 1074 |
+
position_ids: Optional[torch.LongTensor] = None,
|
| 1075 |
+
past_key_values: Optional[List[torch.FloatTensor]] = None,
|
| 1076 |
+
inputs_embeds: Optional[torch.FloatTensor] = None,
|
| 1077 |
+
pixel_values: Optional[torch.FloatTensor] = None,
|
| 1078 |
+
image_sizes: Optional[torch.LongTensor] = None,
|
| 1079 |
+
use_cache: Optional[bool] = None,
|
| 1080 |
+
output_attentions: Optional[bool] = None,
|
| 1081 |
+
output_hidden_states: Optional[bool] = None,
|
| 1082 |
+
return_dict: Optional[bool] = None,
|
| 1083 |
+
) -> Union[Tuple, BaseModelOutputWithPast]:
|
| 1084 |
+
output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
|
| 1085 |
+
output_hidden_states = (
|
| 1086 |
+
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
|
| 1087 |
+
)
|
| 1088 |
+
use_cache = use_cache if use_cache is not None else self.config.use_cache
|
| 1089 |
+
|
| 1090 |
+
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
| 1091 |
+
|
| 1092 |
+
# retrieve input_ids and inputs_embeds
|
| 1093 |
+
if input_ids is not None and inputs_embeds is not None:
|
| 1094 |
+
raise ValueError("You cannot specify both input_ids and inputs_embeds at the same time")
|
| 1095 |
+
elif input_ids is not None:
|
| 1096 |
+
batch_size, seq_length = input_ids.shape[:2]
|
| 1097 |
+
elif inputs_embeds is not None:
|
| 1098 |
+
batch_size, seq_length = inputs_embeds.shape[:2]
|
| 1099 |
+
else:
|
| 1100 |
+
raise ValueError("You have to specify either input_ids or inputs_embeds")
|
| 1101 |
+
|
| 1102 |
+
past_key_values_length = 0
|
| 1103 |
+
|
| 1104 |
+
if self.gradient_checkpointing and self.training:
|
| 1105 |
+
if use_cache:
|
| 1106 |
+
logger.warning_once(
|
| 1107 |
+
"`use_cache=True` is incompatible with gradient checkpointing. Setting `use_cache=False`..."
|
| 1108 |
+
)
|
| 1109 |
+
use_cache = False
|
| 1110 |
+
|
| 1111 |
+
if use_cache:
|
| 1112 |
+
use_legacy_cache = not isinstance(past_key_values, Cache)
|
| 1113 |
+
if use_legacy_cache:
|
| 1114 |
+
past_key_values = DynamicCache.from_legacy_cache(past_key_values)
|
| 1115 |
+
past_key_values_length = past_key_values.get_usable_length(seq_length)
|
| 1116 |
+
|
| 1117 |
+
if position_ids is None:
|
| 1118 |
+
device = input_ids.device if input_ids is not None else inputs_embeds.device
|
| 1119 |
+
position_ids = torch.arange(
|
| 1120 |
+
past_key_values_length, seq_length + past_key_values_length, dtype=torch.long, device=device
|
| 1121 |
+
)
|
| 1122 |
+
position_ids = position_ids.unsqueeze(0).view(-1, seq_length)
|
| 1123 |
+
else:
|
| 1124 |
+
position_ids = position_ids.view(-1, seq_length).long()
|
| 1125 |
+
|
| 1126 |
+
if inputs_embeds is None:
|
| 1127 |
+
if pixel_values is not None and image_sizes is not None:
|
| 1128 |
+
assert self.vision_embed_tokens is not None, "Vision embedding layer is not defined"
|
| 1129 |
+
inputs_embeds = self.vision_embed_tokens(input_ids, pixel_values=pixel_values, image_sizes=image_sizes)
|
| 1130 |
+
else:
|
| 1131 |
+
inputs_embeds = self.embed_tokens(input_ids)
|
| 1132 |
+
|
| 1133 |
+
if attention_mask is not None and self._attn_implementation == "flash_attention_2" and use_cache:
|
| 1134 |
+
is_padding_right = attention_mask[:, -1].sum().item() != batch_size
|
| 1135 |
+
if is_padding_right:
|
| 1136 |
+
raise ValueError(
|
| 1137 |
+
"You are attempting to perform batched generation with padding_side='right'"
|
| 1138 |
+
" this may lead to unexpected behaviour for Flash Attention version of Phi3. Make sure to "
|
| 1139 |
+
" call `tokenizer.padding_side = 'left'` before tokenizing the input. "
|
| 1140 |
+
)
|
| 1141 |
+
|
| 1142 |
+
if self._attn_implementation == "flash_attention_2":
|
| 1143 |
+
# 2d mask is passed through the layers
|
| 1144 |
+
attention_mask = attention_mask if (attention_mask is not None and 0 in attention_mask) else None
|
| 1145 |
+
else:
|
| 1146 |
+
# 4d mask is passed through the layers
|
| 1147 |
+
attention_mask = _prepare_4d_causal_attention_mask(
|
| 1148 |
+
attention_mask,
|
| 1149 |
+
(batch_size, seq_length),
|
| 1150 |
+
inputs_embeds,
|
| 1151 |
+
past_key_values_length,
|
| 1152 |
+
sliding_window=self.config.sliding_window,
|
| 1153 |
+
)
|
| 1154 |
+
|
| 1155 |
+
hidden_states = inputs_embeds
|
| 1156 |
+
|
| 1157 |
+
# decoder layers
|
| 1158 |
+
all_hidden_states = () if output_hidden_states else None
|
| 1159 |
+
all_self_attns = () if output_attentions else None
|
| 1160 |
+
next_decoder_cache = None
|
| 1161 |
+
|
| 1162 |
+
for decoder_layer in self.layers:
|
| 1163 |
+
if output_hidden_states:
|
| 1164 |
+
all_hidden_states += (hidden_states,)
|
| 1165 |
+
|
| 1166 |
+
if self.gradient_checkpointing and self.training:
|
| 1167 |
+
layer_outputs = self._gradient_checkpointing_func(
|
| 1168 |
+
decoder_layer.__call__,
|
| 1169 |
+
hidden_states,
|
| 1170 |
+
attention_mask,
|
| 1171 |
+
position_ids,
|
| 1172 |
+
past_key_values,
|
| 1173 |
+
output_attentions,
|
| 1174 |
+
use_cache,
|
| 1175 |
+
)
|
| 1176 |
+
else:
|
| 1177 |
+
layer_outputs = decoder_layer(
|
| 1178 |
+
hidden_states,
|
| 1179 |
+
attention_mask=attention_mask,
|
| 1180 |
+
position_ids=position_ids,
|
| 1181 |
+
past_key_value=past_key_values,
|
| 1182 |
+
output_attentions=output_attentions,
|
| 1183 |
+
use_cache=use_cache,
|
| 1184 |
+
)
|
| 1185 |
+
|
| 1186 |
+
hidden_states = layer_outputs[0]
|
| 1187 |
+
|
| 1188 |
+
if use_cache:
|
| 1189 |
+
next_decoder_cache = layer_outputs[2 if output_attentions else 1]
|
| 1190 |
+
|
| 1191 |
+
if output_attentions:
|
| 1192 |
+
all_self_attns += (layer_outputs[1],)
|
| 1193 |
+
|
| 1194 |
+
hidden_states = self.norm(hidden_states)
|
| 1195 |
+
|
| 1196 |
+
# add hidden states from the last decoder layer
|
| 1197 |
+
if output_hidden_states:
|
| 1198 |
+
all_hidden_states += (hidden_states,)
|
| 1199 |
+
|
| 1200 |
+
next_cache = None
|
| 1201 |
+
if use_cache:
|
| 1202 |
+
next_cache = next_decoder_cache.to_legacy_cache() if use_legacy_cache else next_decoder_cache
|
| 1203 |
+
if not return_dict:
|
| 1204 |
+
return tuple(v for v in [hidden_states, next_cache, all_hidden_states, all_self_attns] if v is not None)
|
| 1205 |
+
return BaseModelOutputWithPast(
|
| 1206 |
+
last_hidden_state=hidden_states,
|
| 1207 |
+
past_key_values=next_cache,
|
| 1208 |
+
hidden_states=all_hidden_states,
|
| 1209 |
+
attentions=all_self_attns,
|
| 1210 |
+
)
|
| 1211 |
+
|
| 1212 |
+
|
| 1213 |
+
class Phi3VForCausalLM(Phi3VPreTrainedModel):
|
| 1214 |
+
_tied_weights_keys = ["lm_head.weight"]
|
| 1215 |
+
|
| 1216 |
+
# Copied from transformers.models.llama.modeling_llama.LlamaForCausalLM.__init__ with Llama->Phi3
|
| 1217 |
+
def __init__(self, config):
|
| 1218 |
+
super().__init__(config)
|
| 1219 |
+
self.model = Phi3VModel(config)
|
| 1220 |
+
self.vocab_size = config.vocab_size
|
| 1221 |
+
self.lm_head = nn.Linear(config.hidden_size, config.vocab_size, bias=False)
|
| 1222 |
+
|
| 1223 |
+
# Initialize weights and apply final processing
|
| 1224 |
+
self.post_init()
|
| 1225 |
+
|
| 1226 |
+
# Copied from transformers.models.llama.modeling_llama.LlamaForCausalLM.get_input_embeddings
|
| 1227 |
+
def get_input_embeddings(self):
|
| 1228 |
+
return self.model.embed_tokens
|
| 1229 |
+
|
| 1230 |
+
# Copied from transformers.models.llama.modeling_llama.LlamaForCausalLM.set_input_embeddings
|
| 1231 |
+
def set_input_embeddings(self, value):
|
| 1232 |
+
self.model.embed_tokens = value
|
| 1233 |
+
|
| 1234 |
+
# Copied from transformers.models.llama.modeling_llama.LlamaForCausalLM.get_output_embeddings
|
| 1235 |
+
def get_output_embeddings(self):
|
| 1236 |
+
return self.lm_head
|
| 1237 |
+
|
| 1238 |
+
# Copied from transformers.models.llama.modeling_llama.LlamaForCausalLM.set_output_embeddings
|
| 1239 |
+
def set_output_embeddings(self, new_embeddings):
|
| 1240 |
+
self.lm_head = new_embeddings
|
| 1241 |
+
|
| 1242 |
+
# Copied from transformers.models.llama.modeling_llama.LlamaForCausalLM.set_decoder
|
| 1243 |
+
def set_decoder(self, decoder):
|
| 1244 |
+
self.model = decoder
|
| 1245 |
+
|
| 1246 |
+
# Copied from transformers.models.llama.modeling_llama.LlamaForCausalLM.get_decoder
|
| 1247 |
+
def get_decoder(self):
|
| 1248 |
+
return self.model
|
| 1249 |
+
|
| 1250 |
+
# Ignore copy
|
| 1251 |
+
@add_start_docstrings_to_model_forward(PHI3V_INPUTS_DOCSTRING)
|
| 1252 |
+
@replace_return_docstrings(output_type=CausalLMOutputWithPast, config_class=_CONFIG_FOR_DOC)
|
| 1253 |
+
def forward(
|
| 1254 |
+
self,
|
| 1255 |
+
input_ids: torch.LongTensor = None,
|
| 1256 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 1257 |
+
position_ids: Optional[torch.LongTensor] = None,
|
| 1258 |
+
past_key_values: Optional[List[torch.FloatTensor]] = None,
|
| 1259 |
+
inputs_embeds: Optional[torch.FloatTensor] = None,
|
| 1260 |
+
pixel_values: Optional[torch.FloatTensor] = None,
|
| 1261 |
+
image_sizes: Optional[torch.LongTensor] = None,
|
| 1262 |
+
labels: Optional[torch.LongTensor] = None,
|
| 1263 |
+
use_cache: Optional[bool] = None,
|
| 1264 |
+
output_attentions: Optional[bool] = None,
|
| 1265 |
+
output_hidden_states: Optional[bool] = None,
|
| 1266 |
+
return_dict: Optional[bool] = None,
|
| 1267 |
+
) -> Union[Tuple, CausalLMOutputWithPast]:
|
| 1268 |
+
r"""
|
| 1269 |
+
Args:
|
| 1270 |
+
labels (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
|
| 1271 |
+
Labels for computing the masked language modeling loss. Indices should either be in `[0, ...,
|
| 1272 |
+
config.vocab_size]` or -100 (see `input_ids` docstring). Tokens with indices set to `-100` are ignored
|
| 1273 |
+
(masked), the loss is only computed for the tokens with labels in `[0, ..., config.vocab_size]`.
|
| 1274 |
+
|
| 1275 |
+
Returns:
|
| 1276 |
+
|
| 1277 |
+
Example:
|
| 1278 |
+
|
| 1279 |
+
```python
|
| 1280 |
+
>>> from transformers import AutoTokenizer, Phi3ForCausalLM
|
| 1281 |
+
|
| 1282 |
+
>>> model = Phi3ForCausalLM.from_pretrained("microsoft/phi-3-mini-4k-instruct")
|
| 1283 |
+
>>> tokenizer = AutoTokenizer.from_pretrained("microsoft/phi-3-mini-4k-instruct")
|
| 1284 |
+
|
| 1285 |
+
>>> prompt = "This is an example script ."
|
| 1286 |
+
>>> inputs = tokenizer(prompt, return_tensors="pt")
|
| 1287 |
+
|
| 1288 |
+
>>> # Generate
|
| 1289 |
+
>>> generate_ids = model.generate(inputs.input_ids, max_length=30)
|
| 1290 |
+
>>> tokenizer.batch_decode(generate_ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
|
| 1291 |
+
'This is an example script .\n Certainly! Below is a sample script that demonstrates a simple task, such as calculating the sum'
|
| 1292 |
+
```"""
|
| 1293 |
+
|
| 1294 |
+
output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
|
| 1295 |
+
output_hidden_states = (
|
| 1296 |
+
output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
|
| 1297 |
+
)
|
| 1298 |
+
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
| 1299 |
+
|
| 1300 |
+
# decoder outputs consists of (dec_features, layer_state, dec_hidden, dec_attn)
|
| 1301 |
+
outputs = self.model(
|
| 1302 |
+
input_ids=input_ids,
|
| 1303 |
+
attention_mask=attention_mask,
|
| 1304 |
+
position_ids=position_ids,
|
| 1305 |
+
past_key_values=past_key_values,
|
| 1306 |
+
inputs_embeds=inputs_embeds,
|
| 1307 |
+
pixel_values=pixel_values,
|
| 1308 |
+
image_sizes=image_sizes,
|
| 1309 |
+
use_cache=use_cache,
|
| 1310 |
+
output_attentions=output_attentions,
|
| 1311 |
+
output_hidden_states=output_hidden_states,
|
| 1312 |
+
return_dict=return_dict,
|
| 1313 |
+
)
|
| 1314 |
+
|
| 1315 |
+
hidden_states = outputs[0]
|
| 1316 |
+
logits = self.lm_head(hidden_states)
|
| 1317 |
+
logits = logits.float()
|
| 1318 |
+
|
| 1319 |
+
loss = None
|
| 1320 |
+
if labels is not None:
|
| 1321 |
+
# Shift so that tokens < n predict n
|
| 1322 |
+
shift_logits = logits[..., :-1, :].contiguous()
|
| 1323 |
+
shift_labels = labels[..., 1:].contiguous()
|
| 1324 |
+
# Flatten the tokens
|
| 1325 |
+
loss_fct = CrossEntropyLoss()
|
| 1326 |
+
shift_logits = shift_logits.view(-1, self.config.vocab_size)
|
| 1327 |
+
shift_labels = shift_labels.view(-1)
|
| 1328 |
+
# Enable model parallelism
|
| 1329 |
+
shift_labels = shift_labels.to(shift_logits.device)
|
| 1330 |
+
loss = loss_fct(shift_logits, shift_labels)
|
| 1331 |
+
|
| 1332 |
+
if not return_dict:
|
| 1333 |
+
output = (logits,) + outputs[1:]
|
| 1334 |
+
return (loss,) + output if loss is not None else output
|
| 1335 |
+
|
| 1336 |
+
return CausalLMOutputWithPast(
|
| 1337 |
+
loss=loss,
|
| 1338 |
+
logits=logits,
|
| 1339 |
+
past_key_values=outputs.past_key_values,
|
| 1340 |
+
hidden_states=outputs.hidden_states,
|
| 1341 |
+
attentions=outputs.attentions,
|
| 1342 |
+
)
|
| 1343 |
+
|
| 1344 |
+
# Copied from transformers.models.persimmon.modeling_persimmon.PersimmonForCausalLM.prepare_inputs_for_generation
|
| 1345 |
+
def prepare_inputs_for_generation(
|
| 1346 |
+
self, input_ids, past_key_values=None, attention_mask=None, inputs_embeds=None, pixel_values=None, image_sizes=None, **kwargs
|
| 1347 |
+
):
|
| 1348 |
+
if past_key_values is not None:
|
| 1349 |
+
if isinstance(past_key_values, Cache):
|
| 1350 |
+
cache_length = past_key_values.get_seq_length()
|
| 1351 |
+
past_length = past_key_values.seen_tokens
|
| 1352 |
+
max_cache_length = past_key_values.get_max_length()
|
| 1353 |
+
else:
|
| 1354 |
+
cache_length = past_length = past_key_values[0][0].shape[2]
|
| 1355 |
+
max_cache_length = None
|
| 1356 |
+
|
| 1357 |
+
# Keep only the unprocessed tokens:
|
| 1358 |
+
# 1 - If the length of the attention_mask exceeds the length of input_ids, then we are in a setting where
|
| 1359 |
+
# some of the inputs are exclusively passed as part of the cache (e.g. when passing input_embeds as
|
| 1360 |
+
# input)
|
| 1361 |
+
if attention_mask is not None and attention_mask.shape[1] > input_ids.shape[1]:
|
| 1362 |
+
input_ids = input_ids[:, -(attention_mask.shape[1] - past_length) :]
|
| 1363 |
+
# 2 - If the past_length is smaller than input_ids', then input_ids holds all input tokens. We can discard
|
| 1364 |
+
# input_ids based on the past_length.
|
| 1365 |
+
elif past_length < input_ids.shape[1]:
|
| 1366 |
+
input_ids = input_ids[:, past_length:]
|
| 1367 |
+
# 3 - Otherwise (past_length >= input_ids.shape[1]), let's assume input_ids only has unprocessed tokens.
|
| 1368 |
+
|
| 1369 |
+
# If we are about to go beyond the maximum cache length, we need to crop the input attention mask.
|
| 1370 |
+
if (
|
| 1371 |
+
max_cache_length is not None
|
| 1372 |
+
and attention_mask is not None
|
| 1373 |
+
and cache_length + input_ids.shape[1] > max_cache_length
|
| 1374 |
+
):
|
| 1375 |
+
attention_mask = attention_mask[:, -max_cache_length:]
|
| 1376 |
+
|
| 1377 |
+
position_ids = kwargs.get("position_ids", None)
|
| 1378 |
+
if attention_mask is not None and position_ids is None:
|
| 1379 |
+
# create position_ids on the fly for batch generation
|
| 1380 |
+
position_ids = attention_mask.long().cumsum(-1) - 1
|
| 1381 |
+
position_ids.masked_fill_(attention_mask == 0, 1)
|
| 1382 |
+
if past_key_values:
|
| 1383 |
+
position_ids = position_ids[:, -input_ids.shape[1] :]
|
| 1384 |
+
|
| 1385 |
+
# if `inputs_embeds` are passed, we only want to use them in the 1st generation step
|
| 1386 |
+
if inputs_embeds is not None and past_key_values is None:
|
| 1387 |
+
model_inputs = {"inputs_embeds": inputs_embeds}
|
| 1388 |
+
else:
|
| 1389 |
+
model_inputs = {"input_ids": input_ids}
|
| 1390 |
+
|
| 1391 |
+
model_inputs.update(
|
| 1392 |
+
{
|
| 1393 |
+
"position_ids": position_ids,
|
| 1394 |
+
"past_key_values": past_key_values,
|
| 1395 |
+
"use_cache": kwargs.get("use_cache"),
|
| 1396 |
+
"attention_mask": attention_mask,
|
| 1397 |
+
"pixel_values": pixel_values,
|
| 1398 |
+
"image_sizes": image_sizes,
|
| 1399 |
+
}
|
| 1400 |
+
)
|
| 1401 |
+
return model_inputs
|
| 1402 |
+
|
| 1403 |
+
@staticmethod
|
| 1404 |
+
# Copied from transformers.models.llama.modeling_llama.LlamaForCausalLM._reorder_cache
|
| 1405 |
+
def _reorder_cache(past_key_values, beam_idx):
|
| 1406 |
+
reordered_past = ()
|
| 1407 |
+
for layer_past in past_key_values:
|
| 1408 |
+
reordered_past += (
|
| 1409 |
+
tuple(past_state.index_select(0, beam_idx.to(past_state.device)) for past_state in layer_past),
|
| 1410 |
+
)
|
| 1411 |
+
return reordered_past
|
| 1412 |
+
|
| 1413 |
+
|
| 1414 |
+
@add_start_docstrings(
|
| 1415 |
+
"""
|
| 1416 |
+
The [`Phi3VModel`] with a sequence classification head on top (linear layer).
|
| 1417 |
+
|
| 1418 |
+
[`Phi3VForSequenceClassification`] uses the last token in order to do the classification, as other causal models
|
| 1419 |
+
(e.g. GPT-2) do.
|
| 1420 |
+
|
| 1421 |
+
Since it does classification on the last token, it requires to know the position of the last token. If a
|
| 1422 |
+
`pad_token_id` is defined in the configuration, it finds the last token that is not a padding token in each row. If
|
| 1423 |
+
no `pad_token_id` is defined, it simply takes the last value in each row of the batch. Since it cannot guess the
|
| 1424 |
+
padding tokens when `inputs_embeds` are passed instead of `input_ids`, it does the same (take the last value in
|
| 1425 |
+
each row of the batch).
|
| 1426 |
+
""",
|
| 1427 |
+
PHI3V_START_DOCSTRING,
|
| 1428 |
+
)
|
| 1429 |
+
# Copied from transformers.models.llama.modeling_llama.LlamaForSequenceClassification with Llama->Phi3, LLAMA->PHI3, self.transformer->self.model, transformer_outputs->model_outputs
|
| 1430 |
+
class Phi3VForSequenceClassification(Phi3VPreTrainedModel):
|
| 1431 |
+
def __init__(self, config):
|
| 1432 |
+
super().__init__(config)
|
| 1433 |
+
self.num_labels = config.num_labels
|
| 1434 |
+
self.model = Phi3VModel(config)
|
| 1435 |
+
self.score = nn.Linear(config.hidden_size, self.num_labels, bias=False)
|
| 1436 |
+
|
| 1437 |
+
# Initialize weights and apply final processing
|
| 1438 |
+
self.post_init()
|
| 1439 |
+
|
| 1440 |
+
def get_input_embeddings(self):
|
| 1441 |
+
return self.model.embed_tokens
|
| 1442 |
+
|
| 1443 |
+
def set_input_embeddings(self, value):
|
| 1444 |
+
self.model.embed_tokens = value
|
| 1445 |
+
|
| 1446 |
+
@add_start_docstrings_to_model_forward(PHI3V_INPUTS_DOCSTRING)
|
| 1447 |
+
def forward(
|
| 1448 |
+
self,
|
| 1449 |
+
input_ids: torch.LongTensor = None,
|
| 1450 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 1451 |
+
position_ids: Optional[torch.LongTensor] = None,
|
| 1452 |
+
past_key_values: Optional[Union[Cache, List[torch.FloatTensor]]] = None,
|
| 1453 |
+
inputs_embeds: Optional[torch.FloatTensor] = None,
|
| 1454 |
+
pixel_values: Optional[torch.FloatTensor] = None,
|
| 1455 |
+
image_sizes: Optional[torch.LongTensor] = None,
|
| 1456 |
+
labels: Optional[torch.LongTensor] = None,
|
| 1457 |
+
use_cache: Optional[bool] = None,
|
| 1458 |
+
output_attentions: Optional[bool] = None,
|
| 1459 |
+
output_hidden_states: Optional[bool] = None,
|
| 1460 |
+
return_dict: Optional[bool] = None,
|
| 1461 |
+
) -> Union[Tuple, SequenceClassifierOutputWithPast]:
|
| 1462 |
+
r"""
|
| 1463 |
+
labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
|
| 1464 |
+
Labels for computing the sequence classification/regression loss. Indices should be in `[0, ...,
|
| 1465 |
+
config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
|
| 1466 |
+
`config.num_labels > 1` a classification loss is computed (Cross-Entropy).
|
| 1467 |
+
"""
|
| 1468 |
+
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
| 1469 |
+
|
| 1470 |
+
model_outputs = self.model(
|
| 1471 |
+
input_ids,
|
| 1472 |
+
attention_mask=attention_mask,
|
| 1473 |
+
position_ids=position_ids,
|
| 1474 |
+
past_key_values=past_key_values,
|
| 1475 |
+
inputs_embeds=inputs_embeds,
|
| 1476 |
+
pixel_values=pixel_values,
|
| 1477 |
+
image_sizes=image_sizes,
|
| 1478 |
+
use_cache=use_cache,
|
| 1479 |
+
output_attentions=output_attentions,
|
| 1480 |
+
output_hidden_states=output_hidden_states,
|
| 1481 |
+
return_dict=return_dict,
|
| 1482 |
+
)
|
| 1483 |
+
hidden_states = model_outputs[0]
|
| 1484 |
+
logits = self.score(hidden_states)
|
| 1485 |
+
|
| 1486 |
+
if input_ids is not None:
|
| 1487 |
+
batch_size = input_ids.shape[0]
|
| 1488 |
+
else:
|
| 1489 |
+
batch_size = inputs_embeds.shape[0]
|
| 1490 |
+
|
| 1491 |
+
if self.config.pad_token_id is None and batch_size != 1:
|
| 1492 |
+
raise ValueError("Cannot handle batch sizes > 1 if no padding token is defined.")
|
| 1493 |
+
if self.config.pad_token_id is None:
|
| 1494 |
+
sequence_lengths = -1
|
| 1495 |
+
else:
|
| 1496 |
+
if input_ids is not None:
|
| 1497 |
+
# if no pad token found, use modulo instead of reverse indexing for ONNX compatibility
|
| 1498 |
+
sequence_lengths = torch.eq(input_ids, self.config.pad_token_id).int().argmax(-1) - 1
|
| 1499 |
+
sequence_lengths = sequence_lengths % input_ids.shape[-1]
|
| 1500 |
+
sequence_lengths = sequence_lengths.to(logits.device)
|
| 1501 |
+
else:
|
| 1502 |
+
sequence_lengths = -1
|
| 1503 |
+
|
| 1504 |
+
pooled_logits = logits[torch.arange(batch_size, device=logits.device), sequence_lengths]
|
| 1505 |
+
|
| 1506 |
+
loss = None
|
| 1507 |
+
if labels is not None:
|
| 1508 |
+
labels = labels.to(logits.device)
|
| 1509 |
+
if self.config.problem_type is None:
|
| 1510 |
+
if self.num_labels == 1:
|
| 1511 |
+
self.config.problem_type = "regression"
|
| 1512 |
+
elif self.num_labels > 1 and (labels.dtype == torch.long or labels.dtype == torch.int):
|
| 1513 |
+
self.config.problem_type = "single_label_classification"
|
| 1514 |
+
else:
|
| 1515 |
+
self.config.problem_type = "multi_label_classification"
|
| 1516 |
+
|
| 1517 |
+
if self.config.problem_type == "regression":
|
| 1518 |
+
loss_fct = MSELoss()
|
| 1519 |
+
if self.num_labels == 1:
|
| 1520 |
+
loss = loss_fct(pooled_logits.squeeze(), labels.squeeze())
|
| 1521 |
+
else:
|
| 1522 |
+
loss = loss_fct(pooled_logits, labels)
|
| 1523 |
+
elif self.config.problem_type == "single_label_classification":
|
| 1524 |
+
loss_fct = CrossEntropyLoss()
|
| 1525 |
+
loss = loss_fct(pooled_logits.view(-1, self.num_labels), labels.view(-1))
|
| 1526 |
+
elif self.config.problem_type == "multi_label_classification":
|
| 1527 |
+
loss_fct = BCEWithLogitsLoss()
|
| 1528 |
+
loss = loss_fct(pooled_logits, labels)
|
| 1529 |
+
if not return_dict:
|
| 1530 |
+
output = (pooled_logits,) + model_outputs[1:]
|
| 1531 |
+
return ((loss,) + output) if loss is not None else output
|
| 1532 |
+
|
| 1533 |
+
return SequenceClassifierOutputWithPast(
|
| 1534 |
+
loss=loss,
|
| 1535 |
+
logits=pooled_logits,
|
| 1536 |
+
past_key_values=model_outputs.past_key_values,
|
| 1537 |
+
hidden_states=model_outputs.hidden_states,
|
| 1538 |
+
attentions=model_outputs.attentions,
|
| 1539 |
+
)
|
| 1540 |
+
|
| 1541 |
+
|
| 1542 |
+
@add_start_docstrings(
|
| 1543 |
+
"""
|
| 1544 |
+
[`Phi3VModel`] with a token classification head on top (a linear layer on top of the hidden-states output) e.g. for
|
| 1545 |
+
Named-Entity-Recognition (NER) tasks.
|
| 1546 |
+
""",
|
| 1547 |
+
PHI3V_START_DOCSTRING,
|
| 1548 |
+
)
|
| 1549 |
+
# Copied from transformers.models.mpt.modeling_mpt.MptForTokenClassification with Mpt->Phi3,MPT->PHI3,self.transformer->self.model,transformer_outputs->model_outputs
|
| 1550 |
+
class Phi3VForTokenClassification(Phi3VPreTrainedModel):
|
| 1551 |
+
def __init__(self, config: Phi3VConfig):
|
| 1552 |
+
super().__init__(config)
|
| 1553 |
+
self.num_labels = config.num_labels
|
| 1554 |
+
|
| 1555 |
+
self.model = Phi3VModel(config)
|
| 1556 |
+
if hasattr(config, "classifier_dropout") and config.classifier_dropout is not None:
|
| 1557 |
+
classifier_dropout = config.classifier_dropout
|
| 1558 |
+
elif hasattr(config, "hidden_dropout") and config.hidden_dropout is not None:
|
| 1559 |
+
classifier_dropout = config.hidden_dropout
|
| 1560 |
+
else:
|
| 1561 |
+
classifier_dropout = 0.1
|
| 1562 |
+
self.dropout = nn.Dropout(classifier_dropout)
|
| 1563 |
+
self.classifier = nn.Linear(config.hidden_size, config.num_labels)
|
| 1564 |
+
|
| 1565 |
+
# Initialize weights and apply final processing
|
| 1566 |
+
self.post_init()
|
| 1567 |
+
|
| 1568 |
+
@add_start_docstrings_to_model_forward(PHI3V_INPUTS_DOCSTRING)
|
| 1569 |
+
@add_code_sample_docstrings(
|
| 1570 |
+
checkpoint=_CHECKPOINT_FOR_DOC,
|
| 1571 |
+
output_type=TokenClassifierOutput,
|
| 1572 |
+
config_class=_CONFIG_FOR_DOC,
|
| 1573 |
+
)
|
| 1574 |
+
def forward(
|
| 1575 |
+
self,
|
| 1576 |
+
input_ids: Optional[torch.LongTensor] = None,
|
| 1577 |
+
past_key_values: Optional[Tuple[Tuple[torch.Tensor, torch.Tensor], ...]] = None,
|
| 1578 |
+
attention_mask: Optional[torch.Tensor] = None,
|
| 1579 |
+
inputs_embeds: Optional[torch.Tensor] = None,
|
| 1580 |
+
pixel_values: Optional[torch.FloatTensor] = None,
|
| 1581 |
+
image_sizes: Optional[torch.LongTensor] = None,
|
| 1582 |
+
labels: Optional[torch.Tensor] = None,
|
| 1583 |
+
use_cache: Optional[bool] = None,
|
| 1584 |
+
output_attentions: Optional[bool] = None,
|
| 1585 |
+
output_hidden_states: Optional[bool] = None,
|
| 1586 |
+
return_dict: Optional[bool] = None,
|
| 1587 |
+
**deprecated_arguments,
|
| 1588 |
+
) -> Union[Tuple[torch.Tensor], TokenClassifierOutput]:
|
| 1589 |
+
r"""
|
| 1590 |
+
labels (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
|
| 1591 |
+
Labels for computing the sequence classification/regression loss. Indices should be in `[0, ...,
|
| 1592 |
+
config.num_labels - 1]`. If `config.num_labels == 1` a regression loss is computed (Mean-Square loss), If
|
| 1593 |
+
`config.num_labels > 1` a classification loss is computed (Cross-Entropy).
|
| 1594 |
+
"""
|
| 1595 |
+
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
| 1596 |
+
|
| 1597 |
+
model_outputs = self.model(
|
| 1598 |
+
input_ids,
|
| 1599 |
+
past_key_values=past_key_values,
|
| 1600 |
+
attention_mask=attention_mask,
|
| 1601 |
+
inputs_embeds=inputs_embeds,
|
| 1602 |
+
pixel_values=pixel_values,
|
| 1603 |
+
image_sizes=image_sizes,
|
| 1604 |
+
use_cache=use_cache,
|
| 1605 |
+
output_attentions=output_attentions,
|
| 1606 |
+
output_hidden_states=output_hidden_states,
|
| 1607 |
+
return_dict=return_dict,
|
| 1608 |
+
)
|
| 1609 |
+
|
| 1610 |
+
hidden_states = model_outputs[0]
|
| 1611 |
+
hidden_states = self.dropout(hidden_states)
|
| 1612 |
+
logits = self.classifier(hidden_states)
|
| 1613 |
+
|
| 1614 |
+
loss = None
|
| 1615 |
+
if labels is not None:
|
| 1616 |
+
# move labels to correct device to enable model parallelism
|
| 1617 |
+
labels = labels.to(logits.device)
|
| 1618 |
+
batch_size, seq_length = labels.shape
|
| 1619 |
+
loss_fct = CrossEntropyLoss()
|
| 1620 |
+
loss = loss_fct(
|
| 1621 |
+
logits.view(batch_size * seq_length, self.num_labels), labels.view(batch_size * seq_length)
|
| 1622 |
+
)
|
| 1623 |
+
|
| 1624 |
+
if not return_dict:
|
| 1625 |
+
output = (logits,) + model_outputs[2:]
|
| 1626 |
+
return ((loss,) + output) if loss is not None else output
|
| 1627 |
+
|
| 1628 |
+
return TokenClassifierOutput(
|
| 1629 |
+
loss=loss,
|
| 1630 |
+
logits=logits,
|
| 1631 |
+
hidden_states=model_outputs.hidden_states,
|
| 1632 |
+
attentions=model_outputs.attentions,
|
| 1633 |
+
)
|
VLMEvalKit/LICENSE
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Copyright 2023 VLMEvalKit Authors. All rights reserved.
|
| 2 |
+
|
| 3 |
+
Apache License
|
| 4 |
+
Version 2.0, January 2004
|
| 5 |
+
http://www.apache.org/licenses/
|
| 6 |
+
|
| 7 |
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
| 8 |
+
|
| 9 |
+
1. Definitions.
|
| 10 |
+
|
| 11 |
+
"License" shall mean the terms and conditions for use, reproduction,
|
| 12 |
+
and distribution as defined by Sections 1 through 9 of this document.
|
| 13 |
+
|
| 14 |
+
"Licensor" shall mean the copyright owner or entity authorized by
|
| 15 |
+
the copyright owner that is granting the License.
|
| 16 |
+
|
| 17 |
+
"Legal Entity" shall mean the union of the acting entity and all
|
| 18 |
+
other entities that control, are controlled by, or are under common
|
| 19 |
+
control with that entity. For the purposes of this definition,
|
| 20 |
+
"control" means (i) the power, direct or indirect, to cause the
|
| 21 |
+
direction or management of such entity, whether by contract or
|
| 22 |
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
| 23 |
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
| 24 |
+
|
| 25 |
+
"You" (or "Your") shall mean an individual or Legal Entity
|
| 26 |
+
exercising permissions granted by this License.
|
| 27 |
+
|
| 28 |
+
"Source" form shall mean the preferred form for making modifications,
|
| 29 |
+
including but not limited to software source code, documentation
|
| 30 |
+
source, and configuration files.
|
| 31 |
+
|
| 32 |
+
"Object" form shall mean any form resulting from mechanical
|
| 33 |
+
transformation or translation of a Source form, including but
|
| 34 |
+
not limited to compiled object code, generated documentation,
|
| 35 |
+
and conversions to other media types.
|
| 36 |
+
|
| 37 |
+
"Work" shall mean the work of authorship, whether in Source or
|
| 38 |
+
Object form, made available under the License, as indicated by a
|
| 39 |
+
copyright notice that is included in or attached to the work
|
| 40 |
+
(an example is provided in the Appendix below).
|
| 41 |
+
|
| 42 |
+
"Derivative Works" shall mean any work, whether in Source or Object
|
| 43 |
+
form, that is based on (or derived from) the Work and for which the
|
| 44 |
+
editorial revisions, annotations, elaborations, or other modifications
|
| 45 |
+
represent, as a whole, an original work of authorship. For the purposes
|
| 46 |
+
of this License, Derivative Works shall not include works that remain
|
| 47 |
+
separable from, or merely link (or bind by name) to the interfaces of,
|
| 48 |
+
the Work and Derivative Works thereof.
|
| 49 |
+
|
| 50 |
+
"Contribution" shall mean any work of authorship, including
|
| 51 |
+
the original version of the Work and any modifications or additions
|
| 52 |
+
to that Work or Derivative Works thereof, that is intentionally
|
| 53 |
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
| 54 |
+
or by an individual or Legal Entity authorized to submit on behalf of
|
| 55 |
+
the copyright owner. For the purposes of this definition, "submitted"
|
| 56 |
+
means any form of electronic, verbal, or written communication sent
|
| 57 |
+
to the Licensor or its representatives, including but not limited to
|
| 58 |
+
communication on electronic mailing lists, source code control systems,
|
| 59 |
+
and issue tracking systems that are managed by, or on behalf of, the
|
| 60 |
+
Licensor for the purpose of discussing and improving the Work, but
|
| 61 |
+
excluding communication that is conspicuously marked or otherwise
|
| 62 |
+
designated in writing by the copyright owner as "Not a Contribution."
|
| 63 |
+
|
| 64 |
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
| 65 |
+
on behalf of whom a Contribution has been received by Licensor and
|
| 66 |
+
subsequently incorporated within the Work.
|
| 67 |
+
|
| 68 |
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
| 69 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 70 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 71 |
+
copyright license to reproduce, prepare Derivative Works of,
|
| 72 |
+
publicly display, publicly perform, sublicense, and distribute the
|
| 73 |
+
Work and such Derivative Works in Source or Object form.
|
| 74 |
+
|
| 75 |
+
3. Grant of Patent License. Subject to the terms and conditions of
|
| 76 |
+
this License, each Contributor hereby grants to You a perpetual,
|
| 77 |
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
| 78 |
+
(except as stated in this section) patent license to make, have made,
|
| 79 |
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
| 80 |
+
where such license applies only to those patent claims licensable
|
| 81 |
+
by such Contributor that are necessarily infringed by their
|
| 82 |
+
Contribution(s) alone or by combination of their Contribution(s)
|
| 83 |
+
with the Work to which such Contribution(s) was submitted. If You
|
| 84 |
+
institute patent litigation against any entity (including a
|
| 85 |
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
| 86 |
+
or a Contribution incorporated within the Work constitutes direct
|
| 87 |
+
or contributory patent infringement, then any patent licenses
|
| 88 |
+
granted to You under this License for that Work shall terminate
|
| 89 |
+
as of the date such litigation is filed.
|
| 90 |
+
|
| 91 |
+
4. Redistribution. You may reproduce and distribute copies of the
|
| 92 |
+
Work or Derivative Works thereof in any medium, with or without
|
| 93 |
+
modifications, and in Source or Object form, provided that You
|
| 94 |
+
meet the following conditions:
|
| 95 |
+
|
| 96 |
+
(a) You must give any other recipients of the Work or
|
| 97 |
+
Derivative Works a copy of this License; and
|
| 98 |
+
|
| 99 |
+
(b) You must cause any modified files to carry prominent notices
|
| 100 |
+
stating that You changed the files; and
|
| 101 |
+
|
| 102 |
+
(c) You must retain, in the Source form of any Derivative Works
|
| 103 |
+
that You distribute, all copyright, patent, trademark, and
|
| 104 |
+
attribution notices from the Source form of the Work,
|
| 105 |
+
excluding those notices that do not pertain to any part of
|
| 106 |
+
the Derivative Works; and
|
| 107 |
+
|
| 108 |
+
(d) If the Work includes a "NOTICE" text file as part of its
|
| 109 |
+
distribution, then any Derivative Works that You distribute must
|
| 110 |
+
include a readable copy of the attribution notices contained
|
| 111 |
+
within such NOTICE file, excluding those notices that do not
|
| 112 |
+
pertain to any part of the Derivative Works, in at least one
|
| 113 |
+
of the following places: within a NOTICE text file distributed
|
| 114 |
+
as part of the Derivative Works; within the Source form or
|
| 115 |
+
documentation, if provided along with the Derivative Works; or,
|
| 116 |
+
within a display generated by the Derivative Works, if and
|
| 117 |
+
wherever such third-party notices normally appear. The contents
|
| 118 |
+
of the NOTICE file are for informational purposes only and
|
| 119 |
+
do not modify the License. You may add Your own attribution
|
| 120 |
+
notices within Derivative Works that You distribute, alongside
|
| 121 |
+
or as an addendum to the NOTICE text from the Work, provided
|
| 122 |
+
that such additional attribution notices cannot be construed
|
| 123 |
+
as modifying the License.
|
| 124 |
+
|
| 125 |
+
You may add Your own copyright statement to Your modifications and
|
| 126 |
+
may provide additional or different license terms and conditions
|
| 127 |
+
for use, reproduction, or distribution of Your modifications, or
|
| 128 |
+
for any such Derivative Works as a whole, provided Your use,
|
| 129 |
+
reproduction, and distribution of the Work otherwise complies with
|
| 130 |
+
the conditions stated in this License.
|
| 131 |
+
|
| 132 |
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
| 133 |
+
any Contribution intentionally submitted for inclusion in the Work
|
| 134 |
+
by You to the Licensor shall be under the terms and conditions of
|
| 135 |
+
this License, without any additional terms or conditions.
|
| 136 |
+
Notwithstanding the above, nothing herein shall supersede or modify
|
| 137 |
+
the terms of any separate license agreement you may have executed
|
| 138 |
+
with Licensor regarding such Contributions.
|
| 139 |
+
|
| 140 |
+
6. Trademarks. This License does not grant permission to use the trade
|
| 141 |
+
names, trademarks, service marks, or product names of the Licensor,
|
| 142 |
+
except as required for reasonable and customary use in describing the
|
| 143 |
+
origin of the Work and reproducing the content of the NOTICE file.
|
| 144 |
+
|
| 145 |
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
| 146 |
+
agreed to in writing, Licensor provides the Work (and each
|
| 147 |
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
| 148 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
| 149 |
+
implied, including, without limitation, any warranties or conditions
|
| 150 |
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
| 151 |
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
| 152 |
+
appropriateness of using or redistributing the Work and assume any
|
| 153 |
+
risks associated with Your exercise of permissions under this License.
|
| 154 |
+
|
| 155 |
+
8. Limitation of Liability. In no event and under no legal theory,
|
| 156 |
+
whether in tort (including negligence), contract, or otherwise,
|
| 157 |
+
unless required by applicable law (such as deliberate and grossly
|
| 158 |
+
negligent acts) or agreed to in writing, shall any Contributor be
|
| 159 |
+
liable to You for damages, including any direct, indirect, special,
|
| 160 |
+
incidental, or consequential damages of any character arising as a
|
| 161 |
+
result of this License or out of the use or inability to use the
|
| 162 |
+
Work (including but not limited to damages for loss of goodwill,
|
| 163 |
+
work stoppage, computer failure or malfunction, or any and all
|
| 164 |
+
other commercial damages or losses), even if such Contributor
|
| 165 |
+
has been advised of the possibility of such damages.
|
| 166 |
+
|
| 167 |
+
9. Accepting Warranty or Additional Liability. While redistributing
|
| 168 |
+
the Work or Derivative Works thereof, You may choose to offer,
|
| 169 |
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
| 170 |
+
or other liability obligations and/or rights consistent with this
|
| 171 |
+
License. However, in accepting such obligations, You may act only
|
| 172 |
+
on Your own behalf and on Your sole responsibility, not on behalf
|
| 173 |
+
of any other Contributor, and only if You agree to indemnify,
|
| 174 |
+
defend, and hold each Contributor harmless for any liability
|
| 175 |
+
incurred by, or claims asserted against, such Contributor by reason
|
| 176 |
+
of your accepting any such warranty or additional liability.
|
| 177 |
+
|
| 178 |
+
END OF TERMS AND CONDITIONS
|
| 179 |
+
|
| 180 |
+
APPENDIX: How to apply the Apache License to your work.
|
| 181 |
+
|
| 182 |
+
To apply the Apache License to your work, attach the following
|
| 183 |
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
| 184 |
+
replaced with your own identifying information. (Don't include
|
| 185 |
+
the brackets!) The text should be enclosed in the appropriate
|
| 186 |
+
comment syntax for the file format. We also recommend that a
|
| 187 |
+
file or class name and description of purpose be included on the
|
| 188 |
+
same "printed page" as the copyright notice for easier
|
| 189 |
+
identification within third-party archives.
|
| 190 |
+
|
| 191 |
+
Copyright 2023 VLMEvalKit Authors.
|
| 192 |
+
|
| 193 |
+
Licensed under the Apache License, Version 2.0 (the "License");
|
| 194 |
+
you may not use this file except in compliance with the License.
|
| 195 |
+
You may obtain a copy of the License at
|
| 196 |
+
|
| 197 |
+
http://www.apache.org/licenses/LICENSE-2.0
|
| 198 |
+
|
| 199 |
+
Unless required by applicable law or agreed to in writing, software
|
| 200 |
+
distributed under the License is distributed on an "AS IS" BASIS,
|
| 201 |
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 202 |
+
See the License for the specific language governing permissions and
|
| 203 |
+
limitations under the License.
|
a_distributed_notebook/temp/ddp_tutorial.py
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
import tempfile
|
| 4 |
+
import torch
|
| 5 |
+
import torch.distributed as dist
|
| 6 |
+
import torch.nn as nn
|
| 7 |
+
import torch.optim as optim
|
| 8 |
+
import torch.multiprocessing as mp
|
| 9 |
+
|
| 10 |
+
from torch.nn.parallel import DistributedDataParallel as DDP
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def setup(rank, world_size):
|
| 15 |
+
# os.environ['MASTER_ADDR'] = 'localhost'
|
| 16 |
+
# os.environ['MASTER_PORT'] = '12355'
|
| 17 |
+
print(os.environ['MASTER_ADDR'])
|
| 18 |
+
print(os.environ['MASTER_PORT'])
|
| 19 |
+
|
| 20 |
+
# initialize the process group
|
| 21 |
+
dist.init_process_group("gloo", rank=rank, world_size=world_size)
|
| 22 |
+
|
| 23 |
+
def cleanup():
|
| 24 |
+
dist.destroy_process_group()
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
# ``` python
|
| 28 |
+
class ToyModel(nn.Module):
|
| 29 |
+
def __init__(self):
|
| 30 |
+
super(ToyModel, self).__init__()
|
| 31 |
+
self.net1 = nn.Linear(10, 10)
|
| 32 |
+
self.relu = nn.ReLU()
|
| 33 |
+
self.net2 = nn.Linear(10, 5)
|
| 34 |
+
|
| 35 |
+
def forward(self, x):
|
| 36 |
+
return self.net2(self.relu(self.net1(x)))
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
def demo_basic(rank, world_size):
|
| 40 |
+
print(f"Running basic DDP example on rank {rank}.")
|
| 41 |
+
setup(rank, world_size)
|
| 42 |
+
|
| 43 |
+
# create model and move it to GPU with id rank
|
| 44 |
+
|
| 45 |
+
print("Start creating model")
|
| 46 |
+
model = ToyModel().to(rank)
|
| 47 |
+
ddp_model = DDP(model, device_ids=[rank])
|
| 48 |
+
|
| 49 |
+
print("Model created")
|
| 50 |
+
print("Start creating loss function")
|
| 51 |
+
loss_fn = nn.MSELoss()
|
| 52 |
+
print("Loss function created")
|
| 53 |
+
print("Start creating optimizer")
|
| 54 |
+
optimizer = optim.SGD(ddp_model.parameters(), lr=0.001)
|
| 55 |
+
|
| 56 |
+
optimizer.zero_grad()
|
| 57 |
+
outputs = ddp_model(torch.randn(20, 10))
|
| 58 |
+
labels = torch.randn(20, 5).to(rank)
|
| 59 |
+
loss_fn(outputs, labels).backward()
|
| 60 |
+
optimizer.step()
|
| 61 |
+
|
| 62 |
+
cleanup()
|
| 63 |
+
print(f"Finished running basic DDP example on rank {rank}.")
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def run_demo(demo_fn, world_size):
|
| 67 |
+
mp.spawn(demo_fn,
|
| 68 |
+
args=(world_size,),
|
| 69 |
+
nprocs=world_size,
|
| 70 |
+
join=True)
|
| 71 |
+
|
| 72 |
+
# ``` python
|
| 73 |
+
def demo_checkpoint(rank, world_size):
|
| 74 |
+
print(f"Running DDP checkpoint example on rank {rank}.")
|
| 75 |
+
setup(rank, world_size)
|
| 76 |
+
|
| 77 |
+
model = ToyModel().to(rank)
|
| 78 |
+
ddp_model = DDP(model, device_ids=[rank])
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
CHECKPOINT_PATH = tempfile.gettempdir() + "/model.checkpoint"
|
| 82 |
+
if rank == 0:
|
| 83 |
+
# All processes should see same parameters as they all start from same
|
| 84 |
+
# random parameters and gradients are synchronized in backward passes.
|
| 85 |
+
# Therefore, saving it in one process is sufficient.
|
| 86 |
+
torch.save(ddp_model.state_dict(), CHECKPOINT_PATH)
|
| 87 |
+
|
| 88 |
+
# Use a barrier() to make sure that process 1 loads the model after process
|
| 89 |
+
# 0 saves it.
|
| 90 |
+
dist.barrier()
|
| 91 |
+
# configure map_location properly
|
| 92 |
+
map_location = {'cuda:%d' % 0: 'cuda:%d' % rank}
|
| 93 |
+
ddp_model.load_state_dict(
|
| 94 |
+
torch.load(CHECKPOINT_PATH, map_location=map_location, weights_only=True))
|
| 95 |
+
|
| 96 |
+
loss_fn = nn.MSELoss()
|
| 97 |
+
optimizer = optim.SGD(ddp_model.parameters(), lr=0.001)
|
| 98 |
+
|
| 99 |
+
optimizer.zero_grad()
|
| 100 |
+
outputs = ddp_model(torch.randn(20, 10))
|
| 101 |
+
labels = torch.randn(20, 5).to(rank)
|
| 102 |
+
|
| 103 |
+
loss_fn(outputs, labels).backward()
|
| 104 |
+
optimizer.step()
|
| 105 |
+
|
| 106 |
+
# Not necessary to use a dist.barrier() to guard the file deletion below
|
| 107 |
+
# as the AllReduce ops in the backward pass of DDP already served as
|
| 108 |
+
# a synchronization.
|
| 109 |
+
|
| 110 |
+
if rank == 0:
|
| 111 |
+
os.remove(CHECKPOINT_PATH)
|
| 112 |
+
|
| 113 |
+
cleanup()
|
| 114 |
+
print(f"Finished running DDP checkpoint example on rank {rank}.")
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
## Combining DDP with Model Parallelism
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
# ``` python
|
| 121 |
+
class ToyMpModel(nn.Module):
|
| 122 |
+
def __init__(self, dev0, dev1):
|
| 123 |
+
super(ToyMpModel, self).__init__()
|
| 124 |
+
self.dev0 = dev0
|
| 125 |
+
self.dev1 = dev1
|
| 126 |
+
self.net1 = torch.nn.Linear(10, 10).to(dev0)
|
| 127 |
+
self.relu = torch.nn.ReLU()
|
| 128 |
+
self.net2 = torch.nn.Linear(10, 5).to(dev1)
|
| 129 |
+
|
| 130 |
+
def forward(self, x):
|
| 131 |
+
x = x.to(self.dev0)
|
| 132 |
+
x = self.relu(self.net1(x))
|
| 133 |
+
x = x.to(self.dev1)
|
| 134 |
+
return self.net2(x)
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
# ``` python
|
| 138 |
+
def demo_model_parallel(rank, world_size):
|
| 139 |
+
print(f"Running DDP with model parallel example on rank {rank}.")
|
| 140 |
+
setup(rank, world_size)
|
| 141 |
+
|
| 142 |
+
# setup mp_model and devices for this process
|
| 143 |
+
dev0 = rank * 2
|
| 144 |
+
dev1 = rank * 2 + 1
|
| 145 |
+
mp_model = ToyMpModel(dev0, dev1)
|
| 146 |
+
ddp_mp_model = DDP(mp_model)
|
| 147 |
+
|
| 148 |
+
loss_fn = nn.MSELoss()
|
| 149 |
+
optimizer = optim.SGD(ddp_mp_model.parameters(), lr=0.001)
|
| 150 |
+
|
| 151 |
+
optimizer.zero_grad()
|
| 152 |
+
# outputs will be on dev1
|
| 153 |
+
outputs = ddp_mp_model(torch.randn(20, 10))
|
| 154 |
+
labels = torch.randn(20, 5).to(dev1)
|
| 155 |
+
loss_fn(outputs, labels).backward()
|
| 156 |
+
optimizer.step()
|
| 157 |
+
|
| 158 |
+
cleanup()
|
| 159 |
+
print(f"Finished running DDP with model parallel example on rank {rank}.")
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
if __name__ == "__main__":
|
| 163 |
+
n_gpus = torch.cuda.device_count()
|
| 164 |
+
assert n_gpus >= 2, f"Requires at least 2 GPUs to run, but got {n_gpus}"
|
| 165 |
+
world_size = n_gpus
|
| 166 |
+
run_demo(demo_basic, world_size)
|
| 167 |
+
# run_demo(demo_checkpoint, world_size)
|
| 168 |
+
# world_size = n_gpus//2
|
| 169 |
+
# run_demo(demo_model_parallel, world_size)
|
a_distributed_notebook/temp/run.py
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import torch
|
| 3 |
+
import torch.distributed as dist
|
| 4 |
+
import torch.multiprocessing as mp
|
| 5 |
+
|
| 6 |
+
def run(rank, size):
|
| 7 |
+
""" Distributed function to be implemented later. """
|
| 8 |
+
pass
|
| 9 |
+
|
| 10 |
+
def init_process(rank, size, fn, backend='gloo'):
|
| 11 |
+
""" Initialize the distributed environment. """
|
| 12 |
+
os.environ['MASTER_ADDR'] = '127.0.0.1'
|
| 13 |
+
os.environ['MASTER_PORT'] = '29500'
|
| 14 |
+
dist.init_process_group(backend, rank=rank, world_size=size)
|
| 15 |
+
fn(rank, size)
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
if __name__ == "__main__":
|
| 19 |
+
size = 2
|
| 20 |
+
processes = []
|
| 21 |
+
mp.set_start_method("spawn")
|
| 22 |
+
for rank in range(size):
|
| 23 |
+
p = mp.Process(target=init_process, args=(rank, size, run))
|
| 24 |
+
p.start()
|
| 25 |
+
processes.append(p)
|
| 26 |
+
|
| 27 |
+
for p in processes:
|
| 28 |
+
p.join()
|
| 29 |
+
|
| 30 |
+
"""Non-blocking point-to-point communication."""
|
| 31 |
+
|
| 32 |
+
def run(rank, size):
|
| 33 |
+
tensor = torch.zeros(1)
|
| 34 |
+
req = None
|
| 35 |
+
if rank == 0:
|
| 36 |
+
tensor += 1
|
| 37 |
+
# Send the tensor to process 1
|
| 38 |
+
req = dist.isend(tensor=tensor, dst=1)
|
| 39 |
+
print('Rank 0 started sending')
|
| 40 |
+
else:
|
| 41 |
+
# Receive tensor from process 0
|
| 42 |
+
req = dist.irecv(tensor=tensor, src=0)
|
| 43 |
+
print('Rank 1 started receiving')
|
| 44 |
+
req.wait()
|
| 45 |
+
print('Rank ', rank, ' has data ', tensor[0])
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
""" All-Reduce example."""
|
| 49 |
+
def run(rank, size):
|
| 50 |
+
""" Simple collective communication. """
|
| 51 |
+
group = dist.new_group([0, 1])
|
| 52 |
+
tensor = torch.ones(1)
|
| 53 |
+
dist.all_reduce(tensor, op=dist.ReduceOp.SUM, group=group)
|
| 54 |
+
print('Rank ', rank, ' has data ', tensor[0])
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
""" Dataset partitioning helper """
|
| 58 |
+
class Partition(object):
|
| 59 |
+
|
| 60 |
+
def __init__(self, data, index):
|
| 61 |
+
self.data = data
|
| 62 |
+
self.index = index
|
| 63 |
+
|
| 64 |
+
def __len__(self):
|
| 65 |
+
return len(self.index)
|
| 66 |
+
|
| 67 |
+
def __getitem__(self, index):
|
| 68 |
+
data_idx = self.index[index]
|
| 69 |
+
return self.data[data_idx]
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
class DataPartitioner(object):
|
| 73 |
+
|
| 74 |
+
def __init__(self, data, sizes=[0.7, 0.2, 0.1], seed=1234):
|
| 75 |
+
self.data = data
|
| 76 |
+
self.partitions = []
|
| 77 |
+
rng = Random() # from random import Random
|
| 78 |
+
rng.seed(seed)
|
| 79 |
+
data_len = len(data)
|
| 80 |
+
indexes = [x for x in range(0, data_len)]
|
| 81 |
+
rng.shuffle(indexes)
|
| 82 |
+
|
| 83 |
+
for frac in sizes:
|
| 84 |
+
part_len = int(frac * data_len)
|
| 85 |
+
self.partitions.append(indexes[0:part_len])
|
| 86 |
+
indexes = indexes[part_len:]
|
| 87 |
+
|
| 88 |
+
def use(self, partition):
|
| 89 |
+
return Partition(self.data, self.partitions[partition])
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
""" Partitioning MNIST """
|
| 93 |
+
def partition_dataset():
|
| 94 |
+
dataset = datasets.MNIST('./data', train=True, download=True,
|
| 95 |
+
transform=transforms.Compose([
|
| 96 |
+
transforms.ToTensor(),
|
| 97 |
+
transforms.Normalize((0.1307,), (0.3081,))
|
| 98 |
+
]))
|
| 99 |
+
size = dist.get_world_size()
|
| 100 |
+
bsz = 128 // size
|
| 101 |
+
partition_sizes = [1.0 / size for _ in range(size)]
|
| 102 |
+
partition = DataPartitioner(dataset, partition_sizes)
|
| 103 |
+
partition = partition.use(dist.get_rank())
|
| 104 |
+
train_set = torch.utils.data.DataLoader(partition,
|
| 105 |
+
batch_size=bsz,
|
| 106 |
+
shuffle=True)
|
| 107 |
+
return train_set, bsz
|
| 108 |
+
|
| 109 |
+
""" Distributed Synchronous SGD Example """
|
| 110 |
+
def run(rank, size):
|
| 111 |
+
torch.manual_seed(1234)
|
| 112 |
+
train_set, bsz = partition_dataset()
|
| 113 |
+
model = Net()
|
| 114 |
+
optimizer = optim.SGD(model.parameters(),
|
| 115 |
+
lr=0.01, momentum=0.5)
|
| 116 |
+
|
| 117 |
+
num_batches = ceil(len(train_set.dataset) / float(bsz))
|
| 118 |
+
for epoch in range(10):
|
| 119 |
+
epoch_loss = 0.0
|
| 120 |
+
for data, target in train_set:
|
| 121 |
+
optimizer.zero_grad()
|
| 122 |
+
output = model(data)
|
| 123 |
+
loss = F.nll_loss(output, target)
|
| 124 |
+
epoch_loss += loss.item()
|
| 125 |
+
loss.backward()
|
| 126 |
+
average_gradients(model)
|
| 127 |
+
optimizer.step()
|
| 128 |
+
print('Rank ', dist.get_rank(), ', epoch ',
|
| 129 |
+
epoch, ': ', epoch_loss / num_batches)
|
| 130 |
+
|
| 131 |
+
""" Gradient averaging. """
|
| 132 |
+
def average_gradients(model):
|
| 133 |
+
size = float(dist.get_world_size())
|
| 134 |
+
for param in model.parameters():
|
| 135 |
+
dist.all_reduce(param.grad.data, op=dist.ReduceOp.SUM)
|
| 136 |
+
param.grad.data /= size
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
""" Implementation of a ring-reduce with addition. """
|
| 140 |
+
def allreduce(send, recv):
|
| 141 |
+
rank = dist.get_rank()
|
| 142 |
+
size = dist.get_world_size()
|
| 143 |
+
send_buff = send.clone()
|
| 144 |
+
recv_buff = send.clone()
|
| 145 |
+
accum = send.clone()
|
| 146 |
+
|
| 147 |
+
left = ((rank - 1) + size) % size
|
| 148 |
+
right = (rank + 1) % size
|
| 149 |
+
|
| 150 |
+
for i in range(size - 1):
|
| 151 |
+
if i % 2 == 0:
|
| 152 |
+
# Send send_buff
|
| 153 |
+
send_req = dist.isend(send_buff, right)
|
| 154 |
+
dist.recv(recv_buff, left)
|
| 155 |
+
accum[:] += recv_buff[:]
|
| 156 |
+
else:
|
| 157 |
+
# Send recv_buff
|
| 158 |
+
send_req = dist.isend(recv_buff, right)
|
| 159 |
+
dist.recv(send_buff, left)
|
| 160 |
+
accum[:] += send_buff[:]
|
| 161 |
+
send_req.wait()
|
| 162 |
+
recv[:] = accum[:]
|
a_distributed_notebook/temp/run_5.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import torch
|
| 2 |
+
import torch.distributed as dist
|
| 3 |
+
import torch.nn as nn
|
| 4 |
+
import torch.optim as optim
|
| 5 |
+
import os
|
| 6 |
+
|
| 7 |
+
from torch.nn.parallel import DistributedDataParallel as DDP
|
| 8 |
+
|
| 9 |
+
class ToyModel(nn.Module):
|
| 10 |
+
def __init__(self):
|
| 11 |
+
super(ToyModel, self).__init__()
|
| 12 |
+
self.net1 = nn.Linear(10, 10)
|
| 13 |
+
self.relu = nn.ReLU()
|
| 14 |
+
self.net2 = nn.Linear(10, 5)
|
| 15 |
+
|
| 16 |
+
def forward(self, x):
|
| 17 |
+
return self.net2(self.relu(self.net1(x)))
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def demo_basic():
|
| 21 |
+
torch.cuda.set_device(int(os.environ["LOCAL_RANK"]))
|
| 22 |
+
dist.init_process_group("nccl")
|
| 23 |
+
rank = dist.get_rank()
|
| 24 |
+
print(f"Start running basic DDP example on rank {rank}.")
|
| 25 |
+
# create model and move it to GPU with id rank
|
| 26 |
+
device_id = rank % torch.cuda.device_count()
|
| 27 |
+
model = ToyModel().to(device_id)
|
| 28 |
+
ddp_model = DDP(model, device_ids=[device_id])
|
| 29 |
+
loss_fn = nn.MSELoss()
|
| 30 |
+
optimizer = optim.SGD(ddp_model.parameters(), lr=0.001)
|
| 31 |
+
|
| 32 |
+
optimizer.zero_grad()
|
| 33 |
+
outputs = ddp_model(torch.randn(20, 10))
|
| 34 |
+
labels = torch.randn(20, 5).to(device_id)
|
| 35 |
+
loss_fn(outputs, labels).backward()
|
| 36 |
+
optimizer.step()
|
| 37 |
+
dist.destroy_process_group()
|
| 38 |
+
print(f"Finished running basic DDP example on rank {rank}.")
|
| 39 |
+
|
| 40 |
+
if __name__ == "__main__":
|
| 41 |
+
demo_basic()
|
groundingLMM/app.py
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import sys
|
| 2 |
+
import cv2
|
| 3 |
+
import random
|
| 4 |
+
import argparse
|
| 5 |
+
import gradio as gr
|
| 6 |
+
import numpy as np
|
| 7 |
+
from PIL import Image
|
| 8 |
+
import torch
|
| 9 |
+
import torch.nn.functional as F
|
| 10 |
+
from transformers import AutoTokenizer, CLIPImageProcessor
|
| 11 |
+
from diffusers import AutoPipelineForInpainting
|
| 12 |
+
from diffusers.utils import load_image
|
| 13 |
+
|
| 14 |
+
from model.GLaMM import GLaMMForCausalLM
|
| 15 |
+
from model.llava import conversation as conversation_lib
|
| 16 |
+
from model.llava.mm_utils import tokenizer_image_token
|
| 17 |
+
from model.SAM.utils.transforms import ResizeLongestSide
|
| 18 |
+
from tools.generate_utils import center_crop, create_feathered_mask
|
| 19 |
+
from tools.utils import DEFAULT_IM_END_TOKEN, DEFAULT_IM_START_TOKEN, DEFAULT_IMAGE_TOKEN, IMAGE_TOKEN_INDEX
|
| 20 |
+
from tools.markdown_utils import (markdown_default, examples, title, description, article, process_markdown, colors,
|
| 21 |
+
draw_bbox, ImageSketcher)
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def parse_args(args):
|
| 25 |
+
parser = argparse.ArgumentParser(description="GLaMM Model Demo")
|
| 26 |
+
parser.add_argument("--version", default="MBZUAI/GLaMM-FullScope")
|
| 27 |
+
parser.add_argument("--vis_save_path", default="./vis_output", type=str)
|
| 28 |
+
parser.add_argument("--precision", default='bf16', type=str)
|
| 29 |
+
parser.add_argument("--image_size", default=1024, type=int, help="Image size for grounding image encoder")
|
| 30 |
+
parser.add_argument("--model_max_length", default=1536, type=int)
|
| 31 |
+
parser.add_argument("--lora_r", default=8, type=int)
|
| 32 |
+
parser.add_argument("--vision-tower", default="openai/clip-vit-large-patch14-336", type=str)
|
| 33 |
+
parser.add_argument("--local-rank", default=0, type=int, help="node rank")
|
| 34 |
+
parser.add_argument("--use_mm_start_end", action="store_true", default=True)
|
| 35 |
+
parser.add_argument("--conv_type", default="llava_v1", type=str, choices=["llava_v1", "llava_llama_2"])
|
| 36 |
+
|
| 37 |
+
return parser.parse_args(args)
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def setup_tokenizer_and_special_tokens(args):
|
| 41 |
+
""" Load tokenizer and add special tokens. """
|
| 42 |
+
tokenizer = AutoTokenizer.from_pretrained(
|
| 43 |
+
args.version, model_max_length=args.model_max_length, padding_side="right", use_fast=False
|
| 44 |
+
)
|
| 45 |
+
print('\033[92m' + "---- Initialized tokenizer from: {} ----".format(args.version) + '\033[0m')
|
| 46 |
+
tokenizer.pad_token = tokenizer.unk_token
|
| 47 |
+
args.bbox_token_idx = tokenizer("<bbox>", add_special_tokens=False).input_ids[0]
|
| 48 |
+
args.seg_token_idx = tokenizer("[SEG]", add_special_tokens=False).input_ids[0]
|
| 49 |
+
args.bop_token_idx = tokenizer("<p>", add_special_tokens=False).input_ids[0]
|
| 50 |
+
args.eop_token_idx = tokenizer("</p>", add_special_tokens=False).input_ids[0]
|
| 51 |
+
|
| 52 |
+
return tokenizer
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def initialize_model(args, tokenizer):
|
| 56 |
+
""" Initialize the GLaMM model. """
|
| 57 |
+
model_args = {k: getattr(args, k) for k in
|
| 58 |
+
["seg_token_idx", "bbox_token_idx", "eop_token_idx", "bop_token_idx"]}
|
| 59 |
+
|
| 60 |
+
model = GLaMMForCausalLM.from_pretrained(
|
| 61 |
+
args.version, torch_dtype=torch.bfloat16, low_cpu_mem_usage=True, **model_args)
|
| 62 |
+
print('\033[92m' + "---- Initialized model from: {} ----".format(args.version) + '\033[0m')
|
| 63 |
+
|
| 64 |
+
# Configure model tokens
|
| 65 |
+
model.config.eos_token_id = tokenizer.eos_token_id
|
| 66 |
+
model.config.bos_token_id = tokenizer.bos_token_id
|
| 67 |
+
model.config.pad_token_id = tokenizer.pad_token_id
|
| 68 |
+
|
| 69 |
+
return model
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def prepare_model_for_inference(model, args):
|
| 73 |
+
# Initialize vision tower
|
| 74 |
+
print(
|
| 75 |
+
'\033[92m' + "---- Initialized Global Image Encoder (vision tower) from: {} ----".format(
|
| 76 |
+
args.vision_tower
|
| 77 |
+
) + '\033[0m'
|
| 78 |
+
)
|
| 79 |
+
model.get_model().initialize_vision_modules(model.get_model().config)
|
| 80 |
+
vision_tower = model.get_model().get_vision_tower()
|
| 81 |
+
vision_tower.to(dtype=torch.bfloat16, device=args.local_rank)
|
| 82 |
+
model = model.bfloat16().cuda()
|
| 83 |
+
return model
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
def grounding_enc_processor(x: torch.Tensor) -> torch.Tensor:
|
| 87 |
+
IMG_MEAN = torch.Tensor([123.675, 116.28, 103.53]).view(-1, 1, 1)
|
| 88 |
+
IMG_STD = torch.Tensor([58.395, 57.12, 57.375]).view(-1, 1, 1)
|
| 89 |
+
IMG_SIZE = 1024
|
| 90 |
+
x = (x - IMG_MEAN) / IMG_STD
|
| 91 |
+
h, w = x.shape[-2:]
|
| 92 |
+
x = F.pad(x, (0, IMG_SIZE - w, 0, IMG_SIZE - h))
|
| 93 |
+
return x
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
def region_enc_processor(orig_size, post_size, bbox_img):
|
| 97 |
+
orig_h, orig_w = orig_size
|
| 98 |
+
post_h, post_w = post_size
|
| 99 |
+
y_scale = post_h / orig_h
|
| 100 |
+
x_scale = post_w / orig_w
|
| 101 |
+
|
| 102 |
+
bboxes_scaled = [[bbox[0] * x_scale, bbox[1] * y_scale, bbox[2] * x_scale, bbox[3] * y_scale] for bbox in bbox_img]
|
| 103 |
+
|
| 104 |
+
tensor_list = []
|
| 105 |
+
for box_element in bboxes_scaled:
|
| 106 |
+
ori_bboxes = np.array([box_element], dtype=np.float64)
|
| 107 |
+
# Normalizing the bounding boxes
|
| 108 |
+
norm_bboxes = ori_bboxes / np.array([post_w, post_h, post_w, post_h])
|
| 109 |
+
# Converting to tensor, handling device and data type as in the original code
|
| 110 |
+
tensor_list.append(torch.tensor(norm_bboxes, device='cuda').half().to(torch.bfloat16))
|
| 111 |
+
|
| 112 |
+
if len(tensor_list) > 1:
|
| 113 |
+
bboxes = torch.stack(tensor_list, dim=1)
|
| 114 |
+
bboxes = [bboxes.squeeze()]
|
| 115 |
+
else:
|
| 116 |
+
bboxes = tensor_list
|
| 117 |
+
return bboxes
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
def prepare_mask(input_image, image_np, pred_masks, text_output, color_history):
|
| 121 |
+
save_img = None
|
| 122 |
+
for i, pred_mask in enumerate(pred_masks):
|
| 123 |
+
if pred_mask.shape[0] == 0:
|
| 124 |
+
continue
|
| 125 |
+
pred_mask = pred_mask.detach().cpu().numpy()
|
| 126 |
+
mask_list = [pred_mask[i] for i in range(pred_mask.shape[0])]
|
| 127 |
+
if len(mask_list) > 0:
|
| 128 |
+
save_img = image_np.copy()
|
| 129 |
+
colors_temp = colors
|
| 130 |
+
seg_count = text_output.count("[SEG]")
|
| 131 |
+
mask_list = mask_list[-seg_count:]
|
| 132 |
+
for curr_mask in mask_list:
|
| 133 |
+
color = random.choice(colors_temp)
|
| 134 |
+
if len(colors_temp) > 0:
|
| 135 |
+
colors_temp.remove(color)
|
| 136 |
+
else:
|
| 137 |
+
colors_temp = colors
|
| 138 |
+
color_history.append(color)
|
| 139 |
+
curr_mask = curr_mask > 0
|
| 140 |
+
save_img[curr_mask] = (image_np * 0.5 + curr_mask[:, :, None].astype(np.uint8) * np.array(color) * 0.5)[
|
| 141 |
+
curr_mask]
|
| 142 |
+
seg_mask = np.zeros((curr_mask.shape[0], curr_mask.shape[1], 3), dtype=np.uint8)
|
| 143 |
+
seg_mask[curr_mask] = [255, 255, 255] # white for True values
|
| 144 |
+
seg_mask[~curr_mask] = [0, 0, 0] # black for False values
|
| 145 |
+
seg_mask = Image.fromarray(seg_mask)
|
| 146 |
+
mask_path = input_image.replace('image', 'mask')
|
| 147 |
+
seg_mask.save(mask_path)
|
| 148 |
+
|
| 149 |
+
return save_img
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
def generate_new_image(st_pipe, input_str, input_image):
|
| 153 |
+
global mask_path
|
| 154 |
+
if mask_path is None:
|
| 155 |
+
raise gr.Error("No Segmentation Mask")
|
| 156 |
+
|
| 157 |
+
og_image = load_image(input_image)
|
| 158 |
+
st_image, c_box = center_crop(og_image)
|
| 159 |
+
im_height = st_image.size[0]
|
| 160 |
+
st_image = st_image.resize((1024, 1024))
|
| 161 |
+
st_mask = load_image(mask_path)
|
| 162 |
+
st_mask, c_box = center_crop(st_mask)
|
| 163 |
+
st_mask = st_mask.resize((1024, 1024))
|
| 164 |
+
|
| 165 |
+
st_generator = torch.Generator(device="cuda").manual_seed(0)
|
| 166 |
+
st_out = st_pipe(
|
| 167 |
+
prompt=input_str, image=st_image, mask_image=st_mask, guidance_scale=8.0, num_inference_steps=20, strength=0.99,
|
| 168 |
+
generator=st_generator, ).images[0]
|
| 169 |
+
|
| 170 |
+
st_out = st_out.resize((im_height, im_height))
|
| 171 |
+
feathered_mask = create_feathered_mask(st_out.size)
|
| 172 |
+
og_image.paste(st_out, c_box, feathered_mask)
|
| 173 |
+
st_text_out = "Sure, Here's the new image"
|
| 174 |
+
st_text_out = process_markdown(st_text_out, [])
|
| 175 |
+
|
| 176 |
+
return og_image, st_text_out
|
| 177 |
+
|
| 178 |
+
|
| 179 |
+
def inference(input_str, all_inputs, follow_up, generate):
|
| 180 |
+
bbox_img = all_inputs['boxes']
|
| 181 |
+
input_image = all_inputs['image']
|
| 182 |
+
|
| 183 |
+
print("input_str: ", input_str, "input_image: ", input_image)
|
| 184 |
+
|
| 185 |
+
if generate:
|
| 186 |
+
return generate_new_image(st_pipe, input_str, input_image)
|
| 187 |
+
|
| 188 |
+
if not follow_up:
|
| 189 |
+
conv = conversation_lib.conv_templates[args.conv_type].copy()
|
| 190 |
+
conv.messages = []
|
| 191 |
+
conv_history = {'user': [], 'model': []}
|
| 192 |
+
conv_history["user"].append(input_str)
|
| 193 |
+
|
| 194 |
+
input_str = input_str.replace('<', '<').replace('>', '>')
|
| 195 |
+
prompt = input_str
|
| 196 |
+
prompt = f"The {DEFAULT_IMAGE_TOKEN} provides an overview of the picture." + "\n" + prompt
|
| 197 |
+
if args.use_mm_start_end:
|
| 198 |
+
replace_token = (DEFAULT_IM_START_TOKEN + DEFAULT_IMAGE_TOKEN + DEFAULT_IM_END_TOKEN)
|
| 199 |
+
prompt = prompt.replace(DEFAULT_IMAGE_TOKEN, replace_token)
|
| 200 |
+
|
| 201 |
+
if not follow_up:
|
| 202 |
+
conv.append_message(conv.roles[0], prompt)
|
| 203 |
+
conv.append_message(conv.roles[1], "")
|
| 204 |
+
else:
|
| 205 |
+
conv.append_message(conv.roles[0], input_str)
|
| 206 |
+
conv.append_message(conv.roles[1], "")
|
| 207 |
+
prompt = conv.get_prompt()
|
| 208 |
+
|
| 209 |
+
image_np = cv2.imread(input_image)
|
| 210 |
+
image_np = cv2.cvtColor(image_np, cv2.COLOR_BGR2RGB)
|
| 211 |
+
orig_h, orig_w = image_np.shape[:2]
|
| 212 |
+
original_size_list = [image_np.shape[:2]]
|
| 213 |
+
|
| 214 |
+
# Prepare input for Global Image Encoder
|
| 215 |
+
global_enc_image = global_enc_processor.preprocess(
|
| 216 |
+
image_np, return_tensors="pt")["pixel_values"][0].unsqueeze(0).cuda()
|
| 217 |
+
global_enc_image = global_enc_image.bfloat16()
|
| 218 |
+
|
| 219 |
+
# Prepare input for Grounding Image Encoder
|
| 220 |
+
image = transform.apply_image(image_np)
|
| 221 |
+
resize_list = [image.shape[:2]]
|
| 222 |
+
grounding_enc_image = (grounding_enc_processor(torch.from_numpy(image).permute(2, 0, 1).
|
| 223 |
+
contiguous()).unsqueeze(0).cuda())
|
| 224 |
+
grounding_enc_image = grounding_enc_image.bfloat16()
|
| 225 |
+
|
| 226 |
+
# Prepare input for Region Image Encoder
|
| 227 |
+
post_h, post_w = global_enc_image.shape[1:3]
|
| 228 |
+
bboxes = None
|
| 229 |
+
if len(bbox_img) > 0:
|
| 230 |
+
bboxes = region_enc_processor((orig_h, orig_w), (post_h, post_w), bbox_img)
|
| 231 |
+
|
| 232 |
+
input_ids = tokenizer_image_token(prompt, tokenizer, return_tensors="pt")
|
| 233 |
+
input_ids = input_ids.unsqueeze(0).cuda()
|
| 234 |
+
|
| 235 |
+
# Pass prepared inputs to model
|
| 236 |
+
output_ids, pred_masks = model.evaluate(
|
| 237 |
+
global_enc_image, grounding_enc_image, input_ids, resize_list, original_size_list, max_tokens_new=512,
|
| 238 |
+
bboxes=bboxes)
|
| 239 |
+
output_ids = output_ids[0][output_ids[0] != IMAGE_TOKEN_INDEX]
|
| 240 |
+
|
| 241 |
+
text_output = tokenizer.decode(output_ids, skip_special_tokens=False)
|
| 242 |
+
text_output = text_output.replace("\n", "").replace(" ", " ")
|
| 243 |
+
text_output = text_output.split("ASSISTANT: ")[-1]
|
| 244 |
+
print("text_output: ", text_output)
|
| 245 |
+
|
| 246 |
+
# For multi-turn conversation
|
| 247 |
+
conv.messages.pop()
|
| 248 |
+
conv.append_message(conv.roles[1], text_output)
|
| 249 |
+
conv_history["model"].append(text_output)
|
| 250 |
+
color_history = []
|
| 251 |
+
save_img = None
|
| 252 |
+
if "[SEG]" in text_output:
|
| 253 |
+
save_img = prepare_mask(input_image, image_np, pred_masks, text_output, color_history)
|
| 254 |
+
|
| 255 |
+
output_str = text_output # input_str
|
| 256 |
+
if save_img is not None:
|
| 257 |
+
output_image = save_img # input_image
|
| 258 |
+
else:
|
| 259 |
+
if len(bbox_img) > 0:
|
| 260 |
+
output_image = draw_bbox(image_np.copy(), bbox_img)
|
| 261 |
+
else:
|
| 262 |
+
output_image = input_image
|
| 263 |
+
|
| 264 |
+
markdown_out = process_markdown(output_str, color_history)
|
| 265 |
+
|
| 266 |
+
return output_image, markdown_out
|
| 267 |
+
|
| 268 |
+
|
| 269 |
+
if __name__ == "__main__":
|
| 270 |
+
args = parse_args(sys.argv[1:])
|
| 271 |
+
tokenizer = setup_tokenizer_and_special_tokens(args)
|
| 272 |
+
model = initialize_model(args, tokenizer)
|
| 273 |
+
model = prepare_model_for_inference(model, args)
|
| 274 |
+
global_enc_processor = CLIPImageProcessor.from_pretrained(model.config.vision_tower)
|
| 275 |
+
transform = ResizeLongestSide(args.image_size)
|
| 276 |
+
model.eval()
|
| 277 |
+
|
| 278 |
+
st_pipe = AutoPipelineForInpainting.from_pretrained(
|
| 279 |
+
"diffusers/stable-diffusion-xl-1.0-inpainting-0.1", torch_dtype=torch.float16, variant="fp16"
|
| 280 |
+
).to("cuda")
|
| 281 |
+
|
| 282 |
+
conv = None
|
| 283 |
+
# Only to Display output
|
| 284 |
+
conv_history = {'user': [], 'model': []}
|
| 285 |
+
mask_path = None
|
| 286 |
+
|
| 287 |
+
demo = gr.Interface(
|
| 288 |
+
inference, inputs=[gr.Textbox(lines=1, placeholder=None, label="Text Instruction"), ImageSketcher(
|
| 289 |
+
type='filepath', label='Input Image (Please draw bounding boxes)', interactive=True, brush_radius=20,
|
| 290 |
+
elem_id='image_upload'
|
| 291 |
+
).style(height=360), gr.Checkbox(label="Follow up Question"), gr.Checkbox(label="Generate")],
|
| 292 |
+
outputs=[gr.Image(type="pil", label="Output Image"), gr.Markdown(markdown_default)], title=title,
|
| 293 |
+
description=description, article=article, theme=gr.themes.Soft(), examples=examples, allow_flagging="auto", )
|
| 294 |
+
|
| 295 |
+
demo.queue()
|
| 296 |
+
demo.launch()
|
lightning-hydra-template/.github/PULL_REQUEST_TEMPLATE.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
## What does this PR do?
|
| 2 |
+
|
| 3 |
+
<!--
|
| 4 |
+
Please include a summary of the change and which issue is fixed.
|
| 5 |
+
Please also include relevant motivation and context.
|
| 6 |
+
List any dependencies that are required for this change.
|
| 7 |
+
List all the breaking changes introduced by this pull request.
|
| 8 |
+
-->
|
| 9 |
+
|
| 10 |
+
Fixes #\<issue_number>
|
| 11 |
+
|
| 12 |
+
## Before submitting
|
| 13 |
+
|
| 14 |
+
- [ ] Did you make sure **title is self-explanatory** and **the description concisely explains the PR**?
|
| 15 |
+
- [ ] Did you make sure your **PR does only one thing**, instead of bundling different changes together?
|
| 16 |
+
- [ ] Did you list all the **breaking changes** introduced by this pull request?
|
| 17 |
+
- [ ] Did you **test your PR locally** with `pytest` command?
|
| 18 |
+
- [ ] Did you **run pre-commit hooks** with `pre-commit run -a` command?
|
| 19 |
+
|
| 20 |
+
## Did you have fun?
|
| 21 |
+
|
| 22 |
+
Make sure you had fun coding 🙃
|
lightning-hydra-template/.github/dependabot.yml
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# To get started with Dependabot version updates, you'll need to specify which
|
| 2 |
+
# package ecosystems to update and where the package manifests are located.
|
| 3 |
+
# Please see the documentation for all configuration options:
|
| 4 |
+
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
| 5 |
+
|
| 6 |
+
version: 2
|
| 7 |
+
updates:
|
| 8 |
+
- package-ecosystem: "pip" # See documentation for possible values
|
| 9 |
+
directory: "/" # Location of package manifests
|
| 10 |
+
schedule:
|
| 11 |
+
interval: "daily"
|
| 12 |
+
ignore:
|
| 13 |
+
- dependency-name: "pytorch-lightning"
|
| 14 |
+
update-types: ["version-update:semver-patch"]
|
| 15 |
+
- dependency-name: "torchmetrics"
|
| 16 |
+
update-types: ["version-update:semver-patch"]
|
lightning-hydra-template/.github/workflows/code-quality-pr.yaml
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This workflow finds which files were changed, prints them,
|
| 2 |
+
# and runs `pre-commit` on those files.
|
| 3 |
+
|
| 4 |
+
# Inspired by the sktime library:
|
| 5 |
+
# https://github.com/alan-turing-institute/sktime/blob/main/.github/workflows/test.yml
|
| 6 |
+
|
| 7 |
+
name: Code Quality PR
|
| 8 |
+
|
| 9 |
+
on:
|
| 10 |
+
pull_request:
|
| 11 |
+
branches: [main, "release/*", "dev"]
|
| 12 |
+
|
| 13 |
+
jobs:
|
| 14 |
+
code-quality:
|
| 15 |
+
runs-on: ubuntu-latest
|
| 16 |
+
|
| 17 |
+
steps:
|
| 18 |
+
- name: Checkout
|
| 19 |
+
uses: actions/checkout@v2
|
| 20 |
+
|
| 21 |
+
- name: Set up Python
|
| 22 |
+
uses: actions/setup-python@v2
|
| 23 |
+
|
| 24 |
+
- name: Find modified files
|
| 25 |
+
id: file_changes
|
| 26 |
+
uses: trilom/file-changes-action@v1.2.4
|
| 27 |
+
with:
|
| 28 |
+
output: " "
|
| 29 |
+
|
| 30 |
+
- name: List modified files
|
| 31 |
+
run: echo '${{ steps.file_changes.outputs.files}}'
|
| 32 |
+
|
| 33 |
+
- name: Run pre-commits
|
| 34 |
+
uses: pre-commit/action@v2.0.3
|
| 35 |
+
with:
|
| 36 |
+
extra_args: --files ${{ steps.file_changes.outputs.files}}
|
lightning-hydra-template/configs/callbacks/default.yaml
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
defaults:
|
| 2 |
+
- model_checkpoint
|
| 3 |
+
- early_stopping
|
| 4 |
+
- model_summary
|
| 5 |
+
- rich_progress_bar
|
| 6 |
+
- _self_
|
| 7 |
+
|
| 8 |
+
model_checkpoint:
|
| 9 |
+
dirpath: ${paths.output_dir}/checkpoints
|
| 10 |
+
filename: "epoch_{epoch:03d}"
|
| 11 |
+
monitor: "val/acc"
|
| 12 |
+
mode: "max"
|
| 13 |
+
save_last: True
|
| 14 |
+
auto_insert_metric_name: False
|
| 15 |
+
|
| 16 |
+
early_stopping:
|
| 17 |
+
monitor: "val/acc"
|
| 18 |
+
patience: 100
|
| 19 |
+
mode: "max"
|
| 20 |
+
|
| 21 |
+
model_summary:
|
| 22 |
+
max_depth: -1
|
lightning-hydra-template/configs/callbacks/early_stopping.yaml
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# https://lightning.ai/docs/pytorch/stable/api/lightning.pytorch.callbacks.EarlyStopping.html
|
| 2 |
+
|
| 3 |
+
early_stopping:
|
| 4 |
+
_target_: lightning.pytorch.callbacks.EarlyStopping
|
| 5 |
+
monitor: ??? # quantity to be monitored, must be specified !!!
|
| 6 |
+
min_delta: 0. # minimum change in the monitored quantity to qualify as an improvement
|
| 7 |
+
patience: 3 # number of checks with no improvement after which training will be stopped
|
| 8 |
+
verbose: False # verbosity mode
|
| 9 |
+
mode: "min" # "max" means higher metric value is better, can be also "min"
|
| 10 |
+
strict: True # whether to crash the training if monitor is not found in the validation metrics
|
| 11 |
+
check_finite: True # when set True, stops training when the monitor becomes NaN or infinite
|
| 12 |
+
stopping_threshold: null # stop training immediately once the monitored quantity reaches this threshold
|
| 13 |
+
divergence_threshold: null # stop training as soon as the monitored quantity becomes worse than this threshold
|
| 14 |
+
check_on_train_epoch_end: null # whether to run early stopping at the end of the training epoch
|
| 15 |
+
# log_rank_zero_only: False # this keyword argument isn't available in stable version
|
lightning-hydra-template/configs/callbacks/model_checkpoint.yaml
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# https://lightning.ai/docs/pytorch/stable/api/lightning.pytorch.callbacks.ModelCheckpoint.html
|
| 2 |
+
|
| 3 |
+
model_checkpoint:
|
| 4 |
+
_target_: lightning.pytorch.callbacks.ModelCheckpoint
|
| 5 |
+
dirpath: null # directory to save the model file
|
| 6 |
+
filename: null # checkpoint filename
|
| 7 |
+
monitor: null # name of the logged metric which determines when model is improving
|
| 8 |
+
verbose: False # verbosity mode
|
| 9 |
+
save_last: null # additionally always save an exact copy of the last checkpoint to a file last.ckpt
|
| 10 |
+
save_top_k: 1 # save k best models (determined by above metric)
|
| 11 |
+
mode: "min" # "max" means higher metric value is better, can be also "min"
|
| 12 |
+
auto_insert_metric_name: True # when True, the checkpoints filenames will contain the metric name
|
| 13 |
+
save_weights_only: False # if True, then only the model’s weights will be saved
|
| 14 |
+
every_n_train_steps: null # number of training steps between checkpoints
|
| 15 |
+
train_time_interval: null # checkpoints are monitored at the specified time interval
|
| 16 |
+
every_n_epochs: null # number of epochs between checkpoints
|
| 17 |
+
save_on_train_epoch_end: null # whether to run checkpointing at the end of the training epoch or the end of validation
|
lightning-hydra-template/configs/callbacks/model_summary.yaml
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# https://lightning.ai/docs/pytorch/stable/api/lightning.pytorch.callbacks.RichModelSummary.html
|
| 2 |
+
|
| 3 |
+
model_summary:
|
| 4 |
+
_target_: lightning.pytorch.callbacks.RichModelSummary
|
| 5 |
+
max_depth: 1 # the maximum depth of layer nesting that the summary will include
|
lightning-hydra-template/configs/callbacks/none.yaml
ADDED
|
File without changes
|
lightning-hydra-template/configs/callbacks/rich_progress_bar.yaml
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# https://lightning.ai/docs/pytorch/latest/api/lightning.pytorch.callbacks.RichProgressBar.html
|
| 2 |
+
|
| 3 |
+
rich_progress_bar:
|
| 4 |
+
_target_: lightning.pytorch.callbacks.RichProgressBar
|
lightning-hydra-template/configs/debug/default.yaml
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# @package _global_
|
| 2 |
+
|
| 3 |
+
# default debugging setup, runs 1 full epoch
|
| 4 |
+
# other debugging configs can inherit from this one
|
| 5 |
+
|
| 6 |
+
# overwrite task name so debugging logs are stored in separate folder
|
| 7 |
+
task_name: "debug"
|
| 8 |
+
|
| 9 |
+
# disable callbacks and loggers during debugging
|
| 10 |
+
callbacks: null
|
| 11 |
+
logger: null
|
| 12 |
+
|
| 13 |
+
extras:
|
| 14 |
+
ignore_warnings: False
|
| 15 |
+
enforce_tags: False
|
| 16 |
+
|
| 17 |
+
# sets level of all command line loggers to 'DEBUG'
|
| 18 |
+
# https://hydra.cc/docs/tutorials/basic/running_your_app/logging/
|
| 19 |
+
hydra:
|
| 20 |
+
job_logging:
|
| 21 |
+
root:
|
| 22 |
+
level: DEBUG
|
| 23 |
+
|
| 24 |
+
# use this to also set hydra loggers to 'DEBUG'
|
| 25 |
+
# verbose: True
|
| 26 |
+
|
| 27 |
+
trainer:
|
| 28 |
+
max_epochs: 1
|
| 29 |
+
accelerator: cpu # debuggers don't like gpus
|
| 30 |
+
devices: 1 # debuggers don't like multiprocessing
|
| 31 |
+
detect_anomaly: true # raise exception if NaN or +/-inf is detected in any tensor
|
| 32 |
+
|
| 33 |
+
data:
|
| 34 |
+
num_workers: 0 # debuggers don't like multiprocessing
|
| 35 |
+
pin_memory: False # disable gpu memory pin
|
lightning-hydra-template/configs/debug/fdr.yaml
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# @package _global_
|
| 2 |
+
|
| 3 |
+
# runs 1 train, 1 validation and 1 test step
|
| 4 |
+
|
| 5 |
+
defaults:
|
| 6 |
+
- default
|
| 7 |
+
|
| 8 |
+
trainer:
|
| 9 |
+
fast_dev_run: true
|
lightning-hydra-template/configs/debug/limit.yaml
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# @package _global_
|
| 2 |
+
|
| 3 |
+
# uses only 1% of the training data and 5% of validation/test data
|
| 4 |
+
|
| 5 |
+
defaults:
|
| 6 |
+
- default
|
| 7 |
+
|
| 8 |
+
trainer:
|
| 9 |
+
max_epochs: 3
|
| 10 |
+
limit_train_batches: 0.01
|
| 11 |
+
limit_val_batches: 0.05
|
| 12 |
+
limit_test_batches: 0.05
|
lightning-hydra-template/configs/debug/overfit.yaml
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# @package _global_
|
| 2 |
+
|
| 3 |
+
# overfits to 3 batches
|
| 4 |
+
|
| 5 |
+
defaults:
|
| 6 |
+
- default
|
| 7 |
+
|
| 8 |
+
trainer:
|
| 9 |
+
max_epochs: 20
|
| 10 |
+
overfit_batches: 3
|
| 11 |
+
|
| 12 |
+
# model ckpt and early stopping need to be disabled during overfitting
|
| 13 |
+
callbacks: null
|
lightning-hydra-template/configs/debug/profiler.yaml
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# @package _global_
|
| 2 |
+
|
| 3 |
+
# runs with execution time profiling
|
| 4 |
+
|
| 5 |
+
defaults:
|
| 6 |
+
- default
|
| 7 |
+
|
| 8 |
+
trainer:
|
| 9 |
+
max_epochs: 1
|
| 10 |
+
profiler: "simple"
|
| 11 |
+
# profiler: "advanced"
|
| 12 |
+
# profiler: "pytorch"
|
lightning-hydra-template/configs/experiment/example.yaml
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# @package _global_
|
| 2 |
+
|
| 3 |
+
# to execute this experiment run:
|
| 4 |
+
# python train.py experiment=example
|
| 5 |
+
|
| 6 |
+
defaults:
|
| 7 |
+
- override /data: mnist
|
| 8 |
+
- override /model: mnist
|
| 9 |
+
- override /callbacks: default
|
| 10 |
+
- override /trainer: default
|
| 11 |
+
|
| 12 |
+
# all parameters below will be merged with parameters from default configurations set above
|
| 13 |
+
# this allows you to overwrite only specified parameters
|
| 14 |
+
|
| 15 |
+
tags: ["mnist", "simple_dense_net"]
|
| 16 |
+
|
| 17 |
+
seed: 12345
|
| 18 |
+
|
| 19 |
+
trainer:
|
| 20 |
+
min_epochs: 10
|
| 21 |
+
max_epochs: 10
|
| 22 |
+
gradient_clip_val: 0.5
|
| 23 |
+
|
| 24 |
+
model:
|
| 25 |
+
optimizer:
|
| 26 |
+
lr: 0.002
|
| 27 |
+
net:
|
| 28 |
+
lin1_size: 128
|
| 29 |
+
lin2_size: 256
|
| 30 |
+
lin3_size: 64
|
| 31 |
+
compile: false
|
| 32 |
+
|
| 33 |
+
data:
|
| 34 |
+
batch_size: 64
|
| 35 |
+
|
| 36 |
+
logger:
|
| 37 |
+
wandb:
|
| 38 |
+
tags: ${tags}
|
| 39 |
+
group: "mnist"
|
| 40 |
+
aim:
|
| 41 |
+
experiment: "mnist"
|
lightning-hydra-template/configs/extras/default.yaml
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# disable python warnings if they annoy you
|
| 2 |
+
ignore_warnings: False
|
| 3 |
+
|
| 4 |
+
# ask user for tags if none are provided in the config
|
| 5 |
+
enforce_tags: True
|
| 6 |
+
|
| 7 |
+
# pretty print config tree at the start of the run using Rich library
|
| 8 |
+
print_config: True
|
lightning-hydra-template/configs/hydra/default.yaml
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# https://hydra.cc/docs/configure_hydra/intro/
|
| 2 |
+
|
| 3 |
+
# enable color logging
|
| 4 |
+
defaults:
|
| 5 |
+
- override hydra_logging: colorlog
|
| 6 |
+
- override job_logging: colorlog
|
| 7 |
+
|
| 8 |
+
# output directory, generated dynamically on each run
|
| 9 |
+
run:
|
| 10 |
+
dir: ${paths.log_dir}/${task_name}/runs/${now:%Y-%m-%d}_${now:%H-%M-%S}
|
| 11 |
+
sweep:
|
| 12 |
+
dir: ${paths.log_dir}/${task_name}/multiruns/${now:%Y-%m-%d}_${now:%H-%M-%S}
|
| 13 |
+
subdir: ${hydra.job.num}
|
| 14 |
+
|
| 15 |
+
job_logging:
|
| 16 |
+
handlers:
|
| 17 |
+
file:
|
| 18 |
+
# Incorporates fix from https://github.com/facebookresearch/hydra/pull/2242
|
| 19 |
+
filename: ${hydra.runtime.output_dir}/${task_name}.log
|
lightning-hydra-template/configs/logger/csv.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# csv logger built in lightning
|
| 2 |
+
|
| 3 |
+
csv:
|
| 4 |
+
_target_: lightning.pytorch.loggers.csv_logs.CSVLogger
|
| 5 |
+
save_dir: "${paths.output_dir}"
|
| 6 |
+
name: "csv/"
|
| 7 |
+
prefix: ""
|
lightning-hydra-template/configs/logger/many_loggers.yaml
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# train with many loggers at once
|
| 2 |
+
|
| 3 |
+
defaults:
|
| 4 |
+
# - comet
|
| 5 |
+
- csv
|
| 6 |
+
# - mlflow
|
| 7 |
+
# - neptune
|
| 8 |
+
- tensorboard
|
| 9 |
+
- wandb
|
lightning-hydra-template/configs/logger/tensorboard.yaml
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# https://www.tensorflow.org/tensorboard/
|
| 2 |
+
|
| 3 |
+
tensorboard:
|
| 4 |
+
_target_: lightning.pytorch.loggers.tensorboard.TensorBoardLogger
|
| 5 |
+
save_dir: "${paths.output_dir}/tensorboard/"
|
| 6 |
+
name: null
|
| 7 |
+
log_graph: False
|
| 8 |
+
default_hp_metric: True
|
| 9 |
+
prefix: ""
|
| 10 |
+
# version: ""
|
lightning-hydra-template/configs/logger/wandb.yaml
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# https://wandb.ai
|
| 2 |
+
|
| 3 |
+
wandb:
|
| 4 |
+
_target_: lightning.pytorch.loggers.wandb.WandbLogger
|
| 5 |
+
# name: "" # name of the run (normally generated by wandb)
|
| 6 |
+
save_dir: "${paths.output_dir}"
|
| 7 |
+
offline: False
|
| 8 |
+
id: null # pass correct id to resume experiment!
|
| 9 |
+
anonymous: null # enable anonymous logging
|
| 10 |
+
project: "lightning-hydra-template"
|
| 11 |
+
log_model: False # upload lightning ckpts
|
| 12 |
+
prefix: "" # a string to put at the beginning of metric keys
|
| 13 |
+
# entity: "" # set to name of your wandb team
|
| 14 |
+
group: ""
|
| 15 |
+
tags: []
|
| 16 |
+
job_type: ""
|
lightning-hydra-template/configs/model/mnist.yaml
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
_target_: src.models.mnist_module.MNISTLitModule
|
| 2 |
+
|
| 3 |
+
optimizer:
|
| 4 |
+
_target_: torch.optim.Adam
|
| 5 |
+
_partial_: true
|
| 6 |
+
lr: 0.001
|
| 7 |
+
weight_decay: 0.0
|
| 8 |
+
|
| 9 |
+
scheduler:
|
| 10 |
+
_target_: torch.optim.lr_scheduler.ReduceLROnPlateau
|
| 11 |
+
_partial_: true
|
| 12 |
+
mode: min
|
| 13 |
+
factor: 0.1
|
| 14 |
+
patience: 10
|
| 15 |
+
|
| 16 |
+
net:
|
| 17 |
+
_target_: src.models.components.simple_dense_net.SimpleDenseNet
|
| 18 |
+
input_size: 784
|
| 19 |
+
lin1_size: 64
|
| 20 |
+
lin2_size: 128
|
| 21 |
+
lin3_size: 64
|
| 22 |
+
output_size: 10
|
| 23 |
+
|
| 24 |
+
# compile model for faster training with pytorch 2.0
|
| 25 |
+
compile: false
|
lightning-hydra-template/configs/paths/default.yaml
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# path to root directory
|
| 2 |
+
# this requires PROJECT_ROOT environment variable to exist
|
| 3 |
+
# you can replace it with "." if you want the root to be the current working directory
|
| 4 |
+
root_dir: ${oc.env:PROJECT_ROOT}
|
| 5 |
+
|
| 6 |
+
# path to data directory
|
| 7 |
+
data_dir: ${paths.root_dir}/data/
|
| 8 |
+
|
| 9 |
+
# path to logging directory
|
| 10 |
+
log_dir: ${paths.root_dir}/logs/
|
| 11 |
+
|
| 12 |
+
# path to output directory, created dynamically by hydra
|
| 13 |
+
# path generation pattern is specified in `configs/hydra/default.yaml`
|
| 14 |
+
# use it to store all files generated during the run, like ckpts and metrics
|
| 15 |
+
output_dir: ${hydra:runtime.output_dir}
|
| 16 |
+
|
| 17 |
+
# path to working directory
|
| 18 |
+
work_dir: ${hydra:runtime.cwd}
|
lightning-hydra-template/configs/trainer/cpu.yaml
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
defaults:
|
| 2 |
+
- default
|
| 3 |
+
|
| 4 |
+
accelerator: cpu
|
| 5 |
+
devices: 1
|
lightning-hydra-template/configs/trainer/ddp.yaml
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
defaults:
|
| 2 |
+
- default
|
| 3 |
+
|
| 4 |
+
strategy: ddp
|
| 5 |
+
|
| 6 |
+
accelerator: gpu
|
| 7 |
+
devices: 4
|
| 8 |
+
num_nodes: 1
|
| 9 |
+
sync_batchnorm: True
|
lightning-hydra-template/configs/trainer/ddp_sim.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
defaults:
|
| 2 |
+
- default
|
| 3 |
+
|
| 4 |
+
# simulate DDP on CPU, useful for debugging
|
| 5 |
+
accelerator: cpu
|
| 6 |
+
devices: 2
|
| 7 |
+
strategy: ddp_spawn
|
lightning-hydra-template/configs/trainer/default.yaml
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
_target_: lightning.pytorch.trainer.Trainer
|
| 2 |
+
|
| 3 |
+
default_root_dir: ${paths.output_dir}
|
| 4 |
+
|
| 5 |
+
min_epochs: 1 # prevents early stopping
|
| 6 |
+
max_epochs: 10
|
| 7 |
+
|
| 8 |
+
accelerator: cpu
|
| 9 |
+
devices: 1
|
| 10 |
+
|
| 11 |
+
# mixed precision for extra speed-up
|
| 12 |
+
# precision: 16
|
| 13 |
+
|
| 14 |
+
# perform a validation loop every N training epochs
|
| 15 |
+
check_val_every_n_epoch: 1
|
| 16 |
+
|
| 17 |
+
# set True to to ensure deterministic results
|
| 18 |
+
# makes training slower but gives more reproducibility than just setting seeds
|
| 19 |
+
deterministic: False
|
lightning-hydra-template/configs/trainer/gpu.yaml
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
defaults:
|
| 2 |
+
- default
|
| 3 |
+
|
| 4 |
+
accelerator: gpu
|
| 5 |
+
devices: 1
|
lightning-hydra-template/configs/trainer/mps.yaml
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
defaults:
|
| 2 |
+
- default
|
| 3 |
+
|
| 4 |
+
accelerator: mps
|
| 5 |
+
devices: 1
|