MindSpore分布式算子开发指南:从mint.gather接口分析到通用实现流程

文档目标

本文档旨在为新入职员工提供MindSpore分布式算子开发的系统性指导,通过以mint.gather接口为具体案例,详细解析MindSpore的代码结构、接口与算子关系以及分布式算子实现机制,使新员工能够快速理解并上手开发分布式算子。


1. MindSpore接口体系与算子原语关系

1.1 核心用户接口类型

MindSpore为用户提供了多种层次的接口,这些接口最终都会映射到具体的算子原语(Primitive)执行。理解这些接口层次对于分布式算子开发至关重要。

1.1.1 NN接口

NN接口是面向神经网络层的高级封装接口,位于mindspore/nn/目录下。

特点:

  • 封装了一个或多个算子原语的组合调用
  • 提供状态管理(如权重参数、运行模式等)
  • 面向神经网络构建场景

示例:

from mindspore import nn

class MyNetwork(nn.Cell):
    def __init__(self):
        super().__init__()
        self.conv = nn.Conv2d(3, 64, kernel_size=3)  # 内部调用Conv2D算子
        self.dense = nn.Dense(64, 10)                 # 内部调用MatMul算子
    
    def construct(self, x):
        x = self.conv(x)
        x = self.dense(x)
        return x

NN接口与算子原语的关系:

nn.Conv2d (高级封装)
    ├── Conv2D算子原语
    ├── BiasAdd算子原语
    └── 可选的BatchNorm算子原语

1.1.2 functional接口

functional接口提供函数式编程风格的接口,位于mindspore/ops/目录下。

特点:

  • 直接映射到具体的算子原语
  • 无状态,纯函数式调用
  • 适合函数式编程风格

示例:

from mindspore import ops

x = ops.add(a, b)        # 直接调用Add算子原语
y = ops.matmul(m, n)     # 直接调用MatMul算子原语
z = ops.reshape(x, shape) # 直接调用Reshape算子原语

functional接口与算子原语的关系:

ops.add(x, y)
    └── Add算子原语 (直接映射)

ops.matmul(x, y)
    └── MatMul算子原语 (直接映射)

1.1.3 Tensor接口

Tensor接口是Tensor对象上的方法接口,部分实现会调用对应的算子原语。

特点:

  • 面向对象风格,操作更直观
  • 部分方法直接调用算子原语
  • 部分方法为Python层面实现

示例:

import mindspore
from mindspore import Tensor

x = Tensor([1, 2, 3, 4])
y = x.sum()              # 调用ReduceSum算子
z = x.reshape((2, 2))    # 调用Reshape算子
w = x.astype(mindspore.float32)  # 调用Cast算子

1.1.4 魔法方法

魔法方法是Python运算符重载方法,内部通常关联到相应的算子原语调用。

特点:

  • 提供直观的运算符语法
  • 底层调用对应的算子原语
  • 支持自动微分

示例:

import mindspore
from mindspore import Tensor

a = Tensor([1, 2, 3])
b = Tensor([4, 5, 6])

c = a + b    # __add__ -> Add算子
d = a - b    # __sub__ -> Sub算子
e = a * b    # __mul__ -> Mul算子
f = a @ b    # __matmul__ -> MatMul算子

1.2 mint接口说明

1.2.1 mint接口定位

mint接口是MindSpore提供的与PyTorch接口高度对齐的接口集合,位于mindspore/mint/目录下。mint模块不仅包含functional接口,还包含完整的神经网络层接口(NN接口)。

设计目标:

  • 降低PyTorch用户迁移到MindSpore的成本
  • 提供与PyTorch一致的接口体验
  • 简化模型迁移工作

mint模块目录结构:

mindspore/mint/
├── __init__.py              # 导出functional接口
├── nn/                      # 神经网络模块(NN接口)
│   ├── __init__.py
│   ├── functional.py        # nn.functional接口
│   └── layer/               # 神经网络层
│       ├── activation.py    # 激活函数层
│       ├── conv.py          # 卷积层
│       ├── normalization.py # 归一化层
│       ├── pooling.py       # 池化层
│       └── ...
├── optim/                   # 优化器模块
├── linalg/                  # 线性代数模块
├── special/                 # 特殊函数模块
└── distributed/             # 分布式通信模块

1.2.2 mint接口类型

mint模块提供两类主要接口:

1. functional接口(位于mindspore/mint/):

  • 数学运算:abs, sin, cos, matmul, bmm, mm等
  • 数组操作:cat, stack, reshape, transpose, permute等
  • 归约操作:mean, sum, max, min, argmax等

2. NN接口(位于mindspore/mint/nn/):

