Skip to content

Commit 446a31e

Browse files
committed
update qwen3vl
1 parent 75ad1ee commit 446a31e

10 files changed

Lines changed: 104 additions & 30 deletions

File tree

flagscale/models/megatron/qwen2_5_vl/language_module.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@ def __init__(
3636
position_embedding_type: Literal['learned_absolute', 'rope', 'none'] = 'learned_absolute',
3737
num_tokentypes: int = 0,
3838
scatter_to_sequence_parallel: bool = False, # chage default to False
39+
tp_group = None,
3940
):
4041
assert scatter_to_sequence_parallel == False, "QwenVLLanguageModelEmbedding does not support scatter_to_sequence_parallel"
41-
super().__init__(config, vocab_size, max_sequence_length, position_embedding_type, num_tokentypes, scatter_to_sequence_parallel)
42+
super().__init__(config, vocab_size, max_sequence_length, position_embedding_type, num_tokentypes, scatter_to_sequence_parallel, tp_group)
4243

4344

4445
def forward(

flagscale/models/megatron/qwen2_5_vl/vit_model.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def enable_linear(self):
6868
# and https://github.com/huggingface/transformers/pull/45041
6969
# By default, we use CUDNN's convolution ops with optimization.
7070
return self.kernel_size == self.stride and \
71-
version.parse(torch.__version__) > version.parse('2.9.0')
71+
version.parse(torch.__version__) > version.parse('2.9.0') and version.parse(torch.__version__) < version.parse('2.11.0')
7272

7373
def _forward_matmul(self, hidden_states):
7474
target_dtype = self.proj.weight.dtype

flagscale/models/megatron/qwen3_vl/language_model.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from megatron.core.utils import WrappedTensor, deprecate_inference_params
2828
from megatron.core.models.gpt.gpt_model import GPTModel
2929
from megatron.core.process_groups_config import ProcessGroupCollection
30+
from megatron.core.transformer.multi_token_prediction import MultiTokenPredictionBlock
3031

3132
from .language_transformer_block import LanguageTransformerBlock
3233

@@ -100,7 +101,7 @@ def apply_interleaved_mrope(self, freqs, mrope_section):
100101
freqs_t[..., idx] = freqs[dim, ..., idx]
101102
return freqs_t
102103

103-
def forward(self, position_ids: torch.Tensor, mrope_section: List[int]) -> Tensor:
104+
def forward(self, position_ids: torch.Tensor, mrope_section: List[int], cp_group: Optional[torch.distributed.ProcessGroup] = None) -> Tensor:
104105
"""Forward pass of multimodal RoPE embedding.
105106
106107
Args:
@@ -137,10 +138,12 @@ def forward(self, position_ids: torch.Tensor, mrope_section: List[int]) -> Tenso
137138

138139
# shape (seq_length, bs, 1, 2 * dim)
139140
emb = emb[..., None, :].transpose(0, 1).contiguous()
140-
if self.cp_group is not None and self.cp_group.size() > 1:
141+
if cp_group is None:
142+
cp_group = self.cp_group
143+
if cp_group is not None and cp_group.size() > 1:
141144
# slice rotary_pos_emb along sequence dimension and select the parition of the current
142145
# CP rank
143-
emb = get_pos_emb_on_this_cp_rank(emb, 0, self.cp_group)
146+
emb = get_pos_emb_on_this_cp_rank(emb, 0, cp_group)
144147
return emb
145148

146149
class Qwen3VLLanguageModule(GPTModel):
@@ -228,6 +231,7 @@ def __init__(
228231
vocab_size=self.vocab_size,
229232
max_sequence_length=self.max_sequence_length,
230233
position_embedding_type=position_embedding_type,
234+
tp_group=self.pg_collection.tp,
231235
)
232236
if self.position_embedding_type == 'mrope' and not self.config.multi_latent_attention:
233237
self.rotary_pos_emb = Qwen3VLLanguageRotaryEmbedding(
@@ -258,7 +262,7 @@ def __init__(
258262

259263
if self.mtp_process:
260264
self.mtp = MultiTokenPredictionBlock(
261-
config=self.config, spec=self.mtp_block_spec, vp_stage=vp_stage
265+
config=self.config, spec=self.mtp_block_spec, vp_stage=vp_stage, pg_collection=self.pg_collection
262266
)
263267

264268
# Output
@@ -314,18 +318,20 @@ def forward(self, input_ids, position_ids, attention_mask,
314318
visual_pos_masks: Optional[torch.Tensor] = None,
315319
deepstack_visual_embeds: Optional[list[torch.Tensor]] = None,
316320
*, inference_params = None,
317-
loss_mask = None):
321+
loss_mask = None,
322+
padding_mask: Optional[torch.Tensor] = None):
318323

319324
inference_context = deprecate_inference_params(inference_context, inference_params)
320325

321-
decoder_input, rotary_pos_emb, rotary_pos_cos, rotary_pos_sin, sequence_len_offset = (
326+
decoder_input, rotary_pos_emb, rotary_pos_cos, rotary_pos_sin, sequence_len_offset, padding_mask = (
322327
self._preprocess(
323328
input_ids=input_ids,
324329
position_ids=position_ids,
325330
decoder_input=decoder_input,
326331
inference_context=inference_context,
327332
packed_seq_params=packed_seq_params,
328-
)
333+
padding_mask=padding_mask,
334+
)[:6]
329335
)
330336

331337
# Run decoder.
@@ -338,6 +344,7 @@ def forward(self, input_ids, position_ids, attention_mask,
338344
rotary_pos_sin=rotary_pos_sin,
339345
packed_seq_params=packed_seq_params,
340346
sequence_len_offset=sequence_len_offset,
347+
padding_mask=padding_mask,
341348
visual_pos_masks = visual_pos_masks,
342349
deepstack_visual_embeds = deepstack_visual_embeds,
343350
**(extra_block_kwargs or {}),

flagscale/models/megatron/qwen3_vl/language_transformer_block.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,21 @@
6262

6363
class LanguageTransformerBlock(TransformerBlock):
6464

65+
def __init__(
66+
self,
67+
config,
68+
spec,
69+
post_layer_norm=True,
70+
pre_process=True,
71+
post_process=True,
72+
pg_collection=None,
73+
vp_stage=None,
74+
dualpipev_stage=None,
75+
):
76+
super().__init__(
77+
config, spec, post_layer_norm, pre_process, post_process, pg_collection, vp_stage, dualpipev_stage
78+
)
79+
6580
def _checkpointed_forward(
6681
self,
6782
hidden_states: Tensor,
@@ -207,6 +222,7 @@ def forward(
207222
inference_context: Optional[BaseInferenceContext] = None,
208223
packed_seq_params: Optional[PackedSeqParams] = None,
209224
sequence_len_offset: Optional[Tensor] = None,
225+
padding_mask: Optional[Tensor] = None,
210226
# args for deepstack
211227
visual_pos_masks: Optional[torch.Tensor] = None,
212228
deepstack_visual_embeds: Optional[list[torch.Tensor]] = None,
@@ -343,6 +359,7 @@ def forward(
343359
inference_context=inference_context,
344360
packed_seq_params=packed_seq_params,
345361
sequence_len_offset=sequence_len_offset,
362+
padding_mask=padding_mask,
346363
)
347364
# Deepstack visual embedding addition
348365
# NOTE: Assume that this is first pipeline stage that has at least three layers.

flagscale/models/megatron/qwen3_vl/model.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ def __init__(
7272
language_rotary_base: int = 10000,
7373
fp16_lm_cross_entropy: bool = False,
7474
language_share_embeddings_and_output_weights: bool=False,
75+
pg_collection = None,
7576
vp_stage: int=None
7677
) -> None:
7778
super().__init__(config=language_transformer_config)
@@ -121,6 +122,7 @@ def __init__(
121122
share_embeddings_and_output_weights=language_share_embeddings_and_output_weights,
122123
rope_scaling=False,
123124
mtp_block_spec=None,
125+
pg_collection=pg_collection,
124126
vp_stage=vp_stage,
125127
)
126128
self.share_embeddings_and_output_weights = (

flagscale/models/megatron/qwen3_vl/vision_transformer_block.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,12 @@ class VisionTransformerBlock(TransformerBlock):
6767
"""
6868
def __init__(self, config, spec,
6969
post_layer_norm = True, pre_process = True, post_process = True,
70-
pg_collection = None, vp_stage = None,
70+
pg_collection = None, vp_stage = None, dualpipev_stage = None,
7171
projection_config = None, # Note: DeepStack
7272
projection_layer_spec = None, # Note: DeepStack
7373
projection_type = 'mlp', # Note: DeepStack):
7474
):
75-
super().__init__(config, spec, post_layer_norm, pre_process, post_process, pg_collection, vp_stage)
75+
super().__init__(config, spec, post_layer_norm, pre_process, post_process, pg_collection, vp_stage, dualpipev_stage)
7676

7777
if self.final_layernorm != None:
7878
# NOTE(lizhiyu): replace final layernorm with TENorm if using TE

flagscale/train/megatron/train_qwen3_vl.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,17 @@
9292
#### especially for qwen2.5-vl ####
9393
IGNORE_IDX=-100
9494
def model_provider(
95-
pre_process=True, post_process=True, add_encoder=True, add_decoder=True
95+
pre_process=True, post_process=True, vp_stage=None, config=None, pg_collection=None
9696
) -> Union[Qwen3VLModel]:
9797
args = get_args()
9898
print_rank_0("start building qwen3-vl model ...")
9999

100100
# Config of vit, llm and projector
101-
config = core_transformer_config_from_args(args, Qwen3VLTransformerConfig)
101+
if config is None:
102+
config = core_transformer_config_from_args(args, Qwen3VLTransformerConfig)
103+
else:
104+
# config passed from backend, use it directly
105+
pass
102106
use_te = args.transformer_impl == "transformer_engine"
103107
if not use_te:
104108
raise NotImplementedError("The Qwen3-VL model is only implemented with TransformerEngine!")
@@ -144,12 +148,12 @@ def model_provider(
144148

145149
pre_process=pre_process,
146150
post_process=post_process,
147-
add_decoder=add_decoder,
148-
add_encoder=add_encoder,
149151

150152
fp16_lm_cross_entropy=args.fp16_lm_cross_entropy,
151153
parallel_output=True,
152154
language_share_embeddings_and_output_weights=not args.untie_embeddings_and_output_weights,
155+
pg_collection=pg_collection,
156+
vp_stage=vp_stage,
153157
)
154158

155159
model.freeze(

tools/checkpoint/qwen2_5_vl/utils.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,9 @@ def safe_copy(src_tensor: torch.Tensor, dst_tensor: torch.Tensor, skip_dtype_ass
174174
raise ValueError(
175175
f"Get source dtype {src_tensor.dtype}, but target dtype {dst_tensor.dtype}"
176176
)
177-
assert src_tensor.shape == dst_tensor.shape
177+
assert src_tensor.shape == dst_tensor.shape, (
178+
f"Get source shape {src_tensor.shape}, but target shape {dst_tensor.shape}"
179+
)
178180
dst_tensor.data.copy_(src_tensor.data)
179181
return src_tensor.numel()
180182

tools/checkpoint/qwen3_vl/hf2mcore_qwen3_vl.py

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,9 @@ def load_megatron_model(args):
208208

209209

210210
@torch.inference_mode()
211-
def convert_checkpoint_from_megatron_to_transformers(mgmodel, hfmodel, args):
211+
def convert_checkpoint_from_megatron_to_transformers(
212+
mgmodel, hfmodel, args, hf_pretrained_model=None
213+
):
212214
if args.fp16:
213215
mgmodel = mgmodel.half()
214216
hfmodel = hfmodel.half()
@@ -230,7 +232,14 @@ def convert_checkpoint_from_megatron_to_transformers(mgmodel, hfmodel, args):
230232
vision_head_dim = vision_hidden_size // mgvision.config.num_attention_heads
231233
copied_numel = 0
232234
safe_copy(mgvision.rotary_pos_emb.inv_freq, hfvision.rotary_pos_emb.inv_freq)
233-
copied_numel += safe_copy(mgvision.patch_embed.proj.weight, hfvision.patch_embed.proj.weight)
235+
# patch_embed: mcore may use Linear (enable_linear) while hf uses Conv3d
236+
mg_patch_weight = mgvision.patch_embed.proj.weight
237+
hf_patch_weight = hfvision.patch_embed.proj.weight
238+
if mg_patch_weight.dim() == 2 and hf_patch_weight.dim() == 5:
239+
# mcore Linear [embed_dim, flat_dim] -> hf Conv3d [embed_dim, C, T, H, W]
240+
copied_numel += safe_copy(mg_patch_weight.view(hf_patch_weight.shape), hf_patch_weight)
241+
else:
242+
copied_numel += safe_copy(mg_patch_weight, hf_patch_weight)
234243
copied_numel += safe_copy(mgvision.patch_embed.proj.bias, hfvision.patch_embed.proj.bias)
235244
copied_numel += safe_copy(mgvision.pos_embed.weight, hfvision.pos_embed.weight)
236245

@@ -367,7 +376,7 @@ def convert_checkpoint_from_megatron_to_transformers(mgmodel, hfmodel, args):
367376

368377
copied_numel += safe_copy(mgllm.decoder.final_layernorm.weight, hfllm.norm.weight)
369378
if args.untie_embeddings_and_output_weights:
370-
safe_copy(mgllm.output_layer.weight, hfmodel.lm_head.weight)
379+
safe_copy(mgllm.output_layer.weight, hf_pretrained_model.lm_head.weight)
371380

372381
n_params = sum(
373382
[
@@ -382,7 +391,9 @@ def convert_checkpoint_from_megatron_to_transformers(mgmodel, hfmodel, args):
382391

383392

384393
@torch.inference_mode()
385-
def convert_checkpoint_from_transformers_to_megatron(hfmodel, mgmodel, args):
394+
def convert_checkpoint_from_transformers_to_megatron(
395+
hfmodel, mgmodel, args, hf_pretrained_model=None
396+
):
386397
if args.fp16:
387398
mgmodel = mgmodel.half()
388399
hfmodel = hfmodel.half()
@@ -410,7 +421,14 @@ def convert_checkpoint_from_transformers_to_megatron(hfmodel, mgmodel, args):
410421
copied_numel = 0
411422
# rotary_pos_emb.inv_freq is buffer not parameter
412423
safe_copy(hfvision.rotary_pos_emb.inv_freq, mgvision.rotary_pos_emb.inv_freq)
413-
copied_numel += safe_copy(hfvision.patch_embed.proj.weight, mgvision.patch_embed.proj.weight)
424+
# patch_embed: hf uses Conv3d while mcore may use Linear (enable_linear)
425+
hf_patch_weight = hfvision.patch_embed.proj.weight
426+
mg_patch_weight = mgvision.patch_embed.proj.weight
427+
if hf_patch_weight.dim() == 5 and mg_patch_weight.dim() == 2:
428+
# hf Conv3d [embed_dim, C, T, H, W] -> mcore Linear [embed_dim, flat_dim]
429+
copied_numel += safe_copy(hf_patch_weight.reshape(mg_patch_weight.shape), mg_patch_weight)
430+
else:
431+
copied_numel += safe_copy(hf_patch_weight, mg_patch_weight)
414432
copied_numel += safe_copy(hfvision.patch_embed.proj.bias, mgvision.patch_embed.proj.bias)
415433
copied_numel += safe_copy(hfvision.pos_embed.weight, mgvision.pos_embed.weight)
416434

@@ -550,7 +568,7 @@ def convert_checkpoint_from_transformers_to_megatron(hfmodel, mgmodel, args):
550568
copied_numel += safe_copy(hfllm.norm.weight, mgllm.decoder.final_layernorm.weight)
551569
if args.untie_embeddings_and_output_weights:
552570
# lm_head not in hfllm
553-
safe_copy(hfmodel.lm_head.weight, mgllm.output_layer.weight)
571+
safe_copy(hf_pretrained_model.lm_head.weight, mgllm.output_layer.weight)
554572

555573
n_params = sum([t.numel() for t in hfllm.state_dict().values()])
556574
assert n_params == copied_numel, (
@@ -873,15 +891,19 @@ def main():
873891
args.hf_ckpt_path, torch_dtype=config.torch_dtype
874892
)
875893
mg_model = load_megatron_model(args)
876-
convert_checkpoint_from_megatron_to_transformers(mg_model, hf_model, args)
894+
convert_checkpoint_from_megatron_to_transformers(
895+
mg_model, hf_model.model, args, hf_pretrained_model=hf_model
896+
)
877897
save_hfmodel(args, hf_model)
878898
else:
879899
config = AutoConfig.from_pretrained(args.load)
880900
hf_model = Qwen3VLForConditionalGeneration.from_pretrained(
881901
args.load, torch_dtype=config.torch_dtype
882902
)
883903
mg_model = model_provider()
884-
convert_checkpoint_from_transformers_to_megatron(hf_model, mg_model, args)
904+
convert_checkpoint_from_transformers_to_megatron(
905+
hf_model.model, mg_model, args, hf_pretrained_model=hf_model
906+
)
885907
save_mgmodel(mg_model, args)
886908

887909

tools/datasets/qwenvl/data/dataset_helpers.py

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -381,14 +381,19 @@ def encode_chatml(self, sample: ChatMLSample):
381381

382382
# NOTE: we need to mask all system/user input tokens and assistant generation prefix tokens
383383
input_ids = self.tokenizer.apply_chat_template(
384-
conversation, tokenize=True, return_tensors="np"
384+
conversation,
385+
tokenize=True,
386+
return_tensors="np",
387+
return_dict=False,
385388
)[0]
386389
target = input_ids.copy()
387390

388391
conversation_start_idx = 0
389392
if self.use_system_prompt:
390393
system_prompt_prefix = len(
391-
self.tokenizer.apply_chat_template([conversation[0]], tokenize=True)
394+
self.tokenizer.apply_chat_template(
395+
[conversation[0]], tokenize=True, return_dict=False
396+
)
392397
)
393398
conversation_start_idx = 1
394399
else:
@@ -403,7 +408,10 @@ def encode_chatml(self, sample: ChatMLSample):
403408
for turn_idx, turn in enumerate(conversation[conversation_start_idx:]):
404409
if self._single_turn_template:
405410
turn_tokens = self.tokenizer.apply_chat_template(
406-
[turn], tokenize=True, return_tensors="np"
411+
[turn],
412+
tokenize=True,
413+
return_tensors="np",
414+
return_dict=False,
407415
)[0]
408416
turn_content = turn_tokens[system_prompt_prefix:]
409417
n_tokens = len(turn_content)
@@ -414,7 +422,10 @@ def encode_chatml(self, sample: ChatMLSample):
414422
else:
415423
prefix = conversation[: conversation_start_idx + turn_idx + 1]
416424
prefix_tokens = self.tokenizer.apply_chat_template(
417-
prefix, tokenize=True, return_tensors="np"
425+
prefix,
426+
tokenize=True,
427+
return_tensors="np",
428+
return_dict=False,
418429
)[0]
419430
n_tokens = len(prefix_tokens) - prev_prefix_len
420431

@@ -545,8 +556,16 @@ def encode_vqa(self, sample: VQASample):
545556
{"role": "assistant", "content": answer},
546557
]
547558

548-
user_inputs = self.tokenizer.apply_chat_template(conversation[:-1], tokenize=False)
549-
text = self.tokenizer.apply_chat_template(conversation, tokenize=False)
559+
user_inputs = self.tokenizer.apply_chat_template(
560+
conversation[:-1],
561+
tokenize=False,
562+
return_dict=False,
563+
)
564+
text = self.tokenizer.apply_chat_template(
565+
conversation,
566+
tokenize=False,
567+
return_dict=False,
568+
)
550569

551570
# text, target = self.tokenizer.tokenize_conversation(conversation, False, False)
552571
# replace <image> token by <image> * (thw)

0 commit comments

Comments
 (0)