CCCCyx commited on
Commit
2cb8df5
·
verified ·
1 Parent(s): 5b97f7a

Unify modeling with the 0708 standard (transformers 4.57 compatible)

Browse files
Files changed (1) hide show
  1. modeling_moss_vl.py +188 -184
modeling_moss_vl.py CHANGED
@@ -111,12 +111,12 @@ logger = logging.get_logger(__name__)
111
  class MossVLModelOutputWithPast(ModelOutput):
112
  """
113
  Output class for MossVL model with additional vision_token_info and rope_deltas fields.
114
-
115
  Args:
116
  last_hidden_state (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
117
  Sequence of hidden-states at the output of the last layer of the model.
118
  past_key_values (`Cache`, *optional*):
119
- Contains pre-computed hidden-states (key and values in the self-attention blocks and
120
  cross-attention blocks) that can be used to speed up sequential decoding.
121
  hidden_states (`tuple(torch.FloatTensor)`, *optional*):
122
  Tuple of `torch.FloatTensor` (one for the output of the embeddings + one for each layer).
@@ -129,7 +129,7 @@ class MossVLModelOutputWithPast(ModelOutput):
129
  Position offset due to vision tokens. Used for fast position computation in decode stage.
130
  rope_deltas = max_position - sequence_length
131
  """
132
-
133
  last_hidden_state: Optional[torch.FloatTensor] = None
134
  past_key_values: Optional[Cache] = None
135
  hidden_states: Optional[tuple[torch.FloatTensor]] = None
@@ -142,7 +142,7 @@ class MossVLModelOutputWithPast(ModelOutput):
142
  class MossVLCausalLMOutputWithPast(ModelOutput):
143
  """
144
  Output class for MossVL causal language model with additional vision_token_info and rope_deltas fields.
145
-
146
  Args:
147
  loss (`torch.FloatTensor` of shape `(1,)`, *optional*):
148
  Language modeling loss (for next-token prediction).
@@ -159,7 +159,7 @@ class MossVLCausalLMOutputWithPast(ModelOutput):
159
  rope_deltas (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
160
  Position offset due to vision tokens. Used for fast position computation in decode stage.
161
  """
162
-
163
  loss: Optional[torch.FloatTensor] = None
164
  logits: Optional[torch.FloatTensor] = None
165
  past_key_values: Optional[Cache] = None
@@ -225,7 +225,7 @@ class MossVLVisionPatchMerger(nn.Module):
225
  base_hidden_size = config.hidden_size * (config.spatial_merge_size**2)
226
  # 计算输入维度:spatial_merge 后的维度 * (1 + deepstack特征数)
227
  self.input_hidden_size = base_hidden_size * (1 + num_deepstack_features)
228
-
229
  # Use independent LayerNorms for each feature level
230
  # Total features = 1 (last layer) + num_deepstack_features
231
  num_features = 1 + num_deepstack_features
@@ -233,9 +233,9 @@ class MossVLVisionPatchMerger(nn.Module):
233
  nn.LayerNorm(config.hidden_size, eps=1e-6)
234
  for _ in range(num_features)
235
  ])
236
-
237
  self.hidden_size = config.hidden_size
238
-
239
  self.linear_fc1 = nn.Linear(self.input_hidden_size, self.input_hidden_size)
240
  self.act_fn = nn.GELU()
241
  self.linear_fc2 = nn.Linear(self.input_hidden_size, config.out_hidden_size)
@@ -244,14 +244,14 @@ class MossVLVisionPatchMerger(nn.Module):
244
  # 1. Collect all features: [last_hidden_state, deepstack_1, deepstack_2, ...]
245
  # self.norms[0] corresponds to last_hidden_state
246
  # self.norms[1:] corresponds to deepstack_features
247
-
248
  all_inputs = [last_hidden_state] + deepstack_features
249
-
250
  # 2. Apply Norm independently
251
  outs = []
252
  for i, feat in enumerate(all_inputs):
253
  outs.append(self.norms[i](feat))
254
-
255
  # 3. Concat once
256
  x = torch.cat(outs, dim=-1)
257
 
@@ -480,7 +480,7 @@ class MossVLTextRotaryEmbedding(nn.Module):
480
 
481
  if position_ids.ndim == 2:
482
  position_ids = position_ids[None, ...].expand(3, position_ids.shape[0], -1)
483
-
484
  inv_freq_expanded = self.inv_freq[None, None, :, None].float().expand(3, position_ids.shape[1], -1, 1)
485
  position_ids_expanded = position_ids[:, :, None, :].float() # shape (3, bs, 1, positions)
486
 
@@ -628,7 +628,7 @@ class MossVLTextCrossAttention(nn.Module):
628
  def forward(
629
  self,
630
  hidden_states: torch.Tensor,
631
- cross_attention_states: torch.Tensor,
632
  attention_mask: Optional[torch.Tensor] = None,
633
  past_key_values: Optional[Cache] = None,
634
  use_cache: bool = None,
@@ -638,7 +638,7 @@ class MossVLTextCrossAttention(nn.Module):
638
  **kwargs,
639
  ) -> torch.Tensor:
640
  batch_size, seq_length, _ = hidden_states.size()
641
-
642
  # Query from text hidden states
643
  query_states = self.q_proj(hidden_states)
644
  query_states = query_states.view(batch_size, seq_length, self.num_heads, self.head_dim).transpose(1, 2)
@@ -653,13 +653,13 @@ class MossVLTextCrossAttention(nn.Module):
653
  # Key and Value from vision cross_attention_states
654
  key_states = self.k_proj(cross_attention_states)
655
  value_states = self.v_proj(cross_attention_states)
656
-
657
  key_states = key_states.view(batch_size, -1, self.num_key_value_heads, self.head_dim).transpose(1, 2)
658
  key_states = self.k_norm(key_states)
659
  value_states = value_states.view(batch_size, -1, self.num_key_value_heads, self.head_dim).transpose(1, 2)
660
 
661
  # Rotate new keys once; cached keys already include vision RoPE.
662
-
663
  if vision_position_embeddings is not None:
664
  vision_cos, vision_sin = vision_position_embeddings
665
  key_states = apply_rotary_pos_emb_cross_attention(key_states, vision_cos, vision_sin)
@@ -670,13 +670,13 @@ class MossVLTextCrossAttention(nn.Module):
670
  # we still update the cross key states, past_image, new_image. And use it!
671
  key_states, value_states = past_key_values.update(
672
  key_states, value_states, self.layer_idx, {"cache_position": cache_position}
673
- )
674
-
675
  elif cache_position[0] != 0:
676
  key_states, value_states = (
677
  past_key_values.layers[self.layer_idx].keys,
678
  past_key_values.layers[self.layer_idx].values,
679
- )
680
  else:
