Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is tensor representable #136

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Added test, docs/, and updated resolve_rounding_mode function to retu…
…rn new rounding modes.
jvreca committed Mar 22, 2024
commit dad98696a28b3c2781f13c53b5c463e58f1df891
19 changes: 18 additions & 1 deletion docs/qonnx-custom-ops/quant_op.md
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ This operator is not part of the ONNX standard and is not currently versioned.
<dt><tt>narrow</tt> : int (default is 0)</dt>
<dd>Defines if the value range should be interpreted as narrow, when signed=1. E.g. at 8b regular=[-128, 127] vs narrow=[-127, 127].</dd>
<dt><tt>rounding_mode</tt> : string (default is "ROUND")</dt>
<dd>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".</dd>
<dd>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.</dd>
</dl>

#### Inputs
@@ -46,6 +46,23 @@ This operator is not part of the ONNX standard and is not currently versioned.
</dl>


#### Rounding modes
<details>
<summary>rounding modes</summary>
| **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 |
</details>

#### Examples
<details>
<summary>Quant</summary>
16 changes: 15 additions & 1 deletion src/qonnx/custom_op/general/quant.py
Original file line number Diff line number Diff line change
@@ -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}")

20 changes: 20 additions & 0 deletions tests/custom_op/test_runding_mode.py
Original file line number Diff line number Diff line change
@@ -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)