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