681
  raise ValueError(
682
  "Cross attention layer can't find neither `cross_attn_states` nor cached values for key/values!"
@@ -771,7 +771,7 @@ class MossVLSelfAttentionDecoderLayer(GradientCheckpointingLayer):
771
  hidden_states = self.post_attention_layernorm(hidden_states)
772
  hidden_states = self.mlp(hidden_states)
773
  hidden_states = residual + hidden_states
774
-
775
  return hidden_states
776
 
777
 
@@ -785,10 +785,10 @@ class MossVLCrossAttentionDecoderLayer(GradientCheckpointingLayer):
785
 
786
  self.cross_attn = MossVLTextCrossAttention(config=config, layer_idx=layer_idx)
787
  self.mlp = MossVLTextMLP(config)
788
-
789
  self.input_layernorm = MossVLTextRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
790
  self.post_attention_layernorm = MossVLTextRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
791
-
792
  # Gates for cross attention (single scalar value).
793
  # Gate scalar = tanh(gate[0]), initialized to zero so tanh(0)=0 at start.
794
  self.cross_attn_attn_gate = nn.Parameter(torch.zeros(1))
@@ -815,7 +815,7 @@ class MossVLCrossAttentionDecoderLayer(GradientCheckpointingLayer):
815
  # Cross Attention
816
  residual = hidden_states
817
  hidden_states = self.input_layernorm(hidden_states)
818
-
819
  hidden_states, _ = self.cross_attn(
820
  hidden_states=hidden_states,
821
  cross_attention_states=cross_attention_states,
@@ -839,7 +839,7 @@ class MossVLCrossAttentionDecoderLayer(GradientCheckpointingLayer):
839
  hidden_states = full_text_row_masked_out_mask[:, 0] * hidden_states
840
 
841
  hidden_states = residual + self.cross_attn_mlp_gate.tanh() * hidden_states
842
-
843
  return hidden_states
844
 
845
 
@@ -866,7 +866,7 @@ class MossVLPreTrainedModel(PreTrainedModel):
866
 
867
  def _init_weights(self, module):
868
  """Initialize the weights.
869
-
870
  Note: For loading pretrained weights:
871
  - Cross attention: can be initialized from the previous layer's self attention weights
872
  """
@@ -884,7 +884,7 @@ class MossVLPreTrainedModel(PreTrainedModel):
884
  module.linear_fc1.bias.data.zero_()
885
  if module.linear_fc2.bias is not None:
886
  module.linear_fc2.bias.data.zero_()
887
-
888
  # Initialize separate LayerNorms
889
  if hasattr(module, "norms"):
890
  for norm in module.norms:
@@ -915,14 +915,14 @@ class MossVLVisionModel(MossVLPreTrainedModel):
915
  self.rotary_pos_emb = MossVLVisionRotaryEmbedding(head_dim // 2)
916
 
917
  self.blocks = nn.ModuleList([MossVLVisionBlock(config) for _ in range(config.depth)])
918
-
919
  # DeepStack: 记录需要提取特征的层索引
920
  self.deepstack_visual_indexes = config.deepstack_visual_indexes
921
  num_deepstack_features = len(self.deepstack_visual_indexes)
922
-
923
  # Merger: 输入维度 = hidden_size * (1 + num_deepstack_features)
924
  self.merger = MossVLVisionPatchMerger(
925
- config=config,
926
  num_deepstack_features=num_deepstack_features
927
  )
928
 
@@ -1027,9 +1027,9 @@ class MossVLVisionModel(MossVLPreTrainedModel):
1027
  return patch_pos_embeds
1028
 
1029
  def forward(
1030
- self,
1031
- hidden_states: torch.Tensor,
1032
- grid_thw: torch.Tensor,
1033
  **kwargs
1034
  ) -> torch.Tensor:
1035
  """
@@ -1097,10 +1097,10 @@ class MossVLTextModel(MossVLPreTrainedModel):
1097
  self.vocab_size = config.vocab_size
1098
 
1099
  self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
1100
-
1101
  # Store cross_attention_layers for use in forward pass
1102
  self.cross_attention_layers = config.cross_attention_layers
1103
-
1104
  # Create layers: self-attention or cross-attention at specified indices
1105
  self.layers = nn.ModuleList()
1106
  for layer_idx in range(config.num_hidden_layers):
@@ -1114,7 +1114,7 @@ class MossVLTextModel(MossVLPreTrainedModel):
1114
  self.layers.append(
1115
  MossVLSelfAttentionDecoderLayer(config, layer_idx)
1116
  )
1117
-
1118
  self.norm = MossVLTextRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
1119
  self.rotary_emb = MossVLTextRotaryEmbedding(config=config)
1120
  self.gradient_checkpointing = False
@@ -1136,7 +1136,7 @@ class MossVLTextModel(MossVLPreTrainedModel):
1136
  vision_position_ids: Optional[torch.LongTensor] = None,
1137
  use_cache: Optional[bool] = None,
1138
  cache_position: Optional[torch.LongTensor] = None,
1139
- vision_cache_position: Optional[torch.LongTensor] = None,
1140
  **kwargs: Unpack[FlashAttentionKwargs],
1141
  ) -> Union[tuple, BaseModelOutputWithPast]:
1142
  """
@@ -1250,7 +1250,7 @@ class MossVLModel(MossVLPreTrainedModel):
1250
  self.visual = MossVLVisionModel._from_config(config.vision_config)
1251
  self.language_model = MossVLTextModel._from_config(config.text_config)
1252
  self.vision_token_info = None # cache vision_token_info here for decode stage
1253
- self.rope_deltas = None # cache position deltas for decode stage
1254
 
1255
  # Learnable Separator Token: inserted after each image/frame's vision tokens
1256
  # Initialized from LLM's separator_token_init_id embedding
@@ -1259,7 +1259,7 @@ class MossVLModel(MossVLPreTrainedModel):
1259
  )
1260
 
1261
  self.post_init()
1262
-
1263
 
1264
 
1265
  def convert_packed_to_batch(
@@ -1270,25 +1270,25 @@ class MossVLModel(MossVLPreTrainedModel):
1270
  ) -> Tuple[torch.Tensor, List[dict]]:
1271
  """
1272
  Convert packed vision tokens to batched format with separator tokens.
1273
-
1274
  For each image: inserts 1 separator token after the vision tokens.
1275
  For each video: inserts 1 separator token after EACH frame's vision tokens.
1276
-
1277
- Note: media_nums_per_sample counts each video as 1 media item,
1278
  but each frame in a video gets its own separator token.
1279
  """
1280
-
1281
  # Calculate number of tokens per media after spatial merge
1282
  tokens_per_media = (grid_thw[:, 0] * grid_thw[:, 1] * grid_thw[:, 2]) // (self.visual.spatial_merge_size ** 2)
1283
  hidden_size = hidden_states.shape[-1]
1284
-
1285
  # If media_nums_per_sample is not provided, assume batch size = 1
1286
  if media_nums_per_sample is None:
1287
  batch_size = 1
1288
  media_nums_per_sample = [grid_thw.shape[0]]
1289
  else:
1290
  batch_size = len(media_nums_per_sample)
1291
-
1292
  # Optimization for batch_size = 1 (common in inference)
1293
  if batch_size == 1:
1294
  # 1. Calculate total length (pure math, fast)
@@ -1297,21 +1297,21 @@ class MossVLModel(MossVLPreTrainedModel):
1297
  num_tokens = tokens_per_media[i].item()
1298
  num_frames = grid_thw[i, 0].item()
1299
  total_len += num_tokens + num_frames # + separators
1300
-
1301
  # 2. Handle Padding alignment
1302
  pad_multiple = self.config.vision_seq_pad_multiple
1303
  if total_len % pad_multiple != 0:
1304
  max_seq_len = (total_len + pad_multiple - 1) // pad_multiple * pad_multiple
1305
  else:
1306
  max_seq_len = total_len
1307
-
1308
  # 3. Pre-allocate final tensor
1309
  batched_hidden_states = torch.zeros(
1310
  1, max_seq_len, hidden_size,
1311
  dtype=hidden_states.dtype,
1312
  device=hidden_states.device
1313
  )
1314
-
1315
  # 4. Vectorized fill
1316
  sample_info = {
1317
  'medias': [],
@@ -1319,41 +1319,41 @@ class MossVLModel(MossVLPreTrainedModel):
1319
  'pad_start': total_len,
1320
  'pad_end': max_seq_len
1321
  }
1322
-
1323
  token_offset = 0
1324
  current_seq_len = 0
1325
  separator_embedding = self.separator_token.to(hidden_states.dtype)
1326
-
1327
  # Iterate through all medias in this single sample
1328
  for media_idx in range(grid_thw.shape[0]):
1329
  num_tokens = tokens_per_media[media_idx].item()
1330
  t, h, w = grid_thw[media_idx].tolist()
1331
  num_frames = t
1332
  tokens_per_frame = num_tokens // num_frames
1333
-
1334
  # --- Vectorized processing start ---
1335
  # Extract vision tokens: (num_tokens, hidden)
1336
  media_vision_tokens = hidden_states[token_offset : token_offset + num_tokens]
1337
-
1338
  # Reshape to (num_frames, tokens_per_frame, hidden)
1339
  media_vision_tokens = media_vision_tokens.view(num_frames, tokens_per_frame, hidden_size)
1340
-
1341
  # Directly write to destination without creating intermediate large tensors
1342
  chunk_len = num_frames * (tokens_per_frame + 1)
1343
-
1344
  # Get view of the target area: (num_frames, tokens_per_frame + 1, hidden)
1345
  target_view = batched_hidden_states[0, current_seq_len : current_seq_len + chunk_len]
1346
  target_view = target_view.view(num_frames, tokens_per_frame + 1, hidden_size)
1347
-
1348
  # 1. Fill vision tokens
1349
  target_view[:, :tokens_per_frame].copy_(media_vision_tokens)
1350
-
1351
  # 2. Fill separators (Broadcast assignment)
1352
  # separator_embedding is (hidden,), automatically broadcasts to (num_frames, hidden)
1353
  target_view[:, tokens_per_frame] = separator_embedding
1354
-
1355
  # --- Vectorized processing end ---
1356
-
1357
  sample_info['medias'].append({
1358
  'start': current_seq_len,
1359
  'end': current_seq_len + chunk_len,
@@ -1364,12 +1364,12 @@ class MossVLModel(MossVLPreTrainedModel):
1364
  'vision_tokens_per_frame': tokens_per_frame,
1365
  'has_separator': True,
1366
  })
1367
-
1368
  current_seq_len += chunk_len
1369
  token_offset += num_tokens
1370
-
1371
  vision_token_info = [sample_info]
1372
-
1373
  return batched_hidden_states, vision_token_info
1374
 
1375
  # Calculate tokens per sample including separator tokens
@@ -1385,29 +1385,29 @@ class MossVLModel(MossVLPreTrainedModel):
1385
  sample_tokens += num_tokens + num_frames # +num_frames separator tokens
1386
  tokens_per_sample.append(sample_tokens)
1387
  media_idx += num_medias_in_sample
1388
-
1389
  max_seq_len = max(tokens_per_sample)
1390
  pad_multiple = self.config.vision_seq_pad_multiple
1391
  if max_seq_len % pad_multiple != 0:
1392
  max_seq_len = (max_seq_len + pad_multiple - 1) // pad_multiple * pad_multiple
1393
-
1394
  # Initialize batched output with zeros (for padding)
1395
  batched_hidden_states = torch.zeros(
1396
  batch_size, max_seq_len, hidden_size,
1397
  dtype=hidden_states.dtype,
1398
  device=hidden_states.device
1399
  )
1400
-
1401
  # Get separator token (learnable parameter)
1402
  separator_embedding = self.separator_token.to(hidden_states.dtype)
1403
-
1404
  # Track token positions for each sample
1405
  vision_token_info = []
1406
-
1407
  # Split packed tensor and fill batched output
1408
  token_offset = 0
1409
  media_idx = 0
1410
-
1411
  for sample_idx, num_medias_in_sample in enumerate(media_nums_per_sample):
1412
  sample_info = {
1413
  'medias': [], # List of dicts for each media in this sample
@@ -1415,45 +1415,45 @@ class MossVLModel(MossVLPreTrainedModel):
1415
  'pad_start': tokens_per_sample[sample_idx],
1416
  'pad_end': max_seq_len
1417
  }
1418
-
1419
  seq_offset = 0 # Offset within this sample's sequence
1420
-
1421
  # Process each image/video in this sample
1422
  for _ in range(num_medias_in_sample):
1423
  num_tokens = tokens_per_media[media_idx].item()
1424
-
1425
  t, h, w = grid_thw[media_idx].tolist()
1426
  num_frames = t
1427
  tokens_per_frame = num_tokens // num_frames
1428
-
1429
  # Record start position for this media
1430
  media_start = seq_offset
1431
-
1432
  # Vectorized handling of frames
1433
  # Extract vision tokens for this media: (num_tokens, hidden)
1434
  media_vision_tokens = hidden_states[token_offset : token_offset + num_tokens]
1435
-
1436
  # Reshape to (num_frames, tokens_per_frame, hidden)
1437
  media_vision_tokens = media_vision_tokens.view(num_frames, tokens_per_frame, hidden_size)
1438
-
1439
  # Create separators: (num_frames, 1, hidden)
1440
  separators = separator_embedding.view(1, 1, hidden_size).expand(num_frames, 1, hidden_size)
1441
-
1442
  # Concatenate: (num_frames, tokens_per_frame + 1, hidden)
1443
  media_tokens_with_sep = torch.cat([media_vision_tokens, separators], dim=1)
1444
-
1445
  # Flatten: (num_frames * (tokens_per_frame + 1), hidden)
1446
  media_tokens_with_sep = media_tokens_with_sep.view(-1, hidden_size)
1447
-
1448
  # Assign to batched tensor
1449
  media_length_with_sep = media_tokens_with_sep.shape[0]
1450
  batched_hidden_states[sample_idx, seq_offset : seq_offset + media_length_with_sep] = media_tokens_with_sep
1451
-
1452
  seq_offset += media_length_with_sep
1453
-
1454
  # Total tokens for this media = vision_tokens + num_separators
1455
  media_length = num_tokens + num_frames
1456
-
1457
  # Record this image/video's position within the sample
1458
  # Note: length now includes separator tokens
1459
  sample_info['medias'].append({
@@ -1466,12 +1466,12 @@ class MossVLModel(MossVLPreTrainedModel):
1466
  'vision_tokens_per_frame': tokens_per_frame, # Actual vision tokens per frame (excluding separator)
1467
  'has_separator': True, # Flag indicating separator tokens are included
1468
  })
1469
-
1470
  token_offset += num_tokens
1471
  media_idx += 1
1472
-
1473
  vision_token_info.append(sample_info)
1474
-
1475
  return batched_hidden_states, vision_token_info
1476
 
1477
  def get_input_embeddings(self):
@@ -1494,7 +1494,7 @@ class MossVLModel(MossVLPreTrainedModel):
1494
  ) -> torch.Tensor:
1495
  """
1496
  Expand cross_attention_mask from (B, 1, T, N_frames) to (B, 1, T, N_tokens).
1497
-
1498
  Args:
1499
  cross_attention_mask (`torch.Tensor` of shape `(batch_size, 1, text_seq_len, num_frames)`):
1500
  Coarse attention mask where each frame corresponds to one column.
@@ -1505,12 +1505,12 @@ class MossVLModel(MossVLPreTrainedModel):
1505
  Each dict contains 'medias' list with 'length', 'num_frames', and 'vision_tokens_per_frame'.
1506
  target_dtype (`torch.dtype`):
1507
  Target dtype for the output mask (typically inputs_embeds.dtype).
1508
-
1509
  Returns:
1510
  `torch.Tensor` of shape `(batch_size, 1, text_seq_len, total_vision_tokens)`:
1511
  Fine-grained attention mask where each vision token has its own column.
1512
  Masked positions have min_value, unmasked positions have 0.0.
1513
-
1514
  Note:
1515
  - vision_token_info contains the actual token counts after ViT padding (pad to multiple of 8)
1516
  - Separator tokens are treated as part of the same frame, sharing the same mask
@@ -1520,9 +1520,9 @@ class MossVLModel(MossVLPreTrainedModel):
1520
  "vision_token_info must be provided to _expand_cross_attention_mask. "
1521
  "This should be cached from prefill stage or computed during current forward pass."
1522
  )
1523
-
1524
  batch_size = cross_attention_mask.shape[0]
1525
-
1526
  # Determine target vision length (should be consistent across batch, but take max to be safe)
1527
  max_vision_len = 0
1528
  if vision_token_info:
@@ -1552,59 +1552,59 @@ class MossVLModel(MossVLPreTrainedModel):
1552
  dtype=target_dtype,
1553
  device=cross_attention_mask.device
1554
  )
1555
-
1556
  for i in range(batch_size):
1557
  medias = vision_token_info[i]['medias']
1558
  if not medias:
1559
  continue
1560
-
1561
  # Collect repetition counts for all frames in this sample
1562
  repeats = []
1563
  for media in medias:
1564
  num_frames = media.get('num_frames', 1)
1565
  length = media['length']
1566
  has_separator = media.get('has_separator', False)
1567
-
1568
  # Determine tokens per frame (including separator)
1569
  if has_separator:
1570
  vision_tokens_per_frame = media.get('vision_tokens_per_frame', (length // num_frames) - 1)
1571
  tokens_per_frame_with_sep = vision_tokens_per_frame + 1
1572
  else:
1573
  tokens_per_frame_with_sep = length // num_frames
1574
-
1575
  # In convert_packed_to_batch we enforce strictly regular frames
1576
  # so we can assume all frames have the same number of tokens
1577
  repeats.extend([tokens_per_frame_with_sep] * num_frames)
1578
-
1579
  num_valid_frames = len(repeats)
1580
  if num_valid_frames == 0:
1581
  continue
1582
-
1583
  # If cross_attention_mask has more frames (e.g. padded), slice it
1584
  # If it has fewer (shouldn't happen), slice repeats
1585
  valid_mask_frames = min(num_valid_frames, cross_attention_mask.shape[-1])
1586
  if valid_mask_frames < num_valid_frames:
1587
  repeats = repeats[:valid_mask_frames]
1588
-
1589
  # Extract valid columns for this sample
1590
  # (1, text_len, valid_mask_frames)
1591
  source_mask = cross_attention_mask[i, :, :, :valid_mask_frames]
1592
-
1593
  # Convert repeats to tensor
1594
  repeats_tensor = torch.tensor(repeats, device=cross_attention_mask.device)
1595
-
1596
  # Expand using repeat_interleave
1597
  # output shape: (1, text_len, sum(repeats))
1598
  expanded_mask = source_mask.repeat_interleave(repeats_tensor, dim=-1)
1599
-
1600
  # Assign to final_mask
1601
  num_tokens = expanded_mask.shape[-1]
1602
  if num_tokens > max_vision_len:
1603
  num_tokens = max_vision_len
1604
  expanded_mask = expanded_mask[..., :num_tokens]
1605
-
1606
  final_mask[i, :, :, :num_tokens] = expanded_mask
1607
-
1608
  return final_mask
1609
 
1610
  def compute_position_ids(
@@ -1615,89 +1615,89 @@ class MossVLModel(MossVLPreTrainedModel):
1615
  ) -> torch.Tensor:
1616
  """
1617
  Compute 3D position IDs for text tokens with special handling for image tokens.
1618
-
1619
  Rules:
1620
  - Regular text tokens: increment position (x, x, x) -> (x+1, x+1, x+1)
1621
  - Image token: gets (t, t, t) where t = previous_text_position + 1
1622
  - After processing vision tokens, next text token starts at max(vision_bottom_right) + 1
1623
-
1624
  In decode stage, uses cached rope_deltas to quickly compute new positions.
1625
-
1626
  Args:
1627
  input_ids: (batch_size, seq_len)
1628
  attention_mask: (batch_size, seq_len), optional
1629
  cache_position: (seq_len,), position in cache
1630
-
1631
  Returns:
1632
  position_ids: (3, batch_size, seq_len)
1633
  """
1634
  batch_size, seq_len = input_ids.shape
1635
  device = input_ids.device
1636
  image_token_id = self.config.image_token_id
1637
-
1638
  # Decode stage: use cached rope_deltas for fast computation
1639
  if cache_position is not None and cache_position[0] != 0 and self.rope_deltas is not None:
1640
  # In decode, position = cache_position + rope_deltas
1641
  # rope_deltas is per-sample: (batch_size,)
1642
  position_ids = torch.arange(seq_len, device=device, dtype=torch.long)
1643
  position_ids = position_ids.unsqueeze(0).expand(batch_size, -1) # (batch, seq_len)
1644
-
1645
  # Add cache_position offset
1646
  if cache_position is not None:
1647
  position_ids = position_ids + cache_position[0]
1648
-
1649
  # Add rope_deltas (position offset due to vision tokens)
1650
  # self.rope_deltas shape: (batch_size,), need to unsqueeze for broadcasting
1651
  position_ids = position_ids + self.rope_deltas.unsqueeze(1) # (batch, seq_len)
1652
-
1653
  # Expand to 3D: (3, batch, seq_len)
1654
  position_ids = position_ids.unsqueeze(0).expand(3, -1, -1)
1655
-
1656
  return position_ids
1657
-
1658
  # Prefill stage: compute full position_ids with image token awareness
1659
  # Vectorized implementation
1660
-
1661
  # 1. Identify token types
1662
  is_image_token = (input_ids == image_token_id)
1663
  if attention_mask is not None:
1664
  is_padding = (attention_mask == 0)
1665
  else:
1666
  is_padding = torch.zeros_like(input_ids, dtype=torch.bool)
1667
-
1668
  is_regular_token = ~(is_image_token | is_padding)
1669
-
1670
  # 2. Calculate position increments
1671
  # Regular tokens increment position by 1
1672
  # Image tokens do not increment position (they reuse the "current" position counter)
1673
  # Padding tokens do not increment
1674
-
1675
  # cumulative sum of regular tokens gives the position index
1676
  # We want 0-based index for the first regular token
1677
  # cumsum: [1, 2, 2, 3] -> positions: [0, 1, 2, 2]
1678
  # For image token at index i, we want count of regular tokens before i.
1679
  # This is exactly (cumsum - 1) if the token itself is regular? No.
1680
-
1681
  # Let's use the logic: position[i] = sum(is_regular[:i])
1682
  # We can achieve this by cumsum(is_regular) - is_regular
1683
-
1684
  cumulative_regular = is_regular_token.long().cumsum(dim=1)
1685
-
1686
  # For regular token: position = cumsum - 1 (since it's inclusive) => 0, 1, 2...
1687
  # For image token: position = cumsum (since it's not included in cumsum, cumsum is count of prev regulars)
1688
  # Wait, if is_regular[i] is 0, cumsum[i] == cumsum[i-1].
1689
  # So for image token, position = cumsum[i] is correct.
1690
  # For regular token, position = cumsum[i] - 1 is correct.
1691
-
1692
  # Combine: position = cumsum - is_regular.long()
1693
  base_position_ids = cumulative_regular - is_regular_token.long()
1694
-
1695
  # Apply padding mask (set padding positions to 0)
1696
  base_position_ids = base_position_ids.masked_fill(is_padding, 0)
1697
-
1698
  # Expand to 3D: (3, batch, seq_len)
1699
  position_ids = base_position_ids.unsqueeze(0).expand(3, -1, -1).clone()
1700
-
1701
  return position_ids
1702
 
1703
  def compute_vision_position_ids(
@@ -1711,21 +1711,21 @@ class MossVLModel(MossVLPreTrainedModel):
1711
  """
1712
  Compute 3D position IDs for vision tokens (including separator tokens) and update text position_ids.
1713
  Vectorized implementation for improved efficiency.
1714
-
1715
  Position encoding rules:
1716
  - For text: if not image token, increment position (t-1, t-1, t-1) -> (t, t, t) -> ...
1717
  - For vision: top-left is (t, t, t), increases towards bottom-right to (t, t+h-1, t+w-1)
1718
  - Separator Token after each frame: (x, x, x) where x = max(t+h-1, t+w-1) + 1 = max(t+h, t+w)
1719
  - Image token in text: also gets position (x, x, x) - same as separator
1720
  - Next text token after image: starts at (x+1, x+1, x+1)
1721
-
1722
  Args:
1723
  input_ids: (batch_size, seq_len)
1724
  position_ids: (3, batch_size, seq_len) - will be updated in place
1725
  vision_token_info: metadata about vision tokens (now includes separator positions)
1726
  cross_attention_states: (batch_size, max_vision_seq_len, hidden_size)
1727
  attention_mask: (batch_size, seq_len), optional
1728
-
1729
  Returns:
1730
  vision_pos_ids: (3, batch_size, max_vision_seq_len)
1731
  position_ids: (3, batch_size, seq_len) - updated
@@ -1738,17 +1738,17 @@ class MossVLModel(MossVLPreTrainedModel):
1738
 
1739
  # 1. Gather all frame metadata
1740
  # We need to flatten the nested vision_token_info structure to align with image tokens in input_ids
1741
-
1742
  # Find all image tokens in text: (num_occurrences, 2) -> [batch_idx, seq_idx]
1743
  image_token_indices = (input_ids == image_token_id).nonzero()
1744
-
1745
  # Flatten vision_token_info to parallel lists
1746
  # We assume the order of medias in vision_token_info matches the appearance of image tokens in input_ids
1747
  flat_eff_h = []
1748
  flat_eff_w = []
1749
  flat_vis_starts = []
1750
  flat_batch_indices = []
1751
-
1752
  # Processing metadata on CPU (fast enough for typical batch sizes)
1753
  for b_idx, info in enumerate(vision_token_info):
1754
  medias = info.get('medias', [])
@@ -1759,7 +1759,7 @@ class MossVLModel(MossVLPreTrainedModel):
1759
  start = media['start']
1760
  tok_per_frame = media['vision_tokens_per_frame']
1761
  stride = tok_per_frame + 1 # +1 for separator
1762
-
1763
  # Generate entries for all frames in this media
1764
  for f in range(num_frames):
1765
  flat_eff_h.append(eh)
@@ -1769,8 +1769,8 @@ class MossVLModel(MossVLPreTrainedModel):
1769
 
1770
  # Pre-allocate output
1771
  vision_pos_ids = torch.zeros(
1772
- (3, batch_size, max_vision_seq_len),
1773
- dtype=torch.long,
1774
  device=device
1775
  )
1776
 
@@ -1781,152 +1781,152 @@ class MossVLModel(MossVLPreTrainedModel):
1781
 
1782
  # Align lengths (handle truncation if text has fewer tokens or vice versa)
1783
  num_matches = min(len(flat_eff_h), len(image_token_indices))
1784
-
1785
  # Convert to tensors
1786
  flat_eff_h = torch.tensor(flat_eff_h[:num_matches], device=device, dtype=torch.long)
1787
  flat_eff_w = torch.tensor(flat_eff_w[:num_matches], device=device, dtype=torch.long)
1788
  flat_vis_starts = torch.tensor(flat_vis_starts[:num_matches], device=device, dtype=torch.long)
1789
-
1790
  # Get corresponding text positions
1791
  target_indices = image_token_indices[:num_matches]
1792
  batch_rows = target_indices[:, 0]
1793
  text_cols = target_indices[:, 1]
1794
-
1795
  # 2. Compute Shifts and Update Position IDs
1796
-
1797
  # Calculate max dimensions for each image token: separator_pos = t + max(h, w)
1798
  # Shift amount for subsequent tokens = max(h, w) + 1
1799
  max_hw = torch.maximum(flat_eff_h, flat_eff_w)
1800
  shifts = max_hw + 1
1801
-
1802
  # Create a shift map to apply cumulative shifts
1803
  shift_map = torch.zeros((batch_size, input_ids.shape[1]), dtype=torch.long, device=device)
1804
  shift_map[batch_rows, text_cols] = shifts
1805
-
1806
  # Calculate cumulative shifts along sequence
1807
  cum_shifts = shift_map.cumsum(dim=1)
1808
-
1809
  # Calculate t_vals (start position for each vision grid)
1810
  # t_val = original_pos + shifts_before_this_image
1811
  # cum_shifts at image index includes the image's own shift, so we subtract it
1812
  orig_pos = position_ids[0, batch_rows, text_cols]
1813
  shifts_before = cum_shifts[batch_rows, text_cols] - shifts
1814
  t_vals = orig_pos + shifts_before
1815
-
1816
  # Update text position_ids
1817
  # All tokens get shifted by cum_shifts
1818
  # Image tokens specifically need to be at t_val + max_hw (which is t_val + shift - 1)
1819
  # Our cum_shift update gives: orig_pos + shifts_before + shift = t_val + shift
1820
  # So we subtract 1 from image tokens
1821
-
1822
  # Apply global shift
1823
  # Note: position_ids is (3, B, L), cum_shifts is (B, L). Expand to match.
1824
  new_pos_ids = position_ids + cum_shifts.unsqueeze(0)
1825
-
1826
  # Correct image tokens (subtract 1)
1827
  # We can use boolean mask for efficient update
1828
  img_token_mask = torch.zeros_like(input_ids, dtype=torch.bool)
1829
  img_token_mask[batch_rows, text_cols] = True
1830
  new_pos_ids[:, img_token_mask] -= 1
1831
-
1832
  # Ensure padding positions remain 0 (if attention_mask provided)
1833
  if attention_mask is not None:
1834
  # Assuming padding is 0 in attention_mask
1835
  padding_mask = (attention_mask == 0).unsqueeze(0)
1836
  new_pos_ids.masked_fill_(padding_mask, 0)
1837
-
1838
  # Update position_ids in-place
1839
  position_ids.copy_(new_pos_ids)
1840
-
1841
  # 3. Populate Vision Pos IDs
1842
  # Group frames by size (eff_h, eff_w) to vectorize grid generation
1843
  # This is efficient because typically there are few distinct aspect ratios
1844
  unique_shapes = torch.unique(torch.stack([flat_eff_h, flat_eff_w], dim=1), dim=0)
1845
-
1846
  for shape in unique_shapes:
1847
  eh, ew = shape[0].item(), shape[1].item()
1848
-
1849
  # Mask for frames of this shape
1850
  mask = (flat_eff_h == eh) & (flat_eff_w == ew)
1851
-
1852
  sub_t_vals = t_vals[mask]
1853
  sub_batch_rows = batch_rows[mask]
1854
  sub_vis_starts = flat_vis_starts[mask]
1855
-
1856
  num_frames_sub = sub_t_vals.shape[0]
1857
  if num_frames_sub == 0: continue
1858
-
1859
  # Generate grids: (num_frames, eh, ew)
1860
  # y ranges 0..eh-1, x ranges 0..ew-1
1861
  # positions: t + y, t + x
1862
-
1863
  y_grid = torch.arange(eh, device=device).view(1, eh, 1).expand(num_frames_sub, -1, ew)
1864
  x_grid = torch.arange(ew, device=device).view(1, 1, ew).expand(num_frames_sub, eh, -1)
1865
  t_grid = sub_t_vals.view(-1, 1, 1).expand(-1, eh, ew)
1866
-
1867
  h_grid = t_grid + y_grid
1868
  w_grid = t_grid + x_grid
1869
-
1870
  # Flatten to assign
1871
  flat_t = t_grid.reshape(-1)
1872
  flat_h = h_grid.reshape(-1)
1873
  flat_w = w_grid.reshape(-1)
1874
-
1875
  # Calculate destination indices in vision_pos_ids
1876
  # (batch, seq_pos)
1877
  tokens_per_frame = eh * ew
1878
-
1879
  # Offsets for each token in the frame 0..N-1
1880
- seq_offsets = torch.arange(tokens_per_frame, device=device).unsqueeze(0)
1881
  # Add start index: (num_frames, 1) + (1, tokens) -> (num_frames, tokens)
1882
  abs_seq_offsets = seq_offsets + sub_vis_starts.unsqueeze(1)
1883
-
1884
  flat_seq_inds = abs_seq_offsets.reshape(-1)
1885
  flat_batch_inds = sub_batch_rows.unsqueeze(1).expand(-1, tokens_per_frame).reshape(-1)
1886
-
1887
  # Clip to max_vision_seq_len
1888
  valid_mask = flat_seq_inds < max_vision_seq_len
1889
-
1890
  if valid_mask.any():
1891
  final_b = flat_batch_inds[valid_mask]
1892
  final_s = flat_seq_inds[valid_mask]
1893
-
1894
  vision_pos_ids[0, final_b, final_s] = flat_t[valid_mask]
1895
  vision_pos_ids[1, final_b, final_s] = flat_h[valid_mask]
1896
  vision_pos_ids[2, final_b, final_s] = flat_w[valid_mask]
1897
-
1898
  # 4. Handle Separator Tokens
1899
  # Position: t_val + max(eh, ew)
1900
  sep_vals = t_vals + max_hw
1901
  # Index: start + tokens_per_frame = start + eh*ew
1902
  sep_indices = flat_vis_starts + (flat_eff_h * flat_eff_w)
1903
-
1904
  valid_sep_mask = sep_indices < max_vision_seq_len
1905
-
1906
  if valid_sep_mask.any():
1907
  final_b = batch_rows[valid_sep_mask]
1908
  final_s = sep_indices[valid_sep_mask]
1909
  vals = sep_vals[valid_sep_mask]
1910
-
1911
  vision_pos_ids[0, final_b, final_s] = vals
1912
  vision_pos_ids[1, final_b, final_s] = vals
1913
  vision_pos_ids[2, final_b, final_s] = vals
1914
-
1915
  # 5. Compute Rope Deltas
1916
  # rope_deltas[batch_idx] = max_pos + 1 - seq_len
1917
-
1918
  # Use updated position_ids
1919
  # Max pos in each batch - take max across all 3 position dimensions
1920
  # position_ids shape: (3, batch_size, seq_len)
1921
  # We need rope_deltas shape: (batch_size,)
1922
  max_pos = position_ids.max(dim=0).values.max(dim=-1).values # (batch_size,)
1923
  rope_deltas = max_pos + 1 - input_ids.shape[1] # (batch_size,)
1924
-
1925
  return vision_pos_ids, position_ids, rope_deltas
1926
 
1927
  def get_vision_features(
1928
- self,
1929
- pixel_values: torch.FloatTensor,
1930
  grid_thw: Optional[torch.LongTensor] = None,
1931
  media_nums_per_sample: Optional[List[int]] = None
1932
  ):
@@ -1941,12 +1941,12 @@ class MossVLModel(MossVLPreTrainedModel):
1941
  """
1942
  pixel_values = pixel_values.type(self.visual.dtype)
1943
  hidden_states = self.visual(
1944
- pixel_values,
1945
  grid_thw=grid_thw
1946
  )
1947
  vision_embeds, vision_token_info = self.convert_packed_to_batch(
1948
- hidden_states,
1949
- grid_thw,
1950
  media_nums_per_sample
1951
  )
1952
  return vision_embeds, vision_token_info
@@ -2497,14 +2497,14 @@ class MossVLForConditionalGeneration(MossVLPreTrainedModel, GenerationMixin):
2497
 
2498
 
2499
  def get_vision_features(
2500
- self,
2501
- pixel_values: torch.FloatTensor,
2502
  grid_thw: Optional[torch.LongTensor] = None,
2503
  media_nums_per_sample: Optional[List[int]] = None
2504
  ):
2505
  """
2506
  Get vision features for images and videos (merged).
2507
-
2508
  Args:
2509
  pixel_values: vision pixel values (images and videos merged)
2510
  grid_thw: [num_media, 3] tensor with (t, h, w) for each media item
@@ -2558,8 +2558,12 @@ class MossVLForConditionalGeneration(MossVLPreTrainedModel, GenerationMixin):
2558
  cross_attention_mask (`torch.Tensor` of shape `(batch_size, 1, text_seq_len, vision_seq_len)`, *optional*):
2559
  Attention mask for cross-attention between text and vision. Controls which vision tokens each text
2560
  token can attend to, enforcing causal visibility for video frames.
2561
- vision_cache_position / full_vision_token_info: see `MossVLModel.forward`. Used by real-time generation
2562
- to incrementally append new frames to the cross-attention KV cache.
 
 
 
 
2563
  """
2564
  outputs = self.model(
2565
  input_ids=input_ids,
@@ -2617,11 +2621,11 @@ class MossVLForConditionalGeneration(MossVLPreTrainedModel, GenerationMixin):
2617
  ):
2618
  """
2619
  Prepare inputs for generation.
2620
-
2621
- Note: Currently only supports offline visual understanding, meaning all multimodal
2622
- content must be provided before generation starts. We don't support adding new
2623
  images/videos during generation (streaming mode).
2624
-
2625
  Args:
2626
  media_nums_per_sample: One video counts as one media item (regardless of frame count)
2627
  """
@@ -2643,7 +2647,7 @@ class MossVLForConditionalGeneration(MossVLPreTrainedModel, GenerationMixin):
2643
  # For decoding stage, if position_ids are generated by GenerationMixin (2D),
2644
  # we can set them to None to let forward recompute them from cache_position.
2645
  model_inputs["position_ids"] = None
2646
-
2647
  # Handle cross attention mask
2648
  if cross_attention_mask is not None:
2649
  # Slice to current sequence length on text dimension (dim=2)
@@ -2655,10 +2659,10 @@ class MossVLForConditionalGeneration(MossVLPreTrainedModel, GenerationMixin):
2655
  # In decode stage, vision features are retrieved from cross attention cache
2656
  if cache_position[0] != 0:
2657
  model_inputs["pixel_values"] = None
2658
- model_inputs["grid_thw"] = None
2659
  model_inputs["media_nums_per_sample"] = None
2660
  model_inputs["vision_position_ids"] = None
2661
-
2662
  else:
2663
  # In prefill stage, include all vision-related inputs
2664
  model_inputs["vision_position_ids"] = vision_position_ids
@@ -2670,20 +2674,20 @@ class MossVLForConditionalGeneration(MossVLPreTrainedModel, GenerationMixin):
2670
  def _update_model_kwargs_for_generation(self, outputs, model_kwargs, is_encoder_decoder, **kwargs):
2671
  """
2672
  Update model kwargs for generation, extending cross_attention_mask for the newly generated token.
2673
-
2674
  In offline mode (all multimodal content provided before generation):
2675
  - Each newly generated token should have the same cross_attention_mask pattern as the previous token
2676
  - This ensures all generated tokens can attend to all vision tokens that were visible before
2677
  """
2678
  cross_attention_mask_prev = model_kwargs.get("cross_attention_mask", None)
2679
-
2680
  model_kwargs = super()._update_model_kwargs_for_generation(
2681
  outputs=outputs,
2682
  model_kwargs=model_kwargs,
2683
  is_encoder_decoder=is_encoder_decoder,
2684
  **kwargs,
2685
  )
2686
-
2687
  # Extend cross_attention_mask for the new token
2688
  # Copy the last token's mask pattern for the newly generated token
2689
  if cross_attention_mask_prev is not None:
 
111
  class MossVLModelOutputWithPast(ModelOutput):
112
  """
113
  Output class for MossVL model with additional vision_token_info and rope_deltas fields.
114
+
115
  Args:
116
  last_hidden_state (`torch.FloatTensor` of shape `(batch_size, sequence_length, hidden_size)`):
117
  Sequence of hidden-states at the output of the last layer of the model.
118
  past_key_values (`Cache`, *optional*):
119
+ Contains pre-computed hidden-states (key and values in the self-attention blocks and
120
  cross-attention blocks) that can be used to speed up sequential decoding.
121
  hidden_states (`tuple(torch.FloatTensor)`, *optional*):
122
  Tuple of `torch.FloatTensor` (one for the output of the embeddings + one for each layer).
 
129
  Position offset due to vision tokens. Used for fast position computation in decode stage.
130
  rope_deltas = max_position - sequence_length
131
  """
132
+
133
  last_hidden_state: Optional[torch.FloatTensor] = None
134
  past_key_values: Optional[Cache] = None
135
  hidden_states: Optional[tuple[torch.FloatTensor]] = None
 
142
  class MossVLCausalLMOutputWithPast(ModelOutput):
143
  """
144
  Output class for MossVL causal language model with additional vision_token_info and rope_deltas fields.
145
+
146
  Args:
147
  loss (`torch.FloatTensor` of shape `(1,)`, *optional*):
148
  Language modeling loss (for next-token prediction).
 
159
  rope_deltas (`torch.LongTensor` of shape `(batch_size,)`, *optional*):
160
  Position offset due to vision tokens. Used for fast position computation in decode stage.
161
  """
162
+
163
  loss: Optional[torch.FloatTensor] = None
164
  logits: Optional[torch.FloatTensor] = None
165
  past_key_values: Optional[Cache] = None
 
225
  base_hidden_size = config.hidden_size * (config.spatial_merge_size**2)
226
  # 计算输入维度:spatial_merge 后的维度 * (1 + deepstack特征数)
227
  self.input_hidden_size = base_hidden_size * (1 + num_deepstack_features)
228
+
229
  # Use independent LayerNorms for each feature level
230
  # Total features = 1 (last layer) + num_deepstack_features
231
  num_features = 1 + num_deepstack_features
 
233
  nn.LayerNorm(config.hidden_size, eps=1e-6)
234
  for _ in range(num_features)
235
  ])
236
+
237
  self.hidden_size = config.hidden_size
238
+
239
  self.linear_fc1 = nn.Linear(self.input_hidden_size, self.input_hidden_size)
240
  self.act_fn = nn.GELU()
241
  self.linear_fc2 = nn.Linear(self.input_hidden_size, config.out_hidden_size)
 
244
  # 1. Collect all features: [last_hidden_state, deepstack_1, deepstack_2, ...]
245
  # self.norms[0] corresponds to last_hidden_state
246
  # self.norms[1:] corresponds to deepstack_features
247
+
248
  all_inputs = [last_hidden_state] + deepstack_features
249
+
250
  # 2. Apply Norm independently
251
  outs = []
252
  for i, feat in enumerate(all_inputs):
253
  outs.append(self.norms[i](feat))
254
+
255
  # 3. Concat once
256
  x = torch.cat(outs, dim=-1)
257
 
 
480
 
481
  if position_ids.ndim == 2:
482
  position_ids = position_ids[None, ...].expand(3, position_ids.shape[0], -1)
483
+
484
  inv_freq_expanded = self.inv_freq[None, None, :, None].float().expand(3, position_ids.shape[1], -1, 1)
485
  position_ids_expanded = position_ids[:, :, None, :].float() # shape (3, bs, 1, positions)
486
 
 
628
  def forward(
629
  self,
630
  hidden_states: torch.Tensor,
631
+ cross_attention_states: torch.Tensor,
632
  attention_mask: Optional[torch.Tensor] = None,
633
  past_key_values: Optional[Cache] = None,
634
  use_cache: bool = None,
 
638
  **kwargs,
639
  ) -> torch.Tensor:
640
  batch_size, seq_length, _ = hidden_states.size()
641
+
642
  # Query from text hidden states
643
  query_states = self.q_proj(hidden_states)
644
  query_states = query_states.view(batch_size, seq_length, self.num_heads, self.head_dim).transpose(1, 2)
 
653
  # Key and Value from vision cross_attention_states
654
  key_states = self.k_proj(cross_attention_states)
655
  value_states = self.v_proj(cross_attention_states)
656
+
657
  key_states = key_states.view(batch_size, -1, self.num_key_value_heads, self.head_dim).transpose(1, 2)
658
  key_states = self.k_norm(key_states)
659
  value_states = value_states.view(batch_size, -1, self.num_key_value_heads, self.head_dim).transpose(1, 2)
660
 
661
  # Rotate new keys once; cached keys already include vision RoPE.
662
+
663
  if vision_position_embeddings is not None:
664
  vision_cos, vision_sin = vision_position_embeddings
665
  key_states = apply_rotary_pos_emb_cross_attention(key_states, vision_cos, vision_sin)
 
670
  # we still update the cross key states, past_image, new_image. And use it!
671
  key_states, value_states = past_key_values.update(
672
  key_states, value_states, self.layer_idx, {"cache_position": cache_position}
673
+ )
674
+
675
  elif cache_position[0] != 0:
676
  key_states, value_states = (
677
  past_key_values.layers[self.layer_idx].keys,
678
  past_key_values.layers[self.layer_idx].values,
679
+ )
680
  else:
681
  raise ValueError(
682
  "Cross attention layer can't find neither `cross_attn_states` nor cached values for key/values!"
 
771
  hidden_states = self.post_attention_layernorm(hidden_states)
772
  hidden_states = self.mlp(hidden_states)
773
  hidden_states = residual + hidden_states
774
+
775
  return hidden_states
776
 
777
 
 
785
 
786
  self.cross_attn = MossVLTextCrossAttention(config=config, layer_idx=layer_idx)
787
  self.mlp = MossVLTextMLP(config)
788
+
789
  self.input_layernorm = MossVLTextRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
790
  self.post_attention_layernorm = MossVLTextRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
791
+
792
  # Gates for cross attention (single scalar value).
793
  # Gate scalar = tanh(gate[0]), initialized to zero so tanh(0)=0 at start.
794
  self.cross_attn_attn_gate = nn.Parameter(torch.zeros(1))
 
815
  # Cross Attention
816
  residual = hidden_states
817
  hidden_states = self.input_layernorm(hidden_states)
818
+
819
  hidden_states, _ = self.cross_attn(
820
  hidden_states=hidden_states,
821
  cross_attention_states=cross_attention_states,
 
839
  hidden_states = full_text_row_masked_out_mask[:, 0] * hidden_states
840
 
841
  hidden_states = residual + self.cross_attn_mlp_gate.tanh() * hidden_states
842
+
843
  return hidden_states
844
 
845
 
 
866
 
867
  def _init_weights(self, module):
868
  """Initialize the weights.
869
+
870
  Note: For loading pretrained weights:
871
  - Cross attention: can be initialized from the previous layer's self attention weights
872
  """
 
884
  module.linear_fc1.bias.data.zero_()
885
  if module.linear_fc2.bias is not None:
886
  module.linear_fc2.bias.data.zero_()
887
+
888
  # Initialize separate LayerNorms
889
  if hasattr(module, "norms"):
890
  for norm in module.norms:
 
915
  self.rotary_pos_emb = MossVLVisionRotaryEmbedding(head_dim // 2)
916
 
917
  self.blocks = nn.ModuleList([MossVLVisionBlock(config) for _ in range(config.depth)])
918
+
919
  # DeepStack: 记录需要提取特征的层索引
920
  self.deepstack_visual_indexes = config.deepstack_visual_indexes
921
  num_deepstack_features = len(self.deepstack_visual_indexes)
922
+
923
  # Merger: 输入维度 = hidden_size * (1 + num_deepstack_features)
924
  self.merger = MossVLVisionPatchMerger(
925
+ config=config,
926
  num_deepstack_features=num_deepstack_features
927
  )
928
 
 
1027
  return patch_pos_embeds
1028
 
1029
  def forward(
1030
+ self,
1031
+ hidden_states: torch.Tensor,
1032
+ grid_thw: torch.Tensor,
1033
  **kwargs
1034
  ) -> torch.Tensor:
1035
  """
 
1097
  self.vocab_size = config.vocab_size
1098
 
1099
  self.embed_tokens = nn.Embedding(config.vocab_size, config.hidden_size, self.padding_idx)
1100
+
1101
  # Store cross_attention_layers for use in forward pass
1102
  self.cross_attention_layers = config.cross_attention_layers
1103
+
1104
  # Create layers: self-attention or cross-attention at specified indices
1105
  self.layers = nn.ModuleList()
1106
  for layer_idx in range(config.num_hidden_layers):
 
1114
  self.layers.append(
1115
  MossVLSelfAttentionDecoderLayer(config, layer_idx)
1116
  )
1117
+
1118
  self.norm = MossVLTextRMSNorm(config.hidden_size, eps=config.rms_norm_eps)
1119
  self.rotary_emb = MossVLTextRotaryEmbedding(config=config)
1120
  self.gradient_checkpointing = False
 
1136
  vision_position_ids: Optional[torch.LongTensor] = None,
1137
  use_cache: Optional[bool] = None,
1138
  cache_position: Optional[torch.LongTensor] = None,
1139
+ vision_cache_position: Optional[torch.LongTensor] = None,
1140
  **kwargs: Unpack[FlashAttentionKwargs],
1141
  ) -> Union[tuple, BaseModelOutputWithPast]:
