Skip to content

Commit a0867fa

Browse files
author
mokai
committed
aiak-train-2121 [Task] [AIAK-Training-Omni] Skip overlong Kimi VLM samples and handle text-only multimodal inputs
Change-Id: I70f2ddcf1cbdd85027f6f375fb7c5cd47903dca5 (cherry picked from commit 0270d66)
1 parent 86f69f3 commit a0867fa

2 files changed

Lines changed: 78 additions & 28 deletions

File tree

loongforge/data/kimi_k25_plugin.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,9 @@ def _get_mm_inputs(
149149
pixel_values: tensor with shape (num_patches, patch_dim)
150150
grid_thws: tensor with shape (num_images, 3) for [T, H, W]
151151
"""
152-
import torch
152+
mm_inputs = {}
153+
if len(images) == 0 and len(videos) == 0:
154+
return mm_inputs
153155

154156
# Use Kimi's media processor
155157
media_processor = getattr(processor, 'media_processor', None)
@@ -159,8 +161,6 @@ def _get_mm_inputs(
159161
if media_processor is None:
160162
raise ValueError("Processor must have media_processor or image_processor")
161163

162-
mm_inputs = {}
163-
164164
if len(images) != 0:
165165
# Regularize images first
166166
images = self._regularize_images(
@@ -255,12 +255,14 @@ def process_messages(
255255

256256
num_image_tokens, num_video_tokens = 0, 0
257257
messages = deepcopy(messages)
258+
has_images = len(images) > 0
259+
has_videos = len(videos) > 0
258260

259261
for message in messages:
260262
content = message["content"]
261263

262264
# Replace image placeholders
263-
while Placeholder.IMAGE in content:
265+
while has_images and Placeholder.IMAGE in content:
264266
if num_image_tokens >= len(image_grid_thw):
265267
raise ValueError(
266268
f"`len(images)` ({len(images)}) is less than the number of "
@@ -279,7 +281,7 @@ def process_messages(
279281
num_image_tokens += 1
280282

281283
# Replace video placeholders
282-
while Placeholder.VIDEO in content:
284+
while has_videos and Placeholder.VIDEO in content:
283285
if num_video_tokens >= len(video_grid_thw):
284286
raise ValueError(
285287
f"`len(videos)` ({len(videos)}) is less than the number of "
@@ -301,13 +303,13 @@ def process_messages(
301303
message["content"] = content
302304

303305
# Validate counts
304-
if len(images) != num_image_tokens:
306+
if has_images and len(images) != num_image_tokens:
305307
raise ValueError(
306308
f"The number of images ({len(images)}) does not match "
307309
f"the number of {Placeholder.IMAGE} tokens ({num_image_tokens})"
308310
)
309311

310-
if len(videos) != num_video_tokens:
312+
if has_videos and len(videos) != num_video_tokens:
311313
raise ValueError(
312314
f"The number of videos ({len(videos)}) does not match "
313315
f"the number of {Placeholder.VIDEO} tokens ({num_video_tokens})"

loongforge/data/multimodal/kimi_task_encoder.py

Lines changed: 69 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
"""Kimi Task Encoder."""
55

6+
import logging
67
import torch
78
from loongforge.data.multimodal.vlm_task_encoder import VLMTaskEncoder
89
from typing import Dict, List, Optional, Tuple, Union
@@ -26,6 +27,8 @@
2627

2728

2829
from loongforge.utils import constants, get_chat_template
30+
from megatron.energon.task_encoder.base import stateless
31+
from loongforge.data.multimodal import MultiMixQASample, MultiVidQASample
2932
from .base.task_encoder import (
3033
BaseTaskEncoder,
3134
BaseTaskSample,
@@ -96,6 +99,51 @@ def __init__(self, args):
9699
else:
97100
self.merge_kernel_size = list(merge_kernel_size)
98101

102+
def _sample_sequence_limit(self) -> int:
103+
sequence_limit = self.args.seq_length
104+
packed_limit = getattr(self.args, "max_packed_tokens", None)
105+
if self.is_packing_enabled and packed_limit is not None:
106+
sequence_limit = min(sequence_limit, packed_limit)
107+
return sequence_limit
108+
109+
def _should_discard_overlong(self, sample, input_ids) -> bool:
110+
if not self.args.enable_discard_sample:
111+
return False
112+
113+
sequence_limit = self._sample_sequence_limit()
114+
input_length = len(input_ids)
115+
if input_length <= sequence_limit:
116+
return False
117+
118+
logging.warning(
119+
"discard overlong sample %s: input length %s > sequence limit %s",
120+
sample.__key__,
121+
input_length,
122+
sequence_limit,
123+
)
124+
return True
125+
126+
@stateless(restore_seeds=True)
127+
def encode_sample(
128+
self,
129+
sample: Union[CaptioningSample, VQASample, MultiVidQASample, MultiMixQASample],
130+
):
131+
"""Return tokenised multimodal sample."""
132+
if isinstance(sample, CaptioningSample):
133+
encoded_sample = self.encode_captioning(sample)
134+
elif isinstance(sample, VQASample):
135+
encoded_sample = self.encode_vqa(sample)
136+
elif isinstance(sample, MultiVidQASample):
137+
encoded_sample = self.encode_multi_vid_qa(sample)
138+
elif isinstance(sample, MultiMixQASample):
139+
encoded_sample = self.encode_multi_mix_qa(sample)
140+
else:
141+
yield from super().encode_sample(sample)
142+
return
143+
144+
if encoded_sample is not None:
145+
yield encoded_sample
146+
99147
def _get_vision_token_ids(self):
100148
"""Get special token IDs for vision processing."""
101149
media_begin_id = self.tokenizer.convert_tokens_to_ids(MEDIA_BEGIN)
@@ -352,11 +400,9 @@ def encode_captioning(self, sample: CaptioningSample) -> BaseTaskSample:
352400
)
353401
num_tiles = [len(image_grid_thw)] if image_grid_thw is not None else [0]
354402

355-
if self.args.enable_discard_sample:
356-
assert (
357-
len(input_ids) <= self.args.seq_length
358-
), f"{sample.__key__} input length {len(input_ids)}"
359-
elif image_grid_thw is not None:
403+
if self._should_discard_overlong(sample, input_ids):
404+
return None
405+
if not self.args.enable_discard_sample and image_grid_thw is not None:
360406
assert (
361407
image_grid_thw.prod() / 4 <= self.args.seq_length
362408
), f"{sample.__key__} thw {image_grid_thw}"
@@ -414,11 +460,9 @@ def encode_vqa(self, sample: VQASample) -> BaseTaskSample:
414460

415461
num_tiles = [len(image_grid_thw)] if image_grid_thw is not None else [0]
416462

417-
if self.args.enable_discard_sample:
418-
assert (
419-
len(input_ids) <= self.args.seq_length
420-
), f"{sample.__key__} input length {len(input_ids)}"
421-
elif image_grid_thw is not None:
463+
if self._should_discard_overlong(sample, input_ids):
464+
return None
465+
if not self.args.enable_discard_sample and image_grid_thw is not None:
422466
assert (
423467
image_grid_thw.prod() / 4 <= self.args.seq_length
424468
), f"{sample.__key__} grid_thw: {image_grid_thw}"
@@ -564,15 +608,21 @@ def encode_multi_mix_qa(self, sample) -> BaseTaskSample:
564608
f"Unknown training phase {self.args.training_phase}"
565609
)
566610

567-
if self.args.enable_discard_sample:
568-
assert (
569-
len(input_ids) <= self.args.seq_length
570-
), f"{sample.__key__} input length {len(input_ids)}"
571-
elif sample.video is not None and video_grid_thw is not None:
611+
if self._should_discard_overlong(sample, input_ids):
612+
return None
613+
if (
614+
not self.args.enable_discard_sample
615+
and sample.video is not None
616+
and video_grid_thw is not None
617+
):
572618
assert (
573619
video_grid_thw.prod(dim=-1).sum() / 4 <= self.args.seq_length
574620
), f"{sample.__key__} grid_thw: {video_grid_thw}"
575-
elif sample.image is not None and image_grid_thw is not None:
621+
elif (
622+
not self.args.enable_discard_sample
623+
and sample.image is not None
624+
and image_grid_thw is not None
625+
):
576626
assert (
577627
image_grid_thw.prod(dim=-1).sum() / 4 <= self.args.seq_length
578628
), f"{sample.__key__} grid_thw: {image_grid_thw}"
@@ -626,11 +676,9 @@ def encode_multi_vid_qa(self, sample) -> BaseTaskSample:
626676
f"Unknown training phase {self.args.training_phase}"
627677
)
628678

629-
if self.args.enable_discard_sample:
630-
assert (
631-
len(input_ids) <= self.args.seq_length
632-
), f"{sample.__key__} input length {len(input_ids)}"
633-
elif video_grid_thw is not None:
679+
if self._should_discard_overlong(sample, input_ids):
680+
return None
681+
if not self.args.enable_discard_sample and video_grid_thw is not None:
634682
assert (
635683
video_grid_thw.prod(dim=-1).sum() / 4 <= self.args.seq_length
636684
), f"{sample.__key__} grid_thw: {video_grid_thw}"

0 commit comments

Comments
 (0)