接口类型 包含接口
卷积层 Conv1d, Conv2d, Conv3d, ConvTranspose2d
归一化层 BatchNorm1d/2d/3d, LayerNorm, GroupNorm, SyncBatchNorm
激活函数 ReLU, SiLU, Sigmoid, GELU, Tanh, ELU, Mish等
池化层 MaxPool2d, AvgPool1d/2d/3d, AdaptiveAvgPool1d/2d/3d
全连接层 Linear
损失函数 CrossEntropyLoss, MSELoss, BCELoss, NLLLoss等
其他 Dropout, Embedding, Flatten, Upsample等

1.2.3 mint接口与标准接口的区别

特性 mint接口 标准接口
命名风格 PyTorch风格 MindSpore原生风格
参数顺序 与PyTorch一致 MindSpore自定义
默认值 与PyTorch一致 MindSpore自定义
接口范围 functional + NN完整接口 完整接口集

1.2.4 mint接口在MindSpore接口体系中的位置

用户代码
    │
    ├── mindspore.mint.gather()           ─┐
    │                                      │ 映射
    ├── mindspore.mint.nn.Conv2d()        ─┤
    │                                      │
    ├── mindspore.ops.gather_d()          ─┘
    │
    └── mindspore.ops.GatherD()  ────────────> Primitive算子原语
                                               │
                                               ▼
                                          底层算子实现

2. 算子代码自动生成流程分析

2.1 gen_ops.py执行与功能解析

2.1.1 脚本概述

gen_ops.py是MindSpore框架的算子代码自动生成工具,位于mindspore/python/mindspore/ops_generate/gen_ops.py。

核心功能:

  • 根据YAML配置文件自动生成算子相关的Python和C++代码文件
  • 实现声明式算子定义,减少重复代码编写
  • 保证代码一致性和可维护性

2.1.2 执行流程

def main():
    resource_mgr = prepare_resources()  # 1. 准备资源(加载YAML配置)

    for generator in module_generators:  # 2. 依次执行各模块生成器
        generator(resource_mgr)

    gen_utils.clear_obsolete_auto_gen_files()  # 3. 清理过期的自动生成文件

2.1.3 五大生成模块

序号 生成器 功能 输出路径
1 generate_ops_py_files 生成Python算子定义文件 mindspore/python/mindspore/ops/auto_generate/
2 generate_ops_def_files 生成C++算子定义文件 mindspore/ops/op_def/auto_generate/
3 gen_pyboost_code 生成PyBoost加速相关代码 mindspore/ccsrc/pynative/forward/pyboost/auto_generate/
4 generate_aclnn_reg_file 生成ACLNN内核注册代码 mindspore/ops/kernel/ascend/aclnn/
5 generate_api_files 生成API接口定义文件 mindspore/ops/api_def/

2.1.4 资源加载机制

def prepare_resources() -> ResourceManager:
    resource_mgr = ResourceManager()
    resource_mgr.register_resource(OpProtoLoader())           # 算子原型
    resource_mgr.register_resource(DeprecatedOpProtoLoader()) # 废弃算子
    resource_mgr.register_resource(FuncOpProtoLoader())       # 函数算子
    resource_mgr.register_resource(OpDocYamlLoader())         # 文档
    resource_mgr.register_resource(TensorMethodDocYamlLoader())
    resource_mgr.register_resource(MintFuncDocYamlLoader())
    resource_mgr.register_resource(OpApiProtoLoader(...))     # API原型
    return resource_mgr

2.2 YAML定义文件与代码生成

2.2.1 目录结构

mindspore/ops/op_def/
├── yaml/                          # 主要算子YAML定义目录
│   ├── doc/                       # 文档YAML定义
│   ├── communication/             # 通信算子YAML定义
│   ├── infer/                     # 推理相关算子
│   ├── gather_op.yaml             # gather算子定义
│   ├── gather_d_op.yaml           # gather_d算子定义
│   └── ... (约400+个算子定义文件)
├── deprecated/                    # 已废弃的算子YAML定义
├── func_op/                       # 函数式算子YAML定义
├── ops_def.cc                     # 算子定义C++源文件
└── ops_def.h                      # 算子定义头文件

2.2.2 YAML文件结构解析

以gather_d_op.yaml为例:

#operator gather_d
gather_d:
  args:                          # 输入参数定义
    x:                           # 参数名
      dtype: tensor              # 必填,数据类型
    dim:
      dtype: int
      type_cast: tensor          # 支持隐式类型转换
    index:
      dtype: tensor
  returns:                       # 输出定义
    output:
      dtype: tensor
  dispatch:                      # PyBoost分发配置
      enable: True               # 启用PyBoost代码生成

YAML字段说明:

