ai-edge-quantizer-nightly 0.0.1.dev20250302__py3-none-any.whl → 0.5.0.dev20260103__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.
Files changed (69) hide show
  1. ai_edge_quantizer/algorithm_manager.py +224 -0
  2. ai_edge_quantizer/algorithm_manager_api_test.py +7 -0
  3. ai_edge_quantizer/algorithms/nonlinear_quantize/float_casting_test.py +2 -2
  4. ai_edge_quantizer/algorithms/uniform_quantize/common_quantize.py +643 -20
  5. ai_edge_quantizer/algorithms/uniform_quantize/common_quantize_test.py +29 -2
  6. ai_edge_quantizer/algorithms/uniform_quantize/dequantized_weight_recovery.py +29 -35
  7. ai_edge_quantizer/algorithms/uniform_quantize/dequantized_weight_recovery_test.py +35 -12
  8. ai_edge_quantizer/algorithms/uniform_quantize/hadamard_rotation.py +414 -0
  9. ai_edge_quantizer/algorithms/uniform_quantize/hadamard_rotation_test.py +440 -0
  10. ai_edge_quantizer/algorithms/uniform_quantize/mse.py +127 -0
  11. ai_edge_quantizer/algorithms/uniform_quantize/mse_test.py +195 -0
  12. ai_edge_quantizer/algorithms/uniform_quantize/naive_min_max_quantize.py +54 -168
  13. ai_edge_quantizer/algorithms/uniform_quantize/naive_min_max_quantize_test.py +54 -17
  14. ai_edge_quantizer/algorithms/uniform_quantize/octav.py +188 -0
  15. ai_edge_quantizer/algorithms/uniform_quantize/octav_test.py +240 -0
  16. ai_edge_quantizer/algorithms/uniform_quantize/uniform_quantize_tensor.py +260 -13
  17. ai_edge_quantizer/algorithms/uniform_quantize/uniform_quantize_tensor_test.py +152 -5
  18. ai_edge_quantizer/algorithms/utils/common_utils.py +142 -54
  19. ai_edge_quantizer/calibrator.py +58 -94
  20. ai_edge_quantizer/calibrator_test.py +5 -74
  21. ai_edge_quantizer/default_policy.py +108 -16
  22. ai_edge_quantizer/model_modifier.py +132 -8
  23. ai_edge_quantizer/model_modifier_test.py +81 -1
  24. ai_edge_quantizer/model_validator.py +38 -10
  25. ai_edge_quantizer/model_validator_test.py +2 -1
  26. ai_edge_quantizer/params_generator.py +230 -47
  27. ai_edge_quantizer/params_generator_test.py +366 -261
  28. ai_edge_quantizer/qtyping.py +92 -6
  29. ai_edge_quantizer/quantizer.py +167 -23
  30. ai_edge_quantizer/quantizer_test.py +288 -26
  31. ai_edge_quantizer/recipe.py +156 -21
  32. ai_edge_quantizer/recipe_manager.py +158 -1
  33. ai_edge_quantizer/recipe_manager_test.py +146 -32
  34. ai_edge_quantizer/recipe_test.py +93 -17
  35. ai_edge_quantizer/transformation_instruction_generator.py +313 -46
  36. ai_edge_quantizer/transformation_instruction_generator_test.py +449 -27
  37. ai_edge_quantizer/transformation_performer.py +112 -58
  38. ai_edge_quantizer/transformation_performer_test.py +176 -4
  39. ai_edge_quantizer/transformations/duplicate_buffer.py +46 -0
  40. ai_edge_quantizer/transformations/duplicate_buffer_test.py +106 -0
  41. ai_edge_quantizer/transformations/duplicate_tensor.py +62 -0
  42. ai_edge_quantizer/transformations/duplicate_tensor_test.py +131 -0
  43. ai_edge_quantizer/transformations/insert_decomposed_hadamard_rotation.py +299 -0
  44. ai_edge_quantizer/transformations/insert_decomposed_hadamard_rotation_test.py +244 -0
  45. ai_edge_quantizer/transformations/insert_hadamard_rotation.py +186 -0
  46. ai_edge_quantizer/transformations/insert_hadamard_rotation_test.py +200 -0
  47. ai_edge_quantizer/transformations/quantize_tensor.py +24 -44
  48. ai_edge_quantizer/transformations/quantize_tensor_test.py +3 -2
  49. ai_edge_quantizer/transformations/transformation_utils.py +157 -11
  50. ai_edge_quantizer/transformations/transformation_utils_test.py +96 -2
  51. ai_edge_quantizer/utils/calibration_utils.py +263 -1
  52. ai_edge_quantizer/utils/calibration_utils_test.py +173 -3
  53. ai_edge_quantizer/utils/constrained_ops_utils.py +111 -0
  54. ai_edge_quantizer/utils/constrained_ops_utils_test.py +50 -0
  55. ai_edge_quantizer/utils/test_utils.py +191 -58
  56. ai_edge_quantizer/utils/tfl_flatbuffer_utils.py +96 -50
  57. ai_edge_quantizer/utils/tfl_flatbuffer_utils_test.py +20 -0
  58. ai_edge_quantizer/utils/tfl_interpreter_utils.py +138 -5
  59. ai_edge_quantizer/utils/tfl_interpreter_utils_test.py +29 -2
  60. ai_edge_quantizer/utils/validation_utils.py +114 -4
  61. ai_edge_quantizer/utils/validation_utils_test.py +80 -0
  62. {ai_edge_quantizer_nightly-0.0.1.dev20250302.dist-info → ai_edge_quantizer_nightly-0.5.0.dev20260103.dist-info}/METADATA +13 -3
  63. ai_edge_quantizer_nightly-0.5.0.dev20260103.dist-info/RECORD +81 -0
  64. {ai_edge_quantizer_nightly-0.0.1.dev20250302.dist-info → ai_edge_quantizer_nightly-0.5.0.dev20260103.dist-info}/WHEEL +1 -1
  65. ai_edge_quantizer/transformations/emulated_subchannel.py +0 -363
  66. ai_edge_quantizer/transformations/emulated_subchannel_test.py +0 -212
  67. ai_edge_quantizer_nightly-0.0.1.dev20250302.dist-info/RECORD +0 -67
  68. {ai_edge_quantizer_nightly-0.0.1.dev20250302.dist-info → ai_edge_quantizer_nightly-0.5.0.dev20260103.dist-info/licenses}/LICENSE +0 -0
  69. {ai_edge_quantizer_nightly-0.0.1.dev20250302.dist-info → ai_edge_quantizer_nightly-0.5.0.dev20260103.dist-info}/top_level.txt +0 -0
