Skip to content

Commit cc66ee9

Browse files
authored
Merge branch 'develop' into feat/add-granite-model
2 parents a41534e + ab92762 commit cc66ee9

28 files changed

Lines changed: 5591 additions & 13 deletions

File tree

paddleformers/cli/utils/llm_utils.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,17 @@ def get_lora_target_modules(model):
440440
"model.visual.blocks.*mlp.up_proj.*",
441441
"model.visual.blocks.*mlp.down_proj.*",
442442
]
443+
elif model.config.model_type == "internlm2":
444+
# Covers both InternLM2 2.0 and 2.5: both route through the unified
445+
# `intern/` proxy with `model_type = "internlm2"` and share the same
446+
# weight key names (wqkv/wo/w1/w2/w3).
447+
target_modules = [
448+
".*wqkv.*",
449+
".*wo.*",
450+
".*w1.*",
451+
".*w2.*",
452+
".*w3.*",
453+
]
443454
else:
444455
raise ValueError(f"Unknown base_model_prefix: {model.config.model_type}.")
445456
return target_modules

paddleformers/datasets/template/template.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,3 +1004,28 @@ def _get_gpt_oss_prefix():
10041004
chat_sep="<|assistant|>\n",
10051005
mm_plugin=get_mm_plugin(name="glm_ocr", image_token="<|image|>"),
10061006
)
1007+
register_template(
1008+
name="internlm2_5",
1009+
format_user=StringFormatter(slots=["<|im_start|>user\n{{content}}<|im_end|>\n<|im_start|>assistant\n"]),
1010+
format_assistant=StringFormatter(slots=["{{content}}<|im_end|>\n"]),
1011+
format_system=StringFormatter(slots=["<|im_start|>system\n{{content}}<|im_end|>\n"]),
1012+
format_prefix=EmptyFormatter(slots=["<s>"]),
1013+
chat_sep="<|im_end|>\n",
1014+
suffix=["<|im_end|>\n"],
1015+
enable_thinking=None,
1016+
)
1017+
1018+
1019+
register_template(
1020+
name="gemma4",
1021+
format_user=StringFormatter(slots=["<|turn>user\n{{content}}<turn|>\n<|turn>model\n"]),
1022+
format_assistant=StringFormatter(slots=["{{content}}"]),
1023+
format_system=StringFormatter(slots=["<|turn>system\n{{content}}<turn|>\n"]),
1024+
format_observation=StringFormatter(slots=["<|turn>tool\n{{content}}<turn|>\n<|turn>model\n"]),
1025+
format_prefix=EmptyFormatter(slots=[{"bos_token"}]),
1026+
chat_sep="<turn|>\n",
1027+
suffix=["<turn|>"],
1028+
stop_words=["<turn|>"],
1029+
thought_words=("<|channel>thought\n", "\n<channel|>"),
1030+
template_class=Llama2Template,
1031+
)

