1 /* Copyright 2015 The TensorFlow Authors. All Rights Reserved.
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 #define EIGEN_USE_THREADS
17
18 #include "tensorflow/cc/ops/const_op.h"
19 #include "tensorflow/cc/ops/image_ops.h"
20 #include "tensorflow/cc/ops/nn_ops.h"
21 #include "tensorflow/cc/ops/sendrecv_ops.h"
22 #include "tensorflow/cc/ops/standard_ops.h"
23 #include "tensorflow/core/framework/tensor_testutil.h"
24 #include "tensorflow/core/kernels/quantization_utils.h"
25 #include "tensorflow/core/lib/core/status_test_util.h"
26 #include "tensorflow/core/platform/test.h"
27 #include "tensorflow/core/platform/test_benchmark.h"
28 #include "tensorflow/core/public/session.h"
29 #include "tensorflow/tools/graph_transforms/transform_utils.h"
30
31 namespace tensorflow {
32 namespace graph_transforms {
33
34 // Declare here, so we don't need a public header.
35 Status QuantizeNodes(const GraphDef& input_graph_def,
36 const TransformFuncContext& context,
37 GraphDef* output_graph_def);
38 Status RemoveRedundantQuantizations(const GraphDef& input_graph_def,
39 const TransformFuncContext& context,
40 GraphDef* output_graph_def);
41 Status QuantizePlaceholders(const GraphDef& input_graph_def,
42 const TransformFuncContext& context,
43 GraphDef* output_graph_def);
44 Status ConvertFakeQuantsToRequantize(const GraphDef& input_graph_def,
45 const TransformFuncContext& context,
46 GraphDef* output_graph_def);
47 Status MergeAdjacentRequantizes(const GraphDef& input_graph_def,
48 const TransformFuncContext& context,
49 GraphDef* output_graph_def);
50 Status HoistFakeQuants(const GraphDef& input_graph_def,
51 const TransformFuncContext& context,
52 GraphDef* output_graph_def);
53 Status MergeDuplicateNodes(const GraphDef& input_graph_def,
54 const TransformFuncContext& context,
55 GraphDef* output_graph_def);
56
57 class QuantizeNodesTest : public ::testing::Test {
58 protected:
TestTransformedVersusFloatGraph(const TransformFunc & transform_function,const GraphDef & float_graph_def,const std::vector<std::pair<string,Tensor>> & float_inputs,const std::vector<std::pair<string,Tensor>> & transformed_inputs,const std::vector<string> & output_names,const TransformFuncContext & in_context,double threshold,GraphDef * transformed_graph_def)59 void TestTransformedVersusFloatGraph(
60 const TransformFunc& transform_function, const GraphDef& float_graph_def,
61 const std::vector<std::pair<string, Tensor>>& float_inputs,
62 const std::vector<std::pair<string, Tensor>>& transformed_inputs,
63 const std::vector<string>& output_names,
64 const TransformFuncContext& in_context, double threshold,
65 GraphDef* transformed_graph_def) {
66 std::unique_ptr<Session> float_session(NewSession(SessionOptions()));
67 TF_ASSERT_OK(float_session->Create(float_graph_def));
68 std::vector<Tensor> float_outputs;
69 TF_ASSERT_OK(
70 float_session->Run(float_inputs, output_names, {}, &float_outputs));
71
72 TransformFuncContext context(in_context);
73 std::vector<string> input_names;
74 for (const std::pair<const string&, const Tensor&> float_input :
75 float_inputs) {
76 context.input_names.push_back(float_input.first);
77 }
78
79 context.output_names = output_names;
80 TF_ASSERT_OK(
81 transform_function(float_graph_def, context, transformed_graph_def));
82
83 std::unique_ptr<Session> transformed_session(NewSession(SessionOptions()));
84 TF_ASSERT_OK(transformed_session->Create(*transformed_graph_def));
85 std::vector<Tensor> transformed_outputs;
86 TF_ASSERT_OK(transformed_session->Run(transformed_inputs, output_names, {},
87 &transformed_outputs));
88
89 const int output_count = output_names.size();
90 EXPECT_EQ(output_count, float_outputs.size());
91 EXPECT_EQ(output_count, transformed_outputs.size());
92 for (int i = 0; i < output_count; ++i) {
93 test::ExpectTensorNear<float>(float_outputs[i], transformed_outputs[i],
94 threshold);
95 }
96 }
97
TestQuantizedVersusFloatGraph(const GraphDef & float_graph_def,const std::vector<std::pair<string,Tensor>> & inputs,const std::vector<string> & output_names)98 void TestQuantizedVersusFloatGraph(
99 const GraphDef& float_graph_def,
100 const std::vector<std::pair<string, Tensor>>& inputs,
101 const std::vector<string>& output_names) {
102 GraphDef quantized_graph_def;
103 TestTransformedVersusFloatGraph(QuantizeNodes, float_graph_def, inputs,
104 inputs, output_names, {}, 1.0,
105 &quantized_graph_def);
106 // Reshape is not included here because it can be added as part of the
107 // quantization process.
108 const std::set<string> quantizable_ops = {
109 "Add", "BiasAdd", "Concat", "Conv2D", "MatMul", "Relu",
110 "Relu6", "ResizeBilinear", "AvgPool", "MaxPool", "Mul"};
111 for (const NodeDef& node : quantized_graph_def.node()) {
112 EXPECT_EQ(0, quantizable_ops.count(node.op()))
113 << "Found quantizable node " << node.op() << " for node named "
114 << node.name();
115 }
116 }
117
TestGraphWithInputRange(const GraphDef & float_graph_def,const std::vector<std::pair<string,Tensor>> & float_inputs,const std::vector<string> & output_names,float range_min,float range_max)118 void TestGraphWithInputRange(
119 const GraphDef& float_graph_def,
120 const std::vector<std::pair<string, Tensor>>& float_inputs,
121 const std::vector<string>& output_names, float range_min,
122 float range_max) {
123 TransformFuncContext context;
124 context.params["input_min"] = {strings::StrCat(range_min)};
125 context.params["input_max"] = {strings::StrCat(range_max)};
126
127 std::vector<std::pair<string, Tensor>> quantized_inputs;
128 for (const std::pair<string, Tensor>& float_input : float_inputs) {
129 const Tensor& float_tensor = float_input.second;
130 Tensor quantized_tensor(DT_QUINT8, float_tensor.shape());
131 FloatTensorToQuantizedInPlace<quint8>(float_tensor, range_min, range_max,
132 &quantized_tensor);
133 quantized_inputs.push_back({float_input.first, quantized_tensor});
134 }
135
136 GraphDef quantized_graph_def;
137 TestTransformedVersusFloatGraph(
138 QuantizeNodes, float_graph_def, float_inputs, quantized_inputs,
139 output_names, context, 1.0, &quantized_graph_def);
140 }
141
TestGraphWithFallbackRange(const GraphDef & float_graph_def,const std::vector<std::pair<string,Tensor>> & float_inputs,const std::vector<string> & output_names,float range_min,float range_max,GraphDef * quantized_graph_def)142 void TestGraphWithFallbackRange(
143 const GraphDef& float_graph_def,
144 const std::vector<std::pair<string, Tensor>>& float_inputs,
145 const std::vector<string>& output_names, float range_min, float range_max,
146 GraphDef* quantized_graph_def) {
147 TransformFuncContext context;
148 context.params["fallback_min"] = {strings::StrCat(range_min)};
149 context.params["fallback_max"] = {strings::StrCat(range_max)};
150 TestTransformedVersusFloatGraph(QuantizeNodes, float_graph_def,
151 float_inputs, float_inputs, output_names,
152 context, 2.0, quantized_graph_def);
153 }
154
TestIgnoreOps(std::initializer_list<string> ops_to_ignore)155 void TestIgnoreOps(std::initializer_list<string> ops_to_ignore) {
156 auto root = tensorflow::Scope::NewRootScope();
157 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
158
159 // A small helper to construct a Const op.
160 auto const_op = [&](const string& name, const TensorShape& shape,
161 std::initializer_list<float> values) {
162 Tensor tensor(DT_FLOAT, shape);
163 test::FillValues<float>(&tensor, values);
164 return Const(root.WithOpName(name), Input::Initializer(tensor));
165 };
166
167 // A simple graph with two different quantizable ops.
168 int m = 1;
169 int n = 1;
170 int k = 1;
171 Output a_op = const_op("a_op", {m, k}, {2});
172 Output b_op = const_op("b_op", {k, n}, {3});
173 Output c_op = const_op("c_op", {m, k}, {1});
174 Output d_op = const_op("d_op", {k, n}, {4});
175 Output mat_mul_op = MatMul(root.WithOpName("mat_mul_op"), a_op, b_op);
176 Output mul_op = Mul(root.WithOpName("mul"), c_op, d_op);
177
178 GraphDef float_graph_def;
179 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
180
181 TransformFuncContext context;
182 if (ops_to_ignore.size() > 0) {
183 context.params["ignore_op"] = ops_to_ignore;
184 }
185
186 GraphDef quantized_graph_def;
187 TestTransformedVersusFloatGraph(QuantizeNodes, float_graph_def, {}, {},
188 {"mat_mul_op", "mul"}, context, 1.0,
189 &quantized_graph_def);
190
191 // Make sure the quantized graph still contains the op that should have
192 // been ignored by QuantizeNodes.
193 for (const string& op_name : ops_to_ignore) {
194 bool exists_in_quantized_graph = false;
195 for (const NodeDef& node : quantized_graph_def.node()) {
196 if (node.op() == op_name) {
197 exists_in_quantized_graph = true;
198 break;
199 }
200 }
201 EXPECT_TRUE(exists_in_quantized_graph)
202 << "Op " << op_name
203 << " should not have been replace by a quantized version";
204 }
205 }
206
TestQuantizeMatMul(int m,int n,int k,const std::vector<float> & a_values,const std::vector<float> & b_values)207 void TestQuantizeMatMul(int m, int n, int k,
208 const std::vector<float>& a_values,
209 const std::vector<float>& b_values) {
210 auto root = tensorflow::Scope::NewRootScope();
211 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
212
213 Tensor a_tensor(DT_FLOAT, TensorShape({m, k}));
214 test::FillValues<float>(&a_tensor, a_values);
215 Output a_op = Const(root.WithOpName("a_op"), Input::Initializer(a_tensor));
216
217 Tensor b_tensor(DT_FLOAT, TensorShape({k, n}));
218 test::FillValues<float>(&b_tensor, b_values);
219 Output b_op = Const(root.WithOpName("b_op"), Input::Initializer(b_tensor));
220
221 Output mat_mul_op = MatMul(root.WithOpName("mat_mul_op"), a_op, b_op);
222
223 GraphDef float_graph_def;
224 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
225
226 TestQuantizedVersusFloatGraph(float_graph_def, {}, {"mat_mul_op"});
227 }
228
TestQuantizeMatMulTiny()229 void TestQuantizeMatMulTiny() {
230 // These tests are added to test the generate case where
231 // min(matrix) == max(matrix), which used to cause problems.
232 TestQuantizeMatMul(1, 1, 1, {2}, {3});
233 TestQuantizeMatMul(1, 2, 1, {1}, {2, 3});
234 TestQuantizeMatMul(1, 1, 2, {1, 1}, {1, 1});
235 TestQuantizeMatMul(1, 1, 2, {0, 0}, {1, 1});
236 // The general case.
237 TestQuantizeMatMul(1, 1, 2, {1, 2}, {1, 2});
238 }
239
TestQuantizeMatMulSmall()240 void TestQuantizeMatMulSmall() {
241 TestQuantizeMatMul(2, 4, 3, {1, 2, 3, 4, 5, 6},
242 {7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18});
243 }
244
TestQuantizeMul()245 void TestQuantizeMul() {
246 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
247
248 std::vector<int64_t> x_shape({10, 100});
249 const size_t x_num_elements = TensorShape(x_shape).num_elements();
250 std::vector<float> x_values(x_num_elements);
251 for (int i = 0; i < x_num_elements; ++i) {
252 x_values[i] = (i % 256) / 256.0f;
253 }
254
255 std::vector<int64_t> y_shape({100});
256 const size_t y_num_elements = TensorShape(y_shape).num_elements();
257 std::vector<float> y_values(y_num_elements);
258 for (int i = 0; i < y_num_elements; ++i) {
259 y_values[i] = ((i + 23) % 123) - 50;
260 }
261
262 Scope root = Scope::NewRootScope();
263
264 Tensor x_float_tensor(DT_FLOAT, TensorShape(x_shape));
265 test::FillValues<float>(&x_float_tensor, x_values);
266 Output x = Const(root.WithOpName("x"), Input::Initializer(x_float_tensor));
267
268 Tensor y_float_tensor(DT_FLOAT, TensorShape(y_shape));
269 test::FillValues<float>(&y_float_tensor, y_values);
270 Output y = Const(root.WithOpName("y"), Input::Initializer(y_float_tensor));
271
272 Mul mul = Mul(root.WithOpName("mul"), x, y);
273
274 GraphDef float_graph_def;
275 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
276
277 TestQuantizedVersusFloatGraph(float_graph_def, {}, {"mul"});
278 }
279
TestQuantizeAdd()280 void TestQuantizeAdd() {
281 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
282
283 std::vector<int64_t> x_shape({10, 100});
284 const size_t x_num_elements = TensorShape(x_shape).num_elements();
285 std::vector<float> x_values(x_num_elements);
286 for (int i = 0; i < x_num_elements; ++i) {
287 x_values[i] = (i % 256) / 256.0f;
288 }
289
290 std::vector<int64_t> y_shape({100});
291 const size_t y_num_elements = TensorShape(y_shape).num_elements();
292 std::vector<float> y_values(y_num_elements);
293 for (int i = 0; i < y_num_elements; ++i) {
294 y_values[i] = ((i + 23) % 123) - 50;
295 }
296
297 Scope root = Scope::NewRootScope();
298
299 Tensor x_float_tensor(DT_FLOAT, TensorShape(x_shape));
300 test::FillValues<float>(&x_float_tensor, x_values);
301 Output x = Const(root.WithOpName("x"), Input::Initializer(x_float_tensor));
302
303 Tensor y_float_tensor(DT_FLOAT, TensorShape(y_shape));
304 test::FillValues<float>(&y_float_tensor, y_values);
305 Output y = Const(root.WithOpName("y"), Input::Initializer(y_float_tensor));
306
307 Add add = Add(root.WithOpName("add"), x, y);
308
309 GraphDef float_graph_def;
310 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
311
312 TestQuantizedVersusFloatGraph(float_graph_def, {}, {"add"});
313 }
314
TestQuantizeConv2D(int depth,int input_width,int input_height,int input_batch_count,int filter_size,int filter_count,int stride,const string & padding,const std::vector<float> & input_values,const std::vector<float> & filter_values)315 void TestQuantizeConv2D(int depth, int input_width, int input_height,
316 int input_batch_count, int filter_size,
317 int filter_count, int stride, const string& padding,
318 const std::vector<float>& input_values,
319 const std::vector<float>& filter_values) {
320 auto root = tensorflow::Scope::NewRootScope();
321 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
322
323 Tensor input_tensor(DT_FLOAT, TensorShape({input_batch_count, input_height,
324 input_width, depth}));
325 test::FillValues<float>(&input_tensor, input_values);
326 Output input_op =
327 Const(root.WithOpName("input_op"), Input::Initializer(input_tensor));
328
329 Tensor filter_tensor(
330 DT_FLOAT, TensorShape({filter_size, filter_size, depth, filter_count}));
331 test::FillValues<float>(&filter_tensor, filter_values);
332 Output filter_op =
333 Const(root.WithOpName("filter_op"), Input::Initializer(filter_tensor));
334
335 Output conv_op = Conv2D(root.WithOpName("conv_op"), input_op, filter_op,
336 {1, stride, stride, 1}, padding);
337
338 GraphDef float_graph_def;
339 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
340
341 TestQuantizedVersusFloatGraph(float_graph_def, {}, {"conv_op"});
342 }
343
TestQuantizeBiasAdd()344 void TestQuantizeBiasAdd() {
345 auto root = tensorflow::Scope::NewRootScope();
346 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
347
348 Tensor input_tensor(DT_FLOAT, TensorShape({1, 1, 2, 6}));
349 test::FillIota<float>(&input_tensor, 1);
350 Output input_op =
351 Const(root.WithOpName("input_op"), Input::Initializer(input_tensor));
352
353 Tensor offset_tensor(DT_FLOAT, TensorShape({6}));
354 test::FillIota<float>(&offset_tensor, 1);
355 Output offset_op =
356 Const(root.WithOpName("offset_op"), Input::Initializer(offset_tensor));
357
358 Output bias_add_op =
359 BiasAdd(root.WithOpName("bias_add_op"), input_op, offset_op);
360
361 GraphDef float_graph_def;
362 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
363
364 TestQuantizedVersusFloatGraph(float_graph_def, {}, {"bias_add_op"});
365 }
366
TestQuantizeConcat()367 void TestQuantizeConcat() {
368 auto root = tensorflow::Scope::NewRootScope();
369 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
370
371 Tensor shape_tensor(DT_INT32, TensorShape({}));
372 test::FillValues<int32>(&shape_tensor, {0});
373 Output shape_op =
374 Const(root.WithOpName("shape_op"), Input::Initializer(shape_tensor));
375
376 Tensor a_tensor(DT_FLOAT, TensorShape({2, 2, 3}));
377 test::FillValues<float>(&a_tensor, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
378 Output a_op = Const(root.WithOpName("a_op"), Input::Initializer(a_tensor));
379
380 Tensor b_tensor(DT_FLOAT, TensorShape({2, 2, 3}));
381 test::FillValues<float>(&b_tensor,
382 {13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24});
383 Output b_op = Const(root.WithOpName("b_op"), Input::Initializer(b_tensor));
384
385 Output concat_op =
386 Concat(root.WithOpName("concat_op"), {a_op, b_op}, shape_op);
387
388 GraphDef float_graph_def;
389 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
390
391 TestQuantizedVersusFloatGraph(float_graph_def, {}, {"concat_op"});
392 }
393
TestQuantizeRelu()394 void TestQuantizeRelu() {
395 auto root = tensorflow::Scope::NewRootScope();
396 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
397
398 Tensor constant_tensor(DT_FLOAT, TensorShape({1, 2, 6, 1}));
399 test::FillValues<float>(&constant_tensor,
400 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
401 Output constant_op = Const(root.WithOpName("constant_op"),
402 Input::Initializer(constant_tensor));
403
404 Output relu_op = Relu(root.WithOpName("relu_op"), constant_op);
405
406 GraphDef float_graph_def;
407 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
408
409 TestQuantizedVersusFloatGraph(float_graph_def, {}, {"relu_op"});
410 }
411
TestQuantizeRelu6()412 void TestQuantizeRelu6() {
413 auto root = tensorflow::Scope::NewRootScope();
414 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
415
416 Tensor constant_tensor(DT_FLOAT, TensorShape({1, 2, 6, 1}));
417 test::FillValues<float>(&constant_tensor,
418 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
419 Output constant_op = Const(root.WithOpName("constant_op"),
420 Input::Initializer(constant_tensor));
421
422 Output relu6_op = Relu6(root.WithOpName("relu6_op"), constant_op);
423
424 GraphDef float_graph_def;
425 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
426
427 TestQuantizedVersusFloatGraph(float_graph_def, {}, {"relu6_op"});
428 }
429
TestQuantizeMaxPool()430 void TestQuantizeMaxPool() {
431 auto root = tensorflow::Scope::NewRootScope();
432 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
433
434 Tensor constant_tensor(DT_FLOAT, TensorShape({1, 2, 6, 1}));
435 test::FillValues<float>(&constant_tensor,
436 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
437 Output constant_op = Const(root.WithOpName("constant_op"),
438 Input::Initializer(constant_tensor));
439
440 Output max_pool_op = MaxPool(root.WithOpName("max_pool_op"), constant_op,
441 {1, 2, 2, 1}, {1, 1, 1, 1}, "SAME");
442
443 GraphDef float_graph_def;
444 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
445
446 TestQuantizedVersusFloatGraph(float_graph_def, {}, {"max_pool_op"});
447 }
448
TestQuantizeAvgPool()449 void TestQuantizeAvgPool() {
450 auto root = tensorflow::Scope::NewRootScope();
451 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
452
453 Tensor constant_tensor(DT_FLOAT, TensorShape({1, 2, 6, 1}));
454 test::FillValues<float>(&constant_tensor,
455 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
456 Output constant_op = Const(root.WithOpName("constant_op"),
457 Input::Initializer(constant_tensor));
458
459 Output avg_pool_op = AvgPool(root.WithOpName("avg_pool_op"), constant_op,
460 {1, 2, 2, 1}, {1, 1, 1, 1}, "SAME");
461
462 GraphDef float_graph_def;
463 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
464
465 TestQuantizedVersusFloatGraph(float_graph_def, {}, {"avg_pool_op"});
466 }
467
TestQuantizeReshape()468 void TestQuantizeReshape() {
469 auto root = tensorflow::Scope::NewRootScope();
470 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
471
472 Tensor constant_tensor(DT_FLOAT, TensorShape({4, 5}));
473 test::FillValues<float>(&constant_tensor,
474 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
475 11, 12, 13, 14, 15, 16, 17, 18, 19, 20});
476 Output constant_op = Const(root.WithOpName("constant_op"),
477 Input::Initializer(constant_tensor));
478
479 Output reshape_op =
480 Reshape(root.WithOpName("reshape_op"), constant_op, {10, 2});
481
482 GraphDef float_graph_def;
483 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
484
485 TestQuantizedVersusFloatGraph(float_graph_def, {}, {"reshape_op"});
486 }
487
TestRemoveRedundantQuantization()488 void TestRemoveRedundantQuantization() {
489 auto root = tensorflow::Scope::NewRootScope();
490 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
491
492 Tensor quantized_tensor(DT_QUINT8, TensorShape({}));
493 test::FillValues<quint8>(&quantized_tensor, {0});
494 Output quantized_op = Const(root.WithOpName("quantized_op"),
495 Input::Initializer(quantized_tensor));
496
497 Tensor quantized_min_tensor(DT_FLOAT, TensorShape({}));
498 test::FillValues<float>(&quantized_min_tensor, {2.0f});
499 Output quantized_min_op = Const(root.WithOpName("quantized_min_op"),
500 Input::Initializer(quantized_min_tensor));
501
502 Tensor quantized_max_tensor(DT_FLOAT, TensorShape({}));
503 test::FillValues<float>(&quantized_max_tensor, {2.0f});
504 Output quantized_max_op = Const(root.WithOpName("quantized_max_op"),
505 Input::Initializer(quantized_min_tensor));
506
507 Output dequantize_op =
508 Dequantize(root.WithOpName("dequantize_op"), quantized_op,
509 quantized_min_op, quantized_max_op);
510
511 Tensor dequantize_reshape_dims_tensor(DT_INT32, TensorShape({1}));
512 test::FillValues<int32>(&dequantize_reshape_dims_tensor, {-1});
513 Output dequantize_reshape_dims =
514 Const(root.WithOpName("dequantize_reshape_dims"),
515 Input::Initializer(dequantize_reshape_dims_tensor));
516
517 Tensor dequantize_reduction_dims_tensor(DT_INT32, TensorShape({}));
518 test::FillValues<int32>(&dequantize_reduction_dims_tensor, {0});
519 Output dequantize_reduction_dims =
520 Const(root.WithOpName("dequantize_reduction_dims"),
521 Input::Initializer(dequantize_reduction_dims_tensor));
522
523 Output dequantize_reshape = Reshape(root.WithOpName("dequantize_reshape"),
524 dequantize_op, dequantize_reshape_dims);
525
526 Output dequantize_min =
527 Min(root.WithOpName("dequantize_min"), dequantize_reshape,
528 dequantize_reduction_dims, Min::Attrs().KeepDims(false));
529
530 Output dequantize_max =
531 Max(root.WithOpName("dequantize_max"), dequantize_reshape,
532 dequantize_reduction_dims, Max::Attrs().KeepDims(false));
533
534 QuantizeV2 quantize_op(root.WithOpName("quantize_op"), dequantize_op,
535 dequantize_min, dequantize_max, DT_QUINT8,
536 QuantizeV2::Attrs().Mode("MIN_FIRST"));
537
538 Output final_dequantize =
539 Dequantize(root.WithOpName("final_dequantize"), quantize_op.output,
540 quantize_op.output_min, quantize_op.output_max);
541
542 GraphDef float_graph_def;
543 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
544
545 GraphDef removed_graph_def;
546 TestTransformedVersusFloatGraph(
547 RemoveRedundantQuantizations, float_graph_def, {}, {},
548 {"final_dequantize"}, {}, 1.0, &removed_graph_def);
549
550 std::map<string, const NodeDef*> node_map;
551 MapNamesToNodes(removed_graph_def, &node_map);
552 EXPECT_EQ(1, node_map.count("final_dequantize"));
553 EXPECT_EQ("quantized_op", node_map.at("final_dequantize")->input(0));
554 }
555
TestRemoveRedundantQuantizationWithBiasAdd()556 void TestRemoveRedundantQuantizationWithBiasAdd() {
557 auto root = tensorflow::Scope::NewRootScope();
558 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
559
560 Tensor quantized_tensor(DT_QUINT8, TensorShape({1, 6}));
561 test::FillValues<quint8>(&quantized_tensor, {0, 0, 0, 0, 0, 0});
562 Output quantized_op = Const(root.WithOpName("quantized_op"),
563 Input::Initializer(quantized_tensor));
564
565 Tensor quantized_min_tensor(DT_FLOAT, TensorShape({}));
566 test::FillValues<float>(&quantized_min_tensor, {2.0f});
567 Output quantized_min_op = Const(root.WithOpName("quantized_min_op"),
568 Input::Initializer(quantized_min_tensor));
569
570 Tensor quantized_max_tensor(DT_FLOAT, TensorShape({}));
571 test::FillValues<float>(&quantized_max_tensor, {2.0f});
572 Output quantized_max_op = Const(root.WithOpName("quantized_max_op"),
573 Input::Initializer(quantized_min_tensor));
574
575 Tensor offset_tensor(DT_QUINT8, TensorShape({6}));
576 test::FillValues<quint8>(&offset_tensor, {1, 2, 3, 4, 5, 6});
577 Output offset_op =
578 Const(root.WithOpName("offset_op"), Input::Initializer(offset_tensor));
579
580 Tensor offset_min_tensor(DT_FLOAT, TensorShape({}));
581 test::FillValues<float>(&offset_min_tensor, {0.0f});
582 Output offset_min_op = Const(root.WithOpName("offset_min_op"),
583 Input::Initializer(offset_min_tensor));
584
585 Tensor offset_max_tensor(DT_FLOAT, TensorShape({}));
586 test::FillValues<float>(&offset_max_tensor, {255.0f});
587 Output offset_max_op = Const(root.WithOpName("offset_max_op"),
588 Input::Initializer(offset_max_tensor));
589
590 QuantizedBiasAdd quantized_bias_add_op(
591 root.WithOpName("bias_add_op"), quantized_op, offset_op,
592 quantized_min_op, quantized_max_op, offset_min_op, offset_max_op,
593 DT_QINT32);
594
595 RequantizationRange requantization_range_op(
596 root.WithOpName("requantization_range_op"),
597 quantized_bias_add_op.output, quantized_bias_add_op.min_out,
598 quantized_bias_add_op.max_out);
599
600 Requantize requantize_op(
601 root.WithOpName("requantize_op"), quantized_bias_add_op.output,
602 quantized_bias_add_op.min_out, quantized_bias_add_op.max_out,
603 requantization_range_op.output_min, requantization_range_op.output_max,
604 DT_QUINT8);
605
606 Output dequantize_op =
607 Dequantize(root.WithOpName("dequantize_op"), requantize_op.output,
608 requantize_op.output_min, requantize_op.output_max);
609
610 Tensor dequantize_reshape_dims_tensor(DT_INT32, TensorShape({1}));
611 test::FillValues<int32>(&dequantize_reshape_dims_tensor, {-1});
612 Output dequantize_reshape_dims =
613 Const(root.WithOpName("dequantize_reshape_dims"),
614 Input::Initializer(dequantize_reshape_dims_tensor));
615
616 Tensor dequantize_reduction_dims_tensor(DT_INT32, TensorShape({}));
617 test::FillValues<int32>(&dequantize_reduction_dims_tensor, {0});
618 Output dequantize_reduction_dims =
619 Const(root.WithOpName("dequantize_reduction_dims"),
620 Input::Initializer(dequantize_reduction_dims_tensor));
621
622 Output dequantize_reshape = Reshape(root.WithOpName("dequantize_reshape"),
623 dequantize_op, dequantize_reshape_dims);
624
625 Output dequantize_min =
626 Min(root.WithOpName("dequantize_min"), dequantize_reshape,
627 dequantize_reduction_dims, Min::Attrs().KeepDims(false));
628
629 Output dequantize_max =
630 Max(root.WithOpName("dequantize_max"), dequantize_reshape,
631 dequantize_reduction_dims, Max::Attrs().KeepDims(false));
632
633 QuantizeV2 quantize_op(root.WithOpName("quantize_op"), dequantize_op,
634 dequantize_min, dequantize_max, DT_QUINT8,
635 QuantizeV2::Attrs().Mode("MIN_FIRST"));
636
637 Output final_dequantize =
638 Dequantize(root.WithOpName("final_dequantize"), quantize_op.output,
639 quantize_op.output_min, quantize_op.output_max);
640
641 GraphDef float_graph_def;
642 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
643
644 GraphDef removed_graph_def;
645 TestTransformedVersusFloatGraph(
646 RemoveRedundantQuantizations, float_graph_def, {}, {},
647 {"final_dequantize"}, {}, 1.0, &removed_graph_def);
648
649 std::map<string, const NodeDef*> node_map;
650 MapNamesToNodes(removed_graph_def, &node_map);
651 EXPECT_EQ(1, node_map.count("final_dequantize"));
652 EXPECT_EQ("requantize_op", node_map.at("final_dequantize")->input(0));
653 }
654
TestQuantizeResizeBilinear()655 void TestQuantizeResizeBilinear() {
656 auto root = tensorflow::Scope::NewRootScope();
657 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
658
659 Tensor size_tensor(DT_INT32, TensorShape({2}));
660 test::FillValues<int32>(&size_tensor, {256, 256});
661
662 Output constant_op = Const(root.WithOpName("size_tensor_op"),
663 Input::Initializer(size_tensor));
664
665 Output placeholder_op =
666 Placeholder(root.WithOpName("placeholder_op"), DT_FLOAT);
667
668 Output resize_bilinear_op = ResizeBilinear(
669 root.WithOpName("resize_bilinear_op"), placeholder_op, constant_op);
670
671 GraphDef float_graph_def;
672 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
673
674 Tensor input_tensor(DT_FLOAT, {1, 128, 128, 3});
675 test::FillFn<float>(&input_tensor, [](int) { return 100.0f; });
676
677 TestQuantizedVersusFloatGraph(float_graph_def,
678 {{"placeholder_op", input_tensor}},
679 {"resize_bilinear_op"});
680 }
681
TestRemoveRedundantQuantizationWithMultipleOutputs()682 void TestRemoveRedundantQuantizationWithMultipleOutputs() {
683 auto root = tensorflow::Scope::NewRootScope();
684 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
685
686 Tensor quantized_tensor(DT_QUINT8, TensorShape({1, 6}));
687 test::FillValues<quint8>(&quantized_tensor, {0, 0, 0, 0, 0, 0});
688 Output quantized_op = Const(root.WithOpName("quantized_op"),
689 Input::Initializer(quantized_tensor));
690
691 Tensor quantized_min_tensor(DT_FLOAT, TensorShape({}));
692 test::FillValues<float>(&quantized_min_tensor, {2.0f});
693 Output quantized_min_op = Const(root.WithOpName("quantized_min_op"),
694 Input::Initializer(quantized_min_tensor));
695
696 Tensor quantized_max_tensor(DT_FLOAT, TensorShape({}));
697 test::FillValues<float>(&quantized_max_tensor, {2.0f});
698 Output quantized_max_op = Const(root.WithOpName("quantized_max_op"),
699 Input::Initializer(quantized_min_tensor));
700
701 Tensor offset_tensor(DT_QUINT8, TensorShape({6}));
702 test::FillValues<quint8>(&offset_tensor, {1, 2, 3, 4, 5, 6});
703 Output offset_op =
704 Const(root.WithOpName("offset_op"), Input::Initializer(offset_tensor));
705
706 Tensor offset_min_tensor(DT_FLOAT, TensorShape({}));
707 test::FillValues<float>(&offset_min_tensor, {0.0f});
708 Output offset_min_op = Const(root.WithOpName("offset_min_op"),
709 Input::Initializer(offset_min_tensor));
710
711 Tensor offset_max_tensor(DT_FLOAT, TensorShape({}));
712 test::FillValues<float>(&offset_max_tensor, {255.0f});
713 Output offset_max_op = Const(root.WithOpName("offset_max_op"),
714 Input::Initializer(offset_max_tensor));
715
716 QuantizedBiasAdd quantized_bias_add_op(
717 root.WithOpName("bias_add_op"), quantized_op, offset_op,
718 quantized_min_op, quantized_max_op, offset_min_op, offset_max_op,
719 DT_QINT32);
720
721 RequantizationRange requantization_range_op(
722 root.WithOpName("requantization_range_op"),
723 quantized_bias_add_op.output, quantized_bias_add_op.min_out,
724 quantized_bias_add_op.max_out);
725
726 Requantize requantize_op(
727 root.WithOpName("requantize_op"), quantized_bias_add_op.output,
728 quantized_bias_add_op.min_out, quantized_bias_add_op.max_out,
729 requantization_range_op.output_min, requantization_range_op.output_max,
730 DT_QUINT8);
731
732 Output dequantize_op =
733 Dequantize(root.WithOpName("dequantize_op"), requantize_op.output,
734 requantize_op.output_min, requantize_op.output_max);
735
736 Tensor dequantize_reshape_dims_tensor(DT_INT32, TensorShape({1}));
737 test::FillValues<int32>(&dequantize_reshape_dims_tensor, {-1});
738 Output dequantize_reshape_dims =
739 Const(root.WithOpName("dequantize_reshape_dims"),
740 Input::Initializer(dequantize_reshape_dims_tensor));
741
742 Tensor dequantize_reduction_dims_tensor(DT_INT32, TensorShape({}));
743 test::FillValues<int32>(&dequantize_reduction_dims_tensor, {0});
744 Output dequantize_reduction_dims =
745 Const(root.WithOpName("dequantize_reduction_dims"),
746 Input::Initializer(dequantize_reduction_dims_tensor));
747
748 Output dequantize_reshape = Reshape(root.WithOpName("dequantize_reshape"),
749 dequantize_op, dequantize_reshape_dims);
750
751 Output dequantize_min =
752 Min(root.WithOpName("dequantize_min"), dequantize_reshape,
753 dequantize_reduction_dims, Min::Attrs().KeepDims(false));
754
755 Output dequantize_max =
756 Max(root.WithOpName("dequantize_max"), dequantize_reshape,
757 dequantize_reduction_dims, Max::Attrs().KeepDims(false));
758
759 QuantizeV2 quantize_op(root.WithOpName("quantize_op"), dequantize_op,
760 dequantize_min, dequantize_max, DT_QUINT8,
761 QuantizeV2::Attrs().Mode("MIN_FIRST"));
762
763 Output final_dequantize =
764 Dequantize(root.WithOpName("final_dequantize"), quantize_op.output,
765 quantize_op.output_min, quantize_op.output_max);
766
767 Output relu_op = Relu(root.WithOpName("relu_op"), dequantize_op);
768
769 GraphDef float_graph_def;
770 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
771
772 GraphDef removed_graph_def;
773 TestTransformedVersusFloatGraph(
774 RemoveRedundantQuantizations, float_graph_def, {}, {},
775 {"final_dequantize", "relu_op"}, {}, 1.0, &removed_graph_def);
776
777 std::map<string, int> op_type_count;
778 for (const NodeDef& node : removed_graph_def.node()) {
779 ++op_type_count[node.op()];
780 }
781 EXPECT_EQ(2, op_type_count["Dequantize"]);
782 }
783
TestQuantizePlaceholders()784 void TestQuantizePlaceholders() {
785 auto root = tensorflow::Scope::NewRootScope();
786 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
787
788 Output placeholder_op =
789 Placeholder(root.WithOpName("placeholder_op"), DT_FLOAT);
790
791 Output relu_op = Relu(root.WithOpName("relu_op"), placeholder_op);
792
793 GraphDef float_graph_def;
794 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
795
796 TransformFuncContext context;
797 context.input_names = {"placeholder_op"};
798 context.output_names = {"relu_op"};
799 context.params = {{"input_min", {"-10.0"}}, {"input_max", {"10.0"}}};
800
801 GraphDef quantized_graph_def;
802 TF_ASSERT_OK(
803 QuantizePlaceholders(float_graph_def, context, &quantized_graph_def));
804
805 Tensor input_tensor(DT_FLOAT, {});
806 input_tensor.flat<float>()(0) = 5.0f;
807
808 TestQuantizedVersusFloatGraph(
809 float_graph_def, {{"placeholder_op", input_tensor}}, {"relu_op"});
810
811 std::map<string, const NodeDef*> node_map;
812 MapNamesToNodes(quantized_graph_def, &node_map);
813 EXPECT_NE("placeholder_op", node_map.at("relu_op")->input(0));
814 EXPECT_EQ("Placeholder", node_map.at("placeholder_op")->op());
815 EXPECT_EQ(DT_QUINT8,
816 node_map.at("placeholder_op")->attr().at("dtype").type());
817 }
818
TestInputRange()819 void TestInputRange() {
820 auto root = tensorflow::Scope::NewRootScope();
821 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
822
823 const int width = 100;
824
825 Tensor a_data(DT_FLOAT, TensorShape({1, width}));
826 test::FillIota<float>(&a_data, 1.0f);
827 Output a_const = Const(root.WithOpName("a"), Input::Initializer(a_data));
828
829 Output placeholder = Placeholder(root.WithOpName("placeholder"), DT_FLOAT);
830
831 Output bias_add =
832 BiasAdd(root.WithOpName("bias_add"), a_const, placeholder);
833
834 GraphDef graph_def;
835 TF_ASSERT_OK(root.ToGraphDef(&graph_def));
836
837 Tensor placeholder_tensor(DT_FLOAT, TensorShape({width}));
838 test::FillIota<float>(&placeholder_tensor, 1.0f);
839
840 TestGraphWithInputRange(graph_def, {{"placeholder", placeholder_tensor}},
841 {"bias_add"}, 0.0f, 100.0f);
842 }
843
TestFallbackRange()844 void TestFallbackRange() {
845 auto root = tensorflow::Scope::NewRootScope();
846 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
847
848 const int width = 100;
849
850 Tensor a_data(DT_FLOAT, TensorShape({1, width}));
851 test::FillIota<float>(&a_data, 1.0f);
852 Output a_const = Const(root.WithOpName("a"), Input::Initializer(a_data));
853
854 Output placeholder = Placeholder(root.WithOpName("placeholder"), DT_FLOAT);
855
856 Output bias_add =
857 BiasAdd(root.WithOpName("bias_add"), a_const, placeholder);
858
859 GraphDef graph_def;
860 TF_ASSERT_OK(root.ToGraphDef(&graph_def));
861
862 Tensor placeholder_tensor(DT_FLOAT, TensorShape({width}));
863 test::FillIota<float>(&placeholder_tensor, 1.0f);
864
865 GraphDef quantized_graph_def;
866 TestGraphWithFallbackRange(graph_def, {{"placeholder", placeholder_tensor}},
867 {"bias_add"}, 0.0f, 200.0f,
868 &quantized_graph_def);
869
870 for (const NodeDef& node : quantized_graph_def.node()) {
871 EXPECT_NE("RequantizationRange", node.op());
872 }
873 }
874
TestConvertFakeQuantsToRequantize()875 void TestConvertFakeQuantsToRequantize() {
876 auto root = tensorflow::Scope::NewRootScope();
877 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
878
879 Tensor input_tensor(DT_FLOAT, TensorShape({1, 1, 2, 6}));
880 test::FillIota<float>(&input_tensor, 1);
881 Output input_op =
882 Const(root.WithOpName("input_op"), Input::Initializer(input_tensor));
883
884 Tensor offset_tensor(DT_FLOAT, TensorShape({6}));
885 test::FillIota<float>(&offset_tensor, 1);
886 Output offset_op =
887 Const(root.WithOpName("offset_op"), Input::Initializer(offset_tensor));
888
889 Output bias_add_op =
890 BiasAdd(root.WithOpName("bias_add_op"), input_op, offset_op);
891
892 Tensor fake_quant_min_tensor(DT_FLOAT, TensorShape({}));
893 test::FillValues<float>(&fake_quant_min_tensor, {0.0f});
894 Output fake_quant_min_op = Const(root.WithOpName("fake_quant_min_op"),
895 Input::Initializer(fake_quant_min_tensor));
896
897 Tensor fake_quant_max_tensor(DT_FLOAT, TensorShape({}));
898 test::FillValues<float>(&fake_quant_max_tensor, {18.0f});
899 Output fake_quant_max_op = Const(root.WithOpName("fake_quant_max_op"),
900 Input::Initializer(fake_quant_max_tensor));
901
902 Output fake_quant_op =
903 FakeQuantWithMinMaxVars(root.WithOpName("fake_quant_op"), bias_add_op,
904 fake_quant_min_op, fake_quant_max_op);
905
906 GraphDef float_graph_def;
907 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
908
909 GraphDef converted_graph_def;
910 TestTransformedVersusFloatGraph(ConvertFakeQuantsToRequantize,
911 float_graph_def, {}, {}, {"fake_quant_op"},
912 {}, 1.0, &converted_graph_def);
913
914 for (const NodeDef& node : converted_graph_def.node()) {
915 EXPECT_NE("FakeQuantWithMinMaxVars", node.op());
916 }
917 }
918
TestMergeAdjacentRequantizes()919 void TestMergeAdjacentRequantizes() {
920 auto root = tensorflow::Scope::NewRootScope();
921 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
922
923 Tensor input_tensor(DT_QUINT8, TensorShape({1, 1, 2, 6}));
924 test::FillValues<quint8>(&input_tensor,
925 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12});
926 Output input_op =
927 Const(root.WithOpName("input_op"), Input::Initializer(input_tensor));
928
929 Tensor input_min_tensor(DT_FLOAT, TensorShape({}));
930 test::FillValues<float>(&input_min_tensor, {0.0f});
931 Output input_min_op = Const(root.WithOpName("input_min_op"),
932 Input::Initializer(input_min_tensor));
933
934 Tensor input_max_tensor(DT_FLOAT, TensorShape({}));
935 test::FillValues<float>(&input_max_tensor, {255.0f});
936 Output input_max_op = Const(root.WithOpName("input_max_op"),
937 Input::Initializer(input_max_tensor));
938
939 Tensor offset_tensor(DT_QUINT8, TensorShape({6}));
940 test::FillValues<quint8>(&offset_tensor, {1, 2, 3, 4, 5, 6});
941 Output offset_op =
942 Const(root.WithOpName("offset_op"), Input::Initializer(offset_tensor));
943
944 Tensor offset_min_tensor(DT_FLOAT, TensorShape({}));
945 test::FillValues<float>(&offset_min_tensor, {0.0f});
946 Output offset_min_op = Const(root.WithOpName("offset_min_op"),
947 Input::Initializer(offset_min_tensor));
948
949 Tensor offset_max_tensor(DT_FLOAT, TensorShape({}));
950 test::FillValues<float>(&offset_max_tensor, {255.0f});
951 Output offset_max_op = Const(root.WithOpName("offset_max_op"),
952 Input::Initializer(offset_max_tensor));
953
954 QuantizedBiasAdd quantized_bias_add_op(
955 root.WithOpName("quantized_bias_add_op"), input_op, offset_op,
956 input_min_op, input_max_op, offset_min_op, offset_max_op, DT_QINT32);
957
958 RequantizationRange requantization_range_op(
959 root.WithOpName("requantization_range_op"),
960 quantized_bias_add_op.output, quantized_bias_add_op.min_out,
961 quantized_bias_add_op.max_out);
962
963 Requantize requantize_op(
964 root.WithOpName("requantize_op"), quantized_bias_add_op.output,
965 quantized_bias_add_op.min_out, quantized_bias_add_op.max_out,
966 requantization_range_op.output_min, requantization_range_op.output_max,
967 DT_QUINT8);
968
969 Output dequantize_op =
970 Dequantize(root.WithOpName("dequantize_op"), requantize_op.output,
971 requantize_op.output_min, requantize_op.output_max,
972 Dequantize::Attrs().Mode("MIN_FIRST"));
973
974 Tensor quantize_min_tensor(DT_FLOAT, TensorShape({}));
975 test::FillValues<float>(&quantize_min_tensor, {0.0f});
976 Output quantize_min_op = Const(root.WithOpName("quantize_min_op"),
977 Input::Initializer(quantize_min_tensor));
978
979 Tensor quantize_max_tensor(DT_FLOAT, TensorShape({}));
980 test::FillValues<float>(&quantize_max_tensor, {255.0f});
981 Output quantize_max_op = Const(root.WithOpName("quantize_max_op"),
982 Input::Initializer(quantize_max_tensor));
983
984 QuantizeV2 quantize_op(root.WithOpName("quantize_op"), dequantize_op,
985 quantize_min_op, quantize_max_op, DT_QINT32,
986 QuantizeV2::Attrs().Mode("MIN_FIRST"));
987
988 Tensor fake_requantize_min_tensor(DT_FLOAT, TensorShape({}));
989 test::FillValues<float>(&fake_requantize_min_tensor, {0.0f});
990 Output fake_requantize_min_op =
991 Const(root.WithOpName("fake_requantize_min_op"),
992 Input::Initializer(fake_requantize_min_tensor));
993
994 Tensor fake_requantize_max_tensor(DT_FLOAT, TensorShape({}));
995 test::FillValues<float>(&fake_requantize_max_tensor, {255.0f});
996 Output fake_requantize_max_op =
997 Const(root.WithOpName("fake_requantize_max_op"),
998 Input::Initializer(fake_requantize_max_tensor));
999
1000 Requantize fake_requantize_op(
1001 root.WithOpName("fake_requantize_op"), quantize_op.output,
1002 quantize_op.output_min, quantize_op.output_max, fake_requantize_min_op,
1003 fake_requantize_max_op, DT_QUINT8);
1004
1005 Output fake_dequantize_op = Dequantize(
1006 root.WithOpName("fake_dequantize_op"), fake_requantize_op.output,
1007 fake_requantize_op.output_min, fake_requantize_op.output_max,
1008 Dequantize::Attrs().Mode("MIN_FIRST"));
1009
1010 GraphDef float_graph_def;
1011 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
1012
1013 GraphDef converted_graph_def;
1014 TestTransformedVersusFloatGraph(MergeAdjacentRequantizes, float_graph_def,
1015 {}, {}, {"fake_dequantize_op"}, {}, 1.0,
1016 &converted_graph_def);
1017
1018 int requantize_count = 0;
1019 for (const NodeDef& node : converted_graph_def.node()) {
1020 if (node.op() == "Requantize") {
1021 ++requantize_count;
1022 }
1023 }
1024 EXPECT_EQ(1, requantize_count);
1025 }
1026
TestConvertFakeQuantsEndToEnd()1027 void TestConvertFakeQuantsEndToEnd() {
1028 auto root = tensorflow::Scope::NewRootScope();
1029 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
1030
1031 Tensor input_tensor(DT_FLOAT, TensorShape({1, 1, 2, 6}));
1032 test::FillIota<float>(&input_tensor, 1);
1033 Output input_op =
1034 Const(root.WithOpName("input_op"), Input::Initializer(input_tensor));
1035
1036 Tensor offset_tensor(DT_FLOAT, TensorShape({6}));
1037 test::FillIota<float>(&offset_tensor, 1);
1038 Output offset_op =
1039 Const(root.WithOpName("offset_op"), Input::Initializer(offset_tensor));
1040
1041 Output bias_add_op =
1042 BiasAdd(root.WithOpName("bias_add_op"), input_op, offset_op);
1043
1044 Tensor fake_quant_min_tensor(DT_FLOAT, TensorShape({}));
1045 test::FillValues<float>(&fake_quant_min_tensor, {0.0f});
1046 Output fake_quant_min_op = Const(root.WithOpName("fake_quant_min_op"),
1047 Input::Initializer(fake_quant_min_tensor));
1048
1049 Tensor fake_quant_max_tensor(DT_FLOAT, TensorShape({}));
1050 test::FillValues<float>(&fake_quant_max_tensor, {18.0f});
1051 Output fake_quant_max_op = Const(root.WithOpName("fake_quant_max_op"),
1052 Input::Initializer(fake_quant_max_tensor));
1053
1054 Output fake_quant_op =
1055 FakeQuantWithMinMaxVars(root.WithOpName("fake_quant_op"), bias_add_op,
1056 fake_quant_min_op, fake_quant_max_op);
1057
1058 GraphDef float_graph_def;
1059 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
1060
1061 GraphDef converted_graph_def;
1062 TestTransformedVersusFloatGraph(QuantizeNodes, float_graph_def, {}, {},
1063 {"fake_quant_op"}, {}, 1.0,
1064 &converted_graph_def);
1065
1066 int requantize_count = 0;
1067 for (const NodeDef& node : converted_graph_def.node()) {
1068 EXPECT_NE("FakeQuantWithMinMaxVars", node.op());
1069 if (node.op() == "Requantize") {
1070 ++requantize_count;
1071 }
1072 }
1073 EXPECT_EQ(1, requantize_count);
1074 }
1075
TestHoistFakeQuants()1076 void TestHoistFakeQuants() {
1077 auto root = tensorflow::Scope::NewRootScope();
1078 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
1079
1080 Tensor input_tensor(DT_FLOAT, TensorShape({1, 1, 2, 6}));
1081 test::FillIota<float>(&input_tensor, 1);
1082 Output input_op =
1083 Const(root.WithOpName("input_op"), Input::Initializer(input_tensor));
1084
1085 Tensor offset_tensor(DT_FLOAT, TensorShape({6}));
1086 test::FillIota<float>(&offset_tensor, 1);
1087 Output offset_op =
1088 Const(root.WithOpName("offset_op"), Input::Initializer(offset_tensor));
1089
1090 Output bias_add_op =
1091 BiasAdd(root.WithOpName("bias_add_op"), input_op, offset_op);
1092
1093 Output relu_op = Relu(root.WithOpName("relu_op"), bias_add_op);
1094
1095 Output max_pool_op = MaxPool(root.WithOpName("max_pool_op"), relu_op,
1096 {1, 2, 2, 1}, {1, 1, 1, 1}, "SAME");
1097
1098 Tensor fake_quant_min_tensor(DT_FLOAT, TensorShape({}));
1099 test::FillValues<float>(&fake_quant_min_tensor, {0.0f});
1100 Output fake_quant_min_op = Const(root.WithOpName("fake_quant_min_op"),
1101 Input::Initializer(fake_quant_min_tensor));
1102
1103 Tensor fake_quant_max_tensor(DT_FLOAT, TensorShape({}));
1104 test::FillValues<float>(&fake_quant_max_tensor, {18.0f});
1105 Output fake_quant_max_op = Const(root.WithOpName("fake_quant_max_op"),
1106 Input::Initializer(fake_quant_max_tensor));
1107
1108 Output fake_quant_op =
1109 FakeQuantWithMinMaxVars(root.WithOpName("fake_quant_op"), max_pool_op,
1110 fake_quant_min_op, fake_quant_max_op);
1111
1112 GraphDef float_graph_def;
1113 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
1114
1115 GraphDef converted_graph_def;
1116 TestTransformedVersusFloatGraph(HoistFakeQuants, float_graph_def, {}, {},
1117 {"fake_quant_op"}, {}, 1.0,
1118 &converted_graph_def);
1119
1120 std::map<string, const NodeDef*> node_map;
1121 MapNamesToNodes(converted_graph_def, &node_map);
1122 EXPECT_EQ("MaxPool", node_map.at("fake_quant_op")->op());
1123 EXPECT_EQ("FakeQuantWithMinMaxVars",
1124 node_map.at(node_map.at("relu_op")->input(0))->op());
1125 }
1126
TestMergeDuplicateQuantizes()1127 void TestMergeDuplicateQuantizes() {
1128 auto root = tensorflow::Scope::NewRootScope();
1129 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
1130
1131 Tensor quantized_tensor(DT_QUINT8, TensorShape({}));
1132 test::FillValues<quint8>(&quantized_tensor, {0});
1133 Output quantized_op = Const(root.WithOpName("quantized_op"),
1134 Input::Initializer(quantized_tensor));
1135
1136 Tensor quantized_min_tensor(DT_FLOAT, TensorShape({}));
1137 test::FillValues<float>(&quantized_min_tensor, {2.0f});
1138 Output quantized_min_op = Const(root.WithOpName("quantized_min_op"),
1139 Input::Initializer(quantized_min_tensor));
1140
1141 Tensor quantized_max_tensor(DT_FLOAT, TensorShape({}));
1142 test::FillValues<float>(&quantized_max_tensor, {2.0f});
1143 Output quantized_max_op = Const(root.WithOpName("quantized_max_op"),
1144 Input::Initializer(quantized_min_tensor));
1145
1146 Output dequantize_op =
1147 Dequantize(root.WithOpName("dequantize_op"), quantized_op,
1148 quantized_min_op, quantized_max_op);
1149
1150 Tensor quantize_reshape_dims1_tensor(DT_INT32, TensorShape({1}));
1151 test::FillValues<int32>(&quantize_reshape_dims1_tensor, {-1});
1152 Output quantize_reshape_dims1 =
1153 Const(root.WithOpName("dequantize_reshape_dims1"),
1154 Input::Initializer(quantize_reshape_dims1_tensor));
1155
1156 Tensor quantize_reduction_dims1_tensor(DT_INT32, TensorShape({}));
1157 test::FillValues<int32>(&quantize_reduction_dims1_tensor, {0});
1158 Output quantize_reduction_dims1 =
1159 Const(root.WithOpName("quantize_reduction_dims1"),
1160 Input::Initializer(quantize_reduction_dims1_tensor));
1161
1162 Output quantize_reshape1 = Reshape(root.WithOpName("quantize_reshape1"),
1163 dequantize_op, quantize_reshape_dims1);
1164
1165 Output quantize_min1 =
1166 Min(root.WithOpName("quantize_min1"), quantize_reshape1,
1167 quantize_reduction_dims1, Min::Attrs().KeepDims(false));
1168
1169 Output quantize_max1 =
1170 Max(root.WithOpName("quantize_max1"), quantize_reshape1,
1171 quantize_reduction_dims1, Max::Attrs().KeepDims(false));
1172
1173 QuantizeV2 quantize_op1(root.WithOpName("quantize_op1"), dequantize_op,
1174 quantize_min1, quantize_max1, DT_QUINT8,
1175 QuantizeV2::Attrs().Mode("MIN_FIRST"));
1176
1177 Tensor quantize_reshape_dims2_tensor(DT_INT32, TensorShape({1}));
1178 test::FillValues<int32>(&quantize_reshape_dims2_tensor, {-1});
1179 Output quantize_reshape_dims2 =
1180 Const(root.WithOpName("dequantize_reshape_dims2"),
1181 Input::Initializer(quantize_reshape_dims2_tensor));
1182
1183 Tensor quantize_reduction_dims2_tensor(DT_INT32, TensorShape({}));
1184 test::FillValues<int32>(&quantize_reduction_dims2_tensor, {0});
1185 Output quantize_reduction_dims2 =
1186 Const(root.WithOpName("quantize_reduction_dims2"),
1187 Input::Initializer(quantize_reduction_dims2_tensor));
1188
1189 Output quantize_reshape2 = Reshape(root.WithOpName("quantize_reshape2"),
1190 dequantize_op, quantize_reshape_dims2);
1191
1192 Output quantize_min2 =
1193 Min(root.WithOpName("quantize_min2"), quantize_reshape2,
1194 quantize_reduction_dims2, Min::Attrs().KeepDims(false));
1195
1196 Output quantize_max2 =
1197 Max(root.WithOpName("quantize_max2"), quantize_reshape2,
1198 quantize_reduction_dims2, Max::Attrs().KeepDims(false));
1199
1200 QuantizeV2 quantize_op2(root.WithOpName("quantize_op2"), dequantize_op,
1201 quantize_min1, quantize_max1, DT_QUINT8,
1202 QuantizeV2::Attrs().Mode("MIN_FIRST"));
1203
1204 Output final_dequantize1 =
1205 Dequantize(root.WithOpName("final_dequantize1"), quantize_op1.output,
1206 quantize_op1.output_min, quantize_op1.output_max);
1207
1208 Output final_dequantize2 =
1209 Dequantize(root.WithOpName("final_dequantize2"), quantize_op2.output,
1210 quantize_op2.output_min, quantize_op2.output_max);
1211
1212 Output add_op =
1213 Add(root.WithOpName("add_op"), final_dequantize1, final_dequantize2);
1214
1215 GraphDef float_graph_def;
1216 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
1217
1218 GraphDef merged_graph_def;
1219 TestTransformedVersusFloatGraph(MergeDuplicateNodes, float_graph_def, {},
1220 {}, {"add_op"}, {}, 1.0, &merged_graph_def);
1221
1222 std::map<string, int> op_map;
1223 for (const NodeDef& node : merged_graph_def.node()) {
1224 ++op_map[node.op()];
1225 }
1226 EXPECT_EQ(1, op_map["QuantizeV2"]);
1227 }
1228
TestMergeDuplicateConsts()1229 void TestMergeDuplicateConsts() {
1230 auto root = tensorflow::Scope::NewRootScope();
1231 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
1232
1233 const int width = 10;
1234
1235 Tensor a_tensor(DT_FLOAT, TensorShape({width}));
1236 test::FillIota<float>(&a_tensor, 1.0f);
1237 Output a_op = Const(root.WithOpName("a_op"), Input::Initializer(a_tensor));
1238
1239 Tensor b_tensor(DT_FLOAT, TensorShape({width}));
1240 test::FillIota<float>(&b_tensor, 1.0f);
1241 Output b_op = Const(root.WithOpName("b_op"), Input::Initializer(b_tensor));
1242
1243 Output add_op = Add(root.WithOpName("add_op"), a_op, b_op);
1244
1245 Tensor c_tensor(DT_FLOAT, TensorShape({width}));
1246 test::FillIota<float>(&c_tensor, 2.0f);
1247 Output c_op = Const(root.WithOpName("c_op"), Input::Initializer(c_tensor));
1248
1249 Output mul_op = Mul(root.WithOpName("mul_op"), add_op, c_op);
1250
1251 GraphDef float_graph_def;
1252 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
1253
1254 GraphDef merged_graph_def;
1255 TestTransformedVersusFloatGraph(MergeDuplicateNodes, float_graph_def, {},
1256 {}, {"mul_op"}, {}, 1.0, &merged_graph_def);
1257
1258 std::map<string, const NodeDef*> node_map;
1259 MapNamesToNodes(merged_graph_def, &node_map);
1260 EXPECT_EQ(1, (node_map.count("a_op") + node_map.count("b_op")));
1261 string remaining_const;
1262 if (node_map.count("a_op")) {
1263 remaining_const = "a_op";
1264 } else {
1265 remaining_const = "b_op";
1266 }
1267 EXPECT_EQ(remaining_const, node_map["add_op"]->input(0));
1268 EXPECT_EQ(remaining_const, node_map["add_op"]->input(1));
1269 EXPECT_EQ(1, node_map.count("c_op"));
1270 EXPECT_EQ("add_op", node_map["mul_op"]->input(0));
1271 EXPECT_EQ("c_op", node_map["mul_op"]->input(1));
1272 }
1273
TestMergeDuplicatesNested()1274 void TestMergeDuplicatesNested() {
1275 auto root = tensorflow::Scope::NewRootScope();
1276 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
1277
1278 const int width = 10;
1279
1280 Tensor a_tensor(DT_FLOAT, TensorShape({width}));
1281 test::FillIota<float>(&a_tensor, 1.0f);
1282 Output a_op = Const(root.WithOpName("a_op"), Input::Initializer(a_tensor));
1283
1284 Output a_relu_op = Relu(root.WithOpName("a_relu_op"), a_op);
1285
1286 Tensor b_tensor(DT_FLOAT, TensorShape({width}));
1287 test::FillIota<float>(&b_tensor, 1.0f);
1288 Output b_op = Const(root.WithOpName("b_op"), Input::Initializer(b_tensor));
1289
1290 Output b_relu_op = Relu(root.WithOpName("b_relu_op"), b_op);
1291
1292 Output add_op = Add(root.WithOpName("add_op"), a_relu_op, b_relu_op);
1293
1294 Tensor c_tensor(DT_FLOAT, TensorShape({width}));
1295 test::FillIota<float>(&c_tensor, 2.0f);
1296 Output c_op = Const(root.WithOpName("c_op"), Input::Initializer(c_tensor));
1297
1298 Output mul_op = Mul(root.WithOpName("mul_op"), add_op, c_op);
1299
1300 GraphDef float_graph_def;
1301 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
1302
1303 GraphDef merged_graph_def;
1304 TestTransformedVersusFloatGraph(MergeDuplicateNodes, float_graph_def, {},
1305 {}, {"mul_op"}, {}, 1.0, &merged_graph_def);
1306
1307 std::map<string, const NodeDef*> node_map;
1308 MapNamesToNodes(merged_graph_def, &node_map);
1309 EXPECT_EQ(1, (node_map.count("a_op") + node_map.count("b_op")));
1310 EXPECT_EQ(1, (node_map.count("a_relu_op") + node_map.count("b_relu_op")));
1311 string remaining_relu;
1312 if (node_map.count("a_relu_op")) {
1313 remaining_relu = "a_relu_op";
1314 } else {
1315 remaining_relu = "b_relu_op";
1316 }
1317 EXPECT_EQ(remaining_relu, node_map["add_op"]->input(0));
1318 EXPECT_EQ(remaining_relu, node_map["add_op"]->input(1));
1319 EXPECT_EQ(1, node_map.count("c_op"));
1320 EXPECT_EQ("add_op", node_map["mul_op"]->input(0));
1321 EXPECT_EQ("c_op", node_map["mul_op"]->input(1));
1322 }
1323
TestMergeDuplicatesInOut()1324 void TestMergeDuplicatesInOut() {
1325 auto root = tensorflow::Scope::NewRootScope();
1326 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
1327
1328 const int width = 10;
1329
1330 Tensor a_tensor(DT_FLOAT, TensorShape({width}));
1331 test::FillIota<float>(&a_tensor, 1.0f);
1332 Output a_op = Const(root.WithOpName("a_op"), Input::Initializer(a_tensor));
1333
1334 Output a_relu_op = Relu(root.WithOpName("a_relu_op"), a_op);
1335
1336 Tensor b_tensor(DT_FLOAT, TensorShape({width}));
1337 test::FillIota<float>(&b_tensor, 1.0f);
1338 Output b_op = Const(root.WithOpName("b_op"), Input::Initializer(b_tensor));
1339
1340 Output b_relu_op = Relu(root.WithOpName("b_relu_op"), b_op);
1341
1342 Output add_op = Add(root.WithOpName("add_op"), a_relu_op, b_relu_op);
1343
1344 Tensor c_tensor(DT_FLOAT, TensorShape({width}));
1345 test::FillIota<float>(&c_tensor, 2.0f);
1346 Output c_op = Const(root.WithOpName("c_op"), Input::Initializer(c_tensor));
1347
1348 Output mul_op1 = Mul(root.WithOpName("mul_op1"), add_op, c_op);
1349 Output mul_op2 = Mul(root.WithOpName("mul_op2"), add_op, c_op);
1350 Output mul_op3 = Mul(root.WithOpName("mul_op3"), add_op, c_op);
1351
1352 Output final_mul_op =
1353 Mul(root.WithOpName("final_mul_op"), mul_op2, mul_op3);
1354
1355 GraphDef float_graph_def;
1356 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
1357
1358 GraphDef merged_graph_def;
1359 TestTransformedVersusFloatGraph(MergeDuplicateNodes, float_graph_def,
1360 {{"a_op", a_tensor}}, {{"a_op", a_tensor}},
1361 {"mul_op1", "final_mul_op"}, {}, 1.0,
1362 &merged_graph_def);
1363
1364 std::map<string, const NodeDef*> node_map;
1365 MapNamesToNodes(merged_graph_def, &node_map);
1366 EXPECT_EQ(1, node_map.count("a_op"));
1367 EXPECT_EQ(1, node_map.count("b_op"));
1368 EXPECT_EQ(1, node_map.count("a_relu_op"));
1369 EXPECT_EQ(1, node_map.count("b_relu_op"));
1370 EXPECT_EQ(1, node_map.count("mul_op1"));
1371 EXPECT_EQ(1, node_map.count("final_mul_op"));
1372 EXPECT_EQ(1, (node_map.count("mul_op2") + node_map.count("mul_op3")));
1373 string remaining_mul;
1374 if (node_map.count("mul_op2")) {
1375 remaining_mul = "mul_op2";
1376 } else {
1377 remaining_mul = "mul_op3";
1378 }
1379 EXPECT_EQ(remaining_mul, node_map["final_mul_op"]->input(0));
1380 EXPECT_EQ(remaining_mul, node_map["final_mul_op"]->input(1));
1381 EXPECT_EQ(1, node_map.count("c_op"));
1382 EXPECT_EQ("add_op", node_map["mul_op1"]->input(0));
1383 EXPECT_EQ("c_op", node_map["mul_op1"]->input(1));
1384 }
1385
TestExcludeNonFloat()1386 void TestExcludeNonFloat() {
1387 auto root = tensorflow::Scope::NewRootScope();
1388 using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
1389
1390 Tensor int_constant_tensor(DT_INT32, TensorShape({4, 5}));
1391 test::FillIota<int32>(&int_constant_tensor, 1);
1392 Output int_constant = Const(root.WithOpName("int_constant"),
1393 Input::Initializer(int_constant_tensor));
1394
1395 Tensor float_constant_tensor(DT_FLOAT, TensorShape({4, 5}));
1396 test::FillIota<float>(&float_constant_tensor, 2.0f);
1397 Output float_constant = Const(root.WithOpName("float_constant"),
1398 Input::Initializer(float_constant_tensor));
1399
1400 Output excluded_reshape_op =
1401 Reshape(root.WithOpName("excluded_reshape_op"), int_constant, {10, 2});
1402
1403 Output included_reshape_op = Reshape(root.WithOpName("included_reshape_op"),
1404 float_constant, {10, 2});
1405
1406 Output excluded_relu_op =
1407 Relu(root.WithOpName("excluded_relu_op"), excluded_reshape_op);
1408
1409 Output excluded_float_caster = Cast(
1410 root.WithOpName("excluded_float_caster"), excluded_relu_op, DT_FLOAT);
1411
1412 Output included_relu_op =
1413 Relu(root.WithOpName("included_relu_op"), included_reshape_op);
1414
1415 GraphDef float_graph_def;
1416 TF_ASSERT_OK(root.ToGraphDef(&float_graph_def));
1417
1418 GraphDef quantized_graph_def;
1419 TestTransformedVersusFloatGraph(
1420 QuantizeNodes, float_graph_def, {}, {},
1421 {"excluded_float_caster", "included_relu_op"}, {}, 1.0,
1422 &quantized_graph_def);
1423
1424 std::map<string, const NodeDef*> node_map;
1425 MapNamesToNodes(quantized_graph_def, &node_map);
1426 ASSERT_EQ(1, node_map.count("excluded_reshape_op"));
1427 EXPECT_EQ("Reshape", node_map.at("excluded_reshape_op")->op());
1428 ASSERT_EQ(1, node_map.count("included_reshape_op"));
1429 EXPECT_EQ("Dequantize", node_map.at("included_reshape_op")->op());
1430 }
1431 };
1432
TEST_F(QuantizeNodesTest,TestIgnoreOps)1433 TEST_F(QuantizeNodesTest, TestIgnoreOps) {
1434 TestIgnoreOps({});
1435 TestIgnoreOps({"MatMul"});
1436 TestIgnoreOps({"MatMul", "Mul"});
1437 }
1438
TEST_F(QuantizeNodesTest,TestQuantizeMatMulTiny)1439 TEST_F(QuantizeNodesTest, TestQuantizeMatMulTiny) { TestQuantizeMatMulTiny(); }
1440
TEST_F(QuantizeNodesTest,TestQuantizeMatMulSmall)1441 TEST_F(QuantizeNodesTest, TestQuantizeMatMulSmall) {
1442 TestQuantizeMatMulSmall();
1443 }
1444
TEST_F(QuantizeNodesTest,TestQuantizeMul)1445 TEST_F(QuantizeNodesTest, TestQuantizeMul) { TestQuantizeMul(); }
1446
TEST_F(QuantizeNodesTest,TestQuantizeAdd)1447 TEST_F(QuantizeNodesTest, TestQuantizeAdd) { TestQuantizeAdd(); }
1448
TEST_F(QuantizeNodesTest,TestOddPaddingProblem)1449 TEST_F(QuantizeNodesTest, TestOddPaddingProblem) {
1450 // Tests one error case we ran into in a real graph.
1451 TestQuantizeConv2D(1, 4, 4, 1, 3, 1, 2, "SAME",
1452 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
1453 {1, 2, 3, 4, 5, 6, 7, 8, 9});
1454 }
1455
TEST_F(QuantizeNodesTest,TestQuantizeConv2D)1456 TEST_F(QuantizeNodesTest, TestQuantizeConv2D) {
1457 TestQuantizeConv2D(1, 4, 3, 1, 3, 1, 1, "SAME",
1458 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
1459 {1, 4, 7, 2, 5, 8, 3, 6, 9});
1460 }
1461
TEST_F(QuantizeNodesTest,TestQuantizeBiasAdd)1462 TEST_F(QuantizeNodesTest, TestQuantizeBiasAdd) { TestQuantizeBiasAdd(); }
1463
TEST_F(QuantizeNodesTest,TestQuantizeConcat)1464 TEST_F(QuantizeNodesTest, TestQuantizeConcat) { TestQuantizeConcat(); }
1465
TEST_F(QuantizeNodesTest,TestQuantizeRelu)1466 TEST_F(QuantizeNodesTest, TestQuantizeRelu) { TestQuantizeRelu(); }
1467
TEST_F(QuantizeNodesTest,TestQuantizeRelu6)1468 TEST_F(QuantizeNodesTest, TestQuantizeRelu6) { TestQuantizeRelu6(); }
1469
TEST_F(QuantizeNodesTest,TestQuantizeMaxPool)1470 TEST_F(QuantizeNodesTest, TestQuantizeMaxPool) { TestQuantizeMaxPool(); }
1471
TEST_F(QuantizeNodesTest,TestQuantizeAvgPool)1472 TEST_F(QuantizeNodesTest, TestQuantizeAvgPool) { TestQuantizeAvgPool(); }
1473
TEST_F(QuantizeNodesTest,TestQuantizeReshape)1474 TEST_F(QuantizeNodesTest, TestQuantizeReshape) { TestQuantizeReshape(); }
1475
TEST_F(QuantizeNodesTest,TestQuantizeResizeBilinear)1476 TEST_F(QuantizeNodesTest, TestQuantizeResizeBilinear) {
1477 TestQuantizeResizeBilinear();
1478 }
1479
TEST_F(QuantizeNodesTest,TestRemoveRedundantQuantization)1480 TEST_F(QuantizeNodesTest, TestRemoveRedundantQuantization) {
1481 TestRemoveRedundantQuantization();
1482 }
1483
TEST_F(QuantizeNodesTest,TestRemoveRedundantQuantizationWithBiasAdd)1484 TEST_F(QuantizeNodesTest, TestRemoveRedundantQuantizationWithBiasAdd) {
1485 TestRemoveRedundantQuantizationWithBiasAdd();
1486 }
1487
TEST_F(QuantizeNodesTest,TestRemoveRedundantQuantizationWithMultipleOutputs)1488 TEST_F(QuantizeNodesTest, TestRemoveRedundantQuantizationWithMultipleOutputs) {
1489 TestRemoveRedundantQuantizationWithMultipleOutputs();
1490 }
1491
TEST_F(QuantizeNodesTest,TestQuantizePlaceholders)1492 TEST_F(QuantizeNodesTest, TestQuantizePlaceholders) {
1493 TestQuantizePlaceholders();
1494 }
1495
TEST_F(QuantizeNodesTest,TestInputRange)1496 TEST_F(QuantizeNodesTest, TestInputRange) { TestInputRange(); }
1497
TEST_F(QuantizeNodesTest,TestFallbackRange)1498 TEST_F(QuantizeNodesTest, TestFallbackRange) { TestFallbackRange(); }
1499
TEST_F(QuantizeNodesTest,TestConvertFakeQuantsToRequantize)1500 TEST_F(QuantizeNodesTest, TestConvertFakeQuantsToRequantize) {
1501 TestConvertFakeQuantsToRequantize();
1502 }
1503
TEST_F(QuantizeNodesTest,TestMergeAdjacentRequantizes)1504 TEST_F(QuantizeNodesTest, TestMergeAdjacentRequantizes) {
1505 TestMergeAdjacentRequantizes();
1506 }
1507
TEST_F(QuantizeNodesTest,TestConvertFakeQuantsEndToEnd)1508 TEST_F(QuantizeNodesTest, TestConvertFakeQuantsEndToEnd) {
1509 TestConvertFakeQuantsEndToEnd();
1510 }
1511
TEST_F(QuantizeNodesTest,TestHoistFakeQuants)1512 TEST_F(QuantizeNodesTest, TestHoistFakeQuants) { TestHoistFakeQuants(); }
1513
TEST_F(QuantizeNodesTest,TestMergeDuplicateQuantizes)1514 TEST_F(QuantizeNodesTest, TestMergeDuplicateQuantizes) {
1515 TestMergeDuplicateQuantizes();
1516 }
1517
TEST_F(QuantizeNodesTest,TestMergeDuplicateConsts)1518 TEST_F(QuantizeNodesTest, TestMergeDuplicateConsts) {
1519 TestMergeDuplicateConsts();
1520 }
1521
TEST_F(QuantizeNodesTest,TestMergeDuplicatesNested)1522 TEST_F(QuantizeNodesTest, TestMergeDuplicatesNested) {
1523 TestMergeDuplicatesNested();
1524 }
1525
TEST_F(QuantizeNodesTest,TestMergeDuplicateInOut)1526 TEST_F(QuantizeNodesTest, TestMergeDuplicateInOut) {
1527 TestMergeDuplicatesInOut();
1528 }
1529
TEST_F(QuantizeNodesTest,TestExcludeNonFloat)1530 TEST_F(QuantizeNodesTest, TestExcludeNonFloat) { TestExcludeNonFloat(); }
1531
1532 } // namespace graph_transforms
1533 } // namespace tensorflow
1534