字段 说明 示例
args 输入参数定义 x, dim, index
dtype 数据类型 tensor, int, float, bool
default 默认值 default: 0
type_cast 类型转换支持 type_cast: tensor
prim_init 是否作为Primitive的__init__参数 prim_init: True
returns 输出定义 output
dispatch 分发配置 enable: True
function 函数配置 disable: True
class 类配置 name: NewName

2.2.3 从YAML到代码生成的映射关系

YAML定义文件 (gather_d_op.yaml)
        │
        ▼
┌───────────────────────────┐
│   OpProtoLoader.load()    │
│   解析YAML为OpProto对象    │
└───────────────────────────┘
        │
        ▼
┌───────────────────────────┐
│   各类Generator处理        │
│   - OpsDefCcGenerator     │──► C++算子定义 (.cc/.h)
│   - OpsDefPyGenerator     │──► Python算子定义 (.py)
│   - PyBoostGenerator      │──► PyBoost代码
│   - ApiGenerator          │──► API文档
└───────────────────────────┘

命名转换规则:

  • gather_d → 函数名: gather_d,类名: GatherD
  • gather_nd → 函数名: gather_nd,类名: GatherNd

3. mint.gather接口实现分析

3.1 接口映射关系追踪

3.1.1 mint.gather接口定义位置

文件路径: mindspore/python/mindspore/mint/__init__.py

# 第21行
from mindspore.ops.function.array_func import gather_ext as gather

3.1.2 gather_ext函数定义

文件路径: mindspore/python/mindspore/ops/function/array_func.py

def gather_ext(input, dim, index):
    r"""
    Gather data from a tensor by indices.

    .. math::
        output[(i_0, i_1, ..., i_{dim}, i_{dim+1}, ..., i_n)] =
        input[(i_0, i_1, ..., index[(i_0, i_1, ..., i_{dim}, i_{dim+1}, ..., i_n)], i_{dim+1}, ..., i_n)]
    """
    return gather_d_op(input, dim, index)

3.1.3 底层算子原语

文件路径: mindspore/python/mindspore/ops/auto_generate/gen_ops_prim.py

class GatherD(Primitive):
    r"""
    .. code-block::

        prim = ops.GatherD()
        out = prim(x, dim, index)

    is equivalent to

    .. code-block::

        ops.gather_d(x, dim, index)
    """
    @prim_arg_register
    def __init__(self):
        pass

    def __call__(self, x, dim, index):
        res = pyboost_gather_d(self, [x, dim, index])
        if not jit_context():
            return res
        if jit_context().compiled:
            return jit_context().default_output()
        return jit_context().run_op(self, res, x, dim, index)

gather_d_op = GatherD()

3.1.4 接口映射关系总结

mint.gather
    │
    │ (导入映射: from ... import gather_ext as gather)
    ▼
mindspore.ops.function.array_func.gather_ext
    │
    │ (函数调用: return gather_d_op(...))
    ▼
gather_d_op (GatherD算子实例)
    │
    │ (算子调用: pyboost_gather_d)
    ▼
pyboost_gather_d (底层实现)

结论:

  • mint.gather 不是直接定义的,而是通过映射到其他ops接口实现
  • 映射链路:mint.gather → gather_ext → gather_d_op (GatherD算子)
  • GatherD是一个自动生成的Primitive算子类

3.2 底层算子原语分析

3.2.1 算子原语名称

对应的Primitive算子原语名称为GatherD,该算子通过YAML配置自动生成。

3.2.2 算子原语定义

YAML定义 (gather_d_op.yaml):

gather_d:
  args:
    x:
      dtype: tensor
    dim:
      dtype: int
      type_cast: tensor
    index:
      dtype: tensor
  returns:
    output:
      dtype: tensor
  dispatch:
      enable: True

3.2.3 算子原语与用户接口的关系

┌─────────────────────────────────────────────────────────────┐
│                      用户调用层                              │
│  mint.gather(input, dim, index)                            │
│  ops.gather_d(input, dim, index)                           │
│  ops.GatherD()(input, dim, index)                          │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    Python算子层                             │
│  class GatherD(Primitive):                                 │
│      def __call__(self, x, dim, index):                    │
│          return pyboost_gather_d(self, [x, dim, index])    │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    PyBoost加速层                            │
│  pyboost_gather_d()                                        │
│  - 参数校验                                                 │
│  - 设备分发                                                 │
│  - 内核调用                                                 │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│                    底层内核实现                             │
│  Ascend: ACLNN接口                                          │
│  GPU: CUDA内核                                              │
│  CPU: C++实现                                               │
└─────────────────────────────────────────────────────────────┘

4. MindSpore分布式算子核心机制详解

4.1 Info类模式概述

