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