paddleformers/transformers/__init__.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,30 @@
360360
],
361361
"glm_ocr.processor": ["Glm46VProcessor"],
362362
"glm_ocr.image_processor": ["Glm46VImageProcessor"],
363+
"intern_lm2_5.configuration": ["InternLM25Config"],
364+
"intern_lm2_5.modeling": [
365+
"InternLM25DecoderLayer",
366+
"InternLM25Model",
367+
"InternLM25ForCausalLM",
368+
"InternLM25PretrainedModel",
369+
"InternLM25ForSequenceClassification",
370+
"InternLM25ForQuestionAnswering",
371+
"InternLM25ForTokenClassification",
372+
],
373+
"intern_lm2_5.tokenizer": ["InternLM25Tokenizer"],
374+
"intern.configuration": ["InternLM2Config"],
375+
"intern.modeling": [
376+
"InternLM2PretrainedModel",
377+
"InternLM2Model",
378+
"InternLM2ForCausalLM",
379+
"InternLM2ForSequenceClassification",
380+
"InternLM2ForQuestionAnswering",
381+
"InternLM2ForTokenClassification",
382+
],
383+
"intern_lm2.tokenizer": ["InternLM2Tokenizer"],
384+
"gemma4_moe.configuration": ["Gemma4MoeConfig"],
385+
"gemma4_moe.modeling": ["Gemma4MoeForCausalLM"],
386+
"gemma4_moe": [],
363387
"phi4.configuration": ["Phi4Config"],
364388
"phi4.modeling": ["Phi4Model", "Phi4ForCausalLM"],
365389
"phi4.tokenizer": ["Phi4Tokenizer"],
@@ -444,6 +468,10 @@
444468
from .phi3 import *
445469
from .gemma3_text import *
446470
from .glm_ocr import *
471+
from .intern_lm2_5 import *
472+
from .intern import *
473+
from .intern_lm2 import InternLM2Tokenizer
474+
from .gemma4_moe import *
447475
from .phi4 import *
448476
else:
449477
sys.modules[__name__] = _LazyModule(

paddleformers/transformers/auto/configuration.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@
6666
("glm_ocr", "GlmOcrConfig"),
6767
("qwen3_5", "Qwen3_5Config"),
6868
("qwen3_5_moe", "Qwen3_5MoEConfig"),
69+
("internlm2", "InternLM2Config"),
70+
# TODO(VL): When Gemma4 VL is implemented, "gemma4" should point to Gemma4Config (VL wrapper)
71+
("gemma4_text", "Gemma4MoeConfig"),
72+
("gemma4", "Gemma4MoeConfig"), # Temporary: no standalone text ckpt, extract text_config in from_dict
6973
("phi4", "Phi4Config"),
7074
("phi4flash", "Phi4Config"),
7175
]
@@ -99,6 +103,10 @@
99103
("minicpm", "MiniCPM"),
100104
("qwen3_5_moe", "Qwen3_5MoEForConditionalGeneration"),
101105
("qwen3_5", "Qwen3_5ForConditionalGeneration"),
106+
("internlm2", "InternLM2"),
107+
("gemma4_moe", "Gemma4MoeForCausalLM"),
108+
("gemma4_text", "Gemma4MoeForCausalLM"),
109+
("gemma4", "Gemma4MoeForCausalLM"),
102110
("phi4", "Phi4ForCausalLM"),
103111
("phi4flash", "Phi4ForCausalLM"),
104112
]
@@ -115,6 +123,10 @@
115123
("qwen3_vl_text", "qwen3_vl"),
116124
("qwen3_vl_moe_text", "qwen3_vl_moe"),
117125
("granitemoehybrid", "granite"),
126+
("internlm2", "intern"),
127+
# TODO(VL): Remove these when Gemma4 VL module (gemma4/) is created
128+
("gemma4_text", "gemma4_moe"),
129+
("gemma4", "gemma4_moe"),
118130
("phi4flash", "phi4"),
119131
]
120132
)

paddleformers/transformers/auto/modeling.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,10 @@
8282
("Phi3", "phi3"),
8383
("Phi4", "phi4"),
8484
("Gemma3", "gemma3_text"),
85+
("Gemma4Moe", "gemma4_moe"),
8586
("Glm4vMoe", "glm4v_moe"),
8687
("GlmOcr", "glm_ocr"),
88+
("InternLM2", "intern"),
8789
]
8890
)
8991

paddleformers/transformers/deepseek_v4/modeling.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ def _moe_experts(matrix_3d_global, ortho_fn):
142142
moe_grouped_gemm = getattr(config, "moe_grouped_gemm", False)
143143
use_gated_attn = getattr(config, "use_gated_attn", False)
144144
csa_compress_ratios = getattr(config, "csa_compress_ratios", None)
145+
num_empty_layers_add_in_head = getattr(config, "num_empty_layers_add_in_head", 0)
145146

146147
# Get Muon configuration from muon_configs
147148
muon_qkv_update_mode = muon_configs.get("muon_qkv_update_mode", "split_head")
@@ -293,18 +294,25 @@ def _add_layer_slice_config(prefix, layer_idx):
293294