MindSpore的分布式算子实现采用Info类模式,每个算子都有对应的Info类负责:

  1. 布局推断(Layout Inference):推断输入/输出的分布式切分信息
  2. 策略推断(Strategy Inference):推断有效的并行策略
  3. 图替换(Graph Replacement):将原始节点替换为包含通信算子的子图(如需要)

Info类位置:

mindspore/ccsrc/frontend/parallel/ops_info/
├── operator_info.h           # 基类定义
├── matmul_info.cc            # MatMul分布式实现
├── add_info.cc               # Add分布式实现
├── gatherd_info.cc           # GatherD分布式实现
└── ...

4.2 Info类层次结构

4.2.1 基类:OperatorInfo

所有算子Info类都继承自OperatorInfo:

class OperatorInfo {
 public:
  // 分布式推断核心方法
  virtual Status Infer(const OperatorParams &inputs, const OperatorParams &outputs) = 0;
  virtual Status InferTensorInfo() = 0;          // Layout流
  virtual Status InferTensorMap() = 0;           // Strategy流
  virtual Status InferDevMatrixShape() = 0;
  virtual Status InferMirrorOps() = 0;

  // 图替换方法
  virtual Status ReplaceNodeInputOrAttrs() override;  // 输入替换
  virtual Status replace_graph(const CNodePtr &cnode) override;  // 子图替换

  // 策略生成
  virtual std::vector<StrategyPtr> GenerateStrategies(int32_t stage_id) = 0;
};

4.2.2 中间基类

部分算子有更具体的基类:

ArithmeticInfo(二元算子基类):

class ArithmeticInfo : public OperatorInfo {
 protected:
  // 二元算子通用逻辑
  virtual Status InferTensorInfo() override;
  virtual Status InferTensorMap() override;
};

// 继承此基类的算子
class AddInfo : public ArithmeticInfo {};
class SubInfo : public ArithmeticInfo {};
class MulInfo : public ArithmeticInfo {};

MatMulInfoBase(矩阵乘法基类):

class MatMulInfoBase : public OperatorInfo {
 protected:
  virtual Status InferMatrixDim() = 0;
  virtual Status InferBiasTensorInfo() = 0;
};

class MatMulInfo : public MatMulInfoBase {};
class BatchMatMulInfo : public MatMulInfoBase {};

4.2.3 Info类层次图

OperatorInfo (基类)
├── ArithmeticInfo (二元算子)
│   ├── AddInfo
│   ├── SubInfo
│   ├── MulInfo
│   └── DivInfo
├── MatMulInfoBase (矩阵乘法)
│   ├── MatMulInfo
│   └── BatchMatMulInfo
├── ReduceInfo (归约算子)
│   └── ReduceSumInfo
├── GatherDInfo (Gather算子)
└── ... 其他基类

4.3 两种推断流程(核心)

MindSpore分布式算子有两种推断流程,这是理解分布式算子实现的关键:

4.3.1 Layout流(推荐)

特点:

  • 使用TensorInfo和TensorLayout作为抽象
  • 推断更灵活,支持复杂切分模式
  • 适用于所有算子

核心方法:

方法 描述 作用
InferTensorInfo() 推断输入/输出TensorInfo Layout流的核心实现
InferOutputTensorInfo() Layout流中的输出推断 推断输出布局
InferInputTensorInfo() Layout流中的输入推断 输入验证

TensorInfo结构:

class TensorInfo {
public:
  TensorLayout tensor_layout_;  // 包含shape, tensor_map, dev_matrix_shape

  TensorLayout GetTensorLayout() const;
  Shape GetShape() const;              // 张量的物理形状
  TensorMap GetTensorMap() const;      // 切分策略(-1表示不切分)
  DevMatrixShape GetDevMatrixShape() const;  // 设备矩阵形状
};

4.3.2 Strategy流(传统)

特点:

  • 直接推断tensor_map和dev_matrix_shape
  • 逻辑简单,但灵活性有限
  • 多用于遗留算子

核心方法:

方法 描述 作用
InferTensorMap() 推断输出tensor_map 返回tensor_map
InferDevMatrixShape() 推断设备矩阵shape 确定device_mesh
GenerateStrategies() 生成所有有效并行策略 策略枚举

4.3.3 两种流程对比

维度 Layout流 Strategy流
抽象层次 更高(TensorInfo/TensorLayout) 较低(直接操作tensor_map)
灵活性 更高,支持复杂切分模式 较低
适用场景 所有算子,特别是复杂算子 简单算子,遗留算子
推荐程度 ✅ 推荐 ⚠️ 传统方式

4.4 图替换机制(核心)

4.4.1 为什么需要图替换

当算子在分布式环境下需要额外的通信操作时,需要将原始节点替换为包含通信算子的子图。

