• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2021 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 #include "tensorflow/lite/delegates/xnnpack/quantized_reduce_tester.h"
17 
18 #include <array>
19 #include <cstdint>
20 #include <functional>
21 #include <numeric>
22 #include <random>
23 #include <vector>
24 
25 #include <gtest/gtest.h>
26 #include "flatbuffers/flatbuffers.h"  // from @flatbuffers
27 #include "tensorflow/lite/interpreter.h"
28 #include "tensorflow/lite/kernels/register.h"
29 #include "tensorflow/lite/model.h"
30 #include "tensorflow/lite/schema/schema_conversion_utils.h"
31 #include "tensorflow/lite/schema/schema_generated.h"
32 #include "tensorflow/lite/version.h"
33 
34 namespace tflite {
35 namespace xnnpack {
36 
37 template <class T>
Test(Interpreter * delegate_interpreter,Interpreter * default_interpreter) const38 void QuantizedReduceTester::Test(Interpreter* delegate_interpreter,
39                                  Interpreter* default_interpreter) const {
40   std::random_device random_device;
41   auto rng = std::mt19937(random_device());
42   auto input_rng = std::bind(
43       std::uniform_int_distribution<int32_t>(std::numeric_limits<T>::min(),
44                                              std::numeric_limits<T>::max()),
45       std::ref(rng));
46 
47   T* default_input_data = default_interpreter->typed_input_tensor<T>(0);
48   std::generate(default_input_data, default_input_data + InputSize(),
49                 std::ref(input_rng));
50 
51   T* delegate_input_data = delegate_interpreter->typed_input_tensor<T>(0);
52   std::copy(default_input_data, default_input_data + InputSize(),
53             delegate_input_data);
54 
55   ASSERT_EQ(default_interpreter->Invoke(), kTfLiteOk);
56   ASSERT_EQ(delegate_interpreter->Invoke(), kTfLiteOk);
57 
58   T* default_output_data = default_interpreter->typed_output_tensor<T>(0);
59   T* delegate_output_data = delegate_interpreter->typed_output_tensor<T>(0);
60 
61   const int32_t output_size = OutputSize();
62   for (size_t i = 0; i < output_size; i++) {
63     ASSERT_LE(std::abs(static_cast<int32_t>(default_output_data[i]) -
64                        static_cast<int32_t>(delegate_output_data[i])),
65               1)
66         << "default " << static_cast<int32_t>(default_output_data[i])
67         << ", delegate " << static_cast<int32_t>(delegate_output_data[i])
68         << " at index " << i << " / " << output_size;
69   }
70 }
71 
Test(tflite::BuiltinOperator reduce_op,TfLiteDelegate * delegate) const72 void QuantizedReduceTester::Test(tflite::BuiltinOperator reduce_op,
73                                  TfLiteDelegate* delegate) const {
74   std::vector<char> buffer = CreateTfLiteModel(reduce_op);
75   const Model* model = GetModel(buffer.data());
76 
77   std::unique_ptr<Interpreter> delegate_interpreter;
78   ASSERT_EQ(
79       InterpreterBuilder(
80           model,
81           ::tflite::ops::builtin::BuiltinOpResolverWithoutDefaultDelegates())(
82           &delegate_interpreter),
83       kTfLiteOk);
84   std::unique_ptr<Interpreter> default_interpreter;
85   ASSERT_EQ(
86       InterpreterBuilder(
87           model,
88           ::tflite::ops::builtin::BuiltinOpResolverWithoutDefaultDelegates())(
89           &default_interpreter),
90       kTfLiteOk);
91 
92   ASSERT_TRUE(delegate_interpreter);
93   ASSERT_TRUE(default_interpreter);
94 
95   ASSERT_EQ(delegate_interpreter->inputs().size(), 1);
96   ASSERT_EQ(default_interpreter->inputs().size(), 1);
97 
98   ASSERT_EQ(delegate_interpreter->outputs().size(), 1);
99   ASSERT_EQ(default_interpreter->outputs().size(), 1);
100 
101   ASSERT_EQ(delegate_interpreter->AllocateTensors(), kTfLiteOk);
102   ASSERT_EQ(default_interpreter->AllocateTensors(), kTfLiteOk);
103 
104   ASSERT_EQ(delegate_interpreter->ModifyGraphWithDelegate(delegate), kTfLiteOk);
105 
106   if (Unsigned()) {
107     Test<uint8_t>(delegate_interpreter.get(), default_interpreter.get());
108   } else {
109     Test<int8_t>(delegate_interpreter.get(), default_interpreter.get());
110   }
111 }
112 
CreateTfLiteModel(tflite::BuiltinOperator reduce_op) const113 std::vector<char> QuantizedReduceTester::CreateTfLiteModel(
114     tflite::BuiltinOperator reduce_op) const {
115   flatbuffers::FlatBufferBuilder builder;
116   flatbuffers::Offset<OperatorCode> operator_code =
117       CreateOperatorCode(builder, reduce_op);
118 
119   const std::array<flatbuffers::Offset<Buffer>, 2> buffers{{
120       CreateBuffer(builder, builder.CreateVector({})),
121       CreateBuffer(builder, builder.CreateVector(
122                                 reinterpret_cast<const uint8_t*>(Axes().data()),
123                                 sizeof(int32_t) * Axes().size())),
124   }};
125 
126   const std::vector<int32_t> output_shape = OutputShape();
127   const std::array<int32_t, 1> axes_shape{
128       {static_cast<int32_t>(Axes().size())}};
129   const std::array<flatbuffers::Offset<Tensor>, 3> tensors{{
130       CreateTensor(builder,
131                    builder.CreateVector<int32_t>(InputShape().data(),
132                                                  InputShape().size()),
133                    Unsigned() ? TensorType_UINT8 : TensorType_INT8,
134                    /*buffer=*/0, /*name=*/0,
135                    CreateQuantizationParameters(
136                        builder, /*min=*/0, /*max=*/0,
137                        builder.CreateVector<float>({InputScale()}),
138                        builder.CreateVector<int64_t>({InputZeroPoint()}))),
139       CreateTensor(
140           builder,
141           builder.CreateVector<int32_t>(axes_shape.data(), axes_shape.size()),
142           TensorType_INT32, /*buffer=*/1),
143       CreateTensor(builder,
144                    builder.CreateVector<int32_t>(output_shape.data(),
145                                                  output_shape.size()),
146                    Unsigned() ? TensorType_UINT8 : TensorType_INT8,
147                    /*buffer=*/0, /*name=*/0,
148                    CreateQuantizationParameters(
149                        builder, /*min=*/0, /*max=*/0,
150                        builder.CreateVector<float>({OutputScale()}),
151                        builder.CreateVector<int64_t>({OutputZeroPoint()}))),
152   }};
153 
154   const flatbuffers::Offset<ReducerOptions> reducer_options =
155       CreateReducerOptions(builder, KeepDims());
156 
157   const std::array<int32_t, 2> op_inputs{{0, 1}};
158   const std::array<int32_t, 1> op_outputs{{2}};
159   flatbuffers::Offset<Operator> op = CreateOperator(
160       builder, /*opcode_index=*/0,
161       builder.CreateVector<int32_t>(op_inputs.data(), op_inputs.size()),
162       builder.CreateVector<int32_t>(op_outputs.data(), op_outputs.size()),
163       tflite::BuiltinOptions_ReducerOptions, reducer_options.Union());
164 
165   const std::array<int32_t, 1> subgraph_inputs{{0}};
166   const std::array<int32_t, 1> subgraph_outputs{{2}};
167   flatbuffers::Offset<SubGraph> subgraph = CreateSubGraph(
168       builder, builder.CreateVector(tensors.data(), tensors.size()),
169       builder.CreateVector<int32_t>(subgraph_inputs.data(),
170                                     subgraph_inputs.size()),
171       builder.CreateVector<int32_t>(subgraph_outputs.data(),
172                                     subgraph_outputs.size()),
173       builder.CreateVector(&op, 1));
174 
175   flatbuffers::Offset<flatbuffers::String> description =
176       builder.CreateString("Quantized Reduce model");
177 
178   flatbuffers::Offset<Model> model_buffer = CreateModel(
179       builder, TFLITE_SCHEMA_VERSION, builder.CreateVector(&operator_code, 1),
180       builder.CreateVector(&subgraph, 1), description,
181       builder.CreateVector(buffers.data(), buffers.size()));
182 
183   builder.Finish(model_buffer);
184 
185   return std::vector<char>(builder.GetBufferPointer(),
186                            builder.GetBufferPointer() + builder.GetSize());
187 }
188 
ComputeSize(const std::vector<int32_t> & shape)189 int32_t QuantizedReduceTester::ComputeSize(const std::vector<int32_t>& shape) {
190   return std::accumulate(shape.cbegin(), shape.cend(), 1,
191                          std::multiplies<int32_t>());
192 }
193 
194 }  // namespace xnnpack
195 }  // namespace tflite
196