294295
# Main layers
295296
for layer_idx in range(num_hidden_layers):
296-
_add_layer_slice_config(f"model.layers.{layer_idx}", layer_idx)
297+
_add_layer_slice_config(
298+
f"model.layers.{layer_idx + num_empty_layers_add_in_head}",
299+
layer_idx,
300+
)
297301

298302
# MTP layers
299303
if config.mtp_num_layers > 0:
300304
num_nextn_predict_layers = config.mtp_num_layers
301305
else:
302306
num_nextn_predict_layers = config.num_nextn_predict_layers if config.num_nextn_predict_layers else 0
303307
for layer_idx in range(num_nextn_predict_layers):
304-
_add_layer_slice_config(f"model.layers.{num_hidden_layers + layer_idx}", num_hidden_layers + layer_idx)
308+
_add_layer_slice_config(
309+
f"model.layers.{num_hidden_layers + num_empty_layers_add_in_head + layer_idx}",
310+
num_hidden_layers + layer_idx,
311+
)
305312
for layer_idx in range(num_nextn_predict_layers):
306313
_add_layer_slice_config(
307-
f"model.layers.{num_hidden_layers + layer_idx}.transformer_layer", num_hidden_layers + layer_idx
314+
f"model.layers.{num_hidden_layers + num_empty_layers_add_in_head + layer_idx}.transformer_layer",
315+
num_hidden_layers + layer_idx,
308316
)
309317

