Merged
docs: 修复AIDD文档质量扫描报告中的语义与示例问题 #163
docs: 修复AIDD文档质量扫描报告中的语义与示例问题 #163
Merged
xmzAdd on Sep 14
Total: 13 files changed+113-92
@@ -15,7 +15,7 @@ y = (x * rstd) * gamma + beta
15## 函数签名15## 函数签名
16 16 
17```python17```python
18-def add_rms_norm_bias(18+def npu_add_rms_norm_bias(
19 x1: torch.Tensor,19 x1: torch.Tensor,
20 x2: torch.Tensor,20 x2: torch.Tensor,
21 gamma: torch.Tensor,21 gamma: torch.Tensor,
@@ -109,9 +109,11 @@ import torch
109from mindspeed_ops.api.aclnn.npu_add_rms_norm_bias import npu_add_rms_norm_bias109from mindspeed_ops.api.aclnn.npu_add_rms_norm_bias import npu_add_rms_norm_bias
110 110 
111# 示例 1:基本使用(无 beta)111# 示例 1:基本使用(无 beta)
112-x1 = torch.randn(4, 256, dtype=torch.float16)112+dtype = torch.float16
113-x2 = torch.randn(4, 256, dtype=torch.float16)113+device = torch.device("npu")
114-gamma = torch.randn(256, dtype=torch.float16)114+x1 = torch.randn(4, 256, dtype=dtype).to(device)
115+x2 = torch.randn(4, 256, dtype=dtype).to(device)
116+gamma = torch.randn(256, dtype=dtype).to(device)
115 117 
116y, rstd, x = npu_add_rms_norm_bias(x1, x2, gamma)118y, rstd, x = npu_add_rms_norm_bias(x1, x2, gamma)
117 119 
@@ -122,10 +124,12 @@ print(f"x shape: {x.shape}, dtype: {x.dtype}")
122 124 
123```python125```python
124# 示例 2:带 beta 偏置126# 示例 2:带 beta 偏置
125-x1 = torch.randn(2, 8, 512, dtype=torch.float32)127+dtype = torch.float32
126-x2 = torch.randn(2, 8, 512, dtype=torch.float32)128+device = torch.device("npu")
127-gamma = torch.randn(512, dtype=torch.float32)129+x1 = torch.randn(2, 8, 512, dtype=dtype).to(device)
128-beta = torch.randn(512, dtype=torch.float32)130+x2 = torch.randn(2, 8, 512, dtype=dtype).to(device)
131+gamma = torch.randn(512, dtype=dtype).to(device)
132+beta = torch.randn(512, dtype=dtype).to(device)
129 133 
130y, rstd, x = npu_add_rms_norm_bias(x1, x2, gamma, beta, epsilon=1e-5)134y, rstd, x = npu_add_rms_norm_bias(x1, x2, gamma, beta, epsilon=1e-5)
131 135 
@@ -137,9 +141,11 @@ print("AddRmsNormBias operation completed successfully!")
137 141 
138```python142```python
139# 示例 3:多维 gamma(对最后几维做 RMS Norm)143# 示例 3:多维 gamma(对最后几维做 RMS Norm)
140-x1 = torch.randn(2, 4, 8, 64, dtype=torch.float16)144+dtype = torch.float16
141-x2 = torch.randn(2, 4, 8, 64, dtype=torch.float16)145+device = torch.device("npu")
142-gamma = torch.randn(8, 64, dtype=torch.float16) # 对最后 2 维做归一化146+x1 = torch.randn(2, 4, 8, 64, dtype=dtype).to(device)
147+x2 = torch.randn(2, 4, 8, 64, dtype=dtype).to(device)
148+gamma = torch.randn(8, 64, dtype=dtype).to(device) # 对最后 2 维做归一化
143 149 
144y, rstd, x = npu_add_rms_norm_bias(x1, x2, gamma)150y, rstd, x = npu_add_rms_norm_bias(x1, x2, gamma)
145# rstd shape 为 (2, 4, 1, 1)151# rstd shape 为 (2, 4, 1, 1)
@@ -76,7 +76,7 @@ Python接口返回loss;反向传播时自动使用CATLASS内核生成的
76| `hidden_states` | `torch.Tensor` | `[B, S, H]`,最后一维连续且无内部重叠 | `torch.bfloat16` |76| `hidden_states` | `torch.Tensor` | `[B, S, H]`,最后一维连续且无内部重叠 | `torch.bfloat16` |
77| `head_weight` | `torch.Tensor` | `[V, H]`,连续布局 | `torch.bfloat16` |77| `head_weight` | `torch.Tensor` | `[V, H]`,连续布局 | `torch.bfloat16` |
78| `label_chunks` | `Sequence[torch.Tensor]` | 按 `chunk_size` 划分的标签,数量为 `ceil(S / chunk_size)` | 转换为NPU `torch.int32` |78| `label_chunks` | `Sequence[torch.Tensor]` | 按 `chunk_size` 划分的标签,数量为 `ceil(S / chunk_size)` | 转换为NPU `torch.int32` |
79-| `alpha_chunks` | `Sequence[torch.Tensor \| None] \| None` | 每个chunk的归一化因子;省略时使用1 | `torch.float32` 或 `torch.int64` |79+| `alpha_chunks` | `Sequence[torch.Tensor \| None] \| None` | 每个chunk的归一化因子;需显式传参(接口无默认值),传入 `None` 或某一项为 `None` 时使用1 | `torch.float32` 或 `torch.int64` |
80| `chunk_size` | `attr` | 正整数 | `int` |80| `chunk_size` | `attr` | 正整数 | `int` |
81| `ignore_index` | `attr` | 忽略标签,必须在int32范围内 | `int` |81| `ignore_index` | `attr` | 忽略标签,必须在int32范围内 | `int` |
82| `reduction` | `attr` | 支持 `"sum"` 和 `"none"` | `str` |82| `reduction` | `attr` | 支持 `"sum"` 和 `"none"` | `str` |
@@ -11,7 +11,7 @@
11## 函数签名11## 函数签名
12 12 
13```python13```python
14-from mindspeed_ops.api.triton.chunk_gate_delta_rule import chunk_gated_delta_rule14+from mindspeed_ops.api.triton.chunk_gated_delta_rule import chunk_gated_delta_rule
15 15 
16def chunk_gated_delta_rule(16def chunk_gated_delta_rule(
17 q: torch.Tensor,17 q: torch.Tensor,
@@ -41,7 +41,7 @@ def chunk_gated_delta_rule(
41 use_qk_l2norm_in_kernel: 是否对 q/k 做 L2 归一化,默认 False41 use_qk_l2norm_in_kernel: 是否对 q/k 做 L2 归一化,默认 False
42 cu_seqlens: 变长序列累积长度,形状 [N+1],默认 None42 cu_seqlens: 变长序列累积长度,形状 [N+1],默认 None
43 chunk_size: 分块大小,默认 6443 chunk_size: 分块大小,默认 64
44- head_first: 已弃用,仅支持 False44+ head_first: 已弃用,传 True 仅告警仍可执行,建议使用 False
45 45 
46 Returns:46 Returns:
47 o: 输出张量,形状 [B, T, H, V]47 o: 输出张量,形状 [B, T, H, V]
@@ -68,7 +68,7 @@ def chunk_gated_delta_rule(
68| `use_qk_l2norm_in_kernel` | bool | - | 是否对q/k做L2归一化 | - |68| `use_qk_l2norm_in_kernel` | bool | - | 是否对q/k做L2归一化 | - |
69| `cu_seqlens` | torch.LongTensor | \[N+1] | 变长序列累积长度 | int32, int64 |69| `cu_seqlens` | torch.LongTensor | \[N+1] | 变长序列累积长度 | int32, int64 |
70| `chunk_size` | int | - | 分块大小,默认64 | - |70| `chunk_size` | int | - | 分块大小,默认64 | - |
71-| `head_first` | bool | - | 已弃用,仅支持False | - |71+| `head_first` | bool | - | 已弃用,传True仅告警仍可执行,建议使用False | - |
72 72 
73### 约束条件73### 约束条件
74 74 
@@ -99,7 +99,7 @@ def chunk_gated_delta_rule(
99对门控张量 `g`(log空间)沿序列维度按chunk做局部累积求和:99对门控张量 `g`(log空间)沿序列维度按chunk做局部累积求和:
100 100 
101```python101```python
102-g_cumsum = chunk_local_cumsum(g, chunk_size)102+g_cumsum = chunk_local_cumsum(g=g, chunk_size=chunk_size)
103```103```
104 104 
105这一步将log空间的门控值转换为chunk内的相对衰减因子,后续通过 `exp(g_i - g_j)` 实现因果衰减。105这一步将log空间的门控值转换为chunk内的相对衰减因子,后续通过 `exp(g_i - g_j)` 实现因果衰减。
@@ -107,7 +107,7 @@ g_cumsum = chunk_local_cumsum(g, chunk_size)
107#### 步骤2:计算KKT矩阵A107#### 步骤2:计算KKT矩阵A
108 108 
109```python109```python
110-A = chunk_scaled_dot_kkt_fwd(k, g=g_cumsum, beta=beta)110+A = chunk_scaled_dot_kkt_fwd(k=k, g=g_cumsum, beta=beta)
111```111```
112 112 
113在每个chunk内计算 `beta * K @ K^T`,并应用下三角掩码和门控差值指数缩放。输出形状为 `[B, T, H, BT]`,其中 `BT = chunk_size`。113在每个chunk内计算 `beta * K @ K^T`,并应用下三角掩码和门控差值指数缩放。输出形状为 `[B, T, H, BT]`,其中 `BT = chunk_size`。
@@ -115,7 +115,7 @@ A = chunk_scaled_dot_kkt_fwd(k, g=g_cumsum, beta=beta)
115#### 步骤3:矩阵求逆115#### 步骤3:矩阵求逆
116 116 
117```python117```python
118-A = solve_tril(A)118+A = solve_tril(A=A)
119```119```
120 120 
121计算 `(I + A)^-1`,将严格下三角的KKT矩阵转换为WY表示所需的下三角因子。`solve_tril` 通过16×16基础分块求逆 + 逐级合并(32×32 / 64×64)实现高效计算。121计算 `(I + A)^-1`,将严格下三角的KKT矩阵转换为WY表示所需的下三角因子。`solve_tril` 通过16×16基础分块求逆 + 逐级合并(32×32 / 64×64)实现高效计算。
@@ -123,7 +123,7 @@ A = solve_tril(A)
123#### 步骤4:重计算WY表示123#### 步骤4:重计算WY表示
124 124 
125```python125```python
126-w, u = recompute_w_u_fwd(k, v, beta, A, g=g_cumsum)126+w, u = recompute_w_u_fwd(k=k, v=v, beta=beta, A=A, g=g_cumsum)
127```127```
128 128 
129通过矩阵A对加权后的键值对进行变换:129通过矩阵A对加权后的键值对进行变换:
@@ -134,7 +134,7 @@ w, u = recompute_w_u_fwd(k, v, beta, A, g=g_cumsum)
134#### 步骤5:计算隐藏状态H和残差值V\_new134#### 步骤5:计算隐藏状态H和残差值V\_new
135 135 
136```python136```python
137-h, v_new, final_state = chunk_gated_delta_rule_fwd_h(k, w, u, g, initial_state)137+h, v_new, final_state = chunk_gated_delta_rule_fwd_h(k=k, w=w, u=u, g=g, initial_state=initial_state)
138```138```
139 139 
140沿序列迭代更新隐藏状态:140沿序列迭代更新隐藏状态:
@@ -146,7 +146,7 @@ h, v_new, final_state = chunk_gated_delta_rule_fwd_h(k, w, u, g, initial_state)
146#### 步骤6:计算最终输出O146#### 步骤6:计算最终输出O
147 147 
148```python148```python
149-o = chunk_fwd_o(q, k, v_new, h, g, scale)149+o = chunk_fwd_o(q=q, k=k, v=v_new, h=h, g=g, scale=scale)
150```150```
151 151 
152在每个chunk内计算:152在每个chunk内计算:
@@ -159,12 +159,12 @@ o = (q @ h + causal(q @ k^T) @ v_new) * scale
159 159 
160### 反向传播160### 反向传播
161 161 
162-反向传播沿前向的逆序执行,通过以下5个子步骤完成:162+反向传播沿前向的逆序执行,通过以下7个子步骤完成:
163 163 
164#### 步骤1:重计算WY表示164#### 步骤1:重计算WY表示
165 165 
166```python166```python
167-w, u = recompute_w_u_fwd(k, v, beta, A, g)167+w, u = recompute_w_u_fwd(k=k, v=v, beta=beta, A=A, g=g)
168```168```
169 169 
170与前向步骤4相同,重新计算中间变量(checkpointing策略,节省显存)。170与前向步骤4相同,重新计算中间变量(checkpointing策略,节省显存)。
@@ -172,7 +172,7 @@ w, u = recompute_w_u_fwd(k, v, beta, A, g)
172#### 步骤2:重计算H和V\_new172#### 步骤2:重计算H和V\_new
173 173 
174```python174```python
175-h, v_new, _ = chunk_gated_delta_rule_fwd_h(k, w, u, g, initial_state)175+h, v_new, _ = chunk_gated_delta_rule_fwd_h(k=k, w=w, u=u, g=g, initial_state=initial_state)
176```176```
177 177 
178与前向步骤5相同,重新计算隐藏状态。178与前向步骤5相同,重新计算隐藏状态。
@@ -180,7 +180,7 @@ h, v_new, _ = chunk_gated_delta_rule_fwd_h(k, w, u, g, initial_state)
180#### 步骤3:计算dV(局部贡献)180#### 步骤3:计算dV(局部贡献)
181 181 
182```python182```python
183-dv = chunk_bwd_dv_local(q, k, g, do, scale)183+dv = chunk_bwd_dv_local(q=q, k=k, do=do, g=g, scale=scale)
184```184```
185 185 
186计算chunk内注意力对v的梯度:`dv = tril(k @ q^T * scale)^T @ do`。186计算chunk内注意力对v的梯度:`dv = tril(k @ q^T * scale)^T @ do`。
@@ -188,7 +188,9 @@ dv = chunk_bwd_dv_local(q, k, g, do, scale)
188#### 步骤4:计算dH, dH0, dV188#### 步骤4:计算dH, dH0, dV
189 189 
190```python190```python
191-dh, dh0, dv = chunk_gated_delta_rule_bwd_dhu(q, k, w, g, h0, dht, do, dv, scale)191+dh, dh0, dv = chunk_gated_delta_rule_bwd_dhu(
192+ q=q, k=k, w=w, do=do, dv=dv, g=g, h0=initial_state, dht=dht, scale=scale
193+)
192```194```
193 195 
194从最后一个chunk向前迭代,沿隐藏状态递推链反向传播:196从最后一个chunk向前迭代,沿隐藏状态递推链反向传播:
@@ -200,7 +202,9 @@ dh, dh0, dv = chunk_gated_delta_rule_bwd_dhu(q, k, w, g, h0, dht, do, dv, scale)
200#### 步骤5:计算dQ, dK, dW, dG202#### 步骤5:计算dQ, dK, dW, dG
201 203 
202```python204```python
203-dq, dk, dw, dg = chunk_bwd_dqkwg(q, k, v_new, w, g, h, dv, do, dh, scale)205+dq, dk, dw, dg = chunk_bwd_dqkwg(
206+ q=q, k=k, v=v_new, do=do, h=h, dh=dh, g=g, dv=dv, w=w, scale=scale
207+)
204```208```
205 209 
206在每个chunk内累积注意力分数梯度 `dS`,并反向传播到 `q`、`k`、`w`、`g`。210在每个chunk内累积注意力分数梯度 `dS`,并反向传播到 `q`、`k`、`w`、`g`。
@@ -208,10 +212,12 @@ dq, dk, dw, dg = chunk_bwd_dqkwg(q, k, v_new, w, g, h, dv, do, dh, scale)
208#### 步骤6:WY表示反向212#### 步骤6:WY表示反向
209 213 
210```python214```python
211-dk2, dv, db, dg2 = prepare_wy_repr_bwd(k, v, beta, g, A, dw, dv)215+dk2, dv, db, dg2 = prepare_wy_repr_bwd(
216+ k=k, v=v, g=g, beta=beta, A=A, dw=dw, du=dv
217+)
212```218```
213 219 
214-将 `dw` 和 `dv` 的梯度通过WY表示反向传播到 `k`、`v`、`β`、`g`。涉及矩阵逆求导链:220+将 `dw` 与 `du` 的梯度通过WY表示反向传播到 `k`、`v`、`β`、`g`。内核中该参数名为 `du`,本实现传入的是步骤4/5得到的值梯度 `dv`(即调用时 `du=dv`)。涉及矩阵逆求导链:
215 221 
216```python222```python
217∂L/∂M = -A^T @ ∂L/∂A @ A^T223∂L/∂M = -A^T @ ∂L/∂A @ A^T
@@ -220,7 +226,7 @@ dk2, dv, db, dg2 = prepare_wy_repr_bwd(k, v, beta, g, A, dw, dv)
220#### 步骤7:门控梯度Cumsum反向226#### 步骤7:门控梯度Cumsum反向
221 227 
222```python228```python
223-dg = chunk_local_cumsum(dg, chunk_size, reverse=True)229+dg = chunk_local_cumsum(g=dg, chunk_size=chunk_size, reverse=True)
224```230```
225 231 
226将chunk内的门控梯度通过反向cumsum还原到逐token的梯度。232将chunk内的门控梯度通过反向cumsum还原到逐token的梯度。
@@ -248,7 +254,7 @@ g = F.logsigmoid(torch.rand(B, T, H, device=device, dtype=dtype))
248h0 = None254h0 = None
249 255 
250o, ht = chunk_gated_delta_rule(256o, ht = chunk_gated_delta_rule(
251- q, k, v, g, beta,257+ q=q, k=k, v=v, g=g, beta=beta,
252 initial_state=h0,258 initial_state=h0,
253 output_final_state=True,259 output_final_state=True,
254)260)
@@ -284,7 +290,7 @@ cu_seqlens = q.new_tensor([0, 2048, 4096, 6144, 8192], dtype=torch.long)
284h0 = None290h0 = None
285 291 
286o, ht = chunk_gated_delta_rule(292o, ht = chunk_gated_delta_rule(
287- q, k, v, g, beta,293+ q=q, k=k, v=v, g=g, beta=beta,
288 initial_state=h0,294 initial_state=h0,
289 output_final_state=True,295 output_final_state=True,
290 cu_seqlens=cu_seqlens,296 cu_seqlens=cu_seqlens,
@@ -340,7 +346,7 @@ Gated DeltaNet训练时的典型输入(chunk\_size=64):
3403. **beta维度要求**:`beta` 必须为3维张量 `[B, T, H]`,不支持其他形状。3463. **beta维度要求**:`beta` 必须为3维张量 `[B, T, H]`,不支持其他形状。
3414. **变长序列约束**:使用 `cu_seqlens` 时,batch size必须为1,且 `initial_state`参数只能传none。3474. **变长序列约束**:使用 `cu_seqlens` 时,batch size必须为1,且 `initial_state`参数只能传none。
3425. **chunk\_size选择**:默认值为64,需与下游子算子(如 `solve_tril` 仅支持BT=16/32/64)兼容。3485. **chunk\_size选择**:默认值为64,需与下游子算子(如 `solve_tril` 仅支持BT=16/32/64)兼容。
343-6. **head\_first已弃用**:该参数已废弃,仅支持 `head_first=False`。349+6. **head\_first已弃用**:该参数已废弃,传入 `head_first=True` 仅触发告警、仍会继续执行(该参数不参与实际计算),建议使用 `head_first=False`。
3447. **门控g的数值范围**:`g` 为log空间的门控值,内部 `exp(g_diff)` 计算会将其clamp到 `[-9, 0]` 范围,避免指数爆炸。3507. **门控g的数值范围**:`g` 为log空间的门控值,内部 `exp(g_diff)` 计算会将其clamp到 `[-9, 0]` 范围,避免指数爆炸。
3458. **输入幅度建议**:`k`、`β`、`g` 的输入量级建议控制在 \~0.1范围内,过大的值可能导致矩阵求逆发散。3518. **输入幅度建议**:`k`、`β`、`g` 的输入量级建议控制在 \~0.1范围内,过大的值可能导致矩阵求逆发散。
3469. **设备要求**:Triton内核需要在NPU或GPU设备上执行,CPU环境不支持。3529. **设备要求**:Triton内核需要在NPU或GPU设备上执行,CPU环境不支持。
@@ -36,7 +36,7 @@ def clipped_swiglu(
36|------|------|------|------|---------|36|------|------|------|------|---------|
37| `gate_up` | torch.Tensor | `[..., 2K]` | 输入张量,末维为偶数,前K列为gate、后K列为up | 是 |37| `gate_up` | torch.Tensor | `[..., 2K]` | 输入张量,末维为偶数,前K列为gate、后K列为up | 是 |
38| `swiglu_alpha` | float | - | SwiGLU的alpha参数 | 否,默认 `1.702` |38| `swiglu_alpha` | float | - | SwiGLU的alpha参数 | 否,默认 `1.702` |
39-| `swiglu_limit` | float | - | clamp上下限L,gate上限clamp到L,up双向clamp到 `[-L, L]` | 否,默认 `7.0` |39+| `swiglu_limit` | float | - | clamp上下限L(必须≥0),gate上限clamp到L,up双向clamp到 `[-L, L]` | 否,默认 `7.0` |
40 40 
41### 前向输出41### 前向输出
42 42 
@@ -117,34 +117,34 @@ assert y.shape == (B, T, K)
117 117 
118### bf16118### bf16
119 119 
120-| shape | eager(ms) | triton(ms) | speedup | bw(GB/s) |120+| shape | eager(ms) | triton(ms) | speedup |
121-|---|---|---|---|---|121+|---|---|---|---|
122-| (1, 8192) | 0.056 | 0.029 | 1.96× | 863 |122+| (1, 8192) | 0.056 | 0.029 | 1.96× |
123-| (128, 8192) | 0.066 | 0.029 | 2.27× | 108912 |123+| (128, 8192) | 0.066 | 0.029 | 2.27× |
124-| (1024, 8192) | 0.221 | 0.052 | 4.26× | 484314 |124+| (1024, 8192) | 0.221 | 0.052 | 4.26× |
125-| (8192, 8192) | 1.685 | 0.394 | 4.28× | 511687 |125+| (8192, 8192) | 1.685 | 0.394 | 4.28× |
126-| (1, 4096, 24576) | 2.902 | 0.541 | 5.37× | 558400 |126+| (1, 4096, 24576) | 2.902 | 0.541 | 5.37× |
127-| (1, 8192, 24576) | 5.798 | 1.072 | 5.41× | 563449 |127+| (1, 8192, 24576) | 5.798 | 1.072 | 5.41× |
128-| (4, 4096, 24576) | 11.536 | 2.138 | 5.40× | 565097 |128+| (4, 4096, 24576) | 11.536 | 2.138 | 5.40× |
129 129 
130### fp16130### fp16
131 131 
132-| shape | eager(ms) | triton(ms) | speedup | bw(GB/s) |132+| shape | eager(ms) | triton(ms) | speedup |
133-|---|---|---|---|---|133+|---|---|---|---|
134-| (1024, 8192) | 0.240 | 0.072 | 3.35× | 352026 |134+| (1024, 8192) | 0.240 | 0.072 | 3.35× |
135-| (8192, 8192) | 1.686 | 0.487 | 3.47× | 413849 |135+| (8192, 8192) | 1.686 | 0.487 | 3.47× |
136-| (1, 4096, 24576) | 2.687 | 0.602 | 4.47× | 501783 |136+| (1, 4096, 24576) | 2.687 | 0.602 | 4.47× |
137-| (4, 4096, 24576) | 10.903 | 2.226 | 4.90× | 542669 |137+| (4, 4096, 24576) | 10.903 | 2.226 | 4.90× |
138 138 
139### fp32139### fp32
140 140 
141-| shape | eager(ms) | triton(ms) | speedup | bw(GB/s) |141+| shape | eager(ms) | triton(ms) | speedup |
142-|---|---|---|---|---|142+|---|---|---|---|
143-| (1024, 8192) | 0.296 | 0.117 | 2.54× | 431975 |143+| (1024, 8192) | 0.296 | 0.117 | 2.54× |
144-| (8192, 8192) | 3.790 | 0.542 | 7.00× | 743185 |144+| (8192, 8192) | 3.790 | 0.542 | 7.00× |
145-| (1, 4096, 24576) | 5.596 | 0.747 | 7.49× | 808788 |145+| (1, 4096, 24576) | 5.596 | 0.747 | 7.49× |
146-| (1, 8192, 24576) | 10.569 | 1.283 | 8.24× | 941380 |146+| (1, 8192, 24576) | 10.569 | 1.283 | 8.24× |
147-| (4, 4096, 24576) | 21.150 | 2.576 | 8.21× | 937771 |147+| (4, 4096, 24576) | 21.150 | 2.576 | 8.21× |
148 148 
1493D shape `(1, 4096, 24576)` 对应K=12288(LLM hidden常见尺寸),三dtype加速:fp32 8.2× / bf16 5.4× / fp16 4.5×。bf16/fp16的瓶颈为fp32超越函数(sigmoid)计算,fp32已近该算子上限。1493D shape `(1, 4096, 24576)` 对应K=12288(LLM hidden常见尺寸),三dtype加速:fp32 8.2× / bf16 5.4× / fp16 4.5×。bf16/fp16的瓶颈为fp32超越函数(sigmoid)计算,fp32已近该算子上限。
150 150 
@@ -20,16 +20,16 @@ def chunk_local_cumsum(
20) -> torch.Tensor:20) -> torch.Tensor:
21 """21 """
22 Args:22 Args:
23- g: 输入张量,shape 为 (B, T, H) or (B, T, H, K)23+ g: 输入张量,shape 为 (B, T, H) 或 (B, T, H, K)
24 chunk_size: 分块大小,必须是 2 的幂次24 chunk_size: 分块大小,必须是 2 的幂次
25 reverse: 是否在每个 chunk 内反向执行 cumsum,默认 False25 reverse: 是否在每个 chunk 内反向执行 cumsum,默认 False
26 scale: 输出缩放因子,默认 None26 scale: 输出缩放因子,默认 None
27 cu_seqlens: 变长序列的累积长度张量,默认 None。提供时 batch size 必须为 127 cu_seqlens: 变长序列的累积长度张量,默认 None。提供时 batch size 必须为 1
28- head_first: 是否 head 维度在前,仅支持 False28+ head_first: 是否 head 维度在前,arch32 路径仅支持 False
29 output_dtype: 输出数据类型,默认 torch.float29 output_dtype: 输出数据类型,默认 torch.float
30- chunk_indices: 分块索引张量,shape 为 (B, T // chunk_size), 默认为 None30+ chunk_indices: 分块索引张量,shape 为 (num_chunks, 2),每行为 (序列编号, 序列内chunk编号),默认为 None
31 Returns:31 Returns:
32- 分块局部 cumsum 结果,shape 为 (B, T, H)32+ 分块局部 cumsum 结果,shape 为 (B, T, H) 或 (B, T, H, K),与输入 shape 一致
33 """33 """
34```34```
35 35 
@@ -37,19 +37,20 @@ def chunk_local_cumsum(
37 37 
38| 参数 | 类型 | 描述 | 支持的数据类型 |38| 参数 | 类型 | 描述 | 支持的数据类型 |
39|------|------|------|---------------|39|------|------|------|---------------|
40-| g | torch.Tensor | 输入张量,shape为 (B, T, H) | float32, float16, bfloat16 |40+| g | torch.Tensor | 输入张量,shape为 (B, T, H) 或 (B, T, H, K) | float32, float16, bfloat16 |
41| chunk_size | int | 分块大小,必须是2的幂次 | - |41| chunk_size | int | 分块大小,必须是2的幂次 | - |
42| reverse | bool | 是否在chunk内反向cumsum,默认False | - |42| reverse | bool | 是否在chunk内反向cumsum,默认False | - |
43| scale | float | 输出缩放因子,默认None | - |43| scale | float | 输出缩放因子,默认None | - |
44| cu_seqlens | torch.Tensor | 变长序列的累积长度,shape为 (num_seqs + 1,),默认None | int32 |44| cu_seqlens | torch.Tensor | 变长序列的累积长度,shape为 (num_seqs + 1,),默认None | int32 |
45-| head_first | bool | 是否head维度在前,仅支持False | - |45+| head_first | bool | 是否head维度在前,arch32路径仅支持False | - |
46| output_dtype | torch.dtype | 输出数据类型,默认torch.float | - |46| output_dtype | torch.dtype | 输出数据类型,默认torch.float | - |
47+| chunk_indices | torch.LongTensor | 分块索引张量,shape为 (num_chunks, 2),每行为 (序列编号, 序列内chunk编号),默认None;仅在arch32路径的4维输入(vector内核)下生效,3维输入与arch35路径会忽略该参数;为None且提供cu_seqlens时由cu_seqlens自动推导 | int32, int64 |
47 48 
48## 返回值49## 返回值
49 50 
50| 参数 | 类型 | 描述 | 支持的数据类型 |51| 参数 | 类型 | 描述 | 支持的数据类型 |
51| ------|------|------|---------------|52| ------|------|------|---------------|
52-| output | torch.Tensor | 分块局部cumsum结果,shape为 (B, T, H) | 默认float32,可通过output_dtype指定 |53+| output | torch.Tensor | 分块局部cumsum结果,shape为 (B, T, H) 或 (B, T, H, K),与输入shape一致;4维时最后一维K为独立通道维,各通道沿T维独立累加 | 默认float32,可通过output_dtype指定 |
53 54 
54## 实现原理55## 实现原理
55 56 
@@ -59,7 +60,7 @@ def chunk_local_cumsum(
592. **Tiling策略**:根据 `reverse` 模式和head维度大小H动态计算分块大小 `BT`,平衡并行度和UB(Unified Buffer)利用率:602. **Tiling策略**:根据 `reverse` 模式和head维度大小H动态计算分块大小 `BT`,平衡并行度和UB(Unified Buffer)利用率:
60 - `BT = max(chunk_size, next_power_of_2((1 << 11 if reverse else 1 << 12) // H))`61 - `BT = max(chunk_size, next_power_of_2((1 << 11 if reverse else 1 << 12) // H))`
613. **变长序列处理**:若提供 `cu_seqlens`,调用 `prepare_chunk_indices` 生成chunk索引,支持不同长度的序列独立分块。623. **变长序列处理**:若提供 `cu_seqlens`,调用 `prepare_chunk_indices` 生成chunk索引,支持不同长度的序列独立分块。
62-4. **启动内核**:调用Triton内核 `chunk_local_cumsum_scalar_kernel`,按 `(NT, B)` 的grid并行执行,每个chunk内独立完成cumsum计算。63+4. **启动内核**:arch32路径下,3维输入调用Triton内核 `chunk_local_cumsum_scalar_kernel`,按 `(NT, B)` 的grid并行执行,每个chunk内独立完成cumsum计算;4维输入调用 `chunk_local_cumsum_vector_kernel`,此时 `BT = chunk_size`,按 `(cdiv(S, BS), NT, B * H)` 的grid并行执行(`BS` 固定为32),每个chunk内沿T维独立完成cumsum计算,最后一维S按 `BS` 切分。arch35路径由独立实现承接,3维与4维输入均落到scalar内核(4维先reshape为3维)。
635. **后处理**:若指定 `scale`,在内核中对结果进行缩放。645. **后处理**:若指定 `scale`,在内核中对结果进行缩放。
64 65 
65## 使用示例66## 使用示例
@@ -127,8 +128,8 @@ print("varlen chunk_local_cumsum operation exec successfully!")
127## 注意事项128## 注意事项
128 129 
1291. `chunk_size` 必须是2的幂次,否则会抛出 `ValueError`。1301. `chunk_size` 必须是2的幂次,否则会抛出 `ValueError`。
130-2. 当前算子仅支持3维输入 `(B, T, H)`,不支持4维输入 `(B, T, H, D)`。131+2. 算子同时支持3维输入 `(B, T, H)` 与4维输入 `(B, T, H, K)`。arch32路径按输入维度分发:3维走scalar内核,4维走vector内核;arch35路径由独立实现承接,其4维输入会先reshape为3维后复用scalar内核。
1313. 使用 `cu_seqlens` 时,batch size必须为1,否则会抛出 `ValueError`。1323. 使用 `cu_seqlens` 时,batch size必须为1,否则会抛出 `ValueError`。
132-4. 该算子在arch35平台上暂不支持,会抛出 `NotImplementedError`。133+4. 该算子同时支持arch32与arch35架构,运行时自动分发至对应架构的实现。arch32路径下 `head_first=True` 会抛出 `NotImplementedError`。
1335. 对于非常小的张量,可能不会观察到明显的性能提升,因为启动内核的开销和Triton下发可能超过计算收益。1345. 对于非常小的张量,可能不会观察到明显的性能提升,因为启动内核的开销和Triton下发可能超过计算收益。
1346. `output_dtype` 默认为 `torch.float`,在反向传播和context parallel场景下可有效防止中间结果溢出。1356. `output_dtype` 默认为 `torch.float`,在反向传播和context parallel场景下可有效防止中间结果溢出。
@@ -37,7 +37,7 @@ class FusedCrossEntropyLossFunction(torch.autograd.Function):
37 37 
38| 参数 | 类型 | 描述 | 支持的数据类型 |38| 参数 | 类型 | 描述 | 支持的数据类型 |
39| ------ |------|------|---------------|39| ------ |------|------|---------------|
40-| loss | torch.Tensor | [bs * seq_len] | 与输入张量相同的数据类型 |40+| loss | torch.Tensor | 标量(所有token加权交叉熵之和) | float32(内核以FP32计算输出) |
41 41 
42## 实现原理42## 实现原理
43 43 
@@ -54,6 +54,8 @@ import torch
54from mindspeed_ops.api.triton.fused_cross_entropy_loss import FusedCrossEntropyLossFunction54from mindspeed_ops.api.triton.fused_cross_entropy_loss import FusedCrossEntropyLossFunction
55 55 
56# 创建测试张量56# 创建测试张量
57+dtype = torch.float32
58+device = torch.device("npu")
57logits = torch.randn((1024, 16384), requires_grad=True, dtype=dtype).to(device)59logits = torch.randn((1024, 16384), requires_grad=True, dtype=dtype).to(device)
58loss_weight = torch.randn((1024, ), requires_grad=True, dtype=dtype).to(device)60loss_weight = torch.randn((1024, ), requires_grad=True, dtype=dtype).to(device)
59labels = torch.randint(0, 16384, (1024,), dtype=torch.int32).to(device)61labels = torch.randint(0, 16384, (1024,), dtype=torch.int32).to(device)
@@ -72,10 +72,10 @@ bmm1[b, s, i, d] = h_post[b, s, i] * x[b, s, d] # [B, S, N, D]
72**分支2(bmm2)**:residual与h_res的矩阵乘法72**分支2(bmm2)**:residual与h_res的矩阵乘法
73 73 
74```python74```python
75-bmm2[b, s, i, d] = sum_j(h_res[b, s, i, j] * residual[b, s, j, d]) # [B, S, N, D]75+bmm2[b, s, i, d] = sum_j(h_res[b, s, j, i] * residual[b, s, j, d]) # [B, S, N, D]
76```76```
77 77 
78-对N个stream的残差按h_res矩阵进行线性组合。78+对N个stream的残差按h_res矩阵进行线性组合。公式中的 `h_res` 采用**用户输入的**排列,并非内部转置后的张量:源码内部前向会先对 `h_res` 执行 `permute(0,1,3,2)` 转置,再参与bmm2计算;反向得到的 `grad_h_res` 同样按用户输出排列书写,源码内部会在返回前转置还原。
79 79 
80**合并**:逐元素相加80**合并**:逐元素相加
81 81 
@@ -97,12 +97,12 @@ grad_h_post[b, s, i] = sum_d(grad_out[b, s, i, d] * x[b, s, d])
97**bmm2反向**:97**bmm2反向**:
98 98 
99```python99```python
100-grad_residual[b, s, j, d] = sum_i(grad_out[b, s, i, d] * h_res[b, s, i, j])100+grad_residual[b, s, j, d] = sum_i(grad_out[b, s, i, d] * h_res[b, s, j, i])
101-grad_h_res[b, s, i, j] = sum_d(grad_out[b, s, i, d] * residual[b, s, j, d])101+grad_h_res[b, s, i, j] = sum_d(grad_out[b, s, j, d] * residual[b, s, i, d])
102```102```
103 103 
104- `grad_h_post` 和 `grad_h_res` 使用 `atomic_add` 累加,支持D维度分块。104- `grad_h_post` 和 `grad_h_res` 使用 `atomic_add` 累加,支持D维度分块。
105-- `h_res` 在前向中被permute(0,1,3,2),反向输出时还原为原始排列。105+- 上述公式中的 `h_res` / `grad_h_res` 排列约定见上文bmm2分支说明。
106 106 
107### 梯度重计算107### 梯度重计算
108 108 
@@ -159,7 +159,7 @@ assert result.shape == (B, S, N, D)
159## 注意事项159## 注意事项
160 160 
1611. `h_post` 最后一维N必须与 `residual` 倒数第二维一致。1611. `h_post` 最后一维N必须与 `residual` 倒数第二维一致。
162-2. `h_res` 形状必须为 [B, S, N, N],内部会执行 `permute(0,1,3,2)` 转置。162+2. `h_res` 形状必须为 [B, S, N, N],排列约定见上文。
1633. `residual` 的前两维 (B, S) 必须与 `x` 一致,最后两维必须为 (N, D)。1633. `residual` 的前两维 (B, S) 必须与 `x` 一致,最后两维必须为 (N, D)。
1644. 内部计算使用FP32精度,确保数值稳定性。1644. 内部计算使用FP32精度,确保数值稳定性。
1655. 反向计算中 `grad_h_post` 和 `grad_h_res` 使用 `atomic_add` 累加。1655. 反向计算中 `grad_h_post` 和 `grad_h_res` 使用 `atomic_add` 累加。
@@ -55,7 +55,7 @@ def mhc_pre_only_triton(
55| `norm_gamma` | torch.Tensor | [n_D] | RMS归一化可学习缩放参数 | 是 | BF16, FP32 |55| `norm_gamma` | torch.Tensor | [n_D] | RMS归一化可学习缩放参数 | 是 | BF16, FP32 |
56| `mhc_use_gamma` | bool | - | RMS Norm是否应用gamma | 否,默认True | - |56| `mhc_use_gamma` | bool | - | RMS Norm是否应用gamma | 否,默认True | - |
57| `num_stream` | int | - | stream数量,必须整除n_D | 否,默认4 | - |57| `num_stream` | int | - | stream数量,必须整除n_D | 否,默认4 | - |
58-| `eps` | float | - | RMS归一化防除零常数 | 否,默认1e-6 | BF16, FP32 |58+| `eps` | float | - | RMS归一化防除零常数 | 否,默认1e-6 | - |
59| `recompute_info` | - | - | 梯度重计算信息对象 | 否 | - |59| `recompute_info` | - | - | 梯度重计算信息对象 | 否 | - |
60 60 
61### 输出61### 输出
@@ -76,7 +76,7 @@ mhc_pre_only_triton将以下步骤融合为一次前向计算:
761. **RMS归一化**:对输入x进行RMS Norm。761. **RMS归一化**:对输入x进行RMS Norm。
77 77 
78 ```python78 ```python
79- x_norm = x / sqrt(mean(x^2) + eps) * gamma79+ x_norm = x / sqrt(mean(x^2) + eps) * norm_gamma
80 ```80 ```
81 81 
822. **线性投影**:将归一化后的输入投影到num_stream维度。822. **线性投影**:将归一化后的输入投影到num_stream维度。
@@ -4,6 +4,8 @@
4 4 
5recompute\_w\_u\_fwd是一个基于Triton实现的WY表示重计算算子,用于在反向传播过程中重新计算中间变量w和u。该算子是gated delta rule的核心组件,通过矩阵A对键值对进行加权变换,支持可选的门控机制和变长序列处理,充分利用昇腾NPU的并行计算能力实现高性能计算。5recompute\_w\_u\_fwd是一个基于Triton实现的WY表示重计算算子,用于在反向传播过程中重新计算中间变量w和u。该算子是gated delta rule的核心组件,通过矩阵A对键值对进行加权变换,支持可选的门控机制和变长序列处理,充分利用昇腾NPU的并行计算能力实现高性能计算。
6 6 
7+本文中的arch32/arch35为昇腾NPU架构代号(arch32对应Ascend 910B/910_93系列,arch35对应Ascend 950系列),运行时通过 `mindspeed_ops.utils.is_arch35()` 自动判别并分发到对应架构的实现。
8+ 
7***9***
8 10 
9## 函数签名11## 函数签名
@@ -91,7 +93,7 @@ def recompute_w_u_fwd(
911. **分块计算**:将工作按 `[BT, BK]` 和 `[BT, BV]` 的tile切分,充分利用NPU Unified Buffer。931. **分块计算**:将工作按 `[BT, BK]` 和 `[BT, BV]` 的tile切分,充分利用NPU Unified Buffer。
922. **持久化kernel**:采用grid-stride loop,每个AI核轮流处理多个tile,减少调度开销。942. **持久化kernel**:采用grid-stride loop,每个AI核轮流处理多个tile,减少调度开销。
933. **门控融合**:将beta、g、gk的指数运算融合到矩阵乘法中,减少中间结果的存储和访问。953. **门控融合**:将beta、g、gk的指数运算融合到矩阵乘法中,减少中间结果的存储和访问。
94-4. **变长序列支持**:通过 `cu_seqlens` 和 `chunk_indices` 实现对变长序列的高效处理。96+4. **变长序列支持**:通过 `cu_seqlens` 推导出chunk索引(`chunk_indices`,非入参,由实现内部自动生成),实现对变长序列的高效处理。
95 97 
96### 计算流程98### 计算流程
97 99 
@@ -183,7 +185,7 @@ w, u = recompute_w_u_fwd(k=k, v=v, beta=beta, A=A, cu_seqlens=cu_seqlens)
183 185 
184## 适用场景186## 适用场景
185 187 
186-1. **Gated Delta Rule模型训练**:recompute\_w\_u\_fwd是gated delta rule前向计算的核心组件,用于重新计算中间变量。188+1. **Gated Delta Rule模型训练**:recompute\_w\_u\_fwd是gated delta rule反向重计算的核心组件,用于重新计算中间变量。
1872. **变长序列训练**:通过 `cu_seqlens` 支持将不同长度的样本高效打包进同一batch。1892. **变长序列训练**:通过 `cu_seqlens` 支持将不同长度的样本高效打包进同一batch。
1883. **反向传播优化**:在反向传播过程中重新计算中间结果,减少显存占用。1903. **反向传播优化**:在反向传播过程中重新计算中间结果,减少显存占用。
189 191 
@@ -49,11 +49,13 @@ import torch
49from mindspeed_ops.api.triton.rmsnorm_without_weight import RmsnormWithoutWeightFunction49from mindspeed_ops.api.triton.rmsnorm_without_weight import RmsnormWithoutWeightFunction
50 50 
51# 创建测试张量51# 创建测试张量
52-x = torch.randn(1024, 1, 16384)52+dtype = torch.float32
53+device = torch.device("npu")
54+x = torch.randn(1024, 1, 16384, dtype=dtype).to(device)
53norm_eps = 1e-655norm_eps = 1e-6
54 56 
55# 执行RMSNorm归一化计算57# 执行RMSNorm归一化计算
56-triton_result = RmsnormWithoutWeightFunction.apply(x_triton, norm_eps)58+triton_result = RmsnormWithoutWeightFunction.apply(x, norm_eps)
57torch_result = torch.rsqrt(x.square().mean(dim=-1, keepdim=True) + norm_eps)59torch_result = torch.rsqrt(x.square().mean(dim=-1, keepdim=True) + norm_eps)
58 60 
59# 验证结果61# 验证结果
@@ -26,7 +26,7 @@ def rms_norm_gated(
26 x: 输入张量,形状 [B, T, D] 或 [T, D]26 x: 输入张量,形状 [B, T, D] 或 [T, D]
27 g: 门控张量,形状与 x 相同27 g: 门控张量,形状与 x 相同
28 weight: 可学习缩放权重,形状 [D]28 weight: 可学习缩放权重,形状 [D]
29- bias: 偏置,形状 [D](可选,当前实现固定为 None)29+ bias: 偏置,形状 [D](必传参数,无默认值;传 `None` 表示不加偏置)
30 activation: 门控激活函数类型,支持 'swish'/'silu'/'sigmoid'30 activation: 门控激活函数类型,支持 'swish'/'silu'/'sigmoid'
31 residual: 残差输入,形状与 x 相同(可选)31 residual: 残差输入,形状与 x 相同(可选)
32 prenorm: 是否启用 prenorm 模式,启用时返回 (y, residual_out)32 prenorm: 是否启用 prenorm 模式,启用时返回 (y, residual_out)
@@ -48,7 +48,7 @@ def rms_norm_gated(
48| `x` | torch.Tensor | [B, S, D] 或 [T, D] | 输入张量,B为batch大小,S为序列长度,T为BS长度,D为特征维度 | 是 |48| `x` | torch.Tensor | [B, S, D] 或 [T, D] | 输入张量,B为batch大小,S为序列长度,T为BS长度,D为特征维度 | 是 |
49| `g` | torch.Tensor | 同x | 门控张量,与x形状完全一致 | 是 |49| `g` | torch.Tensor | 同x | 门控张量,与x形状完全一致 | 是 |
50| `weight` | torch.Tensor | [D] | 可学习缩放权重(gamma) | 是 |50| `weight` | torch.Tensor | [D] | 可学习缩放权重(gamma) | 是 |
51-| `bias` | torch.Tensor | [D] | 偏置(当前实现固定为None) | 否 |51+| `bias` | torch.Tensor | [D] | 偏置;必传参数(无默认值),传 `None` 时不加偏置 | 是(无默认值,可传 `None`) |
52| `activation` | str | - | 门控激活函数,支持 `'swish'`/`'silu'`/`'sigmoid'` | 否,默认 "swish" |52| `activation` | str | - | 门控激活函数,支持 `'swish'`/`'silu'`/`'sigmoid'` | 否,默认 "swish" |
53| `residual` | torch.Tensor | 同x | 残差输入,在归一化前与x相加 | 否 |53| `residual` | torch.Tensor | 同x | 残差输入,在归一化前与x相加 | 否 |
54| `prenorm` | bool | - | 是否启用prenorm模式 | 否,默认False |54| `prenorm` | bool | - | 是否启用prenorm模式 | 否,默认False |
@@ -107,8 +107,8 @@ def rms_norm_gated(
107|--------|------|107|--------|------|
108| `x` 与 `g` | 必须相同dtype |108| `x` 与 `g` | 必须相同dtype |
109| `weight` | 可与 `x` 不同dtype,kernel内部自动转换 |109| `weight` | 可与 `x` 不同dtype,kernel内部自动转换 |
110-| `residual` | 可与 `x` 不同dtype,通过 `residual_in_fp32=True` 强制fp32存储 |110+| `residual` | 可与 `x` 不同dtype,其dtype由传入张量自身决定;`residual_in_fp32` 仅在未传 `residual` 时生效,决定此时 `residual_out` 是否以fp32存储 |
111-| 输出 `y` | 与 `x` 相同dtype(除非指定 `out_dtype`) |111+| 输出 `y` | 恒与 `x` 相同dtype(公共接口 `rms_norm_gated` 不暴露 `out_dtype`) |
112 112 
113## 实现原理113## 实现原理
114 114 
@@ -179,13 +179,13 @@ assert y.shape == (B, T, D)
179 179 
180```python180```python
181residual = torch.randn(B, T, D, device='npu', dtype=torch.bfloat16)181residual = torch.randn(B, T, D, device='npu', dtype=torch.bfloat16)
182-y = model(x, g, residual=residual)182+y = rms_norm_gated(x, g, weight, bias=None, activation='silu', residual=residual)
183```183```
184 184 
185### Prenorm模式185### Prenorm模式
186 186 
187```python187```python
188-y, residual_out = model(x, g, prenorm=True)188+y, residual_out = rms_norm_gated(x, g, weight, bias=None, activation='silu', prenorm=True)
189```189```
190 190 
191## 性能对比191## 性能对比
@@ -215,7 +215,7 @@ y, residual_out = model(x, g, prenorm=True)
2151. `x` 与 `g` 必须具有完全相同的形状。2151. `x` 与 `g` 必须具有完全相同的形状。
2162. `weight` 的长度必须等于x的最后一维D。2162. `weight` 的长度必须等于x的最后一维D。
2173. 激活函数名称 `swish` 和 `silu` 等价,均表示 `x * sigmoid(x)`。2173. 激活函数名称 `swish` 和 `silu` 等价,均表示 `x * sigmoid(x)`。
218-4. 当前实现中 `bias` 固定为None,如需偏置需扩展实现。218+4. `bias` 为必传参数(无默认值),可传 `None` 表示不加偏置;传入 `[D]` 张量时按元素相加并产生 `db` 梯度。
2195. 反向传播时kernel会重计算前向输出y,这是用计算换显存的设计,在训练显存敏感场景下属于预期行为。2195. 反向传播时kernel会重计算前向输出y,这是用计算换显存的设计,在训练显存敏感场景下属于预期行为。
2206. 对于非常小的张量,可能不会观察到明显的性能提升,因为启动内核的开销可能超过计算收益。2206. 对于非常小的张量,可能不会观察到明显的性能提升,因为启动内核的开销可能超过计算收益。
221-7. 该算子不支持arch35平台。221+7. 该算子同时支持arch32与arch35架构,运行时由 `is_arch35()` 自动分发至对应架构的实现,`bias`、`residual`、`prenorm` 在两种架构上均支持;arch35路径额外要求 `D` 不超过 `65536 / x.element_size()`,超出会抛出 `RuntimeError`。
@@ -89,7 +89,7 @@ class SinkhornFunction(torch.autograd.Function):
89 eps: float = 1e-6,89 eps: float = 1e-6,
90 ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:90 ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
91 """91 """
92- Triton implementation of HC-Split Sinkhorn, optimized for GPU performance92+ Triton implementation of HC-Split Sinkhorn, optimized for Ascend NPU performance
93 93 
94 Args:94 Args:
95 mixes: Input tensor with shape [batch_size, seq_len, (2+hc_mult)*hc_mult]95 mixes: Input tensor with shape [batch_size, seq_len, (2+hc_mult)*hc_mult]
@@ -111,11 +111,11 @@ class SinkhornFunction(torch.autograd.Function):
111 111 
112| 参数 | 类型 | 描述 | 支持的数据类型 |112| 参数 | 类型 | 描述 | 支持的数据类型 |
113|------|------|------|---------------|113|------|------|------|---------------|
114-| mixes | torch.Tensor | [batch_size, seq_len, (2+hc_mult)*hc_mult] | float32 |114+| mixes | torch.Tensor | [batch_size, seq_len, (2+hc_mult)*hc_mult] | float32, float16, bfloat16 |
115| hc_scale | torch.Tensor | [3] | float32 |115| hc_scale | torch.Tensor | [3] | float32 |
116| hc_base | torch.Tensor | [(2+hc_mult)*hc_mult] | - |116| hc_base | torch.Tensor | [(2+hc_mult)*hc_mult] | - |
117| hc_mult | attr | 立即数,当前仅支持4 | int32 |117| hc_mult | attr | 立即数,当前仅支持4 | int32 |
118-| sinkhorn_iters | attr | 立即数,当前仅支持20 | - |118+| sinkhorn_iters | attr | 立即数,默认为20,无取值校验(编译期常量) | - |
119| eps | attr | 立即数,默认为1e-6 | - |119| eps | attr | 立即数,默认为1e-6 | - |
120 120 
121## 输出说明121## 输出说明
@@ -141,12 +141,14 @@ import torch
141from mindspeed_ops.api.triton.sinkhorn import SinkhornFunction141from mindspeed_ops.api.triton.sinkhorn import SinkhornFunction
142 142 
143# 创建测试张量143# 创建测试张量
144+dtype = torch.float32
145+device = torch.device("npu")
144mixes = torch.randn((1, 2048, 24), requires_grad=True, dtype=dtype).to(device)146mixes = torch.randn((1, 2048, 24), requires_grad=True, dtype=dtype).to(device)
145hc_scale = torch.randn((3,), requires_grad=True, dtype=dtype).to(device)147hc_scale = torch.randn((3,), requires_grad=True, dtype=dtype).to(device)
146hc_base = torch.randn((24,), requires_grad=True, dtype=dtype).to(device)148hc_base = torch.randn((24,), requires_grad=True, dtype=dtype).to(device)
147 149 
148# 执行Sinkhorn算子150# 执行Sinkhorn算子
149-triton_pre, triton_post, triton_comb = SinkhornFunction.apply(triton_mixes, triton_hc_scale, triton_hc_base)151+triton_pre, triton_post, triton_comb = SinkhornFunction.apply(mixes, hc_scale, hc_base)
150 152 
151# 验证结果153# 验证结果
152print("sinkhorn operation executed successfully!")154print("sinkhorn operation executed successfully!")
@@ -41,7 +41,7 @@ def moe_sort_chunks_by_index_with_probs(
41| 参数 | 类型 | Shape | 支持dtype | 说明 |41| 参数 | 类型 | Shape | 支持dtype | 说明 |
42|------|------|-------|------------|------|42|------|------|-------|------------|------|
43| `inp` | `torch.Tensor` | `[num_tokens, hidden_size]` | `float16`, `bfloat16`, `float32` | 待重排的token表示 |43| `inp` | `torch.Tensor` | `[num_tokens, hidden_size]` | `float16`, `bfloat16`, `float32` | 待重排的token表示 |
44-| `probs` | `torch.Tensor` | `[num_tokens]` | `float16`, `bfloat16`, `float32` | 可选输入,随 `inp` 一起重排 |44+| `probs` | `torch.Tensor` | `[num_tokens]` | `float16`, `bfloat16`, `float32` | 仅 `moe_sort_chunks_by_index_with_probs` 接口使用,随 `inp` 一起重排 |
45| `split_sizes` | `torch.Tensor` | `[num_splits]` | `int32` | 每个chunk在第0维的长度,元素和应等于 `num_tokens` |45| `split_sizes` | `torch.Tensor` | `[num_splits]` | `int32` | 每个chunk在第0维的长度,元素和应等于 `num_tokens` |
46| `sorted_index` | `torch.Tensor` | `[num_splits]` | `int32` | chunk重排索引,应为 `[0, num_splits)` 的合法排列 |46| `sorted_index` | `torch.Tensor` | `[num_splits]` | `int32` | chunk重排索引,应为 `[0, num_splits)` 的合法排列 |
47 47