mindspore-ai / mindspore-ai/hyper-parallel
训练栈:examples/ 三个 train.yaml 在最新 master 上报错(dp_shard leaf/grad + vl-moe get_input_embeddings/AC 回退)
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 53
- Forks
- 63
- Avg merge
- 23h 45m
- Merged PRs (30d)
- 63
Description
该问题是怎么引起的?
PR #599(训练栈 + qwen3.5 dense/moe/vl-moe 对齐,描述中显式依赖 PR #633 的 dp_shard==1 修复)合入时,examples/ 下三个 train.yaml 是验证过能跑通 + 1c↔FSDP4 对齐的。此后 master 上的若干提交把四处回退/移除了,导致现在直接跑这三个 example 在 init / parallelize 阶段全部崩溃,无法开始训练。下面逐文件说明每一处为什么是 bug。
1. hyper_parallel/platform/torch/fully_shard/param.py(TorchHSDPParamV2)—— sharded _local_tensor 丢了 .detach()
这段代码做什么:meta-init(to_empty)+ FSDP 分片后,要把"切出来的本地分片"绑到 DTensor 参数的 _local_tensor 上。当前 master:
if updated_local_tensor:
with torch.no_grad():
local_view = local_tensor.narrow(dim=shard_dim, start=0, length=length) # ← 缺 .detach()
set_requires_grad_if_needed(self.sharded_param, local_view)
self.sharded_param._local_tensor = local_view
为什么是 bug:Tensor.narrow(...) 返回的是 base(local_tensor)的 autograd 视图(view),仍挂在它的求导图上;这步在 to_empty 期间、torch.no_grad() 下执行 → 是"no_grad 下创建的视图"。之后权重加载 / 混精 upcast 在 grad 模式下原地改写它/它的 base。等构造 torch.optim.AdamW 时,add_param_group 读 param.is_leaf(DTensor 的 is_leaf → self._local_tensor.is_leaf),PyTorch autograd 检测到"no_grad 下建的视图、其 base 又在 grad 模式下被原地改"这种自相矛盾状态,直接抛 RuntimeError。
为什么这样改能修:.narrow(...).detach() 返回共享 storage 但脱离求导图的张量(干净 leaf),不是 local_tensor 的 autograd 视图——is_leaf 读取不再触发该检查。PR #633 原本就有这个 .detach(),master 上某次 fully_shard 重构把它丢了。本质是恢复 PR #633。
2. hyper_parallel/platform/torch/fully_shard/state.py(TorchHSDPStateV2.lazy_init)—— dp_shard==1 时漏 reset
这段代码做什么:lazy_init 在 meta 物化后把每个 sharded 参数 reset_sharded_param() 重新包回正确的 DTensor nn.Parameter,让优化器和 forward 拿到对的对象。当前 master:
def lazy_init(self):
if self.is_shard and not self._reset_sharded_params: # ← 多了 self.is_shard
for hsdp_param in self.hsdp_params:
hsdp_param.reset_sharded_param()
self._reset_sharded_params = True
为什么是 bug:self.is_shard 在 dp_shard==1(world_size==1、实际不分片)时为 False,于是整段 reset 被跳过——单卡路径下 param 没被重新包/重置,留在 meta(HSDP params still on meta device),且第 1 点的 leaf 不变量也建立不起来。PR #599(380840b)时这里是 if not self._reset_sharded_params:,没有 self.is_shard。world_size==1 时同样要 reset/re-wrap(unshard/shard hook 要把模块属性换回普通 nn.Parameter,避免 DTensor 漏进 forward),故去掉守卫。本文件 #2 与上面 #1 合起来就是 PR #633 的"dp_shard==1 leaf/grad"修复,缺一不可。
3. hyper_parallel/models/qwen3_vl_moe/model.py(Qwen3VLMoeModel)—— get_input_embeddings 被误删
这段代码做什么:Qwen3VLMoeModel.forward 在 inputs_embeds is None 时按 HF 标准做法取文本词嵌入:
def forward(self, input_ids, ..., inputs_embeds=None, pixel_values=None, ...):
if inputs_embeds is None:
inputs_embeds = self.get_input_embeddings()(input_ids) # ← 调用 get_input_embeddings
... # 之后再把图像特征 merge 进 inputs_embeds
为什么是 bug:Qwen3VLMoeModel.get_input_embeddings(返回 self.language_model.embed_tokens)被 d464b132 fix(codecheck): add missing docstrings for C0116 warnings(一次性动了 66 个文件的 codecheck/docstring 清理)连带删掉了,但 forward 仍在调它 → vl-moe 第一步 forward 就崩:AttributeError: 'Qwen3VLMoeModel' object has no attribute 'get_input_embeddings'。
为什么这样改能修:把 get_input_embeddings(+ 对称的 set_input_embeddings)补回 Qwen3VLMoeModel,指向 self.language_model.embed_tokens——纯属恢复 PR #599 就有的方法。
4. hyper_parallel/platform/torch/activation_checkpoint/activation_swap.py(_check_and_mark_wrapped)—— 不容忍跨层共享的 rotary
这段代码做什么:激活重计算逐层 checkpoint_wrapper(layer) 时,_check_and_mark_wrapped 遍历该层子模块:先"重叠保护"(任一子模块已 _is_wrapped 就报错),再把所有子模块标记为已包裹。
为什么是 bug:Qwen3-VL-MoE 的所有 text decoder 层共享同一个 MultiModalRotaryEmbedding 实例(有意设计:位置编码算一次、各层共用)。包第 0 层时该 rotary 被标记 _is_wrapped;包第 1 层时,同一个实例被判"已包裹" → ValueError: Submodule 'MultiModalRotaryEmbedding' of 'Qwen3VLMoeTextDecoder' is already wrapped。这个 overlap 守卫是 PR #599 之后才加的(PR #599 没有它),加时没考虑"合法的跨层共享子模块"。vl-moe example 用 activation_checkpoint: full 必然走到这里(dense/moe 用 none 不触发)。
为什么这样改能修:被共享的 rotary 是无状态的(只算位置编码、没有要 checkpoint 的参数),包一次(随第 0 层)、后续层跳过它是正确的,不存在真正的"重叠区域"风险。所以把"子模块已包裹就 raise"改成"continue(跳过)"。
重现步骤
环境:8×Ascend 910B3,CANN 9.0.0,torch 2.7.1 + torch_npu 2.7.1,最新 upstream/master(eebcca6)。填好三个 example 的 weights_path(dense/moe 另需 preset_pt batch 文件),确定性变量 HCCL_DETERMINISTIC=true LCCL_DETERMINISTIC=1 ASCEND_LAUNCH_BLOCKING=1 HCCL_OP_BASE_FFTS_MODE_ENABLE=false,分别跑:
torchrun --standalone --nproc_per_node=4 scripts/train_lm.py examples/qwen3_5_0_8b_base/train.yaml
torchrun --standalone --nproc_per_node=4 scripts/train_lm.py examples/qwen3_5_35b_a3b_base/train.yaml
torchrun --standalone --nproc_per_node=4 scripts/train_vl.py examples/qwen3_vl_30b_a3b_instruct/train.yaml
三个全部崩溃,无一能开始训练。
报错信息
dense / moe —— optimizer 构造(文件 #1+#2):
File ".../hyper_parallel/trainer/base.py", in _build_optimizer
self.optimizer = torch.optim.AdamW(param_groups, ...)
... add_param_group ... param.is_leaf or param.retains_grad
File ".../hyper_parallel/platform/torch/dtensor.py", line 187, in is_leaf
return self._local_tensor.is_leaf
RuntimeError: A view was created in no_grad mode and its base or another view of its base
has been modified inplace with grad mode enabled. ...
vl-moe —— parallelize 的 AC 包裹(文件 #4):
File ".../hyper_parallel/models/qwen3_vl_moe/parallelize.py", in _apply_ac
model.layers[i] = checkpoint_wrapper(layer)
File ".../activation_checkpoint/activation_swap.py", in _check_and_mark_wrapped
raise ValueError(...)
ValueError: Submodule 'MultiModalRotaryEmbedding' of 'Qwen3VLMoeTextDecoder' is already wrapped.
Wrapping overlapping module regions is not allowed.
vl-moe —— AC 修复后 forward(文件 #3):
File ".../hyper_parallel/models/qwen3_vl_moe/model.py", in forward
inputs_embeds = self.get_input_embeddings()(input_ids)
AttributeError: 'Qwen3VLMoeModel' object has no attribute 'get_input_embeddings'
修复(恢复 #1 .detach() + #2 去 self.is_shard 守卫 + #3 补回 get_input_embeddings + #4 容忍共享子模块)后,三个 example 各 20 步 Training completed,1c↔FSDP4 自洽通过(dense/moe ULP 级 ~1e-6,vl-moe 逐位)。修复见关联 PR。
schema_version: 1
source: gitcode
gitcode_repo: mindspore/hyper-parallel
gitcode_issue: 230
source_url: https://gitcode.com/mindspore/hyper-parallel/issues/230
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the four named files: fully_shard/param.py and state.py, models/qwen3_vl_moe/model.py, and activation_checkpoint/activation_swap.py. Run the three listed train.yaml commands in the specified environment and compare the failures with the described leaf, meta-parameter, embedding, and shared-rotary paths. Done means all three examples complete 20 training steps and the stated 1c↔FSDP4 consistency checks pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, pytorch
- Domain
- distributed-systems, machine-learning
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100