Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion .github/workflows/publish_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
- name: Install Python 3
uses: actions/setup-python@v5
with:
python-version: 3.8
python-version: 3.11
- name: Install dependencies
run: |
python -m pip install --upgrade pip
Expand Down
8 changes: 1 addition & 7 deletions .github/workflows/run_tests_suite_pip.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ name: Test pip install
on:
workflow_dispatch: # Allow manual triggers
inputs:
mct_quantizers_version:
description: 'MCT Quantizers version'
required: true
default: 'v1.6.0'
python_version:
description: 'Python version'
required: false
Expand All @@ -24,7 +20,6 @@ jobs:
python-version: ${{ inputs.python_version }}
- name: Install dependencies
run: |
git checkout tags/${{ inputs.mct_quantizers_version }}
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install twine wheel
Expand Down Expand Up @@ -58,5 +53,4 @@ jobs:
pip install torch==2.6.* torchvision "onnx<1.18" "onnxruntime<1.22" "onnxruntime-extensions<0.14"
- name: Run Torch Tests
run: |
python -m unittest discover tests/pytorch_tests --verbose

python -m unittest discover tests/pytorch_tests --verbose
2 changes: 1 addition & 1 deletion .github/workflows/run_various_python_versions_tf.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
timeout-minutes: 10
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11"]
python-version: ["3.10", "3.11"]
steps:
- uses: actions/checkout@v4
- name: Install Python ${{ matrix.python-version }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/run_various_python_versions_torch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
timeout-minutes: 10
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12"]
python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- name: Install Python ${{ matrix.python-version }}
Expand Down
27 changes: 11 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,22 @@ Users can set the quantizers and all the quantization information for each layer

Please note that the quantization wrapper and the quantizers are framework-specific.

<img src="https://github.com/sony/mct_quantizers/raw/main/quantization_infra.png" width="700">
<img src="https://github.com/SonySemiconductorSolutions/mct-quantization-layers/raw/main/quantization_infra.png" width="700">

## Quantizers:

The library provides the "Inferable Quantizer" interface for implementing new quantizers.
This interface is based on the [`BaseInferableQuantizer`](https://github.com/sony/mct_quantizers/blob/main/mct_quantizers/common/base_inferable_quantizer.py) class, which allows the definition of quantizers used for emulating inference-time quantization.
This interface is based on the [`BaseInferableQuantizer`](https://github.com/SonySemiconductorSolutions/mct-quantization-layers/blob/main/mct_quantizers/common/base_inferable_quantizer.py) class, which allows the definition of quantizers used for emulating inference-time quantization.

On top of `BaseInferableQuantizer` the library defines a set of framework-specific quantizers for both weights and activations:
1. [Keras Quantizers](https://github.com/sony/mct_quantizers/tree/main/mct_quantizers/keras/quantizers)
2. [Pytorch Quantizers](https://github.com/sony/mct_quantizers/tree/main/mct_quantizers/pytorch/quantizers)
1. [Keras Quantizers](https://github.com/SonySemiconductorSolutions/mct-quantization-layers/tree/main/mct_quantizers/keras/quantizers)
2. [Pytorch Quantizers](https://github.com/SonySemiconductorSolutions/mct-quantization-layers/tree/main/mct_quantizers/pytorch/quantizers)

### The mark_quantizer Decorator

The [`@mark_quantizer`](https://github.com/sony/mct_quantizers/blob/main/mct_quantizers/common/base_inferable_quantizer.py) decorator is used to assign each quantizer with static properties that define its task compatibility. Each quantizer class should be decorated with this decorator, which defines the following properties:
- [`QuantizationTarget`](https://github.com/sony/mct_quantizers/blob/main/mct_quantizers/common/base_inferable_quantizer.py): An Enum that indicates whether the quantizer is intended for weights or activations quantization.
- [`QuantizationMethod`](https://github.com/sony/mct_quantizers/blob/main/mct_quantizers/common/quant_info.py): A list of quantization methods (Uniform, Symmetric, etc.).
The [`@mark_quantizer`](https://github.com/SonySemiconductorSolutions/mct-quantization-layers/blob/main/mct_quantizers/common/base_inferable_quantizer.py) decorator is used to assign each quantizer with static properties that define its task compatibility. Each quantizer class should be decorated with this decorator, which defines the following properties:
- [`QuantizationTarget`](https://github.com/SonySemiconductorSolutions/mct-quantization-layers/blob/main/mct_quantizers/common/base_inferable_quantizer.py): An Enum that indicates whether the quantizer is intended for weights or activations quantization.
- [`QuantizationMethod`](https://github.com/SonySemiconductorSolutions/mct-quantization-layers/blob/main/mct_quantizers/common/quant_info.py): A list of quantization methods (Uniform, Symmetric, etc.).
- `identifier`: A unique identifier for the quantizer class. This is a helper property that allows the creation of advanced quantizers for specific tasks.

## Getting Started
Expand All @@ -45,16 +45,11 @@ To install the latest stable release of MCT Quantizer from PyPi, run the followi
pip install mct-quantizers
```

If you prefer to use the nightly package (unstable version), you can install it with the following command:
```
pip install mct-quantizers-nightly
```

#### From Source
To work with the MCT Quantizers source code, follow these steps:
```
git clone https://github.com/sony/mct_quantizers.git
cd mct_quantizers
git clone https://github.com/SonySemiconductorSolutions/mct-quantization-layers.git
cd mct-quantization-layers
python setup.py install
```

Expand All @@ -68,7 +63,7 @@ For use with Tensorflow, please install the following package:
For use with PyTorch, please install the following package:
[torch](https://pytorch.org/)

You can also use the [requirements](https://github.com/sony/mct_quantizers/blob/main/requirements.txt) file to set up your environment.
You can also use the [requirements](https://github.com/SonySemiconductorSolutions/mct-quantization-layers/blob/main/requirements.txt) file to set up your environment.

## License
[Apache License 2.0](https://github.com/sony/mct_quantizers/blob/main/LICENSE.md).
[Apache License 2.0](https://github.com/SonySemiconductorSolutions/mct-quantization-layers/blob/main/LICENSE.md).
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,5 @@ def get_release_arguments():
"Topic :: Scientific/Engineering :: Artificial Intelligence"
],
install_requires=read_install_requires(),
python_requires='>=3.9'
python_requires='>=3.10'
)
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,34 @@

def _build_model_with_quantization_holder(act_layer, quant_activation_holder, input_shape, model_name):
inputs = tf.keras.layers.Input(shape=input_shape)
x = tf.keras.layers.Conv2D(filters=3, kernel_size=4)(inputs)
# If all conv outputs are negative, the ReLU output will be 0, causing a quantizer validation error.
# To include positive and negative values ​​in the conv outputs, we set the conv weights to positive values.
# Also set the upper half of the input tensor to positive and the lower half to negative.
conv = tf.keras.layers.Conv2D(filters=3, kernel_size=4)
conv.build(input_shape=input_shape)
kernel, bias = conv.get_weights()
conv.set_weights([np.abs(kernel), bias])
x = conv(inputs)
act_output = act_layer(x)
quant_output = quant_activation_holder(act_output)
return tf.keras.Model(inputs=inputs, outputs=[quant_output, act_output], name=model_name)


def _build_model_with_operator_quantization_holder(act_layer, quant_activation_holder, input_shape, model_name):
inputs = tf.keras.layers.Input(shape=input_shape)
x = tf.keras.layers.Conv2D(filters=3, kernel_size=4)(inputs)
y = tf.keras.layers.Conv2D(filters=3, kernel_size=4)(inputs)
# If all conv outputs are negative, the ReLU output will be 0, causing a quantizer validation error.
# To include positive and negative values ​​in the conv outputs, we set the conv weights to positive values.
# Also set the upper half of the input tensor to positive and the lower half to negative.
conv1 = tf.keras.layers.Conv2D(filters=3, kernel_size=4)
conv1.build(input_shape=input_shape)
kernel1, bias1 = conv1.get_weights()
conv1.set_weights([np.abs(kernel1), bias1])
conv2 = tf.keras.layers.Conv2D(filters=3, kernel_size=4)
conv2.build(input_shape=input_shape)
kernel2, bias2 = conv2.get_weights()
conv2.set_weights([np.abs(kernel2), bias2])
x = conv1(inputs)
y = conv2(inputs)
act_output = act_layer([x, y])
quant_output = quant_activation_holder(act_output)
return tf.keras.Model(inputs=inputs, outputs=[quant_output, act_output], name=model_name)
Expand Down Expand Up @@ -98,7 +116,14 @@ def build_and_save_model(self, quantizer, quantizer_params, layer, model_name, i
self.assertEqual(len(quant_holder_layer), 1)

# Verifying activation quantization after holder
output = model(np.random.randn(1, *input_shape))
# If all conv outputs are negative, the ReLU output will be 0, causing a quantizer validation error.
# To include positive and negative values ​​in the conv outputs, we set the conv weights to positive values.
# Also set the upper half of the input tensor to positive and the lower half to negative.
rand_inp = np.random.randn(1, *input_shape)
sign = np.ones((1, *input_shape))
sign[:, rand_inp.shape[1]//2:, :, :] = -1
rand_inp = rand_inp * sign
output = model(rand_inp)
self.assertTrue(np.any(output[0] != output[1]), "Expecting activation layer output to be different "
"from the activation holder layer output, which should be "
"quantized.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,13 @@ def _build_model_with_quantization_holder(act_layer, quant_activation_holder, in
class Model(torch.nn.Module):
def __init__(self):
super(Model, self).__init__()
# If all conv outputs are negative, the ReLU output will be 0, causing a quantizer validation error.
# To include positive and negative values ​​in the conv outputs, we set the conv weights to positive values.
# Also set the upper half of the input tensor to positive and the lower half to negative.
self.conv = torch.nn.Conv2d(in_channels=3, out_channels=3, kernel_size=4)
with torch.no_grad():
weight = self.conv.weight.abs()
self.conv.weight.copy_(weight)
self.act_layer = act_layer
self.quant_activation_holder = quant_activation_holder

Expand All @@ -74,8 +80,16 @@ def _build_model_with_operator_quantization_holder(act_layer, quant_activation_h
class Model(torch.nn.Module):
def __init__(self):
super(Model, self).__init__()
# If all conv outputs are negative, the ReLU output will be 0, causing a quantizer validation error.
# To include positive and negative values ​​in the conv outputs, we set the conv weights to positive values.
# Also set the upper half of the input tensor to positive and the lower half to negative.
self.conv1 = torch.nn.Conv2d(in_channels=3, out_channels=3, kernel_size=4)
self.conv2 = torch.nn.Conv2d(in_channels=3, out_channels=3, kernel_size=4)
with torch.no_grad():
weight1 = self.conv1.weight.abs()
self.conv1.weight.copy_(weight1)
weight2 = self.conv2.weight.abs()
self.conv2.weight.copy_(weight2)
self.act_layer = act_layer
self.quant_activation_holder = quant_activation_holder

Expand Down Expand Up @@ -115,7 +129,13 @@ def build_and_save_model(self, quantizer, quantizer_params, layer, model_name, i
quant_holder_layer = [_l for _, _l in model.named_modules() if isinstance(_l, PytorchActivationQuantizationHolder)]
self.assertEqual(len(quant_holder_layer), 1)

# If all conv outputs are negative, the ReLU output will be 0, causing a quantizer validation error.
# To include positive and negative values ​​in the conv outputs, we set the conv weights to positive values.
# Also set the upper half of the input tensor to positive and the lower half to negative.
rand_inp = torch.rand(1, *input_shape).to(BaseActivationQuantizerBuildAndSaveTest.device)
sign = torch.ones(1, *input_shape)
sign[:, :, rand_inp.shape[2]//2:, :] = -1
rand_inp = rand_inp * sign
model = model.to(BaseActivationQuantizerBuildAndSaveTest.device)

# Verifying activation quantization after holder
Expand Down