已合并
卷积算子golden和input能力支持 #8206
huafeng793创建于 20 天前
卷积算子golden和input能力支持 #8206
已合并
共 10 个文件变更+1241-528
| @@ -29,10 +29,7 @@ Supported dtypes: float16, float32, bfloat16, hifloat8, float8_e4m3fn, int8, int | |||
| 29 | import numpy as np | 29 | import numpy as np |
| 30 | 30 | ||
| 31 | __golden__ = { | 31 | __golden__ = { |
| 32 | - "kernel": { | 32 | + "kernel": {"conv2dv2": "conv2d_v2_golden", "conv2d_v2": "conv2d_v2_golden"} |
| 33 | - "conv2dv2": "conv2d_v2_golden", | ||
| 34 | - "conv2d_v2": "conv2d_v2_golden" | ||
| 35 | - } | ||
| 36 | } | 33 | } |
| 37 | 34 | ||
| 38 | FP32_STR = "float32" | 35 | FP32_STR = "float32" |
| @@ -92,10 +89,14 @@ def convert_output_dtype(out, output_dtype, enable_hf32=False): | |||
| 92 | if isinstance(dtype_ref, str): | 89 | if isinstance(dtype_ref, str): |
| 93 | module_name, dtype_name = dtype_ref.split(".") | 90 | module_name, dtype_name = dtype_ref.split(".") |
| 94 | try: | 91 | try: |
| 95 | - dtype_cls = getattr(__import__(module_name, fromlist=[dtype_name]), dtype_name) | 92 | + dtype_cls = getattr( |
| 93 | + __import__(module_name, fromlist=[dtype_name]), dtype_name | ||
| 94 | + ) | ||
| 96 | except (ImportError, AttributeError): | 95 | except (ImportError, AttributeError): |
| 97 | - raise RuntimeError(f"{module_name} is required for {output_dtype}. " | 96 | + raise RuntimeError( |
| 98 | - f"Install: pip install {module_name}") | 97 | + f"{module_name} is required for {output_dtype}. " |
| 98 | + f"Install: pip install {module_name}" | ||
| 99 | + ) | ||
| 99 | out = out.astype(dtype_cls) | 100 | out = out.astype(dtype_cls) |
| 100 | else: | 101 | else: |
| 101 | out = out.astype(dtype_ref) | 102 | out = out.astype(dtype_ref) |
| @@ -111,13 +112,13 @@ def process_formats_a5(x, filter, input_formats): | |||
| 111 | - filter supports: NCHW (when x is NCHW) or HWCN (when x is NHWC) | 112 | - filter supports: NCHW (when x is NCHW) or HWCN (when x is NHWC) |
| 112 | """ | 113 | """ |
| 113 | input_data_format, input_filter_format = input_formats[0], input_formats[1] | 114 | input_data_format, input_filter_format = input_formats[0], input_formats[1] |
| 114 | - | 115 | + |
| 115 | if input_data_format == "NHWC": | 116 | if input_data_format == "NHWC": |
| 116 | x = x.transpose(0, 3, 1, 2) | 117 | x = x.transpose(0, 3, 1, 2) |
| 117 | - | 118 | + |
| 118 | if input_filter_format == "HWCN": | 119 | if input_filter_format == "HWCN": |
| 119 | filter = filter.transpose(3, 2, 0, 1) | 120 | filter = filter.transpose(3, 2, 0, 1) |
| 120 | - | 121 | + |
| 121 | return x, filter | 122 | return x, filter |
| 122 | 123 | ||
| 123 | 124 | ||
| @@ -129,14 +130,16 @@ def process_output_format_a5(out, output_format): | |||
| 129 | """ | 130 | """ |
| 130 | if output_format == "NHWC": | 131 | if output_format == "NHWC": |
| 131 | out = out.transpose((0, 2, 3, 1)) | 132 | out = out.transpose((0, 2, 3, 1)) |
| 132 | - | 133 | + |
| 133 | return out | 134 | return out |
| 134 | 135 | ||
| 135 | 136 | ||
| 136 | -def get_ori_pad_from_pad_mode(x_np, filter_np, pads, pad_mode, stride_h, stride_w, dilation_h, dilation_w): | 137 | +def get_ori_pad_from_pad_mode( |
| 138 | + x_np, filter_np, pads, pad_mode, stride_h, stride_w, dilation_h, dilation_w | ||
| 139 | +): | ||
| 137 | """ | 140 | """ |
| 138 | Calculate original padding values based on pad_mode, corresponding to C++ GetOriPadFromPadMode. | 141 | Calculate original padding values based on pad_mode, corresponding to C++ GetOriPadFromPadMode. |
| 139 | - | 142 | + |
| 140 | Args: | 143 | Args: |
| 141 | x_np: Input feature map numpy array | 144 | x_np: Input feature map numpy array |
| 142 | filter_np: Weight filter numpy array | 145 | filter_np: Weight filter numpy array |
| @@ -146,7 +149,7 @@ def get_ori_pad_from_pad_mode(x_np, filter_np, pads, pad_mode, stride_h, stride_ | |||
| 146 | stride_w: Stride in W dimension | 149 | stride_w: Stride in W dimension |
| 147 | dilation_h: Dilation in H dimension | 150 | dilation_h: Dilation in H dimension |
| 148 | dilation_w: Dilation in W dimension | 151 | dilation_w: Dilation in W dimension |
| 149 | - | 152 | + |
| 150 | Returns: | 153 | Returns: |
| 151 | Tuple (pad_top, pad_bottom, pad_left, pad_right) | 154 | Tuple (pad_top, pad_bottom, pad_left, pad_right) |
| 152 | """ | 155 | """ |
| @@ -161,9 +164,19 @@ def get_ori_pad_from_pad_mode(x_np, filter_np, pads, pad_mode, stride_h, stride_ | |||
| 161 | if pad_mode_upper == "SPECIFIC": | 164 | if pad_mode_upper == "SPECIFIC": |
| 162 | if isinstance(pads, (list, tuple)): | 165 | if isinstance(pads, (list, tuple)): |
| 163 | if len(pads) == 4: | 166 | if len(pads) == 4: |
| 164 | - pad_top, pad_bottom, pad_left, pad_right = int(pads[0]), int(pads[1]), int(pads[2]), int(pads[3]) | 167 | + pad_top, pad_bottom, pad_left, pad_right = ( |
| 168 | + int(pads[0]), | ||
| 169 | + int(pads[1]), | ||
| 170 | + int(pads[2]), | ||
| 171 | + int(pads[3]), | ||
| 172 | + ) | ||
| 165 | elif len(pads) == 2: | 173 | elif len(pads) == 2: |
| 166 | - pad_top, pad_bottom, pad_left, pad_right = int(pads[0]), int(pads[0]), int(pads[1]), int(pads[1]) | 174 | + pad_top, pad_bottom, pad_left, pad_right = ( |
| 175 | + int(pads[0]), | ||
| 176 | + int(pads[0]), | ||
| 177 | + int(pads[1]), | ||
| 178 | + int(pads[1]), | ||
| 179 | + ) | ||
| 167 | else: | 180 | else: |
| 168 | pad_val = int(pads[0]) | 181 | pad_val = int(pads[0]) |
| 169 | pad_top = pad_bottom = pad_left = pad_right = pad_val | 182 | pad_top = pad_bottom = pad_left = pad_right = pad_val |
| @@ -173,8 +186,18 @@ def get_ori_pad_from_pad_mode(x_np, filter_np, pads, pad_mode, stride_h, stride_ | |||
| 173 | elif pad_mode_upper == "VALID": | 186 | elif pad_mode_upper == "VALID": |
| 174 | pad_top = pad_bottom = pad_left = pad_right = 0 | 187 | pad_top = pad_bottom = pad_left = pad_right = 0 |
| 175 | else: | 188 | else: |
| 176 | - pad_h = (conv_ceil_div(in_h, stride_h) - 1) * stride_h + dilation_h * (k_h - 1) - in_h + 1 | 189 | + pad_h = ( |
| 177 | - pad_w = (conv_ceil_div(in_w, stride_w) - 1) * stride_w + dilation_w * (k_w - 1) - in_w + 1 | 190 | + (conv_ceil_div(in_h, stride_h) - 1) * stride_h |
| 191 | + + dilation_h * (k_h - 1) | ||
| 192 | + - in_h | ||
| 193 | + + 1 | ||
| 194 | + ) | ||
| 195 | + pad_w = ( | ||
| 196 | + (conv_ceil_div(in_w, stride_w) - 1) * stride_w | ||
| 197 | + + dilation_w * (k_w - 1) | ||
| 198 | + - in_w | ||
| 199 | + + 1 | ||
| 200 | + ) | ||
| 178 | if pad_mode_upper == "SAME" or pad_mode_upper == "SAME_UPPER": | 201 | if pad_mode_upper == "SAME" or pad_mode_upper == "SAME_UPPER": |
| 179 | if pad_mode_upper == "SAME": | 202 | if pad_mode_upper == "SAME": |
| 180 | pad_h = max(0, pad_h) | 203 | pad_h = max(0, pad_h) |
| @@ -193,18 +216,22 @@ def get_ori_pad_from_pad_mode(x_np, filter_np, pads, pad_mode, stride_h, stride_ | |||
| 193 | return pad_top, pad_bottom, pad_left, pad_right | 216 | return pad_top, pad_bottom, pad_left, pad_right |
| 194 | 217 | ||
| 195 | 218 | ||
| 196 | -def conv2d_v2_golden(x, filter, bias=None, offset_w=None, | 219 | +def conv2d_v2_golden( |
| 197 | - *, | 220 | + x, |
| 198 | - strides: list, | 221 | + filter, |
| 199 | - pads: list = [0, 0, 0, 0], | 222 | + bias=None, |
| 200 | - dilations: list = [1, 1, 1, 1], | 223 | + offset_w=None, |
| 201 | - groups: int = 1, | 224 | + *, |
| 202 | - data_format: str = NCHW_FORMAT, | 225 | + strides: list, |
| 203 | - offset_x: int = 0, | 226 | + pads: list = [0, 0, 0, 0], |
| 204 | - pad_mode: str = "SPECIFIC", | 227 | + dilations: list = [1, 1, 1, 1], |
| 205 | - enable_hf32: bool = False, | 228 | + groups: int = 1, |
| 206 | - **kwargs, | 229 | + data_format: str = NCHW_FORMAT, |
| 207 | - ): | 230 | + offset_x: int = 0, |
| 231 | + pad_mode: str = "SPECIFIC", | ||
| 232 | + enable_hf32: bool = False, | ||
| 233 | + **kwargs, | ||
| 234 | +): | ||
| 208 | """ | 235 | """ |
| 209 | Kernel golden for conv2d_v2. | 236 | Kernel golden for conv2d_v2. |
| 210 | All parameters follow @conv2d_v2_def.cpp without outputs. | 237 | All parameters follow @conv2d_v2_def.cpp without outputs. |
| @@ -215,43 +242,49 @@ def conv2d_v2_golden(x, filter, bias=None, offset_w=None, | |||
| 215 | """ | 242 | """ |
| 216 | import torch | 243 | import torch |
| 217 | import torch.nn.functional as F | 244 | import torch.nn.functional as F |
| 218 | - | 245 | + |
| 219 | input_formats = kwargs.get("input_formats", [NCHW_FORMAT, NCHW_FORMAT]) | 246 | input_formats = kwargs.get("input_formats", [NCHW_FORMAT, NCHW_FORMAT]) |
| 220 | input_format = input_formats[0] | 247 | input_format = input_formats[0] |
| 221 | short_soc_version = kwargs.get("short_soc_version", None) | 248 | short_soc_version = kwargs.get("short_soc_version", None) |
| 222 | 249 | ||
| 223 | - x_dtype_str = x.dtype.name | 250 | + x_dtype_str = x.dtype.name |
| 224 | - filter_dtype_str = filter.dtype.name | ||
| 225 | - | ||
| 226 | x_np, filter_np = process_formats_a5(x, filter, input_formats) | 251 | x_np, filter_np = process_formats_a5(x, filter, input_formats) |
| 227 | - | 252 | + |
| 228 | if enable_hf32 and x_dtype_str == FP32_STR: | 253 | if enable_hf32 and x_dtype_str == FP32_STR: |
| 229 | calc_dtype = np.float32 | 254 | calc_dtype = np.float32 |
| 230 | x_np = simulate_hf32_precision(x_np.astype(np.float32), short_soc_version) | 255 | x_np = simulate_hf32_precision(x_np.astype(np.float32), short_soc_version) |
| 231 | - filter_np = simulate_hf32_precision(filter_np.astype(np.float32), short_soc_version) | 256 | + filter_np = simulate_hf32_precision( |
| 257 | + filter_np.astype(np.float32), short_soc_version | ||
| 258 | + ) | ||
| 232 | else: | 259 | else: |
| 233 | - calc_dtype = np.float64 if x_dtype_str == FP32_STR else np.float32 | 260 | + calc_dtype = np.float32 |
| 234 | x_np = x_np.astype(calc_dtype) | 261 | x_np = x_np.astype(calc_dtype) |
| 235 | filter_np = filter_np.astype(calc_dtype) | 262 | filter_np = filter_np.astype(calc_dtype) |
| 236 | - | 263 | + |
| 237 | if bias is not None: | 264 | if bias is not None: |
| 238 | bias_np = bias.astype(calc_dtype) | 265 | bias_np = bias.astype(calc_dtype) |
| 239 | else: | 266 | else: |
| 240 | bias_np = None | 267 | bias_np = None |
| 241 | - | 268 | + |
| 242 | if isinstance(strides, (list, tuple)): | 269 | if isinstance(strides, (list, tuple)): |
| 243 | if len(strides) == 4: | 270 | if len(strides) == 4: |
| 244 | - stride_h, stride_w = int(strides[2]), int(strides[3]) | 271 | + if input_format == "NHWC": |
| 272 | + stride_h, stride_w = int(strides[1]), int(strides[2]) | ||
| 273 | + else: | ||
| 274 | + stride_h, stride_w = int(strides[2]), int(strides[3]) | ||
| 245 | elif len(strides) == 2: | 275 | elif len(strides) == 2: |
| 246 | stride_h, stride_w = int(strides[0]), int(strides[1]) | 276 | stride_h, stride_w = int(strides[0]), int(strides[1]) |
| 247 | else: | 277 | else: |
| 248 | stride_h = stride_w = int(strides[0]) | 278 | stride_h = stride_w = int(strides[0]) |
| 249 | else: | 279 | else: |
| 250 | stride_h = stride_w = int(strides) | 280 | stride_h = stride_w = int(strides) |
| 251 | - | 281 | + |
| 252 | if isinstance(dilations, (list, tuple)): | 282 | if isinstance(dilations, (list, tuple)): |
| 253 | if len(dilations) == 4: | 283 | if len(dilations) == 4: |
| 254 | - dilation_h, dilation_w = int(dilations[2]), int(dilations[3]) | 284 | + if input_format == "NHWC": |
| 285 | + dilation_h, dilation_w = int(dilations[1]), int(dilations[2]) | ||
| 286 | + else: | ||
| 287 | + dilation_h, dilation_w = int(dilations[2]), int(dilations[3]) | ||
| 255 | elif len(dilations) == 2: | 288 | elif len(dilations) == 2: |
| 256 | dilation_h, dilation_w = int(dilations[0]), int(dilations[1]) | 289 | dilation_h, dilation_w = int(dilations[0]), int(dilations[1]) |
| 257 | else: | 290 | else: |
| @@ -259,16 +292,18 @@ def conv2d_v2_golden(x, filter, bias=None, offset_w=None, | |||
| 259 | else: | 292 | else: |
| 260 | dilation_h = dilation_w = int(dilations) | 293 | dilation_h = dilation_w = int(dilations) |
| 261 | 294 | ||
| 262 | - pad_top, pad_bottom, pad_left, pad_right = get_ori_pad_from_pad_mode(x_np, filter_np, pads, pad_mode, stride_h, stride_w, dilation_h, dilation_w) | 295 | + pad_top, pad_bottom, pad_left, pad_right = get_ori_pad_from_pad_mode( |
| 296 | + x_np, filter_np, pads, pad_mode, stride_h, stride_w, dilation_h, dilation_w | ||
| 297 | + ) | ||
| 263 | input_torch = torch.from_numpy(x_np) | 298 | input_torch = torch.from_numpy(x_np) |
| 264 | weight_torch = torch.from_numpy(filter_np) | 299 | weight_torch = torch.from_numpy(filter_np) |
| 265 | bias_torch = torch.from_numpy(bias_np) if bias_np is not None else None | 300 | bias_torch = torch.from_numpy(bias_np) if bias_np is not None else None |
| 266 | - | 301 | + |
| 267 | torch_pad = (pad_left, pad_right, pad_top, pad_bottom) | 302 | torch_pad = (pad_left, pad_right, pad_top, pad_bottom) |
| 268 | if any(pad > 0 for pad in (pad_top, pad_bottom, pad_left, pad_right)): | 303 | if any(pad > 0 for pad in (pad_top, pad_bottom, pad_left, pad_right)): |
| 269 | pad_value = float(offset_x) if offset_x != 0 else 0.0 | 304 | pad_value = float(offset_x) if offset_x != 0 else 0.0 |
| 270 | input_torch = F.pad(input_torch, torch_pad, "constant", pad_value) | 305 | input_torch = F.pad(input_torch, torch_pad, "constant", pad_value) |
| 271 | - | 306 | + |
| 272 | out = torch.nn.functional.conv2d( | 307 | out = torch.nn.functional.conv2d( |
| 273 | input_torch, | 308 | input_torch, |
| 274 | weight_torch, | 309 | weight_torch, |
| @@ -285,7 +320,7 @@ def conv2d_v2_golden(x, filter, bias=None, offset_w=None, | |||
| 285 | output_format = output_formats[0] | 320 | output_format = output_formats[0] |
| 286 | 321 | ||
| 287 | out = convert_output_dtype(out, output_dtype, enable_hf32) | 322 | out = convert_output_dtype(out, output_dtype, enable_hf32) |
| 288 | - | 323 | + |
| 289 | out = process_output_format_a5(out, output_format) | 324 | out = process_output_format_a5(out, output_format) |
| 290 | - | 325 | + |
| 291 | return out | 326 | return out |
| @@ -48,7 +48,18 @@ ASCENDC_TPL_ARGS_DECL( | |||
| 48 | 48 | ||
| 49 | 49 | ||
| 50 | 50 | ||
| 51 | - | 51 | +#define CONV3D_BIG_KERNEL_SEL() \ |
| 52 | + ASCENDC_TPL_KERNEL_TYPE_SEL(ASCENDC_TPL_MIX_AIC_1_2), \ | ||
| 53 | + ASCENDC_TPL_UINT_SEL(FmapTiling, ASCENDC_TPL_UI_LIST, CONV_FMAP_TILING_OTHER), \ | ||
| 54 | + ASCENDC_TPL_UINT_SEL(WeightTiling, ASCENDC_TPL_UI_LIST, CONV_WEIGHT_TILING_OTHER), \ | ||
| 55 | + ASCENDC_TPL_UINT_SEL(L1PingPong, ASCENDC_TPL_UI_LIST, CONV_L1_PINGPONG_ALL_OPEN), \ | ||
| 56 | + ASCENDC_TPL_UINT_SEL(L0PingPong, ASCENDC_TPL_UI_LIST, CONV_L0_PINGPONG_ALL_CLOSE, CONV_L0_PINGPONG_AL0_OPEN, \ | ||
| 57 | + CONV_L0_PINGPONG_BL0_OPEN, CONV_L0_PINGPONG_ALL_OPEN), \ | ||
| 58 | + ASCENDC_TPL_UINT_SEL(OutputOrder, ASCENDC_TPL_UI_LIST, CONV_OUTPUT_ORDER_HW_MODE), \ | ||
| 59 | + ASCENDC_TPL_UINT_SEL(IterOrder, ASCENDC_TPL_UI_LIST, CONV_ITER_ORDER_MITER_FIRST, \ | ||
| 60 | + CONV_ITER_ORDER_NITER_FIRST), \ | ||
| 61 | + ASCENDC_TPL_UINT_SEL(GroupType, ASCENDC_TPL_UI_LIST, CONV_GROUP_TYPE_NORMAL_CONV), \ | ||
| 62 | + ASCENDC_TPL_UINT_SEL(BigKernel, ASCENDC_TPL_UI_LIST, CONV_BIG_KERNEL) | ||
| 52 | 63 | ||
| 53 | 64 | ||
| 54 | 65 | ||
| @@ -59,10 +70,9 @@ ASCENDC_TPL_ARGS_DECL( | |||
| 59 | ASCENDC_TPL_KERNEL_TYPE_SEL(ASCENDC_TPL_AIC_ONLY), CONV_COMMON_ORI_GROUP_SEL(), \ | 70 | ASCENDC_TPL_KERNEL_TYPE_SEL(ASCENDC_TPL_AIC_ONLY), CONV_COMMON_ORI_GROUP_SEL(), \ |
| 60 | ASCENDC_TPL_UINT_SEL(BigKernel, ASCENDC_TPL_UI_LIST, CONV_NORMAL_KERNEL) | 71 | ASCENDC_TPL_UINT_SEL(BigKernel, ASCENDC_TPL_UI_LIST, CONV_NORMAL_KERNEL) |
| 61 | 72 | ||
| 62 | - | ||
| 63 | - | ||
| 64 | 73 | ||
| 65 | - ASCENDC_TPL_UINT_SEL(FmapTiling, ASCENDC_TPL_UI_LIST, CONV_FMAP_TILING_OTHER), \ | 74 | + ASCENDC_TPL_KERNEL_TYPE_SEL(ASCENDC_TPL_MIX_AIC_1_2), \ |
| 75 | + ASCENDC_TPL_UINT_SEL(FmapTiling, ASCENDC_TPL_UI_LIST, CONV_FMAP_TILING_OTHER), \ | ||
| 66 | ASCENDC_TPL_UINT_SEL(WeightTiling, ASCENDC_TPL_UI_LIST, CONV_WEIGHT_TILING_OTHER), \ | 76 | ASCENDC_TPL_UINT_SEL(WeightTiling, ASCENDC_TPL_UI_LIST, CONV_WEIGHT_TILING_OTHER), \ |
| 67 | ASCENDC_TPL_UINT_SEL(L1PingPong, ASCENDC_TPL_UI_LIST, CONV_L1_PINGPONG_ALL_OPEN), \ | 77 | ASCENDC_TPL_UINT_SEL(L1PingPong, ASCENDC_TPL_UI_LIST, CONV_L1_PINGPONG_ALL_OPEN), \ |
| 68 | ASCENDC_TPL_UINT_SEL(L0PingPong, ASCENDC_TPL_UI_LIST, CONV_L0_PINGPONG_ALL_CLOSE, CONV_L0_PINGPONG_AL0_OPEN, \ | 78 | ASCENDC_TPL_UINT_SEL(L0PingPong, ASCENDC_TPL_UI_LIST, CONV_L0_PINGPONG_ALL_CLOSE, CONV_L0_PINGPONG_AL0_OPEN, \ |
| @@ -73,6 +83,7 @@ ASCENDC_TPL_ARGS_DECL( | |||
| 73 | ASCENDC_TPL_UINT_SEL(GroupType, ASCENDC_TPL_UI_LIST, CONV_GROUP_TYPE_NORMAL_CONV, \ | 83 | ASCENDC_TPL_UINT_SEL(GroupType, ASCENDC_TPL_UI_LIST, CONV_GROUP_TYPE_NORMAL_CONV, \ |
| 74 | CONV_GROUP_TYPE_ORI_GROUP_CONV), \ | 84 | CONV_GROUP_TYPE_ORI_GROUP_CONV), \ |
| 75 | ASCENDC_TPL_UINT_SEL(BigKernel, ASCENDC_TPL_UI_LIST, CONV_BIG_KERNEL) | 85 | ASCENDC_TPL_UINT_SEL(BigKernel, ASCENDC_TPL_UI_LIST, CONV_BIG_KERNEL) |
| 86 | + | ||
| 76 | 87 | ||
| 77 | 88 | ||
| 78 | CONV_COMMON_ONLY_MN_FULLLOAD_SEL(), ASCENDC_TPL_UINT_SEL(BigKernel, ASCENDC_TPL_UI_LIST, CONV_NORMAL_KERNEL) | 89 | CONV_COMMON_ONLY_MN_FULLLOAD_SEL(), ASCENDC_TPL_UINT_SEL(BigKernel, ASCENDC_TPL_UI_LIST, CONV_NORMAL_KERNEL) |
| @@ -107,8 +118,8 @@ ASCENDC_TPL_SEL(ASCENDC_TPL_ARGS_SEL(CONV3D_KERNEL_TYPE_SEL, CONV3D_COMMON_ONLY_ | |||
| 107 | ASCENDC_TPL_ARGS_SEL(CONV3D_KERNEL_TYPE_SEL, CONV3D_COMMON_ABL1_FULLLOAD_M_FIRST_SEL()), | 118 | ASCENDC_TPL_ARGS_SEL(CONV3D_KERNEL_TYPE_SEL, CONV3D_COMMON_ABL1_FULLLOAD_M_FIRST_SEL()), |
| 108 | ASCENDC_TPL_ARGS_SEL(CONV3D_KERNEL_TYPE_SEL, CONV3D_COMMON_ABL1_FULLLOAD_N_FIRST_SEL()), | 119 | ASCENDC_TPL_ARGS_SEL(CONV3D_KERNEL_TYPE_SEL, CONV3D_COMMON_ABL1_FULLLOAD_N_FIRST_SEL()), |
| 109 | ASCENDC_TPL_ARGS_SEL(CONV3D_OPT_GROUP_SEL()), ASCENDC_TPL_ARGS_SEL(CONV3D_ORI_GROUP_SEL()), | 120 | ASCENDC_TPL_ARGS_SEL(CONV3D_OPT_GROUP_SEL()), ASCENDC_TPL_ARGS_SEL(CONV3D_ORI_GROUP_SEL()), |
| 110 | - ASCENDC_TPL_ARGS_SEL(CONV3D_KERNEL_TYPE_SEL, CONV3D_BIG_KERNEL_SEL())); | 121 | + ASCENDC_TPL_ARGS_SEL(CONV3D_BIG_KERNEL_SEL())); |
| 111 | 122 | ||
| 112 | } // namespace Conv3DV2Key | 123 | } // namespace Conv3DV2Key |
| 113 | 124 | ||
| 114 | -#endif // CONV3D_V2_TILINGKEY_H | 125 | +#endif // CONV3D_V2_TILINGKEY_H |
| @@ -37,10 +37,7 @@ import numpy as np | |||
| 37 | # Set to False to use PyTorch implementation | 37 | # Set to False to use PyTorch implementation |
| 38 | 38 | ||
| 39 | __golden__ = { | 39 | __golden__ = { |
| 40 | - "kernel": { | 40 | + "kernel": {"conv3dv2": "conv3d_v2_golden", "conv3d_v2": "conv3d_v2_golden"} |
| 41 | - "conv3dv2": "conv3d_v2_golden", | ||
| 42 | - "conv3d_v2": "conv3d_v2_golden" | ||
| 43 | - } | ||
| 44 | } | 41 | } |
| 45 | 42 | ||
| 46 | 43 | ||
| @@ -96,10 +93,14 @@ def convert_output_dtype(out, output_dtype, enable_hf32=False, short_soc_version | |||
| 96 | if isinstance(dtype_ref, str): | 93 | if isinstance(dtype_ref, str): |
| 97 | module_name, dtype_name = dtype_ref.split(".") | 94 | module_name, dtype_name = dtype_ref.split(".") |
| 98 | try: | 95 | try: |
| 99 | - dtype_cls = getattr(__import__(module_name, fromlist=[dtype_name]), dtype_name) | 96 | + dtype_cls = getattr( |
| 97 | + __import__(module_name, fromlist=[dtype_name]), dtype_name | ||
| 98 | + ) | ||
| 100 | except (ImportError, AttributeError): | 99 | except (ImportError, AttributeError): |
| 101 | - raise RuntimeError(f"{module_name} is required for {output_dtype}. " | 100 | + raise RuntimeError( |
| 102 | - f"Install: pip install {module_name}") | 101 | + f"{module_name} is required for {output_dtype}. " |
| 102 | + f"Install: pip install {module_name}" | ||
| 103 | + ) | ||
| 103 | out = out.astype(dtype_cls) | 104 | out = out.astype(dtype_cls) |
| 104 | else: | 105 | else: |
| 105 | out = out.astype(dtype_ref) | 106 | out = out.astype(dtype_ref) |
| @@ -120,6 +121,7 @@ def align(a, b): | |||
| 120 | 121 | ||
| 121 | def _lcm(a, b): | 122 | def _lcm(a, b): |
| 122 | import math | 123 | import math |
| 124 | + | ||
| 123 | return abs(a * b) // math.gcd(a, b) if a and b else 0 | 125 | return abs(a * b) // math.gcd(a, b) if a and b else 0 |
| 124 | 126 | ||
| 125 | 127 | ||
| @@ -132,6 +134,7 @@ def determine_c0(dtype, target_shape): | |||
| 132 | "float4_e2m1", | 134 | "float4_e2m1", |
| 133 | "float4_e1m2", | 135 | "float4_e1m2", |
| 134 | "hifloat8", | 136 | "hifloat8", |
| 137 | + "int8", | ||
| 135 | ]: | 138 | ]: |
| 136 | return 32 | 139 | return 32 |
| 137 | else: | 140 | else: |
| @@ -176,7 +179,7 @@ def to_NDC1HWC0(data, ori_format, target_shape): | |||
| 176 | 179 | ||
| 177 | def is_ascend950(short_soc_version): | 180 | def is_ascend950(short_soc_version): |
| 178 | """Check if the target is Ascend 950PR/950DT""" | 181 | """Check if the target is Ascend 950PR/950DT""" |
| 179 | - return (short_soc_version == "Ascend950") | 182 | + return short_soc_version == "Ascend950" |
| 180 | 183 | ||
| 181 | 184 | ||
| 182 | def process_formats_a2_a3(x, filter, input_formats, input_ori_shapes, groups): | 185 | def process_formats_a2_a3(x, filter, input_formats, input_ori_shapes, groups): |
| @@ -189,34 +192,37 @@ def process_formats_a2_a3(x, filter, input_formats, input_ori_shapes, groups): | |||
| 189 | - DHWCN format is not supported | 192 | - DHWCN format is not supported |
| 190 | """ | 193 | """ |
| 191 | input_data_format, input_filter_format = input_formats[0], input_formats[1] | 194 | input_data_format, input_filter_format = input_formats[0], input_formats[1] |
| 192 | - | 195 | + |
| 193 | if input_data_format == "NDC1HWC0": | 196 | if input_data_format == "NDC1HWC0": |
| 194 | if input_ori_shapes is not None: | 197 | if input_ori_shapes is not None: |
| 195 | x = to_NCDHW_from_NDC1HWC0(x, input_ori_shapes[0]) | 198 | x = to_NCDHW_from_NDC1HWC0(x, input_ori_shapes[0]) |
| 196 | - | 199 | + |
| 197 | if input_filter_format == "FRACTAL_Z_3D": | 200 | if input_filter_format == "FRACTAL_Z_3D": |
| 198 | if input_ori_shapes is not None: | 201 | if input_ori_shapes is not None: |
| 199 | filter = to_NCDHW_from_FRACTAL_Z_3D(filter, input_ori_shapes[1], groups) | 202 | filter = to_NCDHW_from_FRACTAL_Z_3D(filter, input_ori_shapes[1], groups) |
| 200 | - | 203 | + |
| 201 | return x, filter | 204 | return x, filter |
| 202 | 205 | ||
| 203 | 206 | ||
| 204 | -def process_formats_a5(x, filter, input_formats): | 207 | +def process_formats_a5(x, filter, input_formats, input_ori_shapes=None, groups=1): |
| 205 | """ | 208 | """ |
| 206 | Process format conversion for Ascend 950PR/950DT (A5). | 209 | Process format conversion for Ascend 950PR/950DT (A5). |
| 207 | 210 | ||
| 208 | Constraints: | 211 | Constraints: |
| 209 | - x supports: NCDHW, NDHWC | 212 | - x supports: NCDHW, NDHWC |
| 210 | - - filter supports: NCDHW, DHWCN | 213 | + - filter supports: NCDHW, DHWCN, FRACTAL_Z_3D |
| 211 | """ | 214 | """ |
| 212 | input_data_format, input_filter_format = input_formats[0], input_formats[1] | 215 | input_data_format, input_filter_format = input_formats[0], input_formats[1] |
| 213 | - | 216 | + |
| 214 | if input_data_format == "NDHWC": | 217 | if input_data_format == "NDHWC": |
| 215 | x = x.transpose(0, 4, 1, 2, 3) | 218 | x = x.transpose(0, 4, 1, 2, 3) |
| 216 | - | 219 | + |
| 217 | if input_filter_format == "DHWCN": | 220 | if input_filter_format == "DHWCN": |
| 218 | filter = filter.transpose(4, 3, 0, 1, 2) | 221 | filter = filter.transpose(4, 3, 0, 1, 2) |
| 219 | - | 222 | + elif input_filter_format == "FRACTAL_Z_3D": |
| 223 | + if input_ori_shapes is not None and input_ori_shapes[1] is not None: | ||
| 224 | + filter = to_NCDHW_from_FRACTAL_Z_3D(filter, input_ori_shapes[1], groups) | ||
| 225 | + | ||
| 220 | return x, filter | 226 | return x, filter |
| 221 | 227 | ||
| 222 | 228 | ||
| @@ -233,7 +239,7 @@ def process_output_format_a2_a3(out, output_format, input_format, output_ori_sha | |||
| 233 | out = to_NDC1HWC0_from_NCDHW(out, target_shape) | 239 | out = to_NDC1HWC0_from_NCDHW(out, target_shape) |
| 234 | elif output_format == NCDHW_FORMAT and input_format == NDHWC_FORMAT: | 240 | elif output_format == NCDHW_FORMAT and input_format == NDHWC_FORMAT: |
| 235 | out = out.transpose((0, 4, 1, 2, 3)) | 241 | out = out.transpose((0, 4, 1, 2, 3)) |
| 236 | - | 242 | + |
| 237 | return out | 243 | return out |
| 238 | 244 | ||
| 239 | 245 | ||
| @@ -248,7 +254,7 @@ def process_output_format_a5(out, output_format, input_format): | |||
| 248 | out = out.transpose((0, 2, 3, 4, 1)) | 254 | out = out.transpose((0, 2, 3, 4, 1)) |
| 249 | elif output_format == NCDHW_FORMAT and input_format == NDHWC_FORMAT: | 255 | elif output_format == NCDHW_FORMAT and input_format == NDHWC_FORMAT: |
| 250 | out = out.transpose((0, 4, 1, 2, 3)) | 256 | out = out.transpose((0, 4, 1, 2, 3)) |
| 251 | - | 257 | + |
| 252 | return out | 258 | return out |
| 253 | 259 | ||
| 254 | 260 | ||
| @@ -257,7 +263,7 @@ def to_NCDHW_from_NDC1HWC0(data, ori_shape): | |||
| 257 | n, d, h, w, c = ori_shape | 263 | n, d, h, w, c = ori_shape |
| 258 | c0 = determine_c0(data.dtype.name, None) | 264 | c0 = determine_c0(data.dtype.name, None) |
| 259 | c1 = ceil_div(c, c0) | 265 | c1 = ceil_div(c, c0) |
| 260 | - | 266 | + |
| 261 | # NDC1HWC0 shape: (n, d, c1, h, w, c0) | 267 | # NDC1HWC0 shape: (n, d, c1, h, w, c0) |
| 262 | # Transpose to (n, c1, d, h, w, c0) | 268 | # Transpose to (n, c1, d, h, w, c0) |
| 263 | data = data.transpose(0, 2, 1, 3, 4, 5) | 269 | data = data.transpose(0, 2, 1, 3, 4, 5) |
| @@ -266,30 +272,31 @@ def to_NCDHW_from_NDC1HWC0(data, ori_shape): | |||
| 266 | # Slice to (n, c, d, h, w) if there's padding | 272 | # Slice to (n, c, d, h, w) if there's padding |
| 267 | if c1 * c0 > c: | 273 | if c1 * c0 > c: |
| 268 | data = data[:, :c, :, :, :] | 274 | data = data[:, :c, :, :, :] |
| 269 | - | 275 | + |
| 270 | return data | 276 | return data |
| 271 | 277 | ||
| 272 | 278 | ||
| 273 | def to_NCDHW_from_FRACTAL_Z_3D(data, ori_shape, groups=1): | 279 | def to_NCDHW_from_FRACTAL_Z_3D(data, ori_shape, groups=1): |
| 274 | """Convert from FRACTAL_Z_3D to NCDHW format""" | 280 | """Convert from FRACTAL_Z_3D to NCDHW format""" |
| 275 | n, c_in, d, h, w = ori_shape | 281 | n, c_in, d, h, w = ori_shape |
| 276 | - c0 = 16 | 282 | + c0 = determine_c0(data.dtype.name, None) |
| 283 | + n0 = 16 | ||
| 277 | cin_ori = c_in // groups | 284 | cin_ori = c_in // groups |
| 278 | cout_ori = n // groups | 285 | cout_ori = n // groups |
| 279 | - | 286 | + |
| 280 | mag_factor0 = _lcm(cin_ori, c0) // cin_ori | 287 | mag_factor0 = _lcm(cin_ori, c0) // cin_ori |
| 281 | - mag_factor1 = _lcm(cout_ori, c0) // cout_ori | 288 | + mag_factor1 = _lcm(cout_ori, n0) // cout_ori |
| 282 | mag_factor = min(_lcm(mag_factor0, mag_factor1), groups) | 289 | mag_factor = min(_lcm(mag_factor0, mag_factor1), groups) |
| 283 | - | 290 | + |
| 284 | cin_g = align(mag_factor * cin_ori, c0) | 291 | cin_g = align(mag_factor * cin_ori, c0) |
| 285 | - cout_g = align(mag_factor * cout_ori, c0) | 292 | + cout_g = align(mag_factor * cout_ori, n0) |
| 286 | real_g = ceil_div(groups, mag_factor) | 293 | real_g = ceil_div(groups, mag_factor) |
| 287 | cin1_g = cin_g // c0 | 294 | cin1_g = cin_g // c0 |
| 288 | - cout1_g = cout_g // c0 | 295 | + cout1_g = cout_g // n0 |
| 289 | - | 296 | + |
| 290 | - # FRACTAL_Z_3D shape: (real_g * d * cin1_g * h * w, cout1_g, c0, c0) | 297 | + # FRACTAL_Z_3D shape: (real_g * d * cin1_g * h * w, cout1_g, n0, c0) |
| 291 | - data = data.reshape((real_g, d, cin1_g, h, w, cout_g, c0)) | 298 | + data = data.reshape((real_g, d, cin1_g, h, w, cout1_g, n0, c0)) |
| 292 | - | 299 | + |
| 293 | # Reverse the mapping | 300 | # Reverse the mapping |
| 294 | result = np.zeros((n, c_in, d, h, w), dtype=data.dtype) | 301 | result = np.zeros((n, c_in, d, h, w), dtype=data.dtype) |
| 295 | for g in range(groups): | 302 | for g in range(groups): |
| @@ -299,9 +306,17 @@ def to_NCDHW_from_FRACTAL_Z_3D(data, ori_shape, groups=1): | |||
| 299 | dst_cin = e * cin_ori + ci | 306 | dst_cin = e * cin_ori + ci |
| 300 | dst_cout = e * cout_ori + co | 307 | dst_cout = e * cout_ori + co |
| 301 | src_cout = g * cout_ori + co | 308 | src_cout = g * cout_ori + co |
| 302 | - result[src_cout, ci, :, :, :] = \ | 309 | + result[src_cout, ci, :, :, :] = data[ |
| 303 | - data[g // mag_factor, :, dst_cin // c0, :, :, dst_cout, dst_cin % c0] | 310 | + g // mag_factor, |
| 304 | - | 311 | + :, |
| 312 | + dst_cin // c0, | ||
| 313 | + :, | ||
| 314 | + :, | ||
| 315 | + dst_cout // n0, | ||
| 316 | + dst_cout % n0, | ||
| 317 | + dst_cin % c0, | ||
| 318 | + ] | ||
| 319 | + | ||
| 305 | return result | 320 | return result |
| 306 | 321 | ||
| 307 | 322 | ||
| @@ -310,16 +325,18 @@ def to_NDC1HWC0_from_NCDHW(data, ori_shape): | |||
| 310 | n, c, d, h, w = ori_shape | 325 | n, c, d, h, w = ori_shape |
| 311 | c0 = determine_c0(data.dtype.name, None) | 326 | c0 = determine_c0(data.dtype.name, None) |
| 312 | c1 = ceil_div(c, c0) | 327 | c1 = ceil_div(c, c0) |
| 313 | - | 328 | + |
| 314 | # NCDHW -> (n, c1, c0, d, h, w) -> (n, d, c1, h, w, c0) | 329 | # NCDHW -> (n, c1, c0, d, h, w) -> (n, d, c1, h, w, c0) |
| 315 | if c1 * c0 > c: | 330 | if c1 * c0 > c: |
| 316 | num_2_padding_in_c = c1 * c0 - c | 331 | num_2_padding_in_c = c1 * c0 - c |
| 317 | - zero_padding_array = np.zeros((n, num_2_padding_in_c, d, h, w), dtype=data.dtype) | 332 | + zero_padding_array = np.zeros( |
| 333 | + (n, num_2_padding_in_c, d, h, w), dtype=data.dtype | ||
| 334 | + ) | ||
| 318 | data = np.concatenate((data, zero_padding_array), axis=1) | 335 | data = np.concatenate((data, zero_padding_array), axis=1) |
| 319 | - | 336 | + |
| 320 | data = data.reshape((n, c1, c0, d, h, w)) | 337 | data = data.reshape((n, c1, c0, d, h, w)) |
| 321 | data = data.transpose(0, 3, 1, 4, 5, 2) | 338 | data = data.transpose(0, 3, 1, 4, 5, 2) |
| 322 | - | 339 | + |
| 323 | return data | 340 | return data |
| 324 | 341 | ||
| 325 | 342 | ||
| @@ -329,19 +346,19 @@ def to_FRACTAL_Z_3D_from_NCDHW(data, ori_shape, groups=1): | |||
| 329 | c0 = 16 | 346 | c0 = 16 |
| 330 | cin_ori = c_in // groups | 347 | cin_ori = c_in // groups |
| 331 | cout_ori = n // groups | 348 | cout_ori = n // groups |
| 332 | - | 349 | + |
| 333 | mag_factor0 = _lcm(cin_ori, c0) // cin_ori | 350 | mag_factor0 = _lcm(cin_ori, c0) // cin_ori |
| 334 | mag_factor1 = _lcm(cout_ori, c0) // cout_ori | 351 | mag_factor1 = _lcm(cout_ori, c0) // cout_ori |
| 335 | mag_factor = min(_lcm(mag_factor0, mag_factor1), groups) | 352 | mag_factor = min(_lcm(mag_factor0, mag_factor1), groups) |
| 336 | - | 353 | + |
| 337 | cin_g = align(mag_factor * cin_ori, c0) | 354 | cin_g = align(mag_factor * cin_ori, c0) |
| 338 | cout_g = align(mag_factor * cout_ori, c0) | 355 | cout_g = align(mag_factor * cout_ori, c0) |
| 339 | real_g = ceil_div(groups, mag_factor) | 356 | real_g = ceil_div(groups, mag_factor) |
| 340 | cin1_g = cin_g // c0 | 357 | cin1_g = cin_g // c0 |
| 341 | cout1_g = cout_g // c0 | 358 | cout1_g = cout_g // c0 |
| 342 | - | 359 | + |
| 343 | weight_group = np.zeros((real_g, d, cin1_g, h, w, cout_g, c0), dtype=data.dtype) | 360 | weight_group = np.zeros((real_g, d, cin1_g, h, w, cout_g, c0), dtype=data.dtype) |
| 344 | - | 361 | + |
| 345 | for g in range(groups): | 362 | for g in range(groups): |
| 346 | for ci in range(c_in): | 363 | for ci in range(c_in): |
| 347 | for co in range(n // groups): | 364 | for co in range(n // groups): |
| @@ -349,11 +366,12 @@ def to_FRACTAL_Z_3D_from_NCDHW(data, ori_shape, groups=1): | |||
| 349 | dst_cin = e * cin_ori + ci | 366 | dst_cin = e * cin_ori + ci |
| 350 | dst_cout = e * cout_ori + co | 367 | dst_cout = e * cout_ori + co |
| 351 | src_cout = g * cout_ori + co | 368 | src_cout = g * cout_ori + co |
| 352 | - weight_group[g // mag_factor, :, dst_cin // c0, :, :, dst_cout, dst_cin % c0] = \ | 369 | + weight_group[ |
| 353 | - data[src_cout, ci, :, :, :] | 370 | + g // mag_factor, :, dst_cin // c0, :, :, dst_cout, dst_cin % c0 |
| 354 | - | 371 | + ] = data[src_cout, ci, :, :, :] |
| 372 | + | ||
| 355 | weight_group = weight_group.reshape((real_g * d * cin1_g * h * w, cout1_g, c0, c0)) | 373 | weight_group = weight_group.reshape((real_g * d * cin1_g * h * w, cout1_g, c0, c0)) |
| 356 | - | 374 | + |
| 357 | return weight_group | 375 | return weight_group |
| 358 | 376 | ||
| 359 | 377 | ||
| @@ -389,8 +407,17 @@ def _parse_padding(pads): | |||
| 389 | return val, val, val, val, val, val | 407 | return val, val, val, val, val, val |
| 390 | 408 | ||
| 391 | 409 | ||
| 392 | -def _apply_pad_mode(pad_mode, input_shape, filter_shape, stride_d, stride_h, stride_w, | 410 | +def _apply_pad_mode( |
| 393 | - dilation_d, dilation_h, dilation_w): | 411 | + pad_mode, |
| 412 | + input_shape, | ||
| 413 | + filter_shape, | ||
| 414 | + stride_d, | ||
| 415 | + stride_h, | ||
| 416 | + stride_w, | ||
| 417 | + dilation_d, | ||
| 418 | + dilation_h, | ||
| 419 | + dilation_w, | ||
| 420 | +): | ||
| 394 | """ | 421 | """ |
| 395 | Calculate padding based on pad_mode, aligned with C++ GetOriPadFromPadMode and ApplySamesPad logic. | 422 | Calculate padding based on pad_mode, aligned with C++ GetOriPadFromPadMode and ApplySamesPad logic. |
| 396 | 423 | ||
| @@ -464,8 +491,18 @@ def _apply_pad_mode(pad_mode, input_shape, filter_shape, stride_d, stride_h, str | |||
| 464 | return pad_d_front, pad_d_back, pad_top, pad_bottom, pad_left, pad_right | 491 | return pad_d_front, pad_d_back, pad_top, pad_bottom, pad_left, pad_right |
| 465 | 492 | ||
| 466 | 493 | ||
| 467 | -def _process_conv3d_padding(x_np, pads, pad_mode, filter_shape, stride_d, stride_h, stride_w, | 494 | +def _process_conv3d_padding( |
| 468 | - dilation_d, dilation_h, dilation_w): | 495 | + x_np, |
| 496 | + pads, | ||
| 497 | + pad_mode, | ||
| 498 | + filter_shape, | ||
| 499 | + stride_d, | ||
| 500 | + stride_h, | ||
| 501 | + stride_w, | ||
| 502 | + dilation_d, | ||
| 503 | + dilation_h, | ||
| 504 | + dilation_w, | ||
| 505 | +): | ||
| 469 | """ | 506 | """ |
| 470 | Process padding for conv3d operation. | 507 | Process padding for conv3d operation. |
| 471 | 508 | ||
| @@ -487,13 +524,24 @@ def _process_conv3d_padding(x_np, pads, pad_mode, filter_shape, stride_d, stride | |||
| 487 | - torch_pad_list: symmetric padding [d, h, w] for torch.conv3d | 524 | - torch_pad_list: symmetric padding [d, h, w] for torch.conv3d |
| 488 | """ | 525 | """ |
| 489 | # Parse explicit padding into 6-element format | 526 | # Parse explicit padding into 6-element format |
| 490 | - pad_d_front, pad_d_back, pad_top, pad_bottom, pad_left, pad_right = _parse_padding(pads) | 527 | + pad_d_front, pad_d_back, pad_top, pad_bottom, pad_left, pad_right = _parse_padding( |
| 528 | + pads | ||
| 529 | + ) | ||
| 491 | 530 | ||
| 492 | # Apply pad_mode if not SPECIFIC | 531 | # Apply pad_mode if not SPECIFIC |
| 493 | if pad_mode.upper() != "SPECIFIC": | 532 | if pad_mode.upper() != "SPECIFIC": |
| 494 | - pad_d_front, pad_d_back, pad_top, pad_bottom, pad_left, pad_right = _apply_pad_mode( | 533 | + pad_d_front, pad_d_back, pad_top, pad_bottom, pad_left, pad_right = ( |
| 495 | - pad_mode, x_np.shape, filter_shape, stride_d, stride_h, stride_w, | 534 | + _apply_pad_mode( |
| 496 | - dilation_d, dilation_h, dilation_w | 535 | + pad_mode, |
| 536 | + x_np.shape, | ||
| 537 | + filter_shape, | ||
| 538 | + stride_d, | ||
| 539 | + stride_h, | ||
| 540 | + stride_w, | ||
| 541 | + dilation_d, | ||
| 542 | + dilation_h, | ||
| 543 | + dilation_w, | ||
| 544 | + ) | ||
| 497 | ) | 545 | ) |
| 498 | 546 | ||
| 499 | # Calculate symmetric padding (minimum of front/back, top/bottom, left/right) | 547 | # Calculate symmetric padding (minimum of front/back, top/bottom, left/right) |
| @@ -529,18 +577,24 @@ def _process_conv3d_padding(x_np, pads, pad_mode, filter_shape, stride_d, stride | |||
| 529 | return input_pad, torch_pad | 577 | return input_pad, torch_pad |
| 530 | 578 | ||
| 531 | 579 | ||
| 532 | -def conv3d_v2_golden(x, filter, bias=None, scale=None, offset=None, offset_w=None, | 580 | +def conv3d_v2_golden( |
| 533 | - *, | 581 | + x, |
| 534 | - strides, | 582 | + filter, |
| 535 | - pads: list=[0, 0, 0, 0, 0, 0], | 583 | + bias=None, |
| 536 | - dilations: list=[1, 1, 1, 1, 1], | 584 | + scale=None, |
| 537 | - groups: int=1, | 585 | + offset=None, |
| 538 | - data_format:str=NCDHW_FORMAT, | 586 | + offset_w=None, |
| 539 | - offset_x: int= 0, | 587 | + *, |
| 540 | - pad_mod: str='SPECIFIC', | 588 | + strides, |
| 541 | - enable_hf32: bool=False, | 589 | + pads: list = [0, 0, 0, 0, 0, 0], |
| 542 | - **kwargs, | 590 | + dilations: list = [1, 1, 1, 1, 1], |
| 543 | - ): | 591 | + groups: int = 1, |
| 592 | + data_format: str = NCDHW_FORMAT, | ||
| 593 | + offset_x: int = 0, | ||
| 594 | + pad_mod: str = "SPECIFIC", | ||
| 595 | + enable_hf32: bool = False, | ||
| 596 | + **kwargs, | ||
| 597 | +): | ||
| 544 | """ | 598 | """ |
| 545 | Kernel golden for conv3d_v2. | 599 | Kernel golden for conv3d_v2. |
| 546 | All parameters follow @conv3d_v2_def.cpp without outputs. | 600 | All parameters follow @conv3d_v2_def.cpp without outputs. |
| @@ -550,41 +604,46 @@ def conv3d_v2_golden(x, filter, bias=None, scale=None, offset=None, offset_w=Non | |||
| 550 | input_dtypes, output_dtypes. | 604 | input_dtypes, output_dtypes. |
| 551 | """ | 605 | """ |
| 552 | import torch | 606 | import torch |
| 553 | - import torch.nn.functional as F | 607 | + |
| 554 | - | ||
| 555 | short_soc_version = kwargs.get("short_soc_version", "") | 608 | short_soc_version = kwargs.get("short_soc_version", "") |
| 556 | is_950 = is_ascend950(short_soc_version) | 609 | is_950 = is_ascend950(short_soc_version) |
| 557 | - | 610 | + |
| 558 | input_formats = kwargs.get("input_formats", [NCDHW_FORMAT, NCDHW_FORMAT]) | 611 | input_formats = kwargs.get("input_formats", [NCDHW_FORMAT, NCDHW_FORMAT]) |
| 559 | input_ori_shapes = kwargs.get("input_ori_shapes", None) | 612 | input_ori_shapes = kwargs.get("input_ori_shapes", None) |
| 560 | 613 | ||
| 561 | - x_dtype_str = x.dtype.name | 614 | + x_dtype_str = x.dtype.name |
| 562 | - | 615 | + |
| 563 | if is_950: | 616 | if is_950: |
| 564 | - x_np, filter_np = process_formats_a5(x, filter, input_formats) | 617 | + x_np, filter_np = process_formats_a5( |
| 618 | + x, filter, input_formats, input_ori_shapes, groups | ||
| 619 | + ) | ||
| 565 | else: | 620 | else: |
| 566 | - x_np, filter_np = process_formats_a2_a3(x, filter, input_formats, input_ori_shapes, groups) | 621 | + x_np, filter_np = process_formats_a2_a3( |
| 567 | - | 622 | + x, filter, input_formats, input_ori_shapes, groups |
| 623 | + ) | ||
| 624 | + | ||
| 568 | if enable_hf32 and x_dtype_str == FP32_STR: | 625 | if enable_hf32 and x_dtype_str == FP32_STR: |
| 569 | calc_dtype = np.float32 | 626 | calc_dtype = np.float32 |
| 570 | x_np = simulate_hf32_precision(x_np.astype(np.float32), short_soc_version) | 627 | x_np = simulate_hf32_precision(x_np.astype(np.float32), short_soc_version) |
| 571 | - filter_np = simulate_hf32_precision(filter_np.astype(np.float32), short_soc_version) | 628 | + filter_np = simulate_hf32_precision( |
| 629 | + filter_np.astype(np.float32), short_soc_version | ||
| 630 | + ) | ||
| 572 | else: | 631 | else: |
| 573 | calc_dtype = np.float64 if x_dtype_str == FP32_STR else np.float32 | 632 | calc_dtype = np.float64 if x_dtype_str == FP32_STR else np.float32 |
| 574 | x_np = x_np.astype(calc_dtype) | 633 | x_np = x_np.astype(calc_dtype) |
| 575 | filter_np = filter_np.astype(calc_dtype) | 634 | filter_np = filter_np.astype(calc_dtype) |
| 576 | - | 635 | + |
| 577 | if bias is not None: | 636 | if bias is not None: |
| 578 | bias_np = bias.astype(calc_dtype) | 637 | bias_np = bias.astype(calc_dtype) |
| 579 | else: | 638 | else: |
| 580 | bias_np = None | 639 | bias_np = None |
| 581 | - | 640 | + |
| 582 | if scale is not None: | 641 | if scale is not None: |
| 583 | scale_arr = scale if isinstance(scale, np.ndarray) else np.array(scale) | 642 | scale_arr = scale if isinstance(scale, np.ndarray) else np.array(scale) |
| 584 | scale_np = scale_arr.astype(np.float32) | 643 | scale_np = scale_arr.astype(np.float32) |
| 585 | else: | 644 | else: |
| 586 | scale_np = None | 645 | scale_np = None |
| 587 | - | 646 | + |
| 588 | if isinstance(strides, (list, tuple)): | 647 | if isinstance(strides, (list, tuple)): |
| 589 | if len(strides) == 5: | 648 | if len(strides) == 5: |
| 590 | stride_d, stride_h, stride_w = strides[2], strides[3], strides[4] | 649 | stride_d, stride_h, stride_w = strides[2], strides[3], strides[4] |
| @@ -594,17 +653,25 @@ def conv3d_v2_golden(x, filter, bias=None, scale=None, offset=None, offset_w=Non | |||
| 594 | stride_d = stride_h = stride_w = strides[0] | 653 | stride_d = stride_h = stride_w = strides[0] |
| 595 | else: | 654 | else: |
| 596 | stride_d = stride_h = stride_w = int(strides) | 655 | stride_d = stride_h = stride_w = int(strides) |
| 597 | - | 656 | + |
| 598 | if isinstance(dilations, (list, tuple)): | 657 | if isinstance(dilations, (list, tuple)): |
| 599 | if len(dilations) == 5: | 658 | if len(dilations) == 5: |
| 600 | - dilation_d, dilation_h, dilation_w = dilations[2], dilations[3], dilations[4] | 659 | + dilation_d, dilation_h, dilation_w = ( |
| 660 | + dilations[2], | ||
| 661 | + dilations[3], | ||
| 662 | + dilations[4], | ||
| 663 | + ) | ||
| 601 | elif len(dilations) == 3: | 664 | elif len(dilations) == 3: |
| 602 | - dilation_d, dilation_h, dilation_w = dilations[0], dilations[1], dilations[2] | 665 | + dilation_d, dilation_h, dilation_w = ( |
| 666 | + dilations[0], | ||
| 667 | + dilations[1], | ||
| 668 | + dilations[2], | ||
| 669 | + ) | ||
| 603 | else: | 670 | else: |
| 604 | dilation_d = dilation_h = dilation_w = dilations[0] | 671 | dilation_d = dilation_h = dilation_w = dilations[0] |
| 605 | else: | 672 | else: |
| 606 | dilation_d = dilation_h = dilation_w = int(dilations) | 673 | dilation_d = dilation_h = dilation_w = int(dilations) |
| 607 | - | 674 | + |
| 608 | output_dtypes = kwargs.get("output_dtypes", [FP32_STR]) | 675 | output_dtypes = kwargs.get("output_dtypes", [FP32_STR]) |
| 609 | output_dtype = output_dtypes[0] | 676 | output_dtype = output_dtypes[0] |
| 610 | output_formats = kwargs.get("output_formats", [NCDHW_FORMAT]) | 677 | output_formats = kwargs.get("output_formats", [NCDHW_FORMAT]) |
| @@ -613,17 +680,29 @@ def conv3d_v2_golden(x, filter, bias=None, scale=None, offset=None, offset_w=Non | |||
| 613 | 680 | ||
| 614 | # Process padding and prepare tensors for conv3d | 681 | # Process padding and prepare tensors for conv3d |
| 615 | input_pad, pad_torch = _process_conv3d_padding( | 682 | input_pad, pad_torch = _process_conv3d_padding( |
| 616 | - x_np, pads, pad_mod, filter_np.shape, stride_d, stride_h, stride_w, | 683 | + x_np, |
| 617 | - dilation_d, dilation_h, dilation_w | 684 | + pads, |
| 685 | + pad_mod, | ||
| 686 | + filter_np.shape, | ||
| 687 | + stride_d, | ||
| 688 | + stride_h, | ||
| 689 | + stride_w, | ||
| 690 | + dilation_d, | ||
| 691 | + dilation_h, | ||
| 692 | + dilation_w, | ||
| 618 | ) | 693 | ) |
| 619 | 694 | ||
| 620 | input_torch = torch.from_numpy(input_pad) | 695 | input_torch = torch.from_numpy(input_pad) |
| 621 | weight_torch = torch.from_numpy(filter_np) | 696 | weight_torch = torch.from_numpy(filter_np) |
| 622 | - bias_torch = torch.from_numpy(bias_np) if bias_np is not None else None | 697 | + |
| 698 | + is_dequant = x_dtype_str == "int8" and scale_np is not None | ||
| 699 | + bias_torch = ( | ||
| 700 | + torch.from_numpy(bias_np) if bias_np is not None and not is_dequant else None | ||
| 701 | + ) | ||
| 623 | 702 | ||
| 624 | stridedhw = [stride_d, stride_h, stride_w] | 703 | stridedhw = [stride_d, stride_h, stride_w] |
| 625 | dilationdhw = [dilation_d, dilation_h, dilation_w] | 704 | dilationdhw = [dilation_d, dilation_h, dilation_w] |
| 626 | - | 705 | + |
| 627 | out = torch.nn.functional.conv3d( | 706 | out = torch.nn.functional.conv3d( |
| 628 | input_torch, | 707 | input_torch, |
| 629 | weight_torch, | 708 | weight_torch, |
| @@ -633,25 +712,35 @@ def conv3d_v2_golden(x, filter, bias=None, scale=None, offset=None, offset_w=Non | |||
| 633 | dilation=dilationdhw, | 712 | dilation=dilationdhw, |
| 634 | groups=groups, | 713 | groups=groups, |
| 635 | ) | 714 | ) |
| 636 | - | 715 | + |
| 637 | if scale_np is not None: | 716 | if scale_np is not None: |
| 638 | if scale_np.ndim == 1: | 717 | if scale_np.ndim == 1: |
| 639 | - scale_tensor = torch.from_numpy(scale_np.reshape(1, scale_np.shape[0], 1, 1, 1)) | 718 | + scale_tensor = torch.from_numpy( |
| 719 | + scale_np.reshape(1, scale_np.shape[0], 1, 1, 1) | ||
| 720 | + ) | ||
| 640 | elif scale_np.ndim == 5: | 721 | elif scale_np.ndim == 5: |
| 641 | scale_tensor = torch.from_numpy(scale_np) | 722 | scale_tensor = torch.from_numpy(scale_np) |
| 642 | else: | 723 | else: |
| 643 | - raise ValueError(f"scale must be 1D or 5D, got {scale_np.ndim}D with shape {scale_np.shape}") | 724 | + raise ValueError( |
| 644 | - out = torch.multiply(out, scale_tensor).numpy() | 725 | + f"scale must be 1D or 5D, got {scale_np.ndim}D with shape {scale_np.shape}" |
| 726 | + ) | ||
| 727 | + out = torch.multiply(out, scale_tensor) | ||
| 728 | + if is_dequant and bias_np is not None: | ||
| 729 | + bias_tensor = torch.from_numpy(bias_np.reshape(1, -1, 1, 1, 1)) | ||
| 730 | + out = torch.add(out, bias_tensor) | ||
| 731 | + out = out.numpy() | ||
| 645 | else: | 732 | else: |
| 646 | out = out.numpy() | 733 | out = out.numpy() |
| 647 | - | 734 | + |
| 648 | out = convert_output_dtype(out, output_dtype, enable_hf32, short_soc_version) | 735 | out = convert_output_dtype(out, output_dtype, enable_hf32, short_soc_version) |
| 649 | - | 736 | + |
| 650 | output_ori_shapes = kwargs.get("output_ori_shapes", None) | 737 | output_ori_shapes = kwargs.get("output_ori_shapes", None) |
| 651 | - | 738 | + |
| 652 | if not is_950: | 739 | if not is_950: |
| 653 | - out = process_output_format_a2_a3(out, output_format, input_format, output_ori_shapes) | 740 | + out = process_output_format_a2_a3( |
| 741 | + out, output_format, input_format, output_ori_shapes | ||
| 742 | + ) | ||
| 654 | else: | 743 | else: |
| 655 | out = process_output_format_a5(out, output_format, input_format) | 744 | out = process_output_format_a5(out, output_format, input_format) |
| 656 | - | 745 | + |
| 657 | return out | 746 | return out |
| @@ -2,9 +2,9 @@ | |||
| 2 | # -*- coding: UTF-8 -*- | 2 | # -*- coding: UTF-8 -*- |
| 3 | # ---------------------------------------------------------------------------- | 3 | # ---------------------------------------------------------------------------- |
| 4 | # Copyright (c) 2025-2026 Huawei Technologies Co., Ltd. | 4 | # Copyright (c) 2025-2026 Huawei Technologies Co., Ltd. |
| 5 | -# This program is free software, you can redistribute it and/or modify it under terms and conditions of | 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"). | 6 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 7 | -# Please refer to License for details. You may not use this file except in compliance with 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. |
| @@ -12,11 +12,7 @@ | |||
| 12 | 12 | ||
| 13 | import numpy as np | 13 | import numpy as np |
| 14 | 14 | ||
| 15 | -__input__ = { | 15 | +__input__ = {"kernel": {"conv3dv2": "conv3dv2_input"}} |
| 16 | - "kernel": { | ||
| 17 | - "conv3dv2": "conv3dv2_input" | ||
| 18 | - } | ||
| 19 | -} | ||
| 20 | 16 | ||
| 21 | NCDHW_FORMAT = "NCDHW" | 17 | NCDHW_FORMAT = "NCDHW" |
| 22 | 18 | ||
| @@ -27,12 +23,13 @@ def fp32_to_hf32(data): | |||
| 27 | HF32: 1 sign bit, 8 exponent bits, 10 mantissa bits (vs 23 for FP32) | 23 | HF32: 1 sign bit, 8 exponent bits, 10 mantissa bits (vs 23 for FP32) |
| 28 | """ | 24 | """ |
| 29 | import torch | 25 | import torch |
| 26 | + | ||
| 30 | is_torch = isinstance(data, torch.Tensor) | 27 | is_torch = isinstance(data, torch.Tensor) |
| 31 | if is_torch: | 28 | if is_torch: |
| 32 | data_np = data.cpu().numpy() | 29 | data_np = data.cpu().numpy() |
| 33 | else: | 30 | else: |
| 34 | data_np = np.asarray(data) | 31 | data_np = np.asarray(data) |
| 35 | - | 32 | + |
| 36 | data_uint32 = data_np.view(np.uint32) | 33 | data_uint32 = data_np.view(np.uint32) |
| 37 | sign = (data_uint32 >> 31) & 0x1 | 34 | sign = (data_uint32 >> 31) & 0x1 |
| 38 | exponent = (data_uint32 >> 23) & 0xFF | 35 | exponent = (data_uint32 >> 23) & 0xFF |
| @@ -44,7 +41,7 @@ def fp32_to_hf32(data): | |||
| 44 | 41 | ||
| 45 | result = (sign_out << 31) | (exponent_out << 23) | (mantissa_hf32 << 13) | 42 | result = (sign_out << 31) | (exponent_out << 23) | (mantissa_hf32 << 13) |
| 46 | result_np = result.view(np.float32) | 43 | result_np = result.view(np.float32) |
| 47 | - | 44 | + |
| 48 | if is_torch: | 45 | if is_torch: |
| 49 | return torch.from_numpy(result_np) | 46 | return torch.from_numpy(result_np) |
| 50 | return result_np | 47 | return result_np |
| @@ -53,6 +50,7 @@ def fp32_to_hf32(data): | |||
| 53 | def numpy_to_torch_tensor(arr): | 50 | def numpy_to_torch_tensor(arr): |
| 54 | """Convert numpy array to torch tensor""" | 51 | """Convert numpy array to torch tensor""" |
| 55 | import torch | 52 | import torch |
| 53 | + | ||
| 56 | return torch.from_numpy(arr) | 54 | return torch.from_numpy(arr) |
| 57 | 55 | ||
| 58 | 56 | ||
| @@ -61,18 +59,24 @@ def torch_to_numpy_tensor(tensor): | |||
| 61 | return tensor.cpu().numpy() | 59 | return tensor.cpu().numpy() |
| 62 | 60 | ||
| 63 | 61 | ||
| 64 | -def conv3dv2_input(x, filter, bias=None, scale=None, offset=None, offset_w=None, | 62 | +def conv3dv2_input( |
| 65 | - *, | 63 | + x, |
| 66 | - strides, | 64 | + filter, |
| 67 | - pads: list=[0,0,0,0,0,0], | 65 | + bias=None, |
| 68 | - dilations: list=[1,1,1,1,1,1], | 66 | + scale=None, |
| 69 | - groups: int=1, | 67 | + offset=None, |
| 70 | - data_format:str=NCDHW_FORMAT, | 68 | + offset_w=None, |
| 71 | - offset_x: int= 0, | 69 | + *, |
| 72 | - pad_mod: str='SPECIFIC', | 70 | + strides, |
| 73 | - enable_hf32: bool=False, | 71 | + pads: list = [0, 0, 0, 0, 0, 0], |
| 74 | - **kwargs, | 72 | + dilations: list = [1, 1, 1, 1, 1, 1], |
| 75 | - ): | 73 | + groups: int = 1, |
| 74 | + data_format: str = NCDHW_FORMAT, | ||
| 75 | + offset_x: int = 0, | ||
| 76 | + pad_mod: str = "SPECIFIC", | ||
| 77 | + enable_hf32: bool = False, | ||
| 78 | + **kwargs, | ||
| 79 | +): | ||
| 76 | """ | 80 | """ |
| 77 | Input function for conv3dv2. | 81 | Input function for conv3dv2. |
| 78 | All the parameters (names and order) follow @conv3d_v2_def.cpp without outputs. | 82 | All the parameters (names and order) follow @conv3d_v2_def.cpp without outputs. |
| @@ -102,8 +106,23 @@ def conv3dv2_input(x, filter, bias=None, scale=None, offset=None, offset_w=None, | |||
| 102 | offset_input = offset | 106 | offset_input = offset |
| 103 | offset_w_input = offset_w | 107 | offset_w_input = offset_w |
| 104 | 108 | ||
| 109 | + if x.dtype == np.int8 and scale is not None: | ||
| 110 | + if bias is not None and bias.dtype != np.float32: | ||
| 111 | + bias_input = bias.astype(np.float32) | ||
| 112 | + if scale is not None and scale.dtype != np.float32: | ||
| 113 | + scale_input = scale.astype(np.float32) | ||
| 114 | + | ||
| 105 | if x.dtype == np.float32 and enable_hf32: | 115 | if x.dtype == np.float32 and enable_hf32: |
| 106 | x_input = torch_to_numpy_tensor(fp32_to_hf32(numpy_to_torch_tensor(x))) | 116 | x_input = torch_to_numpy_tensor(fp32_to_hf32(numpy_to_torch_tensor(x))) |
| 107 | - filter_input = torch_to_numpy_tensor(fp32_to_hf32(numpy_to_torch_tensor(filter))) | 117 | + filter_input = torch_to_numpy_tensor( |
| 118 | + fp32_to_hf32(numpy_to_torch_tensor(filter)) | ||
| 119 | + ) | ||
| 108 | 120 | ||
| 109 | - return [x_input, filter_input, bias_input, scale_input, offset_input, offset_w_input] | 121 | + return [ |
| 122 | + x_input, | ||
| 123 | + filter_input, | ||
| 124 | + bias_input, | ||
| 125 | + scale_input, | ||
| 126 | + offset_input, | ||
| 127 | + offset_w_input, | ||
| 128 | + ] | ||
| @@ -2,9 +2,9 @@ | |||
| 2 | # -*- coding: UTF-8 -*- | 2 | # -*- coding: UTF-8 -*- |
| 3 | # ---------------------------------------------------------------------------- | 3 | # ---------------------------------------------------------------------------- |
| 4 | # Copyright (c) 2025-2026 Huawei Technologies Co., Ltd. | 4 | # Copyright (c) 2025-2026 Huawei Technologies Co., Ltd. |
| 5 | -# This program is free software, you can redistribute it and/or modify it under terms and conditions of | 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"). | 6 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 7 | -# Please refer to License for details. You may not use this file except in compliance with 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. |
| @@ -19,9 +19,9 @@ __golden__ = { | |||
| 19 | "aclnnConvolutionBackward": "aclnn_convolution_backward_golden", | 19 | "aclnnConvolutionBackward": "aclnn_convolution_backward_golden", |
| 20 | "aclnnConvTbcBackward": "aclnn_conv_tbc_backward_golden", | 20 | "aclnnConvTbcBackward": "aclnn_conv_tbc_backward_golden", |
| 21 | }, | 21 | }, |
| 22 | - "torch_api": { | 22 | + "e2e": { |
| 23 | "torch.ops.aten.convolution_backward": "aten_convolution_backward_golden", | 23 | "torch.ops.aten.convolution_backward": "aten_convolution_backward_golden", |
| 24 | - } | 24 | + }, |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | 27 | ||
| @@ -41,7 +41,9 @@ def to_float32(t): | |||
| 41 | return None | 41 | return None |
| 42 | if isinstance(t, torch.Tensor): | 42 | if isinstance(t, torch.Tensor): |
| 43 | dtype_str = str(t.dtype) | 43 | dtype_str = str(t.dtype) |
| 44 | - if any(s in dtype_str for s in ['hifloat8', 'float8', 'float4', 'int4', 'bfloat16']): | 44 | + if any( |
| 45 | + s in dtype_str for s in ["hifloat8", "float8", "float4", "int4", "bfloat16"] | ||
| 46 | + ): | ||
| 45 | return t.float() | 47 | return t.float() |
| 46 | return t.to(torch.float32) | 48 | return t.to(torch.float32) |
| 47 | return t.astype(np.float32) | 49 | return t.astype(np.float32) |
| @@ -74,21 +76,81 @@ def simulate_hf32_precision(data, short_soc_version=None): | |||
| 74 | return input_hf32.view(np.float32) | 76 | return input_hf32.view(np.float32) |
| 75 | 77 | ||
| 76 | 78 | ||
| 77 | -def _compute_conv_backward(gradOutput, input, weight, stride, padding, | 79 | +def _compute_conv_backward( |
| 78 | - dilation, groups, conv_dim, transposed=False, outputPadding=0, | 80 | + gradOutput, |
| 79 | - outputMask=[True, True, False], biasSizes=None, | 81 | + input, |
| 80 | - cubeMathType=0, short_soc_version=None): | 82 | + weight, |
| 83 | + stride, | ||
| 84 | + padding, | ||
| 85 | + dilation, | ||
| 86 | + groups, | ||
| 87 | + conv_dim, | ||
| 88 | + transposed=False, | ||
| 89 | + outputPadding=0, | ||
| 90 | + outputMask=[True, True, False], | ||
| 91 | + biasSizes=None, | ||
| 92 | + cubeMathType=0, | ||
| 93 | + short_soc_version=None, | ||
| 94 | +): | ||
| 81 | stride = ensure_list(stride, conv_dim) | 95 | stride = ensure_list(stride, conv_dim) |
| 82 | padding = ensure_list(padding, conv_dim) | 96 | padding = ensure_list(padding, conv_dim) |
| 83 | dilation = ensure_list(dilation, conv_dim) | 97 | dilation = ensure_list(dilation, conv_dim) |
| 84 | outputPadding = ensure_list(outputPadding, conv_dim) | 98 | outputPadding = ensure_list(outputPadding, conv_dim) |
| 85 | 99 | ||
| 86 | if isinstance(gradOutput, np.ndarray): | 100 | if isinstance(gradOutput, np.ndarray): |
| 87 | - gradOutput = torch.from_numpy(gradOutput) | 101 | + if gradOutput.dtype not in ( |
| 102 | + np.float32, | ||
| 103 | + np.float16, | ||
| 104 | + np.float64, | ||
| 105 | + np.int64, | ||
| 106 | + np.int32, | ||
| 107 | + np.int16, | ||
| 108 | + np.int8, | ||
| 109 | + np.uint64, | ||
| 110 | + np.uint32, | ||
| 111 | + np.uint16, | ||
| 112 | + np.uint8, | ||
| 113 | + np.bool_, | ||
| 114 | + ): | ||
| 115 | + gradOutput = torch.from_numpy(gradOutput.astype(np.float32)) | ||
| 116 | + else: | ||
| 117 | + gradOutput = torch.from_numpy(gradOutput) | ||
| 88 | if isinstance(input, np.ndarray): | 118 | if isinstance(input, np.ndarray): |
| 89 | - input = torch.from_numpy(input) | 119 | + if input.dtype not in ( |
| 120 | + np.float32, | ||
| 121 | + np.float16, | ||
| 122 | + np.float64, | ||
| 123 | + np.int64, | ||
| 124 | + np.int32, | ||
| 125 | + np.int16, | ||
| 126 | + np.int8, | ||
| 127 | + np.uint64, | ||
| 128 | + np.uint32, | ||
| 129 | + np.uint16, | ||
| 130 | + np.uint8, | ||
| 131 | + np.bool_, | ||
| 132 | + ): | ||
| 133 | + input = torch.from_numpy(input.astype(np.float32)) | ||
| 134 | + else: | ||
| 135 | + input = torch.from_numpy(input) | ||
| 90 | if isinstance(weight, np.ndarray): | 136 | if isinstance(weight, np.ndarray): |
| 91 | - weight = torch.from_numpy(weight) | 137 | + if weight.dtype not in ( |
| 138 | + np.float32, | ||
| 139 | + np.float16, | ||
| 140 | + np.float64, | ||
| 141 | + np.int64, | ||
| 142 | + np.int32, | ||
| 143 | + np.int16, | ||
| 144 | + np.int8, | ||
| 145 | + np.uint64, | ||
| 146 | + np.uint32, | ||
| 147 | + np.uint16, | ||
| 148 | + np.uint8, | ||
| 149 | + np.bool_, | ||
| 150 | + ): | ||
| 151 | + weight = torch.from_numpy(weight.astype(np.float32)) | ||
| 152 | + else: | ||
| 153 | + weight = torch.from_numpy(weight) | ||
| 92 | 154 | ||
| 93 | if gradOutput is not None: | 155 | if gradOutput is not None: |
| 94 | gradOutput = gradOutput.float() | 156 | gradOutput = gradOutput.float() |
| @@ -97,12 +159,20 @@ def _compute_conv_backward(gradOutput, input, weight, stride, padding, | |||
| 97 | if weight is not None: | 159 | if weight is not None: |
| 98 | weight = weight.float() | 160 | weight = weight.float() |
| 99 | 161 | ||
| 100 | - input_dtype_str = str(input.dtype).split('.')[-1] if input is not None else 'float32' | 162 | + input_dtype_str = ( |
| 101 | - if input_dtype_str == 'float32' and input is not None and weight is not None: | 163 | + str(input.dtype).split(".")[-1] if input is not None else "float32" |
| 164 | + ) | ||
| 165 | + if input_dtype_str == "float32" and input is not None and weight is not None: | ||
| 102 | if cubeMathType in [1, 3]: | 166 | if cubeMathType in [1, 3]: |
| 103 | - input_np = simulate_hf32_precision(input.numpy().astype(np.float32), short_soc_version) | 167 | + input_np = simulate_hf32_precision( |
| 104 | - weight_np = simulate_hf32_precision(weight.numpy().astype(np.float32), short_soc_version) | 168 | + input.numpy().astype(np.float32), short_soc_version |
| 105 | - gradOutput_np = simulate_hf32_precision(gradOutput.numpy().astype(np.float32), short_soc_version) | 169 | + ) |
| 170 | + weight_np = simulate_hf32_precision( | ||
| 171 | + weight.numpy().astype(np.float32), short_soc_version | ||
| 172 | + ) | ||
| 173 | + gradOutput_np = simulate_hf32_precision( | ||
| 174 | + gradOutput.numpy().astype(np.float32), short_soc_version | ||
| 175 | + ) | ||
| 106 | input = torch.from_numpy(input_np) | 176 | input = torch.from_numpy(input_np) |
| 107 | weight = torch.from_numpy(weight_np) | 177 | weight = torch.from_numpy(weight_np) |
| 108 | gradOutput = torch.from_numpy(gradOutput_np) | 178 | gradOutput = torch.from_numpy(gradOutput_np) |
| @@ -113,12 +183,23 @@ def _compute_conv_backward(gradOutput, input, weight, stride, padding, | |||
| 113 | 183 | ||
| 114 | if not outputMask[2]: | 184 | if not outputMask[2]: |
| 115 | biasSizes = None | 185 | biasSizes = None |
| 116 | - elif biasSizes is None or (isinstance(biasSizes, (list, torch.Size)) and len(biasSizes) == 0): | 186 | + elif biasSizes is None or ( |
| 187 | + isinstance(biasSizes, (list, torch.Size)) and len(biasSizes) == 0 | ||
| 188 | + ): | ||
| 117 | biasSizes = list(weight.shape[:1]) | 189 | biasSizes = list(weight.shape[:1]) |
| 118 | 190 | ||
| 119 | return torch.ops.aten.convolution_backward( | 191 | return torch.ops.aten.convolution_backward( |
| 120 | - gradOutput, input, weight, biasSizes, | 192 | + gradOutput, |
| 121 | - stride, padding, dilation, transposed, outputPadding, groups, outputMask | 193 | + input, |
| 194 | + weight, | ||
| 195 | + biasSizes, | ||
| 196 | + stride, | ||
| 197 | + padding, | ||
| 198 | + dilation, | ||
| 199 | + transposed, | ||
| 200 | + outputPadding, | ||
| 201 | + groups, | ||
| 202 | + outputMask, | ||
| 122 | ) | 203 | ) |
| 123 | 204 | ||
| 124 | 205 | ||
| @@ -138,7 +219,7 @@ def aclnn_convolution_backward_golden( | |||
| 138 | gradInput=None, | 219 | gradInput=None, |
| 139 | gradWeight=None, | 220 | gradWeight=None, |
| 140 | gradBias=None, | 221 | gradBias=None, |
| 141 | - **kwargs | 222 | + **kwargs, |
| 142 | ): | 223 | ): |
| 143 | """ | 224 | """ |
| 144 | ACLNN API golden for aclnnConvolutionBackward. | 225 | ACLNN API golden for aclnnConvolutionBackward. |
| @@ -147,21 +228,81 @@ def aclnn_convolution_backward_golden( | |||
| 147 | stride, padding, dilation, transposed, | 228 | stride, padding, dilation, transposed, |
| 148 | outputPadding, groups, outputMask, cubeMathType, | 229 | outputPadding, groups, outputMask, cubeMathType, |
| 149 | gradInput, gradWeight, gradBias) | 230 | gradInput, gradWeight, gradBias) |
| 150 | - | 231 | + |
| 151 | Supports 1D, 2D, 3D convolution backward. | 232 | Supports 1D, 2D, 3D convolution backward. |
| 152 | """ | 233 | """ |
| 153 | - input_shape = input.shape if isinstance(input, torch.Tensor) or hasattr(input, 'shape') else None | 234 | + input_shape = ( |
| 154 | - weight_shape = weight.shape if isinstance(weight, torch.Tensor) or hasattr(weight, 'shape') else None | 235 | + input.shape |
| 236 | + if isinstance(input, torch.Tensor) or hasattr(input, "shape") | ||
| 237 | + else None | ||
| 238 | + ) | ||
| 239 | + weight_shape = ( | ||
| 240 | + weight.shape | ||
| 241 | + if isinstance(weight, torch.Tensor) or hasattr(weight, "shape") | ||
| 242 | + else None | ||
| 243 | + ) | ||
| 155 | conv_dim = get_conv_dim(input_shape, weight_shape) | 244 | conv_dim = get_conv_dim(input_shape, weight_shape) |
| 156 | short_soc_version = kwargs.get("short_soc_version", None) | 245 | short_soc_version = kwargs.get("short_soc_version", None) |
| 157 | 246 | ||
| 158 | grad_input, grad_weight, grad_bias = _compute_conv_backward( | 247 | grad_input, grad_weight, grad_bias = _compute_conv_backward( |
| 159 | - gradOutput, input, weight, stride, padding, | 248 | + gradOutput, |
| 160 | - dilation, groups, conv_dim, transposed, outputPadding, outputMask, biasSizes, | 249 | + input, |
| 161 | - cubeMathType=cubeMathType, short_soc_version=short_soc_version | 250 | + weight, |
| 251 | + stride, | ||
| 252 | + padding, | ||
| 253 | + dilation, | ||
| 254 | + groups, | ||
| 255 | + conv_dim, | ||
| 256 | + transposed, | ||
| 257 | + outputPadding, | ||
| 258 | + outputMask, | ||
| 259 | + biasSizes, | ||
| 260 | + cubeMathType=cubeMathType, | ||
| 261 | + short_soc_version=short_soc_version, | ||
| 162 | ) | 262 | ) |
| 163 | - | 263 | + |
| 164 | - return (grad_input, grad_weight, grad_bias) | 264 | + tensor_dtypes = kwargs.get("tensor_dtypes", None) |
| 265 | + | ||
| 266 | + def _convert_output(out, idx): | ||
| 267 | + if out is None: | ||
| 268 | + return None | ||
| 269 | + if isinstance(out, torch.Tensor): | ||
| 270 | + out_np = out.detach().numpy() | ||
| 271 | + else: | ||
| 272 | + out_np = np.asarray(out) | ||
| 273 | + if tensor_dtypes and idx < len(tensor_dtypes): | ||
| 274 | + dtype_str = str(tensor_dtypes[idx]) if tensor_dtypes[idx] else None | ||
| 275 | + if dtype_str in ("hifloat8", "float8_e4m3fn", "float8_e5m2"): | ||
| 276 | + from ttk.utilities import numpy_hifloat8 | ||
| 277 | + import ml_dtypes | ||
| 278 | + | ||
| 279 | + np_dtype_map = { | ||
| 280 | + "hifloat8": numpy_hifloat8(), | ||
| 281 | + "float8_e4m3fn": ml_dtypes.float8_e4m3fn, | ||
| 282 | + "float8_e5m2": ml_dtypes.float8_e5m2, | ||
| 283 | + } | ||
| 284 | + np_dtype = np_dtype_map.get(dtype_str) | ||
| 285 | + if np_dtype is not None: | ||
| 286 | + out_np = out_np.astype(np_dtype) | ||
| 287 | + return np.ascontiguousarray(out_np) | ||
| 288 | + elif dtype_str in ("float16", "bfloat16"): | ||
| 289 | + try: | ||
| 290 | + import ml_dtypes | ||
| 291 | + | ||
| 292 | + dtype_map = {"float16": np.float16, "bfloat16": ml_dtypes.bfloat16} | ||
| 293 | + np_dtype = dtype_map.get(dtype_str) | ||
| 294 | + if np_dtype is not None: | ||
| 295 | + out_np = out_np.astype(np_dtype) | ||
| 296 | + return np.ascontiguousarray(out_np) | ||
| 297 | + except ImportError: | ||
| 298 | + pass | ||
| 299 | + return np.ascontiguousarray(out_np.astype(np.float32)) | ||
| 300 | + | ||
| 301 | + grad_input_result = _convert_output(grad_input, 3) | ||
| 302 | + grad_weight_result = _convert_output(grad_weight, 4) | ||
| 303 | + grad_bias_result = _convert_output(grad_bias, 5) | ||
| 304 | + | ||
| 305 | + return (grad_input_result, grad_weight_result, grad_bias_result) | ||
| 165 | 306 | ||
| 166 | 307 | ||
| 167 | def aclnn_conv_tbc_backward_golden( | 308 | def aclnn_conv_tbc_backward_golden( |
| @@ -174,7 +315,7 @@ def aclnn_conv_tbc_backward_golden( | |||
| 174 | gradInput=None, | 315 | gradInput=None, |
| 175 | gradWeight=None, | 316 | gradWeight=None, |
| 176 | gradBias=None, | 317 | gradBias=None, |
| 177 | - **kwargs | 318 | + **kwargs, |
| 178 | ): | 319 | ): |
| 179 | """ | 320 | """ |
| 180 | ACLNN API golden for aclnnConvTbcBackward. | 321 | ACLNN API golden for aclnnConvTbcBackward. |
| @@ -198,12 +339,18 @@ def aclnn_conv_tbc_backward_golden( | |||
| 198 | input = input.float() | 339 | input = input.float() |
| 199 | weight = weight.float() | 340 | weight = weight.float() |
| 200 | 341 | ||
| 201 | - input_dtype_str = str(input.dtype).split('.')[-1] | 342 | + input_dtype_str = str(input.dtype).split(".")[-1] |
| 202 | - if input_dtype_str == 'float32': | 343 | + if input_dtype_str == "float32": |
| 203 | if cubeMathType in [1, 3]: | 344 | if cubeMathType in [1, 3]: |
| 204 | - self_np = simulate_hf32_precision(self.numpy().astype(np.float32), short_soc_version) | 345 | + self_np = simulate_hf32_precision( |
| 205 | - input_np = simulate_hf32_precision(input.numpy().astype(np.float32), short_soc_version) | 346 | + self.numpy().astype(np.float32), short_soc_version |
| 206 | - weight_np = simulate_hf32_precision(weight.numpy().astype(np.float32), short_soc_version) | 347 | + ) |
| 348 | + input_np = simulate_hf32_precision( | ||
| 349 | + input.numpy().astype(np.float32), short_soc_version | ||
| 350 | + ) | ||
| 351 | + weight_np = simulate_hf32_precision( | ||
| 352 | + weight.numpy().astype(np.float32), short_soc_version | ||
| 353 | + ) | ||
| 207 | self = torch.from_numpy(self_np) | 354 | self = torch.from_numpy(self_np) |
| 208 | input = torch.from_numpy(input_np) | 355 | input = torch.from_numpy(input_np) |
| 209 | weight = torch.from_numpy(weight_np) | 356 | weight = torch.from_numpy(weight_np) |
| @@ -226,7 +373,7 @@ def aclnn_conv_tbc_backward_golden( | |||
| 226 | False, | 373 | False, |
| 227 | [0], | 374 | [0], |
| 228 | 1, | 375 | 1, |
| 229 | - output_mask | 376 | + output_mask, |
| 230 | ) | 377 | ) |
| 231 | 378 | ||
| 232 | if grad_input_ncl is not None: | 379 | if grad_input_ncl is not None: |
| @@ -247,22 +394,40 @@ def aten_convolution_backward_golden( | |||
| 247 | output_padding: Union[int, List[int]] = 0, | 394 | output_padding: Union[int, List[int]] = 0, |
| 248 | groups: int = 1, | 395 | groups: int = 1, |
| 249 | output_mask: List[bool] = [True, True, False], | 396 | output_mask: List[bool] = [True, True, False], |
| 250 | - **kwargs | 397 | + **kwargs, |
| 251 | ): | 398 | ): |
| 252 | """ | 399 | """ |
| 253 | Golden for torch.ops.aten.convolution_backward. | 400 | Golden for torch.ops.aten.convolution_backward. |
| 254 | Supports 1D, 2D, 3D convolution backward. | 401 | Supports 1D, 2D, 3D convolution backward. |
| 255 | """ | 402 | """ |
| 256 | 403 | ||
| 257 | - input_shape = input.shape if isinstance(input, torch.Tensor) or hasattr(input, 'shape') else None | 404 | + input_shape = ( |
| 258 | - weight_shape = weight.shape if isinstance(weight, torch.Tensor) or hasattr(weight, 'shape') else None | 405 | + input.shape |
| 406 | + if isinstance(input, torch.Tensor) or hasattr(input, "shape") | ||
| 407 | + else None | ||
| 408 | + ) | ||
| 409 | + weight_shape = ( | ||
| 410 | + weight.shape | ||
| 411 | + if isinstance(weight, torch.Tensor) or hasattr(weight, "shape") | ||
| 412 | + else None | ||
| 413 | + ) | ||
| 259 | conv_dim = get_conv_dim(input_shape, weight_shape) | 414 | conv_dim = get_conv_dim(input_shape, weight_shape) |
| 260 | short_soc_version = kwargs.get("short_soc_version", None) | 415 | short_soc_version = kwargs.get("short_soc_version", None) |
| 261 | 416 | ||
| 262 | grad_input, grad_weight, grad_bias = _compute_conv_backward( | 417 | grad_input, grad_weight, grad_bias = _compute_conv_backward( |
| 263 | - grad_output, input, weight, stride, padding, | 418 | + grad_output, |
| 264 | - dilation, groups, conv_dim, transposed, output_padding, output_mask, bias_sizes, | 419 | + input, |
| 265 | - short_soc_version=short_soc_version | 420 | + weight, |
| 421 | + stride, | ||
| 422 | + padding, | ||
| 423 | + dilation, | ||
| 424 | + groups, | ||
| 425 | + conv_dim, | ||
| 426 | + transposed, | ||
| 427 | + output_padding, | ||
| 428 | + output_mask, | ||
| 429 | + bias_sizes, | ||
| 430 | + short_soc_version=short_soc_version, | ||
| 266 | ) | 431 | ) |
| 267 | - | 432 | + |
| 268 | - return (grad_input, grad_weight, grad_bias) | 433 | + return (grad_input, grad_weight, grad_bias) |
| @@ -2,26 +2,24 @@ | |||
| 2 | # -*- coding: UTF-8 -*- | 2 | # -*- coding: UTF-8 -*- |
| 3 | # ---------------------------------------------------------------------------- | 3 | # ---------------------------------------------------------------------------- |
| 4 | # Copyright (c) 2025-2026 Huawei Technologies Co., Ltd. | 4 | # Copyright (c) 2025-2026 Huawei Technologies Co., Ltd. |
| 5 | -# This program is free software, you can redistribute it and/or modify it under terms and conditions of | 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"). | 6 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 7 | -# Please refer to License for details. You may not use this file except in compliance with 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 | 12 | ||
| 13 | from typing import List, Optional, Union | 13 | from typing import List, Optional, Union |
| 14 | -import numpy as np | ||
| 15 | -import torch | ||
| 16 | 14 | ||
| 17 | __input__ = { | 15 | __input__ = { |
| 18 | "aclnn": { | 16 | "aclnn": { |
| 19 | "aclnnConvolutionBackward": "aclnn_convolution_backward_input", | 17 | "aclnnConvolutionBackward": "aclnn_convolution_backward_input", |
| 20 | "aclnnConvTbcBackward": "aclnn_conv_tbc_backward_input", | 18 | "aclnnConvTbcBackward": "aclnn_conv_tbc_backward_input", |
| 21 | }, | 19 | }, |
| 22 | - "torch_api": { | 20 | + "e2e": { |
| 23 | "torch.ops.aten.convolution_backward": "aten_convolution_backward_input", | 21 | "torch.ops.aten.convolution_backward": "aten_convolution_backward_input", |
| 24 | - } | 22 | + }, |
| 25 | } | 23 | } |
| 26 | 24 | ||
| 27 | 25 | ||
| @@ -41,7 +39,7 @@ def aclnn_convolution_backward_input( | |||
| 41 | gradInput=None, | 39 | gradInput=None, |
| 42 | gradWeight=None, | 40 | gradWeight=None, |
| 43 | gradBias=None, | 41 | gradBias=None, |
| 44 | - **kwargs | 42 | + **kwargs, |
| 45 | ): | 43 | ): |
| 46 | """ | 44 | """ |
| 47 | Input function for aclnnConvolutionBackward. | 45 | Input function for aclnnConvolutionBackward. |
| @@ -50,7 +48,7 @@ def aclnn_convolution_backward_input( | |||
| 50 | stride, padding, dilation, transposed, | 48 | stride, padding, dilation, transposed, |
| 51 | outputPadding, groups, outputMask, cubeMathType, | 49 | outputPadding, groups, outputMask, cubeMathType, |
| 52 | gradInput, gradWeight, gradBias) | 50 | gradInput, gradWeight, gradBias) |
| 53 | - | 51 | + |
| 54 | Args: | 52 | Args: |
| 55 | gradOutput: Gradient of output (NCL/NCHW/NCDHW) | 53 | gradOutput: Gradient of output (NCL/NCHW/NCDHW) |
| 56 | input: Original input tensor | 54 | input: Original input tensor |
| @@ -68,7 +66,7 @@ def aclnn_convolution_backward_input( | |||
| 68 | gradWeight: Pre-allocated gradWeight output | 66 | gradWeight: Pre-allocated gradWeight output |
| 69 | gradBias: Pre-allocated gradBias output | 67 | gradBias: Pre-allocated gradBias output |
| 70 | **kwargs: Additional context | 68 | **kwargs: Additional context |
| 71 | - | 69 | + |
| 72 | Returns: | 70 | Returns: |
| 73 | List of inputs | 71 | List of inputs |
| 74 | """ | 72 | """ |
| @@ -85,14 +83,14 @@ def aclnn_conv_tbc_backward_input( | |||
| 85 | gradInput=None, | 83 | gradInput=None, |
| 86 | gradWeight=None, | 84 | gradWeight=None, |
| 87 | gradBias=None, | 85 | gradBias=None, |
| 88 | - **kwargs | 86 | + **kwargs, |
| 89 | ): | 87 | ): |
| 90 | """ | 88 | """ |
| 91 | Input function for aclnnConvTbcBackward. | 89 | Input function for aclnnConvTbcBackward. |
| 92 | Parameter names and order follow aclnn_convolution_backward.h: | 90 | Parameter names and order follow aclnn_convolution_backward.h: |
| 93 | aclnnConvTbcBackwardGetWorkspaceSize(self, input, weight, bias, pad, cubeMathType, | 91 | aclnnConvTbcBackwardGetWorkspaceSize(self, input, weight, bias, pad, cubeMathType, |
| 94 | gradInput, gradWeight, gradBias) | 92 | gradInput, gradWeight, gradBias) |
| 95 | - | 93 | + |
| 96 | Args: | 94 | Args: |
| 97 | self: Convolution output gradient (ND/NCL) | 95 | self: Convolution output gradient (ND/NCL) |
| 98 | input: Convolution input (ND/NCL) | 96 | input: Convolution input (ND/NCL) |
| @@ -104,7 +102,7 @@ def aclnn_conv_tbc_backward_input( | |||
| 104 | gradWeight: Pre-allocated gradWeight output | 102 | gradWeight: Pre-allocated gradWeight output |
| 105 | gradBias: Pre-allocated gradBias output | 103 | gradBias: Pre-allocated gradBias output |
| 106 | **kwargs: Additional context | 104 | **kwargs: Additional context |
| 107 | - | 105 | + |
| 108 | Returns: | 106 | Returns: |
| 109 | List of inputs | 107 | List of inputs |
| 110 | """ | 108 | """ |
| @@ -123,10 +121,10 @@ def aten_convolution_backward_input( | |||
| 123 | output_padding: Union[int, List[int]] = 0, | 121 | output_padding: Union[int, List[int]] = 0, |
| 124 | groups: int = 1, | 122 | groups: int = 1, |
| 125 | output_mask: List[bool] = [True, True, False], | 123 | output_mask: List[bool] = [True, True, False], |
| 126 | - **kwargs | 124 | + **kwargs, |
| 127 | ): | 125 | ): |
| 128 | """ | 126 | """ |
| 129 | Input function for torch.ops.aten.convolution_backward. | 127 | Input function for torch.ops.aten.convolution_backward. |
| 130 | Supports 1D, 2D, 3D convolution backward. | 128 | Supports 1D, 2D, 3D convolution backward. |
| 131 | """ | 129 | """ |
| 132 | - return [grad_output, input, weight] | 130 | + return [grad_output, input, weight] |
| @@ -2,15 +2,15 @@ | |||
| 2 | # -*- coding: UTF-8 -*- | 2 | # -*- coding: UTF-8 -*- |
| 3 | # ---------------------------------------------------------------------------- | 3 | # ---------------------------------------------------------------------------- |
| 4 | # Copyright (c) 2025-2026 Huawei Technologies Co., Ltd. | 4 | # Copyright (c) 2025-2026 Huawei Technologies Co., Ltd. |
| 5 | -# This program is free software, you can redistribute it and/or modify it under terms and conditions of | 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"). | 6 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 7 | -# Please refer to License for details. You may not use this file except in compliance with 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 | 12 | ||
| 13 | -from typing import List, Optional, Tuple, Union | 13 | +from typing import List, Tuple, Union |
| 14 | import numpy as np | 14 | import numpy as np |
| 15 | import torch | 15 | import torch |
| 16 | import torch.nn.functional as F | 16 | import torch.nn.functional as F |
| @@ -33,7 +33,7 @@ __golden__ = { | |||
| 33 | "torch_npu.npu_conv2d": "torch_conv2d_golden", | 33 | "torch_npu.npu_conv2d": "torch_conv2d_golden", |
| 34 | "torch_npu.npu_conv3d": "torch_conv3d_golden", | 34 | "torch_npu.npu_conv3d": "torch_conv3d_golden", |
| 35 | "torch_npu.npu_quant_conv2d": "torch_npu_quant_conv2d_golden", | 35 | "torch_npu.npu_quant_conv2d": "torch_npu_quant_conv2d_golden", |
| 36 | - } | 36 | + }, |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | 39 | ||
| @@ -55,7 +55,9 @@ def to_float32(t): | |||
| 55 | return np.float32(t) | 55 | return np.float32(t) |
| 56 | if isinstance(t, torch.Tensor): | 56 | if isinstance(t, torch.Tensor): |
| 57 | dtype_str = str(t.dtype) | 57 | dtype_str = str(t.dtype) |
| 58 | - if any(s in dtype_str for s in ['hifloat8', 'float8', 'float4', 'int4', 'bfloat16']): | 58 | + if any( |
| 59 | + s in dtype_str for s in ["hifloat8", "float8", "float4", "int4", "bfloat16"] | ||
| 60 | + ): | ||
| 59 | return t.float() | 61 | return t.float() |
| 60 | return t.to(torch.float32) | 62 | return t.to(torch.float32) |
| 61 | return t.astype(np.float32) | 63 | return t.astype(np.float32) |
| @@ -98,11 +100,11 @@ def simulate_hf32_precision(data, short_soc_version=None): | |||
| 98 | def convert_output_dtype(out, output_dtype): | 100 | def convert_output_dtype(out, output_dtype): |
| 99 | """ | 101 | """ |
| 100 | Convert output array to target dtype with overflow handling. | 102 | Convert output array to target dtype with overflow handling. |
| 101 | - | 103 | + |
| 102 | Args: | 104 | Args: |
| 103 | out: Output numpy array | 105 | out: Output numpy array |
| 104 | output_dtype: Target dtype - can be str, torch.dtype, int (torch_npu dtype code) | 106 | output_dtype: Target dtype - can be str, torch.dtype, int (torch_npu dtype code) |
| 105 | - | 107 | + |
| 106 | Returns: | 108 | Returns: |
| 107 | numpy array with target dtype | 109 | numpy array with target dtype |
| 108 | """ | 110 | """ |
| @@ -121,13 +123,13 @@ def convert_output_dtype(out, output_dtype): | |||
| 121 | 258: "int8", | 123 | 258: "int8", |
| 122 | 283: "bfloat16", | 124 | 283: "bfloat16", |
| 123 | 290: "hifloat8", | 125 | 290: "hifloat8", |
| 124 | - 292: "float8_e4m3fn" | 126 | + 292: "float8_e4m3fn", |
| 125 | } | 127 | } |
| 126 | 128 | ||
| 127 | if isinstance(output_dtype, int): | 129 | if isinstance(output_dtype, int): |
| 128 | dtype_name = dtype_torch_npu_map.get(output_dtype, "float32") | 130 | dtype_name = dtype_torch_npu_map.get(output_dtype, "float32") |
| 129 | elif isinstance(output_dtype, torch.dtype): | 131 | elif isinstance(output_dtype, torch.dtype): |
| 130 | - dtype_name = str(output_dtype).split('.')[-1] | 132 | + dtype_name = str(output_dtype).split(".")[-1] |
| 131 | else: | 133 | else: |
| 132 | dtype_name = output_dtype | 134 | dtype_name = output_dtype |
| 133 | 135 | ||
| @@ -142,10 +144,14 @@ def convert_output_dtype(out, output_dtype): | |||
| 142 | if isinstance(dtype_ref, str): | 144 | if isinstance(dtype_ref, str): |
| 143 | module_name, dtype_cls_name = dtype_ref.split(".") | 145 | module_name, dtype_cls_name = dtype_ref.split(".") |
| 144 | try: | 146 | try: |
| 145 | - dtype_cls = getattr(__import__(module_name, fromlist=[dtype_cls_name]), dtype_cls_name) | 147 | + dtype_cls = getattr( |
| 148 | + __import__(module_name, fromlist=[dtype_cls_name]), dtype_cls_name | ||
| 149 | + ) | ||
| 146 | except (ImportError, AttributeError): | 150 | except (ImportError, AttributeError): |
| 147 | - raise RuntimeError(f"{module_name} is required for {output_dtype}. " | 151 | + raise RuntimeError( |
| 148 | - f"Install: pip install {module_name}") | 152 | + f"{module_name} is required for {output_dtype}. " |
| 153 | + f"Install: pip install {module_name}" | ||
| 154 | + ) | ||
| 149 | out = out.astype(dtype_cls) | 155 | out = out.astype(dtype_cls) |
| 150 | else: | 156 | else: |
| 151 | out = out.astype(dtype_ref) | 157 | out = out.astype(dtype_ref) |
| @@ -166,30 +172,49 @@ def decode_scale_tensor(scale_tensor): | |||
| 166 | if scale_tensor.dtype == np.int64 or scale_tensor.dtype == np.uint64: | 172 | if scale_tensor.dtype == np.int64 or scale_tensor.dtype == np.uint64: |
| 167 | return scale_tensor.astype(np.uint32).view(np.float32) | 173 | return scale_tensor.astype(np.uint32).view(np.float32) |
| 168 | return scale_tensor.astype(np.float32) | 174 | return scale_tensor.astype(np.float32) |
| 169 | - | 175 | + |
| 170 | if isinstance(scale_tensor, torch.Tensor): | 176 | if isinstance(scale_tensor, torch.Tensor): |
| 171 | np_arr = scale_tensor.cpu().numpy() | 177 | np_arr = scale_tensor.cpu().numpy() |
| 172 | if np_arr.dtype == np.int64 or np_arr.dtype == np.uint64: | 178 | if np_arr.dtype == np.int64 or np_arr.dtype == np.uint64: |
| 173 | return np_arr.astype(np.uint32).view(np.float32) | 179 | return np_arr.astype(np.uint32).view(np.float32) |
| 174 | return np_arr.astype(np.float32) | 180 | return np_arr.astype(np.float32) |
| 175 | - | 181 | + |
| 176 | return np.array(scale_tensor, dtype=np.float32) | 182 | return np.array(scale_tensor, dtype=np.float32) |
| 177 | 183 | ||
| 178 | 184 | ||
| 179 | -def _compute_conv_forward(input, weight, bias, stride, padding, | 185 | +def _compute_conv_forward( |
| 180 | - dilation, groups, conv_dim, transposed=False, | 186 | + input, |
| 181 | - outputPadding=0, cubeMathType=0, short_soc_version=None): | 187 | + weight, |
| 188 | + bias, | ||
| 189 | + stride, | ||
| 190 | + padding, | ||
| 191 | + dilation, | ||
| 192 | + groups, | ||
| 193 | + conv_dim, | ||
| 194 | + transposed=False, | ||
| 195 | + outputPadding=0, | ||
| 196 | + cubeMathType=0, | ||
| 197 | + short_soc_version=None, | ||
| 198 | +): | ||
| 182 | stride = ensure_list(stride, conv_dim) | 199 | stride = ensure_list(stride, conv_dim) |
| 183 | dilation = ensure_list(dilation, conv_dim) | 200 | dilation = ensure_list(dilation, conv_dim) |
| 184 | outputPadding = ensure_list(outputPadding, conv_dim) | 201 | outputPadding = ensure_list(outputPadding, conv_dim) |
| 185 | 202 | ||
| 186 | - input_dtype_str = str(input.dtype).split('.')[-1] if isinstance(input, torch.Tensor) else (str(input.dtype) if hasattr(input, 'dtype') else '') | 203 | + input_dtype_str = ( |
| 187 | - weight_dtype_str = str(weight.dtype).split('.')[-1] if isinstance(weight, torch.Tensor) else (str(weight.dtype) if hasattr(weight, 'dtype') else '') | 204 | + str(input.dtype).split(".")[-1] |
| 205 | + if isinstance(input, torch.Tensor) | ||
| 206 | + else (str(input.dtype) if hasattr(input, "dtype") else "") | ||
| 207 | + ) | ||
| 208 | + weight_dtype_str = ( | ||
| 209 | + str(weight.dtype).split(".")[-1] | ||
| 210 | + if isinstance(weight, torch.Tensor) | ||
| 211 | + else (str(weight.dtype) if hasattr(weight, "dtype") else "") | ||
| 212 | + ) | ||
| 188 | 213 | ||
| 189 | need_upcast = False | 214 | need_upcast = False |
| 190 | - if 'hifloat8' in input_dtype_str or 'hifloat8' in weight_dtype_str: | 215 | + if "hifloat8" in input_dtype_str or "hifloat8" in weight_dtype_str: |
| 191 | need_upcast = True | 216 | need_upcast = True |
| 192 | - elif 'bfloat16' in input_dtype_str: | 217 | + elif "bfloat16" in input_dtype_str: |
| 193 | need_upcast = True | 218 | need_upcast = True |
| 194 | 219 | ||
| 195 | if need_upcast: | 220 | if need_upcast: |
| @@ -213,19 +238,35 @@ def _compute_conv_forward(input, weight, bias, stride, padding, | |||
| 213 | input = F.pad(input, (padding[2], padding[3], padding[0], padding[1])) | 238 | input = F.pad(input, (padding[2], padding[3], padding[0], padding[1])) |
| 214 | padding = [0, 0] | 239 | padding = [0, 0] |
| 215 | elif conv_dim == 3 and len(padding) == 6: | 240 | elif conv_dim == 3 and len(padding) == 6: |
| 216 | - input = F.pad(input, (padding[4], padding[5], padding[2], padding[3], padding[0], padding[1])) | 241 | + input = F.pad( |
| 242 | + input, | ||
| 243 | + ( | ||
| 244 | + padding[4], | ||
| 245 | + padding[5], | ||
| 246 | + padding[2], | ||
| 247 | + padding[3], | ||
| 248 | + padding[0], | ||
| 249 | + padding[1], | ||
| 250 | + ), | ||
| 251 | + ) | ||
| 217 | padding = [0, 0, 0] | 252 | padding = [0, 0, 0] |
| 218 | else: | 253 | else: |
| 219 | padding = ensure_list(padding, conv_dim) | 254 | padding = ensure_list(padding, conv_dim) |
| 220 | 255 | ||
| 221 | - if input_dtype_str == 'float32': | 256 | + if input_dtype_str == "float32": |
| 222 | if cubeMathType in [1, 3]: | 257 | if cubeMathType in [1, 3]: |
| 223 | - input_np = simulate_hf32_precision(input.numpy().astype(np.float32), short_soc_version) | 258 | + input_np = simulate_hf32_precision( |
| 224 | - weight_np = simulate_hf32_precision(weight.numpy().astype(np.float32), short_soc_version) | 259 | + input.numpy().astype(np.float32), short_soc_version |
| 260 | + ) | ||
| 261 | + weight_np = simulate_hf32_precision( | ||
| 262 | + weight.numpy().astype(np.float32), short_soc_version | ||
| 263 | + ) | ||
| 225 | input = torch.from_numpy(input_np) | 264 | input = torch.from_numpy(input_np) |
| 226 | weight = torch.from_numpy(weight_np) | 265 | weight = torch.from_numpy(weight_np) |
| 227 | if bias is not None: | 266 | if bias is not None: |
| 228 | - bias_np = simulate_hf32_precision(bias.numpy().astype(np.float32), short_soc_version) | 267 | + bias_np = simulate_hf32_precision( |
| 268 | + bias.numpy().astype(np.float32), short_soc_version | ||
| 269 | + ) | ||
| 229 | bias = torch.from_numpy(bias_np) | 270 | bias = torch.from_numpy(bias_np) |
| 230 | elif cubeMathType == 2: | 271 | elif cubeMathType == 2: |
| 231 | input = input.to(torch.float16).to(torch.float32) | 272 | input = input.to(torch.float16).to(torch.float32) |
| @@ -234,12 +275,20 @@ def _compute_conv_forward(input, weight, bias, stride, padding, | |||
| 234 | bias = bias.to(torch.float16).to(torch.float32) | 275 | bias = bias.to(torch.float16).to(torch.float32) |
| 235 | 276 | ||
| 236 | out = torch.ops.aten.convolution( | 277 | out = torch.ops.aten.convolution( |
| 237 | - input, weight, bias, | 278 | + input, |
| 238 | - stride, padding, dilation, transposed, outputPadding, groups | 279 | + weight, |
| 280 | + bias, | ||
| 281 | + stride, | ||
| 282 | + padding, | ||
| 283 | + dilation, | ||
| 284 | + transposed, | ||
| 285 | + outputPadding, | ||
| 286 | + groups, | ||
| 239 | ) | 287 | ) |
| 240 | 288 | ||
| 241 | - if 'hifloat8' in input_dtype_str or 'hifloat8' in weight_dtype_str: | 289 | + if "hifloat8" in input_dtype_str or "hifloat8" in weight_dtype_str: |
| 242 | from ttk.utilities import numpy_hifloat8 | 290 | from ttk.utilities import numpy_hifloat8 |
| 291 | + | ||
| 243 | out = torch.from_numpy(out.numpy().astype(numpy_hifloat8()).astype(np.float32)) | 292 | out = torch.from_numpy(out.numpy().astype(numpy_hifloat8()).astype(np.float32)) |
| 244 | 293 | ||
| 245 | return out | 294 | return out |
| @@ -257,32 +306,52 @@ def aclnn_convolution_golden( | |||
| 257 | groups: int = 1, | 306 | groups: int = 1, |
| 258 | output=None, | 307 | output=None, |
| 259 | cubeMathType: int = 0, | 308 | cubeMathType: int = 0, |
| 260 | - **kwargs | 309 | + **kwargs, |
| 261 | ): | 310 | ): |
| 262 | """ | 311 | """ |
| 263 | ACLNN API golden for aclnnConvolution. | 312 | ACLNN API golden for aclnnConvolution. |
| 264 | Parameter names and order follow aclnn_convolution.h: | 313 | Parameter names and order follow aclnn_convolution.h: |
| 265 | aclnnConvolutionGetWorkspaceSize(input, weight, bias, stride, padding, dilation, | 314 | aclnnConvolutionGetWorkspaceSize(input, weight, bias, stride, padding, dilation, |
| 266 | transposed, outputPadding, groups, output, cubeMathType) | 315 | transposed, outputPadding, groups, output, cubeMathType) |
| 267 | - | 316 | + |
| 268 | Supports 1D, 2D, 3D convolutions based on input tensor dimensions. | 317 | Supports 1D, 2D, 3D convolutions based on input tensor dimensions. |
| 269 | Data types: FLOAT, FLOAT16, BFLOAT16, HIFLOAT8, FLOAT8_E4M3FN | 318 | Data types: FLOAT, FLOAT16, BFLOAT16, HIFLOAT8, FLOAT8_E4M3FN |
| 270 | Formats: NCL, NCHW, NCDHW | 319 | Formats: NCL, NCHW, NCDHW |
| 271 | """ | 320 | """ |
| 272 | - input_shape = input.shape if isinstance(input, torch.Tensor) or hasattr(input, 'shape') else None | 321 | + input_shape = ( |
| 273 | - weight_shape = weight.shape if isinstance(weight, torch.Tensor) or hasattr(weight, 'shape') else None | 322 | + input.shape |
| 323 | + if isinstance(input, torch.Tensor) or hasattr(input, "shape") | ||
| 324 | + else None | ||
| 325 | + ) | ||
| 326 | + weight_shape = ( | ||
| 327 | + weight.shape | ||
| 328 | + if isinstance(weight, torch.Tensor) or hasattr(weight, "shape") | ||
| 329 | + else None | ||
| 330 | + ) | ||
| 274 | conv_dim = get_conv_dim(input_shape, weight_shape) | 331 | conv_dim = get_conv_dim(input_shape, weight_shape) |
| 275 | short_soc_version = kwargs.get("short_soc_version", None) | 332 | short_soc_version = kwargs.get("short_soc_version", None) |
| 276 | - | 333 | + |
| 277 | - out = _compute_conv_forward(input, weight, bias, stride, padding, | 334 | + out = _compute_conv_forward( |
| 278 | - dilation, groups, conv_dim, transposed, outputPadding, | 335 | + input, |
| 279 | - cubeMathType, short_soc_version) | 336 | + weight, |
| 280 | - | 337 | + bias, |
| 338 | + stride, | ||
| 339 | + padding, | ||
| 340 | + dilation, | ||
| 341 | + groups, | ||
| 342 | + conv_dim, | ||
| 343 | + transposed, | ||
| 344 | + outputPadding, | ||
| 345 | + cubeMathType, | ||
| 346 | + short_soc_version, | ||
| 347 | + ) | ||
| 348 | + | ||
| 281 | output_tensor_index = kwargs.get("output_tensor_indexes", [-1])[0] | 349 | output_tensor_index = kwargs.get("output_tensor_indexes", [-1])[0] |
| 282 | - output_dtype = kwargs.get('tensor_dtypes')[output_tensor_index] | 350 | + output_dtype = kwargs.get("tensor_dtypes")[output_tensor_index] |
| 283 | - | 351 | + |
| 284 | - if output_dtype == 'hifloat8': | 352 | + if output_dtype == "hifloat8": |
| 285 | from ttk.utilities import numpy_hifloat8 | 353 | from ttk.utilities import numpy_hifloat8 |
| 354 | + | ||
| 286 | out = out.numpy().astype(numpy_hifloat8(), copy=False) | 355 | out = out.numpy().astype(numpy_hifloat8(), copy=False) |
| 287 | else: | 356 | else: |
| 288 | dtype_map = { | 357 | dtype_map = { |
| @@ -292,24 +361,18 @@ def aclnn_convolution_golden( | |||
| 292 | } | 361 | } |
| 293 | target_dtype = dtype_map.get(output_dtype, torch.bfloat16) | 362 | target_dtype = dtype_map.get(output_dtype, torch.bfloat16) |
| 294 | out = out.to(target_dtype) | 363 | out = out.to(target_dtype) |
| 295 | - | 364 | + |
| 296 | return out | 365 | return out |
| 297 | 366 | ||
| 298 | 367 | ||
| 299 | def aclnn_conv_tbc_golden( | 368 | def aclnn_conv_tbc_golden( |
| 300 | - self, | 369 | + self, weight, bias=None, pad: int = 0, output=None, cubeMathType: int = 0, **kwargs |
| 301 | - weight, | ||
| 302 | - bias=None, | ||
| 303 | - pad: int = 0, | ||
| 304 | - output=None, | ||
| 305 | - cubeMathType: int = 0, | ||
| 306 | - **kwargs | ||
| 307 | ): | 370 | ): |
| 308 | """ | 371 | """ |
| 309 | ACLNN API golden for aclnnConvTbc. | 372 | ACLNN API golden for aclnnConvTbc. |
| 310 | Parameter names and order follow aclnn_convolution.h: | 373 | Parameter names and order follow aclnn_convolution.h: |
| 311 | aclnnConvTbcGetWorkspaceSize(self, weight, bias, pad, output, cubeMathType) | 374 | aclnnConvTbcGetWorkspaceSize(self, weight, bias, pad, output, cubeMathType) |
| 312 | - | 375 | + |
| 313 | TBC format: (T, B, C) where T is time/sequence, B is batch, C is channels. | 376 | TBC format: (T, B, C) where T is time/sequence, B is batch, C is channels. |
| 314 | Equivalent to conv1d with input shape (B, C, T). | 377 | Equivalent to conv1d with input shape (B, C, T). |
| 315 | Data types: FLOAT, FLOAT16, BFLOAT16, HIFLOAT8 | 378 | Data types: FLOAT, FLOAT16, BFLOAT16, HIFLOAT8 |
| @@ -318,26 +381,38 @@ def aclnn_conv_tbc_golden( | |||
| 318 | short_soc_version = kwargs.get("short_soc_version", None) | 381 | short_soc_version = kwargs.get("short_soc_version", None) |
| 319 | 382 | ||
| 320 | if isinstance(self, np.ndarray): | 383 | if isinstance(self, np.ndarray): |
| 321 | - self = torch.from_numpy(self) | 384 | + self = torch.from_numpy(self.astype(np.float32)) |
| 322 | if isinstance(weight, np.ndarray): | 385 | if isinstance(weight, np.ndarray): |
| 323 | - weight = torch.from_numpy(weight) | 386 | + weight = torch.from_numpy(weight.astype(np.float32)) |
| 324 | if bias is not None and isinstance(bias, np.ndarray): | 387 | if bias is not None and isinstance(bias, np.ndarray): |
| 325 | - bias = torch.from_numpy(bias) | 388 | + bias = torch.from_numpy(bias.astype(np.float32)) |
| 326 | - | 389 | + |
| 327 | self = to_float32(self) | 390 | self = to_float32(self) |
| 328 | weight = to_float32(weight) | 391 | weight = to_float32(weight) |
| 329 | if bias is not None: | 392 | if bias is not None: |
| 330 | bias = to_float32(bias) | 393 | bias = to_float32(bias) |
| 331 | 394 | ||
| 332 | - input_dtype_str = str(self.dtype).split('.')[-1] | 395 | + if weight.dim() == 3: |
| 333 | - if input_dtype_str == 'float32': | 396 | + weight = weight.permute(2, 1, 0).contiguous() |
| 397 | + | ||
| 398 | + if self.dim() == 3: | ||
| 399 | + self = self.permute(1, 2, 0).contiguous() | ||
| 400 | + | ||
| 401 | + input_dtype_str = str(self.dtype).split(".")[-1] | ||
| 402 | + if input_dtype_str == "float32": | ||
| 334 | if cubeMathType in [1, 3]: | 403 | if cubeMathType in [1, 3]: |
| 335 | - self_np = simulate_hf32_precision(self.numpy().astype(np.float32), short_soc_version) | 404 | + self_np = simulate_hf32_precision( |
| 336 | - weight_np = simulate_hf32_precision(weight.numpy().astype(np.float32), short_soc_version) | 405 | + self.numpy().astype(np.float32), short_soc_version |
| 406 | + ) | ||
| 407 | + weight_np = simulate_hf32_precision( | ||
| 408 | + weight.numpy().astype(np.float32), short_soc_version | ||
| 409 | + ) | ||
| 337 | self = torch.from_numpy(self_np) | 410 | self = torch.from_numpy(self_np) |
| 338 | weight = torch.from_numpy(weight_np) | 411 | weight = torch.from_numpy(weight_np) |
| 339 | if bias is not None: | 412 | if bias is not None: |
| 340 | - bias_np = simulate_hf32_precision(bias.numpy().astype(np.float32), short_soc_version) | 413 | + bias_np = simulate_hf32_precision( |
| 414 | + bias.numpy().astype(np.float32), short_soc_version | ||
| 415 | + ) | ||
| 341 | bias = torch.from_numpy(bias_np) | 416 | bias = torch.from_numpy(bias_np) |
| 342 | elif cubeMathType == 2: | 417 | elif cubeMathType == 2: |
| 343 | self = self.to(torch.float16).to(torch.float32) | 418 | self = self.to(torch.float16).to(torch.float32) |
| @@ -345,11 +420,32 @@ def aclnn_conv_tbc_golden( | |||
| 345 | if bias is not None: | 420 | if bias is not None: |
| 346 | bias = bias.to(torch.float16).to(torch.float32) | 421 | bias = bias.to(torch.float16).to(torch.float32) |
| 347 | 422 | ||
| 348 | - out = torch.ops.aten.convolution( | 423 | + out = torch.ops.aten.convolution(self, weight, bias, [1], [pad], [1], False, [0], 1) |
| 349 | - self, weight, bias, [1], [pad], [1], False, [0], 1 | 424 | + |
| 350 | - ) | 425 | + if out.dim() == 3: |
| 351 | - | 426 | + out = out.permute(2, 0, 1).contiguous() |
| 352 | - return out | 427 | + |
| 428 | + out_np = out.numpy().astype(np.float32) | ||
| 429 | + tensor_dtypes = kwargs.get("tensor_dtypes", []) | ||
| 430 | + if tensor_dtypes: | ||
| 431 | + out_dtype = tensor_dtypes[-1] | ||
| 432 | + if out_dtype in ("hifloat8", "float8_e4m3fn", "float8_e5m2"): | ||
| 433 | + from ttk.utilities import numpy_hifloat8 | ||
| 434 | + import ml_dtypes | ||
| 435 | + | ||
| 436 | + np_dtype_map = { | ||
| 437 | + "hifloat8": numpy_hifloat8(), | ||
| 438 | + "float8_e4m3fn": ml_dtypes.float8_e4m3fn, | ||
| 439 | + "float8_e5m2": ml_dtypes.float8_e5m2, | ||
| 440 | + } | ||
| 441 | + np_dtype = np_dtype_map.get(out_dtype) | ||
| 442 | + if np_dtype is not None: | ||
| 443 | + out_np = out_np.astype(np_dtype) | ||
| 444 | + return out_np | ||
| 445 | + else: | ||
| 446 | + out_np = convert_output_dtype(out_np, out_dtype) | ||
| 447 | + | ||
| 448 | + return out_np | ||
| 353 | 449 | ||
| 354 | 450 | ||
| 355 | def aclnn_conv_depthwise2d_golden( | 451 | def aclnn_conv_depthwise2d_golden( |
| @@ -362,14 +458,14 @@ def aclnn_conv_depthwise2d_golden( | |||
| 362 | dilation: Union[int, List[int]] = 1, | 458 | dilation: Union[int, List[int]] = 1, |
| 363 | out=None, | 459 | out=None, |
| 364 | cubeMathType: int = 0, | 460 | cubeMathType: int = 0, |
| 365 | - **kwargs | 461 | + **kwargs, |
| 366 | ): | 462 | ): |
| 367 | """ | 463 | """ |
| 368 | ACLNN API golden for aclnnConvDepthwise2d. | 464 | ACLNN API golden for aclnnConvDepthwise2d. |
| 369 | Parameter names and order follow aclnn_convolution.h: | 465 | Parameter names and order follow aclnn_convolution.h: |
| 370 | aclnnConvDepthwise2dGetWorkspaceSize(self, weight, kernelSize, bias, stride, | 466 | aclnnConvDepthwise2dGetWorkspaceSize(self, weight, kernelSize, bias, stride, |
| 371 | padding, dilation, out, cubeMathType) | 467 | padding, dilation, out, cubeMathType) |
| 372 | - | 468 | + |
| 373 | Depthwise convolution where groups = input_channels. | 469 | Depthwise convolution where groups = input_channels. |
| 374 | Data types: FLOAT, FLOAT16, BFLOAT16, HIFLOAT8 | 470 | Data types: FLOAT, FLOAT16, BFLOAT16, HIFLOAT8 |
| 375 | Formats: NCHW | 471 | Formats: NCHW |
| @@ -382,42 +478,49 @@ def aclnn_conv_depthwise2d_golden( | |||
| 382 | weight = torch.from_numpy(weight) | 478 | weight = torch.from_numpy(weight) |
| 383 | if bias is not None and isinstance(bias, np.ndarray): | 479 | if bias is not None and isinstance(bias, np.ndarray): |
| 384 | bias = torch.from_numpy(bias) | 480 | bias = torch.from_numpy(bias) |
| 385 | - | 481 | + |
| 386 | self = to_float32(self) | 482 | self = to_float32(self) |
| 387 | weight = to_float32(weight) | 483 | weight = to_float32(weight) |
| 388 | if bias is not None: | 484 | if bias is not None: |
| 389 | bias = to_float32(bias) | 485 | bias = to_float32(bias) |
| 390 | 486 | ||
| 391 | - input_dtype_str = str(self.dtype).split('.')[-1] | 487 | + input_dtype_str = str(self.dtype).split(".")[-1] |
| 392 | - if input_dtype_str == 'float32': | 488 | + if input_dtype_str == "float32": |
| 393 | if cubeMathType in [1, 3]: | 489 | if cubeMathType in [1, 3]: |
| 394 | - self_np = simulate_hf32_precision(self.numpy().astype(np.float32), short_soc_version) | 490 | + self_np = simulate_hf32_precision( |
| 395 | - weight_np = simulate_hf32_precision(weight.numpy().astype(np.float32), short_soc_version) | 491 | + self.numpy().astype(np.float32), short_soc_version |
| 492 | + ) | ||
| 493 | + weight_np = simulate_hf32_precision( | ||
| 494 | + weight.numpy().astype(np.float32), short_soc_version | ||
| 495 | + ) | ||
| 396 | self = torch.from_numpy(self_np) | 496 | self = torch.from_numpy(self_np) |
| 397 | weight = torch.from_numpy(weight_np) | 497 | weight = torch.from_numpy(weight_np) |
| 398 | if bias is not None: | 498 | if bias is not None: |
| 399 | - bias_np = simulate_hf32_precision(bias.numpy().astype(np.float32), short_soc_version) | 499 | + bias_np = simulate_hf32_precision( |
| 500 | + bias.numpy().astype(np.float32), short_soc_version | ||
| 501 | + ) | ||
| 400 | bias = torch.from_numpy(bias_np) | 502 | bias = torch.from_numpy(bias_np) |
| 401 | elif cubeMathType == 2: | 503 | elif cubeMathType == 2: |
| 402 | self = self.to(torch.float16).to(torch.float32) | 504 | self = self.to(torch.float16).to(torch.float32) |
| 403 | weight = weight.to(torch.float16).to(torch.float32) | 505 | weight = weight.to(torch.float16).to(torch.float32) |
| 404 | if bias is not None: | 506 | if bias is not None: |
| 405 | bias = bias.to(torch.float16).to(torch.float32) | 507 | bias = bias.to(torch.float16).to(torch.float32) |
| 406 | - | 508 | + |
| 407 | groups = self.shape[1] | 509 | groups = self.shape[1] |
| 408 | - | 510 | + |
| 409 | stride = ensure_list(stride, 2) | 511 | stride = ensure_list(stride, 2) |
| 410 | padding = ensure_list(padding, 2) | 512 | padding = ensure_list(padding, 2) |
| 411 | dilation = ensure_list(dilation, 2) | 513 | dilation = ensure_list(dilation, 2) |
| 412 | - | 514 | + |
| 413 | out = torch.ops.aten.convolution( | 515 | out = torch.ops.aten.convolution( |
| 414 | self, weight, bias, stride, padding, dilation, False, [0, 0], groups | 516 | self, weight, bias, stride, padding, dilation, False, [0, 0], groups |
| 415 | ) | 517 | ) |
| 416 | 518 | ||
| 417 | output_tensor_index = kwargs.get("output_tensor_indexes", [-1])[0] | 519 | output_tensor_index = kwargs.get("output_tensor_indexes", [-1])[0] |
| 418 | - output_dtype = kwargs.get('tensor_dtypes')[output_tensor_index] | 520 | + output_dtype = kwargs.get("tensor_dtypes")[output_tensor_index] |
| 419 | - if output_dtype == 'hifloat8': | 521 | + if output_dtype == "hifloat8": |
| 420 | from ttk.utilities import numpy_hifloat8 | 522 | from ttk.utilities import numpy_hifloat8 |
| 523 | + | ||
| 421 | out = out.numpy().astype(numpy_hifloat8(), copy=False) | 524 | out = out.numpy().astype(numpy_hifloat8(), copy=False) |
| 422 | else: | 525 | else: |
| 423 | dtype_map = { | 526 | dtype_map = { |
| @@ -444,15 +547,19 @@ def aclnn_quant_conv_golden( | |||
| 444 | outputPadding=0, | 547 | outputPadding=0, |
| 445 | groups=1, | 548 | groups=1, |
| 446 | offsetx=0, | 549 | offsetx=0, |
| 447 | - roundMode='', | 550 | + roundMode="", |
| 448 | output=None, | 551 | output=None, |
| 449 | output_dtype=None, | 552 | output_dtype=None, |
| 450 | - **kwargs | 553 | + **kwargs, |
| 451 | ): | 554 | ): |
| 452 | import torch.nn.functional as F | 555 | import torch.nn.functional as F |
| 453 | 556 | ||
| 454 | - x_shape = x.shape if isinstance(x, torch.Tensor) or hasattr(x, 'shape') else None | 557 | + x_shape = x.shape if isinstance(x, torch.Tensor) or hasattr(x, "shape") else None |
| 455 | - w_shape = weight.shape if isinstance(weight, torch.Tensor) or hasattr(weight, 'shape') else None | 558 | + w_shape = ( |
| 559 | + weight.shape | ||
| 560 | + if isinstance(weight, torch.Tensor) or hasattr(weight, "shape") | ||
| 561 | + else None | ||
| 562 | + ) | ||
| 456 | conv_dim = get_conv_dim(x_shape, w_shape) | 563 | conv_dim = get_conv_dim(x_shape, w_shape) |
| 457 | 564 | ||
| 458 | x_np = to_float32(x) | 565 | x_np = to_float32(x) |
| @@ -460,7 +567,11 @@ def aclnn_quant_conv_golden( | |||
| 460 | x_calc = x_np.numpy() if isinstance(x_np, torch.Tensor) else x_np | 567 | x_calc = x_np.numpy() if isinstance(x_np, torch.Tensor) else x_np |
| 461 | w_calc = w_np.numpy() if isinstance(w_np, torch.Tensor) else w_np | 568 | w_calc = w_np.numpy() if isinstance(w_np, torch.Tensor) else w_np |
| 462 | 569 | ||
| 463 | - scale_np = decode_scale_tensor(scale) if scale is not None else np.ones(w_calc.shape[0], dtype=np.float32) | 570 | + scale_np = ( |
| 571 | + decode_scale_tensor(scale) | ||
| 572 | + if scale is not None | ||
| 573 | + else np.ones(w_calc.shape[0], dtype=np.float32) | ||
| 574 | + ) | ||
| 464 | 575 | ||
| 465 | bias_np = None | 576 | bias_np = None |
| 466 | if bias is not None and not isinstance(bias, (int, float)): | 577 | if bias is not None and not isinstance(bias, (int, float)): |
| @@ -484,7 +595,9 @@ def aclnn_quant_conv_golden( | |||
| 484 | pad_left = pad_right = pads[2] | 595 | pad_left = pad_right = pads[2] |
| 485 | else: | 596 | else: |
| 486 | pad_val = int(pads[0]) | 597 | pad_val = int(pads[0]) |
| 487 | - pad_front = pad_back = pad_top = pad_bottom = pad_left = pad_right = pad_val | 598 | + pad_front = pad_back = pad_top = pad_bottom = pad_left = pad_right = ( |
| 599 | + pad_val | ||
| 600 | + ) | ||
| 488 | else: | 601 | else: |
| 489 | pad_val = int(pads) | 602 | pad_val = int(pads) |
| 490 | pad_front = pad_back = pad_top = pad_bottom = pad_left = pad_right = pad_val | 603 | pad_front = pad_back = pad_top = pad_bottom = pad_left = pad_right = pad_val |
| @@ -503,40 +616,106 @@ def aclnn_quant_conv_golden( | |||
| 503 | pad_val = int(pads) | 616 | pad_val = int(pads) |
| 504 | pad_top = pad_bottom = pad_left = pad_right = pad_val | 617 | pad_top = pad_bottom = pad_left = pad_right = pad_val |
| 505 | 618 | ||
| 506 | - x_torch = torch.from_numpy(x_calc.astype(np.float32)) if x_calc.dtype != np.float32 else torch.from_numpy(x_calc) | 619 | + x_torch = ( |
| 507 | - w_torch = torch.from_numpy(w_calc.astype(np.float32)) if w_calc.dtype != np.float32 else torch.from_numpy(w_calc) | 620 | + torch.from_numpy(x_calc.astype(np.float32)) |
| 621 | + if x_calc.dtype != np.float32 | ||
| 622 | + else torch.from_numpy(x_calc) | ||
| 623 | + ) | ||
| 624 | + w_torch = ( | ||
| 625 | + torch.from_numpy(w_calc.astype(np.float32)) | ||
| 626 | + if w_calc.dtype != np.float32 | ||
| 627 | + else torch.from_numpy(w_calc) | ||
| 628 | + ) | ||
| 508 | 629 | ||
| 509 | if conv_dim == 3: | 630 | if conv_dim == 3: |
| 510 | - pad_needed = any(p > 0 for p in (pad_front, pad_back, pad_top, pad_bottom, pad_left, pad_right)) | 631 | + pad_needed = any( |
| 632 | + p > 0 | ||
| 633 | + for p in (pad_front, pad_back, pad_top, pad_bottom, pad_left, pad_right) | ||
| 634 | + ) | ||
| 511 | else: | 635 | else: |
| 512 | pad_needed = any(p > 0 for p in (pad_top, pad_bottom, pad_left, pad_right)) | 636 | pad_needed = any(p > 0 for p in (pad_top, pad_bottom, pad_left, pad_right)) |
| 513 | 637 | ||
| 514 | if pad_needed: | 638 | if pad_needed: |
| 515 | pad_value = float(offsetx) if offsetx != 0 else 0.0 | 639 | pad_value = float(offsetx) if offsetx != 0 else 0.0 |
| 516 | if conv_dim == 3: | 640 | if conv_dim == 3: |
| 517 | - x_torch = F.pad(x_torch, (pad_left, pad_right, pad_top, pad_bottom, pad_front, pad_back), | 641 | + x_torch = F.pad( |
| 518 | - "constant", pad_value) | 642 | + x_torch, |
| 643 | + (pad_left, pad_right, pad_top, pad_bottom, pad_front, pad_back), | ||
| 644 | + "constant", | ||
| 645 | + pad_value, | ||
| 646 | + ) | ||
| 519 | else: | 647 | else: |
| 520 | - x_torch = F.pad(x_torch, (pad_left, pad_right, pad_top, pad_bottom), | 648 | + x_torch = F.pad( |
| 521 | - "constant", pad_value) | 649 | + x_torch, |
| 650 | + (pad_left, pad_right, pad_top, pad_bottom), | ||
| 651 | + "constant", | ||
| 652 | + pad_value, | ||
| 653 | + ) | ||
| 522 | 654 | ||
| 523 | - bias_torch = torch.from_numpy(bias_np) if bias_np is not None else None | 655 | + bias_torch = None |
| 524 | 656 | ||
| 525 | out = torch.ops.aten.convolution( | 657 | out = torch.ops.aten.convolution( |
| 526 | - x_torch, w_torch, bias_torch, | 658 | + x_torch, |
| 527 | - strides, [0] * conv_dim, dilations_list, | 659 | + w_torch, |
| 528 | - False, [0] * conv_dim, groups | 660 | + bias_torch, |
| 661 | + strides, | ||
| 662 | + [0] * conv_dim, | ||
| 663 | + dilations_list, | ||
| 664 | + False, | ||
| 665 | + [0] * conv_dim, | ||
| 666 | + groups, | ||
| 529 | ) | 667 | ) |
| 530 | 668 | ||
| 531 | out_np = out.numpy() | 669 | out_np = out.numpy() |
| 532 | 670 | ||
| 533 | - if scale_np is not None: | 671 | + orig_x_dtype = ( |
| 534 | - scale_shape = (1, scale_np.shape[0]) + (1,) * conv_dim | 672 | + str(x.dtype).split(".")[-1] |
| 535 | - out_np = out_np * scale_np.reshape(scale_shape) | 673 | + if isinstance(x, torch.Tensor) |
| 674 | + else (str(getattr(x, "dtype", ""))) | ||
| 675 | + ) | ||
| 676 | + offset_np = None | ||
| 677 | + if offset is not None and not isinstance(offset, (int, float)): | ||
| 678 | + offset_np = to_float32(offset) | ||
| 679 | + if isinstance(offset_np, torch.Tensor): | ||
| 680 | + offset_np = offset_np.numpy() | ||
| 681 | + | ||
| 682 | + bias_is_quantized = False | ||
| 683 | + if bias is not None and not isinstance(bias, (int, float)): | ||
| 684 | + if isinstance(bias, torch.Tensor): | ||
| 685 | + bias_is_quantized = bias.dtype in (torch.int32, torch.int64) | ||
| 686 | + elif isinstance(bias, np.ndarray): | ||
| 687 | + bias_is_quantized = bias.dtype in (np.int32, np.int64) | ||
| 688 | + | ||
| 689 | + if orig_x_dtype == "int8": | ||
| 690 | + if bias_is_quantized: | ||
| 691 | + if bias_np is not None: | ||
| 692 | + bias_shape = (1, bias_np.shape[0]) + (1,) * conv_dim | ||
| 693 | + out_np = out_np + bias_np.reshape(bias_shape) | ||
| 694 | + if scale_np is not None: | ||
| 695 | + scale_shape = (1, scale_np.shape[0]) + (1,) * conv_dim | ||
| 696 | + out_np = out_np * scale_np.reshape(scale_shape) | ||
| 697 | + else: | ||
| 698 | + if scale_np is not None: | ||
| 699 | + scale_shape = (1, scale_np.shape[0]) + (1,) * conv_dim | ||
| 700 | + out_np = out_np * scale_np.reshape(scale_shape) | ||
| 701 | + if bias_np is not None: | ||
| 702 | + bias_shape = (1, bias_np.shape[0]) + (1,) * conv_dim | ||
| 703 | + out_np = out_np + bias_np.reshape(bias_shape) | ||
| 704 | + else: | ||
| 705 | + if bias_np is not None: | ||
| 706 | + bias_shape = (1, bias_np.shape[0]) + (1,) * conv_dim | ||
| 707 | + out_np = out_np + bias_np.reshape(bias_shape) | ||
| 708 | + if scale_np is not None: | ||
| 709 | + scale_shape = (1, scale_np.shape[0]) + (1,) * conv_dim | ||
| 710 | + out_np = out_np * scale_np.reshape(scale_shape) | ||
| 711 | + | ||
| 712 | + if offset_np is not None: | ||
| 713 | + offset_shape = (1, offset_np.shape[0]) + (1,) * conv_dim | ||
| 714 | + out_np = out_np + offset_np.reshape(offset_shape) | ||
| 536 | 715 | ||
| 537 | resolved_dtype = output_dtype | 716 | resolved_dtype = output_dtype |
| 538 | if resolved_dtype is None: | 717 | if resolved_dtype is None: |
| 539 | - tensor_dtypes = kwargs.get('tensor_dtypes', None) | 718 | + tensor_dtypes = kwargs.get("tensor_dtypes", None) |
| 540 | if tensor_dtypes is not None and not isinstance(tensor_dtypes, str): | 719 | if tensor_dtypes is not None and not isinstance(tensor_dtypes, str): |
| 541 | output_tensor_index = kwargs.get("output_tensor_indexes", [-1])[0] | 720 | output_tensor_index = kwargs.get("output_tensor_indexes", [-1])[0] |
| 542 | resolved_dtype = tensor_dtypes[output_tensor_index] | 721 | resolved_dtype = tensor_dtypes[output_tensor_index] |
| @@ -544,17 +723,41 @@ def aclnn_quant_conv_golden( | |||
| 544 | resolved_dtype = tensor_dtypes | 723 | resolved_dtype = tensor_dtypes |
| 545 | 724 | ||
| 546 | pre_round_dtypes = {"float16", "bfloat16"} | 725 | pre_round_dtypes = {"float16", "bfloat16"} |
| 547 | - dtype_name = resolved_dtype if isinstance(resolved_dtype, str) else str(resolved_dtype).split('.')[-1] if isinstance(resolved_dtype, torch.dtype) else None | 726 | + np_float8_dtypes = {"hifloat8", "float8_e4m3fn", "float8_e5m2"} |
| 727 | + dtype_name = ( | ||
| 728 | + resolved_dtype | ||
| 729 | + if isinstance(resolved_dtype, str) | ||
| 730 | + else str(resolved_dtype).split(".")[-1] | ||
| 731 | + if isinstance(resolved_dtype, torch.dtype) | ||
| 732 | + else None | ||
| 733 | + ) | ||
| 548 | if dtype_name in pre_round_dtypes: | 734 | if dtype_name in pre_round_dtypes: |
| 549 | - out_np = convert_output_dtype(out_np, resolved_dtype) | 735 | + out_np = out_np.astype(np.float32) |
| 550 | - if roundMode in ["rint", "round"]: | 736 | + if dtype_name == "float16": |
| 551 | - out_np = np.rint(out_np).astype(out_np.dtype) | 737 | + out_np = out_np.astype(np.float16) |
| 552 | - elif roundMode == "floor": | 738 | + elif dtype_name == "bfloat16": |
| 553 | - out_np = np.floor(out_np).astype(out_np.dtype) | 739 | + try: |
| 554 | - elif roundMode == "ceil": | 740 | + import ml_dtypes |
| 555 | - out_np = np.ceil(out_np).astype(out_np.dtype) | 741 | + |
| 742 | + out_np = out_np.astype(ml_dtypes.bfloat16) | ||
| 743 | + except ImportError: | ||
| 744 | + out_np = out_np.astype(np.float32) | ||
| 556 | return out_np | 745 | return out_np |
| 557 | 746 | ||
| 747 | + if dtype_name in np_float8_dtypes: | ||
| 748 | + from ttk.utilities import numpy_hifloat8 | ||
| 749 | + import ml_dtypes | ||
| 750 | + | ||
| 751 | + np_dtype_map = { | ||
| 752 | + "hifloat8": numpy_hifloat8(), | ||
| 753 | + "float8_e4m3fn": ml_dtypes.float8_e4m3fn, | ||
| 754 | + "float8_e5m2": ml_dtypes.float8_e5m2, | ||
| 755 | + } | ||
| 756 | + np_dtype = np_dtype_map.get(dtype_name) | ||
| 757 | + if np_dtype is not None: | ||
| 758 | + out_np = out_np.astype(np_dtype) | ||
| 759 | + return out_np | ||
| 760 | + | ||
| 558 | return convert_output_dtype(out_np, resolved_dtype) | 761 | return convert_output_dtype(out_np, resolved_dtype) |
| 559 | 762 | ||
| 560 | 763 | ||
| @@ -573,7 +776,7 @@ def torch_npu_quant_conv2d_golden( | |||
| 573 | offset=None, | 776 | offset=None, |
| 574 | input_dtype=None, | 777 | input_dtype=None, |
| 575 | weight_dtype=None, | 778 | weight_dtype=None, |
| 576 | - **kwargs | 779 | + **kwargs, |
| 577 | ): | 780 | ): |
| 578 | """ | 781 | """ |
| 579 | E2E golden for torch_npu.npu_quant_conv2d. | 782 | E2E golden for torch_npu.npu_quant_conv2d. |
| @@ -595,7 +798,7 @@ def torch_npu_quant_conv2d_golden( | |||
| 595 | roundMode=round_mode, | 798 | roundMode=round_mode, |
| 596 | output=None, | 799 | output=None, |
| 597 | output_dtype=output_dtype, | 800 | output_dtype=output_dtype, |
| 598 | - **kwargs | 801 | + **kwargs, |
| 599 | ) | 802 | ) |
| 600 | 803 | ||
| 601 | 804 | ||
| @@ -607,13 +810,14 @@ def torch_conv1d_golden( | |||
| 607 | padding: int = 0, | 810 | padding: int = 0, |
| 608 | dilation: int = 1, | 811 | dilation: int = 1, |
| 609 | groups: int = 1, | 812 | groups: int = 1, |
| 610 | - **kwargs | 813 | + **kwargs, |
| 611 | ): | 814 | ): |
| 612 | """ | 815 | """ |
| 613 | Golden for torch.conv1d / torch.nn.functional.conv1d. | 816 | Golden for torch.conv1d / torch.nn.functional.conv1d. |
| 614 | """ | 817 | """ |
| 615 | - return aten_convolution_golden(input, weight, bias, stride, padding, | 818 | + return aten_convolution_golden( |
| 616 | - dilation, groups=groups, **kwargs) | 819 | + input, weight, bias, stride, padding, dilation, groups=groups, **kwargs |
| 820 | + ) | ||
| 617 | 821 | ||
| 618 | 822 | ||
| 619 | def torch_conv2d_golden( | 823 | def torch_conv2d_golden( |
| @@ -624,22 +828,43 @@ def torch_conv2d_golden( | |||
| 624 | padding: Union[int, Tuple[int, int], str] = 0, | 828 | padding: Union[int, Tuple[int, int], str] = 0, |
| 625 | dilation: Union[int, Tuple[int, int]] = 1, | 829 | dilation: Union[int, Tuple[int, int]] = 1, |
| 626 | groups: int = 1, | 830 | groups: int = 1, |
| 627 | - **kwargs | 831 | + **kwargs, |
| 628 | ): | 832 | ): |
| 629 | """ | 833 | """ |
| 630 | Golden for torch.conv2d / torch.nn.functional.conv2d. | 834 | Golden for torch.conv2d / torch.nn.functional.conv2d. |
| 631 | """ | 835 | """ |
| 632 | - if isinstance(padding, str) and padding == 'same': | 836 | + if isinstance(padding, str) and padding == "same": |
| 633 | import torch.nn.functional as F | 837 | import torch.nn.functional as F |
| 634 | - input = to_float32(input) if isinstance(input, torch.Tensor) else torch.from_numpy(input.astype(np.float32)) | ||
| 635 | - weight = to_float32(weight) if isinstance(weight, torch.Tensor) else torch.from_numpy(weight.astype(np.float32)) | ||
| 636 | - if bias is not None: | ||
| 637 | - bias = to_float32(bias) if isinstance(bias, torch.Tensor) else torch.from_numpy(bias.astype(np.float32)) | ||
| 638 | - return F.conv2d(input, weight, bias=bias, stride=stride, | ||
| 639 | - padding='same', dilation=dilation, groups=groups) | ||
| 640 | 838 | ||
| 641 | - return aten_convolution_golden(input, weight, bias, stride, padding, | 839 | + input = ( |
| 642 | - dilation, groups=groups, **kwargs) | 840 | + to_float32(input) |
| 841 | + if isinstance(input, torch.Tensor) | ||
| 842 | + else torch.from_numpy(input.astype(np.float32)) | ||
| 843 | + ) | ||
| 844 | + weight = ( | ||
| 845 | + to_float32(weight) | ||
| 846 | + if isinstance(weight, torch.Tensor) | ||
| 847 | + else torch.from_numpy(weight.astype(np.float32)) | ||
| 848 | + ) | ||
| 849 | + if bias is not None: | ||
| 850 | + bias = ( | ||
| 851 | + to_float32(bias) | ||
| 852 | + if isinstance(bias, torch.Tensor) | ||
| 853 | + else torch.from_numpy(bias.astype(np.float32)) | ||
| 854 | + ) | ||
| 855 | + return F.conv2d( | ||
| 856 | + input, | ||
| 857 | + weight, | ||
| 858 | + bias=bias, | ||
| 859 | + stride=stride, | ||
| 860 | + padding="same", | ||
| 861 | + dilation=dilation, | ||
| 862 | + groups=groups, | ||
| 863 | + ) | ||
| 864 | + | ||
| 865 | + return aten_convolution_golden( | ||
| 866 | + input, weight, bias, stride, padding, dilation, groups=groups, **kwargs | ||
| 867 | + ) | ||
| 643 | 868 | ||
| 644 | 869 | ||
| 645 | def torch_conv3d_golden( | 870 | def torch_conv3d_golden( |
| @@ -650,22 +875,43 @@ def torch_conv3d_golden( | |||
| 650 | padding: Union[int, Tuple[int, int, int], str] = 0, | 875 | padding: Union[int, Tuple[int, int, int], str] = 0, |
| 651 | dilation: Union[int, Tuple[int, int, int]] = 1, | 876 | dilation: Union[int, Tuple[int, int, int]] = 1, |
| 652 | groups: int = 1, | 877 | groups: int = 1, |
| 653 | - **kwargs | 878 | + **kwargs, |
| 654 | ): | 879 | ): |
| 655 | """ | 880 | """ |
| 656 | Golden for torch.conv3d / torch.nn.functional.conv3d. | 881 | Golden for torch.conv3d / torch.nn.functional.conv3d. |
| 657 | """ | 882 | """ |
| 658 | - if isinstance(padding, str) and padding == 'same': | 883 | + if isinstance(padding, str) and padding == "same": |
| 659 | import torch.nn.functional as F | 884 | import torch.nn.functional as F |
| 660 | - input = to_float32(input) if isinstance(input, torch.Tensor) else torch.from_numpy(input.astype(np.float32)) | ||
| 661 | - weight = to_float32(weight) if isinstance(weight, torch.Tensor) else torch.from_numpy(weight.astype(np.float32)) | ||
| 662 | - if bias is not None: | ||
| 663 | - bias = to_float32(bias) if isinstance(bias, torch.Tensor) else torch.from_numpy(bias.astype(np.float32)) | ||
| 664 | - return F.conv3d(input, weight, bias=bias, stride=stride, | ||
| 665 | - padding='same', dilation=dilation, groups=groups) | ||
| 666 | 885 | ||
| 667 | - return aten_convolution_golden(input, weight, bias, stride, padding, | 886 | + input = ( |
| 668 | - dilation, groups=groups, **kwargs) | 887 | + to_float32(input) |
| 888 | + if isinstance(input, torch.Tensor) | ||
| 889 | + else torch.from_numpy(input.astype(np.float32)) | ||
| 890 | + ) | ||
| 891 | + weight = ( | ||
| 892 | + to_float32(weight) | ||
| 893 | + if isinstance(weight, torch.Tensor) | ||
| 894 | + else torch.from_numpy(weight.astype(np.float32)) | ||
| 895 | + ) | ||
| 896 | + if bias is not None: | ||
| 897 | + bias = ( | ||
| 898 | + to_float32(bias) | ||
| 899 | + if isinstance(bias, torch.Tensor) | ||
| 900 | + else torch.from_numpy(bias.astype(np.float32)) | ||
| 901 | + ) | ||
| 902 | + return F.conv3d( | ||
| 903 | + input, | ||
| 904 | + weight, | ||
| 905 | + bias=bias, | ||
| 906 | + stride=stride, | ||
| 907 | + padding="same", | ||
| 908 | + dilation=dilation, | ||
| 909 | + groups=groups, | ||
| 910 | + ) | ||
| 911 | + | ||
| 912 | + return aten_convolution_golden( | ||
| 913 | + input, weight, bias, stride, padding, dilation, groups=groups, **kwargs | ||
| 914 | + ) | ||
| 669 | 915 | ||
| 670 | 916 | ||
| 671 | def aten_convolution_golden( | 917 | def aten_convolution_golden( |
| @@ -682,21 +928,58 @@ def aten_convolution_golden( | |||
| 682 | benchmark: bool = False, | 928 | benchmark: bool = False, |
| 683 | deterministic: bool = False, | 929 | deterministic: bool = False, |
| 684 | cudnn_allow_tf32: bool = True, | 930 | cudnn_allow_tf32: bool = True, |
| 685 | - **kwargs | 931 | + enable_hf32: bool = False, |
| 932 | + **kwargs, | ||
| 686 | ): | 933 | ): |
| 687 | """ | 934 | """ |
| 688 | Golden for torch.ops.aten.convolution. | 935 | Golden for torch.ops.aten.convolution. |
| 689 | Supports 1D, 2D, 3D convolutions. | 936 | Supports 1D, 2D, 3D convolutions. |
| 690 | """ | 937 | """ |
| 691 | - | 938 | + |
| 692 | - input_shape = input.shape if isinstance(input, torch.Tensor) or hasattr(input, 'shape') else None | 939 | + input_shape = ( |
| 693 | - weight_shape = weight.shape if isinstance(weight, torch.Tensor) or hasattr(weight, 'shape') else None | 940 | + input.shape |
| 941 | + if isinstance(input, torch.Tensor) or hasattr(input, "shape") | ||
| 942 | + else None | ||
| 943 | + ) | ||
| 944 | + weight_shape = ( | ||
| 945 | + weight.shape | ||
| 946 | + if isinstance(weight, torch.Tensor) or hasattr(weight, "shape") | ||
| 947 | + else None | ||
| 948 | + ) | ||
| 694 | conv_dim = get_conv_dim(input_shape, weight_shape) | 949 | conv_dim = get_conv_dim(input_shape, weight_shape) |
| 695 | short_soc_version = kwargs.get("short_soc_version", None) | 950 | short_soc_version = kwargs.get("short_soc_version", None) |
| 696 | 951 | ||
| 697 | - out = _compute_conv_forward(input, weight, bias, stride, padding, | 952 | + if enable_hf32: |
| 698 | - dilation, groups, conv_dim, transposed, output_padding, | 953 | + cubeMathType = 1 |
| 699 | - cubeMathType=cubeMathType, | 954 | + |
| 700 | - short_soc_version=short_soc_version) | 955 | + out = _compute_conv_forward( |
| 701 | - | 956 | + input, |
| 702 | - return out | 957 | + weight, |
| 958 | + bias, | ||
| 959 | + stride, | ||
| 960 | + padding, | ||
| 961 | + dilation, | ||
| 962 | + groups, | ||
| 963 | + conv_dim, | ||
| 964 | + transposed, | ||
| 965 | + output_padding, | ||
| 966 | + cubeMathType=cubeMathType, | ||
| 967 | + short_soc_version=short_soc_version, | ||
| 968 | + ) | ||
| 969 | + | ||
| 970 | + input_dtype_str = ( | ||
| 971 | + str(input.dtype).split(".")[-1] | ||
| 972 | + if isinstance(input, torch.Tensor) | ||
| 973 | + else (str(getattr(input, "dtype", ""))) | ||
| 974 | + ) | ||
| 975 | + if input_dtype_str == "bfloat16": | ||
| 976 | + try: | ||
| 977 | + import ml_dtypes | ||
| 978 | + | ||
| 979 | + out = out.to(torch.float32).numpy().astype(ml_dtypes.bfloat16) | ||
| 980 | + except ImportError: | ||
| 981 | + out = out.to(torch.float32).numpy().astype(np.float32) | ||
| 982 | + elif input_dtype_str == "float16": | ||
| 983 | + out = out.to(torch.float16) | ||
| 984 | + | ||
| 985 | + return out | ||
| @@ -2,15 +2,15 @@ | |||
| 2 | # -*- coding: UTF-8 -*- | 2 | # -*- coding: UTF-8 -*- |
| 3 | # ---------------------------------------------------------------------------- | 3 | # ---------------------------------------------------------------------------- |
| 4 | # Copyright (c) 2025-2026 Huawei Technologies Co., Ltd. | 4 | # Copyright (c) 2025-2026 Huawei Technologies Co., Ltd. |
| 5 | -# This program is free software, you can redistribute it and/or modify it under terms and conditions of | 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"). | 6 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 7 | -# Please refer to License for details. You may not use this file except in compliance with 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 | 12 | ||
| 13 | -from typing import List, Optional, Tuple, Union | 13 | +from typing import List, Tuple, Union |
| 14 | import numpy as np | 14 | import numpy as np |
| 15 | import torch | 15 | import torch |
| 16 | 16 | ||
| @@ -32,7 +32,7 @@ __input__ = { | |||
| 32 | "torch_npu.npu_conv3d": "torch_conv3d_input", | 32 | "torch_npu.npu_conv3d": "torch_conv3d_input", |
| 33 | "torch_npu.npu_quant_conv2d": "torch_npu_quant_conv2d_input", | 33 | "torch_npu.npu_quant_conv2d": "torch_npu_quant_conv2d_input", |
| 34 | "torch.ops.aten.convolution": "aten_convolution_input", | 34 | "torch.ops.aten.convolution": "aten_convolution_input", |
| 35 | - } | 35 | + }, |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | 38 | ||
| @@ -48,33 +48,27 @@ def aclnn_convolution_input( | |||
| 48 | groups: int = 1, | 48 | groups: int = 1, |
| 49 | output=None, | 49 | output=None, |
| 50 | cubeMathType: int = 0, | 50 | cubeMathType: int = 0, |
| 51 | - **kwargs | 51 | + **kwargs, |
| 52 | ): | 52 | ): |
| 53 | """ | 53 | """ |
| 54 | Input function for aclnnConvolution. | 54 | Input function for aclnnConvolution. |
| 55 | Parameter names and order follow aclnn_convolution.h: | 55 | Parameter names and order follow aclnn_convolution.h: |
| 56 | aclnnConvolutionGetWorkspaceSize(input, weight, bias, stride, padding, dilation, | 56 | aclnnConvolutionGetWorkspaceSize(input, weight, bias, stride, padding, dilation, |
| 57 | transposed, outputPadding, groups, output, cubeMathType) | 57 | transposed, outputPadding, groups, output, cubeMathType) |
| 58 | - | 58 | + |
| 59 | Supports 1D, 2D, 3D convolutions. | 59 | Supports 1D, 2D, 3D convolutions. |
| 60 | """ | 60 | """ |
| 61 | return [input, weight, bias] | 61 | return [input, weight, bias] |
| 62 | 62 | ||
| 63 | 63 | ||
| 64 | def aclnn_conv_tbc_input( | 64 | def aclnn_conv_tbc_input( |
| 65 | - self, | 65 | + self, weight, bias=None, pad: int = 0, output=None, cubeMathType: int = 0, **kwargs |
| 66 | - weight, | ||
| 67 | - bias=None, | ||
| 68 | - pad: int = 0, | ||
| 69 | - output=None, | ||
| 70 | - cubeMathType: int = 0, | ||
| 71 | - **kwargs | ||
| 72 | ): | 66 | ): |
| 73 | """ | 67 | """ |
| 74 | Input function for aclnnConvTbc. | 68 | Input function for aclnnConvTbc. |
| 75 | Parameter names and order follow aclnn_convolution.h: | 69 | Parameter names and order follow aclnn_convolution.h: |
| 76 | aclnnConvTbcGetWorkspaceSize(self, weight, bias, pad, output, cubeMathType) | 70 | aclnnConvTbcGetWorkspaceSize(self, weight, bias, pad, output, cubeMathType) |
| 77 | - | 71 | + |
| 78 | TBC format: (T, B, C) where T is time/sequence, B is batch, C is channels. | 72 | TBC format: (T, B, C) where T is time/sequence, B is batch, C is channels. |
| 79 | """ | 73 | """ |
| 80 | return [self, weight, bias] | 74 | return [self, weight, bias] |
| @@ -90,14 +84,14 @@ def aclnn_conv_depthwise2d_input( | |||
| 90 | dilation: Union[int, List[int]] = 1, | 84 | dilation: Union[int, List[int]] = 1, |
| 91 | out=None, | 85 | out=None, |
| 92 | cubeMathType: int = 0, | 86 | cubeMathType: int = 0, |
| 93 | - **kwargs | 87 | + **kwargs, |
| 94 | ): | 88 | ): |
| 95 | """ | 89 | """ |
| 96 | Input function for aclnnConvDepthwise2d. | 90 | Input function for aclnnConvDepthwise2d. |
| 97 | Parameter names and order follow aclnn_convolution.h: | 91 | Parameter names and order follow aclnn_convolution.h: |
| 98 | aclnnConvDepthwise2dGetWorkspaceSize(self, weight, kernelSize, bias, stride, | 92 | aclnnConvDepthwise2dGetWorkspaceSize(self, weight, kernelSize, bias, stride, |
| 99 | padding, dilation, out, cubeMathType) | 93 | padding, dilation, out, cubeMathType) |
| 100 | - | 94 | + |
| 101 | Depthwise convolution where groups = input_channels. | 95 | Depthwise convolution where groups = input_channels. |
| 102 | """ | 96 | """ |
| 103 | return [self, weight, bias] | 97 | return [self, weight, bias] |
| @@ -117,8 +111,8 @@ def aclnn_quant_conv2d_input( | |||
| 117 | outputPadding=0, | 111 | outputPadding=0, |
| 118 | groups=1, | 112 | groups=1, |
| 119 | offsetx=0, | 113 | offsetx=0, |
| 120 | - roundMode='', | 114 | + roundMode="", |
| 121 | - **kwargs | 115 | + **kwargs, |
| 122 | ): | 116 | ): |
| 123 | """ | 117 | """ |
| 124 | Input function for aclnnQuantConvolution. | 118 | Input function for aclnnQuantConvolution. |
| @@ -128,14 +122,22 @@ def aclnn_quant_conv2d_input( | |||
| 128 | outputPadding, groups, offsetx, roundMode) | 122 | outputPadding, groups, offsetx, roundMode) |
| 129 | """ | 123 | """ |
| 130 | if scale is not None and not isinstance(scale, (int, float)): | 124 | if scale is not None and not isinstance(scale, (int, float)): |
| 131 | - n_channels = scale.shape[0] if hasattr(scale, 'shape') else len(scale) | 125 | + n_channels = scale.shape[0] if hasattr(scale, "shape") else len(scale) |
| 132 | scale_float = np.random.uniform(0.01, 1.0, size=n_channels).astype(np.float32) | 126 | scale_float = np.random.uniform(0.01, 1.0, size=n_channels).astype(np.float32) |
| 133 | - scale_float = np.bitwise_and(scale_float.view(np.uint32), 0xffffe000).view(np.float32) | 127 | + scale_float = np.bitwise_and(scale_float.view(np.uint32), 0xFFFFE000).view( |
| 128 | + np.float32 | ||
| 129 | + ) | ||
| 134 | scale_encoded = torch.from_numpy(scale_float.view(np.uint32).astype(np.int64)) | 130 | scale_encoded = torch.from_numpy(scale_float.view(np.uint32).astype(np.int64)) |
| 135 | if isinstance(scale, torch.Tensor): | 131 | if isinstance(scale, torch.Tensor): |
| 136 | - scale.copy_(scale_encoded) | 132 | + if scale.dtype == torch.int64: |
| 133 | + scale.copy_(scale_encoded) | ||
| 134 | + else: | ||
| 135 | + scale.copy_(torch.from_numpy(scale_float)) | ||
| 137 | elif isinstance(scale, np.ndarray): | 136 | elif isinstance(scale, np.ndarray): |
| 138 | - scale[:] = scale_encoded.numpy() | 137 | + if scale.dtype == np.int64: |
| 138 | + scale[:] = scale_encoded.numpy() | ||
| 139 | + else: | ||
| 140 | + scale[:] = scale_float | ||
| 139 | else: | 141 | else: |
| 140 | scale = scale_encoded | 142 | scale = scale_encoded |
| 141 | 143 | ||
| @@ -151,13 +153,13 @@ def torch_npu_quant_conv2d_input( | |||
| 151 | dilations=1, | 153 | dilations=1, |
| 152 | groups=1, | 154 | groups=1, |
| 153 | offset_x=0, | 155 | offset_x=0, |
| 154 | - round_mode='rint', | 156 | + round_mode="rint", |
| 155 | output_dtype=None, | 157 | output_dtype=None, |
| 156 | bias=None, | 158 | bias=None, |
| 157 | offset=None, | 159 | offset=None, |
| 158 | input_dtype=None, | 160 | input_dtype=None, |
| 159 | weight_dtype=None, | 161 | weight_dtype=None, |
| 160 | - **kwargs | 162 | + **kwargs, |
| 161 | ): | 163 | ): |
| 162 | """ | 164 | """ |
| 163 | Input function for torch_npu.npu_quant_conv2d. | 165 | Input function for torch_npu.npu_quant_conv2d. |
| @@ -169,12 +171,18 @@ def torch_npu_quant_conv2d_input( | |||
| 169 | For float8/hifloat8 types, scale encoding is left as-is. | 171 | For float8/hifloat8 types, scale encoding is left as-is. |
| 170 | """ | 172 | """ |
| 171 | if scale is not None and not isinstance(scale, (int, float)): | 173 | if scale is not None and not isinstance(scale, (int, float)): |
| 172 | - x_dtype = str(x.dtype).split('.')[-1] if hasattr(x, 'dtype') else '' | 174 | + x_dtype = str(x.dtype).split(".")[-1] if hasattr(x, "dtype") else "" |
| 173 | - if x_dtype == 'int8': | 175 | + if x_dtype == "int8": |
| 174 | - n_channels = scale.shape[0] if hasattr(scale, 'shape') else len(scale) | 176 | + n_channels = scale.shape[0] if hasattr(scale, "shape") else len(scale) |
| 175 | - scale_float = np.random.uniform(0.01, 1.0, size=n_channels).astype(np.float32) | 177 | + scale_float = np.random.uniform(0.01, 1.0, size=n_channels).astype( |
| 176 | - scale_float = np.bitwise_and(scale_float.view(np.uint32), 0xffffe000).view(np.float32) | 178 | + np.float32 |
| 177 | - scale_encoded = torch.from_numpy(scale_float.view(np.uint32).astype(np.int64)) | 179 | + ) |
| 180 | + scale_float = np.bitwise_and(scale_float.view(np.uint32), 0xFFFFE000).view( | ||
| 181 | + np.float32 | ||
| 182 | + ) | ||
| 183 | + scale_encoded = torch.from_numpy( | ||
| 184 | + scale_float.view(np.uint32).astype(np.int64) | ||
| 185 | + ) | ||
| 178 | if isinstance(scale, torch.Tensor): | 186 | if isinstance(scale, torch.Tensor): |
| 179 | scale.copy_(scale_encoded) | 187 | scale.copy_(scale_encoded) |
| 180 | elif isinstance(scale, np.ndarray): | 188 | elif isinstance(scale, np.ndarray): |
| @@ -193,11 +201,19 @@ def torch_conv1d_input( | |||
| 193 | padding: int = 0, | 201 | padding: int = 0, |
| 194 | dilation: int = 1, | 202 | dilation: int = 1, |
| 195 | groups: int = 1, | 203 | groups: int = 1, |
| 196 | - **kwargs | 204 | + enable_hf32: bool = False, |
| 205 | + **kwargs, | ||
| 197 | ): | 206 | ): |
| 198 | """ | 207 | """ |
| 199 | Input function for torch.conv1d / torch.nn.functional.conv1d. | 208 | Input function for torch.conv1d / torch.nn.functional.conv1d. |
| 200 | """ | 209 | """ |
| 210 | + if enable_hf32: | ||
| 211 | + try: | ||
| 212 | + import torch_npu | ||
| 213 | + | ||
| 214 | + torch_npu.conv.allow_hf32 = True | ||
| 215 | + except (ImportError, AttributeError): | ||
| 216 | + pass | ||
| 201 | return [input, weight, bias] | 217 | return [input, weight, bias] |
| 202 | 218 | ||
| 203 | 219 | ||
| @@ -209,7 +225,7 @@ def torch_conv2d_input( | |||
| 209 | padding: Union[int, Tuple[int, int], str] = 0, | 225 | padding: Union[int, Tuple[int, int], str] = 0, |
| 210 | dilation: Union[int, Tuple[int, int]] = 1, | 226 | dilation: Union[int, Tuple[int, int]] = 1, |
| 211 | groups: int = 1, | 227 | groups: int = 1, |
| 212 | - **kwargs | 228 | + **kwargs, |
| 213 | ): | 229 | ): |
| 214 | """ | 230 | """ |
| 215 | Input function for torch.conv2d / torch.nn.functional.conv2d. | 231 | Input function for torch.conv2d / torch.nn.functional.conv2d. |
| @@ -225,7 +241,7 @@ def torch_conv3d_input( | |||
| 225 | padding: Union[int, Tuple[int, int, int], str] = 0, | 241 | padding: Union[int, Tuple[int, int, int], str] = 0, |
| 226 | dilation: Union[int, Tuple[int, int, int]] = 1, | 242 | dilation: Union[int, Tuple[int, int, int]] = 1, |
| 227 | groups: int = 1, | 243 | groups: int = 1, |
| 228 | - **kwargs | 244 | + **kwargs, |
| 229 | ): | 245 | ): |
| 230 | """ | 246 | """ |
| 231 | Input function for torch.conv3d / torch.nn.functional.conv3d. | 247 | Input function for torch.conv3d / torch.nn.functional.conv3d. |
| @@ -246,10 +262,10 @@ def aten_convolution_input( | |||
| 246 | benchmark: bool = False, | 262 | benchmark: bool = False, |
| 247 | deterministic: bool = False, | 263 | deterministic: bool = False, |
| 248 | cudnn_allow_tf32: bool = True, | 264 | cudnn_allow_tf32: bool = True, |
| 249 | - **kwargs | 265 | + **kwargs, |
| 250 | ): | 266 | ): |
| 251 | """ | 267 | """ |
| 252 | Input function for torch.ops.aten.convolution. | 268 | Input function for torch.ops.aten.convolution. |
| 253 | Supports 1D, 2D, 3D convolutions based on input tensor dimensions. | 269 | Supports 1D, 2D, 3D convolutions based on input tensor dimensions. |
| 254 | """ | 270 | """ |
| 255 | - return [input, weight, bias] | 271 | + return [input, weight, bias] |
| @@ -34,7 +34,10 @@ import torch | |||
| 34 | __golden__ = { | 34 | __golden__ = { |
| 35 | "aclnn": { | 35 | "aclnn": { |
| 36 | "aclnnDeformableConv2d": "deformable_conv2d_golden", | 36 | "aclnnDeformableConv2d": "deformable_conv2d_golden", |
| 37 | - } | 37 | + }, |
| 38 | + "e2e": { | ||
| 39 | + "torch_npu.npu_deformable_conv2d": "deformable_conv2d_golden", | ||
| 40 | + }, | ||
| 38 | } | 41 | } |
| 39 | 42 | ||
| 40 | FP32_STR = "float32" | 43 | FP32_STR = "float32" |
| @@ -71,24 +74,6 @@ def due_fp16_overflow(data): | |||
| 71 | return data | 74 | return data |
| 72 | 75 | ||
| 73 | 76 | ||
| 74 | -def simulate_hf32_precision(data, short_soc_version=None): | ||
| 75 | - """ | ||
| 76 | - Simulate HF32 (Half Float 32) precision. | ||
| 77 | - Ascend910B: truncates lower 12 bits of float32 mantissa, keeping 20 bits with rounding. | ||
| 78 | - Default: truncates lower 13 bits of float32 mantissa, keeping 19 bits with rounding. | ||
| 79 | - """ | ||
| 80 | - if data.dtype == np.float32: | ||
| 81 | - input_hf32 = data.view(np.int32) | ||
| 82 | - if short_soc_version in ("Ascend910B",): | ||
| 83 | - input_hf32 = np.right_shift(np.right_shift(input_hf32, 11) + 1, 1) | ||
| 84 | - input_hf32 = np.left_shift(input_hf32, 12) | ||
| 85 | - else: | ||
| 86 | - input_hf32 = np.right_shift(np.right_shift(input_hf32, 12) + 1, 1) | ||
| 87 | - input_hf32 = np.left_shift(input_hf32, 13) | ||
| 88 | - return input_hf32.view(np.float32) | ||
| 89 | - return data | ||
| 90 | - | ||
| 91 | - | ||
| 92 | def convert_output_dtype(out, output_dtype): | 77 | def convert_output_dtype(out, output_dtype): |
| 93 | dtype_map = { | 78 | dtype_map = { |
| 94 | "float16": (np.float16, True), | 79 | "float16": (np.float16, True), |
| @@ -107,10 +92,14 @@ def convert_output_dtype(out, output_dtype): | |||
| 107 | if isinstance(dtype_ref, str): | 92 | if isinstance(dtype_ref, str): |
| 108 | module_name, dtype_name = dtype_ref.split(".") | 93 | module_name, dtype_name = dtype_ref.split(".") |
| 109 | try: | 94 | try: |
| 110 | - dtype_cls = getattr(__import__(module_name, fromlist=[dtype_name]), dtype_name) | 95 | + dtype_cls = getattr( |
| 96 | + __import__(module_name, fromlist=[dtype_name]), dtype_name | ||
| 97 | + ) | ||
| 111 | except (ImportError, AttributeError): | 98 | except (ImportError, AttributeError): |
| 112 | - raise RuntimeError(f"{module_name} is required for {output_dtype}. " | 99 | + raise RuntimeError( |
| 113 | - f"Install: pip install {module_name}") | 100 | + f"{module_name} is required for {output_dtype}. " |
| 101 | + f"Install: pip install {module_name}" | ||
| 102 | + ) | ||
| 114 | out = out.astype(dtype_cls) | 103 | out = out.astype(dtype_cls) |
| 115 | else: | 104 | else: |
| 116 | out = out.astype(dtype_ref) | 105 | out = out.astype(dtype_ref) |
| @@ -125,82 +114,109 @@ def bilinear_interpolate(input_tensor, h, w, c, batch_offset, in_h, in_w): | |||
| 125 | """ | 114 | """ |
| 126 | h_floor = int(np.floor(h)) | 115 | h_floor = int(np.floor(h)) |
| 127 | w_floor = int(np.floor(w)) | 116 | w_floor = int(np.floor(w)) |
| 128 | - | 117 | + |
| 129 | h_delta = h - h_floor | 118 | h_delta = h - h_floor |
| 130 | w_delta = w - w_floor | 119 | w_delta = w - w_floor |
| 131 | - | 120 | + |
| 132 | def get_value(hi, wi): | 121 | def get_value(hi, wi): |
| 133 | if hi >= 0 and wi >= 0 and hi < in_h and wi < in_w: | 122 | if hi >= 0 and wi >= 0 and hi < in_h and wi < in_w: |
| 134 | return input_tensor[batch_offset + hi * in_w + wi] | 123 | return input_tensor[batch_offset + hi * in_w + wi] |
| 135 | return 0.0 | 124 | return 0.0 |
| 136 | - | 125 | + |
| 137 | top_left = get_value(h_floor, w_floor) | 126 | top_left = get_value(h_floor, w_floor) |
| 138 | top_right = get_value(h_floor, w_floor + 1) | 127 | top_right = get_value(h_floor, w_floor + 1) |
| 139 | bottom_left = get_value(h_floor + 1, w_floor) | 128 | bottom_left = get_value(h_floor + 1, w_floor) |
| 140 | bottom_right = get_value(h_floor + 1, w_floor + 1) | 129 | bottom_right = get_value(h_floor + 1, w_floor + 1) |
| 141 | - | 130 | + |
| 142 | top = top_left * (1 - w_delta) + top_right * w_delta | 131 | top = top_left * (1 - w_delta) + top_right * w_delta |
| 143 | bottom = bottom_left * (1 - w_delta) + bottom_right * w_delta | 132 | bottom = bottom_left * (1 - w_delta) + bottom_right * w_delta |
| 144 | - | 133 | + |
| 145 | return top * (1 - h_delta) + bottom * h_delta | 134 | return top * (1 - h_delta) + bottom * h_delta |
| 146 | 135 | ||
| 147 | 136 | ||
| 148 | -def compute_deform_out(x, offset, kernel_size, stride, padding, dilation, deformable_groups, modulated): | 137 | +def compute_deform_out( |
| 138 | + x, offset, kernel_size, stride, padding, dilation, deformable_groups, modulated | ||
| 139 | +): | ||
| 149 | """ | 140 | """ |
| 150 | Compute deformOut - the bilinear-interpolated input at offset positions. | 141 | Compute deformOut - the bilinear-interpolated input at offset positions. |
| 151 | Output shape: (N, inC, outH * kH, outW * kW) in NCHW. | 142 | Output shape: (N, inC, outH * kH, outW * kW) in NCHW. |
| 152 | - | 143 | + |
| 153 | Matches NPU kernel ComputeDeformableOffset in deformable_offsets.h. | 144 | Matches NPU kernel ComputeDeformableOffset in deformable_offsets.h. |
| 154 | """ | 145 | """ |
| 155 | N, inC, inH, inW = x.shape | 146 | N, inC, inH, inW = x.shape |
| 156 | kH, kW = kernel_size[0], kernel_size[1] if len(kernel_size) >= 2 else kernel_size | 147 | kH, kW = kernel_size[0], kernel_size[1] if len(kernel_size) >= 2 else kernel_size |
| 157 | stride_h, stride_w = stride[2], stride[3] | 148 | stride_h, stride_w = stride[2], stride[3] |
| 158 | - pad_h, pad_w = padding[0], padding[2] | 149 | + pad_top, pad_bottom = padding[0], padding[1] |
| 150 | + pad_left, pad_right = padding[2], padding[3] | ||
| 151 | + pad_h = pad_top | ||
| 152 | + pad_w = pad_left | ||
| 159 | dilation_h, dilation_w = dilation[2], dilation[3] | 153 | dilation_h, dilation_w = dilation[2], dilation[3] |
| 160 | - | 154 | + |
| 161 | - outH = (inH + pad_h + pad_h - (kH - 1) * dilation_h - 1) // stride_h + 1 | 155 | + outH = (inH + pad_top + pad_bottom - (kH - 1) * dilation_h - 1) // stride_h + 1 |
| 162 | - outW = (inW + pad_w + pad_w - (kW - 1) * dilation_w - 1) // stride_w + 1 | 156 | + outW = (inW + pad_left + pad_right - (kW - 1) * dilation_w - 1) // stride_w + 1 |
| 163 | - | 157 | + |
| 164 | out_shape = (N, inC, outH * kH, outW * kW) | 158 | out_shape = (N, inC, outH * kH, outW * kW) |
| 165 | deformOut = np.zeros(out_shape, dtype=x.dtype) | 159 | deformOut = np.zeros(out_shape, dtype=x.dtype) |
| 166 | - | 160 | + |
| 167 | k_per_group = inC // deformable_groups | 161 | k_per_group = inC // deformable_groups |
| 168 | - offset_channels_per_group = offset.shape[1] // deformable_groups | ||
| 169 | k_elems = kH * kW | 162 | k_elems = kH * kW |
| 170 | - | 163 | + |
| 171 | for n in range(N): | 164 | for n in range(N): |
| 172 | for out_h_pos in range(outH): | 165 | for out_h_pos in range(outH): |
| 173 | for out_w_pos in range(outW): | 166 | for out_w_pos in range(outW): |
| 174 | base_h = out_h_pos * stride_h - pad_h | 167 | base_h = out_h_pos * stride_h - pad_h |
| 175 | base_w = out_w_pos * stride_w - pad_w | 168 | base_w = out_w_pos * stride_w - pad_w |
| 176 | - | 169 | + |
| 177 | for dg in range(deformable_groups): | 170 | for dg in range(deformable_groups): |
| 178 | - offset_group_start = dg * offset_channels_per_group | ||
| 179 | - | ||
| 180 | for c in range(k_per_group): | 171 | for c in range(k_per_group): |
| 181 | channel_idx = dg * k_per_group + c | 172 | channel_idx = dg * k_per_group + c |
| 182 | - | 173 | + |
| 183 | for ki in range(kH): | 174 | for ki in range(kH): |
| 184 | for kj in range(kW): | 175 | for kj in range(kW): |
| 185 | kernel_idx = ki * kW + kj | 176 | kernel_idx = ki * kW + kj |
| 186 | - | 177 | + |
| 187 | - offset_addr = offset_group_start + kernel_idx | 178 | + w_offset_base = 0 * deformable_groups * k_elems |
| 188 | - height_offset_val = offset[n, offset_addr + k_elems, out_h_pos, out_w_pos] | 179 | + h_offset_base = 1 * deformable_groups * k_elems |
| 189 | - width_offset_val = offset[n, offset_addr, out_h_pos, out_w_pos] | 180 | + m_offset_base = 2 * deformable_groups * k_elems |
| 190 | - mask_val = offset[n, offset_addr + 2 * k_elems, out_h_pos, out_w_pos] if modulated else 1.0 | 181 | + offset_in_group = dg * k_elems + kernel_idx |
| 191 | - | 182 | + |
| 183 | + height_offset_val = offset[ | ||
| 184 | + n, | ||
| 185 | + h_offset_base + offset_in_group, | ||
| 186 | + out_h_pos, | ||
| 187 | + out_w_pos, | ||
| 188 | + ] | ||
| 189 | + width_offset_val = offset[ | ||
| 190 | + n, | ||
| 191 | + w_offset_base + offset_in_group, | ||
| 192 | + out_h_pos, | ||
| 193 | + out_w_pos, | ||
| 194 | + ] | ||
| 195 | + mask_val = ( | ||
| 196 | + offset[ | ||
| 197 | + n, | ||
| 198 | + m_offset_base + offset_in_group, | ||
| 199 | + out_h_pos, | ||
| 200 | + out_w_pos, | ||
| 201 | + ] | ||
| 202 | + if modulated | ||
| 203 | + else 1.0 | ||
| 204 | + ) | ||
| 205 | + | ||
| 192 | point_h = base_h + ki * dilation_h + height_offset_val | 206 | point_h = base_h + ki * dilation_h + height_offset_val |
| 193 | point_w = base_w + kj * dilation_w + width_offset_val | 207 | point_w = base_w + kj * dilation_w + width_offset_val |
| 194 | - | ||
| 195 | - batch_offset = n * inH * inW * inC + channel_idx | ||
| 196 | input_1d = x[n, channel_idx].flatten() | 208 | input_1d = x[n, channel_idx].flatten() |
| 197 | - | 209 | + |
| 198 | - bilinear_val = bilinear_interpolate(input_1d, point_h, point_w, channel_idx, 0, inH, inW) | 210 | + bilinear_val = bilinear_interpolate( |
| 199 | - | 211 | + input_1d, point_h, point_w, channel_idx, 0, inH, inW |
| 212 | + ) | ||
| 213 | + | ||
| 200 | output_h = out_h_pos * kH + ki | 214 | output_h = out_h_pos * kH + ki |
| 201 | output_w = out_w_pos * kW + kj | 215 | output_w = out_w_pos * kW + kj |
| 202 | - deformOut[n, channel_idx, output_h, output_w] = bilinear_val * mask_val | 216 | + deformOut[n, channel_idx, output_h, output_w] = ( |
| 203 | - | 217 | + bilinear_val * mask_val |
| 218 | + ) | ||
| 219 | + | ||
| 204 | return deformOut | 220 | return deformOut |
| 205 | 221 | ||
| 206 | 222 | ||
| @@ -218,12 +234,12 @@ def deformable_conv2d_golden( | |||
| 218 | modulated: bool = True, | 234 | modulated: bool = True, |
| 219 | out=None, | 235 | out=None, |
| 220 | deform_out_optional=None, | 236 | deform_out_optional=None, |
| 221 | - **kwargs | 237 | + **kwargs, |
| 222 | ): | 238 | ): |
| 223 | """ | 239 | """ |
| 224 | Golden for aclnnDeformableConv2d - returns BOTH outputs. | 240 | Golden for aclnnDeformableConv2d - returns BOTH outputs. |
| 225 | Parameters follow aclnnDeformableConv2dGetWorkspaceSize C header signature order. | 241 | Parameters follow aclnnDeformableConv2dGetWorkspaceSize C header signature order. |
| 226 | - | 242 | + |
| 227 | Args: | 243 | Args: |
| 228 | x: (N, C, H, W) Tensor - NCHW | 244 | x: (N, C, H, W) Tensor - NCHW |
| 229 | weight: (outC, inC/groups, kH, kW) Tensor | 245 | weight: (outC, inC/groups, kH, kW) Tensor |
| @@ -238,24 +254,34 @@ def deformable_conv2d_golden( | |||
| 238 | modulated: Whether modulated (DCNv2) | 254 | modulated: Whether modulated (DCNv2) |
| 239 | out: Pre-allocated output tensor (not used in golden) | 255 | out: Pre-allocated output tensor (not used in golden) |
| 240 | deform_out_optional: Pre-allocated deform output tensor (not used in golden) | 256 | deform_out_optional: Pre-allocated deform output tensor (not used in golden) |
| 241 | - | 257 | + |
| 242 | Returns: | 258 | Returns: |
| 243 | tuple: (out, deformOut) where | 259 | tuple: (out, deformOut) where |
| 244 | out: (N, outC, outH, outW) Tensor | 260 | out: (N, outC, outH, outW) Tensor |
| 245 | deformOut: (N, inC, outH*kH, outW*kW) Tensor | 261 | deformOut: (N, inC, outH*kH, outW*kW) Tensor |
| 246 | - | 262 | + |
| 247 | Note: Parameters are passed by position order from TTK, matching C header signature. | 263 | Note: Parameters are passed by position order from TTK, matching C header signature. |
| 248 | Default values are for documentation purpose only. | 264 | Default values are for documentation purpose only. |
| 249 | """ | 265 | """ |
| 250 | bias = bias_optional | 266 | bias = bias_optional |
| 251 | - kernelSize = kernel_size | 267 | + kernelSize = kernel_size if kernel_size is not None else kwargs.get("kernelSize") |
| 252 | - deformableGroups = deformable_groups | 268 | + deformableGroups = ( |
| 253 | - | 269 | + deformable_groups |
| 270 | + if deformable_groups != 1 | ||
| 271 | + else kwargs.get("deformableGroups", deformable_groups) | ||
| 272 | + ) | ||
| 273 | + stride = stride if stride != [1, 1, 1, 1] else kwargs.get("stride", stride) | ||
| 274 | + padding = padding if padding != [0, 0, 0, 0] else kwargs.get("padding", padding) | ||
| 275 | + dilation = ( | ||
| 276 | + dilation if dilation != [1, 1, 1, 1] else kwargs.get("dilation", dilation) | ||
| 277 | + ) | ||
| 278 | + groups = groups if groups != 1 else kwargs.get("groups", groups) | ||
| 279 | + modulated = modulated if modulated else kwargs.get("modulated", modulated) | ||
| 280 | + | ||
| 254 | input_dtypes = kwargs.get("input_dtypes", None) | 281 | input_dtypes = kwargs.get("input_dtypes", None) |
| 255 | tensor_dtypes = kwargs.get("tensor_dtypes", None) | 282 | tensor_dtypes = kwargs.get("tensor_dtypes", None) |
| 256 | output_dtypes = kwargs.get("output_dtypes", [FP32_STR, FP32_STR]) | 283 | output_dtypes = kwargs.get("output_dtypes", [FP32_STR, FP32_STR]) |
| 257 | - short_soc_version = kwargs.get("short_soc_version", None) | 284 | + |
| 258 | - | ||
| 259 | # Determine original input dtype from kwargs (not numpy array dtype) | 285 | # Determine original input dtype from kwargs (not numpy array dtype) |
| 260 | # tensor_dtypes is the original dtype from CSV, e.g., ('bfloat16', 'bfloat16', ...) | 286 | # tensor_dtypes is the original dtype from CSV, e.g., ('bfloat16', 'bfloat16', ...) |
| 261 | # input_dtypes might be None, so use tensor_dtypes as fallback | 287 | # input_dtypes might be None, so use tensor_dtypes as fallback |
| @@ -265,7 +291,7 @@ def deformable_conv2d_golden( | |||
| 265 | original_dtype_str = str(input_dtypes[0]) | 291 | original_dtype_str = str(input_dtypes[0]) |
| 266 | else: | 292 | else: |
| 267 | original_dtype_str = FP32_STR | 293 | original_dtype_str = FP32_STR |
| 268 | - | 294 | + |
| 269 | if isinstance(x, torch.Tensor): | 295 | if isinstance(x, torch.Tensor): |
| 270 | x_np = tensor_to_numpy(x) | 296 | x_np = tensor_to_numpy(x) |
| 271 | weight_np = tensor_to_numpy(weight) | 297 | weight_np = tensor_to_numpy(weight) |
| @@ -276,78 +302,90 @@ def deformable_conv2d_golden( | |||
| 276 | weight_np = np.asarray(weight) | 302 | weight_np = np.asarray(weight) |
| 277 | offset_np = np.asarray(offset) | 303 | offset_np = np.asarray(offset) |
| 278 | bias_np = tensor_to_numpy(bias) | 304 | bias_np = tensor_to_numpy(bias) |
| 279 | - | 305 | + |
| 280 | # Determine calculation precision based on original dtype | 306 | # Determine calculation precision based on original dtype |
| 281 | # float32 uses float64 for higher precision golden calculation | 307 | # float32 uses float64 for higher precision golden calculation |
| 282 | # float16/bfloat16 uses float32 (bfloat16 has ~7 bits precision, similar to float16) | 308 | # float16/bfloat16 uses float32 (bfloat16 has ~7 bits precision, similar to float16) |
| 283 | if original_dtype_str == FP32_STR: | 309 | if original_dtype_str == FP32_STR: |
| 284 | calc_dtype = np.float64 | 310 | calc_dtype = np.float64 |
| 285 | - elif original_dtype_str in ('float16', 'bfloat16'): | 311 | + elif original_dtype_str in ("float16", "bfloat16"): |
| 286 | calc_dtype = np.float32 | 312 | calc_dtype = np.float32 |
| 287 | else: | 313 | else: |
| 288 | # Fallback: use numpy array dtype to decide | 314 | # Fallback: use numpy array dtype to decide |
| 289 | x_dtype_str = x_np.dtype.name | 315 | x_dtype_str = x_np.dtype.name |
| 290 | calc_dtype = np.float64 if x_dtype_str == FP32_STR else np.float32 | 316 | calc_dtype = np.float64 if x_dtype_str == FP32_STR else np.float32 |
| 291 | - | 317 | + |
| 292 | x_np = x_np.astype(calc_dtype) | 318 | x_np = x_np.astype(calc_dtype) |
| 293 | weight_np = weight_np.astype(calc_dtype) | 319 | weight_np = weight_np.astype(calc_dtype) |
| 294 | offset_np = offset_np.astype(calc_dtype) | 320 | offset_np = offset_np.astype(calc_dtype) |
| 295 | if bias_np is not None: | 321 | if bias_np is not None: |
| 296 | bias_np = bias_np.astype(calc_dtype) | 322 | bias_np = bias_np.astype(calc_dtype) |
| 297 | - | 323 | + |
| 298 | x_torch = torch.from_numpy(x_np) | 324 | x_torch = torch.from_numpy(x_np) |
| 299 | weight_torch = torch.from_numpy(weight_np) | 325 | weight_torch = torch.from_numpy(weight_np) |
| 300 | offset_torch = torch.from_numpy(offset_np) | 326 | offset_torch = torch.from_numpy(offset_np) |
| 301 | bias_torch = torch.from_numpy(bias_np) if bias_np is not None else None | 327 | bias_torch = torch.from_numpy(bias_np) if bias_np is not None else None |
| 302 | - | 328 | + |
| 303 | stride = normalize_param(stride, 1) | 329 | stride = normalize_param(stride, 1) |
| 304 | padding = normalize_param(padding, 0) | 330 | padding = normalize_param(padding, 0) |
| 305 | dilation = normalize_param(dilation, 1) | 331 | dilation = normalize_param(dilation, 1) |
| 306 | - | 332 | + |
| 307 | if kernelSize is None: | 333 | if kernelSize is None: |
| 308 | kernelSize = [weight_torch.shape[2], weight_torch.shape[3]] | 334 | kernelSize = [weight_torch.shape[2], weight_torch.shape[3]] |
| 309 | elif isinstance(kernelSize, int): | 335 | elif isinstance(kernelSize, int): |
| 310 | kernelSize = [kernelSize, kernelSize] | 336 | kernelSize = [kernelSize, kernelSize] |
| 311 | elif isinstance(kernelSize, torch.Tensor): | 337 | elif isinstance(kernelSize, torch.Tensor): |
| 312 | - kernelSize = kernelSize.tolist() if kernelSize.numel() > 1 else [kernelSize.item(), kernelSize.item()] | 338 | + kernelSize = ( |
| 313 | - | 339 | + kernelSize.tolist() |
| 340 | + if kernelSize.numel() > 1 | ||
| 341 | + else [kernelSize.item(), kernelSize.item()] | ||
| 342 | + ) | ||
| 343 | + | ||
| 314 | # Convert groups/deformableGroups to int if they are Tensor | 344 | # Convert groups/deformableGroups to int if they are Tensor |
| 315 | if isinstance(groups, torch.Tensor): | 345 | if isinstance(groups, torch.Tensor): |
| 316 | groups = int(groups[0].item()) if groups.numel() > 1 else int(groups.item()) | 346 | groups = int(groups[0].item()) if groups.numel() > 1 else int(groups.item()) |
| 317 | if isinstance(deformableGroups, torch.Tensor): | 347 | if isinstance(deformableGroups, torch.Tensor): |
| 318 | - deformableGroups = int(deformableGroups[0].item()) if deformableGroups.numel() > 1 else int(deformableGroups.item()) | 348 | + deformableGroups = ( |
| 319 | - | 349 | + int(deformableGroups[0].item()) |
| 320 | - stride_h, stride_w = stride[2], stride[3] | 350 | + if deformableGroups.numel() > 1 |
| 321 | - pad_h, pad_w = padding[0], padding[2] | 351 | + else int(deformableGroups.item()) |
| 322 | - dilation_h, dilation_w = dilation[2], dilation[3] | 352 | + ) |
| 323 | - | 353 | + |
| 324 | deformOut_np = compute_deform_out( | 354 | deformOut_np = compute_deform_out( |
| 325 | x_torch.numpy(), | 355 | x_torch.numpy(), |
| 326 | offset_torch.numpy(), | 356 | offset_torch.numpy(), |
| 327 | - kernelSize, stride, padding, dilation, | 357 | + kernelSize, |
| 328 | - deformableGroups, modulated | 358 | + stride, |
| 359 | + padding, | ||
| 360 | + dilation, | ||
| 361 | + deformableGroups, | ||
| 362 | + modulated, | ||
| 329 | ) | 363 | ) |
| 330 | deformOut_torch = torch.from_numpy(deformOut_np) | 364 | deformOut_torch = torch.from_numpy(deformOut_np) |
| 331 | - | 365 | + |
| 332 | out = torch.nn.functional.conv2d( | 366 | out = torch.nn.functional.conv2d( |
| 333 | - deformOut_torch, weight_torch, bias_torch, | 367 | + deformOut_torch, |
| 368 | + weight_torch, | ||
| 369 | + bias_torch, | ||
| 334 | stride=kernelSize, | 370 | stride=kernelSize, |
| 335 | padding=0, | 371 | padding=0, |
| 336 | dilation=1, | 372 | dilation=1, |
| 337 | - groups=groups | 373 | + groups=groups, |
| 338 | ) | 374 | ) |
| 339 | - | 375 | + |
| 340 | out_dtype = output_dtypes[0] if output_dtypes else FP32_STR | 376 | out_dtype = output_dtypes[0] if output_dtypes else FP32_STR |
| 341 | deform_out_dtype = output_dtypes[1] if len(output_dtypes) > 1 else FP32_STR | 377 | deform_out_dtype = output_dtypes[1] if len(output_dtypes) > 1 else FP32_STR |
| 342 | - | 378 | + |
| 343 | # If output_dtypes not provided, infer from tensor_dtypes (output tensors index 4, 5) | 379 | # If output_dtypes not provided, infer from tensor_dtypes (output tensors index 4, 5) |
| 344 | if output_dtypes is None or output_dtypes == [FP32_STR, FP32_STR]: | 380 | if output_dtypes is None or output_dtypes == [FP32_STR, FP32_STR]: |
| 345 | if tensor_dtypes and len(tensor_dtypes) >= 6: | 381 | if tensor_dtypes and len(tensor_dtypes) >= 6: |
| 346 | # tensor_dtypes format: (input, weight, offset, bias, out_placeholder, deformOut_placeholder) | 382 | # tensor_dtypes format: (input, weight, offset, bias, out_placeholder, deformOut_placeholder) |
| 347 | out_dtype = str(tensor_dtypes[4]) if tensor_dtypes[4] else FP32_STR | 383 | out_dtype = str(tensor_dtypes[4]) if tensor_dtypes[4] else FP32_STR |
| 348 | deform_out_dtype = str(tensor_dtypes[5]) if tensor_dtypes[5] else FP32_STR | 384 | deform_out_dtype = str(tensor_dtypes[5]) if tensor_dtypes[5] else FP32_STR |
| 349 | - | 385 | + |
| 350 | out_result = convert_output_dtype(out.detach().numpy(), out_dtype) | 386 | out_result = convert_output_dtype(out.detach().numpy(), out_dtype) |
| 351 | - deformOut_result = convert_output_dtype(deformOut_torch.detach().numpy(), deform_out_dtype) | 387 | + deformOut_result = convert_output_dtype( |
| 352 | - | 388 | + deformOut_torch.detach().numpy(), deform_out_dtype |
| 353 | - return out_result, deformOut_result | 389 | + ) |
| 390 | + | ||
| 391 | + return out_result, deformOut_result | ||
| @@ -2,32 +2,64 @@ | |||
| 2 | # -*- coding: UTF-8 -*- | 2 | # -*- coding: UTF-8 -*- |
| 3 | # ---------------------------------------------------------------------------- | 3 | # ---------------------------------------------------------------------------- |
| 4 | # Copyright (c) 2025-2026 Huawei Technologies Co., Ltd. | 4 | # Copyright (c) 2025-2026 Huawei Technologies Co., Ltd. |
| 5 | -# This program is free software, you can redistribute it and/or modify it under terms and conditions of | 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"). | 6 | # CANN Open Software License Agreement Version 2.0 (the "License"). |
| 7 | -# Please refer to License for details. You may not use this file except in compliance with 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 FIT 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 | 12 | ||
| 13 | import numpy as np | 13 | import numpy as np |
| 14 | 14 | ||
| 15 | __input__ = { | 15 | __input__ = { |
| 16 | - "aclnn": { | 16 | + "aclnn": {"aclnnDeformableConv2d": "deformable_conv2d_input"}, |
| 17 | - "aclnnDeformableConv2d": "deformable_conv2d_input" | 17 | + "e2e": {"torch_npu.npu_deformable_conv2d": "deformable_conv2d_input"}, |
| 18 | - } | ||
| 19 | } | 18 | } |
| 20 | 19 | ||
| 21 | 20 | ||
| 22 | -def deformable_conv2d_input(x, weight, offset, bias=None, | 21 | +def _safe_uniform(shape, dtype, low=-1, high=1): |
| 23 | - *, kernel_size, stride, padding, dilation, | 22 | + if low is None: |
| 24 | - groups=1, deformable_groups=1, modulated=True, | 23 | + low = -1 |
| 25 | - **kwargs): | 24 | + if high is None: |
| 26 | - ''' | 25 | + high = 1 |
| 26 | + import torch | ||
| 27 | + | ||
| 28 | + if isinstance(dtype, torch.dtype): | ||
| 29 | + dtype_map = { | ||
| 30 | + torch.float16: np.float16, | ||
| 31 | + torch.float32: np.float32, | ||
| 32 | + torch.bfloat16: np.float32, | ||
| 33 | + torch.int64: np.int64, | ||
| 34 | + torch.int32: np.int32, | ||
| 35 | + torch.int8: np.int8, | ||
| 36 | + } | ||
| 37 | + dtype = dtype_map.get(dtype, np.float32) | ||
| 38 | + return np.random.uniform(low, high, shape).astype(dtype) | ||
| 39 | + | ||
| 40 | + | ||
| 41 | +def deformable_conv2d_input( | ||
| 42 | + x, | ||
| 43 | + weight, | ||
| 44 | + offset, | ||
| 45 | + bias=None, | ||
| 46 | + kernel_size=None, | ||
| 47 | + stride=None, | ||
| 48 | + padding=None, | ||
| 49 | + dilation=None, | ||
| 50 | + groups=1, | ||
| 51 | + deformable_groups=1, | ||
| 52 | + modulated=True, | ||
| 53 | + out=None, | ||
| 54 | + deform_out=None, | ||
| 55 | + **kwargs, | ||
| 56 | +): | ||
| 57 | + """ | ||
| 27 | Input function for deformable_conv2d operator. | 58 | Input function for deformable_conv2d operator. |
| 28 | All parameters follow @deformable_conv2d_def.cpp without outputs. | 59 | All parameters follow @deformable_conv2d_def.cpp without outputs. |
| 29 | All input Tensors are numpy.ndarray. | 60 | All input Tensors are numpy.ndarray. |
| 30 | 61 | ||
| 62 | + | ||
| 31 | Args: | 63 | Args: |
| 32 | x: Input feature map tensor, shape (N, C, H, W) in NCHW format | 64 | x: Input feature map tensor, shape (N, C, H, W) in NCHW format |
| 33 | weight: Convolution weight tensor, shape (outC, inC/groups, kH, kW) | 65 | weight: Convolution weight tensor, shape (outC, inC/groups, kH, kW) |
| @@ -47,30 +79,57 @@ def deformable_conv2d_input(x, weight, offset, bias=None, | |||
| 47 | - input_ori_formats: List[str] - original input formats | 79 | - input_ori_formats: List[str] - original input formats |
| 48 | - input_ranges: List[tuple] - input data ranges | 80 | - input_ranges: List[tuple] - input data ranges |
| 49 | 81 | ||
| 82 | + | ||
| 50 | Returns: | 83 | Returns: |
| 51 | List of input tensors: [x, weight, offset, bias] | 84 | List of input tensors: [x, weight, offset, bias] |
| 52 | - ''' | 85 | + """ |
| 53 | # Get input ranges from kwargs | 86 | # Get input ranges from kwargs |
| 54 | - input_ranges = kwargs.get('input_ranges', []) | 87 | + input_ranges = kwargs.get("input_ranges", []) |
| 55 | - | 88 | + |
| 56 | - # Apply input ranges if available | 89 | + if x is not None: |
| 57 | - if input_ranges and len(input_ranges) >= 3: | 90 | + r = ( |
| 58 | - x_range = input_ranges[0] if input_ranges[0] else (-10, 10) | 91 | + input_ranges[0] |
| 59 | - weight_range = input_ranges[1] if input_ranges[1] else (-1, 1) | 92 | + if input_ranges and len(input_ranges) > 0 and input_ranges[0] |
| 60 | - offset_range = input_ranges[2] if input_ranges[2] else (-1, 1) | 93 | + else (-10, 10) |
| 61 | - | 94 | + ) |
| 62 | - low, high = x_range | 95 | + x = _safe_uniform(x.shape, x.dtype, r[0], r[1]) |
| 63 | - x = np.random.uniform(low, high, x.shape).astype(x.dtype) | 96 | + |
| 64 | - | 97 | + if weight is not None: |
| 65 | - low, high = weight_range | 98 | + r = ( |
| 66 | - weight = np.random.uniform(low, high, weight.shape).astype(weight.dtype) | 99 | + input_ranges[1] |
| 67 | - | 100 | + if input_ranges and len(input_ranges) > 1 and input_ranges[1] |
| 68 | - low, high = offset_range | 101 | + else (-1, 1) |
| 69 | - offset = np.random.uniform(low, high, offset.shape).astype(offset.dtype) | 102 | + ) |
| 70 | - | 103 | + weight = _safe_uniform(weight.shape, weight.dtype, r[0], r[1]) |
| 71 | - if bias is not None and len(input_ranges) > 3: | 104 | + |
| 72 | - bias_range = input_ranges[3] if input_ranges[3] else (-1, 1) | 105 | + if offset is not None: |
| 73 | - low, high = bias_range | 106 | + r = ( |
| 74 | - bias = np.random.uniform(low, high, bias.shape).astype(bias.dtype) | 107 | + input_ranges[2] |
| 75 | - | 108 | + if input_ranges and len(input_ranges) > 2 and input_ranges[2] |
| 76 | - return [x, weight, offset, bias] | 109 | + else (-1, 1) |
| 110 | + ) | ||
| 111 | + offset = _safe_uniform(offset.shape, offset.dtype, r[0], r[1]) | ||
| 112 | + | ||
| 113 | + if bias is not None: | ||
| 114 | + r = ( | ||
| 115 | + input_ranges[3] | ||
| 116 | + if input_ranges and len(input_ranges) > 3 and input_ranges[3] | ||
| 117 | + else (-1, 1) | ||
| 118 | + ) | ||
| 119 | + bias = _safe_uniform(bias.shape, bias.dtype, r[0], r[1]) | ||
| 120 | + | ||
| 121 | + return [ | ||
| 122 | + x, | ||
| 123 | + weight, | ||
| 124 | + offset, | ||
| 125 | + bias, | ||
| 126 | + kernel_size, | ||
| 127 | + stride, | ||
| 128 | + padding, | ||
| 129 | + dilation, | ||
| 130 | + groups, | ||
| 131 | + deformable_groups, | ||
| 132 | + modulated, | ||
| 133 | + out, | ||
| 134 | + deform_out, | ||
| 135 | + ] | ||