Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9b9c427

Browse files
committed
fix
1 parent 3d977d6 commit 9b9c427

6 files changed

Lines changed: 134 additions & 71 deletions

File tree

‎src/transformers/conversion_mapping.py‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,55 @@
8484

8585
def _build_checkpoint_conversion_mapping():
8686
mapping = {
87+
# fmt: off
88+
# Mapping for old InternVL2-1B/2B checkpoints (model_type="internvl_chat").
89+
# These use different weight key names than the native InternVLForConditionalGeneration.
90+
# Note: InternVL2-2B (Llama/InternLM2 backbone) uses a fused GQA attention.wqkv weight
91+
# that cannot be split automatically; users with InternVL2-2B should use the conversion script.
92+
"internvl_chat": [
93+
# MLP projector: mlp1.{0,1,3} → model.multi_modal_projector.{layer_norm,linear_1,linear_2}
94+
WeightRenaming(r"^mlp1\.0\.", "model.multi_modal_projector.layer_norm."),
95+
WeightRenaming(r"^mlp1\.1\.", "model.multi_modal_projector.linear_1."),
96+
WeightRenaming(r"^mlp1\.3\.", "model.multi_modal_projector.linear_2."),
97+
# Vision encoder prefix: vision_model → model.vision_tower
98+
WeightRenaming(r"^vision_model\.", "model.vision_tower."),
99+
# Vision encoder: encoder.layers → encoder.layer
100+
WeightRenaming(r"\.encoder\.layers\.", ".encoder.layer."),
101+
# Vision embeddings: old names → new names
102+
WeightRenaming(r"\.class_embedding", ".cls_token"),
103+
WeightRenaming(r"\.position_embedding", ".position_embeddings"),
104+
WeightRenaming(r"\.patch_embedding\.", ".patch_embeddings.projection."),
105+
# Vision layer scale: ls1/ls2 → lambda_1/lambda_2
106+
WeightRenaming(r"\.ls1$", ".lambda_1"),
107+
WeightRenaming(r"\.ls2$", ".lambda_2"),
108+
# Vision attention: specific patterns must come before generic .attn. rename
109+
WeightRenaming(r"\.attn\.proj\.", ".attention.projection_layer."),
110+
WeightRenaming(r"\.attn\.dropout\b", ".attention.projection_dropout"),
111+
WeightRenaming(r"\.attn\.", ".attention."),
112+
# Vision layer norms
113+
WeightRenaming(r"\.norm1\.", ".layernorm_before."),
114+
WeightRenaming(r"\.norm2\.", ".layernorm_after."),
115+
# Language model prefix (Qwen2: language_model.model.* → model.language_model.*)
116+
WeightRenaming(r"^language_model\.model\.", "model.language_model."),
117+
WeightRenaming(r"^language_model\.lm_head\.", "lm_head."),
118+
# Language model head (Llama/InternLM2: language_model.output → lm_head)
119+
WeightRenaming(r"^language_model\.output\.", "lm_head."),
120+
# Llama/InternLM2 LM weight renames (applied after prefix rename above)
121+
WeightRenaming(r"\.tok_embeddings\.", ".embed_tokens."),
122+
WeightRenaming(r"\.attention\.wo\.", ".self_attn.o_proj."),
123+
WeightRenaming(r"\.feed_forward\.w1\.", ".mlp.gate_proj."),
124+
WeightRenaming(r"\.feed_forward\.w2\.", ".mlp.down_proj."),
125+
WeightRenaming(r"\.feed_forward\.w3\.", ".mlp.up_proj."),
126+
WeightRenaming(r"\.attention_norm\.", ".input_layernorm."),
127+
WeightRenaming(r"\.ffn_norm\.", ".post_attention_layernorm."),
128+
# Vision QKV: fused attn.qkv → separate q_proj, k_proj, v_proj (applied after .attn. rename)
129+
WeightConverter(
130+
source_patterns=r"\.attention\.qkv\.",
131+
target_patterns=[".attention.q_proj.", ".attention.k_proj.", ".attention.v_proj."],
132+
operations=[Chunk(dim=0)],
133+
),
134+
],
135+
# fmt: on
87136
"llava": [
88137
WeightRenaming(source_patterns=r"language_model.model", target_patterns="language_model"),
89138
WeightRenaming(source_patterns=r"language_model.lm_head", target_patterns="lm_head"),

‎src/transformers/models/auto/configuration_auto.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@
233233
("instructblip", "InstructBlipConfig"),
234234
("instructblipvideo", "InstructBlipVideoConfig"),
235235
("internvl", "InternVLConfig"),
236+
("internvl_chat", "InternVLConfig"),
236237
("internvl_vision", "InternVLVisionConfig"),
237238
("jais2", "Jais2Config"),
238239
("jamba", "JambaConfig"),
@@ -746,6 +747,7 @@
746747
("instructblip", "InstructBLIP"),
747748
("instructblipvideo", "InstructBlipVideo"),
748749
("internvl", "InternVL"),
750+
("internvl_chat", "InternVL"),
749751
("internvl_vision", "InternVLVision"),
750752
("jais2", "Jais2"),
751753
("jamba", "Jamba"),
@@ -1115,6 +1117,7 @@
11151117
("rt_detr_resnet", "rt_detr"),
11161118
("granitevision", "llava_next"),
11171119
("internvl_vision", "internvl"),
1120+
("internvl_chat", "internvl"),
11181121
("qwen2_5_vl_text", "qwen2_5_vl"),
11191122
("qwen2_vl_text", "qwen2_vl"),
11201123
("qwen3_vl_text", "qwen3_vl"),

‎src/transformers/models/auto/modeling_auto.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ class _BaseModelWithGenerate(PreTrainedModel, GenerationMixin):
230230
("instructblip", "InstructBlipModel"),
231231
("instructblipvideo", "InstructBlipVideoModel"),
232232
("internvl", "InternVLModel"),
233+
("internvl_chat", "InternVLModel"),
233234
("internvl_vision", "InternVLVisionModel"),
234235
("jais2", "Jais2Model"),
235236
("jamba", "JambaModel"),
@@ -978,6 +979,7 @@ class _BaseModelWithGenerate(PreTrainedModel, GenerationMixin):
978979
("instructblip", "InstructBlipForConditionalGeneration"),
979980
("instructblipvideo", "InstructBlipVideoForConditionalGeneration"),
980981
("internvl", "InternVLForConditionalGeneration"),
982+
("internvl_chat", "InternVLForConditionalGeneration"),
981983
("janus", "JanusForConditionalGeneration"),
982984
("kosmos-2", "Kosmos2ForConditionalGeneration"),
983985
("kosmos-2.5", "Kosmos2_5ForConditionalGeneration"),

‎src/transformers/models/auto/tokenization_auto.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@
160160
("instructblip", "GPT2Tokenizer" if is_tokenizers_available() else None),
161161
("instructblipvideo", "GPT2Tokenizer" if is_tokenizers_available() else None),
162162
("internvl", "Qwen2Tokenizer" if is_tokenizers_available() else None),
163+
("internvl_chat", "Qwen2Tokenizer" if is_tokenizers_available() else None),
163164
("jais2", "GPT2Tokenizer" if is_tokenizers_available() else None),
164165
("jina_embeddings_v3", "XLMRobertaTokenizer" if is_tokenizers_available() else None),
165166
("kosmos-2", "XLMRobertaTokenizer" if is_tokenizers_available() else None),

‎src/transformers/models/internvl/configuration_internvl.py‎

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222

2323
@auto_docstring(checkpoint="OpenGVLab/InternVL3-1B-hf")
24-
@strict
24+
@strict(accept_kwargs=True)
2525
class InternVLVisionConfig(PreTrainedConfig):
2626
r"""
2727
projection_dropout (`float`, *optional*, defaults to 0.0):
@@ -84,7 +84,7 @@ def __post_init__(self, **kwargs):
8484

8585

8686
@auto_docstring(checkpoint="OpenGVLab/InternVL3-1B-hf")
87-
@strict
87+
@strict(accept_kwargs=True)
8888
class InternVLConfig(PreTrainedConfig):
8989
r"""
9090
downsample_ratio (`float`, *optional*, defaults to 0.5):
@@ -132,5 +132,54 @@ def __post_init__(self, **kwargs):
132132

133133
super().__post_init__(**kwargs)
134134

135+
@classmethod
136+
def from_dict(cls, config_dict, **kwargs):
137+
# Handle old InternVL2 checkpoints with model_type="internvl_chat"
138+
if config_dict.get("model_type") == "internvl_chat":
139+
config_dict = cls._remap_old_internvl_chat_config(config_dict)
140+
return super().from_dict(config_dict, **kwargs)
141+
142+
@classmethod
143+
def _remap_old_internvl_chat_config(cls, config_dict):
144+
"""Map old InternVL2 (internvl_chat) config fields to current InternVLConfig fields."""
145+
config_dict = dict(config_dict)
146+
# Remove auto_map so the native class is used instead of remote code.
147+
# Do NOT change model_type here: keeping it as "internvl_chat" allows the runtime
148+
# weight-renaming in conversion_mapping.py to be looked up by model.config.model_type.
149+
config_dict.pop("auto_map", None)
150+
151+
# llm_config → text_config
152+
if "llm_config" in config_dict and "text_config" not in config_dict:
153+
config_dict["text_config"] = config_dict.pop("llm_config")
154+
elif "llm_config" in config_dict:
155+
config_dict.pop("llm_config")
156+
157+
# select_layer → vision_feature_layer
158+
if "select_layer" in config_dict and "vision_feature_layer" not in config_dict:
159+
config_dict["vision_feature_layer"] = config_dict.pop("select_layer")
160+
elif "select_layer" in config_dict:
161+
config_dict.pop("select_layer")
162+
163+
# force_image_size → vision_config.image_size (if not already set)
164+
if "force_image_size" in config_dict:
165+
force_image_size = config_dict.pop("force_image_size")
166+
vision_config = config_dict.get("vision_config")
167+
if isinstance(vision_config, dict):
168+
vision_config.setdefault("image_size", force_image_size)
169+
170+
# Remap old vision sub-config field names
171+
vision_config = config_dict.get("vision_config")
172+
if isinstance(vision_config, dict):
173+
if "attention_probs_dropout_prob" in vision_config:
174+
dropout = vision_config.pop("attention_probs_dropout_prob")
175+
vision_config.setdefault("attention_dropout", dropout)
176+
vision_config.setdefault("projection_dropout", dropout)
177+
if "qk_normalization" in vision_config:
178+
vision_config["use_qk_norm"] = vision_config.pop("qk_normalization")
179+
if "qkv_bias" in vision_config:
180+
vision_config["attention_bias"] = vision_config.pop("qkv_bias")
181+
182+
return config_dict
183+
135184

136185
__all__ = ["InternVLVisionConfig", "InternVLConfig"]

‎src/transformers/models/internvl/convert_internvl_weights_to_hf.py‎

Lines changed: 28 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,9 @@
2727
AutoTokenizer,
2828
GenerationConfig,
2929
GotOcr2ImageProcessor,
30-
InternVLConfig,
3130
InternVLForConditionalGeneration,
3231
InternVLProcessor,
3332
InternVLVideoProcessor,
34-
InternVLVisionConfig,
35-
LlamaConfig,
36-
Qwen2Config,
3733
)
3834
from transformers.utils import SAFE_WEIGHTS_INDEX_NAME, SAFE_WEIGHTS_NAME, WEIGHTS_INDEX_NAME, WEIGHTS_NAME
3935

@@ -57,8 +53,6 @@
5753
"OpenGVLab/InternVL3-78B": "qwen2",
5854
}
5955