@@ -1,363 +0,0 @@
1
- # Copyright 2024 The AI Edge Quantizer Authors.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- # ==============================================================================
15
-
16
- """Transformation pattern for emulated subchannel quantization."""
17
-
18
- from typing import cast
19
- import numpy as np
20
- from ai_edge_quantizer import qtyping
21
- from ai_edge_quantizer.transformations import quantize_tensor
22
- from ai_edge_quantizer.transformations import transformation_utils
23
- from ai_edge_litert import schema_py_generated # pylint: disable=g-direct-tensorflow-import
24
-
25
-
26
- def emulated_subchannel(
27
- transformation_input: transformation_utils.TransformationInput,
28
- ) -> qtyping.TransformationInfo:
29
- """Emulated subchannel quantization for fully_connected op.
30
-
31
- The input tensor must also be the weight tensor of the fully_connected op.
32
-
33
- after the transformation, the fully connected op will be replaced by:
34
- reshape -> batch_matmul -> mul -> sum -> add (if bias is present) ->
35
- activation (if fused activation function exist, only support ReLU for now)
36
-
37
- Args:
38
- transformation_input: input structure that contains all information needed
39
- for the transformation.
40
-
41
- Returns:
42
- The transformation info.
43
- """
44
- # only apply to a single fully_connected op
45
- if len(transformation_input.consumers) > 1:
46
- raise ValueError('Emulated Subchannel transformation only support one op')
47
- if isinstance(
48
- transformation_input.quant_params, qtyping.NonLinearQuantParams
49
- ):
50
- raise ValueError(
51
- 'Emulated Subchannel transformation only support uniform quantization'
52
- )
53
- if (
54
- transformation_input.op_codes[
55
- transformation_input.subgraph.operators[
56
- transformation_input.consumers[0]
57
- ].opcodeIndex
58
- ].builtinCode
59
- != schema_py_generated.BuiltinOperator.FULLY_CONNECTED
60
- ):
61
- raise ValueError(
62
- 'Emulated Subchannel transformation only support fully_connected op'
63
- )
64
- if transformation_input.producer != -1:
65
- raise ValueError(
66
- 'Emulated Subchannel transformation only support constant tensor'
67
- )
68
-
69
- # insert all tne necessary op codes into the model
70
- reshape_op_code_idx = transformation_utils.add_op_code(
71
- schema_py_generated.BuiltinOperator.RESHAPE, transformation_input.op_codes
72
- )
73
- bmm_op_code_idx = transformation_utils.add_op_code(
74
- schema_py_generated.BuiltinOperator.BATCH_MATMUL,
75
- transformation_input.op_codes,
76
- )
77
- mul_op_code_idx = transformation_utils.add_op_code(
78
- schema_py_generated.BuiltinOperator.MUL, transformation_input.op_codes
79
- )
80
- sum_op_code_idx = transformation_utils.add_op_code(
81
- schema_py_generated.BuiltinOperator.SUM, transformation_input.op_codes
82
- )
83
-
84
- original_fc_op_idx = transformation_input.consumers[0]
85
- if cast(
86
- schema_py_generated.FullyConnectedOptionsT,
87
- transformation_input.subgraph.operators[
88
- original_fc_op_idx
89
- ].builtinOptions,
90
- ).fusedActivationFunction not in (
91
- schema_py_generated.ActivationFunctionType.NONE,
92
- schema_py_generated.ActivationFunctionType.RELU,
93
- ):
94
- raise ValueError(
95
- 'Emulated Subchannel transformation only support'
96
- ' fusedActivationFunction NONE and RELU for now'
97
- )
98
-
99
- weight_tensor = transformation_input.subgraph.tensors[
100
- transformation_input.tensor_id
101
- ]
102
- weight_tensor.type = quantize_tensor.quant_params_to_tflite_type(
103
- transformation_input.quant_params.num_bits
104
- )
105
-
106
- # modify the weight tensor with the correct quantization parameters
107
- transformation_input.buffers[weight_tensor.buffer].data = np.frombuffer(
108
- cast(
109
- np.ndarray, transformation_input.quant_params.quantized_data
110
- ).tobytes(),
111
- dtype=np.uint8,
112
- )
113
- weight_tensor.shape = cast(
114
- np.ndarray, transformation_input.quant_params.quantized_data
115
- ).shape
116
- weight_tensor.quantization.scale = np.ones(shape=[1], dtype=np.float32)
117
- weight_tensor.quantization.zeroPoint = np.zeros(
118
- shape=[1], dtype=np.int64
119
- ).flatten()
120
-
121
- # assuming zero point is 0, so no need to add a zero point tensor
122
- for val in transformation_input.quant_params.zero_point.flatten():
123
- if val != 0:
124
- raise ValueError(
125
- 'Emulated Subchannel transformation only support zero point 0 for now'
126
- )
127
-
128
- scale_tensor_id = transformation_utils.add_new_constant_tensor(
129
- weight_tensor.name + b'_scale',
130
- transformation_input.quant_params.scale,
131
- schema_py_generated.TensorType.FLOAT32,
132
- transformation_input.subgraph,
133
- transformation_input.buffers,
134
- )
135
-
136
- # for fully connected op, the reduce axis is always 1
137
- reduce_axes_data = np.array([1], dtype=np.int32)
138
- reduce_axes_tensor_id = transformation_utils.add_new_constant_tensor(
139
- weight_tensor.name + b'_reduce_axes',
140
- reduce_axes_data,
141
- schema_py_generated.TensorType.INT32,
142
- transformation_input.subgraph,
143
- transformation_input.buffers,
144
- )
145
-
146
- # find the input and output tensor of the fully connected op
147
- activation_input_id = transformation_input.subgraph.operators[
148
- transformation_input.consumers[0]
149
- ].inputs[0]
150
- activation_output_id = transformation_input.subgraph.operators[
151
- transformation_input.consumers[0]
152
- ].outputs[0]
153
- activation_input = transformation_input.subgraph.tensors[activation_input_id]
154
- activation_output = transformation_input.subgraph.tensors[
155
- activation_output_id
156
- ]
157
-
158
- if len(activation_input.shape) != 3:
159
- raise ValueError(
160
- 'Emulated Subchannel transformation only support 3D input tensor'
161
- )
162
- bmm_input_shape = [
163
- activation_input.shape[0] * activation_input.shape[1],
164
- weight_tensor.shape[1],
165
- 1,
166
- weight_tensor.shape[2],
167
- ]
168
- intermediate_tensor_shape = [
169
- activation_input.shape[0] * activation_input.shape[1],
170
- weight_tensor.shape[1],
171
- 1,
172
- weight_tensor.shape[3],
173
- ]
174
- sum_output_shape = [
175
- activation_input.shape[0] * activation_input.shape[1],
176
- 1,
177
- 1,
178
- weight_tensor.shape[3],
179
- ]
180
-
181
- # create constant tensors for reshape
182
- reshape1_shape_id = transformation_utils.add_new_constant_tensor(
183
- activation_output.name + b'_reshape_op1_shape',
184
- np.array(bmm_input_shape, dtype=np.int32),
185
- schema_py_generated.TensorType.INT32,
186
- transformation_input.subgraph,
187
- transformation_input.buffers,
188
- )
189
- reshape2_shape_id = transformation_utils.add_new_constant_tensor(
190
- activation_output.name + b'_reshape_op2_shape',
191
- np.array(activation_output.shape, dtype=np.int32),
192
- schema_py_generated.TensorType.INT32,
193
- transformation_input.subgraph,
194
- transformation_input.buffers,
195
- )
196
-
197
- # create all intermediate tensors
198
- bmm_input_id = transformation_utils.add_new_activation_tensor(
199
- activation_output.name + b'_bmm_input',
200
- bmm_input_shape,
201
- schema_py_generated.TensorType.FLOAT32,
202
- transformation_input.subgraph,
203
- )
204
- mul_input_id = transformation_utils.add_new_activation_tensor(
205
- activation_output.name + b'_mul_input',
206
- intermediate_tensor_shape,
207
- schema_py_generated.TensorType.FLOAT32,
208
- transformation_input.subgraph,
209
- )
210
- sum_input_id = transformation_utils.add_new_activation_tensor(
211
- activation_output.name + b'_reduce_sum_input',
212
- intermediate_tensor_shape,
213
- schema_py_generated.TensorType.FLOAT32,
214
- transformation_input.subgraph,
215
- )
216
- reshape_op2_input_id = transformation_utils.add_new_activation_tensor(
217
- activation_output.name + b'_reshape_op2_input',
218
- sum_output_shape,
219
- schema_py_generated.TensorType.FLOAT32,
220
- transformation_input.subgraph,
221
- )
222
-
223
- # reshape
224
- reshape_op1 = schema_py_generated.OperatorT()
225
- reshape_op1.opcodeIndex = reshape_op_code_idx
226
- reshape_op1_option = schema_py_generated.ReshapeOptionsT()
227
- reshape_op1_option.newShape = bmm_input_shape
228
- reshape_op1.inputs = [activation_input_id, reshape1_shape_id]
229
- reshape_op1.outputs = [bmm_input_id]
230
- reshape_op1.builtinOptionsType = (
231
- schema_py_generated.BuiltinOptions.ReshapeOptions
232
- ) # reshape option index
233
- reshape_op1.builtinOptions = reshape_op1_option
234
-
235
- # batch_matmul
236
- bmm_op = schema_py_generated.OperatorT()
237
- bmm_op.opcodeIndex = bmm_op_code_idx
238
- bmm_op.inputs = [bmm_input_id, transformation_input.tensor_id]
239
- bmm_op.outputs = [mul_input_id]
240
- bmm_op.builtinOptionsType = (
241
- schema_py_generated.BuiltinOptions.BatchMatMulOptions
242
- )
243
- bmm_op.builtinOptions = schema_py_generated.BatchMatMulOptionsT()
244
-
245
- # mul
246
- mul_op = schema_py_generated.OperatorT()
247
- mul_op.opcodeIndex = mul_op_code_idx
248
- mul_option = schema_py_generated.MulOptionsT()
249
- mul_option.fusedActivationFunction = (
250
- schema_py_generated.ActivationFunctionType.NONE
251
- )
252
- mul_op.inputs = [mul_input_id, scale_tensor_id]
253
- mul_op.outputs = [sum_input_id]
254
- mul_op.builtinOptionsType = schema_py_generated.BuiltinOptions.MulOptions
255
- mul_op.builtinOptions = mul_option
256
-
257
- # sum
258
- sum_op = schema_py_generated.OperatorT()
259
- sum_op.opcodeIndex = sum_op_code_idx
260
- sum_op.inputs = [sum_input_id, reduce_axes_tensor_id]
261
- sum_op.outputs = [reshape_op2_input_id]
262
- sum_op.builtinOptionsType = schema_py_generated.BuiltinOptions.ReducerOptions
263
- sum_op.builtinOptions = schema_py_generated.ReducerOptionsT()
264
- sum_op.builtinOptions.keepDims = True
265
-
266
- # reshape
267
- reshape_op2 = schema_py_generated.OperatorT()
268
- reshape_op2.opcodeIndex = reshape_op_code_idx
269
- reshape_op2_option = schema_py_generated.ReshapeOptionsT()
270
- reshape_op2_option.newShape = activation_output.shape
271
- reshape_op2.inputs = [reshape_op2_input_id, reshape2_shape_id]
272
- reshape_op2.outputs = [activation_output_id]
273
- reshape_op2.builtinOptionsType = (
274
- schema_py_generated.BuiltinOptions.ReshapeOptions
275
- )
276
- reshape_op2.builtinOptions = reshape_op2_option
277
-
278
- transformation_input.subgraph.operators.insert(
279
- original_fc_op_idx, reshape_op1
280
- )
281
- transformation_input.subgraph.operators.insert(original_fc_op_idx + 1, bmm_op)
282
- transformation_input.subgraph.operators.insert(original_fc_op_idx + 2, mul_op)
283
- transformation_input.subgraph.operators.insert(original_fc_op_idx + 3, sum_op)
284
- transformation_input.subgraph.operators.insert(
285
- original_fc_op_idx + 4, reshape_op2
286
- )
287
- ops_added = 5
288
- last_op = reshape_op2
289
-
290
- # If there is a bias tensor (the third input to the original fc op),
291
- # we need an add to process it. The current fc op id need to be recalculated
292
- # because we added operators in front of it.
293
- current_fc_op_id = original_fc_op_idx + ops_added
294
- if (
295
- len(transformation_input.subgraph.operators[current_fc_op_id].inputs) > 2
296
- and transformation_input.subgraph.operators[current_fc_op_id].inputs[2]
297
- != -1
298
- ):
299
- add_op_code_idx = transformation_utils.add_op_code(
300
- schema_py_generated.BuiltinOperator.ADD, transformation_input.op_codes
301
- )
302
- reshape_op2_output_id = transformation_utils.add_new_activation_tensor(
303
- activation_output.name + b'_reshape_op2_output',
304
- activation_output.shape,
305
- schema_py_generated.TensorType.FLOAT32,
306
- transformation_input.subgraph,
307
- )
308
- last_op.outputs = [reshape_op2_output_id]
309
- add_op = schema_py_generated.OperatorT()
310
- add_op.opcodeIndex = add_op_code_idx
311
- add_option = schema_py_generated.AddOptionsT()
312
- add_op.builtinOptionsType = schema_py_generated.BuiltinOptions.AddOptions
313
- add_op.builtinOptions = add_option
314
- add_op.inputs = [
315
- reshape_op2_output_id,
316
- transformation_input.subgraph.operators[
317
- original_fc_op_idx + ops_added
318
- ].inputs[2],
319
- ]
320
- add_op.outputs = [activation_output_id]
321
- transformation_input.subgraph.operators.insert(
322
- original_fc_op_idx + ops_added, add_op
323
- )
324
- ops_added += 1
325
- last_op = add_op
326
-
327
- # If the fused activation function is RELU, we need to add a relu op.
328
- # The current fc op id need to be recalculated because we added operators
329
- # in front of it.
330
- fc_fused_activation_function = cast(
331
- schema_py_generated.FullyConnectedOptionsT,
332
- transformation_input.subgraph.operators[
333
- original_fc_op_idx + ops_added
334
- ].builtinOptions,
335
- ).fusedActivationFunction
336
- if (
337
- fc_fused_activation_function
338
- == schema_py_generated.ActivationFunctionType.RELU
339
- ):
340
- activation_output.name += b'_relu'
341
- relu_input_id = transformation_utils.add_new_activation_tensor(
342
- activation_output.name + b'_relu_input',
343
- activation_output.shape,
344
- schema_py_generated.TensorType.FLOAT32,
345
- transformation_input.subgraph,
346
- )
347
- last_op.outputs = [relu_input_id]
348
- relu_op = schema_py_generated.OperatorT()
349
- relu_op.opcodeIndex = transformation_utils.add_op_code(
350
- schema_py_generated.BuiltinOperator.RELU, transformation_input.op_codes
351
- )
352
- relu_op.inputs = [relu_input_id]
353
- relu_op.outputs = [activation_output_id]
354
- transformation_input.subgraph.operators.insert(
355
- original_fc_op_idx + ops_added, relu_op
356
- )
357
- ops_added += 1
358
- last_op = relu_op
359
-
360
- del transformation_input.subgraph.operators[original_fc_op_idx + ops_added]
361
- return qtyping.TransformationInfo(
362
- original_fc_op_idx, ops_added - 1, activation_output_id
363
- )
@@ -1,212 +0,0 @@
1
- # Copyright 2024 The AI Edge Quantizer Authors.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
- # ==============================================================================
15
-
16
- """Tests for emulated_subchannel."""
17
-
18
- import os
19
- import numpy as np
20
- from tensorflow.python.platform import googletest
21
- from ai_edge_quantizer import qtyping
22
- from ai_edge_quantizer.transformations import emulated_subchannel
23
- from ai_edge_quantizer.transformations import transformation_utils
24
- from ai_edge_quantizer.utils import test_utils
25
- from ai_edge_quantizer.utils import tfl_flatbuffer_utils
26
- from ai_edge_litert import schema_py_generated # pylint: disable=g-direct-tensorflow-import
27
-
28
- TEST_DATA_PREFIX_PATH = test_utils.get_path_to_datafile("..")
29
-
30
-
31
- class EmulatedSubchannelTest(googletest.TestCase):
32
- """Tests for emulated_subchannel."""
33
-
34
- def setUp(self):
35
- super().setUp()
36
- self.params = qtyping.UniformQuantParams(
37
- num_bits=8,
38
- quantized_dimension=None,
39
- scale=np.ones([1, 1, 1, 4], dtype=np.float32),
40
- zero_point=np.zeros([1, 1, 1, 4], dtype=np.int64),
41
- symmetric=True,
42
- quantized_data=np.ones([1, 4, 2, 4], dtype=np.int8),
43
- )
44
-
45
- def test_emulate_subchannel_without_bias_succeeds(self):
46
- """Tests the emulated_subchannel function."""
47
- self._model_path = os.path.join(
48
- TEST_DATA_PREFIX_PATH, "tests/models/single_fc_no_bias.tflite"
49
- )
50
- self._model = tfl_flatbuffer_utils.read_model(self._model_path)
51
- subgraph = self._model.subgraphs[0]
52
- model = self._model
53
- ret = emulated_subchannel.emulated_subchannel(
54
- transformation_utils.TransformationInput(
55
- tensor_id=1,
56
- op_codes=model.operatorCodes,
57
- buffers=model.buffers,
58
- subgraph=subgraph,
59
- producer=-1,
60
- consumers=[0],
61
- quant_params=self.params,
62
- )
63
- )
64
- self.assertEqual(ret.op_id, 0)
65
- self.assertEqual(ret.num_ops_added, 4)
66
- self.assertEqual(ret.output_tensor_id, 2)
67
- self.assertEqual(
68
- model.operatorCodes[subgraph.operators[0].opcodeIndex].builtinCode,
69
- schema_py_generated.BuiltinOperator.RESHAPE,
70
- )
71
- self.assertEqual(
72
- model.operatorCodes[subgraph.operators[1].opcodeIndex].builtinCode,
73
- schema_py_generated.BuiltinOperator.BATCH_MATMUL,
74
- )
75
- self.assertEqual(
76
- model.operatorCodes[subgraph.operators[2].opcodeIndex].builtinCode,
77
- schema_py_generated.BuiltinOperator.MUL,
78
- )
79
- self.assertEqual(
80
- model.operatorCodes[subgraph.operators[3].opcodeIndex].builtinCode,
81
- schema_py_generated.BuiltinOperator.SUM,
82
- )
83
- self.assertEqual(
84
- model.operatorCodes[subgraph.operators[4].opcodeIndex].builtinCode,
85
- schema_py_generated.BuiltinOperator.RESHAPE,
86
- )
87
- self.assertEqual(
88
- subgraph.tensors[subgraph.operators[2].inputs[1]].name,
89
- b"arith.constant_scale",
90
- )
91
- self.assertListEqual(
92
- np.frombuffer(
93
- model.buffers[
94
- subgraph.tensors[subgraph.operators[2].inputs[1]].buffer
95
- ].data,
96
- dtype=np.float32,
97
- ).tolist(),
98
- np.ones([1, 1, 1, 4]).flatten().tolist(),
99
- )
100
-
101
- def test_emulate_subchannel_with_bias_succeeds(self):
102
- """Tests the emulated_subchannel function."""
103
- self._model_path = os.path.join(
104
- TEST_DATA_PREFIX_PATH, "tests/models/single_fc_bias.tflite"
105
- )
106
- self._model = tfl_flatbuffer_utils.read_model(self._model_path)
107
- subgraph = self._model.subgraphs[0]
108
- model = self._model
109
- ret = emulated_subchannel.emulated_subchannel(
110
- transformation_utils.TransformationInput(
111
- tensor_id=1,
112
- op_codes=model.operatorCodes,
113
- buffers=model.buffers,
114
- subgraph=subgraph,
115
- producer=-1,
116
- consumers=[0],
117
- quant_params=self.params,
118
- )
119
- )
120
- self.assertEqual(ret.op_id, 0)
121
- self.assertEqual(ret.num_ops_added, 5)
122
- self.assertEqual(ret.output_tensor_id, 3)
123
- self.assertEqual(
124
- model.operatorCodes[subgraph.operators[0].opcodeIndex].builtinCode,
125
- schema_py_generated.BuiltinOperator.RESHAPE,
126
- )
127
- self.assertEqual(
128
- model.operatorCodes[subgraph.operators[1].opcodeIndex].builtinCode,
129
- schema_py_generated.BuiltinOperator.BATCH_MATMUL,
130
- )
131
- self.assertEqual(
132
- model.operatorCodes[subgraph.operators[2].opcodeIndex].builtinCode,
133
- schema_py_generated.BuiltinOperator.MUL,
134
- )
135
- self.assertEqual(
136
- model.operatorCodes[subgraph.operators[3].opcodeIndex].builtinCode,
137
- schema_py_generated.BuiltinOperator.SUM,
138
- )
139
- self.assertEqual(
140
- model.operatorCodes[subgraph.operators[4].opcodeIndex].builtinCode,
141
- schema_py_generated.BuiltinOperator.RESHAPE,
142
- )
143
- self.assertEqual(
144
- model.operatorCodes[subgraph.operators[5].opcodeIndex].builtinCode,
145
- schema_py_generated.BuiltinOperator.ADD,
146
- )
147
- self.assertEqual(
148
- subgraph.tensors[subgraph.operators[2].inputs[1]].name,
149
- b"arith.constant_scale",
150
- )
151
- self.assertListEqual(
152
- np.frombuffer(
153
- model.buffers[
154
- subgraph.tensors[subgraph.operators[2].inputs[1]].buffer
155
- ].data,
156
- dtype=np.float32,
157
- ).tolist(),
158
- np.ones([1, 1, 1, 4]).flatten().tolist(),
159
- )
160
-
161
- def test_emulated_subchannel_with_fused_relu_succeeds(self):
162
- """Tests the emulated_subchannel function with fused relu."""
163
- self._model_path = os.path.join(
164
- TEST_DATA_PREFIX_PATH, "tests/models/single_fc_bias_relu.tflite"
165
- )
166
- self._model = tfl_flatbuffer_utils.read_model(self._model_path)
167
- self._model = tfl_flatbuffer_utils.read_model(self._model_path)
168
- subgraph = self._model.subgraphs[0]
169
- model = self._model
170
- ret = emulated_subchannel.emulated_subchannel(
171
- transformation_utils.TransformationInput(
172
- tensor_id=1,
173
- op_codes=model.operatorCodes,
174
- buffers=model.buffers,
175
- subgraph=subgraph,
176
- producer=-1,
177
- consumers=[0],
178
- quant_params=self.params,
179
- )
180
- )
181
- self.assertEqual(ret.op_id, 0)
182
- self.assertEqual(ret.num_ops_added, 6)
183
- self.assertEqual(ret.output_tensor_id, 3)
184
- self.assertEqual(
185
- model.operatorCodes[subgraph.operators[6].opcodeIndex].builtinCode,
186
- schema_py_generated.BuiltinOperator.RELU,
187
- )
188
-
189
- def test_emulated_subchannel_raises_when_unsupported_activation(self):
190
- """Tests the emulated_subchannel function with unsupported activation."""
191
- self._model_path = os.path.join(
192
- TEST_DATA_PREFIX_PATH, "tests/models/single_fc_bias_relu6.tflite"
193
- )
194
- self._model = tfl_flatbuffer_utils.read_model(self._model_path)
195
- subgraph = self._model.subgraphs[0]
196
- model = self._model
197
- with self.assertRaises(ValueError):
198
- emulated_subchannel.emulated_subchannel(
199
- transformation_utils.TransformationInput(
200
- tensor_id=1,
201
- op_codes=model.operatorCodes,
202
- buffers=model.buffers,
203
- subgraph=subgraph,
204
- producer=-1,
205
- consumers=[0],
206
- quant_params=self.params,
207
- )
208
- )
209
-
210
-
211
- if __name__ == "__main__":
212
- googletest.main()
@@ -1,67 +0,0 @@
1
- ai_edge_quantizer/__init__.py,sha256=4pFSkukSwahYyzwqia0yPRyz8TnFQfGRthVJhYpMWas,793
2
- ai_edge_quantizer/algorithm_manager.py,sha256=qjpdEei5l-k5wgGDnelMGVDAYb7K7z8Nn9FIuZBWPA0,7534
3
- ai_edge_quantizer/algorithm_manager_api.py,sha256=u903TG0s1uIDhJqfeJne3CFl8A93phZrwgV2-hwdcXU,9247
4
- ai_edge_quantizer/algorithm_manager_api_test.py,sha256=tL_ozYFTsOPX8qGcti0KTz37nVsCxf0SSG5C45SyT-g,7319
5
- ai_edge_quantizer/calibrator.py,sha256=2J-bX0k09A7vZSRnO3eP49YO2uBMUQh6-sk3JRz9fGQ,11363
6
- ai_edge_quantizer/calibrator_test.py,sha256=hQk61YUvw1X02CDVAddm2n6Dnyk9GWoDgSpO6nuSJiY,11889
7
- ai_edge_quantizer/conftest.py,sha256=SxCz-5LlRD_lQm4hQc4c6IGG7DS8d7IyEWY9gnscPN0,794
8
- ai_edge_quantizer/default_policy.py,sha256=aDWQO00AxTCpciqPavsGBsgC_q_eN75D9ZbNwET4Nko,9119
9
- ai_edge_quantizer/model_modifier.py,sha256=Z8EYtrz4zhCFpzd1zVwl2AetVE3BGBf5OvB2DbVQuds,5850
10
- ai_edge_quantizer/model_modifier_test.py,sha256=cJd04SLOG-fQZZNZPcisoBLx3cLtWEwGqUBbLb-pif4,4751
11
- ai_edge_quantizer/model_validator.py,sha256=oZk0b1qGczaEm5erJFm4SbwadDnl7DFhC0bXuxwVgps,12787
12
- ai_edge_quantizer/model_validator_test.py,sha256=ctvVmMHvnmFbkG4o8Jaa6kXXRrGHzhYpNylgLSmOboA,12951
13
- ai_edge_quantizer/params_generator.py,sha256=FvBub5yM2q98k7wNLgEyRerf8sVIETvGbrFcXFPUPdA,13523
14
- ai_edge_quantizer/params_generator_test.py,sha256=d9JwR-yxNJgg1SW-m8sFFPkIRdhgsDwMpVKsBQFL0gg,37658
15
- ai_edge_quantizer/qtyping.py,sha256=ekmcJXYzBbdJsaQcj6LtcdiuJoU3sKqaUTAIFBQ9oqc,15092
16
- ai_edge_quantizer/quantizer.py,sha256=Gny7WLuRibiIuDtcRn_g8RCD-zAm_fuDG7WmGq5dRx8,13238
17
- ai_edge_quantizer/quantizer_test.py,sha256=38oTMJwMmxwPDeqT3eaVbazjtuIUIzMQ3mJNKh_eNQY,20493
18
- ai_edge_quantizer/recipe.py,sha256=r5tJiUs-ihZFzeK_jP2sUIUgTqZsL5SWvbUokuIUPDo,2251
19
- ai_edge_quantizer/recipe_manager.py,sha256=qcGUD7e7BISKdsY9WH2rdaRR3acmzSA5qMezGNbzlpo,8931
20
- ai_edge_quantizer/recipe_manager_test.py,sha256=LulVxsYp6TBGFI2PLCUCd4VsFq8ELpC7kMNkUjsLgbo,32230
21
- ai_edge_quantizer/recipe_test.py,sha256=Fg_sfxovI2fRjk5qdu18ghOvXdUvhDR1TxbE0GHDczc,3381
22
- ai_edge_quantizer/transformation_instruction_generator.py,sha256=l_n7bXxIPTQ9AGcl2dkSx_BgJNtSs8ZW_JZ3pxtQ1I0,21652
23
- ai_edge_quantizer/transformation_instruction_generator_test.py,sha256=23MfOBiXv5Wq9FKJen7DrJ66T58qxf4ECriIY7V013k,39113
24
- ai_edge_quantizer/transformation_performer.py,sha256=3ZuaN5xwAu1B9zoGZHqi0__FOSzjGWOcydpCy1_Scac,10951
25
- ai_edge_quantizer/transformation_performer_test.py,sha256=m3V6nd6jsjd6jVId5wTBNuyDB2h2p4tHlMWhlnomlJo,13341
26
- ai_edge_quantizer/algorithms/__init__.py,sha256=lpq1g2ayg3lCPLy79t2VicYcnGKw64FfYIj1V7J-4m8,676
27
- ai_edge_quantizer/algorithms/nonlinear_quantize/__init__.py,sha256=lpq1g2ayg3lCPLy79t2VicYcnGKw64FfYIj1V7J-4m8,676
28
- ai_edge_quantizer/algorithms/nonlinear_quantize/float_casting.py,sha256=Bs9CK7wZAw6jNaZ8xEtbwO2vM34VYXNZSMVWvxJo9nw,9297
29
- ai_edge_quantizer/algorithms/nonlinear_quantize/float_casting_test.py,sha256=s64eDDH9bmRWy6Bl1peHnhGewLnFJjvnhYOdjo1zYOA,22625
30
- ai_edge_quantizer/algorithms/uniform_quantize/__init__.py,sha256=lpq1g2ayg3lCPLy79t2VicYcnGKw64FfYIj1V7J-4m8,676
31
- ai_edge_quantizer/algorithms/uniform_quantize/common_quantize.py,sha256=wPZevOuowJczG9t4Gynzv7tIeH6zhOnaKPsfr2K_fsk,21259
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=OTXjEZ3Ctq3ffYzisX-6HwgK_DuA7uos_aap5PiIUPE,8686
34
- ai_edge_quantizer/algorithms/uniform_quantize/dequantized_weight_recovery_test.py,sha256=y7BK11fkF63Ex_Jzg3fbIdy0D_Ca6HuvChVZR7Uwggc,8073
35
- ai_edge_quantizer/algorithms/uniform_quantize/naive_min_max_quantize.py,sha256=fBqSidFVKZmdO-xIFfwZPdIN1eLJjOik8mUZxZj2ljk,12149
36
- ai_edge_quantizer/algorithms/uniform_quantize/naive_min_max_quantize_test.py,sha256=Hok09dloSyBfD0oDM5VABdSZjM9JWSQhm_hDHNbFujA,7640
37
- ai_edge_quantizer/algorithms/uniform_quantize/uniform_quantize_tensor.py,sha256=Q_vx7YN7KMpjubsngxRdJ4bfdSIV-gmXjtVuxIkZuX4,11078
38
- ai_edge_quantizer/algorithms/uniform_quantize/uniform_quantize_tensor_test.py,sha256=WZ4_bvbG999nOtCIqn7mrMnpRdoJOdiyzxhsL_QiPHA,11395
39
- ai_edge_quantizer/algorithms/utils/__init__.py,sha256=lpq1g2ayg3lCPLy79t2VicYcnGKw64FfYIj1V7J-4m8,676
40
- ai_edge_quantizer/algorithms/utils/common_utils.py,sha256=nlLpUY1LTO9ZC3X0FjQ0EArCZekGUnv2-IF0AUu5zNM,34582
41
- ai_edge_quantizer/algorithms/utils/common_utils_test.py,sha256=zqapGEfYhjQWe9cNGPLmdbwtEUUYQRhlO_kNe0cXX6E,18104
42
- ai_edge_quantizer/transformations/__init__.py,sha256=lpq1g2ayg3lCPLy79t2VicYcnGKw64FfYIj1V7J-4m8,676
43
- ai_edge_quantizer/transformations/dequant_insert.py,sha256=sL1LHFVzBDSd9jgrzlHz38LWU0bwmVX7iBkaNcui0ts,3566
44
- ai_edge_quantizer/transformations/dequant_insert_test.py,sha256=NJ18PnG71_AvUPz3Cr_TmG6URMeBfa7IiDDyddfTkKQ,10830
45
- ai_edge_quantizer/transformations/emulated_subchannel.py,sha256=HVaRxoC8PCAvy3xeMv3OIymukUy_yW1zK0xN8Ann6I4,13602
46
- ai_edge_quantizer/transformations/emulated_subchannel_test.py,sha256=gZP6u9NdPXl7s19qB_Un8evou9ZZV6I9Gy0E1rdobHM,7722
47
- ai_edge_quantizer/transformations/quant_insert.py,sha256=jn6HsJaV-sqBiFPY-Aqbd64t8zgcYVkEkZI375x_FWY,3958
48
- ai_edge_quantizer/transformations/quant_insert_test.py,sha256=X9ptPDvJCFkR5tejKnD1SlHFGPazQTW-wNNMV9MEAuw,10107
49
- ai_edge_quantizer/transformations/quantize_tensor.py,sha256=6CyUFR7fGmzbS-mSuDlSSCJJGxY9X_WnCmEuKqL4LzQ,7864
50
- ai_edge_quantizer/transformations/quantize_tensor_test.py,sha256=QnJmQ_-XN5X0oR57FoY9bWGTp7migf11psbdO9R2pLg,9050
51
- ai_edge_quantizer/transformations/transformation_utils.py,sha256=BaKy5LYWgqli62XGo3AGRDNtHjwpBNp5VF5XgFbfVmg,4298
52
- ai_edge_quantizer/transformations/transformation_utils_test.py,sha256=ks81nNvruOC88Tjdk3_qwku0V8p54p3gOqfObzNhWMM,5371
53
- ai_edge_quantizer/utils/__init__.py,sha256=lpq1g2ayg3lCPLy79t2VicYcnGKw64FfYIj1V7J-4m8,676
54
- ai_edge_quantizer/utils/calibration_utils.py,sha256=1Fj9MIO6aLZIRgyd4axvZN4S_O64nB_-Miu1WP664js,2536
55
- ai_edge_quantizer/utils/calibration_utils_test.py,sha256=Z-AcdTieesWFKyKBb08ZXm4Mgu6cvJ4bg2-MJ7hLD10,2856
56
- ai_edge_quantizer/utils/test_utils.py,sha256=95BDAdjE4Zvd6JZ90fG8FE3wKWE-Lu0ZIE3hQ1B6adI,3616
57
- ai_edge_quantizer/utils/tfl_flatbuffer_utils.py,sha256=F6_AkCSv35FAhJX2qel8VTARhGOVwaeo7_mqRZygrpA,10126
58
- ai_edge_quantizer/utils/tfl_flatbuffer_utils_test.py,sha256=AbyDxoM62k4ojD8gPdkWo--xe5hlX3t0kobQSA80kuk,7740
59
- ai_edge_quantizer/utils/tfl_interpreter_utils.py,sha256=SM8H4i7Jq_nfdsJpImopHndNCJznlLr-6ptUbp5bVWA,10558
60
- ai_edge_quantizer/utils/tfl_interpreter_utils_test.py,sha256=Op3JxtOqlrjzmYF18jnnstL1k9xiY9kKJ8S2vklKGkc,11327
61
- ai_edge_quantizer/utils/validation_utils.py,sha256=oYw33Sg547AqtGw-choPUJmp9SAKkV46J_ddqSsum2Q,3950
62
- ai_edge_quantizer/utils/validation_utils_test.py,sha256=V_qNDikPD4OPB-siOLQCWNVWTAu87h2IgNYt7teFd-o,2934
63
- ai_edge_quantizer_nightly-0.0.1.dev20250302.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
64
- ai_edge_quantizer_nightly-0.0.1.dev20250302.dist-info/METADATA,sha256=QsysTpOi0EkWtLVhaqBS1A-I1w7vWn3VBtyiSVPUXUc,1528
65
- ai_edge_quantizer_nightly-0.0.1.dev20250302.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
66
- ai_edge_quantizer_nightly-0.0.1.dev20250302.dist-info/top_level.txt,sha256=8QTfPnFXNVUhScFLaa-NWZMFWMn72M50DVPubpwWB1g,18
67
- ai_edge_quantizer_nightly-0.0.1.dev20250302.dist-info/RECORD,,