已开启
[Bug] distribute_module 复制路径在 MindSpore 下丢失 param.name 导致参数重名冲突 #224
husichao创建于  6月16日
husichao
6月16日 创建

问题简述 (Summary)

在 MindSpore 后端下,distribute_module 的复制路径(_replicate_submodule_params_buffers)
用 module_prefix + 局部 key 拼出新参数名,而没有沿用参数自身已经全局限定的 param.name。
对叶子模块调用 distribute_module 时 module_prefix 为空,新参数名退化为裸局部 key
(如 "weight")。由于 MindSpore 要求参数名全局唯一,当多个叶子模块都走这条复制路径时,
第二个就会报 its name 'weight' already exists。

使用场景 (Use case)

pynative 模式下用 distribute_module 做张量并行 / 专家并行。两种常见写法都会触发:

  1. 复制类 ParallelStyle(如对 LayerNorm / 路由 gate 的 NoParallel / SequenceParallel)
    传 partition_fn=None,让 distribute_module 把所有参数复制成 DTensor;
  2. 分片类 style 的 partition_fn 只覆盖了部分参数,其余参数交给内置 replicate pass。

在一个有多个叶子线性/嵌入/归一化层的真实模型(例如 DeepSeek-V3)上,TP/EP 初始化阶段必现。

根因 (Root cause)

hyper_parallel/core/dtensor/dtensor.py 的 _replicate_submodule_params_buffers:

param_name = f"{module_prefix}.{key}" if module_prefix else key
new_param = _distribute_module_new_parameter(param_name, dt, requires_grad)

module_prefix 来自 cells_and_names(),是相对于传入 distribute_module 的那个模块的路径。
当 distribute_module 直接作用在叶子模块上时,其根的 module_prefix == "",于是
param_name 退化为裸局部 key("weight")。

_distribute_module_new_parameter 在 MindSpore 分支用该名字构造 Parameter(dtensor, name=param_name, ...):

if platform.platform_type == PlatformType.MINDSPORE:
    return platform.Parameter(dtensor, name=key, requires_grad=requires_grad)

PyTorch 的 Parameter 不依赖全局名字(靠 module 属性槽位 + 层级识别),所以无碍;
但 MindSpore 的 Parameter.name 必须全局唯一,多个叶子都被重命名为 "weight" → 冲突。

备注:同样的裸 key 问题也存在于自带的 ColwiseParallel / RowwiseParallel 的
_partition_linear_fn / _partition_embedding_fn(_distribute_module_new_parameter(key, ...)),
在 MindSpore 多 leaf TP 下同样会重名冲突。

错误栈 (Error)

ValueError: The value [Tensor(shape=[64640, 3584], dtype=Float32, value=...)] ,
its name 'weight' already exists. Please set a unique name for the parameter.
  File ".../hyper_parallel/core/dtensor/dtensor.py", in _replicate_submodule_params_buffers
    new_param = _distribute_module_new_parameter(param_name, dt, requires_grad)

(出现在第二个被复制的叶子模块上;第一个叶子把 "weight" 占用后,第二个再注册同名即报错。)

期望行为 (Expected)

复制(以及分片)重建参数时,MindSpore 下应沿用参数自身已限定的 param.name,
而不是用相对 module_prefix 重新拼。PyTorch 无 name 时再退回构造名。

建议修复 (Suggested fix)

_replicate_submodule_params_buffers 优先取 param.name:

param_name = getattr(param, "name", None) or (
    f"{module_prefix}.{key}" if module_prefix else key
)
new_param = _distribute_module_new_parameter(param_name, dt, requires_grad)

ColwiseParallel / RowwiseParallel 的 _partition_*_fn 同理改用 param.name。

环境 (Environment)

  • hyper_parallel: master @ 0c28158
  • MindSpore: 2.10.0
  • 硬件: Ascend 910B
  • 模型: DeepSeek-V3(pynative,TP / EP)
likedislike