From ea1af52f39ecbd6056461ae81ae390679886f529 Mon Sep 17 00:00:00 2001 From: Daisy Gao Date: Thu, 9 Apr 2026 15:52:49 +0800 Subject: [PATCH 01/51] fix: align THD MoE aux-loss token accounting with valid tokens Pass a THD padding_mask derived from lm_input_ids into GPTModel so MoE router aux/global-aux metrics exclude tail padding and match BSHD token-count semantics. Signed-off-by: Daisy Gao --- .../models/qwen_vl/modelling_qwen3_vl/model.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/megatron/bridge/models/qwen_vl/modelling_qwen3_vl/model.py b/src/megatron/bridge/models/qwen_vl/modelling_qwen3_vl/model.py index 702723fc06..5b0e8424e7 100644 --- a/src/megatron/bridge/models/qwen_vl/modelling_qwen3_vl/model.py +++ b/src/megatron/bridge/models/qwen_vl/modelling_qwen3_vl/model.py @@ -622,6 +622,22 @@ def forward( torch.cuda.nvtx.range_pop() torch.cuda.nvtx.range_push("Qwen3VLModel.forward.language_model") + # For THD packed path we intentionally keep attention_mask=None for model forward. + # MoE aux/global-aux accounting still needs to ignore tail padding tokens, so pass + # a dedicated padding_mask (True=padding) to GPTModel/Router. + padding_mask_for_moe = None + if packed_seq_params is not None and lm_input_ids is not None: + padding_mask_for_moe = lm_input_ids.eq(0) + if _thd_diag_enabled() and _rank0(): + pad_cnt = int(padding_mask_for_moe.sum().item()) + tok_cnt = int(padding_mask_for_moe.numel()) + logger.info( + "[THD_DIAG][model] padding_mask_for_moe: total_tokens=%d padding_tokens=%d valid_tokens=%d", + tok_cnt, + pad_cnt, + tok_cnt - pad_cnt, + ) + output = self.language_model( input_ids=lm_input_ids, position_ids=position_ids, # None in encoder @@ -629,6 +645,7 @@ def forward( decoder_input=combined_embeddings, # only not None in the first decoder PP stage labels=labels, # only not None in the last decoder PP stage loss_mask=loss_mask, # Added for THD training compatibility + padding_mask=padding_mask_for_moe, # for MoE routing/aux-loss token accounting inference_params=inference_params, # currently always None packed_seq_params=packed_seq_params, # currently always None visual_pos_masks=visual_pos_masks, From da9d92634b59b27ac1348ba365ceba51a63569e6 Mon Sep 17 00:00:00 2001 From: Daisy Gao Date: Thu, 9 Apr 2026 16:20:35 +0800 Subject: [PATCH 02/51] fix: wire padding_mask through qwen3-vl gpt forward path Allow Qwen3VLGPTModel and Qwen3VLTransformerBlock to accept and propagate padding_mask so THD MoE routing can consume valid-token masking without crashing. Signed-off-by: Daisy Gao --- .../models/qwen_vl/modelling_qwen3_vl/text_model.py | 6 +++++- .../qwen_vl/modelling_qwen3_vl/transformer_block.py | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/megatron/bridge/models/qwen_vl/modelling_qwen3_vl/text_model.py b/src/megatron/bridge/models/qwen_vl/modelling_qwen3_vl/text_model.py index d067655a1b..5e05ca9ec7 100644 --- a/src/megatron/bridge/models/qwen_vl/modelling_qwen3_vl/text_model.py +++ b/src/megatron/bridge/models/qwen_vl/modelling_qwen3_vl/text_model.py @@ -120,6 +120,7 @@ def forward( *, inference_params: Optional[BaseInferenceContext] = None, loss_mask: Optional[Tensor] = None, + padding_mask: Optional[Tensor] = None, # args for deepstack visual_pos_masks: Optional[torch.Tensor] = None, deepstack_visual_embeds: Optional[list[torch.Tensor]] = None, @@ -148,6 +149,7 @@ def forward( decoder_input=decoder_input, inference_context=inference_context, packed_seq_params=packed_seq_params, + padding_mask=padding_mask, ) ( @@ -156,7 +158,8 @@ def forward( rotary_pos_cos, rotary_pos_sin, sequence_len_offset, - ) = preproc_output[:5] + padding_mask, + ) = preproc_output[:6] # Run decoder. hidden_states = self.decoder( @@ -170,6 +173,7 @@ def forward( # the standard components only. packed_seq_params=packed_seq_params, sequence_len_offset=sequence_len_offset, + padding_mask=padding_mask, visual_pos_masks=visual_pos_masks, deepstack_visual_embeds=deepstack_visual_embeds, **(extra_block_kwargs or {}), diff --git a/src/megatron/bridge/models/qwen_vl/modelling_qwen3_vl/transformer_block.py b/src/megatron/bridge/models/qwen_vl/modelling_qwen3_vl/transformer_block.py index 6284617bed..440e45c873 100644 --- a/src/megatron/bridge/models/qwen_vl/modelling_qwen3_vl/transformer_block.py +++ b/src/megatron/bridge/models/qwen_vl/modelling_qwen3_vl/transformer_block.py @@ -503,6 +503,7 @@ def _checkpointed_forward( rotary_pos_emb: Tensor, attention_bias: Tensor, packed_seq_params: PackedSeqParams, + padding_mask: Optional[Tensor], use_inner_fp8_context: bool, # args for deepstack visual_pos_masks: Optional[torch.Tensor] = None, @@ -517,6 +518,7 @@ def custom_forward( context, context_mask, rotary_pos_emb, + padding_mask, visual_pos_masks, *deepstack_visual_embeds_args, ): @@ -538,6 +540,7 @@ def custom_forward( attention_bias=attention_bias, inference_context=None, packed_seq_params=packed_seq_params, + padding_mask=padding_mask, ) if self.pre_process and deepstack_visual_embeds is not None: @@ -567,6 +570,7 @@ def checkpoint_handler(forward_func): context, context_mask, rotary_pos_emb, + padding_mask, visual_pos_masks, *deepstack_visual_embeds_tuple, ) @@ -579,6 +583,7 @@ def checkpoint_handler(forward_func): context, context_mask, rotary_pos_emb, + padding_mask, visual_pos_masks, *deepstack_visual_embeds_tuple, ) @@ -618,6 +623,7 @@ def checkpoint_handler(forward_func): context, context_mask, rotary_pos_emb, + padding_mask, visual_pos_masks, *deepstack_visual_embeds_tuple, ) @@ -639,6 +645,7 @@ def forward( inference_context: Optional[BaseInferenceContext] = None, packed_seq_params: Optional[PackedSeqParams] = None, sequence_len_offset: Optional[Tensor] = None, + padding_mask: Optional[Tensor] = None, *, inference_params: Optional[BaseInferenceContext] = None, # args for deepstack @@ -730,6 +737,7 @@ def forward( rotary_pos_emb=rotary_pos_emb, attention_bias=attention_bias, packed_seq_params=packed_seq_params, + padding_mask=padding_mask, use_inner_fp8_context=use_inner_fp8_context, visual_pos_masks=visual_pos_masks, deepstack_visual_embeds=deepstack_visual_embeds, @@ -754,6 +762,7 @@ def forward( inference_context=inference_context, packed_seq_params=packed_seq_params, sequence_len_offset=sequence_len_offset, + padding_mask=padding_mask, ) if self.pre_process and deepstack_visual_embeds is not None: From 653dd62fea5349a4a48eeaf9b9a4cf4bf62dad6a Mon Sep 17 00:00:00 2001 From: Daisy Gao Date: Thu, 9 Apr 2026 17:08:33 +0800 Subject: [PATCH 03/51] fix: pass padding_mask into qwen gpt postprocess mtp path Forward padding_mask from Qwen3VLGPTModel into _postprocess so MTP MoE global aux-loss uses masked token accounting consistently. Signed-off-by: Daisy Gao --- .../bridge/models/qwen_vl/modelling_qwen3_vl/text_model.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/megatron/bridge/models/qwen_vl/modelling_qwen3_vl/text_model.py b/src/megatron/bridge/models/qwen_vl/modelling_qwen3_vl/text_model.py index 5e05ca9ec7..d6781ced3a 100644 --- a/src/megatron/bridge/models/qwen_vl/modelling_qwen3_vl/text_model.py +++ b/src/megatron/bridge/models/qwen_vl/modelling_qwen3_vl/text_model.py @@ -208,6 +208,7 @@ def _sp_scatter_embedding(input_ids, position_ids): loss_mask=loss_mask, decoder_input=decoder_input, attention_mask=attention_mask, + padding_mask=padding_mask, inference_params=inference_params, packed_seq_params=packed_seq_params, sequence_len_offset=sequence_len_offset, From 88a8ac209c91e5c6a80fb0ca4e34ea574eeea61b Mon Sep 17 00:00:00 2001 From: Daisy Gao Date: Thu, 9 Apr 2026 19:30:19 +0800 Subject: [PATCH 04/51] fix: update Megatron-LM pointer for main-based THD support Point submodule to the main-based Megatron-LM branch commit that propagates padding_mask through MTP MoE routing. Signed-off-by: Daisy Gao --- 3rdparty/Megatron-LM | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rdparty/Megatron-LM b/3rdparty/Megatron-LM index 23265d2db3..ec7ee7928f 160000 --- a/3rdparty/Megatron-LM +++ b/3rdparty/Megatron-LM @@ -1 +1 @@ -Subproject commit 23265d2db37efa883b3983bce321c631898822f3 +Subproject commit ec7ee7928f78db084d55c0fa1bf8b6ac7c2a19a5 From 924497c7743ce73acc82942ae523780464abd44f Mon Sep 17 00:00:00 2001 From: Daisy Gao Date: Fri, 10 Apr 2026 10:43:27 +0800 Subject: [PATCH 05/51] fix: make diffusion recipe imports optional Guard diffusion recipe imports in recipes.__init__ so missing optional dependencies like diffusers do not block LLM/VLM training startup. Signed-off-by: Daisy Gao --- src/megatron/bridge/recipes/__init__.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/megatron/bridge/recipes/__init__.py b/src/megatron/bridge/recipes/__init__.py index 46d51fdb64..4428a47191 100644 --- a/src/megatron/bridge/recipes/__init__.py +++ b/src/megatron/bridge/recipes/__init__.py @@ -18,8 +18,14 @@ This module exposes all recipe configurations from all model families. """ -from megatron.bridge.diffusion.recipes.flux.flux import * -from megatron.bridge.diffusion.recipes.wan.wan import * +# Diffusion recipes require optional dependencies (e.g. diffusers). Keep +# non-diffusion training paths (LLM/VLM) usable when those deps are absent. +try: + from megatron.bridge.diffusion.recipes.flux.flux import * + from megatron.bridge.diffusion.recipes.wan.wan import * +except ModuleNotFoundError: + pass + from megatron.bridge.recipes.deepseek import * from megatron.bridge.recipes.gemma import * from megatron.bridge.recipes.gemma3_vl import * From 552282d7b123a0e7e0a1aa7e3975cf7debb51d09 Mon Sep 17 00:00:00 2001 From: Daisy Gao Date: Fri, 10 Apr 2026 11:38:28 +0800 Subject: [PATCH 06/51] fix: guard optional deps for Qwen-VL recipe startup Avoid import-time crashes in training environments missing optional diffusion/modelopt/transformers pieces by adding graceful fallbacks for quantization and processor loading. Signed-off-by: Daisy Gao --- .../bridge/models/conversion/auto_bridge.py | 9 ++++++++- .../bridge/recipes/qwen_vl/qwen3_vl.py | 18 ++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/megatron/bridge/models/conversion/auto_bridge.py b/src/megatron/bridge/models/conversion/auto_bridge.py index 0c61b75d47..8dbcb921d1 100644 --- a/src/megatron/bridge/models/conversion/auto_bridge.py +++ b/src/megatron/bridge/models/conversion/auto_bridge.py @@ -30,7 +30,6 @@ from megatron.core.transformer.module import MegatronModule from megatron.core.transformer.transformer_config import MLATransformerConfig, TransformerConfig -from modelopt.torch.quantization.utils import is_quantized from safetensors.torch import save_file from transformers.configuration_utils import PretrainedConfig from typing_extensions import Unpack @@ -51,6 +50,14 @@ logger = logging.getLogger(__name__) +try: + from modelopt.torch.quantization.utils import is_quantized +except Exception: + # modelopt/scipy is optional for recipe import and training startup. + # Keep quantization-only export path available when dependency exists. + def is_quantized(_model: object) -> bool: + return False + MegatronModelT = TypeVar("MegatronModelT", bound=MegatronModule) DataclassT = TypeVar("DataclassT") diff --git a/src/megatron/bridge/recipes/qwen_vl/qwen3_vl.py b/src/megatron/bridge/recipes/qwen_vl/qwen3_vl.py index 5f84009620..5c445784aa 100644 --- a/src/megatron/bridge/recipes/qwen_vl/qwen3_vl.py +++ b/src/megatron/bridge/recipes/qwen_vl/qwen3_vl.py @@ -23,9 +23,14 @@ from typing import Optional, Union import torch -from transformers import AutoTokenizer, Qwen3VLProcessor +from transformers import AutoTokenizer from typing_extensions import TypedDict, Unpack +try: + from transformers import Qwen3VLProcessor +except Exception: + Qwen3VLProcessor = None + from megatron.bridge import AutoBridge from megatron.bridge.data.energon.energon_provider import EnergonProvider from megatron.bridge.data.vlm_datasets import MockVLMConversationProvider @@ -270,9 +275,14 @@ def _make_energon_dataset( ) -> EnergonProvider: """Create an EnergonProvider dataset config for Qwen3-VL recipes.""" tokenizer = AutoTokenizer.from_pretrained(hf_path) - # Use Qwen3VLProcessor to match the HF flow (which uses AutoProcessor). - # This processor accepts both images and videos kwargs. - image_processor = Qwen3VLProcessor.from_pretrained(hf_path) + # Prefer Qwen3VLProcessor on newer transformers; fall back to AutoProcessor + # for older container images that do not yet expose that symbol. + if Qwen3VLProcessor is not None: + image_processor = Qwen3VLProcessor.from_pretrained(hf_path) + else: + from transformers import AutoProcessor + + image_processor = AutoProcessor.from_pretrained(hf_path) task_encoder = QwenVLTaskEncoder( tokenizer=tokenizer, image_processor=image_processor, From 24647716e1a176858a0cdbbdcd4a2cdaa2eb57da Mon Sep 17 00:00:00 2001 From: Daisy Gao Date: Fri, 10 Apr 2026 18:04:36 +0800 Subject: [PATCH 07/51] feat: add qwen35_vl_35b_a3b_sft_energon_config recipe Signed-off-by: Daisy Gao --- .../bridge/recipes/qwen_vl/__init__.py | 2 ++ .../bridge/recipes/qwen_vl/qwen35_vl.py | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/megatron/bridge/recipes/qwen_vl/__init__.py b/src/megatron/bridge/recipes/qwen_vl/__init__.py index 9bc536c45d..0c45ee8dc2 100644 --- a/src/megatron/bridge/recipes/qwen_vl/__init__.py +++ b/src/megatron/bridge/recipes/qwen_vl/__init__.py @@ -52,6 +52,7 @@ qwen35_vl_35b_a3b_peft_config, qwen35_vl_35b_a3b_pretrain_mock_config, qwen35_vl_35b_a3b_sft_config, + qwen35_vl_35b_a3b_sft_energon_config, qwen35_vl_122b_a10b_peft_config, qwen35_vl_122b_a10b_pretrain_mock_config, qwen35_vl_122b_a10b_sft_config, @@ -77,6 +78,7 @@ "qwen35_vl_27b_sft_config", # Qwen3.5-VL SFT configs — MoE "qwen35_vl_35b_a3b_sft_config", + "qwen35_vl_35b_a3b_sft_energon_config", "qwen35_vl_35b_a3b_fsdp_sft_config", "qwen35_vl_122b_a10b_sft_config", "qwen35_vl_397b_a17b_sft_config", diff --git a/src/megatron/bridge/recipes/qwen_vl/qwen35_vl.py b/src/megatron/bridge/recipes/qwen_vl/qwen35_vl.py index af089cc28b..c1bb8fd4ca 100644 --- a/src/megatron/bridge/recipes/qwen_vl/qwen35_vl.py +++ b/src/megatron/bridge/recipes/qwen_vl/qwen35_vl.py @@ -28,7 +28,11 @@ from megatron.bridge import AutoBridge from megatron.bridge.peft.base import PEFT from megatron.bridge.recipes.common import _peft_common_vlm, _sft_common_vlm -from megatron.bridge.recipes.qwen_vl.qwen3_vl import Qwen3VLCommonKwargs, _qwen3_vl_common +from megatron.bridge.recipes.qwen_vl.qwen3_vl import ( + Qwen3VLCommonKwargs, + _make_energon_dataset, + _qwen3_vl_common, +) from megatron.bridge.recipes.utils.finetune_utils import default_peft_config from megatron.bridge.recipes.utils.optimizer_utils import distributed_fused_adam_with_cosine_annealing from megatron.bridge.training.config import ConfigContainer @@ -385,6 +389,19 @@ def qwen35_vl_35b_a3b_sft_config(hf_path: str = "Qwen/Qwen3.5-35B-A3B") -> Confi return cfg +def qwen35_vl_35b_a3b_sft_energon_config(hf_path: str = "Qwen/Qwen3.5-35B-A3B") -> ConfigContainer: + """Return a full SFT config for Qwen3.5-VL 35B-A3B (MoE) with Energon dataset. + + Same as qwen35_vl_35b_a3b_sft_config but uses EnergonProvider instead of HF dataset. + Set the dataset path via CLI override: dataset.path=/path/to/energon/dataset + """ + cfg = qwen35_vl_35b_a3b_sft_config(hf_path=hf_path) + cfg.dataset = _make_energon_dataset( + hf_path, cfg.dataset.seq_length, cfg.train.micro_batch_size, cfg.train.global_batch_size + ) + return cfg + + def qwen35_vl_35b_a3b_fsdp_sft_config(hf_path: str = "Qwen/Qwen3.5-35B-A3B") -> ConfigContainer: """Return a full SFT config for Qwen3.5-VL 35B-A3B (MoE) with Megatron FSDP. From 7d4502dcbe6202855a26c5122254be41a69c628b Mon Sep 17 00:00:00 2001 From: Daisy Gao Date: Mon, 13 Apr 2026 08:44:19 +0800 Subject: [PATCH 08/51] fix: add packing_buffer_size to EnergonProvider and harden Qwen3VLProcessor fallback Signed-off-by: Daisy Gao --- src/megatron/bridge/data/energon/energon_provider.py | 2 ++ src/megatron/bridge/recipes/qwen_vl/qwen3_vl.py | 11 ++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/megatron/bridge/data/energon/energon_provider.py b/src/megatron/bridge/data/energon/energon_provider.py index f33ea48dc1..2afcd0d1b9 100644 --- a/src/megatron/bridge/data/energon/energon_provider.py +++ b/src/megatron/bridge/data/energon/energon_provider.py @@ -35,6 +35,7 @@ class EnergonProvider(DatasetProvider): task_encoder: Optional[Any] = None # Enable batch-level online sequence packing pack_sequences_in_batch: bool = False + packing_buffer_size: Optional[int] = None def build_datasets(self, context: DatasetBuildContext): assert self.path, "EnergonProvider.path must be set. Use CLI override: dataset.path=" @@ -47,6 +48,7 @@ def build_datasets(self, context: DatasetBuildContext): micro_batch_size=self.micro_batch_size, global_batch_size=self.global_batch_size, num_workers=self.num_workers, + packing_buffer_size=self.packing_buffer_size, pg_collection=context.pg_collection, ) return ( diff --git a/src/megatron/bridge/recipes/qwen_vl/qwen3_vl.py b/src/megatron/bridge/recipes/qwen_vl/qwen3_vl.py index 5c445784aa..64b126974a 100644 --- a/src/megatron/bridge/recipes/qwen_vl/qwen3_vl.py +++ b/src/megatron/bridge/recipes/qwen_vl/qwen3_vl.py @@ -276,10 +276,15 @@ def _make_energon_dataset( """Create an EnergonProvider dataset config for Qwen3-VL recipes.""" tokenizer = AutoTokenizer.from_pretrained(hf_path) # Prefer Qwen3VLProcessor on newer transformers; fall back to AutoProcessor - # for older container images that do not yet expose that symbol. + # for older container images that do not yet expose that symbol or lack + # the video_processing sub-module required by from_pretrained. + image_processor = None if Qwen3VLProcessor is not None: - image_processor = Qwen3VLProcessor.from_pretrained(hf_path) - else: + try: + image_processor = Qwen3VLProcessor.from_pretrained(hf_path) + except Exception: + pass + if image_processor is None: from transformers import AutoProcessor image_processor = AutoProcessor.from_pretrained(hf_path) From 942240792bb1ff0a02a17243179c5fb99b55397e Mon Sep 17 00:00:00 2001 From: Daisy Gao Date: Tue, 31 Mar 2026 10:51:01 +0800 Subject: [PATCH 09/51] feat: Add Energon THD packing support for QwenVL TaskEncoder and vlm_step Signed-off-by: Daisy Gao --- .../qwen_vl/data/energon/task_encoder.py | 360 ++++++++++++++++-- src/megatron/bridge/training/vlm_step.py | 62 ++- 2 files changed, 381 insertions(+), 41 deletions(-) diff --git a/src/megatron/bridge/recipes/qwen_vl/data/energon/task_encoder.py b/src/megatron/bridge/recipes/qwen_vl/data/energon/task_encoder.py index 50178a0749..13e90877f0 100644 --- a/src/megatron/bridge/recipes/qwen_vl/data/energon/task_encoder.py +++ b/src/megatron/bridge/recipes/qwen_vl/data/energon/task_encoder.py @@ -12,16 +12,17 @@ # See the License for the specific language governing permissions and # limitations under the License. +import bisect import dataclasses import logging import re from collections import defaultdict -from dataclasses import dataclass -from typing import Dict, List +from dataclasses import dataclass, field +from typing import Dict, List, Optional, Union import numpy as np import torch -from megatron.energon import Batch, DefaultTaskEncoder +from megatron.energon import Batch, DefaultTaskEncoder, stateless from transformers import BatchEncoding from megatron.bridge.data.energon.task_encoder_utils import ( @@ -39,6 +40,46 @@ from megatron.bridge.training.utils.visual_inputs import Qwen2_5_VLVisualInputs +logger = logging.getLogger(__name__) + + +def _search_for_fit(numbers: List[int], capacity: int) -> int: + """Binary search for the largest number that fits within capacity.""" + index = bisect.bisect(numbers, capacity) + return -1 if index == 0 else (index - 1) + + +def greedy_knapsack(item_sizes: List[int], samples: List, max_capacity: int) -> List: + """Greedy bin-packing with binary search. + + Sorts samples by length ascending, then greedily fills each bin by picking + the largest item that still fits (via binary search). Returns a list of bins, + each bin being a list of samples. + """ + assert len(item_sizes) == len(samples) + if not item_sizes: + return [] + + sorted_sizes, sorted_samples = zip(*sorted(zip(item_sizes, samples), key=lambda x: x[0])) + sorted_sizes = list(sorted_sizes) + sorted_samples = list(sorted_samples) + + if sorted_sizes[-1] > max_capacity: + raise ValueError(f"Sample size {sorted_sizes[-1]} exceeds max_capacity {max_capacity}") + + knapsacks = [] + while sorted_sizes: + current_knapsack = [] + remaining = max_capacity + while True: + idx = _search_for_fit(sorted_sizes, remaining) + if idx == -1: + break + remaining -= sorted_sizes[idx] + sorted_sizes.pop(idx) + current_knapsack.append(sorted_samples.pop(idx)) + knapsacks.append(current_knapsack) + return knapsacks def process_vision( processor, images, videos, fps=None, model_version: str = "qwen-vl", min_pixels=None, max_pixels=None ): @@ -103,6 +144,31 @@ class QwenVLTaskSample: video_input_mask: torch.Tensor text: torch.Tensor target: torch.Tensor + total_len: int = 0 + + +@dataclass +class QwenVLTaskSamplePacked: + """Packed sample: multiple QwenVLTaskSample concatenated into one sequence.""" + + __key__: str + __subflavors__: Dict + tokens: torch.Tensor + target: torch.Tensor + imgs: list + videos: list + image_thw_grids: list + video_thw_grids: list + image_input_mask: torch.Tensor + video_input_mask: torch.Tensor + cu_lengths: torch.Tensor + max_length: int + num_sub_samples: int + sub_sample_lengths: list = field(default_factory=list) + num_image_tokens: int = 0 + num_video_tokens: int = 0 + num_text_tokens: int = 0 + num_vit_patches: int = 0 @dataclass @@ -125,6 +191,10 @@ class QwenVLTaskBatch(Batch): position_ids: torch.Tensor labels: torch.Tensor loss_mask: torch.Tensor + # Packing metadata (set when using Energon packing) + cu_lengths: Optional[torch.Tensor] = None + max_lengths: Optional[torch.Tensor] = None + cu_seqlens_argmin: Optional[torch.Tensor] = None def convert_to_qwenvl_content(user_input: str, image_pattern: str = "", video_pattern: str = "