1142
  """
 
1250
  self.visual = MossVLVisionModel._from_config(config.vision_config)
1251
  self.language_model = MossVLTextModel._from_config(config.text_config)
1252
  self.vision_token_info = None # cache vision_token_info here for decode stage
1253
+ self.rope_deltas = None # cache position deltas for decode stage
1254
 
1255
  # Learnable Separator Token: inserted after each image/frame's vision tokens
1256
  # Initialized from LLM's separator_token_init_id embedding
 
1259
  )
1260
 
1261
  self.post_init()
1262
+
1263
 
1264
 
1265
  def convert_packed_to_batch(
 
1270
  ) -> Tuple[torch.Tensor, List[dict]]:
1271
  """
1272
  Convert packed vision tokens to batched format with separator tokens.
1273
+
1274
  For each image: inserts 1 separator token after the vision tokens.
1275
  For each video: inserts 1 separator token after EACH frame's vision tokens.
1276
+
1277
+ Note: media_nums_per_sample counts each video as 1 media item,
1278
  but each frame in a video gets its own separator token.
1279
  """
1280
+
1281
  # Calculate number of tokens per media after spatial merge
1282
  tokens_per_media = (grid_thw[:, 0] * grid_thw[:, 1] * grid_thw[:, 2]) // (self.visual.spatial_merge_size ** 2)
1283
  hidden_size = hidden_states.shape[-1]
1284
+
1285
  # If media_nums_per_sample is not provided, assume batch size = 1
1286
  if media_nums_per_sample is None:
1287
  batch_size = 1
1288
  media_nums_per_sample = [grid_thw.shape[0]]
1289
  else:
1290
  batch_size = len(media_nums_per_sample)
1291
+
1292
  # Optimization for batch_size = 1 (common in inference)
1293
  if batch_size == 1:
1294
  # 1. Calculate total length (pure math, fast)
 
1297
  num_tokens = tokens_per_media[i].item()
1298
  num_frames = grid_thw[i, 0].item()
1299
  total_len += num_tokens + num_frames # + separators
1300
+
1301
  # 2. Handle Padding alignment
1302
  pad_multiple = self.config.vision_seq_pad_multiple
1303
  if total_len % pad_multiple != 0:
1304
  max_seq_len = (total_len + pad_multiple - 1) // pad_multiple * pad_multiple
1305
  else:
1306
  max_seq_len = total_len
1307
+
1308
  # 3. Pre-allocate final tensor
1309
  batched_hidden_states = torch.zeros(
1310
  1, max_seq_len, hidden_size,
1311
  dtype=hidden_states.dtype,
1312
  device=hidden_states.device
1313
  )
1314
+
1315
  # 4. Vectorized fill
1316
  sample_info = {
1317
  'medias': [],
 
1319
  'pad_start': total_len,
1320
  'pad_end': max_seq_len
1321
  }
1322
+
1323
  token_offset = 0
1324
  current_seq_len = 0
1325
  separator_embedding = self.separator_token.to(hidden_states.dtype)
1326
+
1327
  # Iterate through all medias in this single sample
1328
  for media_idx in range(grid_thw.shape[0]):
1329
  num_tokens = tokens_per_media[media_idx].item()
1330
  t, h, w = grid_thw[media_idx].tolist()
1331
  num_frames = t
1332
  tokens_per_frame = num_tokens // num_frames
1333
+
1334
  # --- Vectorized processing start ---
1335
  # Extract vision tokens: (num_tokens, hidden)
1336
  media_vision_tokens = hidden_states[token_offset : token_offset + num_tokens]
1337
+
1338
  # Reshape to (num_frames, tokens_per_frame, hidden)
1339
  media_vision_tokens = media_vision_tokens.view(num_frames, tokens_per_frame, hidden_size)
1340
+
1341
  # Directly write to destination without creating intermediate large tensors
1342
  chunk_len = num_frames * (tokens_per_frame + 1)
1343
+
1344
  # Get view of the target area: (num_frames, tokens_per_frame + 1, hidden)
1345
  target_view = batched_hidden_states[0, current_seq_len : current_seq_len + chunk_len]
1346
  target_view = target_view.view(num_frames, tokens_per_frame + 1, hidden_size)
1347
+
1348
  # 1. Fill vision tokens
1349
  target_view[:, :tokens_per_frame].copy_(media_vision_tokens)
1350
+
1351
  # 2. Fill separators (Broadcast assignment)
1352
  # separator_embedding is (hidden,), automatically broadcasts to (num_frames, hidden)
1353
  target_view[:, tokens_per_frame] = separator_embedding
1354
+
1355
  # --- Vectorized processing end ---
1356
+
1357
  sample_info['medias'].append({
1358
  'start': current_seq_len,
1359
  'end': current_seq_len + chunk_len,
 
1364
  'vision_tokens_per_frame': tokens_per_frame,
1365
  'has_separator': True,
1366
  })
1367
+
1368
  current_seq_len += chunk_len
1369
  token_offset += num_tokens
1370
+
1371
  vision_token_info = [sample_info]
1372
+
1373
  return batched_hidden_states, vision_token_info
1374
 
1375
  # Calculate tokens per sample including separator tokens
 
1385
  sample_tokens += num_tokens + num_frames # +num_frames separator tokens
1386
  tokens_per_sample.append(sample_tokens)
1387
  media_idx += num_medias_in_sample
1388
+
1389
  max_seq_len = max(tokens_per_sample)
1390
  pad_multiple = self.config.vision_seq_pad_multiple
1391
  if max_seq_len % pad_multiple != 0:
1392
  max_seq_len = (max_seq_len + pad_multiple - 1) // pad_multiple * pad_multiple
1393
+
1394
  # Initialize batched output with zeros (for padding)
1395
  batched_hidden_states = torch.zeros(
1396
  batch_size, max_seq_len, hidden_size,
1397
  dtype=hidden_states.dtype,
1398
  device=hidden_states.device
1399
  )
1400
+
1401
  # Get separator token (learnable parameter)
1402
  separator_embedding = self.separator_token.to(hidden_states.dtype)
1403
+
1404
  # Track token positions for each sample
1405
  vision_token_info = []
1406
+
1407
  # Split packed tensor and fill batched output
1408
  token_offset = 0
1409
  media_idx = 0
1410
+
1411
  for sample_idx, num_medias_in_sample in enumerate(media_nums_per_sample):
1412
  sample_info = {
1413
  'medias': [], # List of dicts for each media in this sample
 
1415
  'pad_start': tokens_per_sample[sample_idx],
1416
  'pad_end': max_seq_len
1417
  }
1418
+
1419
  seq_offset = 0 # Offset within this sample's sequence
1420
+
1421
  # Process each image/video in this sample
1422
  for _ in range(num_medias_in_sample):
1423
  num_tokens = tokens_per_media[media_idx].item()
1424
+
1425
  t, h, w = grid_thw[media_idx].tolist()
1426
  num_frames = t
1427
  tokens_per_frame = num_tokens // num_frames
1428
+
1429
  # Record start position for this media
1430
  media_start = seq_offset
1431
+
1432
  # Vectorized handling of frames
1433
  # Extract vision tokens for this media: (num_tokens, hidden)
1434
  media_vision_tokens = hidden_states[token_offset : token_offset + num_tokens]
1435
+
1436
  # Reshape to (num_frames, tokens_per_frame, hidden)
1437
  media_vision_tokens = media_vision_tokens.view(num_frames, tokens_per_frame, hidden_size)
1438
+
1439
  # Create separators: (num_frames, 1, hidden)
1440
  separators = separator_embedding.view(1, 1, hidden_size).expand(num_frames, 1, hidden_size)
1441
+
1442
  # Concatenate: (num_frames, tokens_per_frame + 1, hidden)
1443
  media_tokens_with_sep = torch.cat([media_vision_tokens, separators], dim=1)
1444
+
1445
  # Flatten: (num_frames * (tokens_per_frame + 1), hidden)
1446
  media_tokens_with_sep = media_tokens_with_sep.view(-1, hidden_size)
1447
+
1448
  # Assign to batched tensor
1449
  media_length_with_sep = media_tokens_with_sep.shape[0]
1450
  batched_hidden_states[sample_idx, seq_offset : seq_offset + media_length_with_sep] = media_tokens_with_sep
1451
+
1452
  seq_offset += media_length_with_sep
1453
+
1454
  # Total tokens for this media = vision_tokens + num_separators
1455
  media_length = num_tokens + num_frames
1456
+
1457
  # Record this image/video's position within the sample
1458
  # Note: length now includes separator tokens
1459
  sample_info['medias'].append({
 
1466
  'vision_tokens_per_frame': tokens_per_frame, # Actual vision tokens per frame (excluding separator)
1467
  'has_separator': True, # Flag indicating separator tokens are included
1468
  })
1469
+
1470
  token_offset += num_tokens
1471
  media_idx += 1
1472
+
1473
  vision_token_info.append(sample_info)
1474
+
1475
  return batched_hidden_states, vision_token_info
1476
 
1477
  def get_input_embeddings(self):
 
1494
  ) -> torch.Tensor:
1495
  """