常见场景:

  • Reduce操作后需要聚合结果(如ReduceSum在特定切分下)
  • 需要将局部结果广播到所有设备
  • 需要在特定维度上通信(如AllReduce、AllGather)

4.4.2 图替换方法

方法 描述 调用时机
ReplaceNodeInputOrAttrs() 替换输入张量或修改节点属性 编译优化阶段
replace_graph() 将原始节点替换为通信算子子图 编译优化阶段

4.4.3 通信算子类型

通信算子 用途 MindSpore对应 使用场景
AllReduce 归约(Sum/Max/Min/Prod) ReplaceNode构造AllReduce 需要全局归约时
AllGather 收集分片 ReplaceNode构造AllGather 需要收集所有分片时
ReduceScatter 归约后分发 ReplaceNode构造ReduceScatter 归约后需要切分输出时

4.5 输入验证机制

4.5.1 为什么需要输入验证

分布式算子必须验证输入Layout的兼容性,否则可能导致:

  • 形状不匹配
  • 切分策略冲突
  • 不必要或错误的通信操作

4.5.2 验证逻辑位置

方法 Layout流 Strategy流
输入验证 InferOutputTensorInfo()开头 InferTensorMap()开头
输出推断 InferOutputTensorInfo()后半部分 InferTensorMap()后半部分

4.6 典型算子分析案例

4.6.1 案例1:MatMul(矩阵乘法)

算子基本信息:

  • 算子名称:MatMul
  • Info类:MatMulInfo
  • 基类继承:MatMulInfo → MatMulInfoBase → OperatorInfo

文件位置:mindspore/ccsrc/frontend/parallel/ops_info/matmul_info.cc

1. 输入验证逻辑:

参考源:InferMatrixDim(),文件位置:matmul_info.cc

验证规则:

  • 输入x和w对应维度必须兼容(矩阵乘法规则)
  • 考虑transpose_a和transpose_b属性

2. Layout推断逻辑:

参考源:InferOutputTensorInfo(),文件位置:matmul_info.cc

推断规则(简化):

output_map[i] = x_map[i]  (如果x在第i维切分)
output_map[j] = w_map[j]  (如果w在第j维切分)

约束条件:
x在第k维的切分必须与w在第k维的切分匹配
(因为这两个维度需要做矩阵乘法内积累加)

3. 图替换逻辑:

参考源:replace_graph(),文件位置:matmul_info.cc

通信算子:

  • 场景:当两个输入都在公共维度上切分时
  • 算子:AllReduce(op=SUM)
  • 原因:切分后的乘积需要在所有设备上求和

分布式MatMul计算流程:

场景:x形状[1024, 4096],w形状[4096, 512]
切分策略:x在dim=1切分,w在dim=0切分(都切4096维度)

┌─────────────────────────────────────────────────────────────┐
│ Rank 0: x[:, 0:2048], w[0:2048, :]                          │
│ Rank 1: x[:, 2048:4096], w[2048:4096, :]                    │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│ 每个Rank执行:                                                │
│   local_result = MatMul(x_local, w_local)  # [1024, 512]    │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│ AllReduce(SUM) 聚合所有Rank的结果                           │
│   output = AllReduce(local_result, SUM)                     │
└─────────────────────────────────────────────────────────────┘

4.6.2 案例2:Add(逐元素加法)

算子基本信息:

  • 算子名称:Add
  • Info类:AddInfo
  • 基类继承:AddInfo → ArithmeticInfo → OperatorInfo

文件位置:mindspore/ccsrc/frontend/parallel/ops_info/add_info.cc

ArithmeticInfo(二元算子基类):

class ArithmeticInfo : public OperatorInfo {
 public:
  // 二元算子通用实现
  Status InferTensorInfo() override;

 protected:
  // 检查两个输入是否有相同Layout
  Status CheckInputsTensorInfo();
};

1. 输入验证逻辑:

参考源:ArithmeticInfo::CheckInputsTensorInfo()

验证规则:

  • 两个输入必须有相同的Layout
  • 输出Layout与输入Layout相同
  • 支持广播(当形状维度不足时自动扩展)

2. Layout推断逻辑:

参考源:ArithmeticInfo::InferTensorInfo()

推断规则:

output_tensor_map = input_tensor_map
output_shape = broadcast(x_shape, y_shape)

3. 图替换逻辑:

Add算子通常不需要图替换,因为:

  • 逐元素操作不需要额外通信
  • 两个输入在相同设备上操作

4.6.3 案例3:GatherD(索引收集)

算子基本信息:

  • 算子名称:GatherD
  • Info类:GatherDInfo
  • 基类继承:GatherDInfo → OperatorInfo

文件位置:mindspore/ccsrc/frontend/parallel/ops_info/gatherd_info.cc

