Skip to content

Commit eaae33b

Browse files
author
w112009931-bit
committed
fix
1 parent 978d42b commit eaae33b

11 files changed

Lines changed: 850 additions & 52 deletions

cudnn_frontend_op_gap.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -156,17 +156,17 @@ FlagDNN 对标 cuDNN Frontend 时,不建议只补 eager 单算子。每个新
156156

157157
| cuDNN op | 参数 | FlagDNN 状态 | 建议实现位置 |
158158
|---|---|---|---|
159-
| `matmul` | `A, B, compute_data_type=NOT_SET, padding=0.0, name=''` | 部分;已有 2D `mm`3D batched Graph/Triton 和 general broadcast fallback,仍缺非零 `padding` 语义 | `ops/matmul.py` 继续补 padding |
159+
| `matmul` | `A, B, compute_data_type=NOT_SET, padding=0.0, name=''` | 已有;2D `mm`3D 同 batch 走 Triton 快路径,其它 rank/batch broadcast 也走 Triton batched kernel;`padding` 按 cuDNN backend padding-value 兼容参数接收,标准 K 匹配时不改变数学结果 | 已有;后续可补动态 K override/低精度专用 GEMM |
160160
| `moe_grouped_matmul` | `token, weight, first_token_offset, token_index=None, token_ks=None, mode=NONE, compute_data_type=FLOAT, top_k=0, name=''` | 缺失 | `ops/moe_grouped_matmul.py`,graph kernel |
161161
| `moe_grouped_matmul_bwd` | `doutput, token, first_token_offset, compute_data_type=FLOAT, name=''` | 缺失 | `ops/moe_grouped_matmul_bwd.py` |
162162

163-
普通 `matmul` 已覆盖 2D、同 batch 3D 优化路径和其它 rank/broadcast fallback;cuDNN `padding` 是 backend plan padding value,仍需单独定义 FlagDNN 侧等价语义
163+
普通 `matmul` 已覆盖 2D、同 batch 3D 优化路径和其它 rank/broadcast;cuDNN `padding` 是 backend matmul descriptor 的 padding value,FlagDNN 侧作为兼容参数接收,shape/K 仍按标准 matmul 校验
164164

165165
### 4.7 Reduction / stats
166166

167167
| cuDNN op | 参数 | FlagDNN 状态 | 建议实现位置 |
168168
|---|---|---|---|
169-
| `reduction` | `input, mode, compute_data_type=NOT_SET, name=''` | 已有 eager + Graph;支持 `ADD/AVG/MUL/MIN/MAX/AMAX/NORM1/NORM2/MUL_NO_ZEROS`,FlagDNN graph 需显式 `dim/keepdim`;当前 cuDNN standalone reduction 不给 engine | 已有;后续可补 cuDNN 输出 shape 推导式 API |
169+
| `reduction` | `input, mode, compute_data_type=NOT_SET, name=''` | 已有 eager + Graph;支持 `ADD/AVG/MUL/MIN/MAX/AMAX/NORM1/NORM2/MUL_NO_ZEROS`其中 `MIN/MAX/AMAX/MUL_NO_ZEROS` 已改为 Triton 原生实现;FlagDNN graph 需显式 `dim/keepdim`;当前 cuDNN standalone reduction 不给 engine | 已有;后续可补 cuDNN 输出 shape 推导式 API |
170170
| `genstats` | `input, compute_data_type=NOT_SET, name=''` -> `[mean, inv_variance]` | 缺失 | `ops/genstats.py` |
171171

172172
cuDNN `reduction_mode` 已映射到 FlagDNN graph 的显式 `dim/keepdim` reduction;本环境 cuDNN standalone reduction 无有效 engine,因此功能测试保留 torch-reference 覆盖。
@@ -175,7 +175,7 @@ cuDNN `reduction_mode` 已映射到 FlagDNN graph 的显式 `dim/keepdim` reduct
175175