60-
UNNECESSARY_CONFIG_KEYS = [ "_name_or_path", "_attn_implementation_autoset", "auto_map", "use_bfloat16", "use_flash_attn", "bias", "laux_allreduce", "moe_coeff_ratio", "moe_intermediate_size", "moe_output_scale", "noisy_gate_policy", "shared_expert_intermediate_size", "use_residual", "use_moe", "use_rts", "use_weighted_residual", "moe_config", "num_experts", "num_routed_experts", "num_shared_experts", "capacity_factor", "eval_capacity_factor", "drop_path_rate"] # fmt: skip
61-
6256
# fmt: off
6357
ORIGINAL_TO_CONVERTED_KEY_MAPPING_VISION = {
6458
# Vision encoder mapping
@@ -127,19 +121,12 @@
127121
# fmt: on
128122

129123
CONTEXT_LENGTH = 8192
124+
# Old InternVL2-1B/2B checkpoints use a different tokenizer base than newer models.
130125
OLD_INTERNVL2_CHECKPOINTS = {"OpenGVLab/InternVL2-1B", "OpenGVLab/InternVL2-2B"}
131126
OLD_INTERNVL2_QWEN2_CHECKPOINTS = {"OpenGVLab/InternVL2-1B"}
132127
BASE_SPECIAL_TOKENS = ["<img>", "</img>", "<IMG_CONTEXT>", "<quad>", "</quad>", "<ref>", "</ref>", "<box>", "</box>"]
133128

134129

135-
def is_old_internvl2_checkpoint(path: str | None) -> bool:
136-
return path in OLD_INTERNVL2_CHECKPOINTS
137-
138-
139-
def get_original_config(path: str):
140-
return AutoConfig.from_pretrained(path, trust_remote_code=True)
141-
142-
143130
def get_tokenizer_base_model(path: str) -> tuple[str, bool]:
144131
if path in OLD_INTERNVL2_QWEN2_CHECKPOINTS:
145132
return "Qwen/Qwen2-0.5B-Instruct", False
@@ -155,7 +142,7 @@ def get_tokenizer_special_tokens(path: str) -> tuple[list[str], dict[str, str]]:
155142
"end_image_token": "</img>",
156143
"context_image_token": "<IMG_CONTEXT>",
157144
}
158-
if not is_old_internvl2_checkpoint(path):
145+
if path not in OLD_INTERNVL2_CHECKPOINTS:
159146
special_tokens.append("<video>")
160147
model_specific_tokens["video_token"] = "<video>"
161148

