def resize2d_python( data, scale, layout="NCHW", method="nearest_neighbor", coordinate_transformation_mode="align_corners", ): """Python version of scaling using nearest neighbour""" if layout == "NHWC": data = data.transpose([0, 3, 1, 2]) elif nchw_pack_layout(layout): ishape = data.shape transposed = data.transpose([0, 4, 1, 5, 2, 3]) tshape = transposed.shape data = transposed.reshape( tshape[0] * tshape[1], tshape[2] * tshape[3], tshape[4], tshape[5] ) data = np.expand_dims(data, axis=2) output_np = resize3d_ncdhw(data, (1,) + scale, method, coordinate_transformation_mode) output_np = np.squeeze(output_np, axis=2) if layout == "NHWC": output_np = output_np.transpose([0, 2, 3, 1]) elif nchw_pack_layout(layout): output_np = output_np.reshape(tshape[0:4] + output_np.shape[2:]) output_np = output_np.transpose([0, 2, 4, 5, 1, 3]) return output_np
def _img_scale(b, m, i, n): for j in range(new_h): for k in range(new_w): if coordinate_transformation_mode == "half_pixel": in_y = (j + 0.5) * height_scale - 0.5 else: in_y = j * height_scale y0 = int(math.floor(in_y)) y1 = max(min(y0 + 1, h - 1), 0) y0 = max(y0, 0) y_lerp = in_y - math.floor(in_y) if coordinate_transformation_mode == "half_pixel": in_x = (k + 0.5) * width_scale - 0.5 else: in_x = k * width_scale x0 = int(math.floor(in_x)) x1 = max(min(x0 + 1, w - 1), 0) x0 = max(x0, 0) x_lerp = in_x - math.floor(in_x) if layout == "NHWC": A = image[b][y0][x0][i] B = image[b][y0][x1][i] C = image[b][y1][x0][i] D = image[b][y1][x1][i] elif nchw_pack_layout(layout): A = image[b][i][y0][x0][m][n] B = image[b][i][y0][x1][m][n] C = image[b][i][y1][x0][m][n] D = image[b][i][y1][x1][m][n] else: A = image[b][i][y0][x0] B = image[b][i][y0][x1] C = image[b][i][y1][x0] D = image[b][i][y1][x1] top = _lerp(A, B, x_lerp) bottom = _lerp(C, D, x_lerp) pixel = np.float32(_lerp(top, bottom, y_lerp)) if layout == "NHWC": scaled_image[b][j][k][i] = pixel elif nchw_pack_layout(layout): scaled_image[b][i][j][k][m][n] = pixel else: scaled_image[b][i][j][k] = pixel
def resize_shape_func(attrs, inputs, _): """ Shape function for dyn.image.resize op. """ layout = attrs.layout if nchw_pack_layout(layout) or nchw_xc_layout(layout): out = [ _resize_shape_func(inputs[0].shape, inputs[1], convert(len(inputs[0].shape)), convert(2), convert(3)) ] else: height_axis = width_axis = 1 for i, letter in enumerate(layout): if letter == "H": height_axis = i if letter == "W": width_axis = i out = [ _resize_shape_func( inputs[0].shape, inputs[1], convert(len(inputs[0].shape)), convert(height_axis), convert(width_axis), ) ] return out
def get_2d_pixel(data, layout, image_height, image_width, n, c, y, x, cc, ib, ic): """Get 2d pixel""" y = tvm.te.max(tvm.te.min(y, image_height - 1), 0) x = tvm.te.max(tvm.te.min(x, image_width - 1), 0) if layout == "NHWC": return data(n, y, x, c).astype("float") if layout == "NCHW": return data(n, c, y, x).astype("float") if nchw_pack_layout(layout): return data(n, c, y, x, ib, ic).astype("float") # else must be NCHWxc assert nchw_xc_layout(layout) return data(n, c, y, x, cc).astype("float")
def upsampling_python(data, scale, layout="NCHW"): """ Python version of scaling using nearest neighbour """ ishape = data.shape if layout == "NCHW": oshape = ( ishape[0], ishape[1], int(round(ishape[2] * scale[0])), int(round(ishape[3] * scale[1])), ) output_np = np.zeros(oshape, dtype=data.dtype) for b in range(oshape[0]): for c in range(oshape[1]): output_np[b, c, :, :] = upsample_nearest(data[b, c, :, :], scale) return output_np # NCHWinic if nchw_pack_layout(layout): oshape = ( ishape[0], ishape[1], int(round(ishape[2] * scale[0])), int(round(ishape[3] * scale[1])), ishape[4], ishape[5], ) output_np = np.zeros(oshape, dtype=data.dtype) for b in range(oshape[0]): for ib in range(oshape[4]): for c in range(oshape[1]): for ic in range(oshape[5]): output_np[b, c, :, :, ib, ic] = upsample_nearest( data[b, c, :, :, ib, ic], scale) return output_np if layout == "NHWC": oshape = ( ishape[0], int(round(ishape[1] * scale[0])), int(round(ishape[2] * scale[1])), ishape[3], ) output_np = np.zeros(oshape, dtype=data.dtype) for b in range(oshape[0]): for c in range(oshape[3]): output_np[b, :, :, c] = upsample_nearest(data[b, :, :, c], scale) return output_np raise ValueError("not support this layout {} yet".format(layout))
def get_2d_indices(indices, layout="NCHW"): """Get 2d indices""" (cc, inum, ic) = (0, 0, 0) if layout == "NHWC": n, y, x, c = indices cc = None elif layout == "NCHW": n, c, y, x = indices cc = None elif nchw_pack_layout(layout): n, c, y, x, inum, ic = indices else: # else must be NCHWxc assert nchw_xc_layout(layout) n, c, y, x, cc = indices return n, c, y, x, cc, inum, ic
def resize2d( data, roi, size, layout="NCHW", method="linear", coordinate_transformation_mode="half_pixel", rounding_method="", bicubic_alpha=-0.5, bicubic_exclude=0, extrapolation_value=0.0, out_dtype=None, output_shape=None, ): """Perform resize operation on the data. Parameters ---------- data : tvm.te.Tensor inputs is a 4-D tensor with shape [batch, channel, in_height, in_width] or [batch, in_height, in_width, channel] roi: Tuple of Float or Expr The region of interest for cropping the input image. Expected to be of size 4, and format [start_h, start_w, end_h, end_w]. Only used if coordinate_transformation_mode is tf_crop_and_resize. size: Tuple Output resolution scale to layout: string, optional "NCHW", "NHWC", or "NCHWc". coordinate_transformation_mode: string, optional Describes how to transform the coordinate in the resized tensor to the coordinate in the original tensor. Refer to the ONNX Resize operator specification for details. Available options are "half_pixel", "align_corners" and "asymmetric". method: string, optional method of interpolation ("nearest", "linear", "bicubic") coordinate_transformation_mode : string, optional Describes how to transform the coordinate in the resized tensor to the coordinate in the original tensor. [half_pixel, align_corners, asymmetric, pytorch_half_pixel, tf_half_pixel_for_nn, and tf_crop_and_resize]. rounding_method: Method for rounding coordinate locations bicubic_alpha: float, optional Bicubic spline coefficient bicubic_exclude: bool, optional: Exclude values outside the image fdor bicubic interpolation extrapolation_value: float, optional Value used for extrapolation, when applicable. out_dtype: string, optional Type to return. If left None will be same as input type. output_shape: tvm.tir.container.Array, optional Shape to return. If left None will be inferred (If shape is determined dynamically, pass out_dtype.shape as output_shape) Returns ------- output : tvm.te.Tensor 4-D with shape [batch, channel, in_height*scale, in_width*scale] or [batch, in_height*scale, in_width*scale, channel] or 5-D with shape [batch, channel-major, in_height*scale, in_width*scale, channel-minor] """ method = method.lower() if layout == "NHWC": in_n, in_h, in_w, in_c = data.shape if output_shape is None: output_shape = [in_n, size[0], size[1], in_c] elif layout == "NCHW": in_n, in_c, in_h, in_w = data.shape if output_shape is None: output_shape = [in_n, in_c, size[0], size[1]] elif nchw_pack_layout(layout): # for NCHWinic in_n, in_c, in_h, in_w, in_inum, in_ic = data.shape if output_shape is None: output_shape = [in_n, in_c, size[0], size[1], in_inum, in_ic] elif nchw_xc_layout(layout): # for NCHWxc in_n, in_c, in_h, in_w, in_cc = data.shape if output_shape is None: output_shape = [in_n, in_c, size[0], size[1], in_cc] else: raise ValueError("%s layout is not supported." % layout) if isinstance(size, tuple): size = list(size) for i in range(2): if isinstance(size[i], int): size[i] = tvm.tir.IntImm("int32", size[i]) def compute_func(*indices): return _resize_2d( indices, data, roi, in_h, in_w, size[0], size[1], method=method, layout=layout, coordinate_transformation_mode=coordinate_transformation_mode, rounding_method=rounding_method, alpha=bicubic_alpha, exclude_outside=bicubic_exclude, extrapolation_value=extrapolation_value, out_dtype=out_dtype, ) return te.compute(output_shape, compute_func, name="resize", tag=tag.INJECTIVE)
def verify_upsampling( batch, in_channel, in_height, in_width, scale_h, scale_w, layout="NCHW", method="nearest_neighbor", in_batch_block=0, in_channel_block=0, ): if layout == "NCHW": A = te.placeholder((batch, in_channel, in_height, in_width), name="A") dtype = A.dtype out_shape = ( batch, in_channel, int(round(in_height * scale_h)), int(round(in_width * scale_w)), ) a_np = np.random.uniform(size=(batch, in_channel, in_height, in_width)).astype(dtype) elif nchw_pack_layout(layout): A = te.placeholder((batch, in_channel, in_height, in_width, in_batch_block, in_channel_block), name="A") dtype = A.dtype out_shape = ( batch, in_channel, int(round(in_height * scale_h)), int(round(in_width * scale_w)), in_batch_block, in_channel_block, ) a_np = np.random.uniform(size=(batch, in_channel, in_height, in_width, in_batch_block, in_channel_block)).astype(dtype) elif layout == "NHWC": A = te.placeholder((batch, in_height, in_width, in_channel), name="A") dtype = A.dtype out_shape = ( batch, int(round(in_height * scale_h)), int(round(in_width * scale_w)), in_channel, ) a_np = np.random.uniform(size=(batch, in_height, in_width, in_channel)).astype(dtype) else: raise NotImplementedError("Layout not supported {} ".format(layout)) B = topi.nn.upsampling(A, scale_h, scale_w, layout=layout, method=method, align_corners=False) b_np = tvm.topi.testing.resize2d_python( a_np, (scale_h, scale_w), layout, method[2:] if method[0:2] == "bi" else method, "asymmetric", ) def check_target(target, dev): print("Running on target: %s" % target) with tvm.target.Target(target): s = tvm.topi.testing.get_injective_schedule(target)(B) a = tvm.nd.array(a_np, dev) b = tvm.nd.array(np.zeros(out_shape, dtype=dtype), dev) f = tvm.build(s, [A, B], target) f(a, b) tvm.testing.assert_allclose(b.numpy(), b_np, rtol=1e-5, atol=1e-5) for target, dev in tvm.testing.enabled_targets(): check_target(target, dev)
def bilinear_resize_python(image, out_size, layout, coordinate_transformation_mode="align_corners"): """Bilinear scaling using python""" (new_h, new_w) = out_size (ib, ic) = (1, 1) if layout == "NHWC": (batch, h, w, channel) = image.shape scaled_image = np.ones((batch, new_h, new_w, channel)) # NCHWinic elif nchw_pack_layout(layout): (batch, channel, h, w, ib, ic) = image.shape scaled_image = np.ones((batch, channel, new_h, new_w, ib, ic)) else: (batch, channel, h, w) = image.shape scaled_image = np.ones((batch, channel, new_h, new_w)) if coordinate_transformation_mode == "align_corners": height_scale = np.float32(h - 1) / np.float32(out_size[0] - 1) width_scale = np.float32(w - 1) / np.float32(out_size[1] - 1) else: height_scale = np.float32(h) / np.float32(out_size[0]) width_scale = np.float32(w) / np.float32(out_size[1]) def _lerp(A, B, t): return A * (1.0 - t) + B * t def _img_scale(b, m, i, n): for j in range(new_h): for k in range(new_w): if coordinate_transformation_mode == "half_pixel": in_y = (j + 0.5) * height_scale - 0.5 else: in_y = j * height_scale y0 = int(math.floor(in_y)) y1 = max(min(y0 + 1, h - 1), 0) y0 = max(y0, 0) y_lerp = in_y - math.floor(in_y) if coordinate_transformation_mode == "half_pixel": in_x = (k + 0.5) * width_scale - 0.5 else: in_x = k * width_scale x0 = int(math.floor(in_x)) x1 = max(min(x0 + 1, w - 1), 0) x0 = max(x0, 0) x_lerp = in_x - math.floor(in_x) if layout == "NHWC": A = image[b][y0][x0][i] B = image[b][y0][x1][i] C = image[b][y1][x0][i] D = image[b][y1][x1][i] elif nchw_pack_layout(layout): A = image[b][i][y0][x0][m][n] B = image[b][i][y0][x1][m][n] C = image[b][i][y1][x0][m][n] D = image[b][i][y1][x1][m][n] else: A = image[b][i][y0][x0] B = image[b][i][y0][x1] C = image[b][i][y1][x0] D = image[b][i][y1][x1] top = _lerp(A, B, x_lerp) bottom = _lerp(C, D, x_lerp) pixel = np.float32(_lerp(top, bottom, y_lerp)) if layout == "NHWC": scaled_image[b][j][k][i] = pixel elif nchw_pack_layout(layout): scaled_image[b][i][j][k][m][n] = pixel else: scaled_image[b][i][j][k] = pixel for b in range(batch): for m in range(ib): for i in range(channel): for n in range(ic): _img_scale(b, m, i, n) return scaled_image
def resize( data, size, layout="NCHW", method="bilinear", coordinate_transformation_mode="half_pixel", rounding_method="", bicubic_alpha=-0.5, bicubic_exclude=0, out_dtype=None, output_shape=None, ): """Perform resize operation on the data. Parameters ---------- data : tvm.te.Tensor inputs is a 4-D tensor with shape [batch, channel, in_height, in_width] or [batch, in_height, in_width, channel] size: Tuple Output resolution scale to layout: string, optional "NCHW", "NHWC", or "NCHWc". coordinate_transformation_mode: string, optional Describes how to transform the coordinate in the resized tensor to the coordinate in the original tensor. Refer to the ONNX Resize operator specification for details. Available options are "half_pixel", "align_corners" and "asymmetric". method: {"bilinear", "nearest_neighbor", "bicubic"} Method to be used for resizing. out_dtype: string, optional Type to return. If left None will be same as input type. output_shape: tvm.tir.container.Array, optional Shape to return. If left None will be inferred (If shape is determined dynamically, pass out_dtype.shape as output_shape) Returns ------- output : tvm.te.Tensor 4-D with shape [batch, channel, in_height*scale, in_width*scale] or [batch, in_height*scale, in_width*scale, channel] or 5-D with shape [batch, channel-major, in_height*scale, in_width*scale, channel-minor] """ method = method.lower() if layout == "NHWC": in_n, in_h, in_w, in_c = data.shape if output_shape is None: output_shape = [in_n, size[0], size[1], in_c] elif layout == "NCHW": in_n, in_c, in_h, in_w = data.shape if output_shape is None: output_shape = [in_n, in_c, size[0], size[1]] elif nchw_pack_layout(layout): # for NCHWinic in_n, in_c, in_h, in_w, in_inum, in_ic = data.shape if output_shape is None: output_shape = [in_n, in_c, size[0], size[1], in_inum, in_ic] elif nchw_xc_layout(layout): # for NCHWxc in_n, in_c, in_h, in_w, in_cc = data.shape if output_shape is None: output_shape = [in_n, in_c, size[0], size[1], in_cc] else: raise ValueError("%s layout is not supported." % layout) if isinstance(size, tuple): size = list(size) for i in range(2): if isinstance(size[i], int): size[i] = tvm.tir.IntImm("int32", size[i]) def _nearest_neighbor(*indices): return resize_nearest_neighbor( indices, data, in_h, in_w, size[0], size[1], layout=layout, coordinate_transformation_mode=coordinate_transformation_mode, rounding_method=rounding_method, out_dtype=out_dtype, ) def _bilinear(*indices): return resize_bilinear( indices, data, in_h, in_w, size[0], size[1], layout=layout, coordinate_transformation_mode=coordinate_transformation_mode, out_dtype=out_dtype, ) def _bicubic(*indices): return resize_bicubic( indices, data, in_h, in_w, size[0], size[1], layout=layout, coordinate_transformation_mode=coordinate_transformation_mode, out_dtype=out_dtype, alpha=bicubic_alpha, exclude_outside=bicubic_exclude, ) # Determine which interpolation method to use then run it. if method == "nearest_neighbor": compute_func = _nearest_neighbor elif method == "bilinear": compute_func = _bilinear elif method == "bicubic": compute_func = _bicubic else: raise ValueError("%s method is not supported." % method) return te.compute(output_shape, compute_func, name="resize", tag=tag.INJECTIVE)