1496
  Expand cross_attention_mask from (B, 1, T, N_frames) to (B, 1, T, N_tokens).
1497
+
1498
  Args:
1499
  cross_attention_mask (`torch.Tensor` of shape `(batch_size, 1, text_seq_len, num_frames)`):
1500
  Coarse attention mask where each frame corresponds to one column.
 
1505
  Each dict contains 'medias' list with 'length', 'num_frames', and 'vision_tokens_per_frame'.
1506
  target_dtype (`torch.dtype`):
1507
  Target dtype for the output mask (typically inputs_embeds.dtype).
1508
+
1509
  Returns:
1510
  `torch.Tensor` of shape `(batch_size, 1, text_seq_len, total_vision_tokens)`:
1511
  Fine-grained attention mask where each vision token has its own column.
1512
  Masked positions have min_value, unmasked positions have 0.0.
1513
+
1514
  Note:
1515
  - vision_token_info contains the actual token counts after ViT padding (pad to multiple of 8)
1516
  - Separator tokens are treated as part of the same frame, sharing the same mask
 
1520
  "vision_token_info must be provided to _expand_cross_attention_mask. "
1521
  "This should be cached from prefill stage or computed during current forward pass."
1522
  )
1523
+
1524
  batch_size = cross_attention_mask.shape[0]