@@ -225,22 +212,17 @@ def get_lm_type(path: str) -> Literal["qwen2", "llama"]:
225212
Determine the type of language model (either 'qwen2' or 'llama') based on a given model path.
226213
"""
227214
if path not in LM_TYPE_CORRESPONDENCE:
228-
base_config = get_original_config(path)
229-
230-
lm_arch = base_config.llm_config.architectures[0]
231-
232-
if lm_arch == "InternLM2ForCausalLM":
233-
lm_type = "llama"
234-
elif lm_arch == "Qwen2ForCausalLM":
235-
lm_type = "qwen2"
215+
config = AutoConfig.from_pretrained(path)
216+
text_model_type = config.text_config.model_type
217+
if text_model_type == "qwen2":
218+
return "qwen2"
219+
elif text_model_type in ("llama",):
220+
return "llama"
236221
else:
237222
raise ValueError(
238-
f"Architecture '{lm_arch}' is not supported. Only 'Qwen2ForCausalLM' and 'InternLM2ForCausalLM' are recognized."
223+
f"Text model type '{text_model_type}' is not supported. Only 'qwen2' and 'llama' are recognized."
239224
)
240-
else:
241-
lm_type: Literal["qwen2", "llama"] = LM_TYPE_CORRESPONDENCE[path]
242-
243-
return lm_type
225+
return LM_TYPE_CORRESPONDENCE[path]
244226

245227

246228
def convert_old_keys_to_new_keys(state_dict_keys: dict | None = None, path: str | None = None):
@@ -291,52 +273,30 @@ def load_original_state_dict(input_base_path):
291273

292274

293275
def get_internvl_config(input_base_path):
294-
base_config = get_original_config(input_base_path)
276+
# Load the config natively — InternVL2 (internvl_chat) configs are remapped automatically.
277+
config = AutoConfig.from_pretrained(input_base_path)
295278
tokenizer = build_tokenizer(input_base_path)
296-
llm_config = base_config.llm_config.to_dict()
297-
vision_config = base_config.vision_config.to_dict()
298-
vision_config["use_absolute_position_embeddings"] = True
299-
if get_lm_type(input_base_path) == "qwen2":
300-
language_config_class = Qwen2Config
301-
else:
302-
language_config_class = LlamaConfig
303279

304-
image_size = getattr(base_config, "force_image_size", None) or vision_config["image_size"]
305-
patch_size = vision_config["patch_size"]
306-
if isinstance(image_size, list | tuple):
280+
# Fix image_token_id from the actual tokenizer built for this checkpoint.
281+
config.image_token_id = tokenizer.context_image_token_id
282+
283+
# Recompute image_seq_length from the resolved image_size and downsample_ratio.
284+
image_size = config.vision_config.image_size
285+
patch_size = config.vision_config.patch_size
286+
if isinstance(image_size, (list, tuple)):
307287
image_size = image_size[0]
308-
if isinstance(patch_size, list | tuple):
288+
if isinstance(patch_size, (list, tuple)):
309289
patch_size = patch_size[0]
310-
image_seq_length = int((image_size // patch_size) ** 2 * (base_config.downsample_ratio**2))
290+
config.image_seq_length = int((image_size // patch_size) ** 2 * config.downsample_ratio**2)
311291

312-
llm_config = {k: v for k, v in llm_config.items() if k not in UNNECESSARY_CONFIG_KEYS}
313-
# Force use_cache to True
314-
llm_config["use_cache"] = True
315-
# Force correct eos_token_id for InternVL3
292+
# Force use_cache to True for generation.
293+
config.text_config.use_cache = True
294+
# Force correct eos_token_id for InternVL3 Qwen2 models.
316295
if "InternVL3" in input_base_path and get_lm_type(input_base_path) == "qwen2":
317-
llm_config["eos_token_id"] = 151645
318-
319-
vision_config = {k: v for k, v in vision_config.items() if k not in UNNECESSARY_CONFIG_KEYS}
320-
if "attention_probs_dropout_prob" in vision_config:
321-
attention_dropout = vision_config.pop("attention_probs_dropout_prob")
322-
vision_config["attention_dropout"] = attention_dropout
323-
vision_config["projection_dropout"] = attention_dropout
324-
if "qk_normalization" in vision_config:
325-
use_qk_norm = vision_config.pop("qk_normalization")
326-
vision_config["use_qk_norm"] = use_qk_norm
327-
if "qkv_bias" in vision_config:
328-
attention_bias = vision_config.pop("qkv_bias")
329-
vision_config["attention_bias"] = attention_bias
330-
331-
return InternVLConfig(
332-
text_config=language_config_class(**llm_config),
333-
vision_config=InternVLVisionConfig(**vision_config),
334-
image_token_id=tokenizer.context_image_token_id,
335-
image_seq_length=image_seq_length,
336-
downsample_ratio=base_config.downsample_ratio,
337-
vision_feature_layer=getattr(base_config, "select_layer", -1),
338-
tie_word_embeddings=getattr(base_config, "tie_word_embeddings", llm_config.get("tie_word_embeddings", True)),
339-
)
296+
config.text_config.eos_token_id = 151645
297+
298+
config.architectures = ["InternVLForConditionalGeneration"]
299+
return config
340300

341301

342302
def write_model(
@@ -348,7 +308,6 @@ def write_model(
348308
os.makedirs(model_path, exist_ok=True)
349309

350310
config = get_internvl_config(input_base_path)
351-
config.architectures = ["InternVLForConditionalGeneration"]
352311
config.save_pretrained(model_path)
353312
if push_to_hub:
354313
model_name = (hub_dir or model_path).split(os.path.sep)[-1]

0 commit comments

Comments
 (0)