tuandunghcmut commited on
Commit
d2ab3a0
·
verified ·
1 Parent(s): 4617407

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. DeepSeek-VL2/deepseek_vl2.egg-info/PKG-INFO +461 -0
  2. DeepSeek-VL2/deepseek_vl2.egg-info/SOURCES.txt +26 -0
  3. DeepSeek-VL2/deepseek_vl2.egg-info/dependency_links.txt +1 -0
  4. EAGLE/.gitignore +43 -0
  5. EAGLE/LICENSE +201 -0
  6. EAGLE/gradio_demo.py +334 -0
  7. EAGLE/predict_demo.py +78 -0
  8. EAGLE/setup.py +24 -0
  9. EAGLE/train.py +1201 -0
  10. Groma/README.md +268 -0
  11. VLM2Vec/evaluation/eval_utils.py +26 -0
  12. VLM2Vec/grad_cache/cachex/training.py +30 -0
  13. VLM2Vec/grad_cache/cachex/tree_utils.py +17 -0
  14. VLM2Vec/src/vlm_backbone/phi3_v/configuration_phi3_v.py +217 -0
  15. VLM2Vec/src/vlm_backbone/phi3_v/image_processing_phi3_v.py +286 -0
  16. VLM2Vec/src/vlm_backbone/phi3_v/modeling_phi3_v.py +1633 -0
  17. VLMEvalKit/LICENSE +203 -0
  18. a_distributed_notebook/temp/ddp_tutorial.py +169 -0
  19. a_distributed_notebook/temp/run.py +162 -0
  20. a_distributed_notebook/temp/run_5.py +41 -0
  21. groundingLMM/app.py +296 -0
  22. lightning-hydra-template/.github/PULL_REQUEST_TEMPLATE.md +22 -0
  23. lightning-hydra-template/.github/dependabot.yml +16 -0
  24. lightning-hydra-template/.github/workflows/code-quality-pr.yaml +36 -0
  25. lightning-hydra-template/configs/callbacks/default.yaml +22 -0
  26. lightning-hydra-template/configs/callbacks/early_stopping.yaml +15 -0
  27. lightning-hydra-template/configs/callbacks/model_checkpoint.yaml +17 -0
  28. lightning-hydra-template/configs/callbacks/model_summary.yaml +5 -0
  29. lightning-hydra-template/configs/callbacks/none.yaml +0 -0
  30. lightning-hydra-template/configs/callbacks/rich_progress_bar.yaml +4 -0
  31. lightning-hydra-template/configs/debug/default.yaml +35 -0
  32. lightning-hydra-template/configs/debug/fdr.yaml +9 -0
  33. lightning-hydra-template/configs/debug/limit.yaml +12 -0
  34. lightning-hydra-template/configs/debug/overfit.yaml +13 -0
  35. lightning-hydra-template/configs/debug/profiler.yaml +12 -0
  36. lightning-hydra-template/configs/experiment/example.yaml +41 -0
  37. lightning-hydra-template/configs/extras/default.yaml +8 -0
  38. lightning-hydra-template/configs/hydra/default.yaml +19 -0
  39. lightning-hydra-template/configs/logger/csv.yaml +7 -0
  40. lightning-hydra-template/configs/logger/many_loggers.yaml +9 -0
  41. lightning-hydra-template/configs/logger/tensorboard.yaml +10 -0
  42. lightning-hydra-template/configs/logger/wandb.yaml +16 -0
  43. lightning-hydra-template/configs/model/mnist.yaml +25 -0
  44. lightning-hydra-template/configs/paths/default.yaml +18 -0
  45. lightning-hydra-template/configs/trainer/cpu.yaml +5 -0
  46. lightning-hydra-template/configs/trainer/ddp.yaml +9 -0
  47. lightning-hydra-template/configs/trainer/ddp_sim.yaml +7 -0
  48. lightning-hydra-template/configs/trainer/default.yaml +19 -0
  49. lightning-hydra-template/configs/trainer/gpu.yaml +5 -0
  50. 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
+ ![](./images/vl2_teaser.jpeg)
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('&lt;', '<').replace('&gt;', '>')
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