quantizers 1.2.2__tar.gz → 2.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- quantizers-2.0.0/.github/workflows/python-publish.yml +33 -0
- {quantizers-1.2.2 → quantizers-2.0.0}/.github/workflows/python-test.yml +8 -6
- {quantizers-1.2.2 → quantizers-2.0.0}/.pre-commit-config.yaml +5 -5
- quantizers-2.0.0/PKG-INFO +156 -0
- quantizers-2.0.0/README.md +125 -0
- {quantizers-1.2.2 → quantizers-2.0.0}/pyproject.toml +24 -29
- quantizers-2.0.0/src/quantizers/_backends.py +551 -0
- quantizers-2.0.0/src/quantizers/_torch_ops.py +20 -0
- quantizers-2.0.0/src/quantizers/_version.py +24 -0
- quantizers-2.0.0/src/quantizers/binary/__init__.py +3 -0
- quantizers-2.0.0/src/quantizers/binary/binary_ops.py +17 -0
- quantizers-2.0.0/src/quantizers/fixed_point/__init__.py +3 -0
- quantizers-2.0.0/src/quantizers/fixed_point/fixed_point_ops.py +168 -0
- quantizers-2.0.0/src/quantizers/minifloat/__init__.py +3 -0
- quantizers-2.0.0/src/quantizers/minifloat/float_point_ops.py +61 -0
- {quantizers-1.2.2 → quantizers-2.0.0}/src/quantizers/stateful_quantizers.py +17 -45
- quantizers-2.0.0/src/quantizers/triton/__init__.py +215 -0
- quantizers-2.0.0/src/quantizers/triton/_lowering.py +317 -0
- quantizers-2.0.0/src/quantizers.egg-info/PKG-INFO +156 -0
- quantizers-2.0.0/src/quantizers.egg-info/SOURCES.txt +43 -0
- quantizers-2.0.0/src/quantizers.egg-info/requires.txt +21 -0
- quantizers-2.0.0/src/quantizers.egg-info/scm_file_list.json +39 -0
- quantizers-2.0.0/src/quantizers.egg-info/scm_version.json +8 -0
- quantizers-2.0.0/test/conftest.py +204 -0
- quantizers-2.0.0/test/cpp_source/.gitignore +1 -0
- quantizers-2.0.0/test/cpp_source/Makefile +22 -0
- quantizers-2.0.0/test/cpp_source/ac_types/LICENSE +201 -0
- quantizers-2.0.0/test/cpp_source/ac_types/ac_fixed.h +2032 -0
- quantizers-2.0.0/test/cpp_source/ac_types/ac_float.h +1235 -0
- quantizers-2.0.0/test/cpp_source/ac_types/ac_int.h +3636 -0
- quantizers-2.0.0/test/cpp_source/ac_types/ac_std_float.h +2687 -0
- quantizers-2.0.0/test/cpp_source/quantizers.h +27 -0
- quantizers-2.0.0/test/gen_configs.py +67 -0
- quantizers-2.0.0/test/test_backends.py +206 -0
- quantizers-2.0.0/test/test_quantizer_match.py +98 -0
- quantizers-2.0.0/test/test_stateless_quantizer.py +207 -0
- quantizers-2.0.0/test/test_triton.py +195 -0
- quantizers-2.0.0/test/triton_quantizers.py +120 -0
- quantizers-1.2.2/.github/workflows/python-publish.yml +0 -33
- quantizers-1.2.2/PKG-INFO +0 -138
- quantizers-1.2.2/README.md +0 -110
- quantizers-1.2.2/src/quantizers/_version.py +0 -21
- quantizers-1.2.2/src/quantizers/binary/__init__.py +0 -4
- quantizers-1.2.2/src/quantizers/binary/_binary_ops.py +0 -27
- quantizers-1.2.2/src/quantizers/binary/binary_ops.py +0 -10
- quantizers-1.2.2/src/quantizers/binary/binary_ops_np.py +0 -9
- quantizers-1.2.2/src/quantizers/fixed_point/__init__.py +0 -4
- quantizers-1.2.2/src/quantizers/fixed_point/_fixed_point_ops.py +0 -215
- quantizers-1.2.2/src/quantizers/fixed_point/fixed_point_ops.py +0 -19
- quantizers-1.2.2/src/quantizers/fixed_point/fixed_point_ops_np.py +0 -163
- quantizers-1.2.2/src/quantizers/minifloat/__init__.py +0 -4
- quantizers-1.2.2/src/quantizers/minifloat/_float_point_ops.py +0 -56
- quantizers-1.2.2/src/quantizers/minifloat/float_point_ops.py +0 -15
- quantizers-1.2.2/src/quantizers/minifloat/float_point_ops_np.py +0 -42
- quantizers-1.2.2/src/quantizers.egg-info/PKG-INFO +0 -138
- quantizers-1.2.2/src/quantizers.egg-info/SOURCES.txt +0 -49
- quantizers-1.2.2/src/quantizers.egg-info/requires.txt +0 -15
- quantizers-1.2.2/test/cpp_source/ap_types/ap_binary.h +0 -78
- quantizers-1.2.2/test/cpp_source/ap_types/ap_common.h +0 -376
- quantizers-1.2.2/test/cpp_source/ap_types/ap_decl.h +0 -212
- quantizers-1.2.2/test/cpp_source/ap_types/ap_fixed.h +0 -360
- quantizers-1.2.2/test/cpp_source/ap_types/ap_fixed_base.h +0 -2354
- quantizers-1.2.2/test/cpp_source/ap_types/ap_fixed_ref.h +0 -718
- quantizers-1.2.2/test/cpp_source/ap_types/ap_fixed_special.h +0 -230
- quantizers-1.2.2/test/cpp_source/ap_types/ap_float.h +0 -197
- quantizers-1.2.2/test/cpp_source/ap_types/ap_int.h +0 -330
- quantizers-1.2.2/test/cpp_source/ap_types/ap_int_base.h +0 -1885
- quantizers-1.2.2/test/cpp_source/ap_types/ap_int_ref.h +0 -1346
- quantizers-1.2.2/test/cpp_source/ap_types/ap_int_special.h +0 -223
- quantizers-1.2.2/test/cpp_source/ap_types/ap_shift_reg.h +0 -138
- quantizers-1.2.2/test/cpp_source/ap_types/etc/ap_private.h +0 -7199
- quantizers-1.2.2/test/cpp_source/ap_types/hls_math.h +0 -27
- quantizers-1.2.2/test/cpp_source/ap_types/hls_stream.h +0 -263
- quantizers-1.2.2/test/cpp_source/ap_types/test.cpp +0 -22
- quantizers-1.2.2/test/cpp_source/ap_types/utils/x_hls_utils.h +0 -80
- quantizers-1.2.2/test/cpp_source/quantizers.h +0 -35
- quantizers-1.2.2/test/test_quantizer_match.py +0 -189
- quantizers-1.2.2/test/test_stateless_quantizer.py +0 -179
- {quantizers-1.2.2 → quantizers-2.0.0}/.clang-format +0 -0
- {quantizers-1.2.2 → quantizers-2.0.0}/.gitignore +0 -0
- {quantizers-1.2.2 → quantizers-2.0.0}/LICENSE +0 -0
- {quantizers-1.2.2 → quantizers-2.0.0}/setup.cfg +0 -0
- {quantizers-1.2.2 → quantizers-2.0.0}/src/quantizers/__init__.py +0 -0
- {quantizers-1.2.2 → quantizers-2.0.0}/src/quantizers.egg-info/dependency_links.txt +0 -0
- {quantizers-1.2.2 → quantizers-2.0.0}/src/quantizers.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: Upload Python Package
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
deploy:
|
|
12
|
+
environment:
|
|
13
|
+
name: pypi
|
|
14
|
+
url: https://pypi.org/p/quantizers
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
permissions:
|
|
17
|
+
id-token: write
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v7
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0
|
|
22
|
+
- name: Set up Python
|
|
23
|
+
uses: actions/setup-python@v7
|
|
24
|
+
with:
|
|
25
|
+
python-version: "3.14"
|
|
26
|
+
- name: Install dependencies
|
|
27
|
+
run: |
|
|
28
|
+
python -m pip install --upgrade pip
|
|
29
|
+
pip install build
|
|
30
|
+
- name: Build package
|
|
31
|
+
run: python -m build
|
|
32
|
+
- name: Publish package
|
|
33
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -9,24 +9,26 @@ jobs:
|
|
|
9
9
|
runs-on: ubuntu-latest
|
|
10
10
|
steps:
|
|
11
11
|
- name: Checkout
|
|
12
|
-
uses: actions/checkout@
|
|
12
|
+
uses: actions/checkout@v7
|
|
13
13
|
with:
|
|
14
14
|
fetch-depth: 0
|
|
15
15
|
|
|
16
16
|
- name: Set up Python
|
|
17
|
-
uses: actions/setup-python@
|
|
17
|
+
uses: actions/setup-python@v7
|
|
18
18
|
with:
|
|
19
|
-
python-version: 3.
|
|
19
|
+
python-version: '3.13'
|
|
20
|
+
cache-dependency-path: pyproject.toml
|
|
21
|
+
cache: 'pip'
|
|
20
22
|
|
|
21
23
|
- name: Install dependencies
|
|
22
24
|
run: |
|
|
23
|
-
|
|
25
|
+
pip install torch --index-url https://download.pytorch.org/whl/cpu # CPU-only: skips the CUDA wheels
|
|
24
26
|
pip install -e '.[test]'
|
|
25
27
|
|
|
26
28
|
- name: Run tests
|
|
27
|
-
run: pytest
|
|
29
|
+
run: pytest -n4
|
|
28
30
|
|
|
29
31
|
- name: Upload results to Codecov
|
|
30
|
-
uses: codecov/codecov-action@
|
|
32
|
+
uses: codecov/codecov-action@v7
|
|
31
33
|
with:
|
|
32
34
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
@@ -2,14 +2,14 @@ exclude: '\.svg$|ap_types/|_version.py'
|
|
|
2
2
|
|
|
3
3
|
repos:
|
|
4
4
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
5
|
-
rev: v0.
|
|
5
|
+
rev: v0.15.0
|
|
6
6
|
hooks:
|
|
7
7
|
- id: ruff
|
|
8
8
|
args: [--fix]
|
|
9
9
|
- id: ruff-format
|
|
10
10
|
|
|
11
11
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
12
|
-
rev:
|
|
12
|
+
rev: v6.0.0
|
|
13
13
|
hooks:
|
|
14
14
|
- id: check-added-large-files
|
|
15
15
|
- id: check-case-conflict
|
|
@@ -23,18 +23,18 @@ repos:
|
|
|
23
23
|
- id: trailing-whitespace
|
|
24
24
|
|
|
25
25
|
- repo: https://github.com/asottile/setup-cfg-fmt
|
|
26
|
-
rev:
|
|
26
|
+
rev: v3.2.0
|
|
27
27
|
hooks:
|
|
28
28
|
- id: setup-cfg-fmt
|
|
29
29
|
|
|
30
30
|
- repo: https://github.com/asottile/pyupgrade
|
|
31
|
-
rev: v3.
|
|
31
|
+
rev: v3.21.2
|
|
32
32
|
hooks:
|
|
33
33
|
- id: pyupgrade
|
|
34
34
|
args: ["--py310-plus"]
|
|
35
35
|
|
|
36
36
|
- repo: https://github.com/pre-commit/mirrors-clang-format
|
|
37
|
-
rev:
|
|
37
|
+
rev: v21.1.8
|
|
38
38
|
hooks:
|
|
39
39
|
- id: clang-format
|
|
40
40
|
types_or: [c++, c, cuda]
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: quantizers
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Author-email: Chang Sun <chsun@cern.ch>
|
|
5
|
+
License-Expression: LGPL-3.0-only
|
|
6
|
+
Project-URL: repository, https://github.com/calad0i/quantizers
|
|
7
|
+
Keywords: quantization
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Provides-Extra: keras
|
|
15
|
+
Requires-Dist: keras>=3.0.0; extra == "keras"
|
|
16
|
+
Provides-Extra: torch
|
|
17
|
+
Requires-Dist: torch>=2.12; extra == "torch"
|
|
18
|
+
Provides-Extra: test
|
|
19
|
+
Requires-Dist: pytest; extra == "test"
|
|
20
|
+
Requires-Dist: pytest-cov; extra == "test"
|
|
21
|
+
Requires-Dist: pytest-xdist; extra == "test"
|
|
22
|
+
Requires-Dist: pytest-env; extra == "test"
|
|
23
|
+
Requires-Dist: jax; extra == "test"
|
|
24
|
+
Requires-Dist: tensorflow; extra == "test"
|
|
25
|
+
Requires-Dist: torch; extra == "test"
|
|
26
|
+
Requires-Dist: tinygrad; extra == "test"
|
|
27
|
+
Requires-Dist: mlx[cpu]; extra == "test"
|
|
28
|
+
Requires-Dist: keras>=3.0.0; extra == "test"
|
|
29
|
+
Requires-Dist: triton; sys_platform == "linux" and extra == "test"
|
|
30
|
+
Dynamic: license-file
|
|
31
|
+
|
|
32
|
+
# Quantizers
|
|
33
|
+
[](https://badge.fury.io/py/quantizers)
|
|
34
|
+
[](LICENSE)
|
|
35
|
+
[](https://github.com/calad0i/quantizers/actions/workflows/python-test.yml)
|
|
36
|
+
[](https://app.codecov.io/gh/calad0i/quantizers)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
Hardware-oriented numerical quantizers for deep learning models: same quantizers for `numpy`, `jax`, `torch`, `tensorflow`, `mlx`, `tinygrad`, plus keras 3 variables ones and triton device functions for custom kernels. Bit-exact with the fixed-point and floating-point types of Siemens HLS libraries (`ac_types`), and differentiable through each framework's autodiff when available.
|
|
40
|
+
|
|
41
|
+
## Features
|
|
42
|
+
|
|
43
|
+
- Bit-accurate fixed-point and minifloat quantization, tested against [ac_types](https://github.com/hlslibs/ac_types)' `ac_fixed` and `ac_std_float`
|
|
44
|
+
- `einops` like multi framework dispatched based on the tensor type and lazy import
|
|
45
|
+
- Differentiable, through each framework's own autodiff (and XLA/JIT compilation like `torch.compile`, `jax.jit`, `tf.function`)
|
|
46
|
+
- Surrogate gradients on the bit widths as described in [HGQ [FPGA'26]](https://doi.org/10.1145/3748173.3779200)
|
|
47
|
+
- Triton device functions of every quantizer with vjps for use in custom kernels
|
|
48
|
+
|
|
49
|
+
## Supported Quantizers
|
|
50
|
+
|
|
51
|
+
### Fixed-Point Quantizer
|
|
52
|
+
|
|
53
|
+
Parameters:
|
|
54
|
+
- `k` (keep_negative): Enable negative numbers
|
|
55
|
+
- `i` (integer_bits): Number of bits before decimal point (excludes sign bit)
|
|
56
|
+
- `f` (fractional_bits): Number of bits after decimal point
|
|
57
|
+
- For C++: `W = k + i + f`, `I = k + i`, `S = k`
|
|
58
|
+
|
|
59
|
+
Supported modes:
|
|
60
|
+
- Rounding: `TRN`, `RND`, `RND_CONV`, `TRN_ZERO`, `RND_ZERO`, `RND_MIN_INF`, `RND_INF`
|
|
61
|
+
- Overflow: `WRAP`, `SAT`, `SAT_SYM`, `SAT_ZERO`
|
|
62
|
+
|
|
63
|
+
Gradients:
|
|
64
|
+
- `x`: passed through, except where the value saturates, wraps or is zeroed
|
|
65
|
+
- `i`, `f`: surrogate gradients; `WRAP` and `SAT_ZERO` give none on `i`
|
|
66
|
+
- Zero width (`k + i + f <= 0`): the value is 0, the gradients are left as they are; `null_xgrad_on_zero_width=True` drops the gradient on `x` there
|
|
67
|
+
|
|
68
|
+
Differences from `ap_fixed`: a signed 1-bit `SAT_SYM` gives 0, the only symmetric value (`ap_fixed` keeps `{-1, 0}`), and `WRAP_SM` is not supported.
|
|
69
|
+
|
|
70
|
+
### Minifloat Quantizer
|
|
71
|
+
|
|
72
|
+
Parameters:
|
|
73
|
+
- `m` (mantissa_bits): Mantissa width, excluding the implicit leading bit
|
|
74
|
+
- `e` (exponent_bits): Exponent width
|
|
75
|
+
- `e0` (exponent_zero): Exponent bias, default 1 (IEEE's bias)
|
|
76
|
+
- Normal exponents: `[e0 + 1 - 2^(e-1), e0 - 1 + 2^(e-1)]`
|
|
77
|
+
|
|
78
|
+
Features:
|
|
79
|
+
- Supports subnormal numbers
|
|
80
|
+
- No inf or NaN encodings: the top exponent holds numbers, value beyond the maximum saturates
|
|
81
|
+
- `RND_CONV` rounding for all
|
|
82
|
+
|
|
83
|
+
### Simplified Quantizers
|
|
84
|
+
|
|
85
|
+
- **Binary**: Maps to {-1, 1}, with 0 to 1. Gradient of tanh
|
|
86
|
+
- **Ternary**: Maps to {-1, 0, 1}, i.e. fixed-point `fixed<2, 2, RND_CONV, SAT_SYM>`. Gradient of tanh
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
## Installation
|
|
90
|
+
|
|
91
|
+
**requires python>=3.10**
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
pip install quantizers
|
|
95
|
+
```
|
|
96
|
+
numpy arrays and python scalars need `numpy`. Otherwise, no dependency is required beyond the particular framework you already have. For keras, install `keras>=3.0.0` is expected.
|
|
97
|
+
|
|
98
|
+
## Usage
|
|
99
|
+
|
|
100
|
+
### Stateless Quantizers
|
|
101
|
+
```python
|
|
102
|
+
from quantizers import FixedPointQuantizer, binary_quantize, fixed_quantize, float_quantize, ternary_quantize
|
|
103
|
+
|
|
104
|
+
# Fixed-point: x, k, i, f are tensors of one framework (or python scalars), broadcast together
|
|
105
|
+
quantizer = FixedPointQuantizer(round_mode='RND', overflow_mode='SAT')
|
|
106
|
+
xq = quantizer(x, k, i, f)
|
|
107
|
+
xq = fixed_quantize(x, k, i, f, round_mode='RND', overflow_mode='SAT') # shortcut for the above
|
|
108
|
+
xq = quantizer.round(x, f) # rounding to f fractional bits only, without overflow handling
|
|
109
|
+
|
|
110
|
+
# Minifloat
|
|
111
|
+
xq = float_quantize(x, mantissa_bits, exponent_bits, exponent_zero)
|
|
112
|
+
|
|
113
|
+
# Simplified quantizers
|
|
114
|
+
xq = binary_quantize(x)
|
|
115
|
+
xq = ternary_quantize(x)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Stateful Quantizers
|
|
119
|
+
```python
|
|
120
|
+
from quantizers import BinaryQ, FixedQ, MinifloatQ, TernaryQ
|
|
121
|
+
|
|
122
|
+
# Fixed formats, for inference and testing; for training use the stateless ones
|
|
123
|
+
fixed_q = FixedQ(width, integer_bits, signed, rounding='RND', overflow='SAT') # integer_bits includes the sign bit
|
|
124
|
+
xq = fixed_q(x)
|
|
125
|
+
|
|
126
|
+
mfloat_q = MinifloatQ(mantissa_bits, exponent_bits, exponent_zero)
|
|
127
|
+
xq = mfloat_q(x)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Triton Device Functions
|
|
131
|
+
```python
|
|
132
|
+
import triton
|
|
133
|
+
import triton.language as tl
|
|
134
|
+
from quantizers import triton as qt
|
|
135
|
+
|
|
136
|
+
@triton.jit
|
|
137
|
+
def kernel(x_ptr, i_ptr, f_ptr, g_ptr, y_ptr, dx_ptr, di_ptr, df_ptr, BLOCK: tl.constexpr):
|
|
138
|
+
o = tl.program_id(0) * BLOCK + tl.arange(0, BLOCK)
|
|
139
|
+
x, i, f, g = tl.load(x_ptr + o), tl.load(i_ptr + o), tl.load(f_ptr + o), tl.load(g_ptr + o)
|
|
140
|
+
tl.store(y_ptr + o, qt.fixed_quantize(x, 1, i, f, 'RND', 'SAT'))
|
|
141
|
+
dx, dk, di, df = qt.fixed_quantize_vjp(x, 1, i, f, g, 'RND', 'SAT')
|
|
142
|
+
...
|
|
143
|
+
```
|
|
144
|
+
- `fixed_quantize`, `fixed_round`, `float_quantize`, `binary_quantize`, `ternary_quantize`, each with a `_vjp`, and `float_decompose`
|
|
145
|
+
- Elementwise in float32 over the operands broadcast together (tensors of any dtype, or scalars); modes are constexpr strings
|
|
146
|
+
- A `_vjp` takes the cotangent `g` of the value and returns the cotangent of every operand, of the broadcast shape: reduce those of broadcast operands in the kernel
|
|
147
|
+
- Values match the JAX backend bit for bit on finite floats of the normal range, gradients to float32 rounding
|
|
148
|
+
- Kernels using them recompile when quantizers changes; with `TRITON_INTERPRET=1` they run in Triton's CPU interpreter
|
|
149
|
+
|
|
150
|
+
## Development
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
pip install -e '.[test]'
|
|
154
|
+
pytest -n auto
|
|
155
|
+
```
|
|
156
|
+
The tests compare against a C++ reference built with `make` on the first run (a C++ compiler is needed) and run on the CPU only, Triton kernels in its interpreter.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Quantizers
|
|
2
|
+
[](https://badge.fury.io/py/quantizers)
|
|
3
|
+
[](LICENSE)
|
|
4
|
+
[](https://github.com/calad0i/quantizers/actions/workflows/python-test.yml)
|
|
5
|
+
[](https://app.codecov.io/gh/calad0i/quantizers)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
Hardware-oriented numerical quantizers for deep learning models: same quantizers for `numpy`, `jax`, `torch`, `tensorflow`, `mlx`, `tinygrad`, plus keras 3 variables ones and triton device functions for custom kernels. Bit-exact with the fixed-point and floating-point types of Siemens HLS libraries (`ac_types`), and differentiable through each framework's autodiff when available.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- Bit-accurate fixed-point and minifloat quantization, tested against [ac_types](https://github.com/hlslibs/ac_types)' `ac_fixed` and `ac_std_float`
|
|
13
|
+
- `einops` like multi framework dispatched based on the tensor type and lazy import
|
|
14
|
+
- Differentiable, through each framework's own autodiff (and XLA/JIT compilation like `torch.compile`, `jax.jit`, `tf.function`)
|
|
15
|
+
- Surrogate gradients on the bit widths as described in [HGQ [FPGA'26]](https://doi.org/10.1145/3748173.3779200)
|
|
16
|
+
- Triton device functions of every quantizer with vjps for use in custom kernels
|
|
17
|
+
|
|
18
|
+
## Supported Quantizers
|
|
19
|
+
|
|
20
|
+
### Fixed-Point Quantizer
|
|
21
|
+
|
|
22
|
+
Parameters:
|
|
23
|
+
- `k` (keep_negative): Enable negative numbers
|
|
24
|
+
- `i` (integer_bits): Number of bits before decimal point (excludes sign bit)
|
|
25
|
+
- `f` (fractional_bits): Number of bits after decimal point
|
|
26
|
+
- For C++: `W = k + i + f`, `I = k + i`, `S = k`
|
|
27
|
+
|
|
28
|
+
Supported modes:
|
|
29
|
+
- Rounding: `TRN`, `RND`, `RND_CONV`, `TRN_ZERO`, `RND_ZERO`, `RND_MIN_INF`, `RND_INF`
|
|
30
|
+
- Overflow: `WRAP`, `SAT`, `SAT_SYM`, `SAT_ZERO`
|
|
31
|
+
|
|
32
|
+
Gradients:
|
|
33
|
+
- `x`: passed through, except where the value saturates, wraps or is zeroed
|
|
34
|
+
- `i`, `f`: surrogate gradients; `WRAP` and `SAT_ZERO` give none on `i`
|
|
35
|
+
- Zero width (`k + i + f <= 0`): the value is 0, the gradients are left as they are; `null_xgrad_on_zero_width=True` drops the gradient on `x` there
|
|
36
|
+
|
|
37
|
+
Differences from `ap_fixed`: a signed 1-bit `SAT_SYM` gives 0, the only symmetric value (`ap_fixed` keeps `{-1, 0}`), and `WRAP_SM` is not supported.
|
|
38
|
+
|
|
39
|
+
### Minifloat Quantizer
|
|
40
|
+
|
|
41
|
+
Parameters:
|
|
42
|
+
- `m` (mantissa_bits): Mantissa width, excluding the implicit leading bit
|
|
43
|
+
- `e` (exponent_bits): Exponent width
|
|
44
|
+
- `e0` (exponent_zero): Exponent bias, default 1 (IEEE's bias)
|
|
45
|
+
- Normal exponents: `[e0 + 1 - 2^(e-1), e0 - 1 + 2^(e-1)]`
|
|
46
|
+
|
|
47
|
+
Features:
|
|
48
|
+
- Supports subnormal numbers
|
|
49
|
+
- No inf or NaN encodings: the top exponent holds numbers, value beyond the maximum saturates
|
|
50
|
+
- `RND_CONV` rounding for all
|
|
51
|
+
|
|
52
|
+
### Simplified Quantizers
|
|
53
|
+
|
|
54
|
+
- **Binary**: Maps to {-1, 1}, with 0 to 1. Gradient of tanh
|
|
55
|
+
- **Ternary**: Maps to {-1, 0, 1}, i.e. fixed-point `fixed<2, 2, RND_CONV, SAT_SYM>`. Gradient of tanh
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
## Installation
|
|
59
|
+
|
|
60
|
+
**requires python>=3.10**
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install quantizers
|
|
64
|
+
```
|
|
65
|
+
numpy arrays and python scalars need `numpy`. Otherwise, no dependency is required beyond the particular framework you already have. For keras, install `keras>=3.0.0` is expected.
|
|
66
|
+
|
|
67
|
+
## Usage
|
|
68
|
+
|
|
69
|
+
### Stateless Quantizers
|
|
70
|
+
```python
|
|
71
|
+
from quantizers import FixedPointQuantizer, binary_quantize, fixed_quantize, float_quantize, ternary_quantize
|
|
72
|
+
|
|
73
|
+
# Fixed-point: x, k, i, f are tensors of one framework (or python scalars), broadcast together
|
|
74
|
+
quantizer = FixedPointQuantizer(round_mode='RND', overflow_mode='SAT')
|
|
75
|
+
xq = quantizer(x, k, i, f)
|
|
76
|
+
xq = fixed_quantize(x, k, i, f, round_mode='RND', overflow_mode='SAT') # shortcut for the above
|
|
77
|
+
xq = quantizer.round(x, f) # rounding to f fractional bits only, without overflow handling
|
|
78
|
+
|
|
79
|
+
# Minifloat
|
|
80
|
+
xq = float_quantize(x, mantissa_bits, exponent_bits, exponent_zero)
|
|
81
|
+
|
|
82
|
+
# Simplified quantizers
|
|
83
|
+
xq = binary_quantize(x)
|
|
84
|
+
xq = ternary_quantize(x)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Stateful Quantizers
|
|
88
|
+
```python
|
|
89
|
+
from quantizers import BinaryQ, FixedQ, MinifloatQ, TernaryQ
|
|
90
|
+
|
|
91
|
+
# Fixed formats, for inference and testing; for training use the stateless ones
|
|
92
|
+
fixed_q = FixedQ(width, integer_bits, signed, rounding='RND', overflow='SAT') # integer_bits includes the sign bit
|
|
93
|
+
xq = fixed_q(x)
|
|
94
|
+
|
|
95
|
+
mfloat_q = MinifloatQ(mantissa_bits, exponent_bits, exponent_zero)
|
|
96
|
+
xq = mfloat_q(x)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Triton Device Functions
|
|
100
|
+
```python
|
|
101
|
+
import triton
|
|
102
|
+
import triton.language as tl
|
|
103
|
+
from quantizers import triton as qt
|
|
104
|
+
|
|
105
|
+
@triton.jit
|
|
106
|
+
def kernel(x_ptr, i_ptr, f_ptr, g_ptr, y_ptr, dx_ptr, di_ptr, df_ptr, BLOCK: tl.constexpr):
|
|
107
|
+
o = tl.program_id(0) * BLOCK + tl.arange(0, BLOCK)
|
|
108
|
+
x, i, f, g = tl.load(x_ptr + o), tl.load(i_ptr + o), tl.load(f_ptr + o), tl.load(g_ptr + o)
|
|
109
|
+
tl.store(y_ptr + o, qt.fixed_quantize(x, 1, i, f, 'RND', 'SAT'))
|
|
110
|
+
dx, dk, di, df = qt.fixed_quantize_vjp(x, 1, i, f, g, 'RND', 'SAT')
|
|
111
|
+
...
|
|
112
|
+
```
|
|
113
|
+
- `fixed_quantize`, `fixed_round`, `float_quantize`, `binary_quantize`, `ternary_quantize`, each with a `_vjp`, and `float_decompose`
|
|
114
|
+
- Elementwise in float32 over the operands broadcast together (tensors of any dtype, or scalars); modes are constexpr strings
|
|
115
|
+
- A `_vjp` takes the cotangent `g` of the value and returns the cotangent of every operand, of the broadcast shape: reduce those of broadcast operands in the kernel
|
|
116
|
+
- Values match the JAX backend bit for bit on finite floats of the normal range, gradients to float32 rounding
|
|
117
|
+
- Kernels using them recompile when quantizers changes; with `TRITON_INTERPRET=1` they run in Triton's CPU interpreter
|
|
118
|
+
|
|
119
|
+
## Development
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
pip install -e '.[test]'
|
|
123
|
+
pytest -n auto
|
|
124
|
+
```
|
|
125
|
+
The tests compare against a C++ reference built with `make` on the first run (a C++ compiler is needed) and run on the CPU only, Triton kernels in its interpreter.
|
|
@@ -1,79 +1,74 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
requires = ["setuptools>=
|
|
2
|
+
requires = ["setuptools>=77", "setuptools_scm>=8"]
|
|
3
3
|
|
|
4
4
|
build-backend = "setuptools.build_meta"
|
|
5
5
|
|
|
6
6
|
[project]
|
|
7
7
|
name = "quantizers"
|
|
8
|
-
version = "1.2.2"
|
|
9
8
|
authors = [{ name = "Chang Sun", email = "chsun@cern.ch" }]
|
|
10
9
|
description = ""
|
|
11
10
|
readme = "README.md"
|
|
12
11
|
requires-python = ">=3.10"
|
|
13
|
-
license =
|
|
12
|
+
license = "LGPL-3.0-only"
|
|
13
|
+
license-files = ["LICENSE"]
|
|
14
14
|
keywords = ["quantization"]
|
|
15
15
|
|
|
16
16
|
classifiers = [
|
|
17
17
|
"Programming Language :: Python :: 3",
|
|
18
18
|
"Operating System :: OS Independent",
|
|
19
|
-
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
|
|
20
19
|
"Development Status :: 5 - Production/Stable",
|
|
21
20
|
]
|
|
21
|
+
dynamic = ["version"]
|
|
22
|
+
|
|
22
23
|
|
|
23
24
|
[project.urls]
|
|
24
25
|
repository = "https://github.com/calad0i/quantizers"
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
[tool.setuptools]
|
|
28
|
-
packages = ["quantizers"]
|
|
29
29
|
include-package-data = true
|
|
30
|
-
|
|
30
|
+
|
|
31
|
+
[tool.setuptools.packages.find]
|
|
32
|
+
where = ["src"]
|
|
31
33
|
|
|
32
34
|
|
|
33
35
|
[tool.setuptools_scm]
|
|
34
36
|
write_to = "src/quantizers/_version.py"
|
|
35
37
|
|
|
36
38
|
[project.optional-dependencies]
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
grad = ['keras>=3.10']
|
|
39
|
+
keras = ["keras>=3.0.0"]
|
|
40
|
+
torch = ["torch>=2.12"]
|
|
40
41
|
test = [
|
|
41
42
|
'pytest',
|
|
42
43
|
'pytest-cov',
|
|
43
44
|
'pytest-xdist',
|
|
44
45
|
'pytest-env',
|
|
45
|
-
'keras>=3.0',
|
|
46
|
-
'cppyy',
|
|
47
46
|
'jax',
|
|
47
|
+
'tensorflow',
|
|
48
|
+
'torch',
|
|
49
|
+
'tinygrad',
|
|
50
|
+
'mlx[cpu]',
|
|
51
|
+
'keras>=3.0.0',
|
|
52
|
+
'triton; sys_platform == "linux"',
|
|
48
53
|
]
|
|
49
54
|
|
|
50
55
|
[tool.pytest.ini_options]
|
|
51
|
-
filterwarnings = [
|
|
52
|
-
"ignore:WARNING\\W Pytorch converter is not enabled!:UserWarning",
|
|
53
|
-
"ignore:.\\[93mcover_factor<1.0 will likely to result in overflows:UserWarning",
|
|
54
|
-
"ignore:You are saving your model as an HDF5 file:UserWarning",
|
|
55
|
-
"ignore:Even though the `tf.config.experimental_run_functions_eagerly`:UserWarning",
|
|
56
|
-
"ignore:pkg_resources is deprecated as an API:DeprecationWarning",
|
|
57
|
-
"ignore:distutils Version classes are deprecated:DeprecationWarning",
|
|
58
|
-
"ignore:module 'sre_constants' is deprecated:DeprecationWarning",
|
|
59
|
-
"ignore:Deprecated call to `pkg_resources.declare_namespace:DeprecationWarning",
|
|
60
|
-
]
|
|
56
|
+
filterwarnings = []
|
|
61
57
|
|
|
62
|
-
env = [
|
|
63
|
-
"KERAS_BACKEND=jax",
|
|
64
|
-
"JAX_PLATFORMS=cpu",
|
|
65
|
-
"CUDA_VISIBLE_DEVICES=-1",
|
|
66
|
-
"CLING_ENABLE_CUDA=0",
|
|
67
|
-
]
|
|
58
|
+
env = ["JAX_PLATFORMS=cpu", "CUDA_VISIBLE_DEVICES=-1", "TRITON_INTERPRET=1"]
|
|
68
59
|
|
|
60
|
+
pythonpath = ["test"]
|
|
69
61
|
addopts = "--import-mode=importlib --cov=src/quantizers --cov-report=xml --cov-report=html"
|
|
70
62
|
|
|
71
63
|
[tool.coverage.run]
|
|
72
64
|
omit = ["*/_version.py"]
|
|
65
|
+
patch = ["subprocess"]
|
|
73
66
|
|
|
74
67
|
[tool.coverage.report]
|
|
75
|
-
|
|
76
|
-
|
|
68
|
+
exclude_also = [
|
|
69
|
+
'^[ \t]*\.\.\.[ \t]*(?:#.*)?$',
|
|
70
|
+
'^[ \t]*raise NotImplementedError\b',
|
|
71
|
+
]
|
|
77
72
|
[tool.ruff]
|
|
78
73
|
include = ["src/**/*.py"]
|
|
79
74
|
|