|
27 | 27 | from ...utils import auto_docstring |
28 | 28 | from ...utils.generic import merge_with_config_defaults |
29 | 29 | from ...utils.output_capturing import capture_outputs |
30 | | -from ...vision_utils import get_vision_position_ids |
| 30 | +from ...vision_utils import get_vision_attention_seqlens, get_vision_position_ids |
31 | 31 | from ..auto import AutoConfig, AutoModel |
32 | 32 | from ..qwen2_5_vl.configuration_qwen2_5_vl import Qwen2_5_VLConfig, Qwen2_5_VLVisionConfig |
33 | 33 | from ..qwen2_5_vl.modeling_qwen2_5_vl import ( |
@@ -114,6 +114,13 @@ def __post_init__(self, **kwargs): |
114 | 114 | raise ValueError("vision_config.out_hidden_size must match text_config.hidden_size") |
115 | 115 |
|
116 | 116 |
|
| 117 | +def get_vision_frame_lengths(cu_seqlens: torch.Tensor, kwargs: dict | None = None) -> list[int]: |
| 118 | + """Get patch counts per frame, or consume geometry prepared before graph capture.""" |
| 119 | + if kwargs is not None and (frame_lengths := kwargs.pop("frame_lengths", None)) is not None: |
| 120 | + return frame_lengths |
| 121 | + return (cu_seqlens[1:] - cu_seqlens[:-1]).tolist() |
| 122 | + |
| 123 | + |
117 | 124 | class LlavaOnevision15VisionPatchEmbed(nn.Module): |
118 | 125 | def __init__(self, config: LlavaOnevision15VisionConfig): |
119 | 126 | super().__init__() |
@@ -239,22 +246,23 @@ def forward(self, hidden_states: torch.Tensor, grid_thw: torch.Tensor, **kwargs) |
239 | 246 | Temporal, height and width dimensions of the patch grid for each image or video. |
240 | 247 | """ |
241 | 248 | hidden_states = self.patch_embed(hidden_states) |
242 | | - position_ids = get_vision_position_ids(grid_thw, self.spatial_merge_size) |
| 249 | + position_ids = get_vision_position_ids(grid_thw, self.spatial_merge_size, kwargs=kwargs) |
243 | 250 | cos, sin = self.rotary_pos_emb(hidden_states, position_ids) |
244 | | - lengths = torch.repeat_interleave(grid_thw[:, 1] * grid_thw[:, 2], grid_thw[:, 0]) |
245 | | - frame_lengths = lengths.tolist() |
| 251 | + cu_seqlens, max_seqlen = get_vision_attention_seqlens(grid_thw, self.config, kwargs=kwargs) |
| 252 | + frame_lengths = get_vision_frame_lengths(cu_seqlens, kwargs=kwargs) |
| 253 | + cu_seqlens = cu_seqlens + torch.arange(cu_seqlens.shape[0], device=cu_seqlens.device, dtype=cu_seqlens.dtype) |
| 254 | + if max_seqlen is not None: |
| 255 | + max_seqlen += 1 |
246 | 256 | cls_hidden = self.class_embedding.to(hidden_states.dtype).unsqueeze(0) |
247 | 257 | cls_freqs = torch.cat((self.class_pos_emb, self.class_pos_emb), dim=-1).to(cos.dtype) |
248 | 258 | cls_cos, cls_sin = cls_freqs.cos().to(cos.dtype), cls_freqs.sin().to(sin.dtype) |
249 | 259 | hidden_states, cos, sin = [ |
250 | 260 | torch.cat([torch.cat((cls, frame), dim=0) for frame in torch.split(value, frame_lengths)], dim=0) |
251 | 261 | for value, cls in ((hidden_states, cls_hidden), (cos, cls_cos), (sin, cls_sin)) |
252 | 262 | ] |
253 | | - cu_seqlens = nn.functional.pad((lengths + 1).cumsum(0, dtype=torch.int32), (1, 0)) |
254 | | - |
255 | 263 | hidden_states = self.pre_layernorm(hidden_states) |
256 | 264 | for block in self.blocks: |
257 | | - hidden_states = block(hidden_states, cu_seqlens, cos, sin, **kwargs) |
| 265 | + hidden_states = block(hidden_states, cu_seqlens, cos, sin, max_seqlen=max_seqlen, **kwargs) |
258 | 266 |
|
259 | 267 | hidden_states = torch.cat( |
260 | 268 | [frame[1:] for frame in torch.split(hidden_states, [length + 1 for length in frame_lengths])], dim=0 |
|
0 commit comments