• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2020 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 #ifndef TENSORFLOW_LITE_DELEGATES_XNNPACK_QUANTIZED_CONV_2D_TESTER_H_
17 #define TENSORFLOW_LITE_DELEGATES_XNNPACK_QUANTIZED_CONV_2D_TESTER_H_
18 
19 #include <cstdint>
20 #include <vector>
21 
22 #include <gtest/gtest.h>
23 #include "tensorflow/lite/c/common.h"
24 #include "tensorflow/lite/delegates/xnnpack/xnnpack_delegate.h"
25 #include "tensorflow/lite/interpreter.h"
26 #include "tensorflow/lite/schema/schema_generated.h"
27 
28 namespace tflite {
29 namespace xnnpack {
30 
31 // Creates a model with a single CONV_2D operator with quantized input, output,
32 // and weights, runs this model in two TensorFlow Lite interpreters, one with
33 // the delegate applied, and the other without, and compares the results.
34 class QuantizedConv2DTester {
35  public:
36   QuantizedConv2DTester() = default;
37   QuantizedConv2DTester(const QuantizedConv2DTester&) = delete;
38   QuantizedConv2DTester& operator=(const QuantizedConv2DTester&) = delete;
39 
BatchSize(int32_t batch_size)40   inline QuantizedConv2DTester& BatchSize(int32_t batch_size) {
41     EXPECT_GT(batch_size, 0);
42     batch_size_ = batch_size;
43     return *this;
44   }
45 
BatchSize()46   inline int32_t BatchSize() const { return batch_size_; }
47 
InputChannels(int32_t input_channels)48   inline QuantizedConv2DTester& InputChannels(int32_t input_channels) {
49     EXPECT_GT(input_channels, 0);
50     input_channels_ = input_channels;
51     return *this;
52   }
53 
InputChannels()54   inline int32_t InputChannels() const { return input_channels_; }
55 
OutputChannels(int32_t output_channels)56   inline QuantizedConv2DTester& OutputChannels(int32_t output_channels) {
57     EXPECT_GT(output_channels, 0);
58     output_channels_ = output_channels;
59     return *this;
60   }
61 
OutputChannels()62   inline int32_t OutputChannels() const { return output_channels_; }
63 
InputHeight(int32_t input_height)64   inline QuantizedConv2DTester& InputHeight(int32_t input_height) {
65     EXPECT_GT(input_height, 0);
66     input_height_ = input_height;
67     return *this;
68   }
69 
InputHeight()70   inline int32_t InputHeight() const { return input_height_; }
71 
InputWidth(int32_t input_width)72   inline QuantizedConv2DTester& InputWidth(int32_t input_width) {
73     EXPECT_GT(input_width, 0);
74     input_width_ = input_width;
75     return *this;
76   }
77 
InputWidth()78   inline int32_t InputWidth() const { return input_width_; }
79 
OutputWidth()80   inline int32_t OutputWidth() const {
81     if (Padding() == ::tflite::Padding_SAME) {
82       EXPECT_GE(InputWidth(), 1);
83       return (InputWidth() - 1) / StrideWidth() + 1;
84     } else {
85       EXPECT_GE(InputWidth(), DilatedKernelWidth());
86       return 1 + (InputWidth() - DilatedKernelWidth()) / StrideWidth();
87     }
88   }
89 
OutputHeight()90   inline int32_t OutputHeight() const {
91     if (Padding() == ::tflite::Padding_SAME) {
92       EXPECT_GE(InputHeight(), 1);
93       return (InputHeight() - 1) / StrideHeight() + 1;
94     } else {
95       EXPECT_GE(InputHeight(), DilatedKernelHeight());
96       return 1 + (InputHeight() - DilatedKernelHeight()) / StrideHeight();
97     }
98   }
99 
KernelHeight(int32_t kernel_height)100   inline QuantizedConv2DTester& KernelHeight(int32_t kernel_height) {
101     EXPECT_GT(kernel_height, 0);
102     kernel_height_ = kernel_height;
103     return *this;
104   }
105 
KernelHeight()106   inline int32_t KernelHeight() const { return kernel_height_; }
107 
KernelWidth(int32_t kernel_width)108   inline QuantizedConv2DTester& KernelWidth(int32_t kernel_width) {
109     EXPECT_GT(kernel_width, 0);
110     kernel_width_ = kernel_width;
111     return *this;
112   }
113 
KernelWidth()114   inline int32_t KernelWidth() const { return kernel_width_; }
115 
StrideHeight(int32_t stride_height)116   inline QuantizedConv2DTester& StrideHeight(int32_t stride_height) {
117     EXPECT_GT(stride_height, 0);
118     stride_height_ = stride_height;
119     return *this;
120   }
121 
StrideHeight()122   inline int32_t StrideHeight() const { return stride_height_; }
123 
StrideWidth(int32_t stride_width)124   inline QuantizedConv2DTester& StrideWidth(int32_t stride_width) {
125     EXPECT_GT(stride_width, 0);
126     stride_width_ = stride_width;
127     return *this;
128   }
129 
StrideWidth()130   inline int32_t StrideWidth() const { return stride_width_; }
131 
DilationHeight(int32_t dilation_height)132   inline QuantizedConv2DTester& DilationHeight(int32_t dilation_height) {
133     EXPECT_GT(dilation_height, 0);
134     dilation_height_ = dilation_height;
135     return *this;
136   }
137 
DilationHeight()138   inline int32_t DilationHeight() const { return dilation_height_; }
139 
DilationWidth(int32_t dilation_width)140   inline QuantizedConv2DTester& DilationWidth(int32_t dilation_width) {
141     EXPECT_GT(dilation_width, 0);
142     dilation_width_ = dilation_width;
143     return *this;
144   }
145 
DilationWidth()146   inline int32_t DilationWidth() const { return dilation_width_; }
147 
DilatedKernelHeight()148   inline int32_t DilatedKernelHeight() const {
149     return (KernelHeight() - 1) * DilationHeight() + 1;
150   }
151 
DilatedKernelWidth()152   inline int32_t DilatedKernelWidth() const {
153     return (KernelWidth() - 1) * DilationWidth() + 1;
154   }
155 
Groups(int32_t groups)156   inline QuantizedConv2DTester& Groups(int32_t groups) {
157     EXPECT_EQ(InputChannels() % groups, 0);
158     EXPECT_EQ(OutputChannels() % groups, 0);
159     groups_ = groups;
160     return *this;
161   }
162 
Groups()163   inline int32_t Groups() const { return groups_; }
164 
KernelInputChannels()165   inline int32_t KernelInputChannels() const {
166     return input_channels_ / groups_;
167   }
168 
InputZeroPoint(int32_t input_zero_point)169   inline QuantizedConv2DTester& InputZeroPoint(int32_t input_zero_point) {
170     input_zero_point_ = input_zero_point;
171     return *this;
172   }
173 
InputZeroPoint()174   inline int32_t InputZeroPoint() const { return input_zero_point_; }
175 
OutputZeroPoint(int32_t output_zero_point)176   inline QuantizedConv2DTester& OutputZeroPoint(int32_t output_zero_point) {
177     output_zero_point_ = output_zero_point;
178     return *this;
179   }
180 
OutputZeroPoint()181   inline int32_t OutputZeroPoint() const { return output_zero_point_; }
182 
KernelZeroPoint(int32_t kernel_zero_point)183   inline QuantizedConv2DTester& KernelZeroPoint(int32_t kernel_zero_point) {
184     kernel_zero_point_ = kernel_zero_point;
185     return *this;
186   }
187 
KernelZeroPoint()188   inline int32_t KernelZeroPoint() const { return kernel_zero_point_; }
189 
InputScale(float input_scale)190   inline QuantizedConv2DTester& InputScale(float input_scale) {
191     input_scale_ = input_scale;
192     return *this;
193   }
194 
InputScale()195   inline float InputScale() const { return input_scale_; }
196 
KernelScale(float kernel_scale)197   inline QuantizedConv2DTester& KernelScale(float kernel_scale) {
198     kernel_scale_ = kernel_scale;
199     return *this;
200   }
201 
KernelScale()202   inline float KernelScale() const {
203     EXPECT_FALSE(ChannelWise());
204     return kernel_scale_;
205   }
206 
KernelScales(const std::vector<float> & kernel_scales)207   inline QuantizedConv2DTester& KernelScales(
208       const std::vector<float>& kernel_scales) {
209     EXPECT_GT(kernel_scales.size(), 0);
210     kernel_scales_ = kernel_scales;
211     return *this;
212   }
213 
KernelScales()214   inline const std::vector<float>& KernelScales() const {
215     EXPECT_TRUE(ChannelWise());
216     return kernel_scales_;
217   }
218 
Unsigned()219   inline bool Unsigned() const { return kernel_zero_point_ != 0; }
220 
ChannelWise()221   inline bool ChannelWise() const { return !kernel_scales_.empty(); }
222 
OutputScale(float output_scale)223   inline QuantizedConv2DTester& OutputScale(float output_scale) {
224     output_scale_ = output_scale;
225     return *this;
226   }
227 
OutputScale()228   inline float OutputScale() const { return output_scale_; }
229 
SamePadding()230   inline QuantizedConv2DTester& SamePadding() {
231     padding_ = ::tflite::Padding_SAME;
232     return *this;
233   }
234 
ValidPadding()235   inline QuantizedConv2DTester& ValidPadding() {
236     padding_ = ::tflite::Padding_VALID;
237     return *this;
238   }
239 
ReluActivation()240   inline QuantizedConv2DTester& ReluActivation() {
241     activation_ = ::tflite::ActivationFunctionType_RELU;
242     return *this;
243   }
244 
Relu6Activation()245   inline QuantizedConv2DTester& Relu6Activation() {
246     activation_ = ::tflite::ActivationFunctionType_RELU6;
247     return *this;
248   }
249 
ReluMinus1To1Activation()250   inline QuantizedConv2DTester& ReluMinus1To1Activation() {
251     activation_ = ::tflite::ActivationFunctionType_RELU_N1_TO_1;
252     return *this;
253   }
254 
WeightsCache(TfLiteXNNPackDelegateWeightsCache * weights_cache)255   inline QuantizedConv2DTester& WeightsCache(
256       TfLiteXNNPackDelegateWeightsCache* weights_cache) {
257     weights_cache_ = weights_cache;
258     return *this;
259   }
260 
261   template <class T>
262   void Test(Interpreter* delegate_interpreter,
263             Interpreter* default_interpreter) const;
264 
265   void Test(TfLiteDelegate* delegate) const;
266 
267  private:
268   std::vector<char> CreateTfLiteModel() const;
269 
Padding()270   inline ::tflite::Padding Padding() const { return padding_; }
271 
Activation()272   inline ::tflite::ActivationFunctionType Activation() const {
273     return activation_;
274   }
275 
276   int32_t batch_size_ = 1;
277   int32_t input_channels_ = 1;
278   int32_t output_channels_ = 1;
279   int32_t groups_ = 1;
280   int32_t input_height_ = 1;
281   int32_t input_width_ = 1;
282   int32_t kernel_height_ = 1;
283   int32_t kernel_width_ = 1;
284   int32_t stride_height_ = 1;
285   int32_t stride_width_ = 1;
286   int32_t dilation_height_ = 1;
287   int32_t dilation_width_ = 1;
288   int32_t input_zero_point_ = 0;
289   int32_t output_zero_point_ = 0;
290   int32_t kernel_zero_point_ = 0;
291   float input_scale_ = 0.125f;
292   float kernel_scale_ = 0.25f;
293   std::vector<float> kernel_scales_;
294   float output_scale_ = 1.5f;
295   ::tflite::Padding padding_ = ::tflite::Padding_VALID;
296   ::tflite::ActivationFunctionType activation_ =
297       ::tflite::ActivationFunctionType_NONE;
298   TfLiteXNNPackDelegateWeightsCache* weights_cache_ = nullptr;
299 };
300 
301 }  // namespace xnnpack
302 }  // namespace tflite
303 
304 #endif  // TENSORFLOW_LITE_DELEGATES_XNNPACK_QUANTIZED_CONV_2D_TESTER_H_
305