1. GetAttrs实现 - 解析算子属性:

Status GatherDInfo::GetAttrs() {
  if (input_value_.size() != 3) {
    MS_LOG(ERROR) << name_ << ": Invalid input_value's size";
    return FAILED;
  }

  if (!input_value_[1]->isa<Int64Imm>()) {
    MS_LOG(ERROR) << name_ << ": The value of dim is not int";
    return FAILED;
  }

  int64_t dim = GetValue<int64_t>(input_value_[1]);
  int64_t input_dim = SizeToLong(inputs_shape_[0].size());
  
  if ((dim > (input_dim - 1)) || (dim < -input_dim)) {
    MS_LOG(ERROR) << name_ << ": The dim is out of range";
    return FAILED;
  }

  if (dim < 0) {
    dim += input_dim;
  }

  dim_ = LongToSize(dim);
  return SUCCESS;
}

2. CheckStrategy实现 - 检查切分策略有效性:

Status GatherDInfo::CheckStrategy(const StrategyPtr &strategy) {
  MS_EXCEPTION_IF_NULL(strategy);
  
  if (CheckStrategyValue(strategy, inputs_shape_) != SUCCESS) {
    return FAILED;
  }

  std::vector<Dimensions> stra = strategy->GetInputDim();
  
  if (stra.size() != 2) {
    MS_LOG(ERROR) << name_ << ": The size of strategy must be 2";
    return FAILED;
  }

  const Dimensions &input_strategy = stra[0];
  const Dimensions &index_strategy = stra[1];
  
  if (input_strategy.size() != index_strategy.size()) {
    MS_LOG(ERROR) << name_ << ": Dimension of X and Index strategy should be same";
    return FAILED;
  }

  for (size_t i = 0; i < input_strategy.size(); i++) {
    if (i != dim_) {
      // 非dim维度:input和index切分策略必须相同
      if (input_strategy[i] != index_strategy[i]) {
        MS_LOG(ERROR) << name_ << ": Dimension " << i << " of X and Index should be same";
        return FAILED;
      }
    } else {
      // dim维度:index不能切分
      if (index_strategy[i] != 1) {
        MS_LOG(ERROR) << name_ << ": Index dimension dim can not be splited.";
        return FAILED;
      }
    }
  }

  axis_shard_ = (input_strategy[dim_] != 1);
  return SUCCESS;
}

3. InferTensorMap实现 - 推断张量映射:

Status GatherDInfo::InferTensorMap() {
  // 构建输入张量映射
  Shape input_tensor_map;
  size_t size = inputs_shape_[0].size();
  for (size_t i = 0; i < size; ++i) {
    input_tensor_map.push_back(SizeToLong(size - i - 1));
  }

  // 构建index张量映射(dim维度不映射)
  Shape index_tensor_map = input_tensor_map;
  index_tensor_map[dim_] = -1;  // -1表示该维度不切分

  inputs_tensor_map_.push_back(input_tensor_map);   // input
  inputs_tensor_map_.push_back(index_tensor_map);   // index
  outputs_tensor_map_.push_back(index_tensor_map);  // output
  return SUCCESS;
}

张量映射说明:

  • tensor_map = [1, 0, -1] 表示:
    • 张量第0维映射到设备第1维
    • 张量第1维映射到设备第0维
    • 张量第2维不切分(-1)

4. replace_graph实现 - 生成替换子图:

当在dim维度切分时,需要生成替换子图:

