| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 |
LogSoftmaxGrad
产品支持情况
| 产品 | 是否支持 |
|---|---|
| Atlas A2 训练系列产品 | √ |
| Atlas 800I A2 推理产品 | √ |
| Atlas 200I/500 A2 推理产品 | ✗ |
功能说明
-
接口功能:完成 LogSoftmax 的反向传播,计算 LogSoftmax 正向输入的梯度(gradInput)。
-
计算公式:
其中 outputoutput 为 LogSoftmax 正向输出(即 log_softmax(x)\text{log\_softmax}(x)),gradOutputgradOutput 为上游梯度:
gradInput=gradOutput−exp(output)⋅reduce_sum(gradOutput,dim)gradInput = gradOutput - \exp(output) \cdot \text{reduce\_sum}(gradOutput, dim)
由于 exp(output)\exp(output) 即为 softmax 概率分布,上述计算等价于:
gradInput=gradOutput−softmax(x)⋅reduce_sum(gradOutput,dim)gradInput = gradOutput - softmax(x) \cdot \text{reduce\_sum}(gradOutput, dim)
-
支持的输入/输出数据类型:FLOAT(float32)、FLOAT16(float16)、BFLOAT16(bfloat16),且 gradOutput、output 与 out 三者的数据类型与 shape 必须一致。
参数说明
| 参数名 | 输入/输出 | 数据类型 | 数据格式 | 维度(shape) | 描述 |
|---|---|---|---|---|---|
| gradOutput | 输入 | FLOAT、FLOAT16、BFLOAT16 | ND | 0-8 | LogSoftmax 正向输出的梯度,公式中的 gradOutput,支持空 Tensor。 |
| output | 输入 | FLOAT、FLOAT16、BFLOAT16 | ND | 0-8 | LogSoftmax 正向输出,公式中的 output,支持空 Tensor。 |
| dim | 输入 | INT64 | - | - | 指定进行 reduce 的维度,取值范围为 [−dimNum,dimNum−1][-dimNum, dimNum-1]。 |
| out | 输出 | FLOAT、FLOAT16、BFLOAT16 | ND | 0-8 | 反向计算的输出,即 LogSoftmax 正向输入的梯度 gradInput,支持空 Tensor。 |
调用说明
本算子提供两段式 aclnn 接口 aclnnLogSoftmaxBackwardGetWorkspaceSize 与 aclnnLogSoftmaxBackward,完整可编译的调用示例见 test_aclnn_log_softmax_grad.cpp。
// 第一段:获取 workspace 大小与执行器
uint64_t workspaceSize = 0;
aclOpExecutor* executor = nullptr;
aclnnStatus ret = aclnnLogSoftmaxBackwardGetWorkspaceSize(gradOutput, output, dim, out,
&workspaceSize, &executor);
// 申请 workspace 并执行
void* workspace = nullptr;
aclrtMalloc(&workspace, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
ret = aclnnLogSoftmaxBackward(workspace, workspaceSize, executor, stream);
约束说明
- 输入 gradOutput、output 与输出 out 的 shape 必须一致,不支持广播。
- 指定维度 dim 需在 gradOutput 的维度范围内,范围 [−dimNum,dimNum−1][-dimNum, dimNum-1]。
- 支持的数据类型为 FLOAT、FLOAT16、BFLOAT16;当硬件不支持 bfloat16 向 float32 的 Cast 时,使用 BFLOAT16 会报错。
- 输入 tensor 的维度数不能超过 8;当 dim 为多个轴时,reduce 轴必须连续(如 [2,3,4] 合法,[2,4] 不合法)。
详细设计
host 侧设计
tiling 策略:
在 tiling 函数中会做参数校验,保证输入输出 shape 完全相同,并且 axis 里面的 reduce 轴都是连续的。然后根据输入属性 axis 对当前 shape 进行合轴操作,这样任意 shape 合轴完成后,就只剩三个轴,形状如下:
[mergedDim0, mergedDim1, mergedDim2]
- 如果 axis 中指定的最小 reduce 轴是 0,说明 reduce 轴之前没有维度,那么
mergedDim0 = 1; - 如果 axis 中指定的最大 reduce 轴是最后一个轴(即
dimNum-1),说明 reduce 轴之后没有维度,那么mergedDim2 = 1。
通过平台信息动态获取 UbSize、CoreNum 与 UB block 大小(不再硬编码 BLOCK_SIZE),以保证不同芯片平台的兼容性。
分核策略:
- 根据 mergedDim0 进行分核,优先使用满核原则;如果核间能均分,可视作无大小核区分,大核小核数据块一致;如果核间不能均分,需要将余出的数据块分配到前几个核上;如果
mergedDim0 < CoreNum,则设置实际使用的核数为mergedDim0。 - 数据分块和内存优化策略:充分使用 UB 空间。算子总共是两个输入和一个输出,input_dy 需要进行累加和 reduce 操作,因此给它开启 double buffer,分配 2 块 UB 空间,给 reduce 操作留一块空间,input_x 和 output_z 各 1 块空间,总共 5 块,将 UB 均分为 5 份,并对齐 BLOCK_SIZE,计算出每个 UB 块的数据数量。对于 bfloat16 和 half 类型,需要在计算之前做 cast 操作,这里将搬入的 UB 空间和 Cast 结果的 UB 空间复用:搬入时将数据放到 UB 块的后半部分,再 cast 到整个 UB 块。
- tilingkey 规划策略:
- 如果
mergedDim1值为 1,即不需要进行 reduce 操作,tilingkey 为 0; - 其他情况,tilingkey 为 1。
- 如果
数据检测:
对不支持 AscendC::Cast() bfloat16 向 float32 转换的硬件(即非 Atlas A2 系列),在参数校验阶段直接失败,并打印报错提示。
kernel 侧设计
进行 Init 和 Process 两个阶段,其中 Process 包括数据搬入(CopyIn)、计算(Compute)、搬出(CopyOut)三个阶段。
- 根据不同的 tilingkey 实例化不同的核函数对象。
- 根据 golden 实现,所有数据都需要 cast 为 float32 计算;如果当前数据类型不是 float32,则搬入数据后就进行 cast 操作,并且复用空间。
- 根据 mergedDim0 计算当前核需要处理哪些数据,计算出 start 和 end,开启第一层循环。
- 根据 mergedDim1 和 dim2Tile 确定第二层循环的循环次数。
- tilingKey0(不需要 reduce)的流程如下,公式化简得:
output_z = (input_dy - 1) * exp(input_x)。 - tilingKey1(需要 reduce)的流程按 REDUCE_TAIL / REDUCE_MID 两种模式分别处理。
贡献说明
| 贡献者 | 贡献方 | 贡献算子 | 贡献时间 | 贡献内容 |
|---|---|---|---|---|
| DreamOfAnts | 个人开发者 | LogSoftmaxGrad | 2026 | LogSoftmaxGrad 算子适配开源仓 |