davenliu commited on
Commit
fa0defc
·
verified ·
1 Parent(s): cd5729d

Upload folder using huggingface_hub

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ tokenizer.json filter=lfs diff=lfs merge=lfs -text
added_tokens.json ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "</img>": 151653,
3
+ "</think>": 151668,
4
+ "</tool_call>": 151658,
5
+ "</tool_response>": 151666,
6
+ "<img>": 151652,
7
+ "<think>": 151667,
8
+ "<tool_call>": 151657,
9
+ "<tool_response>": 151665,
10
+ "<|box_end|>": 151649,
11
+ "<|box_start|>": 151648,
12
+ "<|endoftext|>": 151643,
13
+ "<|file_sep|>": 151664,
14
+ "<|fim_middle|>": 151660,
15
+ "<|fim_pad|>": 151662,
16
+ "<|fim_prefix|>": 151659,
17
+ "<|fim_suffix|>": 151661,
18
+ "<|im_end|>": 151645,
19
+ "<|im_start|>": 151644,
20
+ "<|image_pad|>": 151655,
21
+ "<|object_ref_end|>": 151647,
22
+ "<|object_ref_start|>": 151646,
23
+ "<|quad_end|>": 151651,
24
+ "<|quad_start|>": 151650,
25
+ "<|repo_name|>": 151663,
26
+ "<|video_pad|>": 151656,
27
+ "<|vision_pad|>": 151654
28
+ }
chat_template.jinja ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {%- if tools %}
2
+ {{- '<|im_start|>system\n' }}
3
+ {%- if messages[0].role == 'system' %}
4
+ {{- messages[0].content + '\n\n' }}
5
+ {%- endif %}
6
+ {{- "# Tools\n\nYou may call one or more functions to assist with the user query.\n\nYou are provided with function signatures within <tools></tools> XML tags:\n<tools>" }}
7
+ {%- for tool in tools %}
8
+ {{- "\n" }}
9
+ {{- tool | tojson }}
10
+ {%- endfor %}
11
+ {{- "\n</tools>\n\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\n<tool_call>\n{\"name\": <function-name>, \"arguments\": <args-json-object>}\n</tool_call><|im_end|>\n" }}
12
+ {%- else %}
13
+ {%- if messages[0].role == 'system' %}
14
+ {{- '<|im_start|>system\n' + messages[0].content + '<|im_end|>\n' }}
15
+ {%- endif %}
16
+ {%- endif %}
17
+ {%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}
18
+ {%- for message in messages[::-1] %}
19
+ {%- set index = (messages|length - 1) - loop.index0 %}
20
+ {%- if ns.multi_step_tool and message.role == "user" and not(message.content.startswith('<tool_response>') and message.content.endswith('</tool_response>')) %}
21
+ {%- set ns.multi_step_tool = false %}
22
+ {%- set ns.last_query_index = index %}
23
+ {%- endif %}
24
+ {%- endfor %}
25
+ {%- for message in messages %}
26
+ {%- if (message.role == "user") or (message.role == "system" and not loop.first) %}
27
+ {{- '<|im_start|>' + message.role + '\n' + message.content + '<|im_end|>' + '\n' }}
28
+ {%- elif message.role == "assistant" %}
29
+ {%- set content = message.content %}
30
+ {%- set reasoning_content = '' %}
31
+ {%- if message.reasoning_content is defined and message.reasoning_content is not none %}
32
+ {%- set reasoning_content = message.reasoning_content %}
33
+ {%- else %}
34
+ {%- if '</think>' in message.content %}
35
+ {%- set content = message.content.split('</think>')[-1].lstrip('\n') %}
36
+ {%- set reasoning_content = message.content.split('</think>')[0].rstrip('\n').split('<think>')[-1].lstrip('\n') %}
37
+ {%- endif %}
38
+ {%- endif %}
39
+ {%- if loop.index0 > ns.last_query_index %}
40
+ {%- if loop.last or (not loop.last and reasoning_content) %}
41
+ {{- '<|im_start|>' + message.role + '\n<think>\n' + reasoning_content.strip('\n') + '\n</think>\n\n' + content.lstrip('\n') }}
42
+ {%- else %}
43
+ {{- '<|im_start|>' + message.role + '\n' + content }}
44
+ {%- endif %}
45
+ {%- else %}
46
+ {{- '<|im_start|>' + message.role + '\n' + content }}
47
+ {%- endif %}
48
+ {%- if message.tool_calls %}
49
+ {%- for tool_call in message.tool_calls %}
50
+ {%- if (loop.first and content) or (not loop.first) %}
51
+ {{- '\n' }}
52
+ {%- endif %}
53
+ {%- if tool_call.function %}
54
+ {%- set tool_call = tool_call.function %}
55
+ {%- endif %}
56
+ {{- '<tool_call>\n{"name": "' }}
57
+ {{- tool_call.name }}
58
+ {{- '", "arguments": ' }}
59
+ {%- if tool_call.arguments is string %}
60
+ {{- tool_call.arguments }}
61
+ {%- else %}
62
+ {{- tool_call.arguments | tojson }}
63
+ {%- endif %}
64
+ {{- '}\n</tool_call>' }}
65
+ {%- endfor %}
66
+ {%- endif %}
67
+ {{- '<|im_end|>\n' }}
68
+ {%- elif message.role == "tool" %}
69
+ {%- if loop.first or (messages[loop.index0 - 1].role != "tool") %}
70
+ {{- '<|im_start|>user' }}
71
+ {%- endif %}
72
+ {{- '\n<tool_response>\n' }}
73
+ {{- message.content }}
74
+ {{- '\n</tool_response>' }}
75
+ {%- if loop.last or (messages[loop.index0 + 1].role != "tool") %}
76
+ {{- '<|im_end|>\n' }}
77
+ {%- endif %}
78
+ {%- endif %}
79
+ {%- endfor %}
80
+ {%- if add_generation_prompt %}
81
+ {{- '<|im_start|>assistant\n' }}
82
+ {%- if enable_thinking is defined and enable_thinking is false %}
83
+ {{- '<think>\n\n</think>\n\n' }}
84
+ {%- endif %}
85
+ {%- endif %}
config.json ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "AndesVLForConditionalGeneration"
4
+ ],
5
+ "auto_map": {
6
+ "AutoConfig": "configuration_andesvl.AndesVLConfig",
7
+ "AutoModel": "modeling_andesvl.AndesVLForConditionalGeneration",
8
+ "AutoModelForCausalLM": "modeling_andesvl.AndesVLForConditionalGeneration"
9
+ },
10
+ "model_type": "andesvl-siglip2-qwen3",
11
+ "text_config": {
12
+ "vocab_size": 151936,
13
+ "max_position_embeddings": 40960,
14
+ "hidden_size": 1024,
15
+ "intermediate_size": 3072,
16
+ "num_hidden_layers": 28,
17
+ "num_attention_heads": 16,
18
+ "use_sliding_window": false,
19
+ "sliding_window": null,
20
+ "max_window_layers": 28,
21
+ "num_key_value_heads": 8,
22
+ "head_dim": 128,
23
+ "hidden_act": "silu",
24
+ "initializer_range": 0.02,
25
+ "rms_norm_eps": 1e-06,
26
+ "use_cache": true,
27
+ "rope_theta": 1000000,
28
+ "rope_scaling": null,
29
+ "attention_bias": false,
30
+ "attention_dropout": 0.0,
31
+ "tie_word_embeddings": true,
32
+ "architectures": [
33
+ "Qwen3ForCausalLM"
34
+ ],
35
+ "bos_token_id": 151643,
36
+ "eos_token_id": 151645,
37
+ "model_type": "qwen3"
38
+ },
39
+ "vision_config": {
40
+ "architectures": [
41
+ "Siglip2VisionModel"
42
+ ],
43
+ "disable_rope": false,
44
+ "hidden_act": "gelu_pytorch_tanh",
45
+ "hidden_size": 768,
46
+ "intermediate_size": 3072,
47
+ "layer_norm_eps": 1e-06,
48
+ "model_type": "siglip2_navit_rope_model",
49
+ "num_attention_heads": 12,
50
+ "num_channels": 3,
51
+ "num_hidden_layers": 12,
52
+ "num_patches": 1024,
53
+ "patch_size": 16,
54
+ "preserve_original_pe": true,
55
+ "rope_theta": 10000.0
56
+ },
57
+ "tie_word_embeddings": true,
58
+ "torch_dtype": "bfloat16",
59
+ "transformers_version": "4.51.0"
60
+ }
configuration_andesvl.py ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import copy
2
+
3
+ from transformers import Qwen3Config
4
+ from transformers.configuration_utils import PretrainedConfig
5
+ from transformers.utils import logging
6
+ from .configuration_siglip2_navit_rope import Siglip2VisionConfig
7
+
8
+
9
+ logger = logging.get_logger(__name__)
10
+
11
+
12
+ class AndesVLConfig(PretrainedConfig):
13
+ model_type = 'andesvl-siglip2-qwen3'
14
+ is_composition = True
15
+
16
+ def __init__(
17
+ self,
18
+ vision_config=None,
19
+ text_config=None,
20
+ **kwargs):
21
+ super().__init__(**kwargs)
22
+
23
+ self.vision_config = Siglip2VisionConfig(**vision_config) if vision_config is not None else Siglip2VisionConfig()
24
+ self.text_config = Qwen3Config(**text_config) if text_config is not None else Qwen3Config()
25
+
26
+ def to_dict(self):
27
+ """
28
+ Serializes this instance to a Python dictionary. Override the default [`~PretrainedConfig.to_dict`].
29
+ Returns:
30
+ `Dict[str, any]`: Dictionary of all the attributes that make up this configuration instance,
31
+ """
32
+ output = copy.deepcopy(self.__dict__)
33
+ output['vision_config'] = self.vision_config.to_dict()
34
+ output['text_config'] = self.text_config.to_dict()
35
+ output['model_type'] = self.__class__.model_type
36
+ return output
configuration_siglip2_navit_rope.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from typing import Union
3
+ from transformers.configuration_utils import PretrainedConfig
4
+ from transformers.utils import logging
5
+ logger = logging.get_logger(__name__)
6
+
7
+
8
+ class Siglip2VisionConfig(PretrainedConfig):
9
+ model_type = "siglip2_navit_rope_model"
10
+ base_config_key = "vision_config"
11
+
12
+ def __init__(
13
+ self,
14
+ hidden_size=768,
15
+ intermediate_size=3072,
16
+ num_hidden_layers=12,
17
+ num_attention_heads=12,
18
+ num_channels=3,
19
+ patch_size=16,
20
+ hidden_act="gelu_pytorch_tanh",
21
+ layer_norm_eps=1e-6,
22
+ preserve_original_pe=True,
23
+ disable_rope=False,
24
+ num_patches=1369,
25
+ rope_theta=10000.0,
26
+ **kwargs,
27
+ ):
28
+ super().__init__(**kwargs)
29
+
30
+ self.hidden_size = hidden_size
31
+ self.intermediate_size = intermediate_size
32
+ self.num_hidden_layers = num_hidden_layers
33
+ self.num_attention_heads = num_attention_heads
34
+ self.num_channels = num_channels
35
+ self.patch_size = patch_size
36
+ self.hidden_act = hidden_act
37
+ self.layer_norm_eps = layer_norm_eps
38
+ self.preserve_original_pe = preserve_original_pe
39
+ self.disable_rope = disable_rope
40
+ self.num_patches = num_patches
41
+ self.rope_theta = rope_theta
generation_config.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "do_sample": true,
3
+ "temperature": 0.6,
4
+ "top_k": 20,
5
+ "top_p": 0.95,
6
+ "pad_token_id": 151643,
7
+ "bos_token_id": 151643,
8
+ "eos_token_id": [
9
+ 151645,
10
+ 151643
11
+ ]
12
+ }
merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
modeling_andesvl.py ADDED
@@ -0,0 +1,290 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from torch import nn
2
+ import torch.utils.checkpoint
3
+ from transformers import Qwen3ForCausalLM
4
+ from transformers.modeling_utils import PreTrainedModel
5
+ from transformers.utils import logging
6
+ from .configuration_andesvl import AndesVLConfig
7
+ from .modeling_siglip2_navit_rope import Siglip2VisionModel
8
+
9
+ logger = logging.get_logger(__name__)
10
+
11
+ class AndesVLForConditionalGeneration(PreTrainedModel):
12
+ config_class = AndesVLConfig
13
+ main_input_name = 'pixel_values'
14
+ _supports_flash_attn_2 = True
15
+ _no_split_modules = ['Siglip2VisionModel','Qwen3DecoderLayer']
16
+
17
+
18
+ def __init__(self, config: AndesVLConfig):
19
+ super().__init__(config)
20
+
21
+ self.config = config
22
+ self.vision_encoder = Siglip2VisionModel(config.vision_config)
23
+ self.language_model = Qwen3ForCausalLM(config.text_config)
24
+
25
+ vit_hidden_size = self.vision_encoder.config.hidden_size
26
+ llm_hidden_size = self.language_model.config.hidden_size
27
+ self.patch_size = self.vision_encoder.config.patch_size
28
+ self.mlp = nn.Sequential(
29
+ nn.Linear(vit_hidden_size * 4, vit_hidden_size * 4),
30
+ nn.GELU(),
31
+ nn.Linear(vit_hidden_size * 4, llm_hidden_size),
32
+ )
33
+
34
+ def get_input_embeddings(self):
35
+ return self.language_model.model.embed_tokens
36
+
37
+ def set_input_embeddings(self, value):
38
+ self.language_model.model.embed_tokens = value
39
+
40
+ def get_output_embeddings(self):
41
+ return self.language_model.lm_head
42
+
43
+ def set_output_embeddings(self, new_embeddings):
44
+ self.language_model.lm_head = new_embeddings
45
+
46
+ def get_flated_pixel_values(self, pixel_values):
47
+ flated_pixel_values = []
48
+ image_grid_hw = []
49
+ for pv in pixel_values:
50
+ c, h, w = pv.shape
51
+ assert c==3 and h%self.patch_size==0 and w%self.patch_size==0, f"{c}, {w}, {h}, {self.patch_size}"
52
+ image_grid_hw.append((h//self.patch_size, w//self.patch_size))
53
+ fpv = pv.reshape(c, h//(2*self.patch_size), 2, self.patch_size, w//(2*self.patch_size), 2, self.patch_size)
54
+ flated_pixel_values.append(fpv.permute(1, 4, 2, 5, 0, 3, 6).reshape(-1, c*self.patch_size*self.patch_size))
55
+ flated_pixel_values = torch.cat(flated_pixel_values, dim=0) # (Len_img, C, H, W)
56
+ image_grid_hw = torch.tensor(image_grid_hw, device=flated_pixel_values.device) # (N_img, 2)
57
+ return flated_pixel_values, image_grid_hw
58
+
59
+
60
+ def get_vit_embeds_and_merge(self, pixel_values, image_grid_hw, input_embeds, image_flags):
61
+ """
62
+ Args:
63
+ pixel_values: (Len_img, H_vit0), 拉平后的初始patch特征,按照序列维度拼接在一起
64
+ image_grid_hw: (N_img, 2), 每个图片的宽高
65
+ input_embeds: (Bt, Lt, Ht), 每个token的embedding
66
+ image_flags: (Bt, Lt), 每个token是否是图片
67
+ """
68
+ vit_embeds = self.vision_encoder(pixel_values, image_grid_hw) # (Len_img, H_vit)
69
+ vit_embeds = vit_embeds.view(-1, vit_embeds.shape[-1]*4) # (Len_img//4, H_vit*4)
70
+ vit_embeds = self.mlp(vit_embeds) # (Len_img//4, H_llm)
71
+ vit_embeds = vit_embeds[:image_flags.sum()]
72
+ Bt, Lt, Ht = input_embeds.shape
73
+ input_embeds = input_embeds.reshape(-1, Ht)
74
+ image_flags = image_flags.view(-1)
75
+ input_embeds[image_flags == 1] = vit_embeds
76
+ input_embeds = input_embeds.view(Bt, Lt, Ht)
77
+ return input_embeds
78
+
79
+ @torch.inference_mode()
80
+ @torch.autocast(device_type="cuda", dtype=torch.bfloat16)
81
+ def generate(
82
+ self,
83
+ pixel_values=None,
84
+ input_ids=None,
85
+ attention_mask=None,
86
+ image_flags=None, # (Bt, Lt)
87
+ generation_config=None,
88
+ **generate_kwargs,
89
+ ) -> torch.LongTensor:
90
+
91
+ input_embeds = self.language_model.get_input_embeddings()(input_ids) # (Bt, Lt, Ht)
92
+ if image_flags != None and (image_flags == 1).sum() > 0:
93
+ flated_pixel_values, image_grid_hw = self.get_flated_pixel_values(pixel_values)
94
+ input_embeds = self.get_vit_embeds_and_merge(flated_pixel_values, image_grid_hw, input_embeds, image_flags)
95
+ outputs = self.language_model.generate(
96
+ input_ids=input_ids,
97
+ inputs_embeds=input_embeds,
98
+ attention_mask=attention_mask,
99
+ generation_config=generation_config,
100
+ use_cache=True,
101
+ **generate_kwargs,
102
+ )
103
+ return outputs
104
+
105
+ #NOTE: completion和chat接口暂不支持batch推理,需要手动构建self.generate函数的输入来实现。
106
+ def completion(self, prompt, images, tokenizer, image_processor, **kwargs):
107
+ """输入一段文字和一组图片(其中文字中的图片用占位符标记为<image>),输出补全的文本"""
108
+ assert prompt.count("<image>") == len(images), "图片数量和占位符数量不匹配"
109
+ def replacement(m):
110
+ token_count = image_tokens.pop(0)
111
+ return f"<img>{'<|vision_pad|>' * token_count}</img>"
112
+ #首先对所有的图像进行处理,获取对应的size
113
+ max_size = kwargs.get("max_size", 733) # max_size**2为支持的最大的面积
114
+ base = self.patch_size*2
115
+ image_token_id = tokenizer.vocab['<|vision_pad|>'] # 图像token的占位符
116
+ background_color = tuple(int(x*255) for x in image_processor.image_mean)
117
+ transform = T.Compose([T.ToTensor(),T.Normalize(mean=image_processor.image_mean, std=image_processor.image_std)])
118
+ pixel_values = []
119
+ image_tokens = []
120
+ for image in images:
121
+ if isinstance(image, (tuple, list)):
122
+ image, detail = image
123
+ else:
124
+ detail = "low"
125
+ image = load_image(image)
126
+ if detail=="low":
127
+ image = native_preprocess(image, max_size, base, background_color, min_tokens=4)
128
+ pixel_values.append(transform(image))
129
+ image_tokens.append(image.size[0]*image.size[1]//(base*base))
130
+ else:
131
+ raise NotImplementedError("暂未实现")
132
+ new_prompt = re.sub(r"<image>", replacement, prompt)
133
+ input_ids = tokenizer(new_prompt, return_tensors="pt", add_special_tokens=False).input_ids.to(self.device)
134
+ image_flags = (input_ids == image_token_id).int()
135
+ input_ids = input_ids.to(self.vision_encoder.device)
136
+ pixel_values = [pv.to(self.vision_encoder.device) for pv in pixel_values]
137
+ image_flags = image_flags.to(self.vision_encoder.device)
138
+ output_ids = self.generate(pixel_values=pixel_values, input_ids=input_ids, image_flags=image_flags, **kwargs)[0][input_ids.shape[1]:]
139
+ return tokenizer.decode(output_ids, skip_special_tokens=True)
140
+
141
+ def chat(self, messages, tokenizer, image_processor, **kwargs):
142
+ """输入是一组对话信息(openai格式),输出是回复"""
143
+ prompt = ""
144
+ images = []
145
+ for message in messages:
146
+ role = message["role"]
147
+ assert role in ["user", "assistant", "system"], f"非法的角色{role}"
148
+ content = message['content']
149
+ if isinstance(content, str):
150
+ prompt += f"<|im_start|>{role}\n{content}{tokenizer.eos_token}\n"
151
+ elif isinstance(content, list):
152
+ temp = ""
153
+ for sub_content in content:
154
+ if sub_content['type']=='text':
155
+ temp += f"{sub_content['text']}"
156
+ elif sub_content['type']=='image_url':
157
+ temp += "<image>"
158
+ images.append([load_image(sub_content['image_url']['url']), sub_content['image_url'].get("detail",'low')])
159
+ prompt += f"<|im_start|>{role}\n{temp}{tokenizer.eos_token}\n"
160
+ else:
161
+ raise ValueError(f"非法的内容{content}")
162
+ prompt += f"<|im_start|>assistant\n"
163
+ thinking = 'thinking' in kwargs and kwargs['thinking']
164
+ if 'thinking' in kwargs:
165
+ kwargs.pop('thinking')
166
+ prompt += f"<|im_start|>assistant\n" + ('<think>' if thinking else '')
167
+ return ('<think>' if thinking else '') + self.completion(prompt, images, tokenizer, image_processor, **kwargs)
168
+ # return self.completion(prompt, images, tokenizer, image_processor, **kwargs)
169
+
170
+ ########################
171
+ ###下面是图像处理的代码###
172
+ ########################
173
+
174
+ import os
175
+ import math
176
+ import re
177
+ from typing import Union
178
+ import requests
179
+ import base64
180
+ from io import BytesIO
181
+ from PIL import Image
182
+ import torchvision.transforms as T
183
+
184
+ def load_image(source: Union[str, Image.Image]) -> Image.Image:
185
+ """加载图像"""
186
+ if isinstance(source, Image.Image):
187
+ img = source
188
+ elif isinstance(source, str):
189
+ if source.startswith('http'):
190
+ response = requests.get(source)
191
+ response.raise_for_status()
192
+ img = Image.open(BytesIO(response.content))
193
+ elif os.path.exists(source):
194
+ img = Image.open(source)
195
+ elif source.startswith('data:image'):
196
+ img = Image.open(BytesIO(base64.b64decode(source.split(',')[1])))
197
+ else:
198
+ raise ValueError("Unsupported image source")
199
+ else:
200
+ raise ValueError("Unsupported image source")
201
+ return img.convert('RGB')
202
+
203
+ def get_scaled_img_size(image_size, max_area, base, max_resolution=4172, upper=True):
204
+ """计算缩放后的图片大小和包裹矩形的大小"""
205
+ # 计算原始图片的宽高比
206
+ aspect_ratio = image_size[0] / image_size[1]
207
+ # 计算包裹矩形的最大可能宽度和高度
208
+ max_width = math.floor(math.sqrt(max_area * aspect_ratio))
209
+ max_height = math.floor(math.sqrt(max_area / aspect_ratio))
210
+ max_width, max_height = min(max_width, max_resolution), min(
211
+ max_height, max_resolution
212
+ )
213
+ max_width, max_height = max(max_width, base), max(max_height, base)
214
+ # 确保包裹矩形的宽度和高度都是base的整数倍
215
+ if not upper:
216
+ # 向��取整, 保证面积不会超过max_area
217
+ max_width = max_width - max_width % base
218
+ max_height = max_height - max_height % base
219
+ else:
220
+ # 向上取整,同时不超过max_resolution(单边最大长度)
221
+ max_width = min(max_width + (base - max_width % base), max_resolution)
222
+ max_height = min(max_height + (base - max_height % base), max_resolution)
223
+ # 计算缩放因子
224
+ scale_factor = min(max_width / image_size[0], max_height / image_size[1])
225
+ # 计算缩放后的图片大小
226
+ new_image_size = (
227
+ round(image_size[0] * scale_factor),
228
+ round(image_size[1] * scale_factor),
229
+ )
230
+ # 计算包裹矩形的大小
231
+ bounding_box_size = (max_width, max_height)
232
+ return new_image_size, bounding_box_size
233
+
234
+
235
+ def max_preprocess(
236
+ img, max_size, base, background_color, max_resolution=4172, upper=True, force_resize=False
237
+ ):
238
+ """对图片进行预处理,使其面积接近max_size**2"""
239
+ # 首先把图片resize到长度和宽度都低于max_resolution
240
+ w, h = img.size
241
+ if max(w, h) > max_resolution:
242
+ scale = max_resolution / max(w, h)
243
+ w, h = int(w * scale), int(h * scale)
244
+ # 获取缩放后的图片大小和包裹矩形的大小
245
+ new_image_size, bounding_box_size = get_scaled_img_size(
246
+ (w, h), max_size**2, base, max_resolution, upper
247
+ )
248
+ if force_resize:
249
+ return img.resize(bounding_box_size)
250
+ # 创建一个新的画布
251
+ canvas = Image.new("RGB", bounding_box_size, background_color)
252
+ # 计算将图像粘贴到画布上的位置
253
+ paste_width = (bounding_box_size[0] - new_image_size[0]) // 2
254
+ paste_height = (bounding_box_size[1] - new_image_size[1]) // 2
255
+ # 将图像粘贴到画布上
256
+ canvas.paste(img.resize(new_image_size), (paste_width, paste_height))
257
+ return canvas
258
+
259
+ def native_preprocess(
260
+ img, max_size, base, background_color, max_resolution=4172, min_tokens=64
261
+ ):
262
+ # 对图片进行处理,使其宽度和高度都是base的整数倍
263
+ # 如果图片的最长边超过max_resolution,就把图片resize到max_resolution以内
264
+ w, h = img.size
265
+ # 首先保证图片的最长边不超过max_resolution(ViT在极限长度)
266
+ if max(w, h) > max_resolution:
267
+ scale = max_resolution / max(w, h)
268
+ w, h = int(w * scale), int(h * scale)
269
+ img = img.resize((w, h))
270
+ if w * h > max_size**2:
271
+ return max_preprocess(img, max_size, base, background_color, max_resolution)
272
+ if w * h < (base * base * min_tokens):
273
+ return max_preprocess(
274
+ img,
275
+ int(base * (min_tokens**0.5)),
276
+ base,
277
+ background_color,
278
+ max_resolution,
279
+ )
280
+ w1, h1 = w + base - w % base, h + base - h % base
281
+ if w1 == w and h1 == h:
282
+ return img
283
+ else:
284
+ # 创建一个新的(w1, h1)的画布,并把图片resize保证只有一侧存在白边的情况
285
+ scale = min(w1 / w, h1 / h)
286
+ new_w, new_h = int(w * scale), int(h * scale)
287
+ img = img.resize((new_w, new_h))
288
+ canvas = Image.new("RGB", (w1, h1), background_color)
289
+ canvas.paste(img, ((w1 - new_w) // 2, (h1 - new_h) // 2))
290
+ return canvas
modeling_siglip2_navit_rope.py ADDED
@@ -0,0 +1,520 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import math
2
+
3
+ import torch
4
+ import torch.nn as nn
5
+ import torch.nn.functional as F
6
+ import torch.utils.checkpoint
7
+ from transformers.activations import ACT2FN
8
+ from transformers.modeling_utils import PreTrainedModel
9
+ from transformers.utils import (
10
+ is_flash_attn_2_available,
11
+ )
12
+ try:
13
+ from .configuration_siglip2_navit_rope import Siglip2VisionConfig
14
+ except:
15
+ from configuration_siglip2_navit_rope import Siglip2VisionConfig
16
+
17
+ if is_flash_attn_2_available():
18
+ from flash_attn import flash_attn_varlen_func
19
+ else:
20
+ flash_attn_varlen_func = None
21
+
22
+
23
+ # Copied from transformers.models.llama.modeling_llama.rotate_half
24
+ def rotate_half(x):
25
+ """Rotates half the hidden dims of the input."""
26
+ x1 = x[..., : x.shape[-1] // 2]
27
+ x2 = x[..., x.shape[-1] // 2 :]
28
+ return torch.cat((-x2, x1), dim=-1)
29
+
30
+
31
+ def apply_rotary_pos_emb_vision(
32
+ tensor: torch.Tensor, freqs: torch.Tensor
33
+ ) -> torch.Tensor:
34
+ orig_dtype = tensor.dtype
35
+ tensor = tensor.float()
36
+ cos = freqs.cos()
37
+ sin = freqs.sin()
38
+ cos = cos.unsqueeze(1).repeat(1, 1, 2).unsqueeze(0).float()
39
+ sin = sin.unsqueeze(1).repeat(1, 1, 2).unsqueeze(0).float()
40
+ output = (tensor * cos) + (rotate_half(tensor) * sin)
41
+ output = output.to(orig_dtype)
42
+ return output
43
+
44
+
45
+ class VisionRotaryEmbedding(nn.Module):
46
+ def __init__(self, dim: int, theta: float = 10000.0) -> None:
47
+ super().__init__()
48
+ inv_freq = 1.0 / (theta ** (torch.arange(0, dim, 2, dtype=torch.float) / dim))
49
+ self.register_buffer("inv_freq", inv_freq, persistent=False)
50
+
51
+ def forward(self, seqlen: int) -> torch.Tensor:
52
+ seq = torch.arange(
53
+ seqlen, device=self.inv_freq.device, dtype=self.inv_freq.dtype
54
+ )
55
+ freqs = torch.outer(seq, self.inv_freq)
56
+ return freqs
57
+
58
+
59
+ class PatchEmbed(nn.Module):
60
+ def __init__(
61
+ self,
62
+ patch_size,
63
+ num_channels,
64
+ embed_dim,
65
+ num_patches,
66
+ preserve_original_pe=False
67
+ ):
68
+ super().__init__()
69
+ self.patch_size = patch_size
70
+ self.num_patches = num_patches
71
+ self.embed_dim = embed_dim
72
+ self.preserve_original_pe = preserve_original_pe
73
+
74
+ self.proj = nn.Linear(
75
+ num_channels * patch_size * patch_size, embed_dim
76
+ ) # NOTE: bias默认为True
77
+
78
+ if preserve_original_pe:
79
+ assert num_patches**0.5 == int(num_patches**0.5), "num_patches must be a perfect square"
80
+ self.pos_embed = nn.Embedding(num_patches, embed_dim)
81
+ self.original_grid_size = int(num_patches**0.5)
82
+ else:
83
+ self.pos_embed = None
84
+ self.original_grid_size = 0
85
+
86
+ def get_patch_coordinates(self, grid_hw: torch.Tensor, device: torch.device):
87
+ """
88
+ 生成与2x2分块扫描顺序匹配的patch坐标。
89
+ """
90
+ all_h_coords, all_w_coords, all_target_sizes = [], [], []
91
+
92
+ for h, w in grid_hw:
93
+ h, w = h.item(), w.item()
94
+
95
+ # 生成标准网格坐标
96
+ h_grid, w_grid = torch.meshgrid(
97
+ torch.arange(h, device=device, dtype=torch.float32),
98
+ torch.arange(w, device=device, dtype=torch.float32),
99
+ indexing='ij'
100
+ )
101
+
102
+ # 重排列为分块扫描顺序
103
+ h_coords = h_grid.reshape(
104
+ h//2, 2, w//2, 2
105
+ ).permute(0, 2, 1, 3).flatten()
106
+
107
+ w_coords = w_grid.reshape(
108
+ h//2, 2, w//2, 2
109
+ ).permute(0, 2, 1, 3).flatten()
110
+
111
+ all_h_coords.append(h_coords)
112
+ all_w_coords.append(w_coords)
113
+
114
+ target_size = torch.tensor([h, w], device=device, dtype=torch.float32)
115
+ all_target_sizes.append(target_size.expand(h * w, -1))
116
+
117
+ return torch.cat(all_h_coords), torch.cat(all_w_coords), torch.cat(all_target_sizes)
118
+
119
+ def abs_pos_embed(self, grid_hw: torch.Tensor, mode='bicubic') -> torch.Tensor:
120
+ pos_embed_weight = self.pos_embed.weight
121
+ pos_embed_2d = pos_embed_weight.transpose(0, 1).reshape(
122
+ self.embed_dim, self.original_grid_size, self.original_grid_size
123
+ ).unsqueeze(0).to(torch.float32)
124
+
125
+ if grid_hw.numel() == 0:
126
+ return torch.empty(0, self.embed_dim, device=pos_embed_2d.device, dtype=pos_embed_weight.dtype)
127
+
128
+ h_coords, w_coords, target_sizes = self.get_patch_coordinates(grid_hw, pos_embed_2d.device)
129
+
130
+ if h_coords.shape[0] == 0:
131
+ return torch.empty(0, self.embed_dim, device=pos_embed_2d.device, dtype=pos_embed_weight.dtype)
132
+
133
+ target_h = target_sizes[:, 0]
134
+ target_w = target_sizes[:, 1]
135
+
136
+ # 这个归一化公式对于 align_corners=False 是正确的。
137
+ norm_w = (2.0 * (w_coords + 0.5) / target_w) - 1.0
138
+ norm_h = (2.0 * (h_coords + 0.5) / target_h) - 1.0
139
+
140
+ grid = torch.stack((norm_w, norm_h), dim=-1).unsqueeze(0).unsqueeze(0)
141
+
142
+ interpolated_embed = F.grid_sample(
143
+ pos_embed_2d, grid, mode=mode, align_corners=False,
144
+ padding_mode='border'
145
+ )
146
+
147
+ adapted_pos_embed = interpolated_embed.squeeze(0).squeeze(1).permute(1, 0)
148
+
149
+ return adapted_pos_embed.to(pos_embed_weight.dtype)
150
+
151
+
152
+ def forward(self, hidden_states: torch.Tensor, grid_hw: torch.Tensor) -> torch.Tensor:
153
+ """
154
+ Args:
155
+ hidden_states (torch.Tensor): input tensor of shape [seq_len, num_channels*patch_size*patch_size]
156
+ grid_hw (torch.Tensor): 形状为 [num_images, 2] 的张量,表示每个图像的patch网格高度和宽度
157
+ Returns:
158
+ torch.Tensor: output tensor of shape [seq_len, embed_dim]
159
+ """
160
+ target_dtype = self.proj.weight.dtype
161
+ hidden_states = self.proj(hidden_states.to(dtype=target_dtype))
162
+
163
+ if self.preserve_original_pe:
164
+ pos_emb = self.abs_pos_embed(grid_hw)
165
+ hidden_states = hidden_states + pos_emb
166
+
167
+ return hidden_states
168
+
169
+
170
+ class Siglip2MLP(nn.Module):
171
+ def __init__(self, config):
172
+ super().__init__()
173
+ self.config = config
174
+ self.activation_fn = ACT2FN[config.hidden_act]
175
+ self.fc1 = nn.Linear(config.hidden_size, config.intermediate_size)
176
+ self.fc2 = nn.Linear(config.intermediate_size, config.hidden_size)
177
+
178
+ def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
179
+ hidden_states = self.fc1(hidden_states)
180
+ hidden_states = self.activation_fn(hidden_states)
181
+ hidden_states = self.fc2(hidden_states)
182
+ return hidden_states
183
+
184
+
185
+ class Siglip2Attention(nn.Module):
186
+
187
+ def __init__(self, config):
188
+ super().__init__()
189
+ self.config = config
190
+ self.embed_dim = config.hidden_size
191
+ self.num_heads = config.num_attention_heads
192
+ self.head_dim = self.embed_dim // self.num_heads
193
+ if self.head_dim * self.num_heads != self.embed_dim:
194
+ raise ValueError(
195
+ f"embed_dim must be divisible by num_heads (got `embed_dim`: {self.embed_dim} and `num_heads`:"
196
+ f" {self.num_heads})."
197
+ )
198
+ self.scale = self.head_dim**-0.5
199
+
200
+ self.k_proj = nn.Linear(self.embed_dim, self.embed_dim)
201
+ self.v_proj = nn.Linear(self.embed_dim, self.embed_dim)
202
+ self.q_proj = nn.Linear(self.embed_dim, self.embed_dim)
203
+ self.out_proj = nn.Linear(self.embed_dim, self.embed_dim)
204
+
205
+ def forward(
206
+ self,
207
+ hidden_states: torch.Tensor,
208
+ cu_seqlens: torch.Tensor,
209
+ rotary_pos_emb: torch.Tensor = None,
210
+ ) -> torch.Tensor:
211
+ seq_length = hidden_states.shape[0]
212
+ q = self.q_proj(hidden_states)
213
+ k = self.k_proj(hidden_states)
214
+ v = self.v_proj(hidden_states)
215
+
216
+ q = q.reshape(seq_length, self.num_heads, -1)
217
+ k = k.reshape(seq_length, self.num_heads, -1)
218
+ v = v.reshape(seq_length, self.num_heads, -1)
219
+
220
+ q = apply_rotary_pos_emb_vision(q.unsqueeze(0), rotary_pos_emb).squeeze(0)
221
+ k = apply_rotary_pos_emb_vision(k.unsqueeze(0), rotary_pos_emb).squeeze(0)
222
+
223
+ attention_mask = torch.full(
224
+ [1, seq_length, seq_length],
225
+ torch.finfo(q.dtype).min,
226
+ device=q.device,
227
+ dtype=q.dtype,
228
+ )
229
+ for i in range(1, len(cu_seqlens)):
230
+ attention_mask[
231
+ ...,
232
+ cu_seqlens[i - 1] : cu_seqlens[i],
233
+ cu_seqlens[i - 1] : cu_seqlens[i],
234
+ ] = 0
235
+
236
+ q = q.transpose(0, 1)
237
+ k = k.transpose(0, 1)
238
+ v = v.transpose(0, 1)
239
+ attn_weights = torch.matmul(q, k.transpose(1, 2)) / math.sqrt(self.head_dim)
240
+ attn_weights = attn_weights + attention_mask
241
+ attn_weights = nn.functional.softmax(
242
+ attn_weights, dim=-1, dtype=torch.float32
243
+ ).to(q.dtype)
244
+ attn_output = torch.matmul(attn_weights, v)
245
+ attn_output = attn_output.transpose(0, 1)
246
+ attn_output = attn_output.reshape(seq_length, -1)
247
+ attn_output = self.out_proj(attn_output)
248
+ return attn_output
249
+
250
+
251
+ class Siglip2FlashAttention2(nn.Module):
252
+
253
+ def __init__(self, config):
254
+ super().__init__()
255
+ self.config = config
256
+ self.embed_dim = config.hidden_size
257
+ self.num_heads = config.num_attention_heads
258
+ self.head_dim = self.embed_dim // self.num_heads
259
+ if self.head_dim * self.num_heads != self.embed_dim:
260
+ raise ValueError(
261
+ f"embed_dim must be divisible by num_heads (got `embed_dim`: {self.embed_dim} and `num_heads`:"
262
+ f" {self.num_heads})."
263
+ )
264
+ self.scale = self.head_dim**-0.5
265
+
266
+ self.k_proj = nn.Linear(self.embed_dim, self.embed_dim)
267
+ self.v_proj = nn.Linear(self.embed_dim, self.embed_dim)
268
+ self.q_proj = nn.Linear(self.embed_dim, self.embed_dim)
269
+ self.out_proj = nn.Linear(self.embed_dim, self.embed_dim)
270
+
271
+ def forward(
272
+ self,
273
+ hidden_states: torch.Tensor,
274
+ cu_seqlens: torch.Tensor,
275
+ rotary_pos_emb: torch.Tensor = None,
276
+ ) -> torch.Tensor:
277
+ seq_length = hidden_states.shape[0]
278
+ q = self.q_proj(hidden_states)
279
+ k = self.k_proj(hidden_states)
280
+ v = self.v_proj(hidden_states)
281
+
282
+ # 将 q, k, v 重塑为多头注意力的形状
283
+ q = q.reshape(seq_length, self.num_heads, -1)
284
+ k = k.reshape(seq_length, self.num_heads, -1)
285
+ v = v.reshape(seq_length, self.num_heads, -1)
286
+
287
+ q = apply_rotary_pos_emb_vision(q.unsqueeze(0), rotary_pos_emb).squeeze(0)
288
+ k = apply_rotary_pos_emb_vision(k.unsqueeze(0), rotary_pos_emb).squeeze(0)
289
+
290
+ max_seqlen = (cu_seqlens[1:] - cu_seqlens[:-1]).max().item()
291
+ attn_output = flash_attn_varlen_func(
292
+ q, k, v, cu_seqlens, cu_seqlens, max_seqlen, max_seqlen
293
+ ).reshape(seq_length, -1)
294
+ attn_output = self.out_proj(attn_output)
295
+ return attn_output
296
+
297
+
298
+ class Siglip2SdpaAttention(nn.Module):
299
+
300
+ def __init__(self, config):
301
+ super().__init__()
302
+ self.config = config
303
+ self.embed_dim = config.hidden_size
304
+ self.num_heads = config.num_attention_heads
305
+ self.head_dim = self.embed_dim // self.num_heads
306
+ if self.head_dim * self.num_heads != self.embed_dim:
307
+ raise ValueError(
308
+ f"embed_dim must be divisible by num_heads (got `embed_dim`: {self.embed_dim} and `num_heads`:"
309
+ f" {self.num_heads})."
310
+ )
311
+ self.scale = self.head_dim**-0.5
312
+
313
+ self.k_proj = nn.Linear(self.embed_dim, self.embed_dim)
314
+ self.v_proj = nn.Linear(self.embed_dim, self.embed_dim)
315
+ self.q_proj = nn.Linear(self.embed_dim, self.embed_dim)
316
+ self.out_proj = nn.Linear(self.embed_dim, self.embed_dim)
317
+
318
+ def forward(
319
+ self,
320
+ hidden_states: torch.Tensor,
321
+ cu_seqlens: torch.Tensor,
322
+ rotary_pos_emb: torch.Tensor = None,
323
+ ) -> torch.Tensor:
324
+ seq_length = hidden_states.shape[0]
325
+ q = self.q_proj(hidden_states)
326
+ k = self.k_proj(hidden_states)
327
+ v = self.v_proj(hidden_states)
328
+
329
+ q = q.reshape(seq_length, self.num_heads, -1)
330
+ k = k.reshape(seq_length, self.num_heads, -1)
331
+ v = v.reshape(seq_length, self.num_heads, -1)
332
+
333
+ q = apply_rotary_pos_emb_vision(q.unsqueeze(0), rotary_pos_emb).squeeze(0)
334
+ k = apply_rotary_pos_emb_vision(k.unsqueeze(0), rotary_pos_emb).squeeze(0)
335
+
336
+ attention_mask = torch.zeros(
337
+ [1, seq_length, seq_length], device=q.device, dtype=torch.bool
338
+ )
339
+ for i in range(1, len(cu_seqlens)):
340
+ attention_mask[
341
+ ...,
342
+ cu_seqlens[i - 1] : cu_seqlens[i],
343
+ cu_seqlens[i - 1] : cu_seqlens[i],
344
+ ] = True
345
+ q = q.transpose(0, 1)
346
+ k = k.transpose(0, 1)
347
+ v = v.transpose(0, 1)
348
+ attn_output = F.scaled_dot_product_attention(
349
+ q.unsqueeze(0), k.unsqueeze(0), v.unsqueeze(0), attention_mask, dropout_p=0.0
350
+ )
351
+ attn_output = attn_output.squeeze(0).transpose(0, 1)
352
+ attn_output = attn_output.reshape(seq_length, -1)
353
+ attn_output = self.out_proj(attn_output)
354
+ return attn_output
355
+
356
+
357
+ VISION_ATTENTION_CLASSES = {
358
+ "eager": Siglip2Attention,
359
+ "flash_attention_2": Siglip2FlashAttention2,
360
+ "sdpa": Siglip2SdpaAttention,
361
+ }
362
+
363
+
364
+ class Siglip2EncoderLayer(nn.Module):
365
+ def __init__(self, config):
366
+ super().__init__()
367
+ self.embed_dim = config.hidden_size
368
+ self.self_attn = VISION_ATTENTION_CLASSES[config._attn_implementation](
369
+ config=config
370
+ )
371
+ self.layer_norm1 = nn.LayerNorm(self.embed_dim, eps=config.layer_norm_eps)
372
+ self.mlp = Siglip2MLP(config)
373
+ self.layer_norm2 = nn.LayerNorm(self.embed_dim, eps=config.layer_norm_eps)
374
+
375
+ # Ignore copy
376
+ def forward(self, hidden_states, cu_seqlens, rotary_pos_emb):
377
+ residual = hidden_states
378
+
379
+ hidden_states = self.layer_norm1(hidden_states)
380
+ hidden_states = self.self_attn(
381
+ hidden_states=hidden_states,
382
+ cu_seqlens=cu_seqlens,
383
+ rotary_pos_emb=rotary_pos_emb,
384
+ )
385
+ hidden_states = residual + hidden_states
386
+
387
+ residual = hidden_states
388
+ hidden_states = self.layer_norm2(hidden_states)
389
+ hidden_states = self.mlp(hidden_states)
390
+ hidden_states = residual + hidden_states
391
+
392
+ return hidden_states
393
+
394
+
395
+ class Siglip2Encoder(nn.Module):
396
+ """
397
+ Transformer encoder consisting of `config.num_hidden_layers` self attention layers. Each layer is a
398
+ [`Siglip2EncoderLayer`].
399
+
400
+ Args:
401
+ config: Siglip2Config
402
+ """
403
+
404
+ def __init__(self, config):
405
+ super().__init__()
406
+ self.config = config
407
+ self.layers = nn.ModuleList(
408
+ [Siglip2EncoderLayer(config) for _ in range(config.num_hidden_layers)]
409
+ )
410
+ self.gradient_checkpointing = True
411
+
412
+ # Ignore copy
413
+ def forward(
414
+ self,
415
+ hidden_states,
416
+ cu_seqlens,
417
+ rotary_pos_emb,
418
+ ):
419
+ for encoder_layer in self.layers:
420
+ if self.gradient_checkpointing and self.training:
421
+ hidden_states = torch.utils.checkpoint.checkpoint(
422
+ encoder_layer,
423
+ hidden_states,
424
+ cu_seqlens,
425
+ rotary_pos_emb,
426
+ use_reentrant=False,
427
+ )
428
+ else:
429
+ hidden_states = encoder_layer(
430
+ hidden_states,
431
+ cu_seqlens,
432
+ rotary_pos_emb,
433
+ )
434
+ return hidden_states
435
+
436
+
437
+ class Siglip2VisionTransformer(nn.Module):
438
+ def __init__(self, config: Siglip2VisionConfig):
439
+ super().__init__()
440
+ self.config = config
441
+ embed_dim = config.hidden_size
442
+
443
+ self.embeddings = PatchEmbed(
444
+ patch_size=config.patch_size,
445
+ num_channels=config.num_channels,
446
+ embed_dim=embed_dim,
447
+ num_patches=config.num_patches,
448
+ preserve_original_pe=config.preserve_original_pe,
449
+ )
450
+ head_dim = config.hidden_size // config.num_attention_heads
451
+ self.rotary_pos_emb = VisionRotaryEmbedding(head_dim // 2, config.rope_theta)
452
+ self.encoder = Siglip2Encoder(config)
453
+ self.post_layernorm = nn.LayerNorm(embed_dim, eps=config.layer_norm_eps)
454
+
455
+
456
+ def rot_pos_emb(self, grid_hw):
457
+ pos_ids = []
458
+ for h, w in grid_hw:
459
+ hpos_ids = torch.arange(h).unsqueeze(1).expand(-1, w)
460
+ hpos_ids = hpos_ids.reshape(
461
+ h // 2,
462
+ 2,
463
+ w // 2,
464
+ 2,
465
+ )
466
+ hpos_ids = hpos_ids.permute(0, 2, 1, 3)
467
+ hpos_ids = hpos_ids.flatten()
468
+
469
+ wpos_ids = torch.arange(w).unsqueeze(0).expand(h, -1)
470
+ wpos_ids = wpos_ids.reshape(
471
+ h // 2,
472
+ 2,
473
+ w // 2,
474
+ 2,
475
+ )
476
+ wpos_ids = wpos_ids.permute(0, 2, 1, 3)
477
+ wpos_ids = wpos_ids.flatten()
478
+ pos_ids.append(torch.stack([hpos_ids, wpos_ids], dim=-1))
479
+ pos_ids = torch.cat(pos_ids, dim=0)
480
+ max_grid_size = grid_hw.max()
481
+ rotary_pos_emb_full = self.rotary_pos_emb(max_grid_size)
482
+ rotary_pos_emb = rotary_pos_emb_full[pos_ids].flatten(1)
483
+ return rotary_pos_emb
484
+
485
+ def forward(
486
+ self,
487
+ hidden_states: torch.Tensor,
488
+ grid_hw: torch.Tensor,
489
+ ):
490
+ hidden_states = self.embeddings(hidden_states, grid_hw)
491
+ rotary_pos_emb = self.rot_pos_emb(grid_hw)
492
+ cu_seqlens = (grid_hw[:, 0] * grid_hw[:, 1]).cumsum(dim=0, dtype=torch.int32)
493
+ cu_seqlens = F.pad(cu_seqlens, (1, 0), value=0)
494
+ hidden_states = self.encoder(
495
+ hidden_states, cu_seqlens=cu_seqlens, rotary_pos_emb=rotary_pos_emb
496
+ )
497
+ hidden_states = self.post_layernorm(hidden_states)
498
+ return hidden_states
499
+
500
+
501
+ class Siglip2VisionModel(PreTrainedModel):
502
+ supports_gradient_checkpointing = True
503
+ _supports_flash_attn_2 = True
504
+ _supports_sdpa = True
505
+ config_class = Siglip2VisionConfig
506
+ main_input_name = "pixel_values"
507
+
508
+ def __init__(self, config):
509
+ super().__init__(config)
510
+ self.vision_model = Siglip2VisionTransformer(config)
511
+ # Initialize weights and apply final processing
512
+ self.post_init()
513
+
514
+ def get_input_embeddings(self) -> nn.Module:
515
+ return self.vision_model.embeddings.patch_embedding
516
+
517
+ def forward(
518
+ self, hidden_states: torch.Tensor, grid_hw: torch.Tensor
519
+ ) -> torch.Tensor:
520
+ return self.vision_model(hidden_states, grid_hw)
preprocessor_config.json ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "crop_size": {
3
+ "height": 448,
4
+ "width": 448
5
+ },
6
+ "do_center_crop": false,
7
+ "do_convert_rgb": true,
8
+ "do_normalize": true,
9
+ "do_rescale": true,
10
+ "do_resize": false,
11
+ "image_mean": [
12
+ 0.5,
13
+ 0.5,
14
+ 0.5
15
+ ],
16
+ "image_processor_type": "CLIPImageProcessor",
17
+ "image_std": [
18
+ 0.5,
19
+ 0.5,
20
+ 0.5
21
+ ],
22
+ "patch_size": 16,
23
+ "resample": 2,
24
+ "rescale_factor": 0.00392156862745098,
25
+ "size": {
26
+ "shortest_edge": 733
27
+ }
28
+ }
pytorch_model.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:38dd9c9cce255a4fb0434fa344aa51f238b4d85e699f59843c95cdb55a7d86ca
3
+ size 1701479779
special_tokens_map.json ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "additional_special_tokens": [
3
+ "<|im_start|>",
4
+ "<|im_end|>",
5
+ "<|object_ref_start|>",
6
+ "<|object_ref_end|>",
7
+ "<|box_start|>",
8
+ "<|box_end|>",
9
+ "<|quad_start|>",
10
+ "<|quad_end|>",
11
+ "<img>",
12
+ "</img>",
13
+ "<|vision_pad|>",
14
+ "<|image_pad|>",
15
+ "<|video_pad|>"
16
+ ],
17
+ "eos_token": {
18
+ "content": "<|im_end|>",
19
+ "lstrip": false,
20
+ "normalized": false,
21
+ "rstrip": false,
22
+ "single_word": false
23
+ },
24
+ "pad_token": {
25
+ "content": "<|endoftext|>",
26
+ "lstrip": false,
27
+ "normalized": false,
28
+ "rstrip": false,
29
+ "single_word": false
30
+ }
31
+ }
tokenizer.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0e0d3ee707b399f44f189e1abfb2b3cd844b96407e9b2a5a21cb3e0b5f57bb05
3
+ size 11422629
tokenizer_config.json ADDED
@@ -0,0 +1,239 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_bos_token": false,
3
+ "add_prefix_space": false,
4
+ "added_tokens_decoder": {
5
+ "151643": {
6
+ "content": "<|endoftext|>",
7
+ "lstrip": false,
8
+ "normalized": false,
9
+ "rstrip": false,
10
+ "single_word": false,
11
+ "special": true
12
+ },
13
+ "151644": {
14
+ "content": "<|im_start|>",
15
+ "lstrip": false,
16
+ "normalized": false,
17
+ "rstrip": false,
18
+ "single_word": false,
19
+ "special": true
20
+ },
21
+ "151645": {
22
+ "content": "<|im_end|>",
23
+ "lstrip": false,
24
+ "normalized": false,
25
+ "rstrip": false,
26
+ "single_word": false,
27
+ "special": true
28
+ },
29
+ "151646": {
30
+ "content": "<|object_ref_start|>",
31
+ "lstrip": false,
32
+ "normalized": false,
33
+ "rstrip": false,
34
+ "single_word": false,
35
+ "special": true
36
+ },
37
+ "151647": {
38
+ "content": "<|object_ref_end|>",
39
+ "lstrip": false,
40
+ "normalized": false,
41
+ "rstrip": false,
42
+ "single_word": false,
43
+ "special": true
44
+ },
45
+ "151648": {
46
+ "content": "<|box_start|>",
47
+ "lstrip": false,
48
+ "normalized": false,
49
+ "rstrip": false,
50
+ "single_word": false,
51
+ "special": true
52
+ },
53
+ "151649": {
54
+ "content": "<|box_end|>",
55
+ "lstrip": false,
56
+ "normalized": false,
57
+ "rstrip": false,
58
+ "single_word": false,
59
+ "special": true
60
+ },
61
+ "151650": {
62
+ "content": "<|quad_start|>",
63
+ "lstrip": false,
64
+ "normalized": false,
65
+ "rstrip": false,
66
+ "single_word": false,
67
+ "special": true
68
+ },
69
+ "151651": {
70
+ "content": "<|quad_end|>",
71
+ "lstrip": false,
72
+ "normalized": false,
73
+ "rstrip": false,
74
+ "single_word": false,
75
+ "special": true
76
+ },
77
+ "151652": {
78
+ "content": "<img>",
79
+ "lstrip": false,
80
+ "normalized": false,
81
+ "rstrip": false,
82
+ "single_word": false,
83
+ "special": true
84
+ },
85
+ "151653": {
86
+ "content": "</img>",
87
+ "lstrip": false,
88
+ "normalized": false,
89
+ "rstrip": false,
90
+ "single_word": false,
91
+ "special": true
92
+ },
93
+ "151654": {
94
+ "content": "<|vision_pad|>",
95
+ "lstrip": false,
96
+ "normalized": false,
97
+ "rstrip": false,
98
+ "single_word": false,
99
+ "special": true
100
+ },
101
+ "151655": {
102
+ "content": "<|image_pad|>",
103
+ "lstrip": false,
104
+ "normalized": false,
105
+ "rstrip": false,
106
+ "single_word": false,
107
+ "special": true
108
+ },
109
+ "151656": {
110
+ "content": "<|video_pad|>",
111
+ "lstrip": false,
112
+ "normalized": false,
113
+ "rstrip": false,
114
+ "single_word": false,
115
+ "special": true
116
+ },
117
+ "151657": {
118
+ "content": "<tool_call>",
119
+ "lstrip": false,
120
+ "normalized": false,
121
+ "rstrip": false,
122
+ "single_word": false,
123
+ "special": false
124
+ },
125
+ "151658": {
126
+ "content": "</tool_call>",
127
+ "lstrip": false,
128
+ "normalized": false,
129
+ "rstrip": false,
130
+ "single_word": false,
131
+ "special": false
132
+ },
133
+ "151659": {
134
+ "content": "<|fim_prefix|>",
135
+ "lstrip": false,
136
+ "normalized": false,
137
+ "rstrip": false,
138
+ "single_word": false,
139
+ "special": false
140
+ },
141
+ "151660": {
142
+ "content": "<|fim_middle|>",
143
+ "lstrip": false,
144
+ "normalized": false,
145
+ "rstrip": false,
146
+ "single_word": false,
147
+ "special": false
148
+ },
149
+ "151661": {
150
+ "content": "<|fim_suffix|>",
151
+ "lstrip": false,
152
+ "normalized": false,
153
+ "rstrip": false,
154
+ "single_word": false,
155
+ "special": false
156
+ },
157
+ "151662": {
158
+ "content": "<|fim_pad|>",
159
+ "lstrip": false,
160
+ "normalized": false,
161
+ "rstrip": false,
162
+ "single_word": false,
163
+ "special": false
164
+ },
165
+ "151663": {
166
+ "content": "<|repo_name|>",
167
+ "lstrip": false,
168
+ "normalized": false,
169
+ "rstrip": false,
170
+ "single_word": false,
171
+ "special": false
172
+ },
173
+ "151664": {
174
+ "content": "<|file_sep|>",
175
+ "lstrip": false,
176
+ "normalized": false,
177
+ "rstrip": false,
178
+ "single_word": false,
179
+ "special": false
180
+ },
181
+ "151665": {
182
+ "content": "<tool_response>",
183
+ "lstrip": false,
184
+ "normalized": false,
185
+ "rstrip": false,
186
+ "single_word": false,
187
+ "special": false
188
+ },
189
+ "151666": {
190
+ "content": "</tool_response>",
191
+ "lstrip": false,
192
+ "normalized": false,
193
+ "rstrip": false,
194
+ "single_word": false,
195
+ "special": false
196
+ },
197
+ "151667": {
198
+ "content": "<think>",
199
+ "lstrip": false,
200
+ "normalized": false,
201
+ "rstrip": false,
202
+ "single_word": false,
203
+ "special": false
204
+ },
205
+ "151668": {
206
+ "content": "</think>",
207
+ "lstrip": false,
208
+ "normalized": false,
209
+ "rstrip": false,
210
+ "single_word": false,
211
+ "special": false
212
+ }
213
+ },
214
+ "additional_special_tokens": [
215
+ "<|im_start|>",
216
+ "<|im_end|>",
217
+ "<|object_ref_start|>",
218
+ "<|object_ref_end|>",
219
+ "<|box_start|>",
220
+ "<|box_end|>",
221
+ "<|quad_start|>",
222
+ "<|quad_end|>",
223
+ "<img>",
224
+ "</img>",
225
+ "<|vision_pad|>",
226
+ "<|image_pad|>",
227
+ "<|video_pad|>"
228
+ ],
229
+ "bos_token": null,
230
+ "clean_up_tokenization_spaces": false,
231
+ "eos_token": "<|im_end|>",
232
+ "errors": "replace",
233
+ "extra_special_tokens": {},
234
+ "model_max_length": 131072,
235
+ "pad_token": "<|endoftext|>",
236
+ "split_special_tokens": false,
237
+ "tokenizer_class": "Qwen2Tokenizer",
238
+ "unk_token": null
239
+ }
vocab.json ADDED
The diff for this file is too large to render. See raw diff