From e576d186a104d8f85a96760f53e27b9e373324fe Mon Sep 17 00:00:00 2001 From: Arun Rangasamy Date: Thu, 16 Sep 2021 13:07:48 +0530 Subject: [PATCH 1/4] [ONNX][#8838] QLinearSigmoid contrib op and Bug Fix for DequantizeLinear --- python/tvm/relay/frontend/onnx.py | 33 +++++++++++++++++++++- tests/python/frontend/onnx/test_forward.py | 26 +++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/python/tvm/relay/frontend/onnx.py b/python/tvm/relay/frontend/onnx.py index 16686963d3be..aa1457afe1d9 100644 --- a/python/tvm/relay/frontend/onnx.py +++ b/python/tvm/relay/frontend/onnx.py @@ -3176,7 +3176,7 @@ def _impl_v10(cls, inputs, attr, params): @classmethod def _impl_v13(cls, inputs, attr, params): data, scale, zp = inputs - axis = attr.get("axis", 1) + axis = attr.get("axis", 0) return _qnn.op.dequantize(data, scale, _op.cast(zp, "int32"), axis) @@ -3351,6 +3351,36 @@ def _impl_v10(cls, inputs, attr, params): return _qnn.op.quantize(out, y_scale, y_zero_point, out_dtype=dtype) +class QLinearSigmoid(OnnxOpConverter): + """Operator converter for QLinearSigmoid from Microsoft onnxruntime contrib opset.""" + + @classmethod + def _impl_v10(cls, inputs, attr, params): + def get_scalar(x, dtype="float32"): + if isinstance(x, _expr.Var) and x.name_hint in params: + return _op.const(params[x.name_hint].numpy(), dtype) + rank = len(infer_shape(x)) + assert rank <= 1, "QLinearSigmoid scale and zero_point input must be scalars" + if rank == 1: + x = _op.squeeze(x, [0]) + return _op.cast(x, dtype) + + x = inputs[0] + x_scale = get_scalar(inputs[1]) + x_zero_point = get_scalar(inputs[2], "int32") + y_scale = fold_constant(get_scalar(inputs[3])) + y_zero_point = get_scalar(inputs[4], "int32") + + dtype = infer_type(x).checked_type.dtype + + ## Apparently, onnxruntime doesn't do this op in integer, they dequantize to fp32 + ## and then requantize after: + ## https://github.com/microsoft/onnxruntime/blob/master/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphTransformer.cpp#L245 + x = _qnn.op.dequantize(inputs[0], x_scale, x_zero_point) + out = _op.sigmoid(x) + return _qnn.op.quantize(out, y_scale, y_zero_point, out_dtype=dtype) + + class QLinearConcat(OnnxOpConverter): """Operator converter for QLinearConcat from Microsoft onnxruntime contrib opset.""" @@ -3941,6 +3971,7 @@ def _get_convert_map(opset): "QLinearConcat": QLinearConcat.get_converter(opset), "QLinearAdd": QLinearAdd.get_converter(opset), "QLinearMul": QLinearMul.get_converter(opset), + "QLinearSigmoid": QLinearSigmoid.get_converter(opset), "ConvInteger": ConvInteger.get_converter(opset), # Random number generation. "RandomUniform": RandomUniform.get_converter(opset), diff --git a/tests/python/frontend/onnx/test_forward.py b/tests/python/frontend/onnx/test_forward.py index 056d1b8fffdf..ecd0c4c3bf9a 100644 --- a/tests/python/frontend/onnx/test_forward.py +++ b/tests/python/frontend/onnx/test_forward.py @@ -5432,11 +5432,37 @@ def verify_qlinearmul(a_shape, b_shape, c_shape): model = helper.make_model(graph, producer_name="qlinearmul_test") quantize_and_verify_with_ort(model, input_names, [a_shape, b_shape], target, dev) + verify_qlinearmul([7], [7], [7]) verify_qlinearmul([4, 2], [4, 2], [4, 2]) verify_qlinearmul([4, 2], [2], [4, 2]) verify_qlinearmul([5, 1, 7], [2, 7], [5, 2, 7]) +@tvm.testing.parametrize_targets +def test_qlinearsigmoid(target, dev): + def verify_qlinearsigmoid(a_shape): + + a_array = np.random.random(a_shape).astype("float32") + + input_nodes = [helper.make_tensor_value_info("a", TensorProto.FLOAT, list(a_shape))] + + input_values = [a_array] + + node = helper.make_node("Sigmoid", ["a"], ["B"]) + graph = helper.make_graph( + [node], + "qlinearsigmoid_test", + inputs=input_nodes, + outputs=[helper.make_tensor_value_info("B", TensorProto.FLOAT, list(a_shape))], + ) + model = helper.make_model(graph, producer_name="qlinearsigmoid_test") + quantize_and_verify_with_ort(model, ["a"], [a_shape], target, dev) + + verify_qlinearsigmoid([4, 2]) + verify_qlinearsigmoid([5]) + verify_qlinearsigmoid([3, 4, 5]) + + @tvm.testing.parametrize_targets def test_random_uniform(target, dev): def get_random_uniform(shape, dtype="float32", high=1.0, low=0.0, seed=None): From 39f89302d4995f845b28fb7cd7e9c69378eff3fb Mon Sep 17 00:00:00 2001 From: Arun Rangasamy Date: Thu, 16 Sep 2021 13:07:48 +0530 Subject: [PATCH 2/4] [ONNX][#8838] QLinearSigmoid contrib op and Bug Fix for DequantizeLinear --- python/tvm/relay/frontend/onnx.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/python/tvm/relay/frontend/onnx.py b/python/tvm/relay/frontend/onnx.py index aa1457afe1d9..5a1d6bdd76af 100644 --- a/python/tvm/relay/frontend/onnx.py +++ b/python/tvm/relay/frontend/onnx.py @@ -3356,15 +3356,6 @@ class QLinearSigmoid(OnnxOpConverter): @classmethod def _impl_v10(cls, inputs, attr, params): - def get_scalar(x, dtype="float32"): - if isinstance(x, _expr.Var) and x.name_hint in params: - return _op.const(params[x.name_hint].numpy(), dtype) - rank = len(infer_shape(x)) - assert rank <= 1, "QLinearSigmoid scale and zero_point input must be scalars" - if rank == 1: - x = _op.squeeze(x, [0]) - return _op.cast(x, dtype) - x = inputs[0] x_scale = get_scalar(inputs[1]) x_zero_point = get_scalar(inputs[2], "int32") @@ -3375,7 +3366,8 @@ def get_scalar(x, dtype="float32"): ## Apparently, onnxruntime doesn't do this op in integer, they dequantize to fp32 ## and then requantize after: - ## https://github.com/microsoft/onnxruntime/blob/master/onnxruntime/core/providers/dml/DmlExecutionProvider/src/GraphTransformer.cpp#L245 + ## https://github.com/microsoft/onnxruntime/blob/master/onnxruntime/core/ + ## providers/dml/DmlExecutionProvider/src/GraphTransformer.cpp#L245 x = _qnn.op.dequantize(inputs[0], x_scale, x_zero_point) out = _op.sigmoid(x) return _qnn.op.quantize(out, y_scale, y_zero_point, out_dtype=dtype) From 2038822f727cbd7513fa2aec686d48b90282abf1 Mon Sep 17 00:00:00 2001 From: Arun Rangasamy Date: Thu, 16 Sep 2021 13:07:48 +0530 Subject: [PATCH 3/4] [ONNX][#8838] QLinearSigmoid contrib op and Bug Fix for DequantizeLinear --- python/tvm/relay/frontend/onnx.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/python/tvm/relay/frontend/onnx.py b/python/tvm/relay/frontend/onnx.py index 5a1d6bdd76af..693b1d587191 100644 --- a/python/tvm/relay/frontend/onnx.py +++ b/python/tvm/relay/frontend/onnx.py @@ -3357,10 +3357,10 @@ class QLinearSigmoid(OnnxOpConverter): @classmethod def _impl_v10(cls, inputs, attr, params): x = inputs[0] - x_scale = get_scalar(inputs[1]) - x_zero_point = get_scalar(inputs[2], "int32") - y_scale = fold_constant(get_scalar(inputs[3])) - y_zero_point = get_scalar(inputs[4], "int32") + x_scale = get_scalar(inputs[1], params) + x_zero_point = get_scalar(inputs[2], params, "int32") + y_scale = fold_constant(get_scalar(inputs[3], params)) + y_zero_point = get_scalar(inputs[4], params, "int32") dtype = infer_type(x).checked_type.dtype From 85f629653fccbd3b369d68da4757c9330794fe37 Mon Sep 17 00:00:00 2001 From: Arun Rangasamy Date: Thu, 16 Sep 2021 13:07:48 +0530 Subject: [PATCH 4/4] [ONNX][#8838] QLinearSigmoid contrib op and Bug Fix for DequantizeLinear --- python/tvm/relay/frontend/onnx.py | 6 ++++-- tests/python/frontend/onnx/test_forward.py | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/python/tvm/relay/frontend/onnx.py b/python/tvm/relay/frontend/onnx.py index ebdaa6f49508..4d48f5796aca 100644 --- a/python/tvm/relay/frontend/onnx.py +++ b/python/tvm/relay/frontend/onnx.py @@ -3253,7 +3253,9 @@ def _impl_v10(cls, inputs, attr, params): @classmethod def _impl_v13(cls, inputs, attr, params): data, scale, zp = inputs - axis = attr.get("axis", 0) + axis = attr.get("axis", 1) + if len(infer_shape(data)) <= 1: + axis = 0 return _qnn.op.dequantize(data, scale, _op.cast(zp, "int32"), axis) @@ -3445,7 +3447,7 @@ def _impl_v10(cls, inputs, attr, params): ## and then requantize after: ## https://github.com/microsoft/onnxruntime/blob/master/onnxruntime/core/ ## providers/dml/DmlExecutionProvider/src/GraphTransformer.cpp#L245 - x = _qnn.op.dequantize(inputs[0], x_scale, x_zero_point) + x = _qnn.op.dequantize(x, x_scale, x_zero_point) out = _op.sigmoid(x) return _qnn.op.quantize(out, y_scale, y_zero_point, out_dtype=dtype) diff --git a/tests/python/frontend/onnx/test_forward.py b/tests/python/frontend/onnx/test_forward.py index d54a1e58635c..91d3911da530 100644 --- a/tests/python/frontend/onnx/test_forward.py +++ b/tests/python/frontend/onnx/test_forward.py @@ -5571,6 +5571,7 @@ def verify_qlinearsigmoid(a_shape): verify_qlinearsigmoid([4, 2]) verify_qlinearsigmoid([5]) verify_qlinearsigmoid([3, 4, 5]) + verify_qlinearsigmoid([]) @tvm.testing.parametrize_targets