310318
return slice_config
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
import sys
15+
from typing import TYPE_CHECKING
16+
17+
from ...utils.lazy_import import _LazyModule
18+
19+
import_structure = {
20+
"configuration": ["Gemma4MoeConfig"],
21+
"modeling": [
22+
"Gemma4MoeForCausalLM",
23+
],
24+
}
25+
26+
if TYPE_CHECKING:
27+
from .configuration import *
28+
from .modeling import *
29+
else:
30+
sys.modules[__name__] = _LazyModule(
31+
__name__,
32+
globals()["__file__"],
33+
import_structure,
34+
module_spec=__spec__,
35+
)
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from ..configuration_utils import PretrainedConfig
16+
17+
18+
class Gemma4MoeConfig(PretrainedConfig):
19+
"""Gemma4 26B-A4B text-only MoE model configuration.
20+
21+
NOTE: Gemma4 currently only has VL checkpoints (Gemma4ForConditionalGeneration),
22+
no standalone text-only checkpoint exists. The config.json has top-level
23+
model_type="gemma4" (VL wrapper) with text params nested in text_config
24+
(model_type="gemma4_text").
25+
26+
Both "gemma4" and "gemma4_text" are registered in CONFIG_MAPPING to this class,
27+
and from_dict() automatically extracts text_config from the VL wrapper.
28+
29+
TODO(VL): When implementing full multimodal Gemma4:
30+
1. Create Gemma4Config (VL wrapper with text_config + vision_config)
31+
2. Change CONFIG_MAPPING "gemma4" to point to Gemma4Config
32+
3. Keep only "gemma4_text" -> Gemma4MoeConfig
33+
4. Remove the text_config extraction logic in from_dict() below
34+
"""
35+
36+
model_type = "gemma4_text"
37+
keys_to_ignore_at_inference = ["past_key_values"]
38+
39+
@classmethod
40+
def from_dict(cls, config_dict, **kwargs):
41+
"""Load text config from VL wrapper config.
42+
43+
Gemma4 only ships VL checkpoints, so config.json outer model_type="gemma4"
44+
with text params in text_config. This extracts it automatically.
45+
46+
TODO(VL): Move this extraction to Gemma4Config when VL model is implemented.
47+
"""
48+
if config_dict.get("model_type") == "gemma4" and "text_config" in config_dict:
49+
config_dict = config_dict["text_config"]
50+
return super().from_dict(config_dict, **kwargs)
51+
52+
def __init__(
53+
self,
54+
vocab_size=262144,
55+
hidden_size=2816,
56+
intermediate_size=2112,
57+
moe_intermediate_size=704,
58+
num_hidden_layers=30,
59+
num_attention_heads=16,
60+
num_key_value_heads=8,
61+
num_global_key_value_heads=2,
62+
head_dim=256,
63+
global_head_dim=512,
64+
hidden_act="gelu_pytorch_tanh",
65+
hidden_activation=None,
66+
max_position_embeddings=262144,
67+
rms_norm_eps=1e-6,
68+
# RoPE
69+
rope_parameters=None,
70+
sliding_window_rope_base=10000.0,
71+
full_attention_rope_base=1000000.0,
72+
full_attention_rope_partial_factor=0.25,
73+
# Attention pattern
74+
layer_types=None,
75+
sliding_window=1024,
76+
interleaved_attn_pattern=(5, 1),
77+
# MoE
78+
num_experts=128,
79+
top_k_experts=8,
80+
scoring_func="sigmoid",
81+
enable_moe_block=True,
82+
# Gemma4-specific
83+
attention_k_eq_v=True,
84+
final_logit_softcapping=30.0,
85+
scale_embeddings_by_hidden_size=True,
86+
# Pipeline
87+
pp_seg_method="layer:Gemma4TransformerLayer",
88+
tie_word_embeddings=True,
89+
**kwargs,
90+
):
91+
super().__init__(tie_word_embeddings=tie_word_embeddings, **kwargs)
92+
self.vocab_size = vocab_size
93+
self.hidden_size = hidden_size
94+
self.intermediate_size = intermediate_size
95+
self.moe_intermediate_size = moe_intermediate_size
96+
self.num_hidden_layers = num_hidden_layers
97+
self.num_attention_heads = num_attention_heads
98+
self.num_key_value_heads = num_key_value_heads
99+
self.num_global_key_value_heads = num_global_key_value_heads
100+
self.head_dim = head_dim
101+
self.global_head_dim = global_head_dim
102+
self.hidden_act = hidden_activation or hidden_act
103+
self.max_position_embeddings = max_position_embeddings
104+
self.rms_norm_eps = rms_norm_eps
105+
self.enable_moe_block = enable_moe_block
106+
self.sliding_window = sliding_window
107+
self.interleaved_attn_pattern = interleaved_attn_pattern
108+
self.num_experts = num_experts
109+
self.top_k_experts = top_k_experts
110+
self.scoring_func = scoring_func
111+
self.attention_k_eq_v = attention_k_eq_v
112+
self.final_logit_softcapping = final_logit_softcapping
113+
self.scale_embeddings_by_hidden_size = scale_embeddings_by_hidden_size
114+
self.pp_seg_method = pp_seg_method
115+
116+
# Parse rope_parameters from HF config format
117+
if rope_parameters is not None:
118+
sliding_rope = rope_parameters.get("sliding_attention", {})
119+
full_rope = rope_parameters.get("full_attention", {})
120+
self.sliding_window_rope_base = sliding_rope.get("rope_theta", sliding_window_rope_base)
121+
self.full_attention_rope_base = full_rope.get("rope_theta", full_attention_rope_base)
122+
self.full_attention_rope_partial_factor = full_rope.get(
123+
"partial_rotary_factor", full_attention_rope_partial_factor
124+
)
125+
else:
126+
self.sliding_window_rope_base = sliding_window_rope_base
127+
self.full_attention_rope_base = full_attention_rope_base
128+
self.full_attention_rope_partial_factor = full_attention_rope_partial_factor
129+
130+
# Build layer_types from interleaved pattern if not provided
131+
if layer_types is None:
132+
sliding_count, global_count = self.interleaved_attn_pattern
133+
pattern = ["sliding_attention"] * sliding_count + ["full_attention"] * global_count
134+
self.layer_types = (pattern * ((num_hidden_layers // len(pattern)) + 1))[:num_hidden_layers]
135+
else:
136+
self.layer_types = layer_types

0 commit comments

Comments
 (0)