1525
+
1526
  # Determine target vision length (should be consistent across batch, but take max to be safe)
1527
  max_vision_len = 0
1528
  if vision_token_info:
 
1552
  dtype=target_dtype,
1553
  device=cross_attention_mask.device
1554
  )
1555
+
1556
  for i in range(batch_size):
1557
  medias = vision_token_info[i]['medias']
1558
  if not medias:
1559
  continue
1560
+
1561
  # Collect repetition counts for all frames in this sample
1562
  repeats = []
1563
  for media in medias:
1564
  num_frames = media.get('num_frames', 1)
1565
  length = media['length']
1566
  has_separator = media.get('has_separator', False)
1567
+
1568
  # Determine tokens per frame (including separator)
1569
  if has_separator:
1570
  vision_tokens_per_frame = media.get('vision_tokens_per_frame', (length // num_frames) - 1)
1571
  tokens_per_frame_with_sep = vision_tokens_per_frame + 1
1572
  else:
1573
  tokens_per_frame_with_sep = length // num_frames
1574
+
1575
  # In convert_packed_to_batch we enforce strictly regular frames
1576
  # so we can assume all frames have the same number of tokens
1577
  repeats.extend([tokens_per_frame_with_sep] * num_frames)
1578
+
1579
  num_valid_frames = len(repeats)
1580
  if num_valid_frames == 0:
1581
  continue
1582
+
1583
  # If cross_attention_mask has more frames (e.g. padded), slice it
1584
  # If it has fewer (shouldn't happen), slice repeats
1585
  valid_mask_frames = min(num_valid_frames, cross_attention_mask.shape[-1])
1586
  if valid_mask_frames < num_valid_frames:
1587
  repeats = repeats[:valid_mask_frames]
1588
+
1589
  # Extract valid columns for this sample
1590
  # (1, text_len, valid_mask_frames)
1591
  source_mask = cross_attention_mask[i, :, :, :valid_mask_frames]
1592
+
1593
  # Convert repeats to tensor
1594
  repeats_tensor = torch.tensor(repeats, device=cross_attention_mask.device)
1595
+
1596
  # Expand using repeat_interleave
1597
  # output shape: (1, text_len, sum(repeats))
1598
  expanded_mask = source_mask.repeat_interleave(repeats_tensor, dim=-1)
1599
+
1600
  # Assign to final_mask
1601
  num_tokens = expanded_mask.shape[-1]
1602
  if num_tokens > max_vision_len:
1603
  num_tokens = max_vision_len
1604
  expanded_mask = expanded_mask[..., :num_tokens]
1605
+
1606
  final_mask[i, :, :, :num_tokens] = expanded_mask
1607
+
1608
  return final_mask
1609
 
1610
  def compute_position_ids(
 
1615
  ) -> torch.Tensor:
1616
  """
1617
  Compute 3D position IDs for text tokens with special handling for image tokens.
1618
+
1619
  Rules:
1620
  - Regular text tokens: increment position (x, x, x) -> (x+1, x+1, x+1)
1621
  - Image token: gets (t, t, t) where t = previous_text_position + 1
1622
  - After processing vision tokens, next text token starts at max(vision_bottom_right) + 1
1623
+
1624
  In decode stage, uses cached rope_deltas to quickly compute new positions.
1625
+
1626
  Args:
1627
  input_ids: (batch_size, seq_len)
1628
  attention_mask: (batch_size, seq_len), optional
1629
  cache_position: (seq_len,), position in cache
1630
+
1631
  Returns:
1632
  position_ids: (3, batch_size, seq_len)
1633
  """
1634
  batch_size, seq_len = input_ids.shape
1635
  device = input_ids.device
1636
  image_token_id = self.config.image_token_id
1637
+
1638
  # Decode stage: use cached rope_deltas for fast computation
1639
  if cache_position is not None and cache_position[0] != 0 and self.rope_deltas is not None:
1640
  # In decode, position = cache_position + rope_deltas
1641
  # rope_deltas is per-sample: (batch_size,)
1642
  position_ids = torch.arange(seq_len, device=device, dtype=torch.long)
1643
  position_ids = position_ids.unsqueeze(0).expand(batch_size, -1) # (batch, seq_len)
1644
+
1645
  # Add cache_position offset
1646
  if cache_position is not None:
1647
  position_ids = position_ids + cache_position[0]
1648
+
1649
  # Add rope_deltas (position offset due to vision tokens)
1650
  # self.rope_deltas shape: (batch_size,), need to unsqueeze for broadcasting
1651
  position_ids = position_ids + self.rope_deltas.unsqueeze(1) # (batch, seq_len)
1652
+
1653
  # Expand to 3D: (3, batch, seq_len)
1654
  position_ids = position_ids.unsqueeze(0).expand(3, -1, -1)
1655
+
1656
  return position_ids
1657
+
1658
  # Prefill stage: compute full position_ids with image token awareness
1659
  # Vectorized implementation
1660
+
1661
  # 1. Identify token types
1662
  is_image_token = (input_ids == image_token_id)
1663
  if attention_mask is not None:
1664
  is_padding = (attention_mask == 0)
1665
  else:
1666
  is_padding = torch.zeros_like(input_ids, dtype=torch.bool)
1667
+
1668
  is_regular_token = ~(is_image_token | is_padding)
1669
+
1670
  # 2. Calculate position increments
1671
  # Regular tokens increment position by 1
1672
  # Image tokens do not increment position (they reuse the "current" position counter)
1673
  # Padding tokens do not increment
1674
+
1675
  # cumulative sum of regular tokens gives the position index
1676
  # We want 0-based index for the first regular token
1677
  # cumsum: [1, 2, 2, 3] -> positions: [0, 1, 2, 2]
1678
  # For image token at index i, we want count of regular tokens before i.
1679
  # This is exactly (cumsum - 1) if the token itself is regular? No.
1680
+
1681
  # Let's use the logic: position[i] = sum(is_regular[:i])
1682
  # We can achieve this by cumsum(is_regular) - is_regular
1683
+
1684
  cumulative_regular = is_regular_token.long().cumsum(dim=1)
1685
+
1686
  # For regular token: position = cumsum - 1 (since it's inclusive) => 0, 1, 2...
1687
  # For image token: position = cumsum (since it's not included in cumsum, cumsum is count of prev regulars)
1688
  # Wait, if is_regular[i] is 0, cumsum[i] == cumsum[i-1].
1689
  # So for image token, position = cumsum[i] is correct.
1690
  # For regular token, position = cumsum[i] - 1 is correct.
1691
+
1692
  # Combine: position = cumsum - is_regular.long()
1693
  base_position_ids = cumulative_regular - is_regular_token.long()
1694
+
1695
  # Apply padding mask (set padding positions to 0)
1696
  base_position_ids = base_position_ids.masked_fill(is_padding, 0)
1697
+
1698
  # Expand to 3D: (3, batch, seq_len)
1699
  position_ids = base_position_ids.unsqueeze(0).expand(3, -1, -1).clone()
1700
+
1701
  return position_ids
1702
 
1703
  def compute_vision_position_ids(
 
1711
  """
1712
  Compute 3D position IDs for vision tokens (including separator tokens) and update text position_ids.
1713
  Vectorized implementation for improved efficiency.
1714
+
1715
  Position encoding rules:
1716
  - For text: if not image token, increment position (t-1, t-1, t-1) -> (t, t, t) -> ...
1717
  - For vision: top-left is (t, t, t), increases towards bottom-right to (t, t+h-1, t+w-1)
1718
  - Separator Token after each frame: (x, x, x) where x = max(t+h-1, t+w-1) + 1 = max(t+h, t+w)
1719
  - Image token in text: also gets position (x, x, x) - same as separator
1720
  - Next text token after image: starts at (x+1, x+1, x+1)
1721
+
1722
  Args:
1723
  input_ids: (batch_size, seq_len)
1724
  position_ids: (3, batch_size, seq_len) - will be updated in place
1725
  vision_token_info: metadata about vision tokens (now includes separator positions)
1726
  cross_attention_states: (batch_size, max_vision_seq_len, hidden_size)
1727
  attention_mask: (batch_size, seq_len), optional
1728
+
1729
  Returns:
1730
  vision_pos_ids: (3, batch_size, max_vision_seq_len)
1731
  position_ids: (3, batch_size, seq_len) - updated
 
1738
 
1739
  # 1. Gather all frame metadata
1740
  # We need to flatten the nested vision_token_info structure to align with image tokens in input_ids
1741
+
1742
  # Find all image tokens in text: (num_occurrences, 2) -> [batch_idx, seq_idx]
1743
  image_token_indices = (input_ids == image_token_id).nonzero()
1744
+
1745
  # Flatten vision_token_info to parallel lists
1746
  # We assume the order of medias in vision_token_info matches the appearance of image tokens in input_ids
1747
  flat_eff_h = []
1748
  flat_eff_w = []
1749
  flat_vis_starts = []
1750
  flat_batch_indices = []
1751
+
1752
  # Processing metadata on CPU (fast enough for typical batch sizes)
1753
  for b_idx, info in enumerate(vision_token_info):
1754
  medias = info.get('medias', [])
 
1759
  start = media['start']
1760
  tok_per_frame = media['vision_tokens_per_frame']
1761
  stride = tok_per_frame + 1 # +1 for separator
1762
+
1763
  # Generate entries for all frames in this media
1764
  for f in range(num_frames):
1765
  flat_eff_h.append(eh)
 
1769
 
1770
  # Pre-allocate output
1771
  vision_pos_ids = torch.zeros(
1772
+ (3, batch_size, max_vision_seq_len),
1773
+ dtype=torch.long,
1774
  device=device
1775
  )
1776
 
 
1781
 
1782
  # Align lengths (handle truncation if text has fewer tokens or vice versa)
1783
  num_matches = min(len(flat_eff_h), len(image_token_indices))
1784
+
1785
  # Convert to tensors
1786
  flat_eff_h = torch.tensor(flat_eff_h[:num_matches], device=device, dtype=torch.long)
1787
  flat_eff_w = torch.tensor(flat_eff_w[:num_matches], device=device, dtype=torch.long)
1788
  flat_vis_starts = torch.tensor(flat_vis_starts[:num_matches], device=device, dtype=torch.long)
1789
+
1790
  # Get corresponding text positions
1791
  target_indices = image_token_indices[:num_matches]
1792
  batch_rows = target_indices[:, 0]
1793
  text_cols = target_indices[:, 1]
1794
+
1795
  # 2. Compute Shifts and Update Position IDs
1796
+
1797
  # Calculate max dimensions for each image token: separator_pos = t + max(h, w)
1798
  # Shift amount for subsequent tokens = max(h, w) + 1
1799
  max_hw = torch.maximum(flat_eff_h, flat_eff_w)
1800
  shifts = max_hw + 1
1801
+
1802
  # Create a shift map to apply cumulative shifts
1803
  shift_map = torch.zeros((batch_size, input_ids.shape[1]), dtype=torch.long, device=device)
1804
  shift_map[batch_rows, text_cols] = shifts
1805
+
1806
  # Calculate cumulative shifts along sequence
1807
  cum_shifts = shift_map.cumsum(dim=1)
1808
+
1809
  # Calculate t_vals (start position for each vision grid)
1810
  # t_val = original_pos + shifts_before_this_image
1811
  # cum_shifts at image index includes the image's own shift, so we subtract it
1812
  orig_pos = position_ids[0, batch_rows, text_cols]
1813
  shifts_before = cum_shifts[batch_rows, text_cols] - shifts
1814
  t_vals = orig_pos + shifts_before
1815
+
1816
  # Update text position_ids
1817
  # All tokens get shifted by cum_shifts
1818
  # Image tokens specifically need to be at t_val + max_hw (which is t_val + shift - 1)
1819
  # Our cum_shift update gives: orig_pos + shifts_before + shift = t_val + shift
1820
  # So we subtract 1 from image tokens
1821
+
1822
  # Apply global shift
1823
  # Note: position_ids is (3, B, L), cum_shifts is (B, L). Expand to match.
1824
  new_pos_ids = position_ids + cum_shifts.unsqueeze(0)
1825
+
1826
  # Correct image tokens (subtract 1)
1827
  # We can use boolean mask for efficient update
1828
  img_token_mask = torch.zeros_like(input_ids, dtype=torch.bool)
1829
  img_token_mask[batch_rows, text_cols] = True
1830
  new_pos_ids[:, img_token_mask] -= 1
1831
+
1832
  # Ensure padding positions remain 0 (if attention_mask provided)
1833
  if attention_mask is not None:
1834
  # Assuming padding is 0 in attention_mask
1835
  padding_mask = (attention_mask == 0).unsqueeze(0)
1836
  new_pos_ids.masked_fill_(padding_mask, 0)
1837
+
1838
  # Update position_ids in-place
1839
  position_ids.copy_(new_pos_ids)
1840
+
1841
  # 3. Populate Vision Pos IDs
1842
  # Group frames by size (eff_h, eff_w) to vectorize grid generation
1843
  # This is efficient because typically there are few distinct aspect ratios
1844
  unique_shapes = torch.unique(torch.stack([flat_eff_h, flat_eff_w], dim=1), dim=0)
1845
+
1846
  for shape in unique_shapes:
1847
  eh, ew = shape[0].item(), shape[1].item()
1848
+
1849
  # Mask for frames of this shape
1850
  mask = (flat_eff_h == eh) & (flat_eff_w == ew)
1851
+
1852
  sub_t_vals = t_vals[mask]
1853
  sub_batch_rows = batch_rows[mask]
1854
  sub_vis_starts = flat_vis_starts[mask]
1855
+
1856
  num_frames_sub = sub_t_vals.shape[0]
1857
  if num_frames_sub == 0: continue
1858
+
1859
  # Generate grids: (num_frames, eh, ew)
1860
  # y ranges 0..eh-1, x ranges 0..ew-1
1861
  # positions: t + y, t + x
1862
+
1863
  y_grid = torch.arange(eh, device=device).view(1, eh, 1).expand(num_frames_sub, -1, ew)
1864
  x_grid = torch.arange(ew, device=device).view(1, 1, ew).expand(num_frames_sub, eh, -1)
1865
  t_grid = sub_t_vals.view(-1, 1, 1).expand(-1, eh, ew)
1866
+
1867
  h_grid = t_grid + y_grid
1868
  w_grid = t_grid + x_grid
1869
+
1870
  # Flatten to assign
1871
  flat_t = t_grid.reshape(-1)
1872
  flat_h = h_grid.reshape(-1)
1873
  flat_w = w_grid.reshape(-1)
1874
+
1875
  # Calculate destination indices in vision_pos_ids
1876
  # (batch, seq_pos)
1877
  tokens_per_frame = eh * ew
1878
+
1879
  # Offsets for each token in the frame 0..N-1
1880
+ seq_offsets = torch.arange(tokens_per_frame, device=device).unsqueeze(0)
1881
  # Add start index: (num_frames, 1) + (1, tokens) -> (num_frames, tokens)
1882
  abs_seq_offsets = seq_offsets + sub_vis_starts.unsqueeze(1)
1883
+
1884
  flat_seq_inds = abs_seq_offsets.reshape(-1)
1885
  flat_batch_inds = sub_batch_rows.unsqueeze(1).expand(-1, tokens_per_frame).reshape(-1)
1886
+
1887
  # Clip to max_vision_seq_len
1888
  valid_mask = flat_seq_inds < max_vision_seq_len
1889
+
1890
  if valid_mask.any():
1891
  final_b = flat_batch_inds[valid_mask]
1892
  final_s = flat_seq_inds[valid_mask]
1893
+
1894
  vision_pos_ids[0, final_b, final_s] = flat_t[valid_mask]
1895
  vision_pos_ids[1, final_b, final_s] = flat_h[valid_mask]
1896
  vision_pos_ids[2, final_b, final_s] = flat_w[valid_mask]
1897
+
1898
  # 4. Handle Separator Tokens
1899
  # Position: t_val + max(eh, ew)
1900
  sep_vals = t_vals + max_hw
1901
  # Index: start + tokens_per_frame = start + eh*ew
1902
  sep_indices = flat_vis_starts + (flat_eff_h * flat_eff_w)
1903
+
1904
  valid_sep_mask = sep_indices < max_vision_seq_len
1905
+
1906
  if valid_sep_mask.any():
1907
  final_b = batch_rows[valid_sep_mask]
1908
  final_s = sep_indices[valid_sep_mask]
1909
  vals = sep_vals[valid_sep_mask]
1910
+
1911
  vision_pos_ids[0, final_b, final_s] = vals
1912
  vision_pos_ids[1, final_b, final_s] = vals
1913
  vision_pos_ids[2, final_b, final_s] = vals
1914
+
1915
  # 5. Compute Rope Deltas
1916
  # rope_deltas[batch_idx] = max_pos + 1 - seq_len
1917
+
1918
  # Use updated position_ids
1919
  # Max pos in each batch - take max across all 3 position dimensions
1920
  # position_ids shape: (3, batch_size, seq_len)
1921
  # We need rope_deltas shape: (batch_size,)
1922
  max_pos = position_ids.max(dim=0).values.max(dim=-1).values # (batch_size,)
1923
  rope_deltas = max_pos + 1 - input_ids.shape[1] # (batch_size,)
1924
+
1925
  return vision_pos_ids, position_ids, rope_deltas
1926
 
1927
  def get_vision_features(
1928
+ self,
1929
+ pixel_values: torch.FloatTensor,
1930
  grid_thw: Optional[torch.LongTensor] = None,
1931
  media_nums_per_sample: Optional[List[int]] = None
1932
  ):
 
1941
  """
1942
  pixel_values = pixel_values.type(self.visual.dtype)
1943
  hidden_states = self.visual(
1944
+ pixel_values,
1945
  grid_thw=grid_thw
1946
  )
1947
  vision_embeds, vision_token_info = self.convert_packed_to_batch(
1948
+ hidden_states,
1949
+ grid_thw,
1950
  media_nums_per_sample
1951
  )
1952
  return vision_embeds, vision_token_info
 
2497
 
2498
 
2499
  def get_vision_features(
2500
+ self,
2501
+ pixel_values: torch.FloatTensor,
2502
  grid_thw: Optional[torch.LongTensor] = None,
2503
  media_nums_per_sample: Optional[List[int]] = None
2504
  ):
2505
  """
2506
  Get vision features for images and videos (merged).
2507
+
2508
  Args:
2509
  pixel_values: vision pixel values (images and videos merged)
2510
  grid_thw: [num_media, 3] tensor with (t, h, w) for each media item
 
2558
  cross_attention_mask (`torch.Tensor` of shape `(batch_size, 1, text_seq_len, vision_seq_len)`, *optional*):
2559
  Attention mask for cross-attention between text and vision. Controls which vision tokens each text
2560
  token can attend to, enforcing causal visibility for video frames.
2561
+ vision_chunked_length (`int`, *optional*):
2562
+ Number of media items per visual-encoder chunk for offline prefill.
2563
+ vision_cache_position (`torch.LongTensor`, *optional*):
2564
+ Cache positions for incrementally appended realtime vision key/value states.
2565
+ full_vision_token_info (`List[dict]`, *optional*):
2566
+ Cumulative realtime vision metadata used to expand the cross-attention mask.
2567
  """
2568
  outputs = self.model(
2569
  input_ids=input_ids,
 
2621
  ):
2622
  """
2623
  Prepare inputs for generation.
2624
+
2625
+ Note: Currently only supports offline visual understanding, meaning all multimodal
2626
+ content must be provided before generation starts. We don't support adding new
2627
  images/videos during generation (streaming mode).
2628
+
2629
  Args:
2630
  media_nums_per_sample: One video counts as one media item (regardless of frame count)
2631
  """
 
2647
  # For decoding stage, if position_ids are generated by GenerationMixin (2D),
2648
  # we can set them to None to let forward recompute them from cache_position.
2649
  model_inputs["position_ids"] = None
2650
+
2651
  # Handle cross attention mask
2652
  if cross_attention_mask is not None:
2653
  # Slice to current sequence length on text dimension (dim=2)
 
2659
  # In decode stage, vision features are retrieved from cross attention cache
2660
  if cache_position[0] != 0:
2661
  model_inputs["pixel_values"] = None
2662
+ model_inputs["grid_thw"] = None
2663
  model_inputs["media_nums_per_sample"] = None
2664
  model_inputs["vision_position_ids"] = None
2665
+
2666
  else:
2667
  # In prefill stage, include all vision-related inputs
2668
  model_inputs["vision_position_ids"] = vision_position_ids
 
2674
  def _update_model_kwargs_for_generation(self, outputs, model_kwargs, is_encoder_decoder, **kwargs):
2675
  """
2676
  Update model kwargs for generation, extending cross_attention_mask for the newly generated token.
2677
+
2678
  In offline mode (all multimodal content provided before generation):
2679
  - Each newly generated token should have the same cross_attention_mask pattern as the previous token
2680
  - This ensures all generated tokens can attend to all vision tokens that were visible before
2681
  """
2682
  cross_attention_mask_prev = model_kwargs.get("cross_attention_mask", None)
2683
+
2684
  model_kwargs = super()._update_model_kwargs_for_generation(
2685
  outputs=outputs,
2686
  model_kwargs=model_kwargs,
2687
  is_encoder_decoder=is_encoder_decoder,
2688
  **kwargs,
2689
  )
2690
+
2691
  # Extend cross_attention_mask for the new token
2692
  # Copy the last token's mask pattern for the newly generated token
2693
  if cross_attention_mask_prev is not None: