Views
No views yet


| Ovis MLLMs | ViT | LLM | Model Weights | Demo |
|---|---|---|---|---|
| Ovis1.6-Gemma2-9B | Siglip-400M | Gemma2-9B-It | Huggingface | Space |
| Ovis1.6-Llama3.2-3B | Siglip-400M | Llama-3.2-3B-Instruct | Huggingface | Space |
| Ovis1.6-Gemma2-9B-GPTQ-Int4 | Siglip-400M | Gemma2-9B-It | Huggingface | - |
| Ovis1.6-Llama3.2-3B-GPTQ-Int4 | Siglip-400M | Llama-3.2-3B-Instruct | Huggingface | - |
1conda create -n <your_env_name> python=3.10
2conda activate <your_env_name>
3pip install torch==2.2.1 torchvision==0.17.1 torchaudio==2.2.1 --index-url https://download.pytorch.org/whl/cu121
4pip install numpy==1.24.3 transformers==4.44.2 pillow==10.3.0 gekko pandas1git clone https://github.com/AIDC-AI/AutoGPTQ.git
2cd AutoGPTQ
3pip install -vvv --no-build-isolation -e .1import torch
2from PIL import Image
3from transformers import GenerationConfig
4from auto_gptq.modeling import OvisLlamaGPTQForCausalLM
5
6# load model
7load_device = "cuda:0" # customize load device
8model = OvisLlamaGPTQForCausalLM.from_quantized(
9 "AIDC-AI/Ovis1.6-Llama3.2-3B-GPTQ-Int4",
10 device=load_device,
11 trust_remote_code=True
12)
13model.model.generation_config = GenerationConfig.from_pretrained("AIDC-AI/Ovis1.6-Llama3.2-3B-GPTQ-Int4")
14text_tokenizer = model.get_text_tokenizer()
15visual_tokenizer = model.get_visual_tokenizer()
16
17# enter image path and prompt
18image_path = input("Enter image path: ")
19image = Image.open(image_path)
20text = input("Enter prompt: ")
21query = f'<image>\n{text}'
22
23# format conversation
24prompt, input_ids, pixel_values = model.preprocess_inputs(query, [image])
25attention_mask = torch.ne(input_ids, text_tokenizer.pad_token_id)
26input_ids = input_ids.unsqueeze(0).to(device=model.device)
27attention_mask = attention_mask.unsqueeze(0).to(device=model.device)
28pixel_values = [pixel_values.to(dtype=visual_tokenizer.dtype, device=visual_tokenizer.device)]
29
30# generate output
31with torch.inference_mode():
32 gen_kwargs = dict(
33 max_new_tokens=1024,
34 do_sample=False,
35 top_p=None,
36 top_k=None,
37 temperature=None,
38 repetition_penalty=None,
39 eos_token_id=model.generation_config.eos_token_id,
40 pad_token_id=text_tokenizer.pad_token_id,
41 use_cache=True
42 )
43 output_ids = model.generate(input_ids, pixel_values=pixel_values, attention_mask=attention_mask, **gen_kwargs)[0]
44 output = text_tokenizer.decode(output_ids, skip_special_tokens=True)
45 print(f'Output:\n{output}')1batch_inputs = [
2 ('example_image1.jpeg', 'Describe the content of this image.'),
3 ('example_image2.jpeg', 'What is the equation in the image?')
4]
5
6batch_input_ids = []
7batch_attention_mask = []
8batch_pixel_values = []
9
10for image_path, text in batch_inputs:
11 image = Image.open(image_path)
12 query = f'<image>\n{text}'
13 prompt, input_ids, pixel_values = model.preprocess_inputs(query, [image])
14 attention_mask = torch.ne(input_ids, text_tokenizer.pad_token_id)
15 input_ids = input_ids.unsqueeze(0).to(device=model.device)
16 attention_mask = attention_mask.unsqueeze(0).to(device=model.device)
17 pixel_values = [pixel_values.to(dtype=visual_tokenizer.dtype, device=visual_tokenizer.device)]
18 batch_input_ids.append(input_ids.squeeze())
19 batch_attention_mask.append(attention_mask.squeeze())
20 batch_pixel_values.append(pixel_values)
21
22pad_batch_input_ids = torch.nn.utils.rnn.pad_sequence([i.flip(dims=[0]) for i in batch_input_ids],batch_first=True, padding_value=0.0).flip(dims=[1])
23pad_batch_input_ids = pad_batch_input_ids[:,-model.config.multimodal_max_length:]
24pad_batch_attention_mask = torch.nn.utils.rnn.pad_sequence([i.flip(dims=[0]) for i in batch_attention_mask],batch_first=True, padding_value=False).flip(dims=[1])
25pad_batch_attention_mask = pad_batch_attention_mask[:,-model.config.multimodal_max_length:]
26pad_batch_pixel_values = [item for sublist in batch_pixel_values for item in sublist]
27
28# generate output
29with torch.inference_mode():
30 gen_kwargs = dict(
31 max_new_tokens=1024,
32 do_sample=False,
33 top_p=None,
34 top_k=None,
35 temperature=None,
36 repetition_penalty=None,
37 eos_token_id=model.generation_config.eos_token_id,
38 pad_token_id=text_tokenizer.pad_token_id,
39 use_cache=True
40 )
41 output_ids = model.generate(pad_batch_input_ids, pixel_values=pad_batch_pixel_values, attention_mask=pad_batch_attention_mask, **gen_kwargs)
42
43for i in range(len(batch_input_ids)):
44 output = text_tokenizer.decode(output_ids[i], skip_special_tokens=True)
45 print(f'Output_{i}:\n{output}')1from typing import Dict, Sequence, Union, List
2import copy
3import logging
4
5from auto_gptq import BaseQuantizeConfig
6from auto_gptq.modeling import OvisLlamaGPTQForCausalLM
7import torch
8from torch.utils.data import Dataset, DataLoader
9from PIL import Image
10
11
12# Specify paths and hyperparameters for quantization
13model_path = "path/to/finetuned/model"
14quantize_save_path = "path/to/save/quantized/model"
15IGNORE_ID = -100
16device_idx = 2 # you customize
17torch.cuda.set_device(device_idx)
18quantize_config = BaseQuantizeConfig(
19 bits=4, # 4 or 8
20 group_size=128,
21 damp_percent=0.1,
22 desc_act=False, # set to False can significantly speed up inference but the perplexity may slightly bad
23 static_groups=False,
24 sym=True,
25 true_sequential=True,
26)
27
28
29# Load model
30model = OvisLlamaGPTQForCausalLM.from_pretrained(
31 model_path,
32 quantize_config,
33 torch_dtype=torch.bfloat16,
34 multimodal_max_length=2624,
35 llm_attn_implementation='eager',
36 trust_remote_code=True
37).cuda()
38model.model.llm.model.config.use_cache = False
39print(f"Model Loaded!")
40
41
42# prepare calibration samples
43class CalibrationDataset(Dataset):
44 """
45 Dataset class for calibration. Initialize with the loaded Ovis model, and a sample list in the following format:
46 data_list = [
47 {
48 "image": "path/to/image/of/this/sample",
49 "conversations": [
50 {
51 "from": "human",
52 "value": "<image>\n[Your sample prompt]"
53 },
54 {
55 "from": "gpt",
56 "value": "[Anything]"
57 }
58 ]
59 },
60 ...
61 ]
62 """
63 def __init__(self, model, text_max_length, data_list: List[Dict]):
64 self.data = data_list
65 self.model = model
66 self.visual_tokenizer = model.get_visual_tokenizer()
67 self.text_max_length = text_max_length
68
69
70 def __len__(self):
71 return len(self.data)
72
73
74 def __getitem__(self, i: int) -> Dict[str, torch.Tensor]:
75 sample = self.data[i]
76 conversations = copy.deepcopy(sample["conversations"])
77 images = [Image.open(sample['image'])]
78 max_partition = 9
79
80 prompt, input_ids, pixel_values, labels = self.model.preprocess_inputs(
81 conversations,
82 images,
83 max_partition=max_partition,
84 generation_preface=None,
85 return_labels=True,
86 propagate_exception=False
87 )
88
89 if pixel_values is None:
90 pixel_values, _ = self.visual_tokenizer.mock_input()
91
92 input_ids = input_ids[:self.text_max_length]
93 labels = labels[:self.text_max_length]
94
95 return dict(
96 pixel_values=pixel_values,
97 input_ids=input_ids,
98 labels=labels
99 )
100
101
102class DataCollatorForMultimodalDatasetGPTQ:
103 def __init__(self, text_tokenizer):
104 self.text_tokenizer = text_tokenizer
105
106 def __call__(self, instances: Sequence[Dict]) -> Dict[str, Union[torch.Tensor, List[torch.Tensor]]]:
107 pixel_values, input_ids, labels = tuple([instance[key] for instance in instances]
108 for key in ("pixel_values", "input_ids", "labels"))
109 input_ids = torch.nn.utils.rnn.pad_sequence(
110 input_ids,
111 batch_first=True,
112 padding_value=self.text_tokenizer.pad_token_id)
113 attention_mask = torch.ne(input_ids, self.text_tokenizer.pad_token_id)
114 labels = torch.nn.utils.rnn.pad_sequence(
115 labels,
116 batch_first=True,
117 padding_value=IGNORE_ID)
118
119 num_valid_label = torch.not_equal(labels, IGNORE_ID).sum().item()
120 if num_valid_label == 0:
121 logging.warning(
122 f'[DataCollatorForMultimodalDatasetGPTQ] All labels are ignored, may causing training instability\n{input_ids=}\n{attention_mask=}\n{labels=}')
123
124 return dict(
125 input_ids=input_ids,
126 attention_mask=attention_mask,
127 labels=labels,
128 pixel_values=pixel_values
129 )
130
131
132class MyDataLoader(DataLoader):
133 def __len__(self):
134 return len(self.dataset) // self.batch_size # must set drop last=True
135
136
137# prepare your own calibration samples here
138data_list = [
139 {
140 "image": "path/to/image/of/this/sample",
141 "conversations": [
142 {
143 "from": "human",
144 "value": "<image>\n[Your sample prompt]"
145 },
146 {
147 "from": "gpt",
148 "value": "[Anything]"
149 }
150 ]
151 }
152]
153train_dataset = CalibrationDataset(model, text_max_length=832, data_list=data_list)
154print(f"Dataset Loaded!")
155print(f"Total length of the training set: {len(train_dataset)}")
156
157train_loader = MyDataLoader(
158 train_dataset,
159 collate_fn=DataCollatorForMultimodalDatasetGPTQ(model.get_text_tokenizer()),
160 shuffle=False,
161 batch_size=4,
162 drop_last=True,
163 pin_memory=True,
164 num_workers=8
165)
166print(f"Dataloader Loaded!")
167
168
169# start quantizing
170model.quantize(train_loader, cache_examples_on_gpu=False)
171print(f"Model Quantized! Now Saving...")
172
173model.save_quantized(quantize_save_path, use_safetensors=True)
174print(f"ALL Done!")

@article{lu2024ovis,
title={Ovis: Structural Embedding Alignment for Multimodal Large Language Model},
author={Shiyin Lu and Yang Li and Qing-Guo Chen and Zhao Xu and Weihua Luo and Kaifu Zhang and Han-Jia Ye},
year={2024},
journal={arXiv:2405.20797}
}