已合并
fix(pad_v2): golden bfloat16 分支 cv 转为 float 避免类型错误 #3625
yefeicoding创建于 6月29日
fix(pad_v2): golden bfloat16 分支 cv 转为 float 避免类型错误 #3625
已合并
共 8 个文件变更+495-75
| @@ -11,8 +11,6 @@ | |||
| 11 | # ---------------------------------------------------------------------------- | 11 | # ---------------------------------------------------------------------------- |
| 12 | 12 | ||
| 13 | import numpy as np | 13 | import 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.shape | 24 | + 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_tensor | 69 | 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.shape | 73 | + 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.shape | 82 | + 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.shape | 90 | + 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 = 16 | 95 | + transposed = tf.transpose(reshaped, perm) |
| 73 | - axis_c1 = (axis_c + axis_c0 - 1) // axis_c0 | 96 | + |
| 74 | - axis_d = 1 | 97 | + 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_tensor | 100 | + |
| 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 | ||
| 80 | def batch_to_space_nd_golden(x, block_shape, crops, **kwargs): | 115 | def 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 | ||
| 13 | import numpy as np | 13 | import 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.dtype | 25 | + 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,,(),() | ||