ReplaceGraphPtr GatherDInfo::replace_graph(const CNodePtr &cnode) {
  if (!axis_shard_) {
    return replace_graph_;
  }

  GenerateGraph gen_g = GenerateGraph(attrs_);
  if (gen_g.Init(cnode) != SUCCESS) {
    MS_LOG_WITH_NODE(EXCEPTION, cnode) << name_ << "GenerateGraph Init failed";
  }

  if (InferBias() != SUCCESS) {
    MS_LOG_WITH_NODE(EXCEPTION, cnode) << name_ << ": Infer Bias failed.";
  }

  // 分布式GatherD实现逻辑:
  // 1. 将x按dim维度切分成N段,每个rank持有一段
  // 2. 每个rank持有完整的index
  // 3. 计算局部索引:sub = index - bias
  // 4. 处理越界索引:relu + minimum
  // 5. 执行局部gatherd
  // 6. 通过AllReduce聚合结果

  auto sub = gen_g.PushBack({gen_g.NewOpInst(SUB), gen_g.virtual_input_node(), CreateInt32Tensor(bias_)});
  auto relu = gen_g.PushBack({gen_g.NewOpInst(RELU), sub});
  auto minimum = gen_g.PushBack({gen_g.NewOpInst(MINIMUM), relu, CreateInt32Tensor(slice_size_ - 1)});
  auto equal = gen_g.PushBack({gen_g.NewOpInst(EQUAL), sub, minimum});
  auto gatherd = gen_g.PushBack({gen_g.NewOpInst(GATHERD), gen_g.virtual_input_node(), CreatInt64Imm(dim_), minimum});
  auto dtype = gen_g.PushBack({gen_g.NewOpInst(DTYPE), gatherd});
  auto dtype_id = gen_g.PushBack({gen_g.NewOpInst(DTYPETOENUM), CreateStringImm("DtypeToEnum"), 
                                   CreateStringImm("dtype"), dtype});
  auto cast = gen_g.PushBack({gen_g.NewOpInst(CAST), equal, dtype_id});
  auto mul = gen_g.PushBack({gen_g.NewOpInst(MUL), gatherd, cast});

  if (InferGroup() != SUCCESS) {
    MS_LOG_WITH_NODE(EXCEPTION, cnode) << name_ << ": Infer Group failed.";
  }
  
  // 添加AllReduce通信算子
  Attr attr_op = std::make_pair(OP, MakeValue(REDUCE_OP_SUM));
  Attr attr_group = std::make_pair(GROUP, MakeValue(group_.name()));
  OperatorAttrs attrs = {attr_op, attr_group};
  AnfNodePtr reduce_op = gen_g.PushBack({gen_g.NewOpInst(ALL_REDUCE, attrs), mul});
  
  std::vector<std::pair<AnfNodePtr, int64_t>> input_nodes = {
    std::make_pair(sub, 3), 
    std::make_pair(gatherd, 1)
  };
  replace_graph_ = std::make_shared<std::pair<std::vector<std::pair<AnfNodePtr, int64_t>>, AnfNodePtr>>(
    std::make_pair(input_nodes, reduce_op));

  return replace_graph_;
}

分布式GatherD计算流程图:

原始计算: output = GatherD(x, dim, index)

当dim维度切分时:
┌─────────────────────────────────────────────────────────────┐
│ Rank 0: x_slice[0], index (完整)                            │
│ Rank 1: x_slice[1], index (完整)                            │
│ Rank 2: x_slice[2], index (完整)                            │
│ ...                                                         │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│ 每个Rank执行:                                                │
│   local_index = max(0, min(index - bias, slice_size - 1))  │
│   local_result = GatherD(x_slice, dim, local_index)        │
│   mask = (index >= bias) & (index < bias + slice_size)     │
│   result = local_result * mask                              │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│ AllReduce(SUM) 聚合所有Rank的结果                           │
└─────────────────────────────────────────────────────────────┘

4.7 常见算子模式总结

4.7.1 逐元素二元算子(Add, Sub, Mul, Div)

特点:

  • 两个输入必须有相同的Layout
  • 输出Layout与输入Layout相同
  • 通常不需要图替换

推断逻辑:

input1_layout == input2_layout
output_layout = input1_layout

4.7.2 矩阵乘法算子(MatMul, BatchMatMul)

特点:

  • 支持不同切分策略(在不同矩阵维度上)
  • 输出Layout从输入推断
  • 可能需要AllReduce(如果需要求和)

推断逻辑:

output_map[i] = input_map1[i]  (如果input_map1[i] != input_map2[k])
output_map[j] = input_map2[j]  (其他情况)

4.7.3 归约算子(ReduceSum, ReduceMean)

特点:

  • 在指定维度上归约
  • 输出tensor_map在归约维度上为-1(不切分)
  • 可能需要AllReduce / ReduceScatter

推断逻辑:

output_map[reduce_dim] = -1
output_map[other_dim] = input_map[other_dim]

4.8 分析模式总结

4.8.1 分析YAML定义

  • 识别输入/输出参数
  • 识别属性参数
  • 理解算子的基本语义

4.8.2 定位Info类

# 查找Info类文件
find mindspore/ccsrc/frontend/parallel/ops_info/ -name "*{op_name}_info.cc"

4.8.3 分析Info类结构

  • 继承关系(基类是什么)
  • 重写了哪些方法
  • 实现了哪些分布式逻辑

4.8.4 提取参考逻辑

步骤 目标 参考方法
1 输入验证逻辑 CheckInputsTensorInfo() / 输入验证部分
2 Layout推断逻辑 InferTensorInfo() / InferOutputTensorInfo() / InferTensorMap()
3 图替换逻辑 replace_graph() / ReplaceNodeInputOrAttrs()

5. 分布式算子实现参考

5.1 关键目录说明

