ai-edge-quantizer-nightly 0.1.0.dev20250328__py3-none-any.whl → 0.1.0.dev20250329__py3-none-any.whl
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.
- ai_edge_quantizer/algorithm_manager.py +1 -0
- ai_edge_quantizer/algorithms/uniform_quantize/dequantized_weight_recovery.py +25 -29
- ai_edge_quantizer/algorithms/uniform_quantize/dequantized_weight_recovery_test.py +35 -12
- {ai_edge_quantizer_nightly-0.1.0.dev20250328.dist-info → ai_edge_quantizer_nightly-0.1.0.dev20250329.dist-info}/METADATA +1 -1
- {ai_edge_quantizer_nightly-0.1.0.dev20250328.dist-info → ai_edge_quantizer_nightly-0.1.0.dev20250329.dist-info}/RECORD +8 -8
- {ai_edge_quantizer_nightly-0.1.0.dev20250328.dist-info → ai_edge_quantizer_nightly-0.1.0.dev20250329.dist-info}/LICENSE +0 -0
- {ai_edge_quantizer_nightly-0.1.0.dev20250328.dist-info → ai_edge_quantizer_nightly-0.1.0.dev20250329.dist-info}/WHEEL +0 -0
- {ai_edge_quantizer_nightly-0.1.0.dev20250328.dist-info → ai_edge_quantizer_nightly-0.1.0.dev20250329.dist-info}/top_level.txt +0 -0
@@ -170,6 +170,7 @@ register_config_check_policy_func(
|
|
170
170
|
|
171
171
|
DEQUANTIZED_WEIGHT_RECOVERY_OP_NAME_MATERIALIZE_FUNC_DICT = {
|
172
172
|
_TFLOpName.FULLY_CONNECTED: common_quantize.materialize_fc_conv,
|
173
|
+
_TFLOpName.CONV_2D: common_quantize.materialize_fc_conv,
|
173
174
|
_TFLOpName.EMBEDDING_LOOKUP: common_quantize.materialize_embedding_lookup,
|
174
175
|
}
|
175
176
|
|
@@ -70,17 +70,17 @@ def _get_scale(arr: np.ndarray, min_scale: float) -> float:
|
|
70
70
|
return min_scale
|
71
71
|
|
72
72
|
|
73
|
-
def
|
73
|
+
def get_zp_scale_from_dequantized_symmetric_weights(
|
74
74
|
dequant_vals: np.ndarray,
|
75
75
|
quantized_dimension: Optional[int] = None,
|
76
76
|
min_scale: float = 1e-9,
|
77
77
|
) -> tuple[np.ndarray, np.ndarray]:
|
78
|
-
"""Calculates scale and zero point from
|
78
|
+
"""Calculates scale and zero point from dequantized and symmetric weights.
|
79
79
|
|
80
80
|
Handles both per-tensor and per-channel (axis) quantization.
|
81
81
|
|
82
82
|
Args:
|
83
|
-
dequant_vals: The
|
83
|
+
dequant_vals: The dequantized weight values (numpy array).
|
84
84
|
quantized_dimension: The dimension along which quantization was performed
|
85
85
|
(0 or 1), or None for per-tensor quantization.
|
86
86
|
min_scale: The minimum allowed scale value.
|
@@ -91,15 +91,9 @@ def get_zp_scale_from_2d_dequantized_symmetric_weights(
|
|
91
91
|
- scales: Scales (scalar for per-tensor, array for per-channel).
|
92
92
|
|
93
93
|
Raises:
|
94
|
-
ValueError: If `
|
95
|
-
`quantized_dimension` is not 0, 1, or None.
|
94
|
+
ValueError: If `quantized_dimension` is not 0, 1, or None.
|
96
95
|
"""
|
97
96
|
|
98
|
-
if dequant_vals.ndim != 2:
|
99
|
-
raise ValueError(
|
100
|
-
f"Only 2D weights are supported. Got {dequant_vals.ndim} dimensions."
|
101
|
-
)
|
102
|
-
|
103
97
|
if quantized_dimension not in (0, 1, None):
|
104
98
|
raise ValueError(
|
105
99
|
f"quantized_dimension must be 0, 1, or None. Got {quantized_dimension}"
|
@@ -112,23 +106,26 @@ def get_zp_scale_from_2d_dequantized_symmetric_weights(
|
|
112
106
|
# Per-tensor quantization: One scale for the entire tensor.
|
113
107
|
scales = _get_scale(dequant_vals.flatten(), min_scale)
|
114
108
|
scales = np.array([[scales]])
|
115
|
-
|
116
109
|
else:
|
117
110
|
# Per-channel quantization: A scale for each slice along the dimension.
|
118
|
-
scales
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
else np.array(scales).reshape(1, -1)
|
111
|
+
# Create a broadcasted array for per-channel scales. It should have the same
|
112
|
+
# number of dimensions as the input, with 1 in all dimensions except for the
|
113
|
+
# quantized dimension, which retains its original size.
|
114
|
+
scales = np.empty(
|
115
|
+
tuple(
|
116
|
+
[
|
117
|
+
1
|
118
|
+
if i != quantized_dimension
|
119
|
+
else dequant_vals.shape[quantized_dimension]
|
120
|
+
for i in range(dequant_vals.ndim)
|
121
|
+
]
|
122
|
+
)
|
131
123
|
)
|
124
|
+
for i in range(dequant_vals.shape[quantized_dimension]):
|
125
|
+
slices = [slice(None)] * dequant_vals.ndim
|
126
|
+
slices[quantized_dimension] = i
|
127
|
+
vec = dequant_vals[tuple(slices)]
|
128
|
+
scales[tuple(slices)] = _get_scale(vec, min_scale)
|
132
129
|
|
133
130
|
zero_points = np.zeros_like(scales, dtype=np.int32)
|
134
131
|
return zero_points, scales
|
@@ -153,7 +150,7 @@ def get_tensor_quant_params(
|
|
153
150
|
|
154
151
|
Raises:
|
155
152
|
ValueError: If the quantization granularity is blockwise, or if the tensor
|
156
|
-
is not a
|
153
|
+
is not a symmetric weight tensor.
|
157
154
|
"""
|
158
155
|
# Fallback to naive_min_max_quantize.py for non-weight tensors.
|
159
156
|
if tensor_content is None:
|
@@ -166,10 +163,9 @@ def get_tensor_quant_params(
|
|
166
163
|
"Blockwise quantization is not supported for dequantized weight"
|
167
164
|
" recovery."
|
168
165
|
)
|
169
|
-
if
|
166
|
+
if not tensor_quant_config.symmetric:
|
170
167
|
raise ValueError(
|
171
|
-
"Only
|
172
|
-
" recovery."
|
168
|
+
"Only symmetric weights are supported for dequantized weight recovery."
|
173
169
|
)
|
174
170
|
|
175
171
|
quantized_dim = None
|
@@ -178,7 +174,7 @@ def get_tensor_quant_params(
|
|
178
174
|
op_info, tensor_content
|
179
175
|
)
|
180
176
|
|
181
|
-
zp, scale =
|
177
|
+
zp, scale = get_zp_scale_from_dequantized_symmetric_weights(
|
182
178
|
dequant_vals=tensor_content,
|
183
179
|
quantized_dimension=quantized_dim,
|
184
180
|
)
|
@@ -62,7 +62,7 @@ class DequantizedWeightRecoveryTest(parameterized.TestCase):
|
|
62
62
|
):
|
63
63
|
dequant_vals = scale * self._dummy_quantized_weights
|
64
64
|
zp, recovered_scale = (
|
65
|
-
dequantized_weight_recovery.
|
65
|
+
dequantized_weight_recovery.get_zp_scale_from_dequantized_symmetric_weights(
|
66
66
|
dequant_vals, quantized_dimension
|
67
67
|
)
|
68
68
|
)
|
@@ -72,17 +72,40 @@ class DequantizedWeightRecoveryTest(parameterized.TestCase):
|
|
72
72
|
self.assertEqual(np.sum(zp), 0)
|
73
73
|
self.assertEqual(zp.shape, scale.shape)
|
74
74
|
|
75
|
-
|
76
|
-
|
75
|
+
@parameterized.named_parameters(
|
76
|
+
dict(
|
77
|
+
testcase_name="per-tensor-recovery",
|
78
|
+
quantized_dimension=None,
|
79
|
+
scale=np.array([0.1875]).reshape(1, 1),
|
80
|
+
),
|
81
|
+
dict(
|
82
|
+
testcase_name="channel0-recovery",
|
83
|
+
quantized_dimension=0,
|
84
|
+
scale=np.array([0.1875, 1e-4, 12.3]).reshape(3, 1, 1),
|
85
|
+
),
|
86
|
+
dict(
|
87
|
+
testcase_name="channel1-recovery",
|
88
|
+
quantized_dimension=1,
|
89
|
+
scale=np.array([0.003, 1.234]).reshape(1, 2, 1),
|
90
|
+
),
|
91
|
+
)
|
92
|
+
def test_tensor_zp_scale_from_3d_dequantized_symmetric_weights_success(
|
93
|
+
self, quantized_dimension, scale
|
77
94
|
):
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
)
|
95
|
+
dequant_vals = scale * self._dummy_quantized_weights.reshape(3, 2, 2)
|
96
|
+
zp, recovered_scale = (
|
97
|
+
dequantized_weight_recovery.get_zp_scale_from_dequantized_symmetric_weights(
|
98
|
+
dequant_vals, quantized_dimension
|
99
|
+
)
|
100
|
+
)
|
101
|
+
with self.subTest("shapes_match"):
|
102
|
+
self.assertEqual(recovered_scale.shape, scale.shape)
|
103
|
+
self.assertEqual(zp.shape, scale.shape)
|
104
|
+
with self.subTest("scale_value_match"):
|
105
|
+
self.assertSequenceAlmostEqual(recovered_scale.flatten(), scale.flatten())
|
106
|
+
with self.subTest("zp_is_zero"):
|
107
|
+
# Zero point should be zero for symmetric quantization.
|
108
|
+
self.assertEqual(np.sum(zp), 0)
|
86
109
|
|
87
110
|
@parameterized.named_parameters(
|
88
111
|
dict(testcase_name="negative_dimension", quantized_dimension=-1),
|
@@ -95,7 +118,7 @@ class DequantizedWeightRecoveryTest(parameterized.TestCase):
|
|
95
118
|
with self.assertRaisesRegex(
|
96
119
|
ValueError, "quantized_dimension must be 0, 1, or None. Got"
|
97
120
|
):
|
98
|
-
dequantized_weight_recovery.
|
121
|
+
dequantized_weight_recovery.get_zp_scale_from_dequantized_symmetric_weights(
|
99
122
|
dequant_vals, quantized_dimension
|
100
123
|
)
|
101
124
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: ai-edge-quantizer-nightly
|
3
|
-
Version: 0.1.0.
|
3
|
+
Version: 0.1.0.dev20250329
|
4
4
|
Summary: A quantizer for advanced developers to quantize converted AI Edge models.
|
5
5
|
Home-page: https://github.com/google-ai-edge/ai-edge-quantizer
|
6
6
|
Keywords: On-Device ML,AI,Google,TFLite,Quantization,LLMs,GenAI
|
@@ -1,5 +1,5 @@
|
|
1
1
|
ai_edge_quantizer/__init__.py,sha256=4pFSkukSwahYyzwqia0yPRyz8TnFQfGRthVJhYpMWas,793
|
2
|
-
ai_edge_quantizer/algorithm_manager.py,sha256=
|
2
|
+
ai_edge_quantizer/algorithm_manager.py,sha256=0uootLsVD6h9ph9TrnXZMI-ExkX8UvXSV0lbWxBLybU,10492
|
3
3
|
ai_edge_quantizer/algorithm_manager_api.py,sha256=u903TG0s1uIDhJqfeJne3CFl8A93phZrwgV2-hwdcXU,9247
|
4
4
|
ai_edge_quantizer/algorithm_manager_api_test.py,sha256=tL_ozYFTsOPX8qGcti0KTz37nVsCxf0SSG5C45SyT-g,7319
|
5
5
|
ai_edge_quantizer/calibrator.py,sha256=n7AD9j7UScR-CieoI6DQRMeiG_fhLBfSLRiM4460xaM,11895
|
@@ -30,8 +30,8 @@ ai_edge_quantizer/algorithms/nonlinear_quantize/float_casting_test.py,sha256=s64
|
|
30
30
|
ai_edge_quantizer/algorithms/uniform_quantize/__init__.py,sha256=lpq1g2ayg3lCPLy79t2VicYcnGKw64FfYIj1V7J-4m8,676
|
31
31
|
ai_edge_quantizer/algorithms/uniform_quantize/common_quantize.py,sha256=SVu1RSX5xOWhuNEi9hHqgIDGe_ywyHBZAczp7KAcl3k,27220
|
32
32
|
ai_edge_quantizer/algorithms/uniform_quantize/common_quantize_test.py,sha256=qMmKbWqxrCoVKbLKHn9WuCrGKPfHkEyU0Nmhokh8Qeo,2597
|
33
|
-
ai_edge_quantizer/algorithms/uniform_quantize/dequantized_weight_recovery.py,sha256=
|
34
|
-
ai_edge_quantizer/algorithms/uniform_quantize/dequantized_weight_recovery_test.py,sha256=
|
33
|
+
ai_edge_quantizer/algorithms/uniform_quantize/dequantized_weight_recovery.py,sha256=Fk3s9Qy2A_hjUepFOUmTwIZ_wKYVPbdDX4eoP-eoAQU,8726
|
34
|
+
ai_edge_quantizer/algorithms/uniform_quantize/dequantized_weight_recovery_test.py,sha256=sT5eX5TLZEHTtPfnSkCPDlS0sQxlTFWbCsbvOuj--yY,8889
|
35
35
|
ai_edge_quantizer/algorithms/uniform_quantize/naive_min_max_quantize.py,sha256=cbyyYAoQnEraOYSV00wZ557ElBndHduVGeHikYUEFCE,7995
|
36
36
|
ai_edge_quantizer/algorithms/uniform_quantize/naive_min_max_quantize_test.py,sha256=B30SEISYZ9DPs3suKeG2elgXylR98pCEMWSEGgZo20o,7648
|
37
37
|
ai_edge_quantizer/algorithms/uniform_quantize/octav.py,sha256=e5wYtki-vl739gSVAZHAKcs2hA87GvFUjVoSUPlnkyM,6433
|
@@ -64,8 +64,8 @@ ai_edge_quantizer/utils/tfl_interpreter_utils.py,sha256=x2xA2CFPpe_2trcV8v5xGaBE
|
|
64
64
|
ai_edge_quantizer/utils/tfl_interpreter_utils_test.py,sha256=Op3JxtOqlrjzmYF18jnnstL1k9xiY9kKJ8S2vklKGkc,11327
|
65
65
|
ai_edge_quantizer/utils/validation_utils.py,sha256=oYw33Sg547AqtGw-choPUJmp9SAKkV46J_ddqSsum2Q,3950
|
66
66
|
ai_edge_quantizer/utils/validation_utils_test.py,sha256=V_qNDikPD4OPB-siOLQCWNVWTAu87h2IgNYt7teFd-o,2934
|
67
|
-
ai_edge_quantizer_nightly-0.1.0.
|
68
|
-
ai_edge_quantizer_nightly-0.1.0.
|
69
|
-
ai_edge_quantizer_nightly-0.1.0.
|
70
|
-
ai_edge_quantizer_nightly-0.1.0.
|
71
|
-
ai_edge_quantizer_nightly-0.1.0.
|
67
|
+
ai_edge_quantizer_nightly-0.1.0.dev20250329.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
68
|
+
ai_edge_quantizer_nightly-0.1.0.dev20250329.dist-info/METADATA,sha256=3GoKN9dRRW0IhcJA2xnqAhU3znEgEzkDec2STODYtLA,1527
|
69
|
+
ai_edge_quantizer_nightly-0.1.0.dev20250329.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
70
|
+
ai_edge_quantizer_nightly-0.1.0.dev20250329.dist-info/top_level.txt,sha256=8QTfPnFXNVUhScFLaa-NWZMFWMn72M50DVPubpwWB1g,18
|
71
|
+
ai_edge_quantizer_nightly-0.1.0.dev20250329.dist-info/RECORD,,
|
File without changes
|
File without changes
|