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