Skip to content

Commit 491596e

Browse files
authored
[qwen3.5] fix DTensor TP vision position caches (#3899)
Stack from [ghstack](https://github.com/ezyang/ghstack/tree/0.12.0) (oldest at bottom): * #3895 * __->__ #3899 Main TP was failing with `FLA_TILELANG=0 MODULE=qwen3_5 CONFIG=qwen35_debugmodel NGPU=2 ./run_train.sh --parallelism.tensor_parallel_degree 2 --parallelism.data_parallel_shard_degree 1 --debug.seed 42 --debug.deterministic --training.steps 1` ``` [rank0]:[rank0]: File "/data/users/pianpwk/full_spmd_types_torchtitan/tt4_spmd_types/torchtitan/torchtitan/models/qwen3_5/vision_encoder.py", line 91, in _compute_learned_pos_embeds [rank0]:[rank0]: pos_hw = F.interpolate( [rank0]:[rank0]: ^^^^^^^^^^^^^^ [rank0]:[rank0]: File "/data/users/pianpwk/full_spmd_types_torchtitan/pytorch/torch/nn/functional.py", line 5273, in interpolate [rank0]:[rank0]: )._upsample_linear_vec(input, output_size, align_corners, scale_factors) [rank0]:[rank0]: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [rank0]:[rank0]: File "/data/users/pianpwk/full_spmd_types_torchtitan/pytorch/torch/_decomp/decompositions.py", line 4507, in _upsample_linear_vec [rank0]:[rank0]: return _upsample_linear(input, osize, align_corners, scales) [rank0]:[rank0]: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [rank0]:[rank0]: File "/data/users/pianpwk/full_spmd_types_torchtitan/pytorch/torch/_decomp/decompositions.py", line 91, in inner [rank0]:[rank0]: r = f(*tree_map(increase_prec, args), **tree_map(increase_prec, kwargs)) [rank0]:[rank0]: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [rank0]:[rank0]: File "/data/users/pianpwk/full_spmd_types_torchtitan/pytorch/torch/_decomp/decompositions.py", line 4627, in _upsample_linear [rank0]:[rank0]: v = aten._unsafe_index(input, idx) [rank0]:[rank0]: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [rank0]:[rank0]: File "/data/users/pianpwk/full_spmd_types_torchtitan/pytorch/torch/_ops.py", line 1350, in __call__ [rank0]:[rank0]: return self._op(*args, **kwargs) [rank0]:[rank0]: ^^^^^^^^^^^^^^^^^^^^^^^^^ [rank0]:[rank0]: RuntimeError: aten._unsafe_index.Tensor got mixed torch.Tensor and DTensor, need to convert all torch.Tensor to DTensor before calling distributed operators! ``` - DTensor decomposition goes to unsafe_index which creates local plain tensors - fixes by local-mapping interpolate - upcoming spmd_types PR would parallelize inv_freq, get ahead of this by also wrapping positions as DTensors - previously that portion was done in plain tensor
1 parent 6ad8c3d commit 491596e

2 files changed

Lines changed: 43 additions & 15 deletions

File tree

torchtitan/models/qwen3_5/sharding.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@ def _set_vision_encoder_sharding(ve_cfg: "Qwen35VisionEncoder.Config") -> None:
205205
ve_cfg.sharding_config = ShardingConfig(
206206
state_shardings={"pos_embed": dense_param_placement(tp=spmd.R)},
207207
)
208+
ve_cfg.rotary_pos_emb.sharding_config = ShardingConfig(
209+
state_shardings={"inv_freq": dense_param_placement(tp=spmd.I)},
210+
out_src_shardings=dense_param_placement(tp=spmd.I),
211+
)
208212

209213
# patch_embed receives plain pixel_values — wrap as DTensor(Replicate)
210214
ve_cfg.patch_embed_proj.sharding_config = ShardingConfig(

torchtitan/models/qwen3_5/vision_encoder.py

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@
1010
import torch
1111
import torch.nn as nn
1212
import torch.nn.functional as F
13+
from torch.distributed.tensor import DTensor
14+
from torch.distributed.tensor.experimental import local_map
1315
from torch.nn.attention.flex_attention import BlockMask, create_block_mask
1416

1517
from torchtitan.models.common import Linear
1618
from torchtitan.models.common.attention import FlexAttention
1719
from torchtitan.models.common.nn_modules import GELU, LayerNorm
18-
from torchtitan.models.common.rope import CosSinRoPE
20+
from torchtitan.models.common.rope import _maybe_wrap_positions, CosSinRoPE
1921
from torchtitan.protocols.module import Module, ModuleDict
2022

2123
_compiled_create_block_mask = torch.compile(create_block_mask)
@@ -88,12 +90,21 @@ def _compute_learned_pos_embeds(
8890
)
8991

9092
for (h, w), indices in hw_to_indices.items():
91-
pos_hw = F.interpolate(
92-
pos_grid,
93-
size=[h, w],
94-
mode="bilinear",
95-
align_corners=True,
96-
)
93+
if isinstance(pos_grid, DTensor):
94+
pos_hw = local_map(F.interpolate, out_placements=(pos_grid.placements,),)(
95+
pos_grid,
96+
size=[h, w], # pyrefly: ignore [unexpected-keyword]
97+
mode="bilinear", # pyrefly: ignore [unexpected-keyword]
98+
align_corners=True, # pyrefly: ignore [unexpected-keyword]
99+
)
100+
else:
101+
pos_hw = F.interpolate(
102+
pos_grid,
103+
size=[h, w],
104+
mode="bilinear",
105+
align_corners=True,
106+
)
107+
97108
# (1, dim, h, w) → (h*w, dim)
98109
pos_hw = pos_hw.squeeze(0).permute(1, 2, 0).reshape(-1, dim).to(dtype)
99110

@@ -251,7 +262,8 @@ def forward(self, seqlen: int) -> torch.Tensor:
251262
seq = torch.arange(
252263
seqlen, device=self.inv_freq.device, dtype=self.inv_freq.dtype
253264
)
254-
return torch.outer(seq, self.inv_freq)
265+
seq = _maybe_wrap_positions(seq, self.inv_freq)
266+
return torch.outer(seq, self.inv_freq) # pyrefly: ignore
255267

256268

257269
class PatchMerger(Module):
@@ -485,13 +497,25 @@ def compute_position_embeddings(
485497
self.config.dim,
486498
)
487499

488-
rope_cache = _compute_2d_rope_cache(
489-
self._cached_freq_table,
490-
grid_thw,
491-
max_num_patch,
492-
self.spatial_merge_size,
493-
head_dim,
494-
)
500+
if isinstance(self._cached_freq_table, DTensor):
501+
rope_cache = local_map(
502+
_compute_2d_rope_cache,
503+
out_placements=(self._cached_freq_table.placements,),
504+
)(
505+
self._cached_freq_table,
506+
grid_thw, # pyrefly: ignore [bad-argument-count]
507+
max_num_patch,
508+
self.spatial_merge_size,
509+
head_dim,
510+
)
511+
else:
512+
rope_cache = _compute_2d_rope_cache(
513+
self._cached_freq_table,
514+
grid_thw,
515+
max_num_patch,
516+
self.spatial_merge_size,
517+
head_dim,
518+
)
495519

496520
return learned_pos, rope_cache
497521

0 commit comments

Comments
 (0)