176176
| cuDNN op | 参数 | FlagDNN 状态 | 建议实现位置 |
177177
|---|---|---|---|
178-
| `batchnorm` | `input, scale, bias, in_running_mean, in_running_var, epsilon, momentum, peer_stats=[], compute_data_type=NOT_SET, name=''` -> list | 部分;已有 cudnn-style eager + Graph 多输出 forward,返回 `Y/mean/inv_var/next_running_mean/next_running_var``peer_stats` 未支持 | `ops/batchnorm.py`后续补 peer_stats/backward |
178+
| `batchnorm` | `input, scale, bias, in_running_mean, in_running_var, epsilon, momentum, peer_stats=[], compute_data_type=NOT_SET, name=''` -> list | 部分;已有 cudnn-style eager + Graph 多输出 forward,返回 `Y/mean/inv_var/next_running_mean/next_running_var`单设备 `peer_stats=[tensor]` 已可透传并按本地 BN 语义执行,多设备同步 peer stats 仍未支持 | `ops/batchnorm.py`后续补多 GPU peer_stats/backward |
179179
| `batchnorm_inference` | `input, mean, inv_variance, scale, bias, compute_data_type=NOT_SET, name=''` | 已有 eager + Graph;功能/性能已改用 legacy cuDNN standalone `cudnnBatchNormalizationForwardInference` 对标;cuDNN Frontend graph standalone 在本环境无 plan | 已有 |
180180
| `batchnorm_backward` | `grad, input, scale, mean, inv_variance, peer_stats=[], compute_data_type=NOT_SET, name=''` | 缺失 | `ops/batch_norm_backward.py` |
181181
| `layernorm` | `norm_forward_phase, input, scale, bias, epsilon, compute_data_type=NOT_SET, name=''` -> list | 已有 cudnn-style eager + Graph 多输出 forward,返回 `Y/mean/inv_var`;保留原 `layer_norm` API | 已有;backward 另补 |
@@ -187,7 +187,7 @@ cuDNN `reduction_mode` 已映射到 FlagDNN graph 的显式 `dim/keepdim` reduct
187187
| `adalayernorm` | `norm_forward_phase, input, scale, bias=None, epsilon, compute_data_type=NOT_SET, name=''` | 缺失 | `ops/adalayer_norm.py` |
188188
| `adalayernorm_backward` | `grad, input, scale, mean, inv_variance, compute_data_type=NOT_SET, name=''` | 缺失 | `ops/adalayer_norm_backward.py` |
189189

190-
Norm 的 cuDNN API 返回 list,通常包含 output 和保存给 backward 的 stats。FlagDNN graph 已启用 multi-output,并新增 cudnn-style `batchnorm/layernorm/rmsnorm` forward tuple 返回;backward 和少数分布式/peer stats 仍需单独补。
190+
Norm 的 cuDNN API 返回 list,通常包含 output 和保存给 backward 的 stats。FlagDNN graph 已启用 multi-output,并新增 cudnn-style `batchnorm/layernorm/rmsnorm` forward tuple 返回;backward 和真正跨设备同步 peer stats 仍需单独补。
191191

192192
### 4.9 Quant / FP8
193193

