[Model] Avoid scalar synchronizations in GLM-Image preparation (#7172)

Signed-off-by: hyw <yuweih205@gmail.com>
This commit is contained in:
hyw authored and GitHub committed 2026-09-11 09:09:26 +00:00
1 parent a7ab91fb85
commit 3f7c217457
2 files changed
+11 -26

No files matched your search

@@ -399,15 +399,14 @@ class TestGlmImagePrepareModule:
prepare = GlmImagePrepare(
image_projector=projector,
rope=rope,
patch_size=2,
)
# Test forward pass
hidden_states = torch.randn(1, 16, 64, 64) # [B, C, H, W]
result = prepare(hidden_states)
assert len(result) == 5
hidden_out, rope_cos, rope_sin, height, width = result
assert len(result) == 3
hidden_out, rope_cos, rope_sin = result
assert hidden_out.shape[0] == 1 # batch size
assert hidden_out.shape[1] == 1024 # seq_len (32 * 32)
assert hidden_out.shape[2] == 2560 # hidden_dim
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
import math
from collections.abc import Iterable
@@ -124,8 +124,8 @@ class GlmImageImageProjector(nn.Module):
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
batch_size, channel, height, width = hidden_states.shape
post_patch_height = torch.tensor(height // self.patch_size, device=hidden_states.device, dtype=torch.int64)
post_patch_width = torch.tensor(width // self.patch_size, device=hidden_states.device, dtype=torch.int64)
post_patch_height = height // self.patch_size
post_patch_width = width // self.patch_size
# Reshape: [B, C, H, W] -> [B, H', W', C*p*p] -> [B, H'*W', C*p*p]
hidden_states = hidden_states.reshape(
@@ -189,18 +189,16 @@ class GlmImagePrepare(nn.Module):
self,
image_projector: nn.Module,
rope: GlmImageRotaryPosEmbed,
patch_size: int,
):
super().__init__()
self.image_projector = image_projector
self.rope = rope
self.patch_size = patch_size
def forward(
self,
hidden_states: torch.Tensor,
prior_hidden_states: torch.Tensor | None = None,
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
"""Process hidden_states and compute RoPE embeddings.
Args:
@@ -211,14 +209,7 @@ class GlmImagePrepare(nn.Module):
hidden_states: Patched hidden states [B, seq_len, D]
rope_cos: RoPE cos embeddings [seq_len, dim]
rope_sin: RoPE sin embeddings [seq_len, dim]
post_patch_height: Scalar tensor for height after patching
post_patch_width: Scalar tensor for width after patching
"""
batch_size, num_channels, height, width = hidden_states.shape
post_patch_height = torch.tensor(height // self.patch_size, device=hidden_states.device, dtype=torch.int64)
post_patch_width = torch.tensor(width // self.patch_size, device=hidden_states.device, dtype=torch.int64)
# Compute RoPE (uses original 4D hidden_states shape)
image_rotary_emb = self.rope(hidden_states)
rope_cos = image_rotary_emb[0].to(hidden_states.device)
@@ -231,7 +222,7 @@ class GlmImagePrepare(nn.Module):
if prior_hidden_states is not None:
hidden_states = hidden_states + prior_hidden_states
return hidden_states, rope_cos, rope_sin, post_patch_height, post_patch_width
return hidden_states, rope_cos, rope_sin
class GlmImageAdaLayerNormZero(nn.Module):
@@ -961,7 +952,6 @@ class GlmImageTransformer2DModel(CachedTransformer):
1: SequenceParallelInput(split_dim=0, expected_dims=2, split_output=True, auto_pad=True),
# RoPE sin: [seq_len, dim] - shard along sequence dimension
2: SequenceParallelInput(split_dim=0, expected_dims=2, split_output=True, auto_pad=True),
# post_patch_height and post_patch_width are scalars, not sharded
},
# Gather output at proj_out
"proj_out": SequenceParallelOutput(gather_dim=1, expected_dims=3),
@@ -1044,7 +1034,7 @@ class GlmImageTransformer2DModel(CachedTransformer):
)
# Prepare module for SP (encapsulates patch embedding and RoPE for _sp_plan)
self.prepare = GlmImagePrepare(self.image_projector, self.rope, patch_size)
self.prepare = GlmImagePrepare(self.image_projector, self.rope)
self.time_condition_embed = GlmImageCombinedTimestepSizeEmbeddings(
embedding_dim=time_embed_dim,
@@ -1137,12 +1127,10 @@ class GlmImageTransformer2DModel(CachedTransformer):
# 1. Prepare hidden_states and RoPE via GlmImagePrepare module
# _sp_plan will shard hidden_states and RoPE together via split_output=True
hidden_states, rope_cos, rope_sin, post_patch_height_t, post_patch_width_t = self.prepare(
hidden_states, prior_hidden_states
)
hidden_states, rope_cos, rope_sin = self.prepare(hidden_states, prior_hidden_states)
image_rotary_emb = (rope_cos, rope_sin)
post_patch_height = int(post_patch_height_t.item())
post_patch_width = int(post_patch_width_t.item())
post_patch_height = height // self.patch_size
post_patch_width = width // self.patch_size
# Timestep conditioning
temb = self.time_condition_embed(timestep, target_size, crop_coords, hidden_states.dtype)
@@ -1163,8 +1151,6 @@ class GlmImageTransformer2DModel(CachedTransformer):
device=hidden_states.device,
)
hidden_states_mask[:, ctx.sp_original_seq_len :] = False
if hidden_states_mask.all():
hidden_states_mask = None
# 2. Transformer blocks
for layer_idx, block in enumerate(self.transformer_blocks):