目录 说明
mindspore/ops/op_def/yaml/ 算子YAML定义
mindspore/ccsrc/frontend/parallel/ops_info/ 分布式算子实现
mindspore/ccsrc/frontend/parallel/tensor_layout/ 张量布局相关
tests/ut/cpp/parallel/ 分布式算子单元测试

5.2 必要的前置知识

  1. C++编程:熟悉面向对象编程、智能指针、模板等
  2. 分布式计算基础:数据并行、模型并行、流水线并行概念
  3. 通信原语:AllReduce、AllGather、ReduceScatter等
  4. MindSpore框架:算子原语、计算图、自动微分

5.3 开发规范与最佳实践

5.3.1 代码风格与命名规范

命名规范:

  • 类名:大驼峰命名,如GatherDInfo
  • 函数名:大驼峰命名,如InferTensorMap
  • 变量名:下划线命名,如input_tensor_map
  • 成员变量:下划线结尾,如dim_

代码风格:

  • 遵循Google C++代码规范
  • 使用智能指针管理内存
  • 添加必要的注释

5.3.2 错误处理与日志打印

Status XxxInfo::CheckStrategy(const StrategyPtr &strategy) {
  MS_EXCEPTION_IF_NULL(strategy);  // 空指针检查
  
  if (CheckStrategyValue(strategy, inputs_shape_) != SUCCESS) {
    MS_LOG(ERROR) << name_ << ": Invalid strategy";  // 错误日志
    return FAILED;
  }
  
  MS_LOG(INFO) << name_ << ": Strategy check passed";  // 信息日志
  return SUCCESS;
}

5.3.3 测试用例编写规范

  1. 覆盖所有策略组合
  2. 测试边界条件
  3. 验证通信正确性
  4. 检查梯度计算

5.3.4 性能与内存优化建议

  1. 避免不必要的张量拷贝
  2. 使用引用传递
  3. 合理设置通信组
  4. 利用张量重分布机制

6. 总结与参考资源

6.1 本文档核心内容回顾

  1. 接口体系:理解MindSpore的NN接口、functional接口、Tensor接口、mint接口与算子原语的关系
  2. 代码生成:掌握YAML定义到Python/C++代码的自动生成流程
  3. mint.gather案例:完整追踪从用户接口到底层算子的调用链路
  4. 分布式实现:深入分析GatherDInfo的分布式策略实现机制
  5. 开发流程:系统掌握分布式算子开发的完整流程

6.2 分布式算子开发常用资源与文档链接

官方文档:

代码参考:

  • 分布式算子基类:mindspore/ccsrc/frontend/parallel/ops_info/operator_info.h
  • 策略定义:mindspore/ccsrc/frontend/parallel/strategy.h
  • 张量布局:mindspore/ccsrc/frontend/parallel/tensor_layout/tensor_layout.h

6.3 常见问题与解决方案参考

问题 解决方案
策略检查失败 检查CheckStrategy实现,确保切分策略符合算子语义
通信组创建失败 检查InferGroup实现,确保设备矩阵和张量映射正确
梯度计算错误 检查InferMirrorOps实现,确保镜像算子正确创建
性能不达预期 分析通信代价,考虑使用ReduceScatter等优化

6.4 进一步学习的建议与路径

  1. 入门阶段:

    • 阅读现有分布式算子实现(如MatMul、LayerNorm)
    • 运行单元测试,理解测试框架
  2. 进阶阶段:

    • 实现一个简单的分布式算子(如ElementWise操作)
    • 学习代价模型和策略选择机制
  3. 高级阶段:

    • 实现复杂的分布式算子(如Attention、Convolution)
    • 参与自动并行优化

附录:关键代码文件索引

文件 路径 说明
mint接口定义 mindspore/python/mindspore/mint/__init__.py mint模块入口
gather_ext函数 mindspore/python/mindspore/ops/function/array_func.py gather函数实现
GatherD算子 mindspore/python/mindspore/ops/auto_generate/gen_ops_prim.py 自动生成的算子原语
YAML定义 mindspore/ops/op_def/yaml/gather_d_op.yaml 算子YAML配置
代码生成脚本 mindspore/python/mindspore/ops_generate/gen_ops.py 代码生成主脚本
分布式算子基类 mindspore/ccsrc/frontend/parallel/ops_info/operator_info.h OperatorInfo定义
GatherDInfo头文件 mindspore/ccsrc/frontend/parallel/ops_info/gatherd_info.h GatherD分布式算子声明
GatherDInfo实现 mindspore/ccsrc/frontend/parallel/ops_info/gatherd_info.cc GatherD分布式算子实现
策略类 mindspore/ccsrc/frontend/parallel/strategy.h Strategy类定义
张量布局 mindspore/ccsrc/frontend/parallel/tensor_layout/tensor_layout.h TensorLayout类定义