Prhub

#6316 [ci, trainer] fix: fix code, scripts and st for mindspeedllm backend

原始 PR 作者 pengnuoheng 合并时间 2026-05-25 14:26 文件变更 16 提交数 4 评论 2 代码增减 +371 / -257

执行摘要

重命名 MindSpeed 策略并修复后端兼容性

MindSpeed 后端在 verl 中需要统一策略标识和配置结构,以支持新的 mindspeed_megatronmindspeed_fsdp 后端。旧命名 mindspeed_llm 已不再适用,且 llm_kwargs/mm_kwargs 需要重构为更通用的 mcore_kwargs

建议精读,重点关注 MindSpeedEngineConfig 的变更和 get_base_mcore_config_from_engine_config 的设计取舍。合并后可引导用户迁移配置,并尽快补充 FSDP 策略的处理。

讨论亮点

与 review 评论相关的讨论:

  • gemini-code-assist 评论 1:指出 verl/workers/engine/mindspeed/__init__.py 中导入未更新(但实际已更新,评论发表于代码合并前,可能基于旧版本)。
  • gemini-code-assist 评论 2:建议 get_base_mcore_config_from_engine_config 中应根据策略区分 mcore_kwargsfsdp_kwargs,目前代码仅使用 mcore_kwargs,当策略为 mindspeed_fsdp 时可能会丢失配置。该评论未被回应,属于未解决的设计问题。

实现拆解

  1. Engine 配置类重命名:在 verl/workers/config/engine.py 中,将 MindSpeedEngineConfig 的默认策略从 mindspeed_llm 改为 mindspeed_megatron,并将字段 llm_kwargs/mm_kwargs 替换为 mcore_kwargs/fsdp_kwargs
  2. Engine 实现类重命名:在 verl/workers/engine/mindspeed/transformer_impl.py 中,将 MindSpeedLLMEngineWithLMHead 重命名为 MindSpeedMegatronEngineWithLMHead,并修复 _build_megatron_moduleforward_only 分支的逻辑,移除早期 return 使代码更简洁。
  3. 配置转换函数适配:在 verl/workers/engine/mindspeed/utils.py 中,get_base_mcore_config_from_engine_config 不再按策略分支更新 kwargs,而是统一通过 engine_config.mcore_kwargs 注入;同时引入 get_hf_rope_theta 替代直接取 int(hf_config.rope_theta),以支持更多模型。
  4. 导入导出符号更新:更新 verl/workers/engine/__init__.pyverl/workers/engine/mindspeed/__init__.py 中的导入和 __all__ 列表,引用重命名后的类。
  5. 测试脚本与 CI 适配:新增 tests/special_npu/nightly_ci_ascend/run_grpo_qwen3_8b_mindspeedllm_npu.sh 作为 nightly CI 测试脚本,更新其他现有测试脚本中的策略名称和配置字段;修改 .github/workflows/nightly_ascend.yml 添加新测试 Job。
  6. 清理旧示例脚本:删除不再使用的 examples/grpo_trainer/run_qwen3_8b_mindspeed.sh,并用 examples/ascend_extras/grpo_trainer/run_qwen3_30b_a3b_mindspeed.sh 替代。
文件 模块 状态 重要度
verl/workers/engine/mindspeed/transformer_impl.py 引擎层 modified 6.96
verl/workers/config/engine.py 配置层 modified 6.01
verl/workers/engine/mindspeed/utils.py 工具函数 modified 6.29
verl/workers/engine/__init__.py 引擎层 modified 5.56
verl/workers/engine/mindspeed/__init__.py 引擎层 modified 5.44
tests/special_npu/nightly_ci_ascend/run_grpo_qwen3_8b_mindspeedllm_npu.sh 测试脚本 added 6.36
.github/workflows/nightly_ascend.yml CI 配置 modified 4.52

关键符号

MindSpeedLLMEngineWithLMHead -> MindSpeedMegatronEngineWithLMHead _build_megatron_module get_base_mcore_config_from_engine_config get_base_mcore_config_from_model_config MindSpeedEngineConfig.__post_init__

关键源码片段

verl/workers/engine/mindspeed/transformer_impl.py core-logic

核心 engine 实现文件,重命名类并修复 forward_only 分支逻辑。

# verl/workers/engine/mindspeed/transformer_impl.py@EngineRegistry.register(model_type="language_model", backend="mindspeed_megatron", device="npu")
class MindSpeedMegatronEngineWithLMHead(MegatronEngineWithLMHead):
    """MindSpeed Megatron 引擎实现,适用于语言模型(非值模型)。"""
​
    def __init__(
        self,
        model_config: HFModelConfig,
        engine_config: MindSpeedEngineConfig,
        optimizer_config: McoreOptimizerConfig,
        checkpoint_config: CheckpointConfig,
    ):
        super().__init__(model_config, engine_config, optimizer_config, checkpoint_config)
​
    def _init_device_mesh(self):
        # 在初始化模型并行之前重新应用 MindSpeed patch,
        # 因为第一次 patch 时 context_parallel_size 可能还未从 hydra 配置中获取。
        apply_patch(self.model_config, self.engine_config, self.optimizer_config)
        super()._init_device_mesh()
​
    def _build_megatron_module(self):
        # 判断是否为值模型(如 ForTokenClassification)
        is_value_model = (
            "ForTokenClassification" in self.model_config.architectures[0]
            or "ForSequenceClassification" in self.model_config.architectures[0]
        )
        self.is_value_model = is_value_model