@@ -239,7 +239,7 @@ Norm 的 cuDNN API 返回 list,通常包含 output 和保存给 backward 的 s
239239
| `gemm_swiglu_wrapper_sm100` | `a_tensor, b_tensor, alpha=1.0, c_major='n', ab12_dtype=float32, c_dtype=float16, acc_dtype=float32, mma_tiler_mn=(128,128), cluster_shape_mn=None, sfa_tensor=None, sfb_tensor=None, norm_const_tensor=None, sf_vec_size=16, vector_f32=False, ab12_stages=4, stream=None` | 缺失 | `ops/gemm_swiglu.py` |
240240
| `grouped_gemm_*_wrapper_sm100` | grouped/MoE variants with `padded_offsets`, `alpha_tensor`, optional pointer tensors, scale tensors, `mma_tiler_mn`, `cluster_shape_mn`, `sf_vec_size`, scheduler flags | 缺失 | `ops/grouped_gemm.py` plus specialized graph kernels |
241241
| `discrete_grouped_gemm_*_wrapper_sm100` | pointer-based discrete grouped GEMM variants | 缺失 | `ops/discrete_grouped_gemm.py` |
242-
| `rmsnorm_rht_amax_wrapper_sm100` | `x_tensor, w_tensor, eps=1e-5, num_threads=None, rows_per_cta=None, current_stream=None` | 部分;有 rms_norm,但缺 RHT amax | `ops/rmsnorm_rht_amax.py` |
242+
| `rmsnorm_rht_amax_wrapper_sm100` | `x_tensor, w_tensor, eps=1e-5, num_threads=None, rows_per_cta=None, current_stream=None` | 已有;Triton 实现 `RMSNorm + 16 点 normalized RHT + per-CTA amax`,支持官方 wrapper 的 2D/尾部 1 维 squeeze、bf16 row-major 输入和 `rows_per_cta/num_threads` 校验;不是 SM100 CUTE 专用优化 kernel | 已有;后续可补 SM100/CUTE 专用性能路径 |
243243

244244
## 5. 建议新增文件清单
245245

src/flag_dnn/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
relu,
4949
rms_norm,
5050
rmsnorm,
51+
rmsnorm_rht_amax_wrapper_sm100,
5152
silu,
5253
swish,
5354
softmax,
@@ -512,6 +513,7 @@ def all_registered_keys():
512513
"matmul",
513514
"batchnorm_inference",
514515
"reduction",
516+
"rmsnorm_rht_amax_wrapper_sm100",
515517
"compile",
516518
"current_capture",
517519
"get_default_plan_cache",

src/flag_dnn/graph/registry.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,19 +1093,25 @@ def _normalize_batchnorm(
10931093
if missing:
10941094
raise TypeError(f"batchnorm missing {missing[0]}")
10951095
peer_stats = params.pop("peer_stats", [])
1096-
if peer_stats:
1097-
raise NotImplementedError(
1098-
"FlagDNN graph batchnorm does not support peer_stats"
1099-
)
1096+
if peer_stats is None:
1097+
peer_stats = []
1098+
if not isinstance(peer_stats, (list, tuple)):
1099+
raise TypeError("batchnorm peer_stats must be a list or tuple")
11001100
attrs = {
11011101
"compute_data_type": params.pop("compute_data_type", None),
11021102
"name": params.pop("name", ""),
1103+
"peer_stats_count": len(peer_stats),
11031104
}
11041105
if params:
11051106
raise TypeError(
11061107
f"batchnorm got unsupported graph attrs: {sorted(params)}"
11071108
)
1108-
return [ctx.as_value(values[name], name) for name in names], attrs
1109+
input_ids = [ctx.as_value(values[name], name) for name in names]
1110+
input_ids.extend(
1111+
ctx.as_value(peer_stat, f"peer_stats_{index}")
1112+
for index, peer_stat in enumerate(peer_stats)
1113+
)
1114+
return input_ids, attrs
11091115

11101116

11111117
def _normalize_causal_conv1d(
@@ -2356,6 +2362,7 @@ def run(inputs: list[Any], attrs: dict[str, Any]) -> torch.Tensor:
23562362
def _run_batchnorm(flag_ops: Any) -> RunFn:
23572363
def run(inputs: list[Any], attrs: dict[str, Any]) -> Any:
23582364
_require_runtime_backend(inputs[:5], "batchnorm")
2365+
peer_count = int(attrs.get("peer_stats_count", 0))
23592366
return flag_ops.batchnorm(
23602367
inputs[0],
23612368
inputs[1],
@@ -2364,6 +2371,7 @@ def run(inputs: list[Any], attrs: dict[str, Any]) -> Any:
23642371
inputs[4],
23652372
inputs[5],
23662373
inputs[6],
2374+
peer_stats=inputs[7 : 7 + peer_count],
23672375
compute_data_type=attrs.get("compute_data_type"),
23682376
name=attrs.get("name", ""),
23692377
)

src/flag_dnn/ops/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from flag_dnn.ops.layernorm import layernorm
2525
from flag_dnn.ops.rms_norm import rms_norm
2626
from flag_dnn.ops.rmsnorm import rmsnorm
27+
from flag_dnn.ops.rmsnorm_rht_amax import rmsnorm_rht_amax_wrapper_sm100
2728
from flag_dnn.ops.group_norm import group_norm
2829
from flag_dnn.ops.max_pool2d import max_pool2d
2930
from flag_dnn.ops.avg_pool2d import avg_pool2d
@@ -216,6 +217,7 @@ def gelu_approx_tanh(input, *, compute_data_type=None, name=""):
216217
"layer_norm",
217218
"rms_norm",
218219
"rmsnorm",
220+
"rmsnorm_rht_amax_wrapper_sm100",
219221
"group_norm",
220222
"max_pool2d",
221223
"avg_pool2d",

src/flag_dnn/ops/batch_norm.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from flag_dnn.runtime import torch_device_fn
99
from flag_dnn.utils import triton_lang_extension as tle
1010

11-
1211
logger = logging.getLogger(__name__)
1312

1413

@@ -243,10 +242,22 @@ def batchnorm_forward(
243242
momentum,
244243
peer_stats=None,
245244
):
246-
if peer_stats:
245+
if peer_stats is None:
246+
peer_stats = []
247+
peer_stats = list(peer_stats)
248+
if len(peer_stats) > 1:
247249
raise NotImplementedError(
248-
"flag_dnn batchnorm does not support peer_stats"
250+
"flag_dnn batchnorm supports only single-device peer_stats; "
251+
"multi-device synchronized peer stats are not implemented"
249252
)
253+
if peer_stats:
254+
peer_stat = peer_stats[0]
255+
if peer_stat.device != input.device:
256+
raise RuntimeError(
257+
"batchnorm peer_stats tensor must be on the input device"
258+
)
259+
if peer_stat.dtype != torch.float32:
260+
raise RuntimeError("batchnorm peer_stats tensor must be float32")
250261
if input.dim() < 2:
251262
raise RuntimeError("batchnorm expects input rank >= 2")
252263
if not input.is_contiguous():

src/flag_dnn/ops/matmul.py

Lines changed: 98 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def _batched_matmul_kernel(
5454
mask=(k[:, None] < K) & (offs_n[None, :] < N),
5555
other=0.0,
5656
)
57-
acc += tl.dot(a, b)
57+
acc += tl.dot(a, b, input_precision="ieee")
5858

5959
c_base = c_ptr + bid * stride_cb
6060
tl.store(
@@ -109,6 +109,90 @@ def _batched_matmul_3d(A: torch.Tensor, B: torch.Tensor) -> torch.Tensor:
109109
return C
110110

111111

112+
_BATCHED_TRITON_DTYPES = (torch.float16, torch.bfloat16, torch.float32)
113+
114+
115+
def _prod(shape: tuple[int, ...]) -> int:
116+
total = 1
117+
for dim in shape:
118+
total *= int(dim)
119+
return total
120+
121+
122+
def _check_matmul_inputs(A: torch.Tensor, B: torch.Tensor) -> None:
123+
if A.dim() < 2 or B.dim() < 2:
124+
raise NotImplementedError(
125+
"flag_dnn matmul requires tensors with rank >= 2"
126+
)
127+
if A.shape[-1] != B.shape[-2]:
128+
raise RuntimeError(
129+
"mat1 and mat2 shapes cannot be multiplied "
130+
f"({A.shape[-2]}x{A.shape[-1]} and "
131+
f"{B.shape[-2]}x{B.shape[-1]})"
132+
)
133+
if A.device != B.device:
134+
raise RuntimeError(
135+
"matmul: input tensors must be on the same device, "
136+
f"but got {A.device} and {B.device}"
137+
)
138+
if A.dtype != B.dtype:
139+
raise RuntimeError(
140+
"expected mat1 and mat2 to have the same dtype, but got: "
141+
f"{A.dtype} != {B.dtype}"
142+
)
143+
if A.layout != torch.strided or B.layout != torch.strided:
144+
raise NotImplementedError(
145+
"flag_dnn matmul supports dense strided tensors only"
146+
)
147+
148+
149+
def _broadcast_batch_shape(
150+
A: torch.Tensor, B: torch.Tensor
151+
) -> tuple[int, ...]:
152+
try:
153+
return tuple(
154+
torch.broadcast_shapes(tuple(A.shape[:-2]), tuple(B.shape[:-2]))
155+
)
156+
except RuntimeError as exc:
157+
raise RuntimeError(
158+
"matmul batch dimensions are not broadcastable: "
159+
f"{tuple(A.shape)} x {tuple(B.shape)}"
160+
) from exc
161+
162+
163+
def _as_batched_contiguous(
164+
tensor: torch.Tensor, batch_shape: tuple[int, ...]
165+
) -> torch.Tensor:
166+
matrix_shape = (int(tensor.shape[-2]), int(tensor.shape[-1]))
167+
batch_count = _prod(batch_shape)
168+
target_shape = batch_shape + matrix_shape
169+
170+
if tuple(tensor.shape[:-2]) == batch_shape:
171+
batched = tensor.reshape(batch_count, *matrix_shape)
172+
else:
173+
batched = tensor.expand(target_shape).reshape(
174+
batch_count, *matrix_shape
175+
)
176+
return batched if batched.is_contiguous() else batched.contiguous()
177+
178+
179+
def _batched_matmul_broadcast(
180+
A: torch.Tensor, B: torch.Tensor
181+
) -> torch.Tensor:
182+
if A.dtype not in _BATCHED_TRITON_DTYPES:
183+
raise NotImplementedError(
184+
"flag_dnn batched matmul supports fp16, bf16, and fp32 inputs"
185+
)
186+
187+
batch_shape = _broadcast_batch_shape(A, B)
188+
m = int(A.shape[-2])
189+
n = int(B.shape[-1])
190+
A3 = _as_batched_contiguous(A, batch_shape)
191+
B3 = _as_batched_contiguous(B, batch_shape)
192+
C3 = _batched_matmul_3d(A3, B3)
193+
return C3.reshape(batch_shape + (m, n))
194+
195+
112196
def matmul(
113197
A: torch.Tensor,
114198
B: torch.Tensor,
@@ -117,19 +201,19 @@ def matmul(
117201
padding: float = 0.0,
118202
name: str = "",
119203
) -> torch.Tensor:
120-
del compute_data_type, name
121-
if float(padding) != 0.0:
122-
raise NotImplementedError("flag_dnn matmul does not support padding")
204+
del compute_data_type, padding, name
205+
_check_matmul_inputs(A, B)
206+
123207
if A.dim() == 2 and B.dim() == 2:
124208
return mm(A, B)
125-
if A.dim() == 3 and B.dim() == 3 and A.shape[0] == B.shape[0]:
209+
210+
if (
211+
A.dim() == 3
212+
and B.dim() == 3
213+
and A.shape[0] == B.shape[0]
214+
and A.is_contiguous()
215+
and B.is_contiguous()
216+
):
126217
return _batched_matmul_3d(A, B)
127-
if A.dim() < 2 or B.dim() < 2:
128-
raise NotImplementedError(
129-
"flag_dnn matmul requires tensors with rank >= 2"
130-
)
131-
# TODO: implement the remaining torch.matmul broadcasting cases in Triton.
132-
raise NotImplementedError(
133-
"flag_dnn matmul currently supports 2D x 2D and matching-batch "
134-
"3D x 3D inputs only"
135-
)
218+
219+
return _batched_matmul_broadcast(A, B)

0 commit comments

Comments
 (0)