From dad98696a28b3c2781f13c53b5c463e58f1df891 Mon Sep 17 00:00:00 2001 From: jvreca Date: Fri, 22 Mar 2024 15:23:37 +0100 Subject: [PATCH 1/6] Added test, docs/, and updated resolve_rounding_mode function to return new rounding modes. --- docs/qonnx-custom-ops/quant_op.md | 19 ++++++++++++++++++- src/qonnx/custom_op/general/quant.py | 16 +++++++++++++++- tests/custom_op/test_runding_mode.py | 20 ++++++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 tests/custom_op/test_runding_mode.py diff --git a/docs/qonnx-custom-ops/quant_op.md b/docs/qonnx-custom-ops/quant_op.md index 02d115fb..953fdca7 100644 --- a/docs/qonnx-custom-ops/quant_op.md +++ b/docs/qonnx-custom-ops/quant_op.md @@ -21,7 +21,7 @@ This operator is not part of the ONNX standard and is not currently versioned.
narrow : int (default is 0)
Defines if the value range should be interpreted as narrow, when signed=1. E.g. at 8b regular=[-128, 127] vs narrow=[-127, 127].
rounding_mode : string (default is "ROUND")
-
Defines how rounding should be applied during quantization. Currently available modes are: "ROUND", "CEIL" and "FLOOR". Here "ROUND" implies a round-to-even operation. Lowercase variants for the rounding mode string are also supported: "round", "ceil", "floor".
+
Defines how rounding should be applied during quantization. Avaiable options are ROUND, CEIL, FLOOR, UP, DOWN, HALF_UP, HALF_DOWN. The rounding modes are described in the table bellow. The names of rounding modes can be upper case or lower case.
#### Inputs @@ -46,6 +46,23 @@ This operator is not part of the ONNX standard and is not currently versioned. +#### Rounding modes +
+rounding modes +| **Number \ ROUNDING_MODE** | ROUND=HALF_EVEN | CEIL | FLOOR | UP | DOWN | HALF_UP | HALF_DOWN | +|---------------------------- |----------------- |------ |------- |---- |------ |--------- |----------- | +| 5.5 | 6 | 6 | 5 | 6 | 5 | 6 | 5 | +| 2.5 | 2 | 3 | 2 | 3 | 2 | 3 | 2 | +| 1.6 | 2 | 2 | 1 | 2 | 1 | 2 | 2 | +| 1.1 | 1 | 2 | 1 | 2 | 1 | 1 | 1 | +| 1.0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | +| -1.0 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | +| -1.1 | -1 | -1 | -2 | -2 | -1 | -1 | -1 | +| -1.6 | -2 | -1 | -2 | -2 | -1 | -2 | -2 | +| -2.5 | -2 | -2 | -3 | -3 | -2 | -3 | -2 | +| -5.5 | -6 | -5 | -6 | -6 | -5 | -6 | -5 | +
+ #### Examples
Quant diff --git a/src/qonnx/custom_op/general/quant.py b/src/qonnx/custom_op/general/quant.py index f552e7a8..15afd048 100644 --- a/src/qonnx/custom_op/general/quant.py +++ b/src/qonnx/custom_op/general/quant.py @@ -135,12 +135,26 @@ def resolve_rounding_mode(mode_string): """Resolve the rounding mode string of Quant and Trunc ops to the corresponding numpy functions.""" normalized_mode_string = mode_string.upper() - if normalized_mode_string == "ROUND": + if normalized_mode_string == "ROUND" or normalized_mode_string == "HALF_TO_EVEN": return np.round elif normalized_mode_string == "CEIL": return np.ceil elif normalized_mode_string == "FLOOR": return np.floor + elif normalized_mode_string == "UP": + def round_up(x): + return np.sign(x) * np.ceil(np.abs(x)) + return round_up + elif normalized_mode_string == "DOWN": + return np.fix + elif normalized_mode_string == "HALF_UP": + def round_half_up(x): + return np.sign(x) * np.floor(np.abs(x) + 0.5) + return round_half_up + elif normalized_mode_string == "HALF_DOWN": + def round_half_down(x): + return np.sign(x) * np.ceil(np.abs(x) - 0.5) + return round_half_down else: raise ValueError(f"Could not resolve rounding mode called: {normalized_mode_string}") diff --git a/tests/custom_op/test_runding_mode.py b/tests/custom_op/test_runding_mode.py new file mode 100644 index 00000000..54a81f0e --- /dev/null +++ b/tests/custom_op/test_runding_mode.py @@ -0,0 +1,20 @@ +import pytest + +import numpy as np + +from qonnx.custom_op.general.quant import resolve_rounding_mode + +@pytest.mark.parametrize("rmode,exp", [ + ("ROUND", np.array([6, 2, 2, 1, 1, -1, -1, -2, -2, -6])), + ("CEIL", np.array([6, 3, 2, 2, 1, -1, -1, -1, -2, - 5])), + ("FLOOR", np.array([5, 2, 1, 1, 1, -1, -2, -2, -3, -6])), + ("UP", np.array([6, 3, 2, 2, 1, -1, -2, -2, -3, -6])), + ("DOWN", np.array([5, 2, 1, 1, 1, -1, -1, -1, -2, -5])), + ("HALF_UP", np.array([6, 3, 2, 1, 1, -1, -1, -2, -3, -6])), + ("HALF_DOWN", np.array([5, 2, 2, 1, 1, -1, -1, -2, -2, -5])) + ] +) +def test_rounding_modes(rmode, exp): + test_array = np.array([5.5, 2.5, 1.6, 1.1, 1.0, -1.0, -1.1, -1.6, -2.5, -5.5]) + rounding_fn = resolve_rounding_mode(rmode) + assert np.array_equal(rounding_fn(test_array), exp) From 47a88e4fb4d0bc69059297bbea39e69650f95d1f Mon Sep 17 00:00:00 2001 From: jvreca Date: Fri, 22 Mar 2024 15:42:21 +0100 Subject: [PATCH 2/6] Fix table visualization. --- docs/qonnx-custom-ops/quant_op.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/qonnx-custom-ops/quant_op.md b/docs/qonnx-custom-ops/quant_op.md index 953fdca7..b9e11c79 100644 --- a/docs/qonnx-custom-ops/quant_op.md +++ b/docs/qonnx-custom-ops/quant_op.md @@ -49,18 +49,18 @@ This operator is not part of the ONNX standard and is not currently versioned. #### Rounding modes
rounding modes -| **Number \ ROUNDING_MODE** | ROUND=HALF_EVEN | CEIL | FLOOR | UP | DOWN | HALF_UP | HALF_DOWN | -|---------------------------- |----------------- |------ |------- |---- |------ |--------- |----------- | -| 5.5 | 6 | 6 | 5 | 6 | 5 | 6 | 5 | -| 2.5 | 2 | 3 | 2 | 3 | 2 | 3 | 2 | -| 1.6 | 2 | 2 | 1 | 2 | 1 | 2 | 2 | -| 1.1 | 1 | 2 | 1 | 2 | 1 | 1 | 1 | -| 1.0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -| -1.0 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -| -1.1 | -1 | -1 | -2 | -2 | -1 | -1 | -1 | -| -1.6 | -2 | -1 | -2 | -2 | -1 | -2 | -2 | -| -2.5 | -2 | -2 | -3 | -3 | -2 | -3 | -2 | -| -5.5 | -6 | -5 | -6 | -6 | -5 | -6 | -5 | +| **Number \ ROUNDING_MODE** | ROUND=HALF_EVEN | CEIL | FLOOR | UP | DOWN | HALF_UP | HALF_DOWN | +|----------------------------|-----------------|------|-------|----|------|---------|-----------| +| 5.5 | 6 | 6 | 5 | 6 | 5 | 6 | 5 | +| 2.5 | 2 | 3 | 2 | 3 | 2 | 3 | 2 | +| 1.6 | 2 | 2 | 1 | 2 | 1 | 2 | 2 | +| 1.1 | 1 | 2 | 1 | 2 | 1 | 1 | 1 | +| 1.0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | +| -1.0 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | +| -1.1 | -1 | -1 | -2 | -2 | -1 | -1 | -1 | +| -1.6 | -2 | -1 | -2 | -2 | -1 | -2 | -2 | +| -2.5 | -2 | -2 | -3 | -3 | -2 | -3 | -2 | +| -5.5 | -6 | -5 | -6 | -6 | -5 | -6 | -5 |
#### Examples From e2c15045d9ccf5f4c8162c1555c366c337616fee Mon Sep 17 00:00:00 2001 From: jvreca Date: Fri, 22 Mar 2024 15:43:56 +0100 Subject: [PATCH 3/6] Fix table visualization again. --- docs/qonnx-custom-ops/quant_op.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/qonnx-custom-ops/quant_op.md b/docs/qonnx-custom-ops/quant_op.md index b9e11c79..68029406 100644 --- a/docs/qonnx-custom-ops/quant_op.md +++ b/docs/qonnx-custom-ops/quant_op.md @@ -49,6 +49,7 @@ This operator is not part of the ONNX standard and is not currently versioned. #### Rounding modes
rounding modes + | **Number \ ROUNDING_MODE** | ROUND=HALF_EVEN | CEIL | FLOOR | UP | DOWN | HALF_UP | HALF_DOWN | |----------------------------|-----------------|------|-------|----|------|---------|-----------| | 5.5 | 6 | 6 | 5 | 6 | 5 | 6 | 5 | From 7e98eb3287de5c36e463084fc5724a449751c064 Mon Sep 17 00:00:00 2001 From: jvreca Date: Mon, 26 Aug 2024 09:16:02 +0200 Subject: [PATCH 4/6] reformated with pre-commit hooks. --- src/qonnx/custom_op/general/quant.py | 6 ++++++ tests/custom_op/test_runding_mode.py | 11 +++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/qonnx/custom_op/general/quant.py b/src/qonnx/custom_op/general/quant.py index 15afd048..5cdc1294 100644 --- a/src/qonnx/custom_op/general/quant.py +++ b/src/qonnx/custom_op/general/quant.py @@ -142,18 +142,24 @@ def resolve_rounding_mode(mode_string): elif normalized_mode_string == "FLOOR": return np.floor elif normalized_mode_string == "UP": + def round_up(x): return np.sign(x) * np.ceil(np.abs(x)) + return round_up elif normalized_mode_string == "DOWN": return np.fix elif normalized_mode_string == "HALF_UP": + def round_half_up(x): return np.sign(x) * np.floor(np.abs(x) + 0.5) + return round_half_up elif normalized_mode_string == "HALF_DOWN": + def round_half_down(x): return np.sign(x) * np.ceil(np.abs(x) - 0.5) + return round_half_down else: raise ValueError(f"Could not resolve rounding mode called: {normalized_mode_string}") diff --git a/tests/custom_op/test_runding_mode.py b/tests/custom_op/test_runding_mode.py index 54a81f0e..eb48d644 100644 --- a/tests/custom_op/test_runding_mode.py +++ b/tests/custom_op/test_runding_mode.py @@ -4,15 +4,18 @@ from qonnx.custom_op.general.quant import resolve_rounding_mode -@pytest.mark.parametrize("rmode,exp", [ + +@pytest.mark.parametrize( + "rmode,exp", + [ ("ROUND", np.array([6, 2, 2, 1, 1, -1, -1, -2, -2, -6])), - ("CEIL", np.array([6, 3, 2, 2, 1, -1, -1, -1, -2, - 5])), + ("CEIL", np.array([6, 3, 2, 2, 1, -1, -1, -1, -2, -5])), ("FLOOR", np.array([5, 2, 1, 1, 1, -1, -2, -2, -3, -6])), ("UP", np.array([6, 3, 2, 2, 1, -1, -2, -2, -3, -6])), ("DOWN", np.array([5, 2, 1, 1, 1, -1, -1, -1, -2, -5])), ("HALF_UP", np.array([6, 3, 2, 1, 1, -1, -1, -2, -3, -6])), - ("HALF_DOWN", np.array([5, 2, 2, 1, 1, -1, -1, -2, -2, -5])) - ] + ("HALF_DOWN", np.array([5, 2, 2, 1, 1, -1, -1, -2, -2, -5])), + ], ) def test_rounding_modes(rmode, exp): test_array = np.array([5.5, 2.5, 1.6, 1.1, 1.0, -1.0, -1.1, -1.6, -2.5, -5.5]) From fafc4d7f5496fed4129bc820a2815c99cd0105b0 Mon Sep 17 00:00:00 2001 From: jvreca Date: Mon, 26 Aug 2024 09:18:49 +0200 Subject: [PATCH 5/6] Removed the _TO_ to make it consitant with others --- src/qonnx/custom_op/general/quant.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qonnx/custom_op/general/quant.py b/src/qonnx/custom_op/general/quant.py index 5cdc1294..b0b50b9a 100644 --- a/src/qonnx/custom_op/general/quant.py +++ b/src/qonnx/custom_op/general/quant.py @@ -135,7 +135,7 @@ def resolve_rounding_mode(mode_string): """Resolve the rounding mode string of Quant and Trunc ops to the corresponding numpy functions.""" normalized_mode_string = mode_string.upper() - if normalized_mode_string == "ROUND" or normalized_mode_string == "HALF_TO_EVEN": + if normalized_mode_string == "ROUND" or normalized_mode_string == "HALF_EVEN": return np.round elif normalized_mode_string == "CEIL": return np.ceil From bbd214b241c7df76b262046758c94a52aa16a4f8 Mon Sep 17 00:00:00 2001 From: Yaman Umuroglu Date: Fri, 20 Dec 2024 00:01:15 +0100 Subject: [PATCH 6/6] trigger CI