已合并
fix(pad_v2): golden bfloat16 分支 cv 转为 float 避免类型错误 #3625
yefeicoding创建于 6月29日
fix(pad_v2): golden bfloat16 分支 cv 转为 float 避免类型错误 #3625
已合并
yefeicoding创建于 6月29日
8 个文件变更+495-75
@@ -11,8 +11,6 @@
11# ----------------------------------------------------------------------------11# ----------------------------------------------------------------------------
12 12 
13import numpy as np13import numpy as np
14-import tensorflow.compat.v1 as tf
15-tf.disable_v2_behavior()
16 14 
17 15 
18__golden__ = {16__golden__ = {
@@ -22,59 +20,96 @@ __golden__ = {
22}20}
23 21 
24 22 
25-def _trans_nc1hwc0_to_nhwc(data):23+def _ceil_div(x, y):
26- in_shape = data.shape24+ return (x + y - 1) // y
25+ 
26+ 
27+def shape_6d_2_5d(tensor):
28+ n, di, c1, hi, wi, c0 = tensor.shape
29+ tmp_tensor = tensor.reshape(n, di, c1, hi, wi, c0)
30+ tmp_tensor = np.transpose(tmp_tensor, axes=(0, 1, 3, 4, 2, 5))
31+ new_tensor = tmp_tensor.reshape(n, di, hi, wi, c1 * c0)
32+ return new_tensor
33+ 
34+ 
35+def shape_5d_2_6d(tensor):
36+ import math
37+ c0 = 16
38+ n, di, hi, wi, c = tensor.shape
39+ c1 = math.ceil(c / c0)
40+ tmp_tensor = tensor.reshape(n, di, hi, wi, c1, c0)
41+ new_tensor = np.transpose(tmp_tensor, axes=(0, 1, 4, 2, 3, 5))
42+ return new_tensor
43+ 
44+ 
45+def trans_nhwc_to_nc1hwc0(input_data, c0=16):
46+ in_shape = np.shape(input_data)
47+ axis_n = in_shape[0]
48+ axis_h = in_shape[1]
49+ axis_w = in_shape[2]
50+ axis_c = in_shape[3]
51+ axis_c0 = c0
52+ axis_c1 = _ceil_div(axis_c, axis_c0)
53+ c_pad = 0
54+ tmp_input_tensor = np.pad(input_data, ((0, 0), (0, 0), (0, 0), (0, c_pad)), mode="constant", constant_values=(0, 0))
55+ tmp_input_tensor = tmp_input_tensor.reshape(axis_n, axis_h, axis_w, axis_c1, axis_c0)
56+ output_arr = np.transpose(tmp_input_tensor, axes=(0, 3, 1, 2, 4))
57+ return output_arr
58+ 
59+ 
60+def trans_nc1hwc0_to_nhwc(input_data):
61+ in_shape = np.shape(input_data)
27 axis_n = in_shape[0]62 axis_n = in_shape[0]
28 axis_c1 = in_shape[1]63 axis_c1 = in_shape[1]
29 axis_h = in_shape[2]64 axis_h = in_shape[2]
30 axis_w = in_shape[3]65 axis_w = in_shape[3]
31 axis_c0 = in_shape[4]66 axis_c0 = in_shape[4]
32- tmp_input_tensor = np.transpose(data, axes=(0, 2, 3, 1, 4))67+ tmp_input_tensor = np.transpose(input_data, axes=(0, 2, 3, 1, 4))
33 tmp_input_tensor = tmp_input_tensor.reshape(axis_n, axis_h, axis_w, axis_c1 * axis_c0)68 tmp_input_tensor = tmp_input_tensor.reshape(axis_n, axis_h, axis_w, axis_c1 * axis_c0)
34 return tmp_input_tensor69 return tmp_input_tensor
35 70 
36 71 
37-def _trans_nhwc_to_nc1hwc0(data):72+def _high_dim_batch_to_space_nd(input_tensor, block_shape, crops):
38- in_shape = data.shape73+ import tensorflow as tf
39- axis_n = in_shape[0]
40- axis_h = in_shape[1]
41- axis_w = in_shape[2]
42- axis_c = in_shape[3]
43- axis_c0 = 16
44- axis_c1 = (axis_c + axis_c0 - 1) // axis_c0
45- tmp_input_tensor = data.reshape(axis_n, axis_h, axis_w, axis_c1, axis_c0)
46- tmp_input_tensor = np.transpose(tmp_input_tensor, axes=(0, 3, 1, 2, 4))
47- return tmp_input_tensor
48 74 
75+ M = block_shape.shape[0]
76+ input_shape = input_tensor.shape
77+ batch_size = input_shape[0]
78+ spatial_shape = input_shape[1 : 1 + M]
79+ remain_shape = input_shape[1 + M :]
49 80 
50-def _shape_6d_2_5d(data):81+ block_prod = tf.reduce_prod(block_shape)
51- in_shape = data.shape82+ new_batch = batch_size // block_prod
52- axis_d = in_shape[0]
53- axis_c1 = in_shape[1]
54- axis_h = in_shape[2]
55- axis_w = in_shape[3]
56- axis_n = in_shape[4]
57- axis_c0 = in_shape[5]
58- axis_n = axis_n * axis_d
59- axis_c = axis_c1 * axis_c0
60- tmp_input_tensor = data.reshape(axis_n, axis_c1, axis_h, axis_w, axis_c0)
61- tmp_input_tensor = np.transpose(tmp_input_tensor, axes=(0, 2, 3, 1, 4))
62- tmp_input_tensor = tmp_input_tensor.reshape(axis_n, axis_h, axis_w, axis_c)
63- return tmp_input_tensor
64 83 
84+ new_shape = tf.concat(
85+ [block_shape, [new_batch], spatial_shape, remain_shape], axis=0
86+ )
87+ reshaped = tf.reshape(input_tensor, new_shape)
65 88 
66-def _shape_5d_2_6d(data):89+ perm = [M]
67- in_shape = data.shape90+ for i in range(M):
68- axis_n = in_shape[0]91+ perm.append(M + 1 + i)
69- axis_h = in_shape[1]92+ perm.append(i)
70- axis_w = in_shape[2]93+ remain_start = M + 1 + M
71- axis_c = in_shape[3]94+ perm.extend(range(remain_start, reshaped.shape.rank))
72- axis_c0 = 1695+ transposed = tf.transpose(reshaped, perm)
73- axis_c1 = (axis_c + axis_c0 - 1) // axis_c096+ 
74- axis_d = 197+ expanded_spatial = spatial_shape * block_shape
75- tmp_input_tensor = data.reshape(axis_d, axis_n, axis_h, axis_w, axis_c1, axis_c0)98+ new_shape2 = tf.concat([[new_batch], expanded_spatial, remain_shape], axis=0)
76- tmp_input_tensor = np.transpose(tmp_input_tensor, axes=(0, 4, 2, 3, 1, 5))99+ merged = tf.reshape(transposed, new_shape2)
77- return tmp_input_tensor100+ 
101+ begin = [0]
102+ size = [new_batch]
103+ for i in range(M):
104+ begin.append(crops[i, 0])
105+ size.append(expanded_spatial[i] - crops[i, 0] - crops[i, 1])
106+ R = input_tensor.shape.rank - 1 - M
107+ for i in range(R):
108+ begin.append(0)
109+ size.append(remain_shape[i])
110+ 
111+ output = tf.slice(merged, begin, size)
112+ return output
78 113 
79 114 
80def batch_to_space_nd_golden(x, block_shape, crops, **kwargs):115def batch_to_space_nd_golden(x, block_shape, crops, **kwargs):
@@ -86,24 +121,36 @@ def batch_to_space_nd_golden(x, block_shape, crops, **kwargs):
86 input_formats, output_formats, input_ori_formats, output_ori_formats,121 input_formats, output_formats, input_ori_formats, output_ori_formats,
87 input_dtypes, output_dtypes.122 input_dtypes, output_dtypes.
88 '''123 '''
89- input_format = kwargs.get('input_formats', ['ND'])[0]124+ import tensorflow.compat.v1 as tf
90- 125+ tf.disable_v2_behavior()
91- if input_format == 'NC1HWC0':126+ 
92- x = _trans_nc1hwc0_to_nhwc(x)127+ data_x = x
93- elif input_format == "NDC1HWC0":128+ block_shape_arr = np.array(block_shape).astype(np.int64)
94- x = _shape_6d_2_5d(x)129+ crops_arr = np.array(crops).astype(np.int64)
95- 130+ 
96- tensor_x = tf.placeholder(x.dtype, shape=x.shape)131+ input_formats = kwargs.get('input_formats', ())
97- block_shape_tensor = tf.constant(block_shape.tolist())132+ fmt = input_formats[0] if input_formats and len(input_formats) > 0 else 'ND'
98- crops_tensor = tf.constant(crops.tolist())133+ if isinstance(fmt, (list, tuple)):
99- out = tf.batch_to_space_nd(tensor_x, block_shape_tensor, crops_tensor)134+ fmt = fmt[0] if fmt else 'ND'
100- 135+ 
136+ if fmt == 'NC1HWC0':
137+ data_x = trans_nc1hwc0_to_nhwc(data_x)
138+ elif fmt == "NDC1HWC0":
139+ data_x = shape_6d_2_5d(data_x)
140+ 
141+ tensor_x = tf.placeholder(data_x.dtype, shape=data_x.shape)
142+ tf_block_shape = tf.constant(block_shape_arr)
143+ tf_crops = tf.constant(crops_arr)
144+ if block_shape_arr.shape[0] > 4:
145+ out = _high_dim_batch_to_space_nd(tensor_x, tf_block_shape, tf_crops)
146+ else:
147+ out = tf.batch_to_space_nd(tensor_x, tf_block_shape, tf_crops)
148+ 
101 with tf.Session() as sess:149 with tf.Session() as sess:
102- res = sess.run(out, feed_dict={tensor_x: x})150+ res = sess.run(out, feed_dict={tensor_x: data_x})
103- 151+ 
104- if input_format == "NC1HWC0":152+ if fmt == "NC1HWC0":
105- res = _trans_nhwc_to_nc1hwc0(res)153+ res = trans_nhwc_to_nc1hwc0(res)
106- elif input_format == "NDC1HWC0":154+ elif fmt == "NDC1HWC0":
107- res = _shape_5d_2_6d(res)155+ res = shape_5d_2_6d(res)
108- 156+ return res
109- return res
@@ -130,7 +130,7 @@ def pad_v2_golden(x, paddings, constant_values, **kwargs):
130 cv = constant_values_arr[0]130 cv = constant_values_arr[0]
131 elif x.dtype.name == "bfloat16":131 elif x.dtype.name == "bfloat16":
132 x_tensor = _numpy_to_torch_tensor(x).to(torch.float32)132 x_tensor = _numpy_to_torch_tensor(x).to(torch.float32)
133- cv = constant_values_arr[0]133+ cv = float(constant_values_arr[0])
134 elif x.dtype.name in fp8dtypes:134 elif x.dtype.name in fp8dtypes:
135 x_tensor = _numpy_to_torch_tensor(x.view(np.int8))135 x_tensor = _numpy_to_torch_tensor(x.view(np.int8))
136 constant_values_arr = constant_values_arr.view(np.int8)136 constant_values_arr = constant_values_arr.view(np.int8)
@@ -15,8 +15,7 @@ import numpy as np
15 15 
16__golden__ = {16__golden__ = {
17 "kernel": {17 "kernel": {
18- "transpose": "transpose_golden",18+ "transpose": "transpose_golden"
19- "transpose_d": "transpose_golden"
20 }19 }
21}20}
22 21 
@@ -11,7 +11,6 @@
11# ----------------------------------------------------------------------------11# ----------------------------------------------------------------------------
12 12 
13import numpy as np13import numpy as np
14-import torch
15 14 
16 15 
17__golden__ = {16__golden__ = {
@@ -21,13 +20,58 @@ __golden__ = {
21}20}
22 21 
23 22 
24-def sinc_golden(x, **kwargs):23+def _numpy_bfloat16():
25- ori_dtype = kwargs.get("input_dtypes", ["float32"])[0]24+ try:
26- x_dtype = x.dtype25+ from ml_dtypes import bfloat16
27- 26+ except ModuleNotFoundError:
28- if "bfloat16" in str(ori_dtype).lower() or "float16" in str(ori_dtype).lower():27+ try:
29- x_tensor = torch.from_numpy(x.astype(np.float32))28+ import tensorflow
30- output = torch.sinc(x_tensor)29+ bfloat16 = tensorflow.bfloat16.as_numpy_dtype
31- return output.numpy().astype(x_dtype, copy=False)30+ except ModuleNotFoundError:
31+ raise RuntimeError("ml-dtypes or tensorflow is needed to support bfloat16 dtype!!! "
32+ "Please install with `pip3 install ml-dtypes` or `pip3 install tensorflow`")
33+ return bfloat16
34+ 
35+ 
36+def _numpy_to_torch_tensor(np_array):
37+ import torch
38+ if np_array is None:
39+ return None
40+ np_dtype = np_array.dtype.name
41+ if "bfloat16" in np_dtype:
42+ np_int16 = np_array.view(dtype=np.int16)
43+ t_int16 = torch.from_numpy(np_int16)
44+ return t_int16.view(torch.bfloat16)
32 else:45 else:
33- return np.sinc(x)46+ return torch.from_numpy(np_array)
47+ 
48+ 
49+def _torch_to_numpy_tensor(torch_tensor):
50+ import torch
51+ if torch_tensor is None:
52+ return None
53+ if not isinstance(torch_tensor, torch.Tensor):
54+ raise RuntimeError(f"Only support torch.Tensor. But got {type(torch_tensor)}")
55+ torch_dtype = torch_tensor.dtype
56+ if torch_dtype == torch.bfloat16:
57+ t_int16 = torch_tensor.view(torch.int16)
58+ np_int16 = t_int16.numpy()
59+ return np_int16.view(dtype=_numpy_bfloat16())
60+ else:
61+ return torch_tensor.numpy()
62+ 
63+ 
64+def sinc_golden(x, **kwargs):
65+ '''
66+ Kernel golden for sinc.
67+ All the parameters follow @sinc_def.cpp without outputs.
68+ All the input Tensors are numpy.ndarray.
69+ kwargs may contain: short_soc_version, input_ori_shapes, output_ori_shapes,
70+ input_formats, output_formats, input_ori_formats, output_ori_formats,
71+ input_dtypes, output_dtypes.
72+ '''
73+ import torch
74+ 
75+ input_x = _numpy_to_torch_tensor(x)
76+ output = torch.sinc(input_x)
77+ return _torch_to_numpy_tensor(output)
@@ -0,0 +1,183 @@
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+ 
13+import numpy as np
14+ 
15+ 
16+__golden__ = {
17+ "kernel": {
18+ "truncate_div": "truncate_div_golden"
19+ }
20+}
21+ 
22+ 
23+def _broadcast_to_maxshape(shapes):
24+ """
25+ produce broadcast shape
26+ for example:
27+ input: shape is [[2, 3], [3, 2, 1], [3, 1, 3]]
28+ output: [1, 2, 3], [3, 2, 1], [3, 1, 3], [3, 2, 3]
29+ """
30+ def _max(_shape):
31+ no_one_shape = [s for s in _shape if s != 1]
32+ if len(no_one_shape) == 0:
33+ max_value = 1
34+ else:
35+ max_value = no_one_shape[0]
36+ return max_value
37+ max_dim_length = max(len(list(shape)) for shape in shapes)
38+ input_shapes = []
39+ for shape in shapes:
40+ input_shapes.append([1 for _ in range(max_dim_length - len(shape))] + list(shape))
41+ input_shapes = list(map(list, zip(*input_shapes)))
42+ max_shape = [_max(shape) for shape in input_shapes]
43+ input_shapes = list(map(list, zip(*input_shapes)))
44+ return (*input_shapes, max_shape)
45+ 
46+ 
47+def _numpy_bfloat16():
48+ try:
49+ from ml_dtypes import bfloat16
50+ except ModuleNotFoundError:
51+ try:
52+ import tensorflow
53+ bfloat16 = tensorflow.bfloat16.as_numpy_dtype
54+ except ModuleNotFoundError:
55+ raise RuntimeError("ml-dtypes or tensorflow is needed to support bfloat16 dtype!!! "
56+ "Please install with `pip3 install ml-dtypes` or `pip3 install tensorflow`")
57+ return bfloat16
58+ 
59+ 
60+def _numpy_to_torch_tensor(np_array):
61+ import torch
62+ if np_array is None:
63+ return None
64+ np_dtype = np_array.dtype.name
65+ if "bfloat16" in np_dtype:
66+ np_int16 = np_array.view(dtype=np.int16)
67+ t_int16 = torch.from_numpy(np_int16)
68+ return t_int16.view(torch.bfloat16)
69+ else:
70+ return torch.from_numpy(np_array)
71+ 
72+ 
73+def _torch_to_numpy_tensor(torch_tensor):
74+ import torch
75+ if torch_tensor is None:
76+ return None
77+ if not isinstance(torch_tensor, torch.Tensor):
78+ raise RuntimeError(f"Only support torch.Tensor. But got {type(torch_tensor)}")
79+ torch_dtype = torch_tensor.dtype
80+ if torch_dtype == torch.bfloat16:
81+ t_int16 = torch_tensor.view(torch.int16)
82+ np_int16 = t_int16.numpy()
83+ return np_int16.view(dtype=_numpy_bfloat16())
84+ else:
85+ return torch_tensor.numpy()
86+ 
87+ 
88+def truncate_div_golden(x1, x2, **kwargs):
89+ '''
90+ Kernel golden for truncate_div.
91+ All the parameters follow @truncate_div_def.cpp without outputs.
92+ All the input Tensors are numpy.ndarray.
93+ kwargs may contain: short_soc_version, input_ori_shapes, output_ori_shapes,
94+ input_formats, output_formats, input_ori_formats, output_ori_formats,
95+ input_dtypes, output_dtypes.
96+ '''
97+ import torch
98+ 
99+ type_int = [torch.int8, torch.int32, torch.int64]
100+ type_uint = [torch.uint8]
101+ type_float = [torch.float, torch.float16, torch.bfloat16]
102+ 
103+ _, _, res_shape = _broadcast_to_maxshape([x1.shape, x2.shape])
104+ x2_broadcast = np.broadcast_to(x2, res_shape)
105+ zero_x2_broadcast_idx = np.where(x2_broadcast == 0)
106+ 
107+ output_dtype = kwargs.get("output_dtypes", [None])[0]
108+ if output_dtype is None:
109+ output_dtype = str(x1.dtype)
110+ need_zero_handling = output_dtype in ["int32", "int8", "uint8", "int64"]
111+ 
112+ zero_idx = np.where(x2 == 0)
113+ if len(zero_idx[0]) > 0 and need_zero_handling:
114+ x2[zero_idx] = 1
115+ 
116+ x1_t = _numpy_to_torch_tensor(x1)
117+ x2_t = _numpy_to_torch_tensor(x2)
118+ 
119+ res = 0
120+ 
121+ dtype = torch.promote_types(x1_t.dtype, x2_t.dtype)
122+ if dtype in (torch.int32, torch.int64):
123+ info = torch.iinfo(dtype)
124+ min_val, max_val = info.min, info.max
125+ dangerous_mask = (x1_t == min_val) & (x2_t == -1)
126+ safe_x2 = torch.where(dangerous_mask, torch.ones_like(x2_t), x2_t)
127+ res = torch.div(x1_t, safe_x2, rounding_mode="trunc")
128+ elif dtype == torch.int16:
129+ dangerous_mask = (x2_t == 0)
130+ safe_x1 = torch.where(dangerous_mask, torch.full_like(x1_t, -1), x1_t)
131+ safe_x2 = torch.where(dangerous_mask, torch.full_like(x2_t, -1), x2_t)
132+ res = torch.div(safe_x1, safe_x2, rounding_mode="trunc")
133+ else:
134+ res = torch.div(x1_t, x2_t, rounding_mode='trunc')
135+ 
136+ if len(zero_idx[0]) > 0 and need_zero_handling:
137+ x2[zero_idx] = 0
138+ if res.dtype in type_int:
139+ res[zero_x2_broadcast_idx] = -1
140+ if res.dtype in type_uint:
141+ res[zero_x2_broadcast_idx] = 255
142+ 
143+ if dtype in (torch.int16, torch.int32):
144+ info = torch.iinfo(dtype)
145+ min_val, max_val = info.min, info.max
146+ 
147+ mask = (x1_t == max_val) & (x2_t == min_val)
148+ res = torch.where(mask, torch.tensor(0, dtype=dtype), res)
149+ 
150+ mask = (x1_t == max_val) & (x2_t == -1)
151+ res = torch.where(mask, torch.tensor(-max_val, dtype=dtype), res)
152+ 
153+ mask = (x1_t == min_val) & (x2_t == -1)
154+ res = torch.where(mask, torch.tensor(min_val, dtype=dtype), res)
155+ 
156+ mask = (x2_t == 0)
157+ res = torch.where(mask, torch.tensor(-1, dtype=dtype), res)
158+ 
159+ if dtype == torch.int64:
160+ info = torch.iinfo(dtype)
161+ min_val, max_val = info.min, info.max
162+ 
163+ mask = (x1_t == max_val) & (x2_t == 0)
164+ res = torch.where(mask, torch.tensor(-1, dtype=dtype), res)
165+ 
166+ mask = (x1_t == max_val) & (x2_t == -1)
167+ res = torch.where(mask, torch.tensor(-max_val, dtype=dtype), res)
168+ 
169+ mask = (x1_t == min_val) & (x2_t == 0)
170+ res = torch.where(mask, torch.tensor(-1, dtype=dtype), res)
171+ 
172+ mask = (x1_t == min_val) & (x2_t == -1)
173+ res = torch.where(mask, torch.tensor(min_val, dtype=dtype), res)
174+ 
175+ mask = (x1_t >= 0) & (x1_t != max_val) & (x2_t == 0)
176+ res = torch.where(mask, torch.tensor(4294967295, dtype=dtype), res)
177+ 
178+ mask = (x1_t == -1) & (x2_t == 0)
179+ res = torch.where(mask, torch.tensor(-1, dtype=dtype), res)
180+ 
181+ res_np = _torch_to_numpy_tensor(res)
182+ 
183+ return res_np.astype(output_dtype, copy=False)
@@ -0,0 +1,6 @@
1+testcase_name,network_name,op_name,input_dtypes,input_ori_shapes,output_ori_shapes,input_ori_formats,output_ori_formats,attributes,input_shapes,output_dtypes,output_shapes,input_formats,output_formats,input_data_ranges,precision_tolerances,absolute_precision,output_inplace_indexes,output_shape_unknown_indexes,is_enabled,remark,soc_series,priority,dump_file_prefix,manual_input_binaries,manual_golden_binaries
2+truncate_div_custom_15,UNKNOWN,truncate_div,"('float16', 'float16')","((13, 17, 21), ())","((13, 17, 21),)","('ND', 'ND')","('ND',)",{},"((13, 17, 21), ())","('float16',)","((13, 17, 21),)","('ND', 'ND')","('ND',)","((-65504, 65504), (-1, 1))",,1e-08,(),(),True,,,0,,(),()
3+truncate_div_custom_2,UNKNOWN,truncate_div,"('float32', 'float32')","((), (2048, 5, 2))","((2048, 5, 2),)","('ND', 'ND')","('ND',)",{},"((), (2048, 5, 2))","('float32',)","((2048, 5, 2),)","('ND', 'ND')","('ND',)","((-10000, 10000), (-10000, 10000))",,1e-08,(),(),True,,,0,,(),()
4+truncate_div_custom_51,UNKNOWN,truncate_div,"('int32', 'float32')","((3, 5, 7, 99), (3, 1, 1, 99))","((3, 5, 7, 99),)","('ND', 'ND')","('ND',)",{},"((3, 5, 7, 99), (3, 1, 1, 99))","('float32',)","((3, 5, 7, 99),)","('ND', 'ND')","('ND',)","((-2147483648, 2147483647), (-10, 10))",,1e-08,(),(),True,,,0,,(),()
5+truncate_div_custom_48,UNKNOWN,truncate_div,"('int64', 'int64')","((17772, 1, 2, 1, 2, 1, 2, 1), (2, 2, 2, 2, 2, 2, 2))","((17772, 2, 2, 2, 2, 2, 2, 2),)","('ND', 'ND')","('ND',)",{},"((17772, 1, 2, 1, 2, 1, 2, 1), (2, 2, 2, 2, 2, 2, 2))","('int64',)","((17772, 2, 2, 2, 2, 2, 2, 2),)","('ND', 'ND')","('ND',)","((-9223372036854775808, 9223372036854775807), (-9223372036854775808, 9223372036854775807))",,1e-08,(),(),True,,,0,,(),()
6+truncate_div_custom_50,UNKNOWN,truncate_div,"('float16', 'float32')","((3, 5, 7, 99), (3, 1, 1, 99))","((3, 5, 7, 99),)","('ND', 'ND')","('ND',)",{},"((3, 5, 7, 99), (3, 1, 1, 99))","('float32',)","((3, 5, 7, 99),)","('ND', 'ND')","('ND',)","((-3.4028235e+38, 3.4028235e+38), (-1, 1))",,1e-08,(),(),True,,,0,,(),()
@@ -0,0 +1,135 @@
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+ 
13+import numpy as np
14+ 
15+ 
16+__golden__ = {
17+ "kernel": {
18+ "truncate_mod": "truncate_mod_golden"
19+ }
20+}
21+ 
22+ 
23+def _broadcast_to_maxshape(shapes):
24+ """
25+ produce broadcast shape
26+ for example:
27+ input: shape is [[2, 3], [3, 2, 1], [3, 1, 3]]
28+ output: [1, 2, 3], [3, 2, 1], [3, 1, 3], [3, 2, 3]
29+ """
30+ def _max(_shape):
31+ no_one_shape = [s for s in _shape if s != 1]
32+ if len(no_one_shape) == 0:
33+ max_value = 1
34+ else:
35+ max_value = no_one_shape[0]
36+ return max_value
37+ max_dim_length = max(len(list(shape)) for shape in shapes)
38+ input_shapes = []
39+ for shape in shapes:
40+ input_shapes.append([1 for _ in range(max_dim_length - len(shape))] + list(shape))
41+ input_shapes = list(map(list, zip(*input_shapes)))
42+ max_shape = [_max(shape) for shape in input_shapes]
43+ input_shapes = list(map(list, zip(*input_shapes)))
44+ return (*input_shapes, max_shape)
45+ 
46+ 
47+def _numpy_bfloat16():
48+ try:
49+ from ml_dtypes import bfloat16
50+ except ModuleNotFoundError:
51+ try:
52+ import tensorflow
53+ bfloat16 = tensorflow.bfloat16.as_numpy_dtype
54+ except ModuleNotFoundError:
55+ raise RuntimeError("ml-dtypes or tensorflow is needed to support bfloat16 dtype!!! "
56+ "Please install with `pip3 install ml-dtypes` or `pip3 install tensorflow`")
57+ return bfloat16
58+ 
59+ 
60+def _numpy_to_torch_tensor(np_array):
61+ import torch
62+ if np_array is None:
63+ return None
64+ np_dtype = np_array.dtype.name
65+ if "bfloat16" in np_dtype:
66+ np_int16 = np_array.view(dtype=np.int16)
67+ t_int16 = torch.from_numpy(np_int16)
68+ return t_int16.view(torch.bfloat16)
69+ else:
70+ return torch.from_numpy(np_array)
71+ 
72+ 
73+def _torch_to_numpy_tensor(torch_tensor):
74+ import torch
75+ if torch_tensor is None:
76+ return None
77+ if not isinstance(torch_tensor, torch.Tensor):
78+ raise RuntimeError(f"Only support torch.Tensor. But got {type(torch_tensor)}")
79+ torch_dtype = torch_tensor.dtype
80+ if torch_dtype == torch.bfloat16:
81+ t_int16 = torch_tensor.view(torch.int16)
82+ np_int16 = t_int16.numpy()
83+ return np_int16.view(dtype=_numpy_bfloat16())
84+ else:
85+ return torch_tensor.numpy()
86+ 
87+ 
88+def truncate_mod_golden(x1, x2, **kwargs):
89+ '''
90+ Kernel golden for truncate_mod.
91+ All the parameters follow @truncate_mod_def.cpp without outputs.
92+ All the input Tensors are numpy.ndarray.
93+ kwargs may contain: short_soc_version, input_ori_shapes, output_ori_shapes,
94+ input_formats, output_formats, input_ori_formats, output_ori_formats,
95+ input_dtypes, output_dtypes.
96+ '''
97+ import torch
98+ 
99+ output_dtype = kwargs.get("output_dtypes", [None])[0]
100+ if output_dtype is None:
101+ output_dtype = str(x1.dtype)
102+ 
103+ type_int = [torch.int8, torch.int16, torch.int32, torch.int64]
104+ type_uint = [torch.uint8, torch.uint16, torch.uint32, torch.uint64]
105+ type_float = [torch.float16, torch.bfloat16, torch.float, torch.float64]
106+ 
107+ # copy
108+ x1 = x1.copy()
109+ x2 = x2.copy()
110+ 
111+ # 除零保护
112+ _, _, res_shape = _broadcast_to_maxshape([x1.shape, x2.shape])
113+ X2_broadcast = np.broadcast_to(x2, res_shape)
114+ zero_X2_broadcast_idx = np.where(X2_broadcast == 0)
115+ 
116+ zero_idx = np.where(x2 == 0)
117+ if zero_idx:
118+ x2[zero_idx] = 1
119+ 
120+ x1 = _numpy_to_torch_tensor(x1)
121+ x2 = _numpy_to_torch_tensor(x2)
122+ res = torch.fmod(x1, x2)
123+ 
124+ # 除零保护
125+ if zero_idx:
126+ x2[zero_idx] = 0
127+ if res.dtype in type_int:
128+ res[zero_X2_broadcast_idx] = -1
129+ if res.dtype in type_uint:
130+ res[zero_X2_broadcast_idx] = 255
131+ if res.dtype in type_float:
132+ res[zero_X2_broadcast_idx] = torch.nan
133+ 
134+ res_np = _torch_to_numpy_tensor(res)
135+ return res_np.astype(output_dtype, copy=False)
@@ -0,0 +1,6 @@
1+testcase_name,network_name,op_name,input_dtypes,input_ori_shapes,output_ori_shapes,input_ori_formats,output_ori_formats,attributes,input_shapes,output_dtypes,output_shapes,input_formats,output_formats,input_data_ranges,precision_tolerances,absolute_precision,output_inplace_indexes,output_shape_unknown_indexes,is_enabled,remark,soc_series,priority,dump_file_prefix,manual_input_binaries,manual_golden_binaries
2+truncate_mod_3,UNKNOWN,truncate_mod,"('bfloat16', 'bfloat16')","((1, 79, 1, 112, 1), (1, 79, 1, 112, 1))","((1, 79, 1, 112, 1),)","('NCDHW', 'NCDHW')","('NCDHW',)",{},"((1, 79, 1, 112, 1), (1, 79, 1, 112, 1))","('bfloat16',)","((1, 79, 1, 112, 1),)","('NCDHW', 'NCDHW')","('NCDHW',)","((10, 1000), (0.0001, 100))","((0.004, 0.004),)",1e-08,(),(),True,,,0,,(),()
3+truncate_mod_31,UNKNOWN,truncate_mod,"('float16', 'float16')","((1, 96, 1, 1, 96), (1, 96, 1, 1, 96))","((1, 96, 1, 1, 96),)","('NDHWC', 'NDHWC')","('NDHWC',)",{},"((1, 96, 1, 1, 96), (1, 96, 1, 1, 96))","('float16',)","((1, 96, 1, 1, 96),)","('NDHWC', 'NDHWC')","('NDHWC',)","((-1, 1), (-1, 1))","((0.001, 0.001),)",1e-08,(),(),True,,,0,,(),()
4+truncate_mod_14,UNKNOWN,truncate_mod,"('float32', 'float32')","((96, 1), (96, 1))","((96, 1),)","('ND', 'ND')","('ND',)",{},"((1, 6, 16, 16), (1, 6, 16, 16))","('float32',)","((1, 6, 16, 16),)","('FRACTAL_NZ', 'FRACTAL_NZ')","('FRACTAL_NZ',)","((-1, 1), (-1, 1))","((0.0001, 0.0001),)",1e-08,(),(),True,,,0,,(),()
5+truncate_mod_6,UNKNOWN,truncate_mod,"('int8', 'int8')","((1, 1, 7, 1), (1, 1, 7, 1))","((1, 1, 7, 1),)","('NCHW', 'NCHW')","('NCHW',)",{},"((7, 1, 16, 32), (7, 1, 16, 32))","('int8',)","((7, 1, 16, 32),)","('FRACTAL_Z', 'FRACTAL_Z')","('FRACTAL_Z',)","((-100, 100), (-100, 100))","((0.001, 0.001),)",1e-08,(),(),True,,,0,,(),()
6+truncate_mod_21,UNKNOWN,truncate_mod,"('int8', 'int8')","((1, 1, 1, 320), (1, 1, 1, 320))","((1, 1, 1, 320),)","('NCHW', 'NCHW')","('NCHW',)",{},"((1, 1, 1, 320), (1, 1, 1, 320))","('int8',)","((1, 1, 1, 320),)","('NCHW', 'NCHW')","('NCHW',)","((-100, 100), (-100, 100))","((0.001, 0.001),)",1e-08,(),(),True,,,0,,(),()