已合并
qbmm v3 golden with new ttk #5976
he_kan创建于 6月11日
qbmm v3 golden with new ttk #5976
已合并
he_kan创建于 6月11日
6 个文件变更+1193-419
@@ -0,0 +1,162 @@
1+#!/usr/bin/env python3
2+# -*- coding: UTF-8 -*-
3+# ----------------------------------------------------------------------------
4+# Copyright (c) 2026 Huawei Technologies Co., Ltd.
5+# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
6+# CANN Open Software License Agreement Version 2.0 (the "License").
7+# Please refer to the License for details. You may not use this file except in compliance with the License.
8+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
9+# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
10+# See LICENSE in the root of the software repository for the full text of the License.
11+# ----------------------------------------------------------------------------
12+import numpy as np
13+from ml_dtypes import bfloat16
14+ 
15+try:
16+ from en_dtypes import float4_e2m1
17+ _HAS_FLOAT4 = True
18+except ImportError:
19+ _HAS_FLOAT4 = False
20+ 
21+__golden__ = {
22+ "kernel": {
23+ "dual_level_quant_batch_matmul": "dual_level_quant_batch_matmul_golden"
24+ }
25+}
26+ 
27+_DTYPE_ATTR_MAP = {1: np.float16, 27: bfloat16}
28+ 
29+ 
30+def customize_inputs(x1, x2, x1_level0_scale, x1_level1_scale, x2_level0_scale,
31+ x2_level1_scale, bias=None, *, dtype=1, transpose_x1=False,
32+ transpose_x2=True, level0_group_size=512, level1_group_size=32,
33+ **kwargs):
34+ input_formats = kwargs.get('input_formats', ())
35+ input_ori_shapes = kwargs.get('input_ori_shapes', ())
36+ if len(input_formats) > 1 and input_formats[1] == 'FRACTAL_NZ':
37+ ori_shape = input_ori_shapes[1] if len(input_ori_shapes) > 1 else None
38+ x2 = _nz_to_nd(x2, ori_shape)
39+ return x1, x2, x1_level0_scale, x1_level1_scale, x2_level0_scale, x2_level1_scale, bias
40+ 
41+ 
42+def pre_compare(*outputs, **kwargs):
43+ return list(outputs)
44+ 
45+ 
46+def dual_level_quant_batch_matmul_golden(x1, x2, x1_level0_scale, x1_level1_scale,
47+ x2_level0_scale, x2_level1_scale, bias=None, *,
48+ dtype=1, transpose_x1=False, transpose_x2=True,
49+ level0_group_size=512, level1_group_size=32,
50+ **kwargs):
51+ x1, x2, x1_level0_scale, x1_level1_scale, x2_level0_scale, x2_level1_scale, bias = customize_inputs(
52+ x1, x2, x1_level0_scale, x1_level1_scale, x2_level0_scale, x2_level1_scale, bias,
53+ dtype=dtype, transpose_x1=transpose_x1, transpose_x2=transpose_x2,
54+ level0_group_size=level0_group_size, level1_group_size=level1_group_size, **kwargs)
55+ 
56+ x1_f32 = x1.astype(np.float32)
57+ x2_f32 = x2.astype(np.float32)
58+ 
59+ if transpose_x2:
60+ x2_f32 = np.swapaxes(x2_f32, -2, -1)
61+ 
62+ x1_l0 = x1_level0_scale.astype(np.float32)
63+ x2_l0 = x2_level0_scale.astype(np.float32)
64+ x1_l1 = _e8m0_to_float(x1_level1_scale)
65+ x2_l1 = _e8m0_to_float(x2_level1_scale)
66+ 
67+ M, K = x1_f32.shape
68+ N = x2_f32.shape[1]
69+ 
70+ num_l1_groups = x1_l1.shape[-2] * x1_l1.shape[-1] if x1_l1.ndim >= 2 else x1_l1.shape[0]
71+ x1_l1_flat = x1_l1.reshape(M, -1)
72+ x2_l1_flat = x2_l1.reshape(N, -1)
73+ 
74+ num_l0_groups = x1_l0.shape[1]
75+ l1_per_l0 = level0_group_size // level1_group_size
76+ 
77+ acc = np.zeros((M, N), dtype=np.float32)
78+ for g0 in range(num_l0_groups):
79+ acc_l0 = np.zeros((M, N), dtype=np.float32)
80+ for g1 in range(l1_per_l0):
81+ g1_global = g0 * l1_per_l0 + g1
82+ if g1_global >= num_l1_groups:
83+ break
84+ k_start = g1_global * level1_group_size
85+ k_end = min(k_start + level1_group_size, K)
86+ if k_end <= k_start:
87+ break
88+ partial = np.matmul(x1_f32[:, k_start:k_end], x2_f32[k_start:k_end, :])
89+ s1 = x1_l1_flat[:, g1_global][:, np.newaxis]
90+ s2 = x2_l1_flat[:, g1_global][np.newaxis, :]
91+ acc_l0 += partial * s1 * s2
92+ acc += x1_l0[:, g0][:, np.newaxis] * x2_l0[g0, :][np.newaxis, :] * acc_l0
93+ 
94+ if bias is not None:
95+ acc = acc + bias.astype(np.float32).reshape(1, -1)
96+ 
97+ output_dtypes = kwargs.get("output_dtypes", None)
98+ if output_dtypes is not None:
99+ acc = _cast_output_dtype(acc, output_dtypes[0])
100+ else:
101+ target_dtype = _DTYPE_ATTR_MAP.get(dtype, np.float16)
102+ acc = acc.astype(target_dtype)
103+ 
104+ return [acc]
105+ 
106+ 
107+class DualLevelQuantBatchMatmulAssets:
108+ 
109+ golden = dual_level_quant_batch_matmul_golden
110+ customize_inputs = customize_inputs
111+ pre_compare = pre_compare
112+ 
113+ tolerance = {
114+ "float16": {
115+ "standard": "BenchmarkCompareStandard",
116+ "avg_re_rtol": 2.0,
117+ "max_re_rtol": 10.0,
118+ "rmse_rtol": 2.0,
119+ "small_value": 0.001,
120+ "small_value_atol": 1e-5,
121+ },
122+ "bfloat16": {
123+ "standard": "BenchmarkCompareStandard",
124+ "avg_re_rtol": 2.0,
125+ "max_re_rtol": 10.0,
126+ "rmse_rtol": 2.0,
127+ "small_value": 0.001,
128+ "small_value_atol": 1e-5,
129+ },
130+ }
131+ 
132+ 
133+def _e8m0_to_float(arr):
134+ raw = arr.view(np.uint8).astype(np.float32)
135+ result = np.power(2.0, raw - 127.0)
136+ result[raw == 255.0] = np.nan
137+ return result
138+ 
139+ 
140+def _cast_output_dtype(arr, dtype_name):
141+ dtype_map = {"float16": np.float16, "float32": np.float32, "bfloat16": bfloat16}
142+ target = dtype_map.get(dtype_name)
143+ if target is not None:
144+ return arr.astype(target)
145+ return arr.astype(dtype_name)
146+ 
147+ 
148+def _nz_to_nd(data, ori_shape=None):
149+ shape = data.shape
150+ batch_dims = len(shape) - 4
151+ perm = list(range(batch_dims)) + [batch_dims + 1, batch_dims + 2, batch_dims + 0, batch_dims + 3]
152+ data = np.transpose(data, perm)
153+ m1 = shape[batch_dims + 1]
154+ m0_actual = shape[batch_dims + 2]
155+ n1 = shape[batch_dims + 0]
156+ n0_actual = shape[batch_dims + 3]
157+ data = data.reshape(*shape[:batch_dims], m1 * m0_actual, n1 * n0_actual)
158+ if ori_shape is not None:
159+ target_M = ori_shape[-2]
160+ target_N = ori_shape[-1]
161+ data = data[..., :target_M, :target_N]
162+ return data
@@ -0,0 +1,142 @@
1+#!/usr/bin/env python3
2+# -*- coding: UTF-8 -*-
3+# ----------------------------------------------------------------------------
4+# Copyright (c) 2026 Huawei Technologies Co., Ltd.
5+# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
6+# CANN Open Software License Agreement Version 2.0 (the "License").
7+# Please refer to the License for details. You may not use this file except in compliance with the License.
8+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
9+# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
10+# See LICENSE in the root of the software repository for the full text of the License.
11+# ----------------------------------------------------------------------------
12+import numpy as np
13+from ml_dtypes import bfloat16, float8_e5m2, float8_e4m3fn
14+ 
15+try:
16+ from en_dtypes import hifloat8
17+ _HAS_HIFLOAT8 = True
18+except ImportError:
19+ _HAS_HIFLOAT8 = False
20+ 
21+__golden__ = {
22+ "kernel": {
23+ "quant_batch_matmul_inplace_add": "quant_batch_matmul_inplace_add_golden"
24+ }
25+}
26+ 
27+ 
28+def customize_inputs(x1, x2, x2_scale, y, x1_scale=None, *, transpose_x1=False,
29+ transpose_x2=False, group_size=0, **kwargs):
30+ return x1, x2, x2_scale, y, x1_scale
31+ 
32+ 
33+def pre_compare(*outputs, **kwargs):
34+ return list(outputs)
35+ 
36+ 
37+def quant_batch_matmul_inplace_add_golden(x1, x2, x2_scale, y, x1_scale=None, *,
38+ transpose_x1=False, transpose_x2=False,
39+ group_size=0, **kwargs):
40+ x1, x2, x2_scale, y, x1_scale = customize_inputs(
41+ x1, x2, x2_scale, y, x1_scale,
42+ transpose_x1=transpose_x1, transpose_x2=transpose_x2,
43+ group_size=group_size, **kwargs)
44+ 
45+ x1_f32 = _to_float32(x1)
46+ x2_f32 = _to_float32(x2)
47+ 
48+ if transpose_x1:
49+ x1_f32 = np.swapaxes(x1_f32, -2, -1)
50+ if transpose_x2:
51+ x2_f32 = np.swapaxes(x2_f32, -2, -1)
52+ 
53+ is_mx = _is_mx_scale(x2_scale)
54+ 
55+ if is_mx:
56+ acc = _mxfp8_matmul(x1_f32, x2_f32, x1_scale, x2_scale)
57+ else:
58+ acc = _per_tensor_matmul(x1_f32, x2_f32, x1_scale, x2_scale)
59+ 
60+ y_out = acc + y.astype(np.float32)
61+ 
62+ output_dtypes = kwargs.get("output_dtypes", None)
63+ if output_dtypes is not None:
64+ y_out = _cast_output_dtype(y_out, output_dtypes[0])
65+ else:
66+ y_out = y_out.astype(np.float32)
67+ 
68+ return [y_out]
69+ 
70+ 
71+def _to_float32(arr):
72+ dtype_str = str(arr.dtype)
73+ if "e4m3" in dtype_str or "e5m2" in dtype_str:
74+ return arr.astype(np.float32)
75+ if "hifloat" in dtype_str or "hif8" in dtype_str:
76+ return arr.astype(np.float32)
77+ return arr.astype(np.float32)
78+ 
79+ 
80+def _is_mx_scale(scale):
81+ if scale is None:
82+ return False
83+ return "e8m0" in str(scale.dtype)
84+ 
85+ 
86+def _e8m0_to_float(arr):
87+ raw = arr.view(np.uint8).astype(np.float32)
88+ result = np.power(2.0, raw - 127.0)
89+ result[raw == 255.0] = np.nan
90+ return result
91+ 
92+ 
93+def _per_tensor_matmul(x1, x2, x1_scale, x2_scale):
94+ acc = np.matmul(x1, x2)
95+ s1 = x1_scale.astype(np.float32).reshape(-1)[0] if x1_scale is not None else 1.0
96+ s2 = x2_scale.astype(np.float32).reshape(-1)[0] if x2_scale is not None else 1.0
97+ acc = acc * (s1 * s2)
98+ return acc
99+ 
100+ 
101+def _mxfp8_matmul(x1, x2, x1_scale, x2_scale):
102+ M, K = x1.shape
103+ N = x2.shape[1]
104+ 
105+ x1s_f = _e8m0_to_float(x1_scale)
106+ x2s_f = _e8m0_to_float(x2_scale)
107+ 
108+ x1s_flat = x1s_f.reshape(M, -1)
109+ x2s_flat = x2s_f.reshape(-1, N)
110+ 
111+ num_groups = x1s_flat.shape[1]
112+ group_size_k = K // num_groups
113+ 
114+ out = np.zeros((M, N), dtype=np.float32)
115+ for g in range(num_groups):
116+ k_start = g * group_size_k
117+ k_end = (g + 1) * group_size_k
118+ partial = np.matmul(x1[:, k_start:k_end], x2[k_start:k_end, :])
119+ s1 = x1s_flat[:, g][:, np.newaxis]
120+ s2 = x2s_flat[g, :][np.newaxis, :]
121+ out += partial * s1 * s2
122+ 
123+ return out
124+ 
125+ 
126+class QuantBatchMatmulInplaceAddAssets:
127+ 
128+ golden = quant_batch_matmul_inplace_add_golden
129+ customize_inputs = customize_inputs
130+ pre_compare = pre_compare
131+ 
132+ tolerance = {
133+ "float32": {"standard": "IsClose", "rtol": 1e-3, "atol": 1e-3},
134+ }
135+ 
136+ 
137+def _cast_output_dtype(arr, dtype_name):
138+ dtype_map = {"float16": np.float16, "float32": np.float32, "bfloat16": bfloat16}
139+ target = dtype_map.get(dtype_name)
140+ if target is not None:
141+ return arr.astype(target)
142+ return arr.astype(dtype_name)
@@ -1,346 +1,594 @@
1-#!/usr/bin/env python31+#!/usr/bin/env python3
2-# -*- coding: UTF-8 -*-2+# -*- coding: UTF-8 -*-
3-# ----------------------------------------------------------------------------3+# ----------------------------------------------------------------------------
4-# Copyright (c) 2026 Huawei Technologies Co., Ltd.4+# Copyright (c) 2026 Huawei Technologies Co., Ltd.
5-# This program is free software, you can redistribute it and/or modify it under the terms and conditions of5+# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
6-# CANN Open Software License Agreement Version 2.0 (the "License").6+# CANN Open Software License Agreement Version 2.0 (the "License").
7-# Please refer to the License for details. You may not use this file except in compliance with the License.7+# Please refer to the License for details. You may not use this file except in compliance with the License.
8-# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,8+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
9-# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.9+# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
10-# See LICENSE in the root of the software repository for the full text of the License.10+# See LICENSE in the root of the software repository for the full text of the License.
11-# ----------------------------------------------------------------------------11+# ----------------------------------------------------------------------------
12-__golden__ = {12+import numpy as np
13- "kernel": {13+import en_dtypes
14- "quant_batch_matmul_v3": "quant_batch_matmul_v3_golden"14+import ml_dtypes
15- }15+np_fp4_e2m1 = en_dtypes.float4_e2m1
16-}16+np_fp4_e1m2 = en_dtypes.float4_e1m2
17- 17+np_hif8 = en_dtypes.hifloat8
18-import torch18+np_mx_scale = en_dtypes.float8_e8m0
19-import os19+np_bfloat16 = ml_dtypes.bfloat16
20-import numpy as np20+np_fp8_e4m3 = ml_dtypes.float8_e4m3fn
21-from ml_dtypes import bfloat1621+np_fp8_e5m2 = ml_dtypes.float8_e5m2
22- 22+np_int4 = ml_dtypes.int4
23-def quant_batch_matmul_v3_golden(x1, x2, scale, offset = None, bias = None, pertoken_scale = None, * ,dtype: int,23+ 
24- transpose_x1: bool = False, transpose_x2: bool = False,24+__golden__ = {
25- group_size:int = 0, **kwargs):25+ "kernel": {
26- 26+ "quant_batch_matmul_v3": "quant_batch_matmul_v3_golden"
27- 27+ }
28- isAscend910B = False28+ }
29- if kwargs['short_soc_version'] in ("Ascend910B", "Ascend910_93"):29+ 
30- isAscend910B = True30+ 
31- deq_scale = scale31+# 参数命名与算子定义(V3 op index)及V5 API的对应关系:
32- 32+# x1 → 算子入参0 x1 (左矩阵) → V5: x1
33- testcase_name = kwargs['testcase_name']33+# x2 → 算子入参1 x2 (右矩阵) → V5: x2
34- 34+# scale → 算子入参2 scale (x2量化scale) → V5: x2Scale; golden接收的是customize_inputs处理后的deq_scale
35- x1_dtype = x1.dtype.name35+# offset → 算子入参3 offset (x2量化offset) → V5: x2Offset
36- x2_dtype = x2.dtype.name36+# bias → 算子入参4 bias → V5: bias
37- deq_scale_dtype = deq_scale.dtype.name37+# pertoken_scale 算子入参5 pertoken_scale (x1量化scale) → V5: x1Scale
38- bias_dtype = None38+# y → 算子出参0 y (结果) → V5: out
39- if bias is not None:39+#
40- bias_dtype = bias.dtype.name40+# 内部变量命名遵循V5语义, 与算子入参名存在明显关联:
41- 41+# x2_scale → 算子入参scale (x2侧量化scale, customize_inputs后为deq_scale)
42- output_dtypes = kwargs['output_dtypes']42+# x1_scale 算子入参pertoken_scale (x1侧量化scale)
43- out_dtype = output_dtypes[0]43+# scale_dtype 算子入参scale的原始dtype (通过kwargs传入)
44- trans_a = transpose_x144+# y_dtype → 算子出参y的dtype
45- trans_b = transpose_x245+#
46- 46+# T-C场景简化说明:
47- groups = group_size47+# customize_inputs已将UINT64 scale转为float32 deq_scale(含高19位截断, 等价于scale_generate).
48- group_size_m, group_size_n, group_size_k = unpack_groupsize(groups)48+# offset不从uint64 scale中提取, 保留原始输入参数(与TTK框架行为一致:
49- 49+# 原始offset输入为None时不参与requant计算, 仅当显式提供时才使用).
50- # mxfp4、mxfp8,输入先和scale相乘,再去做MMAD50+# golden()接收的x2_scale在两种T-C场景下均为float32/bf16,
51- is_mxFP = pertoken_scale is not None and \51+# bias位置由is_bias_vec决定(与TTK golden及_compute_pertoken一致):
52- x1_dtype in ("float4_e2m1", "float4_e1m2", "float8_e4m3fn", "float8_e5m2") and \52+# 非is_bias_vec时bias在×x2Scale前加入(int32域/float32域加法),
53- deq_scale_dtype in ("float8_e8m0",)53+# is_bias_vec时bias在×x2Scale后加入(fixpipe后处理).
54- # fp8hif8,pertoken_scale代表2路scale, 2路scale是用fixpipe中运算的,需要进行高19位与操作,否则会出现精度问题54+# T-C-static(uint64)T-C-dynamic(float32/bf16)合并为单个_compute_tc函数.
55- is_two_scale = pertoken_scale is not None and x1_dtype in ("float8_e4m3fn", "float8_e5m2", "hifloat8") and \55+ 
56- not is_mxFP and deq_scale.shape[0] == 1 and pertoken_scale.shape[0] == 156+def quant_batch_matmul_v3_golden(x1, x2, scale, offset=None, bias=None, pertoken_scale=None,
57- # int8,pertoken_scale代表pertoken,pertoken不是在fixpipe中运算的,无需高19位与操作57+ *, dtype: int, transpose_x1: bool = False, transpose_x2: bool = False,
58- is_pertoken = pertoken_scale is not None and x1_dtype in ('int8', "float8_e4m3fn", "float8_e5m2", "hifloat8") and not is_two_scale58+ group_size: int = 0, **kwargs):
59- is_950_compatible = out_dtype == 'bfloat16' and x1_dtype == 'int8' and deq_scale_dtype != 'uint64' and pertoken_scale is None59+ scale_dtype = kwargs.get('scale_dtype', _dtype_to_str(scale.dtype))
60- is_bias_vec = (x1_dtype == 'int8' or x1_dtype == "int4") and bias is not None and bias_dtype in ('bfloat16', "float16", "float32")60+ x1, x2, scale, offset, bias, pertoken_scale = customize_inputs(
61- is_perblock = x1_dtype in ("float8_e4m3fn", "float8_e5m2", "hifloat8") and deq_scale_dtype in ("float32",) and len(deq_scale.shape) > 1 and len(pertoken_scale.shape) > 161+ x1, x2, scale, offset, bias, pertoken_scale,
62- 62+ dtype=dtype, transpose_x1=transpose_x1, transpose_x2=transpose_x2,
63- # mxFP463+ group_size=group_size, **kwargs)
64- if is_mxFP:64+ y_dtype = kwargs.get('output_dtypes', ['float32'])[0]
65- deq_scale_mx = deq_scale65+ x1_dtype = _dtype_to_str(x1.dtype)
66- pertoken_scale_mx = pertoken_scale66+ x2_dtype = _dtype_to_str(x2.dtype)
67- if x1_dtype in ("float8_e4m3fn", "float8_e5m2"):67+ bias_dtype = _dtype_to_str(bias.dtype) if bias is not None else None
68- x1 = torch.from_numpy(x1.astype(np.float32))68+ x2_scale = scale.astype(np.float32) if scale.dtype != np_mx_scale else scale
69- 69+ x1_scale = pertoken_scale
70- if x2_dtype in ("float8_e4m3fn", "float8_e5m2"):70+ group_size_m, group_size_n, group_size_k = _unpack_groupsize(group_size)
71- x2 = torch.from_numpy(x2.astype(np.float32))71+ quant_mode = _determine_quant_mode(
72- # mxFP4单独处理transpose,统一使用(M,K)和(K,N)格式处理mxFP472+ x1_dtype, x2_dtype, x1_scale, x2_scale, scale_dtype, group_size_n)
73- if trans_a:73+ do_scale_gen = _needs_scale_generate(x1_dtype, x2_scale, bias_dtype, scale_dtype)
74- x1 = np.swapaxes(x1, -1, -2)74+ is_bias_vec = x1_dtype in ('int8', 'int4') and \
75- pertoken_scale_mx = np.swapaxes(pertoken_scale_mx, -1, -2)75+ bias_dtype is not None and \
76- if len(pertoken_scale_mx.shape) == 3:76+ bias_dtype in ('bfloat16', 'float16', 'float32')
77- pertoken_scale_mx = pertoken_scale_mx.reshape(pertoken_scale_mx.shape[0] * pertoken_scale_mx.shape[1], pertoken_scale_mx.shape[2])77+ if offset is not None:
78- pertoken_scale_mx = np.swapaxes(pertoken_scale_mx, -1, -2)78+ offset = offset.astype(np.float32)
79- else:79+ if x2_scale.shape[-1] < offset.shape[-1]:
80- if len(pertoken_scale_mx.shape) == 3:80+ offset = offset[0]
81- pertoken_scale_mx = pertoken_scale_mx.reshape(pertoken_scale_mx.shape[0], pertoken_scale_mx.shape[1] * pertoken_scale_mx.shape[2])81+ if quant_mode == "G-G":
82- if trans_b:82+ y = _compute_mx(x1, x2, x2_scale, x1_scale, bias, bias_dtype,
83- x2 = np.swapaxes(x2, -1, -2)83+ transpose_x1, transpose_x2, y_dtype)
84- if len(deq_scale_mx.shape) == 3:84+ elif quant_mode == "B-B":
85- deq_scale_mx = deq_scale_mx.reshape(deq_scale_mx.shape[0], deq_scale_mx.shape[1] * deq_scale_mx.shape[2])85+ y = _compute_perblock(x1, x2, x2_scale, x1_scale,
86- deq_scale_mx = np.swapaxes(deq_scale_mx, -1, -2)86+ group_size_m, group_size_n, group_size_k,
87- else:87+ transpose_x1, transpose_x2, y_dtype, bias)
88- deq_scale_mx = np.swapaxes(deq_scale_mx, -1, -2)88+ else:
89- if len(deq_scale_mx.shape) == 3:89+ if x1_dtype in ('int8', 'int4') and x2_dtype in ('int8', 'int4'):
90- deq_scale_mx = deq_scale_mx.reshape(deq_scale_mx.shape[0] * deq_scale_mx.shape[1], deq_scale_mx.shape[2])90+ x1 = x1.astype(np.int32)
91- 91+ x2 = x2.astype(np.int32)
92- k_dim = x1.shape[-1]92+ else:
93- if ceil_div(k_dim, 32) % 2 != 0:93+ x1 = x1.astype(np.float32)
94- pertoken_scale_mx = pertoken_scale_mx[:, :-1]94+ x2 = x2.astype(np.float32)
95- deq_scale_mx = deq_scale_mx[:-1, :]95+ if transpose_x1:
96- 96+ x1 = np.transpose(x1, _gen_axes_for_transpose(len(x1.shape) - 2, [1, 0]))
97- # broadcast,每个数对应32个数97+ if transpose_x2:
98- pertoken_scale_mx_broadcast = np.repeat(pertoken_scale_mx, 32, axis=-1)98+ x2 = np.transpose(x2, _gen_axes_for_transpose(len(x2.shape) - 2, [1, 0]))
99- deq_scale_mx_broadcast = np.repeat(deq_scale_mx, 32, axis=-2)99+ matmul_out = np.matmul(x1, x2)
100- x1_dims = len(x1.shape)100+ if y_dtype == 'int8':
101- x2_dims = len(x2.shape)101+ y = _compute_requant(matmul_out, x2_scale, offset, bias, bias_dtype)
102- x1_pad_len = pertoken_scale_mx_broadcast.shape[-1] - x1.shape[-1]102+ elif y_dtype == 'int32':
103- x2_pad_len = deq_scale_mx_broadcast.shape[-2] - x2.shape[-2]103+ y = _compute_int32(matmul_out, bias, bias_dtype)
104- x1 = np.pad(x1, [(0, 0)] * (x1_dims -1) + [(0, x1_pad_len)], mode='constant', constant_values=0)104+ elif quant_mode == "K-C":
105- x2 = np.pad(x2, [(0, 0)] * (x2_dims -2) + [(0, x2_pad_len)] + [(0, 0)], mode='constant', constant_values=0)105+ y = _compute_pertoken(matmul_out, x2_scale, x1_scale, bias, bias_dtype,
106- 106+ is_bias_vec, y_dtype, x1_dtype)
107- x1 = x1 * pertoken_scale_mx_broadcast107+ elif quant_mode == "T-C":
108- x2 = x2 * deq_scale_mx_broadcast108+ y = _compute_tc(matmul_out, x2_scale, bias, bias_dtype,
109- 109+ do_scale_gen, is_bias_vec, y_dtype)
110- # 升精度 & 转torch110+ else:
111- if x1_dtype in ("float8_e4m3fn", "float8_e5m2", "float4_e2m1", "float4_e1m2", "hifloat8"):111+ if matmul_out.dtype == np.int32:
112- x1 = torch.from_numpy(x1.astype(np.float32))112+ matmul_out = matmul_out.astype(np.float32)
113- elif x1_dtype in ("int4",):113+ y = _cast_output_dtype(matmul_out * x2_scale, y_dtype)
114- x1 = torch.from_numpy(x1.astype(np.int32)).to(torch.int32)114+ return [y]
115- else:115+ 
116- x1 = torch.from_numpy(x1).to(torch.int32)116+ 
117- if x2_dtype in ("float8_e4m3fn", "float8_e5m2", "float4_e2m1", "float4_e1m2", "hifloat8"):117+ 
118- x2 = torch.from_numpy(x2.astype(np.float32))118+def customize_inputs(x1, x2, scale, offset=None, bias=None, pertoken_scale=None,
119- elif x2_dtype in ("int4",):119+ *, dtype: int, transpose_x1: bool = False, transpose_x2: bool = False,
120- x2 = torch.from_numpy(x2.astype(np.int32)).to(torch.int32)120+ group_size: int = 0, **kwargs):
121- else:121+ if scale.dtype in (np.uint64, np.int64):
122- x2 = torch.from_numpy(x2).to(torch.int32)122+ deq_scale = _u64_to_deq_scale(scale)
123- 123+ if offset is not None:
124- if not (is_mxFP):124+ offset = _u64_to_offset(scale)
125- if trans_a:125+ else:
126- array_trans = gen_axes_for_transpose(len(x1.shape) - 2, [1, 0])126+ deq_scale = scale
127- x1 = x1.permute(*array_trans)127+ input_formats = kwargs.get('input_formats', ())
128- if trans_b:128+ input_ori_shapes = kwargs.get('input_ori_shapes', ())
129- array_trans = gen_axes_for_transpose(len(x2.shape) - 2, [1, 0])129+ if len(input_formats) > 1 and input_formats[1] == 'FRACTAL_NZ':
130- x2 = x2.permute(*array_trans)130+ ori_shape = input_ori_shapes[1] if len(input_ori_shapes) > 1 else None
131- 131+ x2 = _nz_to_nd(x2, ori_shape)
132- if not is_perblock:132+ if len(input_formats) > 2 and input_formats[2] == 'FRACTAL_NZ' and \
133- out = torch.matmul(x1, x2)133+ kwargs.get('scale_dtype') not in ("uint64", "int64"):
134- else:134+ ori_shape = input_ori_shapes[2] if len(input_ori_shapes) > 2 else None
135- pass135+ deq_scale = _nz_to_nd(deq_scale, ori_shape)
136- 136+ return x1, x2, deq_scale, offset, bias, pertoken_scale
137- if is_mxFP: # mxFP不做scale处理137+ 
138- pass138+ 
139- elif deq_scale_dtype == "uint64":139+def pre_compare(*outputs, **kwargs):
140- deq_scale = np.load(testcase_name + "_deq_scale.npy")140+ return list(outputs)
141- deq_scale_tensor = torch.from_numpy(deq_scale)141+ 
142- else:142+ 
143- deq_scale = deq_scale.astype(np.float32)143+class QuantBatchMatmulV3Assets:
144- deq_scale_tensor = torch.from_numpy(deq_scale)144+ """quant_batch_matmul_v3 算子的全部资产(每个都是可选的)"""
145- 145+ golden = quant_batch_matmul_v3_golden
146- if offset is not None:146+ customize_inputs = customize_inputs
147- offset = np.load(testcase_name + "_offset.npy")147+ pre_compare = pre_compare
148- offset = torch.from_numpy(offset)148+ 
149- if deq_scale_tensor.shape[-1] < offset.shape[-1]:149+ tolerance = {
150- offset = offset[0]150+ "float32": {
151- 151+ "standard": "BenchmarkCompareStandard",
152- if bias is not None and bias_dtype == "int32":152+ "avg_re_rtol": 2.0, "max_re_rtol": 5.0, "rmse_rtol": 2.0,
153- bias = torch.from_numpy(bias).to(torch.int32)153+ "small_value": 1e-6, "small_value_atol": 1e-9,
154- out = torch.add(out, bias)154+ },
155- 155+ "float16": {
156- if is_perblock:156+ "standard": "BenchmarkCompareStandard",
157- pertoken_scale_tensor = torch.from_numpy(pertoken_scale).to(torch.float32)157+ "avg_re_rtol": 2.0, "max_re_rtol": 10.0, "rmse_rtol": 2.0,
158- 158+ "small_value": 0.001, "small_value_atol": 1e-5,
159- if trans_a:159+ },
160- array_trans = gen_axes_for_transpose(len(pertoken_scale_tensor.shape) - 2, [1, 0])160+ "bfloat16": {
161- pertoken_scale_tensor = pertoken_scale_tensor.permute(*array_trans)161+ "standard": "BenchmarkCompareStandard",
162- if trans_b:162+ "avg_re_rtol": 2.0, "max_re_rtol": 10.0, "rmse_rtol": 2.0,
163- array_trans = gen_axes_for_transpose(len(deq_scale_tensor.shape) - 2, [1, 0])163+ "small_value": 0.001, "small_value_atol": 1e-5,
164- deq_scale_tensor = deq_scale_tensor.permute(*array_trans)164+ },
165- 165+ "float8_e5m2": {
166- batch_x1_shape = x1.shape[:-2]166+ "standard": "BenchmarkCompareStandard",
167- batch_x2_shape = x2.shape[:-2]167+ "avg_re_rtol": 2.0, "max_re_rtol": 10.0, "rmse_rtol": 2.0,
168- batch_x1 = [int(i) for i in batch_x1_shape]168+ "small_value": 0.001, "small_value_atol": 1e-5,
169- batch_x2 = [int(i) for i in batch_x2_shape]169+ },
170- import copy170+ "int32": {"standard": "BinaryMatch"},
171- batch_out = copy.deepcopy(batch_x1) if len(batch_x1) > len(batch_x2) else copy.deepcopy(batch_x2)171+ "int8": {"standard": "IsClose", "rtol": 0, "atol": 1},
172- if batch_x2 != batch_x1 and len(batch_x1) != 0 and len(batch_x2) != 0:172+ }
173- idx= 1173+ 
174- for item in reversed(batch_out):174+ 
175- if idx <= len(batch_x1) and idx <= len(batch_x2):175+# ----------------------------------------------------------------------------
176- batch_out[-idx] = max(batch_x1[-idx], batch_x2[-idx])176+# 量化模式计算函数 — 每种量化类型一个函数, 函数前注释给出计算基础流程
177- elif idx <= len(batch_x1):177+# ----------------------------------------------------------------------------
178- batch_out[-idx] = batch_x1[-idx]178+ 
179- else:179+def _compute_mx(x1, x2, x2_scale, x1_scale, bias, bias_dtype,
180- batch_out[-idx] = batch_x2[-idx]180+ transpose_x1, transpose_x2, y_dtype):
181- idx = idx+1181+ # MX(G-G) 计算流程:
182- if batch_x1 != batch_out:182+ # 1. x1/x2转换为float32
183- new_x1_shape = batch_out + list(x1.shape[-2:])183+ # 2. 将x1Scale(E8M0)预乘到x1, 将x2Scale(E8M0)预乘到x2 (含transpose对齐和K轴padding)
184- x1 = torch.broadcast_to(x1, new_x1_shape)184+ # 3. matmul(x1, x2) → 结果已含scale效果
185- new_s_shape = batch_out + list(pertoken_scale_tensor.shape[-2:])185+ # 4. +bias(FP32 opt)
186- pertoken_scale_tensor = torch.broadcast_to(pertoken_scale_tensor, new_s_shape)186+ # 5. cast到y_dtype
187- 187+ x2_scale_mx = x2_scale.copy().astype(np.float32)
188- if batch_x2 != batch_out:188+ x1_scale_mx = x1_scale.copy().astype(np.float32)
189- new_x2_shape = batch_out + list(x2.shape[-2:])189+ x1 = x1.astype(np.float32)
190- x2 = torch.broadcast_to(x2, new_x2_shape)190+ x2 = x2.astype(np.float32)
191- new_s_shape = batch_out + list(deq_scale_tensor.shape[-2:])191+ 
192- deq_scale_tensor = torch.broadcast_to(deq_scale_tensor, new_s_shape)192+ if transpose_x1:
193- 193+ x1 = np.swapaxes(x1, -1, -2)
194- # batch轴合轴194+ x1_scale_mx = np.swapaxes(x1_scale_mx, -1, -2)
195- batch_all = 1195+ if len(x1_scale_mx.shape) == 3:
196- if batch_out:196+ x1_scale_mx = x1_scale_mx.reshape(
197- batch_all = np.prod(batch_out)197+ x1_scale_mx.shape[0] * x1_scale_mx.shape[1], x1_scale_mx.shape[2])
198- x1 = x1.reshape([batch_all] + list(x1.shape[-2:]))198+ x1_scale_mx = np.swapaxes(x1_scale_mx, -1, -2)
199- x2 = x2.reshape([batch_all] + list(x2.shape[-2:]))199+ else:
200- pertoken_scale_tensor = pertoken_scale_tensor.reshape([batch_all] + list(pertoken_scale_tensor.shape[-2:]))200+ if len(x1_scale_mx.shape) == 3:
201- deq_scale_tensor = deq_scale_tensor.reshape([batch_all] + list(deq_scale_tensor.shape[-2:]))201+ x1_scale_mx = x1_scale_mx.reshape(
202- 202+ x1_scale_mx.shape[0], x1_scale_mx.shape[1] * x1_scale_mx.shape[2])
203- 203+ 
204- # Ascend_910B新增biasDtype float32 float16,当Ascend_910B时,不执行这段代码204+ if transpose_x2:
205- if not isAscend910B and not is_950_compatible and not is_bias_vec:205+ x2 = np.swapaxes(x2, -1, -2)
206- # fp8 hif8 的bias 处理206+ if len(x2_scale_mx.shape) == 3:
207- if bias is not None and bias_dtype == "float32" and not (is_mxFP):207+ x2_scale_mx = x2_scale_mx.reshape(
208- bias = torch.from_numpy(bias).to(torch.float32)208+ x2_scale_mx.shape[0], x2_scale_mx.shape[1] * x2_scale_mx.shape[2])
209- out = torch.add(out, bias)209+ x2_scale_mx = np.swapaxes(x2_scale_mx, -1, -2)
210- if is_mxFP:210+ else:
211- if bias is not None:211+ x2_scale_mx = np.swapaxes(x2_scale_mx, -1, -2)
212- bias = torch.from_numpy(bias.astype(np.float32))212+ if len(x2_scale_mx.shape) == 3:
213- out = (out + bias).numpy().astype(out_dtype)213+ x2_scale_mx = x2_scale_mx.reshape(
214- else:214+ x2_scale_mx.shape[0] * x2_scale_mx.shape[1], x2_scale_mx.shape[2])
215- out = out.numpy().astype(out_dtype)215+ 
216- elif is_perblock:216+ k_dim = x1.shape[-1]
217- # 已预处理:x1,x2,deq_scale和pertoken_scale全为非转置217+ if _ceil_div(k_dim, 32) % 2 != 0:
218- 218+ x1_scale_mx = x1_scale_mx[:, :-1]
219- m = x1.shape[-2] # 非转置情况下,m是倒数第二维219+ x2_scale_mx = x2_scale_mx[:-1, :]
220- k = x1.shape[-1] # 非转置情况下,k是倒数第一维220+ 
221- n = x2.shape[-1] # 非转置情况下,n是倒数第一维221+ x1_scale_mx_br = np.repeat(x1_scale_mx, 32, axis=-1)
222- out = torch.zeros(m, n)222+ x2_scale_mx_br = np.repeat(x2_scale_mx, 32, axis=-2)
223- if pertoken_scale_tensor.dim() > 2 or deq_scale_tensor.dim() > 2:223+ 
224- out = torch.zeros(batch_all, m, n)224+ x1_dims = len(x1.shape)
225- pertoken_scale_tensor_m = torch.repeat_interleave(pertoken_scale_tensor, repeats=group_size_m, dim=-2)225+ x2_dims = len(x2.shape)
226- pertoken_scale_tensor_m = pertoken_scale_tensor_m[..., :m, :]226+ x1_pad_len = x1_scale_mx_br.shape[-1] - x1.shape[-1]
227- deq_scale_tensor_n = torch.repeat_interleave(deq_scale_tensor, repeats=group_size_n, dim=-1)227+ x2_pad_len = x2_scale_mx_br.shape[-2] - x2.shape[-2]
228- deq_scale_tensor_n = deq_scale_tensor_n[..., :n]228+ if x1_pad_len > 0:
229- if pertoken_scale_tensor.dim() > 2 or deq_scale_tensor.dim() > 2:229+ x1 = np.pad(x1, [(0, 0)] * (x1_dims - 1) + [(0, x1_pad_len)],
230- for i in range(batch_all):230+ mode='constant', constant_values=0)
231- for k_idx in range((k + group_size_k - 1) // group_size_k):231+ if x2_pad_len > 0:
232- k_start = k_idx * group_size_k232+ x2 = np.pad(x2, [(0, 0)] * (x2_dims - 2) + [(0, x2_pad_len)] + [(0, 0)],
233- k_end = min((k_idx + 1) * group_size_k, k)233+ mode='constant', constant_values=0)
234- scale_mul = pertoken_scale_tensor_m[i, :, k_idx].unsqueeze(1) * deq_scale_tensor_n[i, k_idx, :].unsqueeze(0)234+ 
235- out[i] += torch.matmul(x1[i, :, k_start:k_end], x2[i, k_start:k_end, :]) * scale_mul235+ x1 = x1 * x1_scale_mx_br
236- else:236+ x2 = x2 * x2_scale_mx_br
237- for k_idx in range((k + group_size_k - 1) // group_size_k):237+ 
238- k_start = k_idx * group_size_k238+ y = np.matmul(x1, x2)
239- k_end = min((k_idx + 1) * group_size_k, k)239+ if bias is not None:
240- scale_mul = pertoken_scale_tensor_m[:, k_idx].unsqueeze(1) * deq_scale_tensor_n[k_idx, :].unsqueeze(0)240+ y = _cast_output_dtype(y + bias.astype(np.float32), y_dtype)
241- out += torch.matmul(x1[:, k_start:k_end], x2[k_start:k_end, :]) * scale_mul241+ else:
242- if out_dtype == 'bfloat16':242+ y = _cast_output_dtype(y, y_dtype)
243- out_dtype = bfloat16243+ return y
244- out = (out).numpy().astype(out_dtype) # 暂时只支持fp16/bf16/fp32244+ 
245- 245+ 
246- else:246+def _compute_perblock(x1, x2, x2_scale, x1_scale,
247- if out_dtype == 'int8':247+ group_size_m, group_size_n, group_size_k,
248- out = f32_2_s9(out * deq_scale_tensor)248+ transpose_x1, transpose_x2, y_dtype, bias=None):
249- if offset is not None:249+ # B-B(PerBlock) 计算流程:
250- out = f32_2_s9(out) + f32_2_s9(offset)250+ # 1. x1/x2转换为float32
251- out = np.clip(out, -128, 127).numpy().astype(out_dtype)251+ # 2. 对x1Scale/x2Scale做transpose对齐x1/x2的行列方向
252- elif out_dtype == 'bfloat16':252+ # 3. broadcast对齐batch维度
253- output_dtype = bfloat16253+ # 4. x1Scale沿M轴repeat(groupSizeM), x2Scale沿N轴repeat(groupSizeN)
254- if is_pertoken:254+ # 5. 分K轴block级累加: matmul(x1[:,k_start:k_end], x2[k_start:k_end,:]) × (x1Scale[:,k_idx] × x2Scale[k_idx,:])
255- pertoken_scale_slice = torch.unsqueeze(torch.from_numpy(pertoken_scale), dim=1).to(torch.float32)255+ # 6. cast到y_dtype
256- out = out * deq_scale_tensor * pertoken_scale_slice256+ # 注: B-B不支持bias; 仅FP8/HIF8可走PerBlock(INT8/INT4走V4)
257- elif is_two_scale:257+ x1 = x1.astype(np.float32)
258- two_scale = scale_generate(pertoken_scale * deq_scale)258+ x2 = x2.astype(np.float32)
259- two_scale_tensor = torch.unsqueeze(torch.from_numpy(two_scale), dim=1).to(torch.float32)259+ x1_scale_f = x1_scale.astype(np.float32)
260- out = out * two_scale_tensor260+ x2_scale_f = x2_scale.astype(np.float32)
261- elif is_950_compatible:261+ 
262- if deq_scale.shape[0] == 1 and (bias_dtype != "bfloat16" and bias_dtype != "float32"):262+ if transpose_x1:
263- scale = scale_generate(deq_scale)263+ x1 = np.transpose(x1, _gen_axes_for_transpose(len(x1.shape) - 2, [1, 0]))
264- deq_scale_tensor = torch.unsqueeze(torch.from_numpy(scale), dim=1).to(torch.float32)264+ x1_scale_f = np.transpose(x1_scale_f, _gen_axes_for_transpose(len(x1_scale_f.shape) - 2, [1, 0]))
265- out = out * deq_scale_tensor265+ if transpose_x2:
266- else:266+ x2 = np.transpose(x2, _gen_axes_for_transpose(len(x2.shape) - 2, [1, 0]))
267- out = out * deq_scale_tensor267+ x2_scale_f = np.transpose(x2_scale_f, _gen_axes_for_transpose(len(x2_scale_f.shape) - 2, [1, 0]))
268- # Ascend_910B新增biasDtype float32 float16, 这段代码扩展 or bias_dtype == "float32"268+ 
269- if (isAscend910B or is_950_compatible) and bias is not None and (bias_dtype == "bfloat16" or bias_dtype == "float32"):269+ batch_x1 = list(x1.shape[:-2])
270- bias_fp32 = torch.from_numpy(bias.astype(np.float32))270+ batch_x2 = list(x2.shape[:-2])
271- out = (out + bias_fp32).numpy().astype(output_dtype)271+ batch_ps = list(x1_scale_f.shape[:-2])
272- elif is_bias_vec:272+ batch_ds = list(x2_scale_f.shape[:-2])
273- bias_fp32 = torch.from_numpy(bias.astype(np.float32))273+ 
274- out = (out + bias_fp32).numpy().astype(output_dtype)274+ all_batches = [b for b in [batch_x1, batch_x2, batch_ps, batch_ds] if b]
275- else:275+ if not all_batches:
276- out = out.numpy().astype(output_dtype)276+ batch_out = []
277- elif out_dtype == 'float16':277+ else:
278- if is_pertoken:278+ max_len = max(len(b) for b in all_batches)
279- pertoken_scale_slice = torch.unsqueeze(torch.from_numpy(pertoken_scale), dim=1).to(torch.float32)279+ batch_out = list(all_batches[0])
280- out = out * deq_scale_tensor * pertoken_scale_slice280+ for b in all_batches[1:]:
281- elif is_two_scale:281+ padded_b = [1] * (max_len - len(b)) + b
282- two_scale = scale_generate(pertoken_scale * deq_scale)282+ padded_out = [1] * (max_len - len(batch_out)) + batch_out
283- two_scale_tensor = torch.unsqueeze(torch.from_numpy(two_scale), dim=1).to(torch.float32)283+ for idx in range(max_len):
284- out = out * two_scale_tensor284+ padded_out[idx] = max(padded_out[idx], padded_b[idx])
285- else:285+ batch_out = padded_out
286- out = (out * deq_scale_tensor)286+ 
287- # Ascend_910B新增biasDtype float32 float16287+ if batch_out:
288- if (isAscend910B and bias is not None and (bias_dtype == "float16" or bias_dtype == "float32")) or is_bias_vec:288+ if batch_x1 != batch_out:
289- bias_fp32 = torch.from_numpy(bias.astype(np.float32))289+ x1 = np.broadcast_to(x1, batch_out + list(x1.shape[-2:]))
290- out = (out + bias_fp32).numpy().astype(out_dtype)290+ if batch_x2 != batch_out:
291- else:291+ x2 = np.broadcast_to(x2, batch_out + list(x2.shape[-2:]))
292- out = out.numpy().astype(out_dtype)292+ if batch_ps != batch_out:
293- elif out_dtype == 'hifloat8':293+ x1_scale_f = np.broadcast_to(x1_scale_f, batch_out + list(x1_scale_f.shape[-2:]))
294- out = (out * deq_scale_tensor).numpy().astype(out_dtype)294+ if batch_ds != batch_out:
295- elif out_dtype == 'float8_e4m3fn':295+ x2_scale_f = np.broadcast_to(x2_scale_f, batch_out + list(x2_scale_f.shape[-2:]))
296- out = (out * deq_scale_tensor).numpy().astype(out_dtype)296+ 
297- elif out_dtype == 'float32':297+ batch_all = int(np.prod(batch_out))
298- if is_pertoken:298+ x1 = x1.reshape([batch_all] + list(x1.shape[-2:]))
299- pertoken_scale_slice = torch.unsqueeze(torch.from_numpy(pertoken_scale), dim=1).to(torch.float32)299+ x2 = x2.reshape([batch_all] + list(x2.shape[-2:]))
300- out = (out * deq_scale_tensor * pertoken_scale_slice).numpy().astype(out_dtype)300+ x1_scale_f = x1_scale_f.reshape([batch_all] + list(x1_scale_f.shape[-2:]))
301- elif is_two_scale:301+ x2_scale_f = x2_scale_f.reshape([batch_all] + list(x2_scale_f.shape[-2:]))
302- two_scale = scale_generate(pertoken_scale * deq_scale)302+ 
303- two_scale_tensor = torch.unsqueeze(torch.from_numpy(two_scale), dim=1).to(torch.float32)303+ m = x1.shape[-2]
304- out = (out * two_scale_tensor).numpy().astype(out_dtype)304+ k = x1.shape[-1]
305- else:305+ n = x2.shape[-1]
306- out = (out * deq_scale_tensor).numpy().astype(out_dtype)306+ 
307- elif out_dtype == 'int32':307+ x1_scale_m = np.repeat(x1_scale_f, group_size_m, axis=-2)
308- out = out.numpy().astype(out_dtype)308+ x1_scale_m = x1_scale_m[..., :m, :]
309- else:309+ x2_scale_n = np.repeat(x2_scale_f, group_size_n, axis=-1)
310- print("Please check whether this dtype '{out_dtype}' is supported")310+ x2_scale_n = x2_scale_n[..., :n]
311- 311+ 
312- if os.path.exists(testcase_name + "_deq_scale.npy"):312+ has_batch = x1.ndim > 2
313- os.remove(testcase_name + "_deq_scale.npy")313+ if has_batch:
314- if os.path.exists(testcase_name + "_offset.npy"):314+ y = np.zeros((batch_all, m, n), dtype=np.float32)
315- os.remove(testcase_name + "_offset.npy")315+ for i in range(batch_all):
316- return out316+ for k_idx in range(_ceil_div(k, group_size_k)):
317- 317+ k_start = k_idx * group_size_k
318-def unpack_groupsize(group_size):318+ k_end = min((k_idx + 1) * group_size_k, k)
319- group_size_M = (group_size >> 32) & 0xFFFF319+ x1_s_col = np.expand_dims(x1_scale_m[i, :, k_idx], axis=1)
320- group_size_N = (group_size >> 16) & 0xFFFF320+ x2_s_row = np.expand_dims(x2_scale_n[i, k_idx, :], axis=0)
321- group_size_K = group_size & 0xFFFF321+ scale_mul = x1_s_col * x2_s_row
322- # 当前只有0和1的情况,后续需要推导再改322+ y[i] += np.matmul(x1[i, :, k_start:k_end], x2[i, k_start:k_end, :]) * scale_mul
323- if group_size_M == 0:323+ if batch_out:
324- group_size_M = 1324+ y = y.reshape(batch_out + [m, n])
325- if group_size_N == 0:325+ else:
326- group_size_N = 1326+ y = np.zeros((m, n), dtype=np.float32)
327- return group_size_M, group_size_N, group_size_K327+ for k_idx in range(_ceil_div(k, group_size_k)):
328- 328+ k_start = k_idx * group_size_k
329-def ceil_div(a, b):329+ k_end = min((k_idx + 1) * group_size_k, k)
330- return (a + b - 1) // b330+ x1_s_col = np.expand_dims(x1_scale_m[:, k_idx], axis=1)
331- 331+ x2_s_row = np.expand_dims(x2_scale_n[k_idx, :], axis=0)
332-def gen_axes_for_transpose(offset, base):332+ scale_mul = x1_s_col * x2_s_row
333- return [x for x in range(offset)] + [x + offset for x in base]333+ y += np.matmul(x1[:, k_start:k_end], x2[k_start:k_end, :]) * scale_mul
334- 334+ 
335-def f32_2_s9(array):335+ if bias is not None:
336- array_round = np.round(array)336+ y = y + bias.astype(np.float32)
337- array_round_clip = np.clip(array_round, -256, 255)337+ return _cast_output_dtype(y, y_dtype)
338- return array_round_clip338+ 
339- 339+ 
340-def scale_generate(fp32_deq_scale):340+def _compute_pertoken(matmul_out, x2_scale, x1_scale, bias, bias_dtype,
341- uint32_deq_scale = np.frombuffer(fp32_deq_scale, np.uint32)341+ is_bias_vec, y_dtype, x1_dtype):
342- #与高19位运,模拟硬件342+ # K-C(PerToken参) 计流程:
343- uint32_deq_scale &= 0XFFFFE000343+ # 1. INT32 bias前加 (int32域加法, 与硬件fixpipe一致)
344- fp32_deq_scale = np.frombuffer(uint32_deq_scale, np.float32)344+ # 2. float32: 判断isDoubleScale → merged_scale或分离scale乘法 (float32域)
345- 345+ # 3. float32 bias(非is_bias_vec)和is_bias_vec的bias均在scale乘法后加入 (与硬件fixpipe一致)
346- return fp32_deq_scale346+ # 4. cast到y_dtype
347+ out = matmul_out
348+ if bias is not None and bias_dtype == "int32":
349+ out = out + bias
350+ 
351+ out = out.astype(np.float32)
352+ is_two_scale = x1_dtype in ("float8_e4m3fn", "float8_e5m2", "hifloat8") and \
353+ x1_scale.shape[0] == 1 and x2_scale.shape[0] == 1
354+ if is_two_scale:
355+ merged_scale = x2_scale.astype(np.float32) * x1_scale.astype(np.float32)
356+ merged_scale_slice = np.expand_dims(merged_scale, axis=1)
357+ out = out * merged_scale_slice
358+ else:
359+ x1_scale_slice = np.expand_dims(x1_scale, axis=1).astype(np.float32)
360+ out = out * x2_scale.astype(np.float32) * x1_scale_slice
361+ 
362+ if not is_bias_vec and bias is not None and bias_dtype == "float32":
363+ out = out + bias.astype(np.float32)
364+ if is_bias_vec and bias is not None:
365+ return _cast_output_dtype(out + bias.astype(np.float32), y_dtype)
366+ if y_dtype == 'float32':
367+ return out.astype(np.float32)
368+ return _cast_output_dtype(out, y_dtype)
369+ 
370+ 
371+def _compute_tc(matmul_out, x2_scale, bias, bias_dtype,
372+ do_scale_gen, is_bias_vec, y_dtype):
373+ # T-C(PerTensor/PerChannel, x1Scale不参与) 计算流程:
374+ # customize_inputs已将UINT64 scale转为float32 deq_scale,
375+ # T-C-static(uint64)和T-C-dynamic(float32/bf16)合并处理, bias位置由is_bias_vec决定.
376+ #
377+ # 计算流程:
378+ # 1. 非is_bias_vec: +bias (int32域/float32域加法, 反量化前加入, 与TTK golden及_compute_pertoken一致)
379+ # 2. 转float32
380+ # 3. 若do_scale_gen=True: 截断x2Scale高19位
381+ # 4. x2Scale若1维则expand到2维; out = out × x2Scale (float32域乘法)
382+ # 5. is_bias_vec时+bf16/fp16/fp32 bias (fixpipe后处理, 反量化后加入)
383+ # 6. cast到y_dtype
384+ out = matmul_out
385+ 
386+ if not is_bias_vec and bias is not None:
387+ if bias_dtype == "int32":
388+ out = out + bias
389+ elif bias_dtype in ("float32", "bfloat16"):
390+ out = out.astype(np.float32) + bias.astype(np.float32)
391+ 
392+ out = out.astype(np.float32)
393+ if do_scale_gen:
394+ x2_scale = _scale_generate(x2_scale)
395+ if x2_scale.ndim == 1:
396+ x2_scale = np.expand_dims(x2_scale, axis=0)
397+ out = out * x2_scale.astype(np.float32)
398+ 
399+ if is_bias_vec and bias is not None:
400+ return _cast_output_dtype(out + bias.astype(np.float32), y_dtype)
401+ if y_dtype == 'float32':
402+ return out.astype(np.float32)
403+ return _cast_output_dtype(out, y_dtype)
404+ 
405+ 
406+def _compute_requant(matmul_out, x2_scale, offset, bias, bias_dtype):
407+ # Requant(y=INT8) 计算流程 — T-C的输出dtype变体:
408+ # 1. +INT32 bias (int32域加法, 与TTK一致, 反量化前加入)
409+ # 2. 转float32: f32_2_s9(out × x2Scale) — float32域乘法 + 9bit量化截断
410+ # 3. +f32_2_s9(offset) (若有)
411+ # 4. clip[-128, 127] → int8
412+ # 注: 仅INT8×INT8+UINT64 scale支持requant
413+ out = matmul_out
414+ if bias is not None and bias_dtype == "int32":
415+ out = out + bias
416+ 
417+ out = out.astype(np.float32)
418+ out = _f32_2_s9(out * x2_scale.astype(np.float32))
419+ if offset is not None:
420+ out = _f32_2_s9(out) + _f32_2_s9(offset)
421+ return np.clip(out, -128, 127).astype(np.int8)
422+ 
423+ 
424+def _compute_int32(matmul_out, bias, bias_dtype):
425+ # 纯整数(y=INT32) 计算流程 — scale不参与计算的输出dtype变体:
426+ # 1. +INT32 bias (int32域加法, 与TTK一致); float32 bias在float32域加法
427+ # 2. cast到int32
428+ # 注: 仅INT8×INT8支持; scale不参与, bias位置不影响最终结果
429+ out = matmul_out
430+ if bias is not None:
431+ if bias_dtype == "int32":
432+ out = out + bias
433+ else:
434+ out = out.astype(np.float32) + bias.astype(np.float32)
435+ return out.astype(np.int32)
436+ 
437+ 
438+# ----------------------------------------------------------------------------
439+# 量化模式判定与辅助函数
440+# ----------------------------------------------------------------------------
441+ 
442+def _determine_quant_mode(x1_dtype, x2_dtype, x1_scale, x2_scale,
443+ scale_dtype, group_size_n):
444+ # 量化模式判定流程对齐op_tiling代码: 双轴(x1+x2)独立判定 → 组合映射
445+ # Step1判x2(x2Scale侧): P1(MX)→P2(PerBlock)→P3(PerTensor)→P4(PerChannel)
446+ # Step2判x1(x1Scale侧): P0(skip)→P1(MX)→P2(PerBlock)→P3(PERTENSOR/isDoubleScale)→P4(PERTOKEN)
447+ # Step3组合映射 → 量化场景名 + 公式
448+ # 输出dtype变体(y=INT8/INT32)不影响量化模式判定, 由_compute_requant/_compute_int32处理
449+ # T-C不再区分static/dynamic子模式: customize_inputs已将UINT64转为float32 deq_scale,
450+ # bias位置由is_bias_vec决定(非is_bias_vec→scale前加, is_bias_vec→scale后加)
451+ #
452+ # 模式名(与op_tiling代码boolean flags的对应):
453+ # G-G = isMxPerGroup (MX_PERGROUP+MX_PERGROUP)
454+ # B-B = isPerBlock (PERBLOCK+PERBLOCK, 仅FP8/HIF8)
455+ # K-C = isPertoken+isPerChannel/isPerTensor (PERTOKEN+PERCHANNEL/PERTENSOR,
456+ # 或PERTENSOR+PERTENSOR(isDoubleScale); 公式统一, numpy广播无需区分)
457+ # T-C = isPerTensor/isPerChannel (DEFAULT+PERTENSOR/PERCHANNEL, bias位置由is_bias_vec决定)
458+ fp8_hif8 = ("float8_e4m3fn", "float8_e5m2", "hifloat8")
459+ fp4_fp8 = ("float4_e2m1", "float4_e1m2", "float8_e4m3fn", "float8_e5m2")
460+ 
461+ # Step1 P1 + Step2 P1: MX — both x1 and x2 must be fp4/fp8
462+ # FP8×FP4 mx伪量化已去除: x1和x2必须同属fp4或fp8族
463+ if x1_scale is not None and \
464+ x1_dtype in fp4_fp8 and x2_dtype in fp4_fp8 and \
465+ scale_dtype == "float8_e8m0":
466+ return "G-G"
467+ 
468+ # Step1 P2 + Step2 P2: PerBlock (B-B) — 仅FP8/HIF8, 不含INT8/INT4
469+ # 代码条件: isFp8Hif8Input ∧ scaleDtype==FP32 ∧ scaleShapeLen>1
470+ # ∧ (scaleShapeLen>2 ∨ scaleDim0!=1 ∨ groupSizeN>1)
471+ # isFp8Hif8Input ∧ perTokenScaleDtype==FP32 ∧ pertokenLen>1
472+ if x1_scale is not None and \
473+ x1_dtype in fp8_hif8 and \
474+ scale_dtype == "float32" and \
475+ _dtype_to_str(x1_scale.dtype) == "float32" and \
476+ x2_scale.ndim > 1 and \
477+ (x2_scale.ndim > 2 or x2_scale.shape[0] != 1 or group_size_n > 1) and \
478+ x1_scale.ndim > 1:
479+ return "B-B"
480+ 
481+ # Step2 P3-P4: x1Scale参与 — K-C/T-C动态FP8/HIF8/T-T动态(isDoubleScale)
482+ # 公式统一: out = matmul × x2Scale × x1Scale [+bias]
483+ if x1_scale is not None:
484+ return "K-C"
485+ 
486+ # Step2 P0: x1Scale不参与(pertoken_scale=null) — T-C
487+ # bias位置由is_bias_vec决定(与TTK golden及_compute_pertoken一致):
488+ # 非is_bias_vec → bias在scale前加入 (int32域/float32域加法)
489+ # is_bias_vec → bias在scale后加入 (fixpipe后处理)
490+ return "T-C"
491+ 
492+ 
493+def _needs_scale_generate(x1_dtype, x2_scale, bias_dtype, scale_dtype):
494+ # 950硬件对int8/int4输入做fixpipe精度截断(scale_generate高19位掩码)
495+ # 条件: int8/int4 + 单行x2Scale + bias不是bf16/f32 + x2Scale原始dtype非uint64/int64
496+ # uint64/int64的deq_scale已是截断精度(customize_inputs中_u64_to_deq_scale已做0xFFFFE000掩码),
497+ # 即使apply scale_generate也无副作用(已是截断值再截断=原值), 但为避免不必要的计算, 仍跳过
498+ if x1_dtype not in ("int8", "int4"):
499+ return False
500+ if scale_dtype in ("uint64", "int64"):
501+ return False
502+ if x2_scale.shape[0] != 1:
503+ return False
504+ if bias_dtype in ("bfloat16", "float32"):
505+ return False
506+ return True
507+ 
508+ 
509+def _u64_to_deq_scale(u64_scale):
510+ deq_u32 = u64_scale.astype(np.uint32).copy()
511+ deq_u32 &= np.uint32(0xFFFFE000)
512+ return deq_u32.view(np.float32).reshape(u64_scale.shape)
513+ 
514+ 
515+def _u64_to_offset(u64_scale):
516+ raw = (u64_scale.astype(np.uint64) >> np.uint64(37)) & np.uint64(0x1FF)
517+ raw = raw.astype(np.int64)
518+ sign_mask = np.int64(0x100)
519+ raw = np.where(raw & sign_mask, raw - np.int64(0x200), raw)
520+ return raw.astype(np.float32).reshape(u64_scale.shape)
521+ 
522+ 
523+def _scale_generate(fp32_array):
524+ u32 = fp32_array.view(np.uint32).copy()
525+ u32 &= np.uint32(0xFFFFE000)
526+ return u32.view(np.float32)
527+ 
528+ 
529+def _f32_2_s9(array):
530+ return np.clip(np.round(array), -256, 255)
531+ 
532+ 
533+def _ceil_div(a, b):
534+ return (a + b - 1) // b
535+ 
536+ 
537+def _unpack_groupsize(group_size):
538+ gs_m = (group_size >> 32) & 0xFFFF
539+ gs_n = (group_size >> 16) & 0xFFFF
540+ gs_k = group_size & 0xFFFF
541+ if gs_m == 0:
542+ gs_m = 1
543+ if gs_n == 0:
544+ gs_n = 1
545+ if gs_k == 0:
546+ gs_k = 1
547+ return gs_m, gs_n, gs_k
548+ 
549+ 
550+def _gen_axes_for_transpose(offset, base):
551+ return [x for x in range(offset)] + [x + offset for x in base]
552+ 
553+ 
554+def _cast_output_dtype(arr, dtype_name):
555+ dtype_map = {
556+ "float16": np.float16, "float32": np.float32, "int32": np.int32,
557+ "int8": np.int8, "bfloat16": np_bfloat16,
558+ "hifloat8": np_hif8, "float8_e4m3fn": np_fp8_e4m3,
559+ "float8_e5m2": np_fp8_e5m2,
560+ }
561+ target = dtype_map.get(dtype_name)
562+ if target is not None:
563+ return arr.astype(target)
564+ return arr.astype(dtype_name)
565+ 
566+ 
567+def _dtype_to_str(dtype):
568+ dtype_map = {
569+ np.float16: "float16", np.float32: "float32", np.float64: "float64",
570+ np.int8: "int8", np.int32: "int32", np.uint64: "uint64",
571+ np_bfloat16: "bfloat16", np_int4: "int4",
572+ np_fp8_e4m3: "float8_e4m3fn", np_fp8_e5m2: "float8_e5m2",
573+ np_hif8: "hifloat8", np_mx_scale: "float8_e8m0",
574+ np_fp4_e2m1: "float4_e2m1", np_fp4_e1m2: "float4_e1m2",
575+ }
576+ return dtype_map.get(dtype, str(dtype))
577+ 
578+ 
579+def _nz_to_nd(data, ori_shape):
580+ if ori_shape is None:
581+ raise ValueError("ori_shape is required for NZ→ND conversion to remove fractal padding")
582+ shape = data.shape
583+ batch_dims = len(shape) - 4
584+ perm = list(range(batch_dims)) + [batch_dims + 1, batch_dims + 2, batch_dims + 0, batch_dims + 3]
585+ data = np.transpose(data, perm)
586+ m1 = shape[batch_dims + 1]
587+ m0_actual = shape[batch_dims + 2]
588+ n1 = shape[batch_dims + 0]
589+ n0_actual = shape[batch_dims + 3]
590+ data = data.reshape(*shape[:batch_dims], m1 * m0_actual, n1 * n0_actual)
591+ target_M = ori_shape[-2]
592+ target_N = ori_shape[-1]
593+ data = data[..., :target_M, :target_N]
594+ return data
@@ -16,48 +16,82 @@ __input__ = {
16}16}
17 17 
18import numpy as np18import numpy as np
19+import warnings
20+ 
21+UNSIGNED_ONLY_DTYPES = ("float8_e8m0",)
22+ 
23+ 
24+def _check_and_fix_unsigned_dtype_nan(tensor, input_index, input_ranges, testcase_name):
25+ if tensor is None:
26+ return tensor
27+ dtype_str = str(tensor.dtype)
28+ if not any(d in dtype_str for d in UNSIGNED_ONLY_DTYPES):
29+ return tensor
30+ fp32_check = tensor.astype(np.float32)
31+ nan_count = int(np.isnan(fp32_check).sum())
32+ if nan_count == 0:
33+ return tensor
34+ orig_range = None
35+ if input_ranges is not None:
36+ try:
37+ orig_range = input_ranges[input_index] if input_index < len(input_ranges) else None
38+ except (TypeError, IndexError):
39+ pass
40+ orig_low, orig_high = -10, 10
41+ if orig_range is not None and len(orig_range) >= 2:
42+ orig_low = orig_range[0] if orig_range[0] is not None else -10
43+ orig_high = orig_range[1] if orig_range[1] is not None else 10
44+ new_high = max(abs(float(orig_low)), abs(float(orig_high)), 1.0)
45+ new_low = max(new_high * 0.001, 1e-6)
46+ warnings.warn(
47+ f"[{testcase_name}] Input {input_index} dtype={dtype_str} contains {nan_count} NaN "
48+ f"values (original range ({orig_low}, {orig_high}) includes negatives). "
49+ f"Regenerating with positive range ({new_low}, {new_high})."
50+ )
51+ new_data = np.random.uniform(new_low, new_high, tensor.shape).astype(np.float32)
52+ return new_data.astype(tensor.dtype)
53+ 
19 54 
20def quant_batch_matmul_v3_inputs(x1, x2, scale, offset = None, bias = None, pertoken_scale = None, *, dtype: int,55def quant_batch_matmul_v3_inputs(x1, x2, scale, offset = None, bias = None, pertoken_scale = None, *, dtype: int,
21 transpose_x1: bool = False, transpose_x2: bool = False,56 transpose_x1: bool = False, transpose_x2: bool = False,
22 group_size:int = 0, **kwargs):57 group_size:int = 0, **kwargs):
23- # 获取数据
24 input_deq_scale = scale58 input_deq_scale = scale
25 output_dtypes = kwargs['output_dtypes']59 output_dtypes = kwargs['output_dtypes']
26 out_dtype = output_dtypes[0]60 out_dtype = output_dtypes[0]
27- testcase_name = kwargs['testcase_name']61+ testcase_name = kwargs.get('testcase_name', 'unknown')
62+ input_ranges = kwargs.get('input_ranges', None)
28 63 
29- # convert scale to uint6464+ x1 = _check_and_fix_unsigned_dtype_nan(x1, 0, input_ranges, testcase_name)
30- if input_deq_scale.dtype == "uint64" and pertoken_scale is None:65+ x2 = _check_and_fix_unsigned_dtype_nan(x2, 1, input_ranges, testcase_name)
66+ input_deq_scale = _check_and_fix_unsigned_dtype_nan(input_deq_scale, 2, input_ranges, testcase_name)
67+ pertoken_scale = _check_and_fix_unsigned_dtype_nan(pertoken_scale, 5, input_ranges, testcase_name)
68+ 
69+ if input_deq_scale.dtype in ("uint64", "int64") and pertoken_scale is None:
31 deq_scale_shape = scale.shape70 deq_scale_shape = scale.shape
32- input_deq_scale = scale_generate(deq_scale_shape, offset, out_dtype, testcase_name)71+ target_dtype = input_deq_scale.dtype
72+ input_deq_scale = scale_generate(deq_scale_shape, offset, out_dtype)
73+ if target_dtype == "int64":
74+ input_deq_scale = input_deq_scale.astype(np.int64)
33 75 
34 return x1, x2, input_deq_scale, offset, bias, pertoken_scale76 return x1, x2, input_deq_scale, offset, bias, pertoken_scale
35 77 
36-def scale_generate(deq_scale_shape, offset, out_dtype, testcase_name):78+def scale_generate(deq_scale_shape, offset, out_dtype):
37 has_offset = offset is not None79 has_offset = offset is not None
38 80 
39 fp32_deq_scale = np.random.uniform(low=-5, high=5, size=deq_scale_shape).astype(np.float32)81 fp32_deq_scale = np.random.uniform(low=-5, high=5, size=deq_scale_shape).astype(np.float32)
40 uint32_deq_scale = np.frombuffer(fp32_deq_scale, np.uint32).reshape(deq_scale_shape)82 uint32_deq_scale = np.frombuffer(fp32_deq_scale, np.uint32).reshape(deq_scale_shape)
41- # 与高19位运算,模拟硬件
42 uint32_deq_scale &= 0XFFFFE00083 uint32_deq_scale &= 0XFFFFE000
43 84 
44 if has_offset:85 if has_offset:
45 offset_shape = offset.shape86 offset_shape = offset.shape
46 fp32_offset = np.random.uniform(low=-5, high=5, size=offset_shape).astype(np.float32)87 fp32_offset = np.random.uniform(low=-5, high=5, size=offset_shape).astype(np.float32)
47 88 
48- # dequant
49 if out_dtype != "int8":89 if out_dtype != "int8":
50- fp32_deq_scale = np.frombuffer(uint32_deq_scale, np.float32).reshape(deq_scale_shape)
51- np.save(testcase_name + "_deq_scale.npy", fp32_deq_scale)
52 uint64_deq_scale = np.zeros(deq_scale_shape, np.uint64)90 uint64_deq_scale = np.zeros(deq_scale_shape, np.uint64)
53 uint64_deq_scale |= np.uint64(uint32_deq_scale)91 uint64_deq_scale |= np.uint64(uint32_deq_scale)
54- # requant
55 elif out_dtype == "int8":92 elif out_dtype == "int8":
56- fp32_deq_scale = np.frombuffer(uint32_deq_scale, np.float32).reshape(deq_scale_shape)
57- np.save(testcase_name + "_deq_scale.npy", fp32_deq_scale)
58 s9_offset = 093 s9_offset = 0
59 if has_offset:94 if has_offset:
60- np.save(testcase_name + "_offset.npy", fp32_offset)
61 s9_offset = f32_2_s9(fp32_offset).astype(int).reshape(offset_shape)95 s9_offset = f32_2_s9(fp32_offset).astype(int).reshape(offset_shape)
62 s9_offset &= 0X1FF96 s9_offset &= 0X1FF
63 s9_offset = s9_offset[0] if deq_scale_shape[-1] < offset_shape[-1] else s9_offset97 s9_offset = s9_offset[0] if deq_scale_shape[-1] < offset_shape[-1] else s9_offset
@@ -1,27 +1,27 @@
1-testcase_name,op_name,input_shapes,input_ori_shapes,output_shapes,output_ori_shapes,input_dtypes,output_dtypes,input_formats,input_ori_formats,output_formats,output_ori_formats,attributes,input_data_ranges,precision_tolerances,absolute_precision,is_enabled,m_feat,n_feat,k_feat1+testcase_name,op_name,input_shapes,input_ori_shapes,output_shapes,output_ori_shapes,input_dtypes,output_dtypes,input_formats,input_ori_formats,output_formats,output_ori_formats,attributes,input_data_ranges,precision_tolerances,absolute_precision,is_enabled,m_feat,n_feat,k_feat
2-qbmm_BB_case0001,quant_batch_matmul_v3,"((1, 1008), (1008, 144), (8, 2), None, None, (1, 8))","((1, 1008), (1008, 144), (8, 2), None, None, (1, 8))","((1, 144),)","((1, 144),)","('float8_e4m3fn', 'float8_e5m2', 'float32', 'int8', 'int8', 'float32')",float16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': False, 'group_size': 549764202624}","((-3, 3),)","((0.001, 0.001),)",,1,one,multiple_of_16,multiple_of_162+qbmm_BB_case0001,quant_batch_matmul_v3,"((1, 1008), (1008, 144), (8, 2), None, None, (1, 8))","((1, 1008), (1008, 144), (8, 2), None, None, (1, 8))","((1, 144),)","((1, 144),)","('float8_e4m3fn', 'float8_e5m2', 'float32', 'int8', 'int8', 'float32')",'float16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': False, 'group_size': 549764202624}","((-3, 3),)","((0.001, 0.001),)",,1,one,multiple_of_16,multiple_of_16
3-qbmm_BB_case0002,quant_batch_matmul_v3,"((1296, 464), (1296, 1312), (11, 11), None, None, (11, 4))","((1296, 464), (1296, 1312), (11, 11), None, None, (11, 4))","((464, 1312),)","((464, 1312),)","('float8_e5m2', 'float8_e5m2', 'float32', 'int8', 'int8', 'float32')",float16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': True, 'transpose_x2': False, 'group_size': 549764202624}","((-1000, 1000),)","((0.001, 0.001),)",,1,multiple_of_16,multiple_of_32,multiple_of_163+qbmm_BB_case0002,quant_batch_matmul_v3,"((1296, 464), (1296, 1312), (11, 11), None, None, (11, 4))","((1296, 464), (1296, 1312), (11, 11), None, None, (11, 4))","((464, 1312),)","((464, 1312),)","('float8_e5m2', 'float8_e5m2', 'float32', 'int8', 'int8', 'float32')",'float16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': True, 'transpose_x2': False, 'group_size': 549764202624}","((-1000, 1000),)","((0.001, 0.001),)",,1,multiple_of_16,multiple_of_32,multiple_of_16
4-qbmm_BB_case0004,quant_batch_matmul_v3,"((1663, 883), (861, 883), (7, 7), None, None, (13, 7))","((1663, 883), (861, 883), (7, 7), None, None, (13, 7))","((1663, 861),)","((1663, 861),)","('float8_e4m3fn', 'float8_e4m3fn', 'float32', 'int8', 'int8', 'float32')",float16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': True, 'group_size': 549764202624}","((-10, 10),)","((0.001, 0.001),)",,1,prime,random,prime4+qbmm_BB_case0004,quant_batch_matmul_v3,"((1663, 883), (861, 883), (7, 7), None, None, (13, 7))","((1663, 883), (861, 883), (7, 7), None, None, (13, 7))","((1663, 861),)","((1663, 861),)","('float8_e4m3fn', 'float8_e4m3fn', 'float32', 'int8', 'int8', 'float32')",'float16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': True, 'group_size': 549764202624}","((-10, 10),)","((0.001, 0.001),)",,1,prime,random,prime
5-qbmm_BB_case0003,quant_batch_matmul_v3,"((944, 1936), (1808, 944), (15, 8), None, None, (8, 16))","((944, 1936), (1808, 944), (15, 8), None, None, (8, 16))","((1936, 1808),)","((1936, 1808),)","('float8_e5m2', 'float8_e4m3fn', 'float32', 'int8', 'int8', 'float32')",float16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': True, 'transpose_x2': True, 'group_size': 549764202624}","((-10, 10),)","((0.001, 0.001),)",,1,multiple_of_16,multiple_of_16,multiple_of_165+qbmm_BB_case0003,quant_batch_matmul_v3,"((944, 1936), (1808, 944), (15, 8), None, None, (8, 16))","((944, 1936), (1808, 944), (15, 8), None, None, (8, 16))","((1936, 1808),)","((1936, 1808),)","('float8_e5m2', 'float8_e4m3fn', 'float32', 'int8', 'int8', 'float32')",'float16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': True, 'transpose_x2': True, 'group_size': 549764202624}","((-10, 10),)","((0.001, 0.001),)",,1,multiple_of_16,multiple_of_16,multiple_of_16
6-qbmm_BB_case0015,quant_batch_matmul_v3,"((1741, 1344), (1741, 941), (14, 8), None, None, (14, 11))","((1741, 1344), (1741, 941), (14, 8), None, None, (14, 11))","((1344, 941),)","((1344, 941),)","('hifloat8', 'hifloat8', 'float32', 'int8', 'int8', 'float32')",float32,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': True, 'transpose_x2': False, 'group_size': 549764202624}","((-10, 10),)","((0.001, 0.001),)",,1,random,random,random6+qbmm_BB_case0015,quant_batch_matmul_v3,"((1741, 1344), (1741, 941), (14, 8), None, None, (14, 11))","((1741, 1344), (1741, 941), (14, 8), None, None, (14, 11))","((1344, 941),)","((1344, 941),)","('hifloat8', 'hifloat8', 'float32', 'int8', 'int8', 'float32')",'float32',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': True, 'transpose_x2': False, 'group_size': 549764202624}","((-10, 10),)","((0.001, 0.001),)",,1,random,random,random
7-qbmm_BB_case0029,quant_batch_matmul_v3,"((5, 6, 7, 1296, 751), (5, 6, 7, 751, 1), (5, 6, 7, 6, 1), None, None, (5, 6, 7, 11, 6))","((5, 6, 7, 1296, 751), (5, 6, 7, 751, 1), (5, 6, 7, 6, 1), None, None, (5, 6, 7, 11, 6))","((5, 6, 7, 1296, 1),)","((5, 6, 7, 1296, 1),)","('hifloat8', 'hifloat8', 'float32', 'int8', 'int8', 'float32')",bfloat16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': False, 'group_size': 549764202624}","((-10, 10),)","((0.001, 0.001),)",,1,multiple_of_16,one,prime7+qbmm_BB_case0029,quant_batch_matmul_v3,"((5, 6, 7, 1296, 751), (5, 6, 7, 751, 1), (5, 6, 7, 6, 1), None, None, (5, 6, 7, 11, 6))","((5, 6, 7, 1296, 751), (5, 6, 7, 751, 1), (5, 6, 7, 6, 1), None, None, (5, 6, 7, 11, 6))","((5, 6, 7, 1296, 1),)","((5, 6, 7, 1296, 1),)","('hifloat8', 'hifloat8', 'float32', 'int8', 'int8', 'float32')",'bfloat16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': False, 'group_size': 549764202624}","((-10, 10),)","((0.001, 0.001),)",,1,multiple_of_16,one,prime
8-qbmm_MXFP4_case0001,quant_batch_matmul_v3,"((197, 960), (854, 960), (854, 15, 2), None, None, (197, 15, 2))","((197, 960), (854, 960), (854, 15, 2), None, None, (197, 15, 2))","((197, 854),)","((197, 854),)","('float4_e2m1', 'float4_e2m1', 'float8_e8m0', 'int8', 'int8', 'float8_e8m0')",float32,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': True, 'group_size': 4295032864}","((-3, 3),)","((0.001, 0.001),)",,1,random,random,multiple_of_328+qbmm_MXFP4_case0001,quant_batch_matmul_v3,"((197, 960), (854, 960), (854, 15, 2), None, None, (197, 15, 2))","((197, 960), (854, 960), (854, 15, 2), None, None, (197, 15, 2))","((197, 854),)","((197, 854),)","('float4_e2m1', 'float4_e2m1', 'float8_e8m0', 'int8', 'int8', 'float8_e8m0')",'float32',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': True, 'group_size': 4295032864}","((-3, 3),)","((0.001, 0.001),)",,1,random,random,multiple_of_32
9-qbmm_KT_case0007,quant_batch_matmul_v3,"((1, 1), (1, 1), (1,), None, None, (1,))","((1, 1), (1, 1), (1,), None, None, (1,))","((1, 1),)","((1, 1),)","('float8_e4m3fn', 'float8_e4m3fn', 'float32', 'int8', 'int8', 'float32')",float16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': False}","((-10, 10),)","((0.001, 0.001),)",,1,one,one,one9+qbmm_KT_case0007,quant_batch_matmul_v3,"((1, 1), (1, 1), (1,), None, None, (1,))","((1, 1), (1, 1), (1,), None, None, (1,))","((1, 1),)","((1, 1),)","('float8_e4m3fn', 'float8_e4m3fn', 'float32', 'int8', 'int8', 'float32')",'float16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': False}","((-10, 10),)","((0.001, 0.001),)",,1,one,one,one
10-qbmm_KC_case0027,quant_batch_matmul_v3,"((5, 1, 1, 1), (1, 4, 1, 1), (1,), None, None, (1,))","((5, 1, 1, 1), (1, 4, 1, 1), (1,), None, None, (1,))","((5, 4, 1, 1),)","((5, 4, 1, 1),)","('float8_e5m2', 'float8_e5m2', 'float32', 'int8', 'int8', 'float32')",float32,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': True}","((-10, 10),)","((0.001, 0.001),)",,1,one,one,one10+qbmm_KC_case0027,quant_batch_matmul_v3,"((5, 1, 1, 1), (1, 4, 1, 1), (1,), None, None, (1,))","((5, 1, 1, 1), (1, 4, 1, 1), (1,), None, None, (1,))","((5, 4, 1, 1),)","((5, 4, 1, 1),)","('float8_e5m2', 'float8_e5m2', 'float32', 'int8', 'int8', 'float32')",'float32',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': True}","((-10, 10),)","((0.001, 0.001),)",,1,one,one,one
11-qbmm_TC_case0067,quant_batch_matmul_v3,"((5, 1, 576, 560), (1, 3, 560, 256), (256,), None, None, (1,))","((5, 1, 576, 560), (1, 3, 560, 256), (256,), None, None, (1,))","((5, 3, 576, 256),)","((5, 3, 576, 256),)","('hifloat8', 'hifloat8', 'float32', 'int8', 'int8', 'float32')",bfloat16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': False}","((-10, 10),)","((0.001, 0.001),)",,1,multiple_of_32,multiple_of_32,multiple_of_1611+qbmm_TC_case0067,quant_batch_matmul_v3,"((5, 1, 576, 560), (1, 3, 560, 256), (256,), None, None, (1,))","((5, 1, 576, 560), (1, 3, 560, 256), (256,), None, None, (1,))","((5, 3, 576, 256),)","((5, 3, 576, 256),)","('hifloat8', 'hifloat8', 'float32', 'int8', 'int8', 'float32')",'bfloat16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': False}","((-10, 10),)","((0.001, 0.001),)",,1,multiple_of_32,multiple_of_32,multiple_of_16
12-qbmm_KC_case0006,quant_batch_matmul_v3,"((639, 1), (1, 757), (757,), None, None, (639,))","((639, 1), (1, 757), (757,), None, None, (639,))","((639, 757),)","((639, 757),)","('float8_e5m2', 'float8_e4m3fn', 'float32', 'int8', 'int8', 'float32')",float16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': False}","((-10, 10),)","((0.001, 0.001),)",,1,random,random,one12+qbmm_KC_case0006,quant_batch_matmul_v3,"((639, 1), (1, 757), (757,), None, None, (639,))","((639, 1), (1, 757), (757,), None, None, (639,))","((639, 757),)","((639, 757),)","('float8_e5m2', 'float8_e4m3fn', 'float32', 'int8', 'int8', 'float32')",'float16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': False}","((-10, 10),)","((0.001, 0.001),)",,1,random,random,one
13-qbmm_KC_case0008,quant_batch_matmul_v3,"((1872, 1648), (1744, 1648), (1744,), None, None, (1872,))","((1872, 1648), (1744, 1648), (1744,), None, None, (1872,))","((1872, 1744),)","((1872, 1744),)","('hifloat8', 'hifloat8', 'float32', 'int8', 'int8', 'float32')",float16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': True}","((-10, 10),)","((0.001, 0.001),)",,1,multiple_of_16,multiple_of_16,multiple_of_1613+qbmm_KC_case0008,quant_batch_matmul_v3,"((1872, 1648), (1744, 1648), (1744,), None, None, (1872,))","((1872, 1648), (1744, 1648), (1744,), None, None, (1872,))","((1872, 1744),)","((1872, 1744),)","('hifloat8', 'hifloat8', 'float32', 'int8', 'int8', 'float32')",'float16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': True}","((-10, 10),)","((0.001, 0.001),)",,1,multiple_of_16,multiple_of_16,multiple_of_16
14-qbmm_TC_case0001,quant_batch_matmul_v3,"((592, 368), (151, 368), (151,), None, None, None)","((592, 368), (151, 368), (151,), None, None, None)","((592, 151),)","((592, 151),)","('int8', 'int8', 'uint64', 'int8', 'int8', 'int8')",float16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': True}","((-10, 10),)","((0.001, 0.001),)",,1,multiple_of_16,random,multiple_of_1614+qbmm_TC_case0001,quant_batch_matmul_v3,"((592, 368), (151, 368), (151,), None, None, None)","((592, 368), (151, 368), (151,), None, None, None)","((592, 151),)","((592, 151),)","('int8', 'int8', 'uint64', 'int8', 'int8', 'int8')",'float16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': True}","((-10, 10),)","((0.001, 0.001),)",,1,multiple_of_16,random,multiple_of_16
15-qbmm_TC_case0002,quant_batch_matmul_v3,"((1, 1), (1, 1), (1,), None, None, None)","((1, 1), (1, 1), (1,), None, None, None)","((1, 1),)","((1, 1),)","('int8', 'int8', 'uint64', 'int8', 'int8', 'int8')",bfloat16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': True, 'transpose_x2': False}","((-10, 10),)","((0.001, 0.001),)",,1,one,one,one15+qbmm_TC_case0002,quant_batch_matmul_v3,"((1, 1), (1, 1), (1,), None, None, None)","((1, 1), (1, 1), (1,), None, None, None)","((1, 1),)","((1, 1),)","('int8', 'int8', 'uint64', 'int8', 'int8', 'int8')",'bfloat16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': True, 'transpose_x2': False}","((-10, 10),)","((0.001, 0.001),)",,1,one,one,one
16-qbmm_TC_case0015,quant_batch_matmul_v3,"((699, 719), (59, 719), (59,), None, None, None)","((699, 719), (59, 719), (59,), None, None, None)","((699, 59),)","((699, 59),)","('float8_e5m2', 'float8_e4m3fn', 'uint64', 'int8', 'int8', 'int8')",float16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': True}","((-10, 10),)","((0.001, 0.001),)",,1,random,prime,prime16+qbmm_TC_case0015,quant_batch_matmul_v3,"((699, 719), (59, 719), (59,), None, None, None)","((699, 719), (59, 719), (59,), None, None, None)","((699, 59),)","((699, 59),)","('float8_e5m2', 'float8_e4m3fn', 'uint64', 'int8', 'int8', 'int8')",'float16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': True}","((-10, 10),)","((0.001, 0.001),)",,1,random,prime,prime
17-qbmm_TC_case0005,quant_batch_matmul_v3,"((257, 447), (257, 941), (941,), None, None, None)","((257, 447), (257, 941), (941,), None, None, None)","((447, 941),)","((447, 941),)","('int8', 'int8', 'bfloat16', 'int8', 'int8', 'int8')",bfloat16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': True, 'transpose_x2': False}","((-10, 10),)","((0.001, 0.001),)",,1,random,prime,prime17+qbmm_TC_case0005,quant_batch_matmul_v3,"((257, 447), (257, 941), (941,), None, None, None)","((257, 447), (257, 941), (941,), None, None, None)","((447, 941),)","((447, 941),)","('int8', 'int8', 'bfloat16', 'int8', 'int8', 'int8')",'bfloat16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': True, 'transpose_x2': False}","((-10, 10),)","((0.001, 0.001),)",,1,random,prime,prime
18-qbmm_TC_case0012,quant_batch_matmul_v3,"((1, 1), (1, 1), (1,), None, None, None)","((1, 1), (1, 1), (1,), None, None, None)","((1, 1),)","((1, 1),)","('float8_e4m3fn', 'float8_e4m3fn', 'uint64', 'int8', 'int8', 'int8')",bfloat16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': True, 'transpose_x2': False}","((-10, 10),)","((0.001, 0.001),)",,1,one,one,one18+qbmm_TC_case0012,quant_batch_matmul_v3,"((1, 1), (1, 1), (1,), None, None, None)","((1, 1), (1, 1), (1,), None, None, None)","((1, 1),)","((1, 1),)","('float8_e4m3fn', 'float8_e4m3fn', 'uint64', 'int8', 'int8', 'int8')",'bfloat16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': True, 'transpose_x2': False}","((-10, 10),)","((0.001, 0.001),)",,1,one,one,one
19-qbmm_TT_case0001,quant_batch_matmul_v3,"((432, 272), (432, 176), (1,), None, None, None)","((432, 272), (432, 176), (1,), None, None, None)","((272, 176),)","((272, 176),)","('int8', 'int8', 'uint64', 'int8', 'int8', 'int8')",float16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': True, 'transpose_x2': False}","((-3, 3),)","((0.001, 0.001),)",,1,multiple_of_16,multiple_of_16,multiple_of_1619+qbmm_TT_case0001,quant_batch_matmul_v3,"((432, 272), (432, 176), (1,), None, None, None)","((432, 272), (432, 176), (1,), None, None, None)","((272, 176),)","((272, 176),)","('int8', 'int8', 'uint64', 'int8', 'int8', 'int8')",'float16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': True, 'transpose_x2': False}","((-3, 3),)","((0.001, 0.001),)",,1,multiple_of_16,multiple_of_16,multiple_of_16
20-qbmm_TT_case0005,quant_batch_matmul_v3,"((691, 272), (691, 592), (1,), None, None, None)","((691, 272), (691, 592), (1,), None, None, None)","((272, 592),)","((272, 592),)","('int8', 'int8', 'bfloat16', 'int8', 'int8', 'int8')",bfloat16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': True, 'transpose_x2': False}","((-10, 10),)","((0.001, 0.001),)",,1,multiple_of_16,multiple_of_16,prime20+qbmm_TT_case0005,quant_batch_matmul_v3,"((691, 272), (691, 592), (1,), None, None, None)","((691, 272), (691, 592), (1,), None, None, None)","((272, 592),)","((272, 592),)","('int8', 'int8', 'bfloat16', 'int8', 'int8', 'int8')",'bfloat16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': True, 'transpose_x2': False}","((-10, 10),)","((0.001, 0.001),)",,1,multiple_of_16,multiple_of_16,prime
21-qbmm_KC_case0001,quant_batch_matmul_v3,"((811, 131), (811, 160), (160,), None, None, (131,))","((811, 131), (811, 160), (160,), None, None, (131,))","((131, 160),)","((131, 160),)","('int8', 'int8', 'float32', 'int8', 'int8', 'float32')",float16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': True, 'transpose_x2': False}","((-3, 3),)","((0.001, 0.001),)",,1,prime,multiple_of_32,prime21+qbmm_KC_case0001,quant_batch_matmul_v3,"((811, 131), (811, 160), (160,), None, None, (131,))","((811, 131), (811, 160), (160,), None, None, (131,))","((131, 160),)","((131, 160),)","('int8', 'int8', 'float32', 'int8', 'int8', 'float32')",'float16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': True, 'transpose_x2': False}","((-3, 3),)","((0.001, 0.001),)",,1,prime,multiple_of_32,prime
22-qbmm_KC_case0002,quant_batch_matmul_v3,"((194, 1), (1, 1), (1,), None, None, (194,))","((194, 1), (1, 1), (1,), None, None, (194,))","((194, 1),)","((194, 1),)","('int8', 'int8', 'float32', 'int8', 'int8', 'float32')",bfloat16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': True}","((-1000, 1000),)","((0.001, 0.001),)",,1,random,one,one22+qbmm_KC_case0002,quant_batch_matmul_v3,"((194, 1), (1, 1), (1,), None, None, (194,))","((194, 1), (1, 1), (1,), None, None, (194,))","((194, 1),)","((194, 1),)","('int8', 'int8', 'float32', 'int8', 'int8', 'float32')",'bfloat16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': True}","((-1000, 1000),)","((0.001, 0.001),)",,1,random,one,one
23-qbmm_KT_case0011,quant_batch_matmul_v3,"((1, 1), (1, 1), (1,), None, (1,), (1,))","((1, 1), (1, 1), (1,), None, (1,), (1,))","((1, 1),)","((1, 1),)","('int8', 'int8', 'float32', 'int8', 'float32', 'float32')",float16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': False}","((-10, 10),)","((0.001, 0.001),)",,1,one,one,one23+qbmm_KT_case0011,quant_batch_matmul_v3,"((1, 1), (1, 1), (1,), None, (1,), (1,))","((1, 1), (1, 1), (1,), None, (1,), (1,))","((1, 1),)","((1, 1),)","('int8', 'int8', 'float32', 'int8', 'float32', 'float32')",'float16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': False}","((-10, 10),)","((0.001, 0.001),)",,1,one,one,one
24-qbmm_KC_case0003,quant_batch_matmul_v3,"((679, 149), (238, 149), (238,), None, None, (679,))","((679, 149), (238, 149), (238,), None, None, (679,))","((679, 238),)","((679, 238),)","('int8', 'int8', 'bfloat16', 'int8', 'int8', 'float32')",bfloat16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': True}","((-10, 10),)","((0.001, 0.001),)",,1,random,random,random24+qbmm_KC_case0003,quant_batch_matmul_v3,"((679, 149), (238, 149), (238,), None, None, (679,))","((679, 149), (238, 149), (238,), None, None, (679,))","((679, 238),)","((679, 238),)","('int8', 'int8', 'bfloat16', 'int8', 'int8', 'float32')",'bfloat16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': True}","((-10, 10),)","((0.001, 0.001),)",,1,random,random,random
25-qbmm_KC_case0014,quant_batch_matmul_v3,"((1232, 1348), (1104, 1348), (1104,), None, (1104,), (1232,))","((1232, 1348), (1104, 1348), (1104,), None, (1104,), (1232,))","((1232, 1104),)","((1232, 1104),)","('int8', 'int8', 'float32', 'int8', 'float32', 'float32')",bfloat16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': True}","((-10, 10),)","((0.001, 0.001),)",,1,multiple_of_16,multiple_of_16,random25+qbmm_KC_case0014,quant_batch_matmul_v3,"((1232, 1348), (1104, 1348), (1104,), None, (1104,), (1232,))","((1232, 1348), (1104, 1348), (1104,), None, (1104,), (1232,))","((1232, 1104),)","((1232, 1104),)","('int8', 'int8', 'float32', 'int8', 'float32', 'float32')",'bfloat16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': True}","((-10, 10),)","((0.001, 0.001),)",,1,multiple_of_16,multiple_of_16,random
26-qbmm_TC_case0027,quant_batch_matmul_v3,"((240, 176), (176, 304), (304,), None, (304,), None)","((240, 176), (176, 304), (304,), None, (304,), None)","((240, 304),)","((240, 304),)","('int8', 'int8', 'uint64', 'int8', 'int32', 'int8')",int8,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': False}","((-10, 10),)","((0.001, 0.001),)",,1,multiple_of_16,multiple_of_16,multiple_of_1626+qbmm_TC_case0027,quant_batch_matmul_v3,"((240, 176), (176, 304), (304,), None, (304,), None)","((240, 176), (176, 304), (304,), None, (304,), None)","((240, 304),)","((240, 304),)","('int8', 'int8', 'uint64', 'int8', 'int32', 'int8')",'int8',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': False, 'transpose_x2': False}","((-10, 10),)","((0.001, 0.001),)",,1,multiple_of_16,multiple_of_16,multiple_of_16
27-qbmm_TC_case0020,quant_batch_matmul_v3,"((443, 128), (443, 320), (320,), None, None, None)","((443, 128), (443, 320), (320,), None, None, None)","((128, 320),)","((128, 320),)","('float8_e4m3fn', 'float8_e5m2', 'uint64', 'int8', 'int8', 'int8')",bfloat16,"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': True, 'transpose_x2': False}","((-10, 10),)","((0.001, 0.001),)",,1,multiple_of_32,multiple_of_32,prime27+qbmm_TC_case0020,quant_batch_matmul_v3,"((443, 128), (443, 320), (320,), None, None, None)","((443, 128), (443, 320), (320,), None, None, None)","((128, 320),)","((128, 320),)","('float8_e4m3fn', 'float8_e5m2', 'uint64', 'int8', 'int8', 'int8')",'bfloat16',"('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND', 'ND', 'ND', 'ND', 'ND', 'ND')","('ND',)","('ND',)","{'dtype': 1, 'transpose_x1': True, 'transpose_x2': False}","((-10, 10),)","((0.001, 0.001),)",,1,multiple_of_32,multiple_of_32,prime
@@ -9,49 +9,235 @@
9# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.9# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
10# See LICENSE in the root of the software repository for the full text of the License.10# See LICENSE in the root of the software repository for the full text of the License.
11# ----------------------------------------------------------------------------11# ----------------------------------------------------------------------------
12+import ml_dtypes
13+import numpy as np
14+from ml_dtypes import bfloat16, float8_e5m2, float8_e4m3fn
15+ 
12__golden__ = {16__golden__ = {
13- "e2e": {17+ "kernel": {
14- "torch_npu.npu_transpose_quant_batchmatmul": "torch_npu_npu_transpose_quant_batchmatmul_golden"18+ "transpose_quant_batch_mat_mul": "transpose_quant_batch_mat_mul_golden"
15- }19+ },
20+ "e2e": {
21+ "torch_npu.npu_transpose_quant_batchmatmul": "torch_npu_npu_transpose_quant_batchmatmul_golden"
22+ }
16}23}
17 24 
18-import ml_dtypes25+_DTYPE_ATTR_MAP = {1: np.float16, 27: bfloat16}
19-import torch
20-import numpy as np
21 26 
27+_FRACTAL_DIMS = {
28+ "float16": (16, 16),
29+ "bfloat16": (16, 16),
30+ "float32": (16, 8),
31+}
32+ 
33+ 
34+def customize_inputs(x1, x2, bias=None, x1_scale=None, x2_scale=None, *,
35+ dtype=1, group_size=0, perm_x1=(1, 0, 2), perm_x2=(0, 1, 2),
36+ perm_y=(1, 0, 2), batch_split_factor=1, **kwargs):
37+ input_formats = kwargs.get('input_formats', ())
38+ input_ori_shapes = kwargs.get('input_ori_shapes', ())
39+ if len(input_formats) > 1 and input_formats[1] == 'FRACTAL_NZ':
40+ x2_dtype_str = _dtype_to_str(x2.dtype)
41+ ori_shape = input_ori_shapes[1] if len(input_ori_shapes) > 1 else None
42+ x2 = _nz_to_nd(x2, x2_dtype_str, ori_shape)
43+ return x1, x2, bias, x1_scale, x2_scale
44+ 
45+ 
46+def pre_compare(*outputs, **kwargs):
47+ return list(outputs)
48+ 
49+ 
50+def transpose_quant_batch_mat_mul_golden(x1, x2, bias=None, x1_scale=None,
51+ x2_scale=None, *, dtype=1, group_size=0,
52+ perm_x1=(1, 0, 2), perm_x2=(0, 1, 2),
53+ perm_y=(1, 0, 2), batch_split_factor=1,
54+ **kwargs):
55+ x1, x2, bias, x1_scale, x2_scale = customize_inputs(
56+ x1, x2, bias, x1_scale, x2_scale,
57+ dtype=dtype, group_size=group_size, perm_x1=perm_x1, perm_x2=perm_x2,
58+ perm_y=perm_y, batch_split_factor=batch_split_factor, **kwargs)
59+ 
60+ x1_f32 = x1.astype(np.float32)
61+ x2_f32 = x2.astype(np.float32)
62+ 
63+ x1_t = np.transpose(x1_f32, axes=list(perm_x1))
64+ 
65+ if tuple(perm_x2) == (0, 2, 1):
66+ x2_t = np.swapaxes(x2_f32, -2, -1)
67+ if x2_scale is not None and x2_scale.ndim == 4:
68+ x2_scale = np.transpose(x2_scale, (0, 2, 1, 3))
69+ else:
70+ x2_t = x2_f32
71+ 
72+ is_mx = _is_mx_scale(x1_scale)
73+ 
74+ if is_mx:
75+ acc = _mxfp8_matmul(x1_t, x2_t, x1_scale, x2_scale)
76+ else:
77+ acc = _kc_matmul(x1_t, x2_t, x1_scale, x2_scale)
78+ 
79+ out = np.transpose(acc, axes=list(perm_y))
80+ 
81+ output_dtypes = kwargs.get("output_dtypes", None)
82+ if output_dtypes is not None:
83+ out = _cast_output_dtype(out, output_dtypes[0])
84+ else:
85+ target_dtype = _DTYPE_ATTR_MAP.get(dtype, np.float16)
86+ out = out.astype(target_dtype)
87+ 
88+ return [out]
89+ 
90+ 
91+def _is_mx_scale(scale):
92+ if scale is None:
93+ return False
94+ dtype_str = str(scale.dtype)
95+ return "e8m0" in dtype_str
96+ 
97+ 
98+def _e8m0_to_float(arr):
99+ raw = arr.view(np.uint8).astype(np.float32)
100+ result = np.power(2.0, raw - 127.0)
101+ result[raw == 255.0] = np.nan
102+ return result
103+ 
104+ 
105+def _kc_matmul(x1, x2, x1_scale, x2_scale):
106+ acc = np.matmul(x1, x2)
107+ 
108+ if x2_scale is not None:
109+ acc = acc * x2_scale.astype(np.float32).reshape(1, 1, -1)
110+ 
111+ if x1_scale is not None:
112+ acc = acc * x1_scale.astype(np.float32).reshape(1, -1, 1)
113+ 
114+ return acc
115+ 
116+ 
117+def _mxfp8_matmul(x1, x2, x1_scale, x2_scale):
118+ B, M, K = x1.shape
119+ N = x2.shape[2]
120+ group_size_k = 32
121+ num_groups = K // group_size_k
122+ 
123+ x1_scale_f = _e8m0_to_float(x1_scale)
124+ x2_scale_f = _e8m0_to_float(x2_scale)
125+ 
126+ x1_scale_flat = x1_scale_f.reshape(M, B, num_groups)
127+ x1_scale_flat = np.transpose(x1_scale_flat, (1, 0, 2))
128+ 
129+ x2_scale_flat = x2_scale_f.reshape(B, num_groups, N)
130+ 
131+ out = np.zeros((B, M, N), dtype=np.float32)
132+ for g in range(num_groups):
133+ k_start = g * group_size_k
134+ k_end = (g + 1) * group_size_k
135+ partial = np.matmul(x1[:, :, k_start:k_end], x2[:, k_start:k_end, :])
136+ s1 = x1_scale_flat[:, :, g][:, :, np.newaxis]
137+ s2 = x2_scale_flat[:, g, :][:, np.newaxis, :]
138+ out += partial * s1 * s2
139+ 
140+ return out
141+ 
142+ 
143+class TransposeQuantBatchMatMulAssets:
144+ 
145+ golden = transpose_quant_batch_mat_mul_golden
146+ customize_inputs = customize_inputs
147+ pre_compare = pre_compare
148+ 
149+ tolerance = {
150+ "float16": {
151+ "standard": "BenchmarkCompareStandard",
152+ "avg_re_rtol": 2.0,
153+ "max_re_rtol": 10.0,
154+ "rmse_rtol": 2.0,
155+ "small_value": 0.001,
156+ "small_value_atol": 1e-5,
157+ },
158+ "bfloat16": {
159+ "standard": "BenchmarkCompareStandard",
160+ "avg_re_rtol": 2.0,
161+ "max_re_rtol": 10.0,
162+ "rmse_rtol": 2.0,
163+ "small_value": 0.001,
164+ "small_value_atol": 1e-5,
165+ },
166+ }
167+ 
168+ 
169+def _dtype_to_str(dtype):
170+ dtype_map = {
171+ np.float16: "float16",
172+ np.float32: "float32",
173+ np.float64: "float64",
174+ bfloat16: "bfloat16",
175+ }
176+ return dtype_map.get(dtype, str(dtype))
177+ 
178+ 
179+def _cast_output_dtype(arr, dtype_name):
180+ dtype_map = {"float16": np.float16, "float32": np.float32, "bfloat16": bfloat16}
181+ target = dtype_map.get(dtype_name)
182+ if target is not None:
183+ return arr.astype(target)
184+ return arr.astype(dtype_name)
185+ 
186+ 
187+def _nz_to_nd(data, dtype_str, ori_shape=None):
188+ m0, n0 = _FRACTAL_DIMS.get(dtype_str, (16, 16))
189+ shape = data.shape
190+ batch_dims = len(shape) - 4
191+ perm = list(range(batch_dims)) + [batch_dims + 1, batch_dims + 2, batch_dims + 0, batch_dims + 3]
192+ data = np.transpose(data, perm)
193+ m1 = shape[batch_dims + 1]
194+ m0_actual = shape[batch_dims + 2]
195+ n1 = shape[batch_dims + 0]
196+ n0_actual = shape[batch_dims + 3]
197+ data = data.reshape(*shape[:batch_dims], m1 * m0_actual, n1 * n0_actual)
198+ if ori_shape is not None:
199+ target_M = ori_shape[-2]
200+ target_N = ori_shape[-1]
201+ data = data[..., :target_M, :target_N]
202+ return data
203+ 
204+ 
205+# ===== E2E golden (torch-based, retained for e2e mode) =====
22 206 
23def torch_npu_npu_transpose_quant_batchmatmul_golden(x1, x2, dtype, *, bias=None, x1_scale=None,207def torch_npu_npu_transpose_quant_batchmatmul_golden(x1, x2, dtype, *, bias=None, x1_scale=None,
24- x2_scale=None, group_sizes=None, perm_x1=None,208+ x2_scale=None, group_sizes=None, perm_x1=None,
25- perm_x2=None, perm_y=None, batch_split_factor=None, **kwargs):209+ perm_x2=None, perm_y=None, batch_split_factor=None, **kwargs):
26- x1 = torch_to_numpy(x1)210+ import torch
27- x2 = torch_to_numpy(x2)211+ x1 = _torch_to_numpy(x1)
28- bias = torch_to_numpy(bias)212+ x2 = _torch_to_numpy(x2)
29- x1_scale = torch_to_numpy(x1_scale)213+ bias = _torch_to_numpy(bias)
30- x2_scale = torch_to_numpy(x2_scale)214+ x1_scale = _torch_to_numpy(x1_scale)
215+ x2_scale = _torch_to_numpy(x2_scale)
31 x1_dtype = str(x1.dtype)216 x1_dtype = str(x1.dtype)
32 x2_dtype = str(x2.dtype)217 x2_dtype = str(x2.dtype)
33 x1_scale_dtype = ""218 x1_scale_dtype = ""
34 if isinstance(x1_scale, torch.Tensor):219 if isinstance(x1_scale, torch.Tensor):
35 x1_scale_dtype = str(x1_scale.dtype)220 x1_scale_dtype = str(x1_scale.dtype)
36- pertoken_flag = (x1_scale is not None 221+ pertoken_flag = (x1_scale is not None
37- and x1_dtype in ("int8", "float8_e4m3fn", "float8_e5m2")222+ and x1_dtype in ("int8", "float8_e4m3fn", "float8_e5m2")
38- and x1_scale_dtype in ("float32",))223+ and x1_scale_dtype in ("float32",))
39 224 
40- x1 = transpose_(x1, perm_x1)225+ x1 = _transpose_(x1, perm_x1)
41- x2 = transpose_(x2, perm_x2)226+ x2 = _transpose_(x2, perm_x2)
42 227 
43- x1 = x_dtype_cope(x1, x1_dtype)228+ x1 = _x_dtype_cope(x1, x1_dtype)
44- x2 = x_dtype_cope(x2, x2_dtype)229+ x2 = _x_dtype_cope(x2, x2_dtype)
45 if pertoken_flag:230 if pertoken_flag:
46- out = pertoken_calculation(x1, x2, x1_scale, x2_scale, bias, is_bias_epilogue=False, output_dtype=dtype)231+ out = _pertoken_calculation(x1, x2, x1_scale, x2_scale, bias, is_bias_epilogue=False, output_dtype=dtype)
47 else:232 else:
48 raise TypeError("Please check whether this quantitative method is supported")233 raise TypeError("Please check whether this quantitative method is supported")
49- out = transpose_(out, perm_y)234+ out = _transpose_(out, perm_y)
50- out = out_dtype_cope(out, dtype)235+ out = _out_dtype_cope(out, dtype)
51 return out236 return out
52 237 
53 238 
54-def pertoken_calculation(x1, x2, x1_scale, x2_scale, bias, is_bias_epilogue=False, output_dtype=2):239+def _pertoken_calculation(x1, x2, x1_scale, x2_scale, bias, is_bias_epilogue=False, output_dtype=2):
240+ import torch
55 x1 = torch.from_numpy(x1)241 x1 = torch.from_numpy(x1)
56 x2 = torch.from_numpy(x2)242 x2 = torch.from_numpy(x2)
57 out = torch.matmul(x1, x2)243 out = torch.matmul(x1, x2)
@@ -71,7 +257,7 @@ def pertoken_calculation(x1, x2, x1_scale, x2_scale, bias, is_bias_epilogue=Fals
71 return out.numpy()257 return out.numpy()
72 258 
73 259 
74-def x_dtype_cope(x, x_dtype):260+def _x_dtype_cope(x, x_dtype):
75 if x_dtype in ("float8_e4m3fn", "float8_e5m2", "float4_e2m1", "float4_e1m2", "hifloat8"):261 if x_dtype in ("float8_e4m3fn", "float8_e5m2", "float4_e2m1", "float4_e1m2", "hifloat8"):
76 x = x.astype(np.float32)262 x = x.astype(np.float32)
77 else:263 else:
@@ -79,7 +265,8 @@ def x_dtype_cope(x, x_dtype):
79 return x265 return x
80 266 
81 267 
82-def transpose_(x, array_trans_x):268+def _transpose_(x, array_trans_x):
269+ import torch
83 if isinstance(x, torch.Tensor):270 if isinstance(x, torch.Tensor):
84 x = torch.permute(x, array_trans_x)271 x = torch.permute(x, array_trans_x)
85 elif isinstance(x, np.ndarray):272 elif isinstance(x, np.ndarray):
@@ -89,8 +276,8 @@ def transpose_(x, array_trans_x):
89 return x276 return x
90 277 
91 278 
92-def out_dtype_cope(out, output_dtype):279+def _out_dtype_cope(out, output_dtype):
93- from ml_dtypes import bfloat16, float8_e4m3fn280+ import torch
94 if output_dtype == torch.float32:281 if output_dtype == torch.float32:
95 out = out.astype(np.float32)282 out = out.astype(np.float32)
96 elif output_dtype == torch.float16:283 elif output_dtype == torch.float16:
@@ -109,12 +296,13 @@ def out_dtype_cope(out, output_dtype):
109 return out296 return out
110 297 
111 298 
112-def torch_to_numpy(x):299+def _torch_to_numpy(x):
300+ import torch
113 if isinstance(x, torch.Tensor):301 if isinstance(x, torch.Tensor):
114 if x.dtype == torch.float8_e5m2:302 if x.dtype == torch.float8_e5m2:
115- x = x.to(torch.float32).numpy().astype(ml_dtypes.float8_e5m2)303+ x = x.to(torch.float32).numpy().astype(float8_e5m2)
116 elif x.dtype == torch.float8_e4m3fn:304 elif x.dtype == torch.float8_e4m3fn:
117- x = x.to(torch.float32).numpy().astype(ml_dtypes.float8_e4m3fn)305+ x = x.to(torch.float32).numpy().astype(float8_e4m3fn)
118 else:306 else:
119 x = x.numpy()307 x = x.numpy()
120- return x308+ return x