diff --git a/python/tvm/relay/frontend/caffe.py b/python/tvm/relay/frontend/caffe.py index 74d10623054c1..68bf767557d5d 100644 --- a/python/tvm/relay/frontend/caffe.py +++ b/python/tvm/relay/frontend/caffe.py @@ -66,6 +66,7 @@ def __init__(self, init_layer_dict, predict_layer, exp_tab): "Slice": self.convert_slice, "Softmax": self.convert_softmax, "TanH": self.convert_tanh, + "Reduction": self.convert_reduction, } def convert_flatten(self, op): @@ -563,6 +564,44 @@ def convert_tanh(self, op): out = _op.tanh(in_expr) return out + def convert_reduction(self, op): + """ Convert Reduction layer """ + reduction_dic = ["NOP", "SUM", "ASUM", "SUMSQ", "MEAN"] + + inputs = op.bottom + in_expr = self.exp_tab.get_expr(inputs[0]) + method = op.reduction_param.operation + axis = op.reduction_param.axis + coeff = op.reduction_param.coeff + coeff_expr = self.exp_tab.new_const(np.asarray(coeff, np.float32)) + num_axes = len(_infer_shape(in_expr)) + + # Currently, only reduction along ALL "tail" axes is supported in Caffe; + # reduction of axis M through N, where N < num_axes - 1, is unsupported. + if 0 < axis < (num_axes - 1): + for _axis in reversed(range(axis + 1, num_axes)): + in_expr = _op.sum(in_expr, axis=_axis) + in_expr = _op.squeeze(in_expr) + + if reduction_dic[method] == "SUM": + out = _op.sum(in_expr, axis=axis) + elif reduction_dic[method] == "MEAN": + out = _op.mean(in_expr, axis=axis) + elif reduction_dic[method] == "ASUM": + in_expr = _op.abs(in_expr) + out = _op.sum(in_expr, axis=axis) + elif reduction_dic[method] == "SUMSQ": + in_expr = _op.multiply(in_expr, in_expr) + out = _op.sum(in_expr, axis=axis) + else: + raise tvm.error.OpAttributeInvalid( + "reduction method:{} is invalid in Caffe frontend.".format(method) + ) + + if float(coeff) != 1.0: + out = _op.multiply(out, coeff_expr) + return out + def convert_crop(self, op): """Convert Crop layer""" inputs = op.bottom diff --git a/tests/python/frontend/caffe/test_forward.py b/tests/python/frontend/caffe/test_forward.py index c3caf8539a9ad..0027a6b417364 100644 --- a/tests/python/frontend/caffe/test_forward.py +++ b/tests/python/frontend/caffe/test_forward.py @@ -783,6 +783,85 @@ def test_forward_TanH(): _test_tanh(np.random.rand(10).astype(np.float32)) +####################################################################### +# Reduction +# ----------- + + +def _test_reduction(data, **kwargs): + """ One iteration of Reduction """ + _test_op(data, L.Reduction, "Reduction", **kwargs) + + +def test_forward_Reduction(): + """ Reduction """ + reduction_op = {"SUM": 1, "ASUM": 2, "SUMSQ": 3, "MEAN": 4} + _test_reduction(np.random.rand(10).astype(np.float32), operation=reduction_op["SUM"], axis=0) + _test_reduction( + np.random.rand(10, 20, 30, 40).astype(np.float32), operation=reduction_op["SUM"], axis=3 + ) + _test_reduction( + np.random.rand(10, 20, 30, 40).astype(np.float32), operation=reduction_op["SUM"], axis=1 + ) + _test_reduction( + np.random.rand(10).astype(np.float32), operation=reduction_op["SUM"], axis=0, coeff=0.5 + ) + _test_reduction( + np.random.rand(10, 20, 30, 40).astype(np.float32), + operation=reduction_op["SUM"], + axis=3, + coeff=5.0, + ) + _test_reduction(np.random.rand(10).astype(np.float32), operation=reduction_op["ASUM"]) + _test_reduction( + np.random.rand(10, 20).astype(np.float32), operation=reduction_op["ASUM"], axis=1 + ) + _test_reduction( + np.random.rand(10, 20, 30, 40).astype(np.float32), operation=reduction_op["ASUM"], axis=3 + ) + _test_reduction( + np.random.rand(10).astype(np.float32), operation=reduction_op["ASUM"], axis=0, coeff=0.0 + ) + _test_reduction( + np.random.rand(10, 20, 30).astype(np.float32), + operation=reduction_op["ASUM"], + axis=2, + coeff=7.0, + ) + _test_reduction( + np.random.rand(10, 20, 30, 40, 10).astype(np.float32), + operation=reduction_op["ASUM"], + axis=3, + coeff=1.0, + ) + _test_reduction(np.random.rand(10).astype(np.float32), operation=reduction_op["SUMSQ"], axis=0) + _test_reduction( + np.random.rand(10, 20, 30, 40).astype(np.float32), operation=reduction_op["SUMSQ"], axis=3 + ) + _test_reduction( + np.random.rand(10).astype(np.float32), operation=reduction_op["SUMSQ"], axis=0, coeff=0.0 + ) + _test_reduction( + np.random.rand(10, 20, 30, 40, 50).astype(np.float32), + operation=reduction_op["SUMSQ"], + axis=4, + coeff=2.0, + ) + _test_reduction(np.random.rand(10).astype(np.float32), operation=reduction_op["MEAN"], axis=0) + _test_reduction( + np.random.rand(10, 20, 30, 40).astype(np.float32), operation=reduction_op["MEAN"], axis=3 + ) + _test_reduction( + np.random.rand(10).astype(np.float32), operation=reduction_op["MEAN"], axis=0, coeff=0.0 + ) + _test_reduction( + np.random.rand(10, 20, 30, 40).astype(np.float32), + operation=reduction_op["MEAN"], + axis=3, + coeff=2.0, + ) + + ####################################################################### # Embed # ----------- @@ -1015,6 +1094,7 @@ def test_forward_Inceptionv1(): # Reshape test_forward_Reshape() test_forward_Flatten() + test_forward_Reduction() # Math test_forward_Concat()