tuandunghcmut commited on
Commit
0d2c90e
·
verified ·
1 Parent(s): 80ed450

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. Ovis/.ipynb_checkpoints/README-checkpoint.md +110 -0
  2. Ovis/Ovis1.6-Gemma2-27B/1c18c1e92281df303545f22c27200f046fc44ec4/__init__.py +0 -0
  3. Ovis/Ovis1.6-Gemma2-27B/1c18c1e92281df303545f22c27200f046fc44ec4/__pycache__/configuration_ovis.cpython-310.pyc +0 -0
  4. Ovis/Ovis1.6-Gemma2-27B/1c18c1e92281df303545f22c27200f046fc44ec4/__pycache__/configuration_ovis.cpython-39.pyc +0 -0
  5. Ovis/Ovis1.6-Gemma2-27B/1c18c1e92281df303545f22c27200f046fc44ec4/__pycache__/modeling_ovis.cpython-310.pyc +0 -0
  6. Ovis/Ovis1.6-Gemma2-27B/1c18c1e92281df303545f22c27200f046fc44ec4/__pycache__/modeling_ovis.cpython-39.pyc +0 -0
  7. Ovis/Ovis1.6-Gemma2-27B/1c18c1e92281df303545f22c27200f046fc44ec4/configuration_ovis.py +201 -0
  8. Ovis/Ovis1.6-Gemma2-27B/1c18c1e92281df303545f22c27200f046fc44ec4/modeling_ovis.py +625 -0
  9. Ovis/Ovis1.6-Gemma2-27B/__init__.py +0 -0
  10. Ovis/docs/license/QWEN_LICENSE +53 -0
  11. Ovis/ovis.egg-info/PKG-INFO +30 -0
  12. Ovis/ovis.egg-info/SOURCES.txt +24 -0
  13. Ovis/ovis.egg-info/dependency_links.txt +1 -0
  14. Ovis/ovis.egg-info/requires.txt +26 -0
  15. Ovis/ovis.egg-info/top_level.txt +1 -0
  16. Ovis/ovis/__init__.py +3 -0
  17. Ovis/ovis/model/__init__.py +2 -0
  18. Ovis/ovis/model/__pycache__/conversation_formatter.cpython-311.pyc +0 -0
  19. Ovis/ovis/model/__pycache__/modeling_ovis.cpython-310.pyc +0 -0
  20. Ovis/ovis/model/modeling_ovis.py +434 -0
  21. Ovis/ovis/model/visual_tokenizer/base_visual_tokenizer.py +264 -0
  22. Ovis/ovis/model/visual_tokenizer/clip_visual_tokenizer.py +41 -0
  23. Ovis/ovis/model/visual_tokenizer/siglip_visual_tokenizer.py +43 -0
  24. Ovis/ovis/serve/__pycache__/runner.cpython-310.pyc +0 -0
  25. Ovis/ovis/serve/__pycache__/runner.cpython-311.pyc +0 -0
  26. Ovis/ovis/train/dataset/__init__.py +0 -0
  27. Ovis/ovis/train/dataset/caption_dataset.py +67 -0
  28. Ovis/ovis/train/dataset/conversation_dataset.py +67 -0
  29. Ovis/ovis/train/dataset/multimodal_dataset.py +72 -0
  30. Ovis/ovis/util/__init__.py +0 -0
  31. Ovis/ovis/util/__pycache__/__init__.cpython-310.pyc +0 -0
  32. Ovis/ovis/util/__pycache__/__init__.cpython-311.pyc +0 -0
  33. Ovis/ovis/util/__pycache__/constants.cpython-310.pyc +0 -0
  34. Ovis/ovis/util/__pycache__/constants.cpython-311.pyc +0 -0
  35. Ovis/ovis/util/__pycache__/utils.cpython-311.pyc +0 -0
  36. VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/.ipynb_checkpoints/Qwen2-VL-2B-Instruct_DSPAR_MINI_6345-checkpoint.json +1 -0
  37. VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6275.json +1 -0
  38. VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6278.json +1 -0
  39. VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6385.json +1 -0
  40. VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6481.json +1 -0
  41. VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6500.json +1 -0
  42. VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6513.json +1 -0
  43. VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6515.json +1 -0
  44. VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6517.json +1 -0
  45. VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6521.json +1 -0
  46. VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6533.json +1 -0
  47. VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6539.json +1 -0
  48. VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6580.json +1 -0
  49. VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6589.json +1 -0
  50. VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6608.json +1 -0
Ovis/.ipynb_checkpoints/README-checkpoint.md ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Ovis: Structural Embedding Alignment for Multimodal Large Language Model
2
+
3
+ Ovis (Open VISion) is a novel Multimodal Large Language Model (MLLM) architecture, designed to structurally align visual and textual embeddings. For a comprehensive introduction, please refer to the [Ovis paper](https://arxiv.org/abs/2405.20797).
4
+
5
+ <div style="text-align: center;">
6
+ <img style="max-width: 100%;" src="docs/ovis-illustration.png" alt="Ovis Illustration"/>
7
+ </div>
8
+
9
+ ## Release
10
+ - [11/26] 🔥 Announcing [Ovis1.6-Gemma2-27B](https://huggingface.co/AIDC-AI/Ovis1.6-Gemma2-27B)!
11
+ - [11/04] 🔥 Announcing quantized versions of Ovis1.6: [Ovis1.6-Gemma2-9B-GPTQ-Int4](https://huggingface.co/AIDC-AI/Ovis1.6-Gemma2-9B-GPTQ-Int4) and [Ovis1.6-Llama3.2-3B-GPTQ-Int4](https://huggingface.co/AIDC-AI/Ovis1.6-Llama3.2-3B-GPTQ-Int4)!
12
+ - [10/22] 🔥 Announcing Ovis1.6-Llama3.2-3B ([Model](https://huggingface.co/AIDC-AI/Ovis1.6-Llama3.2-3B), [Demo](https://huggingface.co/spaces/AIDC-AI/Ovis1.6-Llama3.2-3B))!
13
+ - [09/19] 🔥 Announcing Ovis1.6-Gemma2-9B ([Model](https://huggingface.co/AIDC-AI/Ovis1.6-Gemma2-9B), [Demo](https://huggingface.co/spaces/AIDC-AI/Ovis1.6-Gemma2-9B))! This latest release further enhances high-resolution image processing, is trained on a larger, more diverse, and higher-quality dataset, and refines the training process with DPO training following instruction-tuning.
14
+ - [07/24] 🔥 Introducing Ovis1.5, featuring improved high-resolution image processing and optimized training data for enhanced performance.
15
+ - [06/14] 🔥 Launch of Ovis1.0, the inaugural version of the Ovis model.
16
+
17
+ ## Contents
18
+ - [Install](#install)
19
+ - [Model](#model)
20
+ - [Performance](#performance)
21
+ - [Finetune](#finetune)
22
+ - [Inference](#inference)
23
+ - [Quantization](#quantization)
24
+ - [Citation](#citation)
25
+ - [Team](#team)
26
+ - [License](#license)
27
+
28
+ ## Install
29
+ Ovis has been tested with Python 3.10, Torch 2.4.0, Transformers 4.46.2, and DeepSpeed 0.15.4. For a comprehensive list of package dependencies, please consult the `requirements.txt` file. Before finetuning or inference, please install Ovis as follows.
30
+ ```bash
31
+ git clone [email protected]:AIDC-AI/Ovis.git
32
+ conda create -n ovis python=3.10 -y
33
+ conda activate ovis
34
+ cd Ovis
35
+ pip install -r requirements.txt
36
+ pip install -e .
37
+ ```
38
+
39
+ ## Model
40
+ Ovis can be instantiated with popular LLMs. We provide the following Ovis MLLMs:
41
+
42
+ | Ovis MLLMs | ViT | LLM | Model Weights | Demo |
43
+ |:------------------|:-----------:|:------------------:|:---------------------------------------------------------------:|:----------------------------------------------------------------:|
44
+ | Ovis1.6-Gemma2-27B | Siglip-400M | Gemma2-27B-It | [Huggingface](https://huggingface.co/AIDC-AI/Ovis1.6-Gemma2-27B) | - |
45
+ | Ovis1.6-Gemma2-9B | Siglip-400M | Gemma2-9B-It | [Huggingface](https://huggingface.co/AIDC-AI/Ovis1.6-Gemma2-9B) | [Space](https://huggingface.co/spaces/AIDC-AI/Ovis1.6-Gemma2-9B) |
46
+ | Ovis1.6-Llama3.2-3B | Siglip-400M | Llama-3.2-3B-Instruct | [Huggingface](https://huggingface.co/AIDC-AI/Ovis1.6-Llama3.2-3B) | [Space](https://huggingface.co/spaces/AIDC-AI/Ovis1.6-Llama3.2-3B) |
47
+
48
+ ## Performance
49
+ With **29B** parameters, **Ovis1.6-Gemma2-27B** achieves exceptional performance in the [OpenCompass](https://github.com/open-compass/VLMEvalKit) benchmark, ranking among the top-tier open-source MLLMs.
50
+
51
+ ![performance-Ovis1_6-Gemma2-27B](docs/performance/Ovis1_6-Gemma2-27B.png)
52
+
53
+ With just **10B** parameters, **Ovis1.6-Gemma2-9B** leads the [OpenCompass](https://github.com/open-compass/VLMEvalKit) benchmark among open-source MLLMs within **30B** parameters.
54
+
55
+ ![performance-Ovis1_6-Gemma2-9B](docs/performance/Ovis1_6-Gemma2-9B.png)
56
+
57
+ **Ovis1.6-Llama3.2-3B** leads the [OpenCompass](https://github.com/open-compass/VLMEvalKit) benchmark among open-source MLLMs under **4B** parameters, even surpassing Llama-3.2-11B-Vision-Instruct.
58
+
59
+ ![performance-Ovis1_6-Llama3_2-3B](docs/performance/Ovis1_6-Llama3_2-3B.png)
60
+
61
+ ## Finetune
62
+ Finetuning Ovis1.6-Gemma2-9B is supported in [ms-swift](https://github.com/modelscope/ms-swift).
63
+
64
+ ## Inference
65
+ We provide an inference wrapper in `ovis/serve/runner.py`, which can be used as:
66
+ ```python
67
+ from PIL import Image
68
+ from ovis.serve.runner import RunnerArguments, OvisRunner
69
+ image = Image.open('temp.png')
70
+ text = 'PROMPT'
71
+ runner_args = RunnerArguments(model_path='AIDC-AI/Ovis1.6-Gemma2-27B')
72
+ runner = OvisRunner(runner_args)
73
+ generation = runner.run([image, text])
74
+ ```
75
+ Based on [Gradio](https://github.com/gradio-app/gradio), Ovis can also be accessed via a web user interface:
76
+ ```bash
77
+ python ovis/serve/server.py --model_path MODEL_PATH --port PORT
78
+ ```
79
+
80
+ ## Quantization
81
+ We quantized Ovis1.6 using AutoGPTQ. For detailed information on running and creating your own quantized version, please refer to the respective Huggingface model cards: [Ovis1.6-Gemma2-9B-GPTQ-Int4](https://huggingface.co/AIDC-AI/Ovis1.6-Gemma2-9B-GPTQ-Int4) and [Ovis1.6-Llama3.2-3B-GPTQ-Int4](https://huggingface.co/AIDC-AI/Ovis1.6-Llama3.2-3B-GPTQ-Int4). Quantized Ovis1.6 maintains performance comparable to its non-quantized counterpart while requiring less GPU memory:
82
+
83
+ - Benchmark performance:
84
+ ![performance-Ovis1_6-Gemma2-9B-GPTQ-Int4](docs/performance/Ovis1_6-Gemma2-9B-GPTQ-Int4.png)
85
+ ![performance-Ovis1_6-Llama3_2-3B-GPTQ-Int4](docs/performance/Ovis1_6-Llama3_2-3B-GPTQ-Int4.png)
86
+
87
+ - GPU memory usage (max_partition=9):
88
+ ![performance-Ovis1_6-VRAM-Comparison](docs/performance/Ovis1_6-VRAM-Comparison.png)
89
+
90
+ ## Citation
91
+ If you find Ovis useful, please cite the paper
92
+ ```
93
+ @article{lu2024ovis,
94
+ title={Ovis: Structural Embedding Alignment for Multimodal Large Language Model},
95
+ author={Shiyin Lu and Yang Li and Qing-Guo Chen and Zhao Xu and Weihua Luo and Kaifu Zhang and Han-Jia Ye},
96
+ year={2024},
97
+ journal={arXiv:2405.20797}
98
+ }
99
+ ```
100
+
101
+ ## Team
102
+ This work is a collaborative effort by the MarcoVL team. We would also like to provide links to the following MLLM papers from our team:
103
+ - [Parrot: Multilingual Visual Instruction Tuning](https://arxiv.org/abs/2406.02539)
104
+ - [Wings: Learning Multimodal LLMs without Text-only Forgetting](https://arxiv.org/abs/2406.03496)
105
+
106
+ ## License
107
+ This project is licensed under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt) (SPDX-License-Identifier: Apache-2.0).
108
+
109
+ ## Disclaimer
110
+ We used compliance-checking algorithms during the training process, to ensure the compliance of the trained model to the best of our ability. Due to the complexity of the data and the diversity of language model usage scenarios, we cannot guarantee that the model is completely free of copyright issues or improper content. If you believe anything infringes on your rights or generates improper content, please contact us, and we will promptly address the matter.
Ovis/Ovis1.6-Gemma2-27B/1c18c1e92281df303545f22c27200f046fc44ec4/__init__.py ADDED
File without changes
Ovis/Ovis1.6-Gemma2-27B/1c18c1e92281df303545f22c27200f046fc44ec4/__pycache__/configuration_ovis.cpython-310.pyc ADDED
Binary file (6.66 kB). View file
 
Ovis/Ovis1.6-Gemma2-27B/1c18c1e92281df303545f22c27200f046fc44ec4/__pycache__/configuration_ovis.cpython-39.pyc ADDED
Binary file (6.6 kB). View file
 
Ovis/Ovis1.6-Gemma2-27B/1c18c1e92281df303545f22c27200f046fc44ec4/__pycache__/modeling_ovis.cpython-310.pyc ADDED
Binary file (21.1 kB). View file
 
Ovis/Ovis1.6-Gemma2-27B/1c18c1e92281df303545f22c27200f046fc44ec4/__pycache__/modeling_ovis.cpython-39.pyc ADDED
Binary file (21.1 kB). View file
 
Ovis/Ovis1.6-Gemma2-27B/1c18c1e92281df303545f22c27200f046fc44ec4/configuration_ovis.py ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from abc import ABC, abstractmethod
2
+ from typing import List, Dict, Union, Optional
3
+
4
+ from transformers import PretrainedConfig, AutoConfig
5
+
6
+ IGNORE_ID = -100
7
+ IMAGE_TOKEN_ID = -200
8
+ IMAGE_TOKEN = "<image>"
9
+ IMAGE_ATOM_ID = -300
10
+ IMAGE_INDICATOR_IDS = [-301, -302, -303, -304, -305]
11
+
12
+
13
+ # ----------------------------------------------------------------------
14
+ # Visual Tokenizer Configuration
15
+ # ----------------------------------------------------------------------
16
+ class BaseVisualTokenizerConfig(PretrainedConfig):
17
+ def __init__(
18
+ self,
19
+ vocab_size=16384,
20
+ tokenize_function="softmax",
21
+ tau=1.0,
22
+ depths=None,
23
+ drop_cls_token=False,
24
+ backbone_config: Optional[Union[PretrainedConfig, dict]] = None,
25
+ hidden_stride: int = 1,
26
+ **kwargs
27
+ ):
28
+ super().__init__(**kwargs)
29
+ self.vocab_size = vocab_size
30
+ self.tokenize_function = tokenize_function
31
+ self.tau = tau
32
+ if isinstance(depths, str):
33
+ depths = [int(x) for x in depths.split('|')]
34
+ self.depths = depths
35
+ self.backbone_kwargs = {}
36
+ self.drop_cls_token = drop_cls_token
37
+ if backbone_config is not None:
38
+ assert isinstance(backbone_config, (PretrainedConfig, dict)), \
39
+ f"expect `backbone_config` to be instance of PretrainedConfig or dict, but got {type(backbone_config)} type"
40
+ if not isinstance(backbone_config, PretrainedConfig):
41
+ model_type = backbone_config['model_type']
42
+ backbone_config.pop('model_type')
43
+ backbone_config = AutoConfig.for_model(model_type, **backbone_config)
44
+ self.backbone_config = backbone_config
45
+ self.hidden_stride = hidden_stride
46
+
47
+
48
+ class SiglipVisualTokenizerConfig(BaseVisualTokenizerConfig):
49
+ model_type = "siglip_visual_tokenizer"
50
+
51
+ def __init__(self, **kwargs):
52
+ super().__init__(**kwargs)
53
+ if self.drop_cls_token:
54
+ self.drop_cls_token = False
55
+ if self.depths:
56
+ assert len(self.depths) == 1
57
+ self.backbone_kwargs['num_hidden_layers'] = self.depths[0]
58
+
59
+
60
+ AutoConfig.register("siglip_visual_tokenizer", SiglipVisualTokenizerConfig)
61
+
62
+
63
+ # ----------------------------------------------------------------------
64
+ # Ovis Configuration
65
+ # ----------------------------------------------------------------------
66
+ class OvisConfig(PretrainedConfig):
67
+ model_type = "ovis"
68
+
69
+ def __init__(
70
+ self,
71
+ llm_config: Optional[Union[PretrainedConfig, dict]] = None,
72
+ visual_tokenizer_config: Optional[Union[PretrainedConfig, dict]] = None,
73
+ multimodal_max_length=8192,
74
+ hidden_size=None,
75
+ conversation_formatter_class=None,
76
+ llm_attn_implementation=None,
77
+ disable_tie_weight=False,
78
+ **kwargs
79
+ ):
80
+ super().__init__(**kwargs)
81
+ if llm_config is not None:
82
+ assert isinstance(llm_config, (PretrainedConfig, dict)), \
83
+ f"expect `llm_config` to be instance of PretrainedConfig or dict, but got {type(llm_config)} type"
84
+ if not isinstance(llm_config, PretrainedConfig):
85
+ model_type = llm_config['model_type']
86
+ llm_config.pop('model_type')
87
+ llm_config = AutoConfig.for_model(model_type, **llm_config)
88
+ self.llm_config = llm_config
89
+ if visual_tokenizer_config is not None:
90
+ assert isinstance(visual_tokenizer_config, (PretrainedConfig, dict)), \
91
+ f"expect `visual_tokenizer_config` to be instance of PretrainedConfig or dict, but got {type(visual_tokenizer_config)} type"
92
+ if not isinstance(visual_tokenizer_config, PretrainedConfig):
93
+ model_type = visual_tokenizer_config['model_type']
94
+ visual_tokenizer_config.pop('model_type')
95
+ visual_tokenizer_config = AutoConfig.for_model(model_type, **visual_tokenizer_config)
96
+ self.visual_tokenizer_config = visual_tokenizer_config
97
+ self.multimodal_max_length = multimodal_max_length
98
+ self.hidden_size = hidden_size
99
+ self.conversation_formatter_class = conversation_formatter_class
100
+ self.llm_attn_implementation = llm_attn_implementation
101
+ self.disable_tie_weight = disable_tie_weight
102
+
103
+
104
+ # ----------------------------------------------------------------------
105
+ # Conversation Formatter
106
+ # ----------------------------------------------------------------------
107
+ class ConversationFormatter(ABC):
108
+ support_tokenizer_types = None
109
+
110
+ def __init__(self, tokenizer):
111
+ tokenizer_type = type(tokenizer).__name__
112
+ assert tokenizer_type in self.support_tokenizer_types, \
113
+ f'Invalid tokenizer type, expected one from `{self.support_tokenizer_types}`, but got `{tokenizer_type}`'
114
+ self.tokenizer = tokenizer
115
+ self.image_token = IMAGE_TOKEN
116
+ self.image_token_id = IMAGE_TOKEN_ID
117
+ self.ignore_id = IGNORE_ID
118
+
119
+ def _tokenize_with_image_symbol(self, text):
120
+ text_chunks = [self.tokenizer(chunk, add_special_tokens=False).input_ids for chunk in
121
+ text.split(self.image_token)]
122
+ token_ids = []
123
+ num_chuck = len(text_chunks)
124
+ for i, chunk in enumerate(text_chunks):
125
+ token_ids.extend(chunk)
126
+ if i < num_chuck - 1:
127
+ token_ids.append(self.image_token_id)
128
+ return token_ids
129
+
130
+ @abstractmethod
131
+ def format(self, conversations: List[Dict], generation_preface=None):
132
+ pass
133
+
134
+ @abstractmethod
135
+ def format_query(self, query, generation_preface=""):
136
+ pass
137
+
138
+
139
+ class GemmaConversationFormatter(ConversationFormatter):
140
+ support_tokenizer_types = ['GemmaTokenizer', 'GemmaTokenizerFast']
141
+
142
+ def __init__(self, tokenizer):
143
+ super().__init__(tokenizer)
144
+ # Gemma does not support system prompt
145
+ self.from2role = {
146
+ "human": "<start_of_turn>user\n",
147
+ "gpt": "<start_of_turn>model\n",
148
+ }
149
+ self.gpt_token_num = None
150
+ self.im_end = "<end_of_turn>\n"
151
+ self.bos_token = "<bos>"
152
+ self.bos_token_ids = None
153
+
154
+ def format(self, conversations: List[Dict], generation_preface=None):
155
+ if self.gpt_token_num is None:
156
+ self.gpt_token_num = len(self.tokenizer(self.from2role["gpt"], add_special_tokens=False).input_ids)
157
+
158
+ if self.bos_token_ids is None:
159
+ self.bos_token_ids = self.tokenizer(self.bos_token, add_special_tokens=False).input_ids
160
+
161
+ if conversations[0]["from"] == "system":
162
+ raise ValueError("Gemma does not support system prompt")
163
+
164
+ if generation_preface is not None:
165
+ conversations.append({
166
+ "from": "gpt",
167
+ "value": generation_preface
168
+ })
169
+
170
+ prompt = "" + self.bos_token
171
+ input_ids = [] + self.bos_token_ids
172
+ labels = [] + [IGNORE_ID] * len(input_ids)
173
+ num_conversation = len(conversations)
174
+ for i, conversation in enumerate(conversations):
175
+ frm = conversation["from"]
176
+ role = self.from2role[frm]
177
+ message = conversation["value"].strip()
178
+ text = role + message
179
+ if i < num_conversation - 1 or generation_preface is None:
180
+ text += self.im_end
181
+ prompt += text
182
+ token_ids = self._tokenize_with_image_symbol(text)
183
+ input_ids.extend(token_ids)
184
+ label_ids = [self.ignore_id] * len(token_ids)
185
+ if frm == "gpt":
186
+ # learning `\n` following `im_end` is meaningless, so the last `\n` token is ignored in label
187
+ label_ids[self.gpt_token_num:-1] = token_ids[self.gpt_token_num:-1]
188
+ labels.extend(label_ids)
189
+
190
+ assert self._tokenize_with_image_symbol(prompt) == input_ids
191
+ assert len(input_ids) == len(labels)
192
+
193
+ return prompt, input_ids, labels
194
+
195
+ def format_query(self, query, generation_preface=""):
196
+ prompt, input_ids, _ = self.format([{
197
+ "from": "human",
198
+ "value": query
199
+ }], generation_preface=generation_preface)
200
+
201
+ return prompt, input_ids
Ovis/Ovis1.6-Gemma2-27B/1c18c1e92281df303545f22c27200f046fc44ec4/modeling_ovis.py ADDED
@@ -0,0 +1,625 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) 2024 AIDC-AI
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
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ #
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ import logging
16
+ import os
17
+ import importlib.metadata
18
+
19
+ from packaging import version
20
+ from importlib import import_module
21
+ from typing import List, Callable, Union, Optional, Dict
22
+
23
+ import PIL.Image
24
+ import torch
25
+ import transformers
26
+ from torch import Tensor
27
+ from torch.nn import init
28
+ from torch.nn.functional import softmax, gumbel_softmax, pad
29
+ from transformers.utils import is_flash_attn_2_available
30
+ from transformers import PreTrainedModel, AutoModel, AutoTokenizer, AutoModelForCausalLM, AutoImageProcessor
31
+ from transformers import SiglipImageProcessor, SiglipVisionModel
32
+ from transformers.cache_utils import HybridCache
33
+ from transformers.generation.utils import GenerateOutput
34
+
35
+ from .configuration_ovis import BaseVisualTokenizerConfig, SiglipVisualTokenizerConfig
36
+ from .configuration_ovis import OvisConfig, ConversationFormatter
37
+ from .configuration_ovis import IGNORE_ID, IMAGE_ATOM_ID, IMAGE_INDICATOR_IDS, IMAGE_TOKEN_ID
38
+
39
+
40
+ # ----------------------------------------------------------------------
41
+ # Visual Tokenizer
42
+ # ----------------------------------------------------------------------
43
+ class BaseVisualTokenizer(PreTrainedModel):
44
+ base_model_prefix = "backbone"
45
+ main_input_name = None
46
+ _image_processor_class = None
47
+ _image_processor_kwargs = {}
48
+ _backbone_class = None
49
+ _backbone_name_or_path = None
50
+
51
+ def __init__(self, config: BaseVisualTokenizerConfig, *inputs, **kwargs):
52
+ super().__init__(config, *inputs, **kwargs)
53
+ self.image_processor = AutoImageProcessor.from_pretrained(kwargs['image_processor_name_or_path'])
54
+ self.backbone = AutoModel.from_config(self.config.backbone_config)
55
+ head_dim = self.config.vocab_size - len(IMAGE_INDICATOR_IDS) # reserved tokens for IMAGE_INDICATORS
56
+ self.head = torch.nn.Sequential(
57
+ torch.nn.Linear(
58
+ self.backbone.config.hidden_size * self.config.hidden_stride * self.config.hidden_stride, head_dim,
59
+ bias=False
60
+ ),
61
+ torch.nn.LayerNorm(head_dim)
62
+ )
63
+
64
+ assert all((self.image_processor.do_resize,
65
+ not getattr(self.image_processor, 'do_center_crop', False),
66
+ self.image_processor.do_rescale,
67
+ self.image_processor.do_normalize
68
+ )), f"image_processor `{self.image_processor}` is not supported currently"
69
+
70
+ def get_backbone(self):
71
+ return self.backbone
72
+
73
+ def get_image_processor(self):
74
+ return self.image_processor
75
+
76
+ def mock_input(self):
77
+ height, width = self.get_image_size()
78
+ return torch.zeros(1, 3, height, width), self.construct_image_placeholders((1, 1))
79
+
80
+ def get_head(self):
81
+ return self.head
82
+
83
+ def get_image_size(self):
84
+ raise NotImplementedError
85
+
86
+ @staticmethod
87
+ def construct_image_placeholders(grid):
88
+ image_placeholders = [IMAGE_INDICATOR_IDS[0], IMAGE_ATOM_ID, IMAGE_INDICATOR_IDS[1]]
89
+ if grid[0] * grid[1] > 1:
90
+ for r in range(grid[0]):
91
+ for c in range(grid[1]):
92
+ image_placeholders.append(IMAGE_ATOM_ID)
93
+ if c < grid[1] - 1:
94
+ image_placeholders.append(IMAGE_INDICATOR_IDS[2])
95
+ if r < grid[0] - 1:
96
+ image_placeholders.append(IMAGE_INDICATOR_IDS[3])
97
+ image_placeholders.append(IMAGE_INDICATOR_IDS[4])
98
+ return image_placeholders
99
+
100
+ def preprocess_image(self, image: PIL.Image.Image, max_partition=9, covering_threshold=0.9, convert_to_rgb=True):
101
+ def _preprocess(img: PIL.Image.Image, side):
102
+ # first resize and preprocess
103
+ w, h = img.size
104
+ if w == h:
105
+ new_width = new_height = side
106
+ elif w > h:
107
+ new_width = side
108
+ new_height = int(h / w * new_width)
109
+ else:
110
+ new_height = side
111
+ new_width = int(w / h * new_height)
112
+ new_size = dict(height=new_height, width=new_width)
113
+ pixel_values = self.image_processor.preprocess(img, size=new_size, return_tensors='pt')['pixel_values']
114
+
115
+ # then pad to square
116
+ square_values = torch.zeros([1, 3, side, side], dtype=pixel_values.dtype, device=pixel_values.device)
117
+ new_height, new_width = pixel_values.shape[2:]
118
+ if new_height == new_width:
119
+ square_values[:, :, :, :] = pixel_values
120
+ elif new_height > new_width:
121
+ from_index = (side - new_width) // 2
122
+ square_values[:, :, :, from_index:from_index + new_width] = pixel_values
123
+ else:
124
+ from_index = (side - new_height) // 2
125
+ square_values[:, :, from_index:from_index + new_height, :] = pixel_values
126
+
127
+ return square_values
128
+
129
+ def _partition(img, grid):
130
+ w, h = img.size
131
+ row_height = h // grid[0]
132
+ col_width = w // grid[1]
133
+
134
+ partition = []
135
+ for row in range(grid[0]):
136
+ for col in range(grid[1]):
137
+ left = col * col_width
138
+ upper = row * row_height
139
+ right = w if col == grid[1] - 1 else (col + 1) * col_width
140
+ lower = h if row == grid[0] - 1 else (row + 1) * row_height
141
+ partition.append((left, upper, right, lower))
142
+
143
+ return partition
144
+
145
+ def _covering_area(left, upper, right, lower, side):
146
+ w = right - left
147
+ h = lower - upper
148
+ w, h = max(w, h), min(w, h)
149
+ if w > side:
150
+ h = h / w * side
151
+ w = side
152
+ return w * h
153
+
154
+ def _get_best_grid(img, side):
155
+ img_area = img.size[0] * img.size[1]
156
+
157
+ candidate_grids = []
158
+ for i in range(1, max_partition + 1):
159
+ for j in range(1, max_partition + 1):
160
+ if i * j <= max_partition:
161
+ candidate_grids.append((i, j))
162
+
163
+ all_grids = []
164
+ good_grids = []
165
+ for grid in candidate_grids:
166
+ partition = _partition(img, grid)
167
+ covering_ratio = sum([_covering_area(*p, side) for p in partition]) / img_area
168
+ assert covering_ratio <= 1.0
169
+ all_grids.append((grid, covering_ratio))
170
+ if covering_ratio > covering_threshold:
171
+ good_grids.append((grid, covering_ratio))
172
+
173
+ if len(good_grids) > 0:
174
+ # pick the good partition with minimum #sub_images and break the tie using covering_ratio
175
+ return sorted(good_grids, key=lambda x: (x[0][0] * x[0][1], -x[1]))[0][0]
176
+ else:
177
+ # pick the partition with maximum covering_ratio and break the tie using #sub_images
178
+ return sorted(all_grids, key=lambda x: (-x[1], x[0][0] * x[0][1]))[0][0]
179
+
180
+ if convert_to_rgb and image.mode != 'RGB':
181
+ image = image.convert('RGB')
182
+
183
+ sides = self.get_image_size()
184
+ if sides[0] != sides[1]:
185
+ raise ValueError('get_image_size() returns non-square size')
186
+ side = sides[0]
187
+ grid = _get_best_grid(image, side)
188
+ partition = _partition(image, grid)
189
+ crops = [image.crop(p) for p in partition]
190
+ if len(crops) > 1:
191
+ crops.insert(0, image)
192
+ pixel_values = torch.cat([_preprocess(crop, side) for crop in crops], dim=0)
193
+ image_placeholders = self.construct_image_placeholders(grid)
194
+ return pixel_values, image_placeholders
195
+
196
+ def tokenize(self, logits):
197
+ def st_argmax(y_soft, dim): # straight-through softmax
198
+ index = y_soft.max(dim, keepdim=True)[1]
199
+ y_hard = torch.zeros_like(y_soft, memory_format=torch.legacy_contiguous_format).scatter_(dim, index, 1.0)
200
+ ret = y_hard - y_soft.detach() + y_soft
201
+ return ret
202
+
203
+ if self.config.tokenize_function == 'softmax':
204
+ tokens = softmax(logits, dim=-1)
205
+ elif self.config.tokenize_function == 'gumbel_argmax':
206
+ tokens = gumbel_softmax(logits, tau=self.config.tau, hard=True)
207
+ elif self.config.tokenize_function == 'st_argmax':
208
+ tokens = st_argmax(logits, dim=-1)
209
+ else:
210
+ raise ValueError(
211
+ f'Invalid `max_type`, expected softmax or gumbel_argmax or st_argmax, but got {self.config.tokenize_function}')
212
+ return tokens
213
+
214
+ def encode(self, pixel_values):
215
+ output = self.backbone(pixel_values, output_hidden_states=True, return_dict=True)
216
+ features = output.hidden_states[-1]
217
+ if self.config.drop_cls_token:
218
+ features = features[:, 1:, :]
219
+
220
+ # merge number of `hidden_stride * hidden_stride` hidden states together to reduce token sequence length
221
+ # e.g., for hidden_stride=3, this leads to a token length reduction: 729 -> 81 for siglip
222
+ if self.config.hidden_stride > 1:
223
+ n, l, d = features.shape # this `d` maybe different from the above `d
224
+ sqrt_l = int(l ** 0.5)
225
+ assert sqrt_l ** 2 == l, "The token sequence length should be a perfect square."
226
+ features = features.reshape(n, sqrt_l, sqrt_l, d)
227
+ pl = (self.config.hidden_stride - (sqrt_l % self.config.hidden_stride)) % self.config.hidden_stride
228
+ features = pad(features, (0, 0, 0, pl, 0, pl), "constant", 0)
229
+ sqrt_l += pl
230
+ features = features.reshape(n, sqrt_l // self.config.hidden_stride, self.config.hidden_stride,
231
+ sqrt_l // self.config.hidden_stride, self.config.hidden_stride, d)
232
+ features = features.permute(0, 1, 3, 2, 4, 5) # [n, sqrt_l/hs, sqrt_l/hs, hs, hs, d]
233
+ features = features.flatten(3) # [n, sqrt_l/hs, sqrt_l/hs, hs*hs*d]
234
+ features = features.reshape(
235
+ n, -1, self.config.hidden_stride * self.config.hidden_stride * d)
236
+
237
+ return features
238
+
239
+ def forward(self, pixel_values) -> torch.Tensor: # [BatchSize, ImageShape] -> [BatchSize, #Token, VocabSize]
240
+ features = self.encode(pixel_values)
241
+ logits = self.head(features)
242
+ tokens = self.tokenize(logits)
243
+ # tokens' shape is [BatchSize, #Token, VocabSize-5], so padding with [BatchSize, #Token, 5], after
244
+ # which, tokens' shape should become [BatchSize, #Token, VocabSize]
245
+ batch_size, token_len, _ = tokens.shape
246
+ padding_tensor = torch.zeros(size=(batch_size, token_len, len(IMAGE_INDICATOR_IDS)),
247
+ dtype=tokens.dtype,
248
+ device=tokens.device,
249
+ layout=tokens.layout,
250
+ requires_grad=False)
251
+ tokens = torch.cat((tokens, padding_tensor), dim=2)
252
+ return tokens
253
+
254
+
255
+ class SiglipVisualTokenizer(BaseVisualTokenizer):
256
+ config_class = SiglipVisualTokenizerConfig
257
+ supports_gradient_checkpointing = True
258
+ _no_split_modules = ["SiglipVisionTransformer"]
259
+ _image_processor_class = SiglipImageProcessor
260
+ _image_processor_kwargs = {}
261
+ _backbone_class = SiglipVisionModel
262
+ _backbone_name_or_path = "google/siglip-so400m-patch14-384"
263
+
264
+ def get_image_size(self):
265
+ height = self.image_processor.size["height"]
266
+ width = self.image_processor.size["width"]
267
+ return height, width
268
+
269
+
270
+ AutoModel.register(SiglipVisualTokenizerConfig, SiglipVisualTokenizer)
271
+
272
+
273
+ # ----------------------------------------------------------------------
274
+ # Ovis
275
+ # ----------------------------------------------------------------------
276
+ class VisualEmbedding(torch.nn.Embedding):
277
+ def forward(self, visual_tokens: Tensor) -> Tensor:
278
+ if visual_tokens.dtype in [torch.int8, torch.int16, torch.int32, torch.int64, torch.long]:
279
+ return super().forward(visual_tokens)
280
+ return torch.matmul(visual_tokens, self.weight)
281
+
282
+ def reset_parameters(self, mean=0., std=1.) -> None:
283
+ init.normal_(self.weight, mean=mean, std=std)
284
+ self._fill_padding_idx_with_zero()
285
+
286
+
287
+ class OvisPreTrainedModel(PreTrainedModel):
288
+ config_class = OvisConfig
289
+ base_model_prefix = "ovis"
290
+
291
+
292
+ class Ovis(OvisPreTrainedModel):
293
+
294
+ def __init__(self, config: OvisConfig, *inputs, **kwargs):
295
+ super().__init__(config, *inputs, **kwargs)
296
+ attn_kwargs = dict()
297
+ if self.config.llm_attn_implementation:
298
+ if self.config.llm_attn_implementation == "sdpa":
299
+ raise ValueError("`sdpa` is currently not supported")
300
+ elif self.config.llm_attn_implementation == "flash_attention_2":
301
+ assert (is_flash_attn_2_available() and
302
+ version.parse(importlib.metadata.version("flash_attn")) >= version.parse("2.6.3")), \
303
+ "Using `flash_attention_2` requires having `flash_attn>=2.6.3` installed."
304
+ attn_kwargs["attn_implementation"] = self.config.llm_attn_implementation
305
+ self.llm = AutoModelForCausalLM.from_config(self.config.llm_config, **attn_kwargs)
306
+ assert self.config.hidden_size == self.llm.config.hidden_size, "hidden size mismatch"
307
+ self.text_tokenizer = AutoTokenizer.from_pretrained(self.config.name_or_path)
308
+ self.visual_tokenizer = AutoModel.from_config(self.config.visual_tokenizer_config,
309
+ image_processor_name_or_path=self.config.name_or_path)
310
+ self.vte = VisualEmbedding(
311
+ self.config.visual_tokenizer_config.vocab_size,
312
+ self.config.hidden_size,
313
+ device=self.visual_tokenizer.device,
314
+ dtype=self.visual_tokenizer.dtype
315
+ )
316
+
317
+ def _merge_modules(modules_list: tuple):
318
+ merged_modules = []
319
+ for modules in modules_list:
320
+ merged_modules.extend(modules if modules else [])
321
+ return merged_modules
322
+
323
+ self._no_split_modules = _merge_modules((self.llm._no_split_modules, self.visual_tokenizer._no_split_modules))
324
+ self._skip_keys_device_placement = self.llm._skip_keys_device_placement
325
+ self._keep_in_fp32_modules = _merge_modules(
326
+ (self.llm._keep_in_fp32_modules, self.visual_tokenizer._keep_in_fp32_modules))
327
+ self.is_parallelizable = all((self.llm.is_parallelizable, self.visual_tokenizer.is_parallelizable))
328
+ self.supports_gradient_checkpointing = all(
329
+ (self.llm.supports_gradient_checkpointing, self.visual_tokenizer.supports_gradient_checkpointing))
330
+ self._supports_flash_attn_2 = True
331
+ self._supports_sdpa = False
332
+
333
+ def get_text_tokenizer(self):
334
+ return self.text_tokenizer
335
+
336
+ def get_visual_tokenizer(self):
337
+ return self.visual_tokenizer
338
+
339
+ def tie_weights(self):
340
+ if not self.config.disable_tie_weight:
341
+ self.get_llm().tie_weights()
342
+
343
+ def get_llm(self):
344
+ return self.llm
345
+
346
+ def get_vte(self):
347
+ return self.vte
348
+
349
+ def get_wte(self):
350
+ return self.llm.get_input_embeddings()
351
+
352
+ def get_conversation_formatter(self) -> ConversationFormatter:
353
+ if getattr(self, 'conversation_formatter', None) is None:
354
+ self.conversation_formatter = getattr(import_module(".configuration_ovis", __package__),
355
+ self.config.conversation_formatter_class)(self.text_tokenizer)
356
+ return self.conversation_formatter
357
+
358
+ def forward(
359
+ self,
360
+ input_ids: torch.Tensor,
361
+ attention_mask: torch.Tensor,
362
+ labels: Optional[torch.Tensor],
363
+ pixel_values: List[Optional[torch.Tensor]],
364
+ **kwargs
365
+ ):
366
+ assert self.training, "`forward` can only be used in training. For inference, use `generate`."
367
+ _, inputs_embeds, labels, attention_mask = self.merge_multimodal(
368
+ text_input_ids=input_ids,
369
+ text_attention_masks=attention_mask,
370
+ text_labels=labels,
371
+ pixel_values=pixel_values
372
+ )
373
+ return self.llm(inputs_embeds=inputs_embeds, labels=labels, attention_mask=attention_mask, **kwargs)
374
+
375
+ def merge_multimodal(
376
+ self,
377
+ text_input_ids: torch.Tensor,
378
+ text_attention_masks: torch.Tensor,
379
+ text_labels: Optional[torch.Tensor],
380
+ pixel_values: List[Optional[torch.Tensor]],
381
+ left_padding: bool = False
382
+ ):
383
+ input_device = text_input_ids.device
384
+ visual_vocab_szie = self.get_visual_tokenizer().config.vocab_size
385
+ visual_indicator_embeds = self.get_vte()(
386
+ torch.tensor(
387
+ list(range(visual_vocab_szie - 5, visual_vocab_szie)),
388
+ dtype=torch.long,
389
+ device=self.get_visual_tokenizer().device
390
+ )
391
+ ).to(device=input_device)
392
+
393
+ if self.training:
394
+ # When training, to be compatible with deepspeed zero, each sample has to include pixel_value tensor.
395
+ # For text-only sample, one can simply use a full zero tensor as pixel_value, which will be ignored
396
+ # (see below in this function); so, the gradient will not be affected.
397
+ num_images = [x.shape[0] for x in pixel_values]
398
+ visual_tokens = self.visual_tokenizer(torch.cat([x for x in pixel_values], dim=0))
399
+ visual_embeds = torch.split(self.get_vte()(visual_tokens).to(dtype=self.dtype, device=input_device),
400
+ split_size_or_sections=num_images, dim=0)
401
+ visual_input_ids = torch.split(torch.argmax(visual_tokens, dim=-1).to(device=input_device),
402
+ split_size_or_sections=num_images, dim=0)
403
+ visual_labels = [torch.full(x.shape, IGNORE_ID, dtype=torch.long, device=input_device) for x in
404
+ visual_input_ids]
405
+ else:
406
+ # When inference, sample can include only text with `None` pixel_value
407
+ num_images = [x.shape[0] if x is not None else 0 for x in pixel_values]
408
+ if sum(num_images) > 0:
409
+ visual_tokens = self.visual_tokenizer(torch.cat([x for x in pixel_values if x is not None], dim=0))
410
+ visual_embeds = torch.split(self.get_vte()(visual_tokens).to(dtype=self.dtype, device=input_device),
411
+ split_size_or_sections=num_images, dim=0)
412
+ visual_input_ids = torch.split(torch.argmax(visual_tokens, dim=-1).to(device=input_device),
413
+ split_size_or_sections=num_images, dim=0)
414
+ visual_labels = [torch.full(x.shape, IGNORE_ID, dtype=torch.long, device=input_device) for x in
415
+ visual_input_ids]
416
+ else:
417
+ # just placeholders
418
+ visual_embeds = [None] * len(num_images)
419
+ visual_input_ids = [None] * len(num_images)
420
+ visual_labels = [None] * len(num_images)
421
+ if text_labels is None:
422
+ text_labels = torch.full(text_input_ids.shape, IGNORE_ID, dtype=torch.long, device=input_device)
423
+
424
+ input_embeds = []
425
+ attention_masks = []
426
+ labels = []
427
+ for text_input_id, text_label, text_attention_mask, visual_embed, visual_input_id, visual_label in zip(
428
+ text_input_ids, text_labels, text_attention_masks, visual_embeds, visual_input_ids, visual_labels
429
+ ):
430
+ placeholder_token_mask = torch.lt(text_input_id, 0)
431
+ text_embed = self.get_wte()(torch.masked_fill(text_input_id, placeholder_token_mask, 0))
432
+ for i, indicator_id in enumerate(IMAGE_INDICATOR_IDS):
433
+ text_embed[text_input_id == indicator_id] = visual_indicator_embeds[i]
434
+ image_atom_positions = torch.where(torch.eq(text_input_id, IMAGE_ATOM_ID))[0].tolist()
435
+ if len(image_atom_positions) > 0:
436
+ input_embed_parts = []
437
+ attention_mask_parts = []
438
+ label_parts = []
439
+ prev_image_atom_position = -1
440
+ for index, image_atom_position in enumerate(image_atom_positions):
441
+ input_embed_parts.append(
442
+ text_embed[prev_image_atom_position + 1:image_atom_position, :])
443
+ label_parts.append(
444
+ text_label[prev_image_atom_position + 1:image_atom_position])
445
+ attention_mask_parts.append(
446
+ text_attention_mask[prev_image_atom_position + 1:image_atom_position])
447
+ input_embed_parts.append(visual_embed[index])
448
+ attention_mask_parts.append(
449
+ torch.ones_like(visual_label[index], dtype=torch.bool))
450
+ label_parts.append(visual_label[index])
451
+ prev_image_atom_position = image_atom_position
452
+ if prev_image_atom_position + 1 < text_input_id.shape[0]:
453
+ input_embed_parts.append(
454
+ text_embed[prev_image_atom_position + 1:, :])
455
+ attention_mask_parts.append(
456
+ text_attention_mask[prev_image_atom_position + 1:])
457
+ label_parts.append(
458
+ text_label[prev_image_atom_position + 1:])
459
+ input_embed = torch.cat(input_embed_parts, dim=0)
460
+ attention_mask = torch.cat(attention_mask_parts, dim=0)
461
+ label = torch.cat(label_parts, dim=0)
462
+ else:
463
+ input_embed = text_embed
464
+ attention_mask = text_attention_mask
465
+ label = text_label
466
+ if self.training:
467
+ # Make visual_embed & visual_indicator_embeds involved in the backward graph,
468
+ # to be compatible with deepspeed zero and ddp.
469
+ input_embed += torch.sum(visual_embed * 0.0) + torch.sum(visual_indicator_embeds * 0.0)
470
+ input_embeds.append(input_embed)
471
+ attention_masks.append(attention_mask)
472
+ labels.append(label)
473
+
474
+ if self.training: # padding to self.config.multimodal_max_length for increased training speed
475
+ padding_size = max(0, self.config.multimodal_max_length - len(input_embeds[0]))
476
+ input_embeds[0] = torch.nn.ConstantPad2d((0, 0, 0, padding_size), 0.0)(input_embeds[0])
477
+ attention_masks[0] = torch.nn.ConstantPad1d((0, padding_size), False)(attention_masks[0])
478
+ labels[0] = torch.nn.ConstantPad1d((0, padding_size), IGNORE_ID)(labels[0])
479
+ batch_input_embeds = self.pad_truncate_sequence(input_embeds, batch_first=True, padding_value=0.0, left_padding=left_padding)
480
+ batch_attention_mask = self.pad_truncate_sequence(attention_masks, batch_first=True, padding_value=False, left_padding=left_padding)
481
+ batch_labels = self.pad_truncate_sequence(labels, batch_first=True, padding_value=IGNORE_ID, left_padding=left_padding)
482
+
483
+ return visual_input_ids, batch_input_embeds, batch_labels, batch_attention_mask
484
+
485
+ def pad_truncate_sequence(self, sequences: List[torch.Tensor], batch_first: bool = True, padding_value: float = 0.0, left_padding: bool = False) -> torch.Tensor:
486
+ if left_padding == False:
487
+ pad_sequence = torch.nn.utils.rnn.pad_sequence(sequences, batch_first=batch_first, padding_value=padding_value)
488
+ return pad_sequence[:,:self.config.multimodal_max_length]
489
+ else:
490
+ pad_sequence = torch.nn.utils.rnn.pad_sequence([i.flip(dims=[0]) for i in sequences],batch_first=True, padding_value=padding_value).flip(dims=[1])
491
+ return pad_sequence[:,-self.config.multimodal_max_length:]
492
+
493
+ def preprocess_inputs(
494
+ self,
495
+ text_or_conversations: Union[List[Dict], str],
496
+ images: Optional[List[PIL.Image.Image]],
497
+ max_partition=9,
498
+ generation_preface='',
499
+ return_labels=False,
500
+ propagate_exception=True
501
+ ):
502
+ # convert text to conversations
503
+ if isinstance(text_or_conversations, str):
504
+ conversations = [{
505
+ "from": "human",
506
+ "value": text_or_conversations
507
+ }]
508
+ elif isinstance(text_or_conversations, list):
509
+ conversations = text_or_conversations
510
+ else:
511
+ raise ValueError(f'Invalid type of `text_or_conversations`, expected `List[Dict]` or `str`,'
512
+ f' but got {type(text_or_conversations)}')
513
+
514
+ # format conversations
515
+ prompt, raw_input_ids, raw_labels = self.get_conversation_formatter().format(
516
+ conversations, generation_preface=generation_preface)
517
+
518
+ # place image placeholders
519
+ input_ids = []
520
+ labels = []
521
+ pixel_values = []
522
+ invalidate_label = False
523
+ image_token_indices = [i for i, v in enumerate(raw_input_ids) if v == IMAGE_TOKEN_ID]
524
+ last_image_token_index = -1
525
+ for i in range(len(image_token_indices)):
526
+ head = 0 if i == 0 else image_token_indices[i - 1] + 1
527
+ tail = image_token_indices[i]
528
+ last_image_token_index = tail
529
+ input_ids.extend(raw_input_ids[head:tail])
530
+ labels.extend(raw_labels[head:tail])
531
+ try:
532
+ image = images[i]
533
+ raw_pixel_values, image_placeholders = self.visual_tokenizer.preprocess_image(
534
+ image, max_partition=max_partition)
535
+ except Exception as e:
536
+ if propagate_exception:
537
+ raise e
538
+ logging.exception(e)
539
+ invalidate_label = True
540
+ raw_pixel_values, image_placeholders = self.visual_tokenizer.mock_input()
541
+ input_ids.extend(image_placeholders)
542
+ labels.extend([IGNORE_ID] * len(image_placeholders))
543
+ pixel_values.append(raw_pixel_values)
544
+ input_ids.extend(raw_input_ids[last_image_token_index + 1:])
545
+ labels.extend(raw_labels[last_image_token_index + 1:])
546
+
547
+ # return tensors
548
+ input_ids = torch.tensor(input_ids, dtype=torch.long)
549
+ labels = torch.tensor([IGNORE_ID] * len(labels) if invalidate_label else labels, dtype=torch.long)
550
+ pixel_values = torch.cat(pixel_values, dim=0) if len(pixel_values) > 0 else None
551
+
552
+ if return_labels:
553
+ return prompt, input_ids, pixel_values, labels
554
+ else:
555
+ return prompt, input_ids, pixel_values
556
+
557
+ def save_pretrained(
558
+ self,
559
+ save_directory: Union[str, os.PathLike],
560
+ is_main_process: bool = True,
561
+ state_dict: Optional[dict] = None,
562
+ save_function: Callable = torch.save,
563
+ push_to_hub: bool = False,
564
+ max_shard_size: Union[int, str] = "5GB",
565
+ safe_serialization: bool = True,
566
+ variant: Optional[str] = None,
567
+ token: Optional[Union[str, bool]] = None,
568
+ save_peft_format: bool = True,
569
+ **kwargs
570
+ ):
571
+ super().save_pretrained(save_directory,
572
+ is_main_process=is_main_process,
573
+ state_dict=state_dict,
574
+ save_function=save_function,
575
+ safe_serialization=safe_serialization)
576
+ self.get_text_tokenizer().save_pretrained(save_directory)
577
+ self.get_visual_tokenizer().get_image_processor().save_pretrained(save_directory)
578
+
579
+ def _get_hybrid_cache_for_llm(self, batch_size: int, max_cache_len: int):
580
+ cache_cls = HybridCache
581
+ llm = self.get_llm()
582
+
583
+ need_new_cache = (
584
+ not hasattr(llm, "_cache")
585
+ or (not isinstance(llm._cache, cache_cls))
586
+ or llm._cache.batch_size != batch_size
587
+ or llm._cache.max_cache_len < max_cache_len
588
+ )
589
+
590
+ if need_new_cache:
591
+ if hasattr(llm.config, "_pre_quantization_dtype"):
592
+ cache_dtype = llm.config._pre_quantization_dtype
593
+ else:
594
+ cache_dtype = llm.dtype
595
+ llm._cache = cache_cls(
596
+ config=llm.config,
597
+ batch_size=batch_size,
598
+ max_cache_len=max_cache_len,
599
+ device=llm.device,
600
+ dtype=cache_dtype,
601
+ )
602
+ else:
603
+ llm._cache.reset()
604
+ return llm._cache
605
+
606
+ # TODO: support batch generation
607
+ def generate(
608
+ self,
609
+ inputs: Optional[torch.Tensor] = None,
610
+ **kwargs
611
+ ) -> Union[GenerateOutput, torch.LongTensor]:
612
+ _, inputs_embeds, labels, attention_mask = self.merge_multimodal(
613
+ text_input_ids=inputs,
614
+ text_attention_masks=kwargs.pop('attention_mask'),
615
+ text_labels=None,
616
+ pixel_values=kwargs.pop('pixel_values'),
617
+ left_padding=True
618
+ )
619
+ if getattr(self.generation_config, 'cache_implementation') == 'hybrid': # mainly for Gemma2
620
+ kwargs['past_key_values'] = self._get_hybrid_cache_for_llm(
621
+ getattr(kwargs, "num_beams", inputs_embeds.shape[0]), kwargs['max_new_tokens'] + inputs_embeds.shape[-2])
622
+ self.get_llm()._supports_cache_class = True
623
+ kwargs['cache_implementation'] = None
624
+
625
+ return self.llm.generate(inputs=None, inputs_embeds=inputs_embeds, attention_mask=attention_mask, **kwargs)
Ovis/Ovis1.6-Gemma2-27B/__init__.py ADDED
File without changes
Ovis/docs/license/QWEN_LICENSE ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Tongyi Qianwen LICENSE AGREEMENT
2
+
3
+ Tongyi Qianwen Release Date: August 3, 2023
4
+
5
+ By clicking to agree or by using or distributing any portion or element of the Tongyi Qianwen Materials, you will be deemed to have recognized and accepted the content of this Agreement, which is effective immediately.
6
+
7
+ 1. Definitions
8
+ a. This Tongyi Qianwen LICENSE AGREEMENT (this "Agreement") shall mean the terms and conditions for use, reproduction, distribution and modification of the Materials as defined by this Agreement.
9
+ b. "We"(or "Us") shall mean Alibaba Cloud.
10
+ c. "You" (or "Your") shall mean a natural person or legal entity exercising the rights granted by this Agreement and/or using the Materials for any purpose and in any field of use.
11
+ d. "Third Parties" shall mean individuals or legal entities that are not under common control with Us or You.
12
+ e. "Tongyi Qianwen" shall mean the large language models (including Qwen model and Qwen-Chat model), and software and algorithms, consisting of trained model weights, parameters (including optimizer states), machine-learning model code, inference-enabling code, training-enabling code, fine-tuning enabling code and other elements of the foregoing distributed by Us.
13
+ f. "Materials" shall mean, collectively, Alibaba Cloud's proprietary Tongyi Qianwen and Documentation (and any portion thereof) made available under this Agreement.
14
+ g. "Source" form shall mean the preferred form for making modifications, including but not limited to model source code, documentation source, and configuration files.
15
+ h. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation,
16
+ and conversions to other media types.
17
+
18
+ 2. Grant of Rights
19
+ You are granted a non-exclusive, worldwide, non-transferable and royalty-free limited license under Alibaba Cloud's intellectual property or other rights owned by Us embodied in the Materials to use, reproduce, distribute, copy, create derivative works of, and make modifications to the Materials.
20
+
21
+ 3. Redistribution
22
+ You may reproduce and distribute copies of the Materials or derivative works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
23
+ a. You shall give any other recipients of the Materials or derivative works a copy of this Agreement;
24
+ b. You shall cause any modified files to carry prominent notices stating that You changed the files;
25
+ c. You shall retain in all copies of the Materials that You distribute the following attribution notices within a "Notice" text file distributed as a part of such copies: "Tongyi Qianwen is licensed under the Tongyi Qianwen LICENSE AGREEMENT, Copyright (c) Alibaba Cloud. All Rights Reserved."; and
26
+ d. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such derivative works as a whole, provided Your use, reproduction, and distribution of the work otherwise complies with the terms and conditions of this Agreement.
27
+
28
+ 4. Restrictions
29
+ If you are commercially using the Materials, and your product or service has more than 100 million monthly active users, You shall request a license from Us. You cannot exercise your rights under this Agreement without our express authorization.
30
+
31
+ 5. Rules of use
32
+ a. The Materials may be subject to export controls or restrictions in China, the United States or other countries or regions. You shall comply with applicable laws and regulations in your use of the Materials.
33
+ b. You can not use the Materials or any output therefrom to improve any other large language model (excluding Tongyi Qianwen or derivative works thereof).
34
+
35
+ 6. Intellectual Property
36
+ a. We retain ownership of all intellectual property rights in and to the Materials and derivatives made by or for Us. Conditioned upon compliance with the terms and conditions of this Agreement, with respect to any derivative works and modifications of the Materials that are made by you, you are and will be the owner of such derivative works and modifications.
37
+ b. No trademark license is granted to use the trade names, trademarks, service marks, or product names of Us, except as required to fulfill notice requirements under this Agreement or as required for reasonable and customary use in describing and redistributing the Materials.
38
+ c. If you commence a lawsuit or other proceedings (including a cross-claim or counterclaim in a lawsuit) against Us or any entity alleging that the Materials or any output therefrom, or any part of the foregoing, infringe any intellectual property or other right owned or licensable by you, then all licences granted to you under this Agreement shall terminate as of the date such lawsuit or other proceeding is commenced or brought.
39
+
40
+ 7. Disclaimer of Warranty and Limitation of Liability
41
+
42
+ a. We are not obligated to support, update, provide training for, or develop any further version of the Tongyi Qianwen Materials or to grant any license thereto.
43
+ b. THE MATERIALS ARE PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED WARRANTY OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT, OR FITNESS FOR A PARTICULAR PURPOSE. WE MAKE NO WARRANTY AND ASSUME NO RESPONSIBILITY FOR THE SAFETY OR STABILITY OF THE MATERIALS AND ANY OUTPUT THEREFROM.
44
+ c. IN NO EVENT SHALL WE BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE MATERIALS OR ANY OUTPUT OF IT, NO MATTER HOW IT’S CAUSED.
45
+ d. You will defend, indemnify and hold harmless Us from and against any claim by any third party arising out of or related to your use or distribution of the Materials.
46
+
47
+ 8. Survival and Termination.
48
+ a. The term of this Agreement shall commence upon your acceptance of this Agreement or access to the Materials and will continue in full force and effect until terminated in accordance with the terms and conditions herein.
49
+ b. We may terminate this Agreement if you breach any of the terms or conditions of this Agreement. Upon termination of this Agreement, you must delete and cease use of the Materials. Sections 7 and 9 shall survive the termination of this Agreement.
50
+
51
+ 9. Governing Law and Jurisdiction.
52
+ a. This Agreement and any dispute arising out of or relating to it will be governed by the laws of China, without regard to conflict of law principles, and the UN Convention on Contracts for the International Sale of Goods does not apply to this Agreement.
53
+ b. The People's Courts in Hangzhou City shall have exclusive jurisdiction over any dispute arising out of this Agreement.
Ovis/ovis.egg-info/PKG-INFO ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.1
2
+ Name: ovis
3
+ Version: 1.6.0
4
+ License-File: LICENSE
5
+ Requires-Dist: torch==2.4.0
6
+ Requires-Dist: transformers==4.46.2
7
+ Requires-Dist: tokenizers==0.20.3
8
+ Requires-Dist: sentencepiece==0.1.99
9
+ Requires-Dist: pyarrow==14.0.2
10
+ Requires-Dist: accelerate==1.1.0
11
+ Requires-Dist: pydantic==2.8.2
12
+ Requires-Dist: markdown2[all]
13
+ Requires-Dist: numpy==1.24.3
14
+ Requires-Dist: scikit-learn==1.2.2
15
+ Requires-Dist: requests
16
+ Requires-Dist: httpx
17
+ Requires-Dist: uvicorn
18
+ Requires-Dist: fastapi==0.112.4
19
+ Requires-Dist: einops==0.6.1
20
+ Requires-Dist: einops-exts==0.0.4
21
+ Requires-Dist: timm==0.6.13
22
+ Requires-Dist: tiktoken
23
+ Requires-Dist: transformers_stream_generator==0.0.4
24
+ Requires-Dist: scipy
25
+ Requires-Dist: pandas
26
+ Requires-Dist: torchaudio
27
+ Requires-Dist: xformers
28
+ Requires-Dist: pillow==10.3.0
29
+ Requires-Dist: deepspeed==0.15.4
30
+ Requires-Dist: gradio
Ovis/ovis.egg-info/SOURCES.txt ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ LICENSE
2
+ README.md
3
+ setup.py
4
+ ovis/__init__.py
5
+ ovis.egg-info/PKG-INFO
6
+ ovis.egg-info/SOURCES.txt
7
+ ovis.egg-info/dependency_links.txt
8
+ ovis.egg-info/requires.txt
9
+ ovis.egg-info/top_level.txt
10
+ ovis/model/__init__.py
11
+ ovis/model/configuration_ovis.py
12
+ ovis/model/conversation_formatter.py
13
+ ovis/model/modeling_ovis.py
14
+ ovis/train/__init__.py
15
+ ovis/train/arguments.py
16
+ ovis/train/callback.py
17
+ ovis/train/train.py
18
+ ovis/train/dataset/__init__.py
19
+ ovis/train/dataset/caption_dataset.py
20
+ ovis/train/dataset/conversation_dataset.py
21
+ ovis/train/dataset/multimodal_dataset.py
22
+ ovis/util/__init__.py
23
+ ovis/util/constants.py
24
+ ovis/util/utils.py
Ovis/ovis.egg-info/dependency_links.txt ADDED
@@ -0,0 +1 @@
 
 
1
+
Ovis/ovis.egg-info/requires.txt ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ torch==2.4.0
2
+ transformers==4.46.2
3
+ tokenizers==0.20.3
4
+ sentencepiece==0.1.99
5
+ pyarrow==14.0.2
6
+ accelerate==1.1.0
7
+ pydantic==2.8.2
8
+ markdown2[all]
9
+ numpy==1.24.3
10
+ scikit-learn==1.2.2
11
+ requests
12
+ httpx
13
+ uvicorn
14
+ fastapi==0.112.4
15
+ einops==0.6.1
16
+ einops-exts==0.0.4
17
+ timm==0.6.13
18
+ tiktoken
19
+ transformers_stream_generator==0.0.4
20
+ scipy
21
+ pandas
22
+ torchaudio
23
+ xformers
24
+ pillow==10.3.0
25
+ deepspeed==0.15.4
26
+ gradio
Ovis/ovis.egg-info/top_level.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ ovis
Ovis/ovis/__init__.py ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ import os
2
+
3
+ os.environ["TOKENIZERS_PARALLELISM"] = "false"
Ovis/ovis/model/__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ from .visual_tokenizer.clip_visual_tokenizer import ClipVisualTokenizerConfig, ClipVisualTokenizer
2
+ from .visual_tokenizer.siglip_visual_tokenizer import SiglipVisualTokenizerConfig, SiglipVisualTokenizer
Ovis/ovis/model/__pycache__/conversation_formatter.cpython-311.pyc ADDED
Binary file (12 kB). View file
 
Ovis/ovis/model/__pycache__/modeling_ovis.cpython-310.pyc ADDED
Binary file (14 kB). View file
 
Ovis/ovis/model/modeling_ovis.py ADDED
@@ -0,0 +1,434 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import os
3
+
4
+ from packaging import version
5
+ from datetime import datetime
6
+ from importlib import import_module
7
+ from typing import List, Union, Callable, Optional, Dict
8
+
9
+ import PIL.Image
10
+ import deepspeed
11
+ import torch
12
+ import transformers
13
+ from torch import Tensor
14
+ from torch.nn import init
15
+ from transformers import PreTrainedModel, AutoConfig, AutoModel, AutoTokenizer, AutoModelForCausalLM
16
+ from transformers.cache_utils import HybridCache
17
+ from transformers.generation.utils import GenerateOutput
18
+ from transformers.integrations.deepspeed import is_deepspeed_zero3_enabled, deepspeed_config
19
+
20
+ from ovis.model.configuration_ovis import OvisConfig
21
+ from ovis.model.conversation_formatter import ConversationFormatter
22
+ from ovis.util.constants import IGNORE_ID, BEGIN_LINE, END_LINE, IMAGE_ATOM_ID, IMAGE_INDICATOR_IDS, \
23
+ IMAGE_TOKEN_ID
24
+ from ovis.util.utils import rank0_print
25
+
26
+
27
+ class VisualEmbedding(torch.nn.Embedding):
28
+ def forward(self, visual_tokens: Tensor) -> Tensor:
29
+ if visual_tokens.dtype in [torch.int8, torch.int16, torch.int32, torch.int64, torch.long]:
30
+ return super().forward(visual_tokens)
31
+ return torch.matmul(visual_tokens, self.weight)
32
+
33
+ def reset_parameters(self, mean=0., std=1.) -> None:
34
+ init.normal_(self.weight, mean=mean, std=std)
35
+ self._fill_padding_idx_with_zero()
36
+
37
+
38
+ class OvisPreTrainedModel(PreTrainedModel):
39
+ config_class = OvisConfig
40
+ base_model_prefix = "ovis"
41
+
42
+
43
+ class Ovis(OvisPreTrainedModel):
44
+
45
+ def __init__(self, config: OvisConfig, *inputs, **kwargs):
46
+ super().__init__(config, *inputs, **kwargs)
47
+ if kwargs.get('train_from_scratch'):
48
+ self.llm = kwargs['llm']
49
+ self.generation_config = self.llm.generation_config
50
+ self.config.llm_config = self.llm.config
51
+ self.config.hidden_size = self.llm.config.hidden_size # for deepspeed auto configuration
52
+ self.text_tokenizer = kwargs['text_tokenizer']
53
+ self.visual_tokenizer = kwargs['visual_tokenizer']
54
+ self.config.visual_tokenizer_config = self.visual_tokenizer.config
55
+ else:
56
+ attn_kwargs = dict()
57
+ if self.config.llm_attn_implementation:
58
+ attn_kwargs['attn_implementation'] = self.config.llm_attn_implementation
59
+ self.llm = AutoModelForCausalLM.from_config(self.config.llm_config, **attn_kwargs)
60
+ assert self.config.hidden_size == self.llm.config.hidden_size, "hidden size mismatch"
61
+ self.text_tokenizer = AutoTokenizer.from_pretrained(self.config.name_or_path)
62
+ self.visual_tokenizer = AutoModel.from_config(self.config.visual_tokenizer_config,
63
+ image_processor_name_or_path=self.config.name_or_path)
64
+
65
+ # initialize vte
66
+ if is_deepspeed_zero3_enabled():
67
+ with deepspeed.zero.Init(config_dict_or_path=deepspeed_config()):
68
+ self.vte = VisualEmbedding(self.config.visual_tokenizer_config.vocab_size, self.config.hidden_size)
69
+ else:
70
+ self.vte = VisualEmbedding(self.config.visual_tokenizer_config.vocab_size, self.config.hidden_size,
71
+ device=self.visual_tokenizer.device, dtype=self.visual_tokenizer.dtype)
72
+
73
+ def _merge_modules(modules_list: tuple):
74
+ merged_modules = []
75
+ for modules in modules_list:
76
+ merged_modules.extend(modules if modules else [])
77
+ return merged_modules
78
+
79
+ self._no_split_modules = _merge_modules((self.llm._no_split_modules, self.visual_tokenizer._no_split_modules))
80
+ self._skip_keys_device_placement = self.llm._skip_keys_device_placement
81
+ self._keep_in_fp32_modules = _merge_modules(
82
+ (self.llm._keep_in_fp32_modules, self.visual_tokenizer._keep_in_fp32_modules))
83
+ self.is_parallelizable = all((self.llm.is_parallelizable, self.visual_tokenizer.is_parallelizable))
84
+ self.supports_gradient_checkpointing = all(
85
+ (self.llm.supports_gradient_checkpointing, self.visual_tokenizer.supports_gradient_checkpointing))
86
+ self._supports_flash_attn_2 = all(
87
+ (self.llm._supports_flash_attn_2, self.visual_tokenizer._supports_flash_attn_2))
88
+ self._supports_sdpa = all((self.llm._supports_sdpa, self.visual_tokenizer._supports_sdpa))
89
+
90
+ def get_text_tokenizer(self):
91
+ return self.text_tokenizer
92
+
93
+ def get_visual_tokenizer(self):
94
+ return self.visual_tokenizer
95
+
96
+ def tie_weights(self):
97
+ if not self.config.disable_tie_weight:
98
+ self.get_llm().tie_weights()
99
+
100
+ def re_init_vte(self, mean, std):
101
+ vte = self.get_vte()
102
+ rank0_print(BEGIN_LINE)
103
+ rank0_print(f'[{datetime.now()}] Before re-initialization of vte: ')
104
+ with deepspeed.zero.GatheredParameters([vte.weight]):
105
+ rank0_print(f'vte.weight: {vte.weight}')
106
+ with deepspeed.zero.GatheredParameters([vte.weight], modifier_rank=0):
107
+ if not is_deepspeed_zero3_enabled() or deepspeed.comm.get_rank() == 0:
108
+ vte.reset_parameters(mean, std)
109
+ rank0_print(f'[{datetime.now()}] After re-initialization of vte:')
110
+ with deepspeed.zero.GatheredParameters([vte.weight]):
111
+ rank0_print(f'vte.weight: {vte.weight}')
112
+ rank0_print(END_LINE)
113
+
114
+ def get_monitor_tensors(self):
115
+ monitor_tensors = dict(
116
+ wte=self.get_wte().weight,
117
+ lm_head=self.get_lm_head().weight,
118
+ vte=self.get_vte().weight
119
+ )
120
+ monitor_tensors.update(
121
+ {f'visual_tokenizer_{k}': v for k, v in self.get_visual_tokenizer().get_monitor_tensors().items()})
122
+ return monitor_tensors
123
+
124
+ def get_lm_head(self):
125
+ return self.get_llm().get_output_embeddings()
126
+
127
+ def get_llm(self):
128
+ return self.llm
129
+
130
+ def get_vte(self):
131
+ return self.vte
132
+
133
+ def get_wte(self):
134
+ return self.llm.get_input_embeddings()
135
+
136
+ def get_conversation_formatter(self) -> ConversationFormatter:
137
+ if getattr(self, 'conversation_formatter', None) is None:
138
+ self.conversation_formatter = getattr(import_module(".conversation_formatter", __package__),
139
+ self.config.conversation_formatter_class)(self.text_tokenizer)
140
+ return self.conversation_formatter
141
+
142
+ def forward(
143
+ self,
144
+ input_ids: torch.Tensor,
145
+ attention_mask: torch.Tensor,
146
+ labels: Optional[torch.Tensor],
147
+ pixel_values: List[Optional[torch.Tensor]],
148
+ **kwargs
149
+ ):
150
+ assert self.training, "`forward` can only be used in training. For inference, use `generate`."
151
+ _, inputs_embeds, labels, attention_mask = self.merge_multimodal(
152
+ text_input_ids=input_ids,
153
+ text_attention_masks=attention_mask,
154
+ text_labels=labels,
155
+ pixel_values=pixel_values
156
+ )
157
+ return self.llm(inputs_embeds=inputs_embeds, labels=labels, attention_mask=attention_mask, **kwargs)
158
+
159
+ def merge_multimodal(
160
+ self,
161
+ text_input_ids: torch.Tensor,
162
+ text_attention_masks: torch.Tensor,
163
+ text_labels: Optional[torch.Tensor],
164
+ pixel_values: List[Optional[torch.Tensor]]
165
+ ):
166
+ input_device = text_input_ids.device
167
+ visual_vocab_szie = self.get_visual_tokenizer().config.vocab_size
168
+ visual_indicator_embeds = self.get_vte()(
169
+ torch.tensor(
170
+ list(range(visual_vocab_szie - 5, visual_vocab_szie)),
171
+ dtype=torch.long,
172
+ device=self.get_visual_tokenizer().device
173
+ )
174
+ ).to(device=input_device)
175
+
176
+ if self.training:
177
+ # When training, to be compatible with deepspeed zero, each sample has to include pixel_value tensor.
178
+ # For text-only sample, one can simply use a full zero tensor as pixel_value, which will be ignored
179
+ # (see below in this function); so, the gradient will not be affected.
180
+ num_images = [x.shape[0] for x in pixel_values]
181
+ visual_tokens = self.visual_tokenizer(torch.cat([x for x in pixel_values], dim=0))
182
+ visual_embeds = torch.split(self.get_vte()(visual_tokens).to(dtype=self.dtype, device=input_device),
183
+ split_size_or_sections=num_images, dim=0)
184
+ visual_input_ids = torch.split(torch.argmax(visual_tokens, dim=-1).to(device=input_device),
185
+ split_size_or_sections=num_images, dim=0)
186
+ visual_labels = [torch.full(x.shape, IGNORE_ID, dtype=torch.long, device=input_device) for x in
187
+ visual_input_ids]
188
+ else:
189
+ # When inference, sample can include only text with `None` pixel_value
190
+ num_images = [x.shape[0] if x is not None else 0 for x in pixel_values]
191
+ if sum(num_images) > 0:
192
+ visual_tokens = self.visual_tokenizer(torch.cat([x for x in pixel_values if x is not None], dim=0))
193
+ visual_embeds = torch.split(self.get_vte()(visual_tokens).to(dtype=self.dtype, device=input_device),
194
+ split_size_or_sections=num_images, dim=0)
195
+ visual_input_ids = torch.split(torch.argmax(visual_tokens, dim=-1).to(device=input_device),
196
+ split_size_or_sections=num_images, dim=0)
197
+ visual_labels = [torch.full(x.shape, IGNORE_ID, dtype=torch.long, device=input_device) for x in
198
+ visual_input_ids]
199
+ else:
200
+ # just placeholders
201
+ visual_embeds = [None] * len(num_images)
202
+ visual_input_ids = [None] * len(num_images)
203
+ visual_labels = [None] * len(num_images)
204
+ # just placeholders
205
+ text_labels = torch.full(text_input_ids.shape, IGNORE_ID, dtype=torch.long, device=input_device)
206
+
207
+ input_embeds = []
208
+ attention_masks = []
209
+ labels = []
210
+ for text_input_id, text_label, text_attention_mask, visual_embed, visual_input_id, visual_label in zip(
211
+ text_input_ids, text_labels, text_attention_masks, visual_embeds, visual_input_ids, visual_labels
212
+ ):
213
+ placeholder_token_mask = torch.lt(text_input_id, 0)
214
+ text_embed = self.get_wte()(torch.masked_fill(text_input_id, placeholder_token_mask, 0))
215
+ for i, indicator_id in enumerate(IMAGE_INDICATOR_IDS):
216
+ text_embed[text_input_id == indicator_id] = visual_indicator_embeds[i]
217
+ image_atom_positions = torch.where(torch.eq(text_input_id, IMAGE_ATOM_ID))[0].tolist()
218
+ if len(image_atom_positions) > 0:
219
+ input_embed_parts = []
220
+ attention_mask_parts = []
221
+ label_parts = []
222
+ prev_image_atom_position = -1
223
+ for index, image_atom_position in enumerate(image_atom_positions):
224
+ input_embed_parts.append(
225
+ text_embed[prev_image_atom_position + 1:image_atom_position, :])
226
+ label_parts.append(
227
+ text_label[prev_image_atom_position + 1:image_atom_position])
228
+ attention_mask_parts.append(
229
+ text_attention_mask[prev_image_atom_position + 1:image_atom_position])
230
+ input_embed_parts.append(visual_embed[index])
231
+ attention_mask_parts.append(
232
+ torch.ones_like(visual_label[index], dtype=torch.bool))
233
+ label_parts.append(visual_label[index])
234
+ prev_image_atom_position = image_atom_position
235
+ if prev_image_atom_position + 1 < text_input_id.shape[0]:
236
+ input_embed_parts.append(
237
+ text_embed[prev_image_atom_position + 1:, :])
238
+ attention_mask_parts.append(
239
+ text_attention_mask[prev_image_atom_position + 1:])
240
+ label_parts.append(
241
+ text_label[prev_image_atom_position + 1:])
242
+ input_embed = torch.cat(input_embed_parts, dim=0)
243
+ attention_mask = torch.cat(attention_mask_parts, dim=0)
244
+ label = torch.cat(label_parts, dim=0)
245
+ else:
246
+ input_embed = text_embed
247
+ attention_mask = text_attention_mask
248
+ label = text_label
249
+ if self.training:
250
+ # Make visual_embed & visual_indicator_embeds involved in the backward graph,
251
+ # to be compatible with deepspeed zero and ddp.
252
+ input_embed += torch.sum(visual_embed * 0.0) + torch.sum(visual_indicator_embeds * 0.0)
253
+ input_embeds.append(input_embed)
254
+ attention_masks.append(attention_mask)
255
+ labels.append(label)
256
+
257
+ if self.training: # padding to self.config.multimodal_max_length for increased training speed
258
+ padding_size = max(0, self.config.multimodal_max_length - len(input_embeds[0]))
259
+ input_embeds[0] = torch.nn.ConstantPad2d((0, 0, 0, padding_size), 0.0)(input_embeds[0])
260
+ attention_masks[0] = torch.nn.ConstantPad1d((0, padding_size), False)(attention_masks[0])
261
+ labels[0] = torch.nn.ConstantPad1d((0, padding_size), IGNORE_ID)(labels[0])
262
+ batch_input_embeds = torch.nn.utils.rnn.pad_sequence(input_embeds, batch_first=True, padding_value=0.0)[:,
263
+ :self.config.multimodal_max_length, :]
264
+ batch_attention_mask = torch.nn.utils.rnn.pad_sequence(attention_masks, batch_first=True, padding_value=False)[
265
+ :,
266
+ :self.config.multimodal_max_length]
267
+ batch_labels = torch.nn.utils.rnn.pad_sequence(labels, batch_first=True, padding_value=IGNORE_ID)[:,
268
+ :self.config.multimodal_max_length]
269
+
270
+ return visual_input_ids, batch_input_embeds, batch_labels, batch_attention_mask
271
+
272
+ def preprocess_inputs(
273
+ self,
274
+ text_or_conversations: Union[List[Dict], str],
275
+ images: Optional[List[PIL.Image.Image]],
276
+ max_partition=9,
277
+ generation_preface='',
278
+ return_labels=False,
279
+ propagate_exception=True
280
+ ):
281
+ # convert text to conversations
282
+ if isinstance(text_or_conversations, str):
283
+ conversations = [{
284
+ "from": "human",
285
+ "value": text_or_conversations
286
+ }]
287
+ elif isinstance(text_or_conversations, list):
288
+ conversations = text_or_conversations
289
+ else:
290
+ raise ValueError(f'Invalid type of `text_or_conversations`, expected `List[Dict]` or `str`,'
291
+ f' but got {type(text_or_conversations)}')
292
+
293
+ # format conversations
294
+ prompt, raw_input_ids, raw_labels = self.get_conversation_formatter().format(
295
+ conversations, generation_preface=generation_preface)
296
+
297
+ # place image placeholders
298
+ input_ids = []
299
+ labels = []
300
+ pixel_values = []
301
+ invalidate_label = False
302
+ image_token_indices = [i for i, v in enumerate(raw_input_ids) if v == IMAGE_TOKEN_ID]
303
+ last_image_token_index = -1
304
+ for i in range(len(image_token_indices)):
305
+ head = 0 if i == 0 else image_token_indices[i - 1] + 1
306
+ tail = image_token_indices[i]
307
+ last_image_token_index = tail
308
+ input_ids.extend(raw_input_ids[head:tail])
309
+ labels.extend(raw_labels[head:tail])
310
+ try:
311
+ image = images[i]
312
+ raw_pixel_values, image_placeholders = self.visual_tokenizer.preprocess_image(
313
+ image, max_partition=max_partition)
314
+ except Exception as e:
315
+ if propagate_exception:
316
+ raise e
317
+ logging.exception(e)
318
+ invalidate_label = True
319
+ raw_pixel_values, image_placeholders = self.visual_tokenizer.mock_input()
320
+ input_ids.extend(image_placeholders)
321
+ labels.extend([IGNORE_ID] * len(image_placeholders))
322
+ pixel_values.append(raw_pixel_values)
323
+ input_ids.extend(raw_input_ids[last_image_token_index + 1:])
324
+ labels.extend(raw_labels[last_image_token_index + 1:])
325
+
326
+ # return tensors
327
+ input_ids = torch.tensor(input_ids, dtype=torch.long)
328
+ labels = torch.tensor([IGNORE_ID] * len(labels) if invalidate_label else labels, dtype=torch.long)
329
+ pixel_values = torch.cat(pixel_values, dim=0) if len(pixel_values) > 0 else None
330
+
331
+ if return_labels:
332
+ return prompt, input_ids, pixel_values, labels
333
+ else:
334
+ return prompt, input_ids, pixel_values
335
+
336
+ def save_pretrained(
337
+ self,
338
+ save_directory: Union[str, os.PathLike],
339
+ is_main_process: bool = True,
340
+ state_dict: Optional[dict] = None,
341
+ save_function: Callable = torch.save,
342
+ push_to_hub: bool = False,
343
+ max_shard_size: Union[int, str] = "5GB",
344
+ safe_serialization: bool = True,
345
+ variant: Optional[str] = None,
346
+ token: Optional[Union[str, bool]] = None,
347
+ save_peft_format: bool = True,
348
+ **kwargs
349
+ ):
350
+ super().save_pretrained(save_directory,
351
+ is_main_process=is_main_process,
352
+ state_dict=state_dict,
353
+ save_function=save_function,
354
+ safe_serialization=safe_serialization)
355
+ self.get_text_tokenizer().save_pretrained(save_directory)
356
+ self.get_visual_tokenizer().get_image_processor().save_pretrained(save_directory)
357
+
358
+ # uncomment the following will additionally save a separate visual tokenizer
359
+ # visual_tokenizer_directory = os.path.join(save_directory, 'visual_tokenizer')
360
+ # self.get_visual_tokenizer().save_pretrained(visual_tokenizer_directory,
361
+ # is_main_process=is_main_process,
362
+ # state_dict=None,
363
+ # save_function=save_function,
364
+ # safe_serialization=safe_serialization)
365
+ # self.get_visual_tokenizer().get_image_processor().save_pretrained(visual_tokenizer_directory)
366
+
367
+ def _get_hybrid_cache_for_llm(self, batch_size: int, max_cache_len: int):
368
+ cache_cls = HybridCache
369
+ llm = self.get_llm()
370
+
371
+ if version.parse(transformers.__version__) >= version.parse("4.46.0"):
372
+ need_new_cache = (
373
+ not hasattr(llm, "_cache")
374
+ or (not isinstance(llm._cache, cache_cls))
375
+ or llm._cache.batch_size != batch_size
376
+ or llm._cache.max_cache_len < max_cache_len
377
+ )
378
+ else:
379
+ need_new_cache = (
380
+ not hasattr(llm, "_cache")
381
+ or (not isinstance(llm._cache, cache_cls))
382
+ or llm._cache.max_batch_size != batch_size
383
+ or llm._cache.max_cache_len < max_cache_len
384
+ )
385
+
386
+ if need_new_cache:
387
+ if hasattr(llm.config, "_pre_quantization_dtype"):
388
+ cache_dtype = llm.config._pre_quantization_dtype
389
+ else:
390
+ cache_dtype = llm.dtype
391
+ if version.parse(transformers.__version__) >= version.parse("4.46.0"):
392
+ llm._cache = cache_cls(
393
+ config=llm.config,
394
+ batch_size=batch_size,
395
+ max_cache_len=max_cache_len,
396
+ device=llm.device,
397
+ dtype=cache_dtype,
398
+ )
399
+ else:
400
+ llm._cache = cache_cls(
401
+ config=llm.config,
402
+ max_batch_size=batch_size,
403
+ max_cache_len=max_cache_len,
404
+ device=llm.device,
405
+ dtype=cache_dtype,
406
+ )
407
+ else:
408
+ llm._cache.reset()
409
+ return llm._cache
410
+
411
+ # TODO: support batch generation
412
+ def generate(
413
+ self,
414
+ inputs: Optional[torch.Tensor] = None,
415
+ **kwargs
416
+ ) -> Union[GenerateOutput, torch.LongTensor]:
417
+ assert inputs.shape[0] == 1, 'Currently, only support `batch_size=1`'
418
+ _, inputs_embeds, labels, attention_mask = self.merge_multimodal(
419
+ text_input_ids=inputs,
420
+ text_attention_masks=kwargs.pop('attention_mask'),
421
+ text_labels=None,
422
+ pixel_values=kwargs.pop('pixel_values')
423
+ )
424
+ if getattr(self.generation_config, 'cache_implementation') == 'hybrid': # mainly for Gemma2
425
+ kwargs['past_key_values'] = self._get_hybrid_cache_for_llm(
426
+ getattr(kwargs, "num_beams", 1), kwargs['max_new_tokens'] + inputs_embeds.shape[-2])
427
+ self.get_llm()._supports_cache_class = True
428
+ kwargs['cache_implementation'] = None
429
+
430
+ return self.llm.generate(inputs=None, inputs_embeds=inputs_embeds, attention_mask=attention_mask, **kwargs)
431
+
432
+
433
+ AutoConfig.register("ovis", OvisConfig)
434
+ AutoModelForCausalLM.register(OvisConfig, Ovis)
Ovis/ovis/model/visual_tokenizer/base_visual_tokenizer.py ADDED
@@ -0,0 +1,264 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Union, Optional
2
+
3
+ import PIL.Image
4
+ import torch
5
+ from torch.nn.functional import softmax, gumbel_softmax, pad
6
+ from transformers import PretrainedConfig, PreTrainedModel, AutoImageProcessor, AutoModel, AutoConfig
7
+ from ovis.util.constants import IMAGE_INDICATOR_IDS, IMAGE_ATOM_ID
8
+
9
+
10
+ class BaseVisualTokenizerConfig(PretrainedConfig):
11
+ def __init__(
12
+ self,
13
+ vocab_size=16384,
14
+ tokenize_function="softmax",
15
+ tau=1.0,
16
+ depths=None,
17
+ drop_cls_token=False,
18
+ backbone_config: Optional[Union[PretrainedConfig, dict]] = None,
19
+ hidden_stride: int = 1,
20
+ **kwargs
21
+ ):
22
+ super().__init__(**kwargs)
23
+ self.vocab_size = vocab_size
24
+ self.tokenize_function = tokenize_function
25
+ self.tau = tau
26
+ if isinstance(depths, str):
27
+ depths = [int(x) for x in depths.split('|')]
28
+ self.depths = depths
29
+ self.backbone_kwargs = {}
30
+ self.drop_cls_token = drop_cls_token
31
+ if backbone_config is not None:
32
+ assert isinstance(backbone_config, (PretrainedConfig, dict)), \
33
+ f"expect `backbone_config` to be instance of PretrainedConfig or dict, but got {type(backbone_config)} type"
34
+ if not isinstance(backbone_config, PretrainedConfig):
35
+ model_type = backbone_config['model_type']
36
+ backbone_config.pop('model_type')
37
+ backbone_config = AutoConfig.for_model(model_type, **backbone_config)
38
+ self.backbone_config = backbone_config
39
+ self.hidden_stride = hidden_stride
40
+
41
+
42
+ class BaseVisualTokenizer(PreTrainedModel):
43
+ base_model_prefix = "backbone"
44
+ main_input_name = None
45
+ _image_processor_class = None
46
+ _image_processor_kwargs = {}
47
+ _backbone_class = None
48
+ _backbone_name_or_path = None
49
+
50
+ def __init__(self, config: BaseVisualTokenizerConfig, *inputs, **kwargs):
51
+ super().__init__(config, *inputs, **kwargs)
52
+ if kwargs.get('train_from_scratch'):
53
+ self.image_processor = self._image_processor_class.from_pretrained(self._backbone_name_or_path,
54
+ **self._image_processor_kwargs)
55
+ self.backbone = self._backbone_class.from_pretrained(self._backbone_name_or_path,
56
+ **self.config.backbone_kwargs)
57
+ self.config.backbone_config = self.backbone.config
58
+ else:
59
+ self.image_processor = AutoImageProcessor.from_pretrained(kwargs['image_processor_name_or_path'])
60
+ self.backbone = AutoModel.from_config(self.config.backbone_config)
61
+ head_dim = self.config.vocab_size - len(IMAGE_INDICATOR_IDS) # reserved tokens for IMAGE_INDICATORS
62
+ self.head = torch.nn.Sequential(
63
+ torch.nn.Linear(
64
+ self.backbone.config.hidden_size * self.config.hidden_stride * self.config.hidden_stride, head_dim,
65
+ bias=False
66
+ ),
67
+ torch.nn.LayerNorm(head_dim)
68
+ )
69
+
70
+ assert all((self.image_processor.do_resize,
71
+ not getattr(self.image_processor, 'do_center_crop', False),
72
+ self.image_processor.do_rescale,
73
+ self.image_processor.do_normalize
74
+ )), f"image_processor `{self.image_processor}` is not supported currently"
75
+
76
+ def get_backbone(self):
77
+ return self.backbone
78
+
79
+ def get_monitor_tensors(self):
80
+ raise NotImplementedError
81
+
82
+ def get_image_processor(self):
83
+ return self.image_processor
84
+
85
+ def mock_input(self):
86
+ height, width = self.get_image_size()
87
+ return torch.zeros(1, 3, height, width), self.construct_image_placeholders((1, 1))
88
+
89
+ def get_head(self):
90
+ return self.head
91
+
92
+ def get_image_size(self):
93
+ raise NotImplementedError
94
+
95
+ @staticmethod
96
+ def construct_image_placeholders(grid):
97
+ image_placeholders = [IMAGE_INDICATOR_IDS[0], IMAGE_ATOM_ID, IMAGE_INDICATOR_IDS[1]]
98
+ if grid[0] * grid[1] > 1:
99
+ for r in range(grid[0]):
100
+ for c in range(grid[1]):
101
+ image_placeholders.append(IMAGE_ATOM_ID)
102
+ if c < grid[1] - 1:
103
+ image_placeholders.append(IMAGE_INDICATOR_IDS[2])
104
+ if r < grid[0] - 1:
105
+ image_placeholders.append(IMAGE_INDICATOR_IDS[3])
106
+ image_placeholders.append(IMAGE_INDICATOR_IDS[4])
107
+ return image_placeholders
108
+
109
+ def preprocess_image(self, image: PIL.Image.Image, max_partition=9, covering_threshold=0.9, convert_to_rgb=True):
110
+ def _preprocess(img: PIL.Image.Image, side):
111
+ # first resize and preprocess
112
+ w, h = img.size
113
+ if w == h:
114
+ new_width = new_height = side
115
+ elif w > h:
116
+ new_width = side
117
+ new_height = int(h / w * new_width)
118
+ else:
119
+ new_height = side
120
+ new_width = int(w / h * new_height)
121
+ new_size = dict(height=new_height, width=new_width)
122
+ pixel_values = self.image_processor.preprocess(img, size=new_size, return_tensors='pt')['pixel_values']
123
+
124
+ # then pad to square
125
+ square_values = torch.zeros([1, 3, side, side], dtype=pixel_values.dtype, device=pixel_values.device)
126
+ new_height, new_width = pixel_values.shape[2:]
127
+ if new_height == new_width:
128
+ square_values[:, :, :, :] = pixel_values
129
+ elif new_height > new_width:
130
+ from_index = (side - new_width) // 2
131
+ square_values[:, :, :, from_index:from_index + new_width] = pixel_values
132
+ else:
133
+ from_index = (side - new_height) // 2
134
+ square_values[:, :, from_index:from_index + new_height, :] = pixel_values
135
+
136
+ return square_values
137
+
138
+ def _partition(img, grid):
139
+ w, h = img.size
140
+ row_height = h // grid[0]
141
+ col_width = w // grid[1]
142
+
143
+ partition = []
144
+ for row in range(grid[0]):
145
+ for col in range(grid[1]):
146
+ left = col * col_width
147
+ upper = row * row_height
148
+ right = w if col == grid[1] - 1 else (col + 1) * col_width
149
+ lower = h if row == grid[0] - 1 else (row + 1) * row_height
150
+ partition.append((left, upper, right, lower))
151
+
152
+ return partition
153
+
154
+ def _covering_area(left, upper, right, lower, side):
155
+ w = right - left
156
+ h = lower - upper
157
+ w, h = max(w, h), min(w, h)
158
+ if w > side:
159
+ h = h / w * side
160
+ w = side
161
+ return w * h
162
+
163
+ def _get_best_grid(img, side):
164
+ img_area = img.size[0] * img.size[1]
165
+
166
+ candidate_grids = []
167
+ for i in range(1, max_partition + 1):
168
+ for j in range(1, max_partition + 1):
169
+ if i * j <= max_partition:
170
+ candidate_grids.append((i, j))
171
+
172
+ all_grids = []
173
+ good_grids = []
174
+ for grid in candidate_grids:
175
+ partition = _partition(img, grid)
176
+ covering_ratio = sum([_covering_area(*p, side) for p in partition]) / img_area
177
+ assert covering_ratio <= 1.0
178
+ all_grids.append((grid, covering_ratio))
179
+ if covering_ratio > covering_threshold:
180
+ good_grids.append((grid, covering_ratio))
181
+
182
+ if len(good_grids) > 0:
183
+ # pick the good partition with minimum #sub_images and break the tie using covering_ratio
184
+ return sorted(good_grids, key=lambda x: (x[0][0] * x[0][1], -x[1]))[0][0]
185
+ else:
186
+ # pick the partition with maximum covering_ratio and break the tie using #sub_images
187
+ return sorted(all_grids, key=lambda x: (-x[1], x[0][0] * x[0][1]))[0][0]
188
+
189
+ if convert_to_rgb and image.mode != 'RGB':
190
+ image = image.convert('RGB')
191
+
192
+ sides = self.get_image_size()
193
+ if sides[0] != sides[1]:
194
+ raise ValueError('get_image_size() returns non-square size')
195
+ side = sides[0]
196
+ grid = _get_best_grid(image, side)
197
+ partition = _partition(image, grid)
198
+ crops = [image.crop(p) for p in partition]
199
+ if len(crops) > 1:
200
+ crops.insert(0, image)
201
+ pixel_values = torch.cat([_preprocess(crop, side) for crop in crops], dim=0)
202
+ image_placeholders = self.construct_image_placeholders(grid)
203
+ return pixel_values, image_placeholders
204
+
205
+ def get_backbone_layer(self, index):
206
+ return self.backbone.vision_model.encoder.layers[index]
207
+
208
+ def tokenize(self, logits):
209
+ def st_argmax(y_soft, dim): # straight-through softmax
210
+ index = y_soft.max(dim, keepdim=True)[1]
211
+ y_hard = torch.zeros_like(y_soft, memory_format=torch.legacy_contiguous_format).scatter_(dim, index, 1.0)
212
+ ret = y_hard - y_soft.detach() + y_soft
213
+ return ret
214
+
215
+ if self.config.tokenize_function == 'softmax':
216
+ tokens = softmax(logits, dim=-1)
217
+ elif self.config.tokenize_function == 'gumbel_argmax':
218
+ tokens = gumbel_softmax(logits, tau=self.config.tau, hard=True)
219
+ elif self.config.tokenize_function == 'st_argmax':
220
+ tokens = st_argmax(logits, dim=-1)
221
+ else:
222
+ raise ValueError(
223
+ f'Invalid `max_type`, expected softmax or gumbel_argmax or st_argmax, but got {self.config.tokenize_function}')
224
+ return tokens
225
+
226
+ def encode(self, pixel_values):
227
+ output = self.backbone(pixel_values, output_hidden_states=True, return_dict=True)
228
+ features = output.hidden_states[-1]
229
+ if self.config.drop_cls_token:
230
+ features = features[:, 1:, :]
231
+
232
+ # merge number of `hidden_stride * hidden_stride` hidden states together to reduce token sequence length
233
+ # e.g., for hidden_stride=3, this leads to a token length reduction: 729 -> 81 for siglip
234
+ if self.config.hidden_stride > 1:
235
+ n, l, d = features.shape # this `d` maybe different from the above `d
236
+ sqrt_l = int(l ** 0.5)
237
+ assert sqrt_l ** 2 == l, "The token sequence length should be a perfect square."
238
+ features = features.reshape(n, sqrt_l, sqrt_l, d)
239
+ pl = (self.config.hidden_stride - (sqrt_l % self.config.hidden_stride)) % self.config.hidden_stride
240
+ features = pad(features, (0, 0, 0, pl, 0, pl), "constant", 0)
241
+ sqrt_l += pl
242
+ features = features.reshape(n, sqrt_l // self.config.hidden_stride, self.config.hidden_stride,
243
+ sqrt_l // self.config.hidden_stride, self.config.hidden_stride, d)
244
+ features = features.permute(0, 1, 3, 2, 4, 5) # [n, sqrt_l/hs, sqrt_l/hs, hs, hs, d]
245
+ features = features.flatten(3) # [n, sqrt_l/hs, sqrt_l/hs, hs*hs*d]
246
+ features = features.reshape(
247
+ n, -1, self.config.hidden_stride * self.config.hidden_stride * d)
248
+
249
+ return features
250
+
251
+ def forward(self, pixel_values) -> torch.Tensor: # [BatchSize, ImageShape] -> [BatchSize, #Token, VocabSize]
252
+ features = self.encode(pixel_values)
253
+ logits = self.head(features)
254
+ tokens = self.tokenize(logits)
255
+ # tokens' shape is [BatchSize, #Token, VocabSize-5], so padding with [BatchSize, #Token, 5], after
256
+ # which, tokens' shape should become [BatchSize, #Token, VocabSize]
257
+ batch_size, token_len, _ = tokens.shape
258
+ padding_tensor = torch.zeros(size=(batch_size, token_len, len(IMAGE_INDICATOR_IDS)),
259
+ dtype=tokens.dtype,
260
+ device=tokens.device,
261
+ layout=tokens.layout,
262
+ requires_grad=False)
263
+ tokens = torch.cat((tokens, padding_tensor), dim=2)
264
+ return tokens
Ovis/ovis/model/visual_tokenizer/clip_visual_tokenizer.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from transformers import AutoConfig, AutoModel
2
+ from transformers import CLIPVisionModel, CLIPImageProcessor
3
+ from .base_visual_tokenizer import BaseVisualTokenizerConfig, BaseVisualTokenizer
4
+
5
+ MODEL_TYPE = "clip_visual_tokenizer"
6
+
7
+
8
+ class ClipVisualTokenizerConfig(BaseVisualTokenizerConfig):
9
+ model_type = MODEL_TYPE
10
+
11
+ def __init__(self, **kwargs):
12
+ super().__init__(**kwargs)
13
+ if self.depths:
14
+ assert len(self.depths) == 1
15
+ self.backbone_kwargs['num_hidden_layers'] = self.depths[0]
16
+
17
+
18
+ class ClipVisualTokenizer(BaseVisualTokenizer):
19
+ config_class = ClipVisualTokenizerConfig
20
+ supports_gradient_checkpointing = True
21
+ _no_split_modules = ["CLIPEncoderLayer"]
22
+ _image_processor_class = CLIPImageProcessor
23
+ _image_processor_kwargs = dict(do_center_crop=False)
24
+ _backbone_class = CLIPVisionModel
25
+ _backbone_name_or_path = "openai/clip-vit-large-patch14-336"
26
+
27
+ def get_monitor_tensors(self):
28
+ return dict(
29
+ backbone_bottom=self.backbone.vision_model.encoder.layers[0].self_attn.k_proj.weight,
30
+ backbone_top=self.backbone.vision_model.encoder.layers[-1].self_attn.out_proj.weight,
31
+ head=self.head[0].weight
32
+ )
33
+
34
+ def get_image_size(self):
35
+ height = self.image_processor.crop_size["height"]
36
+ width = self.image_processor.crop_size["width"]
37
+ return height, width
38
+
39
+
40
+ AutoConfig.register(MODEL_TYPE, ClipVisualTokenizerConfig)
41
+ AutoModel.register(ClipVisualTokenizerConfig, ClipVisualTokenizer)
Ovis/ovis/model/visual_tokenizer/siglip_visual_tokenizer.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from transformers import AutoConfig, AutoModel
2
+ from transformers import SiglipVisionModel, SiglipImageProcessor
3
+ from .base_visual_tokenizer import BaseVisualTokenizerConfig, BaseVisualTokenizer
4
+
5
+ MODEL_TYPE = "siglip_visual_tokenizer"
6
+
7
+
8
+ class SiglipVisualTokenizerConfig(BaseVisualTokenizerConfig):
9
+ model_type = MODEL_TYPE
10
+
11
+ def __init__(self, **kwargs):
12
+ super().__init__(**kwargs)
13
+ if self.drop_cls_token:
14
+ self.drop_cls_token = False
15
+ if self.depths:
16
+ assert len(self.depths) == 1
17
+ self.backbone_kwargs['num_hidden_layers'] = self.depths[0]
18
+
19
+
20
+ class SiglipVisualTokenizer(BaseVisualTokenizer):
21
+ config_class = SiglipVisualTokenizerConfig
22
+ supports_gradient_checkpointing = True
23
+ _no_split_modules = ["SiglipVisionTransformer"]
24
+ _image_processor_class = SiglipImageProcessor
25
+ _image_processor_kwargs = {}
26
+ _backbone_class = SiglipVisionModel
27
+ _backbone_name_or_path = "google/siglip-so400m-patch14-384"
28
+
29
+ def get_monitor_tensors(self):
30
+ return dict(
31
+ backbone_bottom=self.backbone.vision_model.encoder.layers[0].self_attn.k_proj.weight,
32
+ backbone_top=self.backbone.vision_model.encoder.layers[-1].self_attn.out_proj.weight,
33
+ head=self.head[0].weight
34
+ )
35
+
36
+ def get_image_size(self):
37
+ height = self.image_processor.size["height"]
38
+ width = self.image_processor.size["width"]
39
+ return height, width
40
+
41
+
42
+ AutoConfig.register(MODEL_TYPE, SiglipVisualTokenizerConfig)
43
+ AutoModel.register(SiglipVisualTokenizerConfig, SiglipVisualTokenizer)
Ovis/ovis/serve/__pycache__/runner.cpython-310.pyc ADDED
Binary file (3.45 kB). View file
 
Ovis/ovis/serve/__pycache__/runner.cpython-311.pyc ADDED
Binary file (6.61 kB). View file
 
Ovis/ovis/train/dataset/__init__.py ADDED
File without changes
Ovis/ovis/train/dataset/caption_dataset.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ from datetime import datetime
3
+ from typing import Dict
4
+
5
+ import pandas
6
+ import torch
7
+
8
+ from ovis.train.dataset.multimodal_dataset import MultimodalDataset
9
+ from ovis.util.constants import IMAGE_TOKEN, IGNORE_ID
10
+ from ovis.util.utils import rank0_print
11
+
12
+
13
+ class CaptionDataset(MultimodalDataset):
14
+
15
+ def load(self):
16
+ rank0_print(f"[{datetime.now()}] Loading dataset {self.name} from {self.meta_file} begin")
17
+ samples = pandas.read_parquet(self.meta_file, engine='pyarrow')
18
+ rank0_print(f"[{datetime.now()}] Loading dataset {self.name} end")
19
+ return samples
20
+
21
+ def __getitem__(self, i: int) -> Dict[str, torch.Tensor]:
22
+ sample = self.samples.iloc[i]
23
+ text = sample['caption']
24
+ image_path = sample['image_path']
25
+
26
+ # read and preprocess image
27
+ pixel_values, image_placeholders = self.visual_tokenizer.mock_input()
28
+ valid_image = False
29
+ image, e = self.read_image(image_path)
30
+ if image is None:
31
+ logging.warning(
32
+ f'reading image failed with index: {i}, image path: {image_path}, and exception: {e}')
33
+ else:
34
+ try:
35
+ pixel_values, image_placeholders = self.visual_tokenizer.preprocess_image(
36
+ image, max_partition=self.max_partitions[0])
37
+ valid_image = True
38
+ except Exception as e:
39
+ logging.warning(
40
+ f'preprocessing image failed with index: {i}, image path: {image_path}, and exception: {e}')
41
+
42
+ # preprocess text
43
+ if text is None:
44
+ logging.warning(f'text is `None`, index: {i}')
45
+ text = ""
46
+ if not valid_image:
47
+ logging.warning(f'image is not valid, so set text as empty, index: {i}, image path: {image_path}')
48
+ text = ""
49
+ text = text.replace(IMAGE_TOKEN, '').strip()
50
+ head, tail = self.caption_template.split(IMAGE_TOKEN)
51
+ head_ids = self.text_tokenizer(head, add_special_tokens=False).input_ids
52
+ tail_ids = self.text_tokenizer(tail, add_special_tokens=False).input_ids
53
+ text_ids = self.text_tokenizer(text, add_special_tokens=False).input_ids
54
+ input_ids = head_ids + image_placeholders + tail_ids + text_ids
55
+ labels = [IGNORE_ID] * (len(input_ids) - len(text_ids)) + text_ids
56
+
57
+ input_ids = input_ids[:self.text_max_length]
58
+ labels = labels[:self.text_max_length]
59
+
60
+ input_ids = torch.tensor(input_ids, dtype=torch.long)
61
+ labels = torch.tensor(labels, dtype=torch.long)
62
+
63
+ return dict(
64
+ pixel_values=pixel_values,
65
+ input_ids=input_ids,
66
+ labels=labels
67
+ )
Ovis/ovis/train/dataset/conversation_dataset.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import copy
2
+ import json
3
+ import logging
4
+ from datetime import datetime
5
+ from typing import Dict
6
+
7
+ import torch
8
+
9
+ from ovis.train.dataset.multimodal_dataset import MultimodalDataset
10
+ from ovis.util.utils import rank0_print
11
+
12
+
13
+ class ConversationDataset(MultimodalDataset):
14
+ def load(self):
15
+ rank0_print(f"[{datetime.now()}] Loading dataset {self.name} from {self.meta_file} begin")
16
+ with open(self.meta_file, 'r', encoding='utf-8') as f:
17
+ samples = json.load(f)
18
+ rank0_print(f'#samples: {len(samples)}')
19
+ rank0_print(f'sample: {samples[0]}')
20
+ rank0_print(f"[{datetime.now()}] Loading dataset {self.name} end")
21
+ return samples
22
+
23
+ def __getitem__(self, i: int) -> Dict[str, torch.Tensor]:
24
+ sample = self.samples[i]
25
+ conversations = copy.deepcopy(sample["conversations"])
26
+
27
+ images = None
28
+ max_partition = None
29
+ if 'image' in sample:
30
+ image_paths = sample['image']
31
+ if isinstance(image_paths, str):
32
+ image_paths = [image_paths]
33
+ images = []
34
+ for image_path in image_paths:
35
+ image, e = self.read_image(image_path)
36
+ if image is None:
37
+ logging.warning(
38
+ f'reading image failed with index: {i}, image path: {image_path}, and exception: {e}')
39
+ images = None
40
+ break
41
+ images.append(image)
42
+ elif 'video' in sample:
43
+ raise RuntimeError('video is to be supported')
44
+
45
+ if images:
46
+ max_partition = self.max_partitions[0] if len(images) == 1 else self.max_partitions[1]
47
+
48
+ prompt, input_ids, pixel_values, labels = self.model.preprocess_inputs(
49
+ conversations,
50
+ images,
51
+ max_partition=max_partition,
52
+ generation_preface=None,
53
+ return_labels=True,
54
+ propagate_exception=False
55
+ )
56
+
57
+ if pixel_values is None:
58
+ pixel_values, _ = self.visual_tokenizer.mock_input()
59
+
60
+ input_ids = input_ids[:self.text_max_length]
61
+ labels = labels[:self.text_max_length]
62
+
63
+ return dict(
64
+ pixel_values=pixel_values,
65
+ input_ids=input_ids,
66
+ labels=labels
67
+ )
Ovis/ovis/train/dataset/multimodal_dataset.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import os
3
+ from typing import Dict, Sequence, Union, List
4
+
5
+ import torch
6
+ from PIL import Image
7
+ from torch.utils.data import Dataset
8
+ from transformers import PreTrainedTokenizer
9
+
10
+ from ovis.model.modeling_ovis import Ovis
11
+ from ovis.train.arguments import TrainingArguments
12
+ from ovis.util.constants import IGNORE_ID
13
+
14
+
15
+ class MultimodalDataset(Dataset):
16
+ def __init__(self, name: str, info: Dict, model: Ovis, training_args: TrainingArguments):
17
+ self.name = name
18
+ self.meta_file = info['meta_file']
19
+ self.image_dir = info['image_dir']
20
+ self.caption_template = info.get('caption_template', None)
21
+ self.text_tokenizer = model.get_text_tokenizer()
22
+ self.visual_tokenizer = model.get_visual_tokenizer()
23
+ self.image_height, self.image_width = self.visual_tokenizer.get_image_size()
24
+ self.model = model
25
+ self.text_max_length = training_args.text_max_length
26
+ self.max_partitions = [int(m.strip()) for m in training_args.max_partitions.split('|')]
27
+ self.samples = self.load()
28
+
29
+ def load(self):
30
+ raise NotImplementedError
31
+
32
+ def __getitem__(self, i: int) -> Dict[str, torch.Tensor]:
33
+ raise NotImplementedError
34
+
35
+ def __len__(self):
36
+ return len(self.samples)
37
+
38
+ def read_image(self, path):
39
+ try:
40
+ full_path = os.path.join(self.image_dir, path)
41
+ image = Image.open(full_path).convert('RGB')
42
+ return image, None
43
+ except Exception as e:
44
+ return None, e
45
+
46
+
47
+ class DataCollatorForMultimodalDataset:
48
+ def __init__(self, text_tokenizer: PreTrainedTokenizer):
49
+ self.text_tokenizer = text_tokenizer
50
+
51
+ def __call__(self, instances: Sequence[Dict]) -> Dict[str, Union[torch.Tensor, List[torch.Tensor]]]:
52
+ pixel_values, input_ids, labels = tuple([instance[key] for instance in instances]
53
+ for key in ("pixel_values", "input_ids", "labels"))
54
+ input_ids = torch.nn.utils.rnn.pad_sequence(
55
+ input_ids,
56
+ batch_first=True,
57
+ padding_value=self.text_tokenizer.pad_token_id)
58
+ attention_mask = torch.ne(input_ids, self.text_tokenizer.pad_token_id)
59
+ labels = torch.nn.utils.rnn.pad_sequence(
60
+ labels,
61
+ batch_first=True,
62
+ padding_value=IGNORE_ID)
63
+ num_valid_label = torch.not_equal(labels, IGNORE_ID).sum().item()
64
+ if num_valid_label == 0:
65
+ logging.warning(
66
+ f'[DataCollatorForMultimodalDataset] All labels in a batch are ignored, which may lead to training instability\n{input_ids=}\n{attention_mask=}\n{labels=}')
67
+ return dict(
68
+ input_ids=input_ids,
69
+ attention_mask=attention_mask,
70
+ labels=labels,
71
+ pixel_values=pixel_values
72
+ )
Ovis/ovis/util/__init__.py ADDED
File without changes
Ovis/ovis/util/__pycache__/__init__.cpython-310.pyc ADDED
Binary file (145 Bytes). View file
 
Ovis/ovis/util/__pycache__/__init__.cpython-311.pyc ADDED
Binary file (161 Bytes). View file
 
Ovis/ovis/util/__pycache__/constants.cpython-310.pyc ADDED
Binary file (460 Bytes). View file
 
Ovis/ovis/util/__pycache__/constants.cpython-311.pyc ADDED
Binary file (503 Bytes). View file
 
Ovis/ovis/util/__pycache__/utils.cpython-311.pyc ADDED
Binary file (1.28 kB). View file
 
VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/.ipynb_checkpoints/Qwen2-VL-2B-Instruct_DSPAR_MINI_6345-checkpoint.json ADDED
@@ -0,0 +1 @@
 
 
1
+ "Bức tranh này mô tả một người đàn ông đang đứng trên đường phố. Anh ấy đang nhìn xuống phía dưới, có vẻ như đang tập trung vào một vật gì đó. Anh ấy đang mặc một chiếc áo khoác màu xanh, quần jeans và giày sneaker trắng. Anh ấy có vẻ như đang ở trong một khu vực có nhiều cây xanh."
VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6275.json ADDED
@@ -0,0 +1 @@
 
 
1
+ "Bức tranh này mô tả một người đàn ông đang đi bộ trên đường. Anh ấy đang đeo một chiếc khẩu trang y tế màu xanh lá cây và đang cầm một chiếc túi xách. Anh ấy có một chiếc đồng hồ đeo tay và một chiếc áo khoác ngắn. Anh ấy đang đi trên một con đường xanh."
VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6278.json ADDED
@@ -0,0 +1 @@
 
 
1
+ "Bức tranh này mô tả một người đàn ông đang đi bộ trên đường. Anh ấy có một chiếc túi xách trên vai và đang đeo một chiếc kính. Anh ấy có một chiếc quần jeans và đôi giày. Anh ấy có một vẻ mặt buồn bã và đang cố gắng giữ cho mình không rơi vào tầm tay của người khác."
VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6385.json ADDED
@@ -0,0 +1 @@
 
 
1
+ "Bức tranh này mô tả một người đi bộ trên đường. Người này có một chiếc mũ đen và một chiếc khẩu trang màu đỏ. Người này đang đi bộ trên một con đường xanh."
VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6481.json ADDED
@@ -0,0 +1 @@
 
 
1
+ "Bức ảnh này mô tả một người đàn ông đang đi bộ trên đường. Anh ấy có mái tóc ngắn, mặc áo hoodie màu xanh nhạt và quần áo thể thao. Anh ấy đang đeo một chiếc túi xách trên vai."
VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6500.json ADDED
@@ -0,0 +1 @@
 
 
1
+ "Bức tranh này mô tả một người đàn ông đang đi bộ trên đường. Anh ấy có một chiếc áo khoác màu xanh, quần đen và giày trắng. Anh ấy có vẻ như đang đi bộ trên một con đường màu xám."
VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6513.json ADDED
@@ -0,0 +1 @@
 
 
1
+ "Bức tranh này mô tả một người đi bộ trên đường phố. Người này đang mặc một bộ đồ màu xanh, có một chiếc túi xách trên vai."
VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6515.json ADDED
@@ -0,0 +1 @@
 
 
1
+ "Bức tranh này mô tả một người phụ nữ đang đứng trên đường phố. Cô ấy đang mặc một chiếc áo thun màu hồng và quần short. Cô ấy có hai chân và hai tay. Cô ấy đang nhìn về phía trước và có vẻ như đang ngắm nhìn hoặc nhìn vào một thứ gì đó. Cô ấy có hai đôi giày màu đen. Bức tranh được chụp ở một góc đường phố."
VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6517.json ADDED
@@ -0,0 +1 @@
 
 
1
+ "Bức tranh này mô tả một người đàn ông đang đứng trên một bức tường màu xanh. Anh ta đang nhìn về phía trước và có vẻ như đang tập trung vào một điều gì đó. Bức tranh có một màu sắc đơn giản và không có nhiều chi tiết."
VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6521.json ADDED
@@ -0,0 +1 @@
 
 
1
+ "Bức tranh này mô tả một người phụ nữ đang đi bộ trên đường. Cô ấy đang đeo một chiếc túi xách trên vai và mặc một bộ quần áo màu đen. Cô ấy đang đi trên một con đường có một con đường đi bộ."
VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6533.json ADDED
@@ -0,0 +1 @@
 
 
1
+ "Bức tranh này mô tả một người đàn ông đang đấm vào người khác trên đường. Người đàn ông đang đấm vào người khác bằng một cây cối."
VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6539.json ADDED
@@ -0,0 +1 @@
 
 
1
+ "Bức tranh này mô tả một người đàn ông đang đi bộ trên đường. Anh ta đang mặc một bộ đồ bảo hộ lao động màu xanh dương, có một chiếc áo khoác và quần áo dài. Anh ta đang đứng trên một con phố có gạch cống và đường đi xước."
VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6580.json ADDED
@@ -0,0 +1 @@
 
 
1
+ "Bức tranh này mô tả một người phụ nữ đang đi bộ trên đường. Cô ấy đang đeo một chiếc khẩu trang y tế màu xanh lá cây. Cô ấy đang mặc một chiếc áo khoác màu trắng, quần đen và giày sneaker màu trắng. Cô ấy cũng đang đeo một chiếc túi đeo chéo trên vai."
VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6589.json ADDED
@@ -0,0 +1 @@
 
 
1
+ "Bức tranh này mô tả một người đàn ông đang cố gắng giữ lại tóc của mình. Anh ta đang cố gắng giữ lại tóc của mình bằng tay. Anh ta đang mặc một chiếc áo màu trắng và quần short màu xám. Anh ta cũng đang đeo một chiếc đồng hồ trên tay."
VLMEvalKit_old/outputs/Qwen2-VL-2B-Instruct/DSPAR_MINI/2024-12-24_08-17-11/Qwen2-VL-2B-Instruct/T2024-12-24_08-17-20_Gd57daa89/json/Qwen2-VL-2B-Instruct_DSPAR_MINI_6608.json ADDED
@@ -0,0 +1 @@
 
 
1
+ "Bức tranh này mô tả một người đàn ông đang đi bộ trên đường. Anh ấy đang mặc một chiếc áo thun màu xám và một chiếc áo vest màu đỏ. Anh ấy đang cầm một chiếc túi xách màu trắng. Anh ấy có một chiếc kính kính màu đen và một chiếc mũ nón màu đen. Anh ấy có một chiếc điện thoại di động trong túi xách. Anh ấy có một chiếc áo dài màu đỏ và một chiếc áo dài màu xanh. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo d��i màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc áo dài màu xanh và một chiếc áo dài màu đỏ. Anh ấy có một chiếc"