​
        from megatron.core.enums import ModelType
        from megatron.training.training import get_model
​
        # 如果只做前向推理,则不需要优化器等辅助模块
        if self.engine_config.forward_only:
            module = get_model(gpt_model_provider, ModelType.encoder_or_decoder, wrap_with_ddp=False)
        else:
            # 训练模式,需要 DDP 包装
            module = get_model(gpt_model_provider, ModelType.encoder_or_decoder, wrap_with_ddp=True)
​
        # 加载权重(通过 vanilla bridge)
        if self.vanilla_bridge:
            self.bridge.load_weights(module, self.model_config.local_path)
        else:
            raise ValueError(f"vanilla_bridge should be true now, but got {self.vanilla_bridge}")
​
        # 打印模型规模(仅 rank 0)
        if torch.distributed.get_rank() == 0:
            print_model_size(module[0])
​
        # 如果启用 routing replay,打印相关实例数
        if self.enable_routing_replay:
            print(f"routing replay layers: {len(RouterReplay.router_instances)}")
​
        return module
verl/workers/config/engine.py core-logic

配置 dataclass 变更,重命名策略和 kwargs 字段。

# verl/workers/config/engine.py@dataclass
class MindSpeedEngineConfig(McoreEngineConfig):
    """Configuration for mindspeed parallelism.    The inheritance from BaseConfig provides omegaconf.DictConfig-like interface for a dataclass config.    Args:
        mcore_kwargs dict[str, Any]: mindspeed_megatron engine kwargs.
        fsdp_kwargs dict[str, Any]: mindspeed_fsdp engine kwargs.
    """
​
    strategy: str = "mindspeed_megatron"
    mcore_kwargs: dict[str, Any] = field(default_factory=dict)
    fsdp_kwargs: dict[str, Any] = field(default_factory=dict)
​
    def __post_init__(self) -> None:
        """config validation logics go here"""
        # 验证策略仅支持 mindspeed_megatron 或 mindspeed_fsdp
        assert self.strategy in ["mindspeed_megatron", "mindspeed_fsdp"], f"strategy {self.strategy} not supported"
        assert self.dtype in ["bfloat16", "float16"], f"dtype {self.dtype} not supported"
        if self.tensor_model_parallel_size == 1:
            warnings.warn("set sequence parallel to false as TP size is 1", stacklevel=2)
            self.sequence_parallel = False
verl/workers/engine/mindspeed/utils.py dependency-wiring

配置转换函数适配新策略和 kwargs。

# verl/workers/engine/mindspeed/utils.pydef get_base_mcore_config_from_engine_config(engine_config: MindSpeedEngineConfig) -> dict:
    """
    从 MindSpeedEngineConfig 创建基础 TransformerConfig 的公共部分。    Args:
        engine_config: mindspeed engine configuration    Returns:
        TransformerConfig 字典(不包含模型结构相关参数)
    """
​
    base_config = {
        # 并行配置
        "tensor_model_parallel_size": engine_config.tensor_model_parallel_size,
        "expert_model_parallel_size": engine_config.expert_model_parallel_size,
        "expert_tensor_parallel_size": engine_config.expert_tensor_parallel_size,
        "pipeline_model_parallel_size": engine_config.pipeline_model_parallel_size,
        "virtual_pipeline_model_parallel_size": engine_config.virtual_pipeline_model_parallel_size,
        "context_parallel_size": engine_config.context_parallel_size,
        "sequence_parallel": engine_config.sequence_parallel,
        "use_distributed_optimizer": engine_config.use_distributed_optimizer,
        "seed": engine_config.seed,
    }
​
    # 直接使用 mcore_kwargs 注入额外参数,不再按策略分支
    # 注意:当策略为 mindspeed_fsdp 时,fsdp_kwargs 不会被处理,可能需要后续扩展
    base_config.update(engine_config.mcore_kwargs)
    return base_config

评论区精华

Import 未及时更新导致的潜在 ImportError 正确性

gemini-code-assist 评论指出 __init__.py 中导入未更新为 MindSpeedMegatronEngineWithLMHead,可能导致 ImportError。

结论:代码在最终版本中已经更新了导入,评论基于旧 diff,实际已修复。 · 已解决

FSDP 策略配置处理缺失 设计

gemini-code-assist 评论指出 utils.py 中 get_base_mcore_config_from_engine_config 仅使用 mcore_kwargs,未考虑 fsdp_kwargs,当策略为 mindspeed_fsdp 时配置错误。

结论:当前实现未处理,属于已知待改进项。 · unresolved

风险与影响

  1. 配置向后兼容性:使用旧策略名 mindspeed_llm 或旧字段 llm_kwargs/mm_kwargs 的用户配置会失效,需要迁移。
  2. FSDP 策略未完全支持:虽然配置类新增了 fsdp_kwargs,但 get_base_mcore_config_from_engine_config 未针对 mindspeed_fsdp 做特殊处理,可能导致 FSDP 运行时配置错误。
  3. 测试覆盖不完整:新增的测试脚本仅覆盖单节点 16 卡场景,多节点或超长序列场景未验证。

用户:使用 MindSpeed 后端的用户需更新配置和启动脚本中的策略名及 kwargs;新用户可按新配置规范编写。
系统:Ascend NPU 上的 GRPO 训练流程需要验证是否稳定。
团队:后续若有新策略(如 mindspeed_fsdp)需补充对应配置逻辑。

配置向后不兼容 FSDP 策略未完全支持 测试覆盖有限

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论