From 8b1fb4d592d0b0eb889087ea0d376764c3d4dc3d Mon Sep 17 00:00:00 2001 From: Xingyu Zhou Date: Mon, 28 Oct 2019 11:34:56 -0700 Subject: [PATCH] [Relay][Op] Enhance Upsample Operator to support float scales (#4206) * :add scale2 for upsample * update unit test for upsampling * support latest upsample op for multiple frontend * fix lint * fix lint * fix lint * fix lint * update scale description and rebase --- include/tvm/expr_operator.h | 3 +++ include/tvm/relay/attrs/nn.h | 9 ++++--- nnvm/python/nnvm/to_relay.py | 3 ++- python/tvm/relay/frontend/caffe2.py | 2 +- python/tvm/relay/frontend/coreml.py | 3 ++- python/tvm/relay/frontend/darknet.py | 5 ++-- python/tvm/relay/frontend/keras.py | 8 +++--- python/tvm/relay/frontend/nnvm_common.py | 2 +- python/tvm/relay/frontend/onnx.py | 5 ++-- python/tvm/relay/op/nn/_nn.py | 5 ++-- python/tvm/relay/op/nn/nn.py | 14 ++++++---- src/relay/op/nn/upsampling.cc | 11 ++++---- tests/python/relay/test_op_level2.py | 25 +++++++++++------- tests/python/relay/test_pass_alter_op_layout.py | 4 +-- tests/python/relay/test_pass_fuse_ops.py | 8 +++--- topi/python/topi/nn/upsampling.py | 20 +++++++++----- topi/python/topi/testing/upsampling_python.py | 10 ++++--- topi/tests/python/test_topi_upsampling.py | 35 ++++++++++++++----------- 18 files changed, 104 insertions(+), 68 deletions(-) diff --git a/include/tvm/expr_operator.h b/include/tvm/expr_operator.h index 007ae58..adc77a8 100644 --- a/include/tvm/expr_operator.h +++ b/include/tvm/expr_operator.h @@ -700,6 +700,9 @@ inline Expr make_zero(Type t) { } \ inline Expr Name(const Expr& a, int b) { \ return Name(a, make_const(a.type(), b)); \ + } \ + inline Expr Name(const Expr& a, double b) { \ + return Name(a, make_const(Float(64), b)); \ } #define TVM_DEFINE_LOGICAL_OP_CONST_VAL_OVERLOAD(Name) \ diff --git a/include/tvm/relay/attrs/nn.h b/include/tvm/relay/attrs/nn.h index 793b43a..f8e5af9 100644 --- a/include/tvm/relay/attrs/nn.h +++ b/include/tvm/relay/attrs/nn.h @@ -387,14 +387,17 @@ struct FIFOBufferAttrs : public tvm::AttrsNode { /*! \brief Attributes for upsampling operator */ struct UpSamplingAttrs : public tvm::AttrsNode { - int scale; + double scale_h; + double scale_w; std::string layout; std::string method; bool align_corners; TVM_DECLARE_ATTRS(UpSamplingAttrs, "relay.attrs.UpSamplingAttrs") { - TVM_ATTR_FIELD(scale) - .describe("Should be true to preserve the values at the corner pixels"); + TVM_ATTR_FIELD(scale_h) + .describe("The upsampling factor for height"); + TVM_ATTR_FIELD(scale_w) + .describe("The upsampling factor for width"); TVM_ATTR_FIELD(layout).set_default("NCHW") .describe("Dimension ordering of input data. Can be 'NCHW', 'NHWC', etc." "'N', 'C', 'H', 'W' stands for batch, channel, height, and width" diff --git a/nnvm/python/nnvm/to_relay.py b/nnvm/python/nnvm/to_relay.py index 26dba0f..94a736d 100644 --- a/nnvm/python/nnvm/to_relay.py +++ b/nnvm/python/nnvm/to_relay.py @@ -219,7 +219,8 @@ def _upsampling(children, attrs, odtype='float32'): method = attrs.get_str('method', 'NEAREST_NEIGHBOR') return op.nn.upsampling( children[0], - scale=scale, + scale_h=scale, + scale_w=scale, layout=layout, method=method) diff --git a/python/tvm/relay/frontend/caffe2.py b/python/tvm/relay/frontend/caffe2.py index ac16a6b..456d782 100644 --- a/python/tvm/relay/frontend/caffe2.py +++ b/python/tvm/relay/frontend/caffe2.py @@ -280,7 +280,7 @@ class ResizeNearest(Caffe2OpConverter): assert width_scale == height_scale return _op.nn.upsampling( - inputs[0], scale=int(width_scale), method="NEAREST_NEIGHBOR") + inputs[0], scale_h=int(width_scale), scale_w=int(width_scale), method="NEAREST_NEIGHBOR") class Sum(Caffe2OpConverter): diff --git a/python/tvm/relay/frontend/coreml.py b/python/tvm/relay/frontend/coreml.py index 8b158ca..a24043d 100644 --- a/python/tvm/relay/frontend/coreml.py +++ b/python/tvm/relay/frontend/coreml.py @@ -313,7 +313,8 @@ def _UpsampleLayerParams(op, inexpr, etab): raise tvm.error.OpAttributeUnimplemented( 'Upsample height and width must be equal.') interpolationMode = 'nearest_neighbor' if op.mode == 0 else 'bilinear' - return _op.nn.upsampling(inexpr, scale=op.scalingFactor[0], method=interpolationMode) + return _op.nn.upsampling(inexpr, scale_h=op.scalingFactor[0], + scale_w=op.scalingFactor[1], method=interpolationMode) def _L2NormalizeLayerParams(op, inexpr, etab): diff --git a/python/tvm/relay/frontend/darknet.py b/python/tvm/relay/frontend/darknet.py index 982bcea..a2a72ea 100644 --- a/python/tvm/relay/frontend/darknet.py +++ b/python/tvm/relay/frontend/darknet.py @@ -129,7 +129,7 @@ def _darknet_shortcut(inputs, params, attrs, prefix): if input_0_size > input_1_size: scale = int(input_0_size/input_1_size) - input_1 = get_relay_op('upsampling')(input_1, scale=scale) + input_1 = get_relay_op('upsampling')(input_1, scale_h=scale, scale_w=scale) elif input_0_size < input_1_size: stride = int(input_1_size/input_0_size) @@ -196,7 +196,8 @@ def _darknet_reshape(inputs, params, attrs, prefix): def _darknet_upsampling(inputs, params, attrs, prefix): """Process the upsampling operation.""" new_attrs = {} - new_attrs['scale'] = attrs.get('scale', 1) + new_attrs['scale_h'] = attrs.get('scale', 1) + new_attrs['scale_w'] = attrs.get('scale', 1) return get_relay_op('upsampling')(*inputs, **new_attrs) def _darknet_l2normalize(inputs, params, attrs, prefix): diff --git a/python/tvm/relay/frontend/keras.py b/python/tvm/relay/frontend/keras.py index cc092f3..15f7440 100644 --- a/python/tvm/relay/frontend/keras.py +++ b/python/tvm/relay/frontend/keras.py @@ -398,13 +398,14 @@ def _convert_upsample(inexpr, keras_layer, _): params = {} if upsample_type == 'UpSampling1D': h = keras_layer.size - params['scale'] = h + params['scale_h'] = h elif upsample_type == 'UpSampling2D': h, w = keras_layer.size if h != w: raise tvm.error.OpAttributeInvalid( 'Height must equal width for operator Upsample.') - params['scale'] = h + params['scale_h'] = h + params['scale_w'] = h if hasattr(keras_layer, 'interpolation'): interpolation = keras_layer.interpolation @@ -418,7 +419,8 @@ def _convert_upsample(inexpr, keras_layer, _): if h != w or w != d: raise tvm.error.OpAttributeInvalid( 'Height, width, and depth must all be equal for operator Upsample.') - params['scale'] = h + params['scale_h'] = h + params['scale_w'] = h else: raise tvm.error.OpNotImplemented( 'Operator {} is not supported for frontend Keras.'.format(upsample_type)) diff --git a/python/tvm/relay/frontend/nnvm_common.py b/python/tvm/relay/frontend/nnvm_common.py index ef2b81c..5f24fa0 100644 --- a/python/tvm/relay/frontend/nnvm_common.py +++ b/python/tvm/relay/frontend/nnvm_common.py @@ -112,7 +112,7 @@ def _transpose(inputs, attrs): def _upsampling(inputs, attrs): scale = attrs.get_int("scale") - return _op.nn.upsampling(inputs[0], scale=scale) + return _op.nn.upsampling(inputs[0], scale_h=scale, scale_w=scale) def _elemwise_sum(inputs, _, _dtype='float32'): diff --git a/python/tvm/relay/frontend/onnx.py b/python/tvm/relay/frontend/onnx.py index b007b41..1d74a01 100644 --- a/python/tvm/relay/frontend/onnx.py +++ b/python/tvm/relay/frontend/onnx.py @@ -581,7 +581,7 @@ class Upsample(OnnxOpConverter): assert len(inputs) == 2, "Upsample op take 2 inputs, {} given".format(len(inputs)) scales = params[inputs[1].name_hint].asnumpy() inputs = inputs[:1] - assert len(scales) == 4 and scales[0] == 1.0 and scales[1] == 1.0 and scales[2] == scales[3] + assert len(scales) == 4 and scales[0] == 1.0 and scales[1] == 1.0 mode = attr.get('mode') if mode == b'nearest': method = "nearest_neighbor" @@ -590,7 +590,8 @@ class Upsample(OnnxOpConverter): else: raise tvm.error.OpAttributeInvalid( 'Value {} in attribute "mode" of operator Upsample is not valid.'.format(mode)) - attr = {'scale':int(scales[-1]), 'method':method, 'layout':'NCHW', 'align_corners':True} + attr = {'scale_h':scales[-2], 'scale_w':scales[-1], 'method':method, + 'layout':'NCHW', 'align_corners':True} return AttrCvt('upsampling')(inputs, attr) diff --git a/python/tvm/relay/op/nn/_nn.py b/python/tvm/relay/op/nn/_nn.py index 5786c22..8915480 100644 --- a/python/tvm/relay/op/nn/_nn.py +++ b/python/tvm/relay/op/nn/_nn.py @@ -409,11 +409,12 @@ def schedule_upsampling(_, outs, target): @reg.register_compute("nn.upsampling") def compute_upsampling(attrs, inputs, out_dtype, target): - scale = attrs.scale + scale_h = attrs.scale_h + scale_w = attrs.scale_w layout = attrs.layout method = attrs.method align_corners = attrs.align_corners - return [topi.nn.upsampling(inputs[0], scale, layout, method, align_corners)] + return [topi.nn.upsampling(inputs[0], scale_h, scale_w, layout, method, align_corners)] # pad reg.register_schedule("nn.pad", schedule_broadcast) diff --git a/python/tvm/relay/op/nn/nn.py b/python/tvm/relay/op/nn/nn.py index 1f289d1..6488eab 100644 --- a/python/tvm/relay/op/nn/nn.py +++ b/python/tvm/relay/op/nn/nn.py @@ -483,7 +483,8 @@ def global_avg_pool2d(data, def upsampling(data, - scale=1, + scale_h=1, + scale_w=1, layout="NCHW", method="nearest_neighbor", align_corners=False): @@ -492,7 +493,7 @@ def upsampling(data, This operator takes data as input and does 2D scaling to the given scale factor. In the default case, where the data_layout is `NCHW` with data of shape (n, c, h, w) - out will have a shape (n, c, h*scale, w*scale) + out will have a shape (n, c, h*scale_h, w*scale_w) method indicates the algorithm to be used while calculating the out value and method can be one of ("bilinear", "nearest_neighbor", "bicubic") @@ -502,8 +503,11 @@ def upsampling(data, data : tvm.relay.Expr The input data to the operator. - scale : tvm.relay.Expr - The scale factor for upsampling. + scale_h : tvm.relay.Expr + The scale factor for height upsampling. + + scale_w : tvm.relay.Expr + The scale factor for width upsampling. layout : str, optional Layout of the input. @@ -519,7 +523,7 @@ def upsampling(data, result : tvm.relay.Expr The computed result. """ - return _make.upsampling(data, scale, layout, method, align_corners) + return _make.upsampling(data, scale_h, scale_w, layout, method, align_corners) def batch_flatten(data): diff --git a/src/relay/op/nn/upsampling.cc b/src/relay/op/nn/upsampling.cc index c473f86..e044722 100644 --- a/src/relay/op/nn/upsampling.cc +++ b/src/relay/op/nn/upsampling.cc @@ -80,9 +80,8 @@ bool UpSamplingRel(const Array& types, << " But got " << in_layout; auto oshape = layout_converter.ForwardShape(data->shape); - - oshape.Set(2, oshape[2] * param->scale); - oshape.Set(3, oshape[3] * param->scale); + oshape.Set(2, ir::Cast::make(oshape[2].type(), tvm::round(oshape[2] * param->scale_h))); + oshape.Set(3, ir::Cast::make(oshape[3].type(), tvm::round(oshape[3] * param->scale_w))); // assign output type reporter->Assign(types[1], @@ -95,14 +94,16 @@ bool UpSamplingRel(const Array& types, // Positional relay function to create upsampling operator // used by frontend FFI. Expr MakeUpSampling(Expr data, - int scale, + double scale_h, + double scale_w, std::string layout, std::string method, bool align_corners) { auto attrs = make_node(); attrs->layout = std::move(layout); attrs->method = std::move(method); - attrs->scale = scale; + attrs->scale_h = scale_h; + attrs->scale_w = scale_w; attrs->align_corners = align_corners; static const Op& op = Op::Get("nn.upsampling"); return CallNode::make(op, {data}, Attrs(attrs), {}); diff --git a/tests/python/relay/test_op_level2.py b/tests/python/relay/test_op_level2.py index 9236d6e..982161d 100644 --- a/tests/python/relay/test_op_level2.py +++ b/tests/python/relay/test_op_level2.py @@ -232,14 +232,17 @@ def test_conv2d_transpose_run(): def test_upsampling_infer_type(): n, c , h, w = tvm.var("n"), tvm.var("c"), tvm.var("h"), tvm.var("w") + scale = tvm.const(2.0, "float64") x = relay.var("x", relay.TensorType((n, c, h, w), "float32")) - y = relay.nn.upsampling(x, scale=2, layout="NCHW", method="bilinear") + y = relay.nn.upsampling(x, scale_h=2, scale_w=2, layout="NCHW", method="bilinear") "method=\"BINLINEAR\"" in y.astext() yy = run_infer_type(y) - assert yy.checked_type == relay.TensorType((n, c, h*2, w*2), "float32") + assert yy.checked_type == relay.TensorType((n, c, tvm.expr.Cast("int32", tvm.round(h*scale)), + tvm.expr.Cast("int32", tvm.round(w*scale))), + "float32") n, c = tvm.var("n"), tvm.var("c") x = relay.var("x", relay.TensorType((n, c, 100, 200), "float32")) - y = relay.nn.upsampling(x, scale=2, layout="NCHW", method="bilinear") + y = relay.nn.upsampling(x, scale_h=2, scale_w=2, layout="NCHW", method="bilinear") yy = run_infer_type(y) assert yy.checked_type == relay.TensorType((n, c, 200, 400), "float32") @@ -504,29 +507,31 @@ def test_batch_flatten(): def _test_upsampling(layout, method, align_corners=False): n, c, h, w = tvm.var("n"), 16, 32, 32 - scale = 2 + scale_h = 2.0 + scale_w = 2.0 dtype = "float32" def get_shape(): if layout == "NCHW": - return (c, h, w), (c, h*scale, w*scale) + return (c, h, w), (c, int(round(h*scale_h)), int(round(w*scale_w))) else: - return (h, w, c), (h*scale, w*scale, c) + return (h, w, c), (int(round(h*scale_h)), int(round(w*scale_w)), c) ishape, oshape = get_shape() x = relay.var("x", relay.TensorType((n,) + ishape, dtype)) - y = relay.nn.upsampling(x, scale=scale, layout=layout, + y = relay.nn.upsampling(x, scale_h=scale_h, scale_w=scale_w, layout=layout, method=method, align_corners=align_corners) yy = run_infer_type(y) assert yy.checked_type == relay.TensorType((n,) + oshape, dtype) dshape = (1,) + ishape x = relay.var("x", shape=dshape) - y = relay.nn.upsampling(x, scale=scale, layout=layout, + y = relay.nn.upsampling(x, scale_h=scale_h, scale_w=scale_w, layout=layout, method=method, align_corners=align_corners) func = relay.Function([x], y) data = np.random.uniform(size=dshape).astype(dtype) if method == "nearest_neighbor": - ref = topi.testing.upsampling_python(data, (scale, scale), layout) + ref = topi.testing.upsampling_python(data, (scale_h, scale_w), layout) else: - ref = topi.testing.bilinear_resize_python(data, (h*scale, w*scale), layout) + ref = topi.testing.bilinear_resize_python(data, (int(round(h*scale_h)), + int(round(w*scale_w))), layout) for target, ctx in ctx_list(): executor = relay.create_executor("graph", ctx=ctx, target=target) out = executor.evaluate(func)(data) diff --git a/tests/python/relay/test_pass_alter_op_layout.py b/tests/python/relay/test_pass_alter_op_layout.py index 8ae7777..f1200ec 100644 --- a/tests/python/relay/test_pass_alter_op_layout.py +++ b/tests/python/relay/test_pass_alter_op_layout.py @@ -487,7 +487,7 @@ def test_alter_layout_nchw_upsamping_op(): x = relay.var("x", shape=(1, 32, 28, 28)) weight = relay.var('weight', shape=(32, 32, 3, 3)) y = relay.nn.conv2d(x, weight, channels=32, kernel_size=(3, 3), padding=(1, 1)) - y = relay.nn.upsampling(y, scale=2) + y = relay.nn.upsampling(y, scale_h=2, scale_w=2) y = relay.nn.avg_pool2d(y, pool_size=(2, 2), strides=(2, 2)) y = relay.Function(analysis.free_vars(y), y) return y @@ -506,7 +506,7 @@ def test_alter_layout_nchw_upsamping_op(): x = relay.layout_transform(x, "NCHW", "NCHW16c") y = relay.nn.conv2d(x, weight, channels=32, kernel_size=(3, 3), padding=(1, 1), data_layout="NCHW16c") - y = relay.nn.upsampling(y, scale=2, layout="NCHW16c") + y = relay.nn.upsampling(y, scale_h=2, scale_w=2, layout="NCHW16c") y = relay.nn.avg_pool2d(y, pool_size=(2, 2), strides=(2, 2), layout='NCHW16c') y = relay.layout_transform(y, "NCHW16c", "NCHW") y = relay.Function(analysis.free_vars(y), y) diff --git a/tests/python/relay/test_pass_fuse_ops.py b/tests/python/relay/test_pass_fuse_ops.py index 45faa14..7ec21ea 100644 --- a/tests/python/relay/test_pass_fuse_ops.py +++ b/tests/python/relay/test_pass_fuse_ops.py @@ -126,7 +126,7 @@ def test_concatenate(): def before(dshape): x = relay.var("x", shape=dshape) pooled = relay.nn.max_pool2d(x, pool_size=(2, 2), strides=(2, 2), padding=(0, 0)) - upsampled = relay.nn.upsampling(pooled, scale=2, layout="NCHW") + upsampled = relay.nn.upsampling(pooled, scale_h=2, scale_w=2, layout="NCHW") concat = relay.concatenate((upsampled, x), axis=1) out = relay.add(concat, relay.const(1, "float32")) return relay.Function(relay.analysis.free_vars(out), out) @@ -138,7 +138,7 @@ def test_concatenate(): p0 = relay.var("p0", shape=(dshape[0], dshape[1], dshape[2]//2, dshape[3]//2)) p1 = relay.var("p1", shape=dshape) - upsampled = relay.nn.upsampling(p0, scale=2, layout="NCHW") + upsampled = relay.nn.upsampling(p0, scale_h=2, scale_w=2, layout="NCHW") concat = relay.concatenate((upsampled, p1), axis=1) out = relay.add(concat, relay.const(1, "float32")) f1 = relay.Function([p0, p1], out) @@ -164,7 +164,7 @@ def test_tuple_root(): def before(dshape): x = relay.var("x", shape=dshape) pooled = relay.nn.max_pool2d(x, pool_size=(2, 2), strides=(2, 2), padding=(0, 0)) - upsampled = relay.nn.upsampling(pooled, scale=2, layout="NCHW") + upsampled = relay.nn.upsampling(pooled, scale_h=2, scale_w=2, layout="NCHW") out = relay.Tuple((upsampled, x)) return relay.Function(relay.analysis.free_vars(out), out) @@ -174,7 +174,7 @@ def test_tuple_root(): f0 = relay.Function([x], pooled) p0 = relay.var("p0", shape=(dshape[0], dshape[1], dshape[2]//2, dshape[3]//2)) - upsampled = relay.nn.upsampling(p0, scale=2, layout="NCHW") + upsampled = relay.nn.upsampling(p0, scale_h=2, scale_w=2, layout="NCHW") f1 = relay.Function([p0], upsampled) x = relay.var("x", shape=dshape) diff --git a/topi/python/topi/nn/upsampling.py b/topi/python/topi/nn/upsampling.py index 6092136..771c9e2 100644 --- a/topi/python/topi/nn/upsampling.py +++ b/topi/python/topi/nn/upsampling.py @@ -17,10 +17,12 @@ """TVM operator upsampling compute.""" from __future__ import absolute_import import topi +import tvm from ..util import simplify -def upsampling(data, scale, layout="NCHW", method='nearest_neighbor', align_corners=False): +def upsampling(data, scale_h, scale_w, layout="NCHW", method='nearest_neighbor', + align_corners=False): """Perform upsampling on the data. Nearest neighbor and bilinear upsampling are supported. @@ -31,8 +33,11 @@ def upsampling(data, scale, layout="NCHW", method='nearest_neighbor', align_corn [batch, channel, in_height, in_width] or [batch, in_height, in_width, channel] - scale : int - Scaling factor + scale_h : float + Scaling factor for height + + scale_w : float + Scaling factor for width layout : string, optional either "NCHW" or "NHWC" @@ -43,14 +48,17 @@ def upsampling(data, scale, layout="NCHW", method='nearest_neighbor', align_corn Returns ------- output : tvm.Tensor - 4-D with shape [batch, channel, in_height*scale, in_width*scale] + 4-D with shape [batch, channel, in_height*scale_h, in_width*scale_w] or [batch, in_height*scale, in_width*scale, channel] """ base_layout = layout[0:4] if base_layout == "NCHW": - out_shape = (simplify(data.shape[2] * scale), simplify(data.shape[3] * scale)) + out_shape = (simplify(topi.cast(tvm.round(data.shape[2] * scale_h), data.shape[2].dtype)), + simplify(topi.cast(tvm.round(data.shape[3] * scale_w), data.shape[3].dtype))) elif layout == "NHWC": - out_shape = (simplify(data.shape[1] * scale), simplify(data.shape[2] * scale)) + out_shape = (simplify(topi.cast(tvm.round(data.shape[1] * scale_h), data.shape[1].dtype)), + simplify(topi.cast(tvm.round(data.shape[2] * scale_w), data.shape[2].dtype))) + else: raise ValueError("not support this layout {} yet".format(layout)) return topi.image.resize(data, out_shape, layout=layout, diff --git a/topi/python/topi/testing/upsampling_python.py b/topi/python/topi/testing/upsampling_python.py index 167fdfc..6ea7d6a 100644 --- a/topi/python/topi/testing/upsampling_python.py +++ b/topi/python/topi/testing/upsampling_python.py @@ -22,8 +22,8 @@ import numpy as np def upsample_nearest(arr, scale): """ Populate the array by scale factor""" h, w = arr.shape - out_h = math.floor(h * scale[0]) - out_w = math.floor(w * scale[1]) + out_h = int(round(h * scale[0])) + out_w = int(round(w * scale[1])) out = np.empty((out_h, out_w)) for y in range(out_h): for x in range(out_w): @@ -37,14 +37,16 @@ def upsampling_python(data, scale, layout='NCHW'): ishape = data.shape if layout == 'NCHW': - oshape = (ishape[0], ishape[1], math.floor(ishape[2]*scale[0]), math.floor(ishape[3]*scale[1])) + 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 if layout == 'NHWC': - oshape = (ishape[0], math.floor(ishape[1]*scale[0]), math.floor(ishape[1]*scale[1]), ishape[3]) + 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]): diff --git a/topi/tests/python/test_topi_upsampling.py b/topi/tests/python/test_topi_upsampling.py index f878c23..83909c0 100644 --- a/topi/tests/python/test_topi_upsampling.py +++ b/topi/tests/python/test_topi_upsampling.py @@ -23,30 +23,29 @@ import math from common import get_all_backend -def verify_upsampling(batch, in_channel, in_height, in_width, scale, layout='NCHW', method="nearest_neighbor"): - - +def verify_upsampling(batch, in_channel, in_height, in_width, scale_h, scale_w, + layout='NCHW', method="nearest_neighbor"): if layout == 'NCHW': A = tvm.placeholder((batch, in_channel, in_height, in_width), name='A') dtype = A.dtype - out_shape = (batch, in_channel, in_height*scale, in_width*scale) + 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 layout == 'NHWC': A = tvm.placeholder((batch, in_height, in_width, in_channel), name='A') dtype = A.dtype - out_shape = (batch, in_height*scale, in_width*scale, in_channel) + 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, layout=layout, method=method, align_corners=False) + B = topi.nn.upsampling(A, scale_h, scale_w, layout=layout, method=method, align_corners=False) if method == "bilinear": - out_size = (in_height*scale, in_width*scale) + out_size = (int(round(in_height*scale_h)), int(round(in_width*scale_w))) b_np = topi.testing.bilinear_resize_python(a_np, out_size, layout, align_corners=False) else: - b_np = topi.testing.upsampling_python(a_np, (scale, scale), layout) + b_np = topi.testing.upsampling_python(a_np, (scale_h, scale_w), layout) def check_device(device): ctx = tvm.context(device, 0) @@ -68,20 +67,24 @@ def verify_upsampling(batch, in_channel, in_height, in_width, scale, layout='NCH def test_upsampling(): # nearest_neighbor - NCHW - verify_upsampling(8, 16, 32, 32, 2) - verify_upsampling(2, 32, 64, 64, 3) + verify_upsampling(8, 16, 32, 32, 2.0, 2.0) + verify_upsampling(2, 32, 64, 64, 3.0, 3.0) + verify_upsampling(1, 64, 22, 32, 1.954545497894287, 2.0) ## nearest_neighbor - NHWC - verify_upsampling(8, 16, 32, 32, 2, layout="NHWC") - verify_upsampling(2, 32, 64, 64, 3, layout="NHWC") + verify_upsampling(8, 16, 32, 32, 2.0, 2.0, layout="NHWC") + verify_upsampling(2, 32, 64, 64, 3.0, 3.0, layout="NHWC") + verify_upsampling(1, 64, 22, 32, 1.954545497894287, 2.0, layout="NHWC") # bilinear - NCHW - verify_upsampling(2, 2, 32, 32, 2, method="bilinear") - verify_upsampling(2, 2, 32, 32, 3, method="bilinear") + verify_upsampling(2, 2, 32, 32, 2.0, 2.0, method="bilinear") + verify_upsampling(2, 2, 32, 32, 3.0, 3.0, method="bilinear") + verify_upsampling(1, 64, 22, 32, 1.954545497894287, 2.0, method="bilinear") # bilinear - NHWC - verify_upsampling(2, 2, 32, 32, 2, layout="NHWC", method="bilinear") - verify_upsampling(2, 2, 32, 32, 3, layout="NHWC", method="bilinear") + verify_upsampling(2, 2, 32, 32, 2.0, 2.0, layout="NHWC", method="bilinear") + verify_upsampling(2, 2, 32, 32, 3.0, 3.0, layout="NHWC", method="bilinear") + verify_upsampling(1, 64, 22, 32, 3.0, 3.0, layout="NHWC", method="bilinear") if __name__ == "__main__": test_upsampling() -- 2.7.4