blob: b50b40ae6d647a711d4ff994682d842797670d93 [file] [log] [blame]
/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/lite/c/builtin_op_data.h"
#include "tensorflow/lite/c/common.h"
#include "tensorflow/lite/kernels/internal/tensor_ctypes.h"
#include "tensorflow/lite/micro/kernels/kernel_runner.h"
#include "tensorflow/lite/micro/test_helpers.h"
#include "tensorflow/lite/micro/testing/micro_test.h"
namespace tflite {
namespace testing {
namespace {
// Index of the output tensor in context->tensors, specific to
// DepthwiseConv.
constexpr int kOutputTensorIndex = 3;
constexpr int kMaxFilterChannels = 64;
constexpr int kMaxBiasChannels = 64;
// Creates a DepthwiseConv opeerator, calls it with the provided input tensors
// and some defaults parameters, and compares the output with
// expected_output_data.
//
// The tensors parameter contains both the input tensors as well as a
// preallocated output tensor into which the output is stored.
template <typename T>
TfLiteStatus ValidateDepthwiseConvGoldens(
const T* expected_output_data, int output_length,
TfLiteDepthwiseConvParams* conv_params, float tolerance, int tensors_size,
TfLiteTensor* tensors) {
int inputs_array_data[] = {3, 0, 1, 2};
TfLiteIntArray* inputs_array = IntArrayFromInts(inputs_array_data);
int outputs_array_data[] = {1, 3};
TfLiteIntArray* outputs_array = IntArrayFromInts(outputs_array_data);
const TFLMRegistration registration = Register_DEPTHWISE_CONV_2D();
micro::KernelRunner runner(registration, tensors, tensors_size, inputs_array,
outputs_array,
reinterpret_cast<void*>(conv_params));
int input_depth = tensors[0].dims->data[3];
int output_depth = tensors[1].dims->data[3];
int depth_mul = output_depth / input_depth;
conv_params->padding = kTfLitePaddingValid;
conv_params->depth_multiplier = depth_mul;
const char* init_data = reinterpret_cast<const char*>(conv_params);
// TODO(b/154240825): Use a test macro here which fails and returns.
TfLiteStatus status = runner.InitAndPrepare(init_data);
if (status != kTfLiteOk) {
return status;
}
TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, runner.Invoke());
const T* output_data = tflite::GetTensorData<T>(&tensors[kOutputTensorIndex]);
for (int i = 0; i < output_length; ++i) {
TF_LITE_MICRO_EXPECT_NEAR(expected_output_data[i], output_data[i],
tolerance);
}
return kTfLiteOk;
}
template <typename T, typename BiasT>
void TestDepthwiseConvQuantizedPerChannel(
int* input_dims_data, const float* input_data, T* input_quantized,
float input_scale, int input_zero_point, int* filter_dims_data,
const float* filter_data, int8_t* filter_data_quantized,
int* bias_dims_data, const float* bias_data, BiasT* bias_data_quantized,
int* output_dims_data, const float* expected_output_data,
T* expected_output_data_quantized, T* output_data, float output_scale,
int output_zero_point, TfLiteDepthwiseConvParams* conv_params,
TfLiteType filter_packed_type = kTfLiteNoType) {
TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
TfLiteIntArray* filter_dims = IntArrayFromInts(filter_dims_data);
TfLiteIntArray* bias_dims = IntArrayFromInts(bias_dims_data);
TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
const int output_dims_count = ElementCount(*output_dims);
int filter_zero_points[kMaxFilterChannels];
float filter_scales[kMaxFilterChannels];
int bias_zero_points[kMaxBiasChannels];
float bias_scales[kMaxBiasChannels];
TfLiteAffineQuantization filter_quant;
TfLiteAffineQuantization bias_quant;
TfLiteTensor input_tensor = CreateQuantizedTensor(
input_data, input_quantized, input_dims, input_scale, input_zero_point);
TfLiteTensor filter_tensor = CreateSymmetricPerChannelQuantizedTensor(
filter_data, filter_data_quantized, filter_dims, filter_scales,
filter_zero_points, &filter_quant, 3 /* quantized dimension */, false,
filter_packed_type);
TfLiteTensor bias_tensor = CreatePerChannelQuantizedBiasTensor(
bias_data, bias_data_quantized, bias_dims, input_scale, &filter_scales[1],
bias_scales, bias_zero_points, &bias_quant, 3 /* quantized dimension */
);
TfLiteTensor output_tensor = CreateQuantizedTensor(
output_data, output_dims, output_scale, input_zero_point);
// TODO(njeff): Affine Quantization Params should be set on tensor creation.
float input_scales[] = {1, input_scale};
int input_zero_points[] = {1, input_zero_point};
TfLiteAffineQuantization input_quant = {FloatArrayFromFloats(input_scales),
IntArrayFromInts(input_zero_points),
0};
input_tensor.quantization = {kTfLiteAffineQuantization, &input_quant};
float output_scales[] = {1, output_scale};
int output_zero_points[] = {1, output_zero_point};
TfLiteAffineQuantization output_quant = {FloatArrayFromFloats(output_scales),
IntArrayFromInts(output_zero_points),
0};
output_tensor.quantization = {kTfLiteAffineQuantization, &output_quant};
constexpr int inputs_size = 3;
constexpr int outputs_size = 1;
constexpr int tensors_size = inputs_size + outputs_size;
TfLiteTensor tensors[tensors_size] = {
input_tensor,
filter_tensor,
bias_tensor,
output_tensor,
};
Quantize(expected_output_data, expected_output_data_quantized,
output_dims_count, output_scale, output_zero_point);
TF_LITE_MICRO_EXPECT_EQ(
kTfLiteOk, ValidateDepthwiseConvGoldens(expected_output_data_quantized,
output_dims_count, conv_params,
1.0, tensors_size, tensors));
}
void TestDepthwiseConvQuantizedPerChannel(
int* input_dims_data, const float* input_data, int8_t* input_quantized,
float input_scale, int input_zero_point, int* filter_dims_data,
const float* filter_data, int8_t* filter_data_quantized,
int* bias_dims_data, const float* bias_data, int32_t* bias_data_quantized,
int* output_dims_data, const float* expected_output_data,
int8_t* expected_output_data_quantized, int8_t* output_data,
float output_scale, int output_zero_point,
TfLiteDepthwiseConvParams* conv_params,
TfLiteType filter_packed_type = kTfLiteNoType) {
return TestDepthwiseConvQuantizedPerChannel<int8_t, int32_t>(
input_dims_data, input_data, input_quantized, input_scale,
input_zero_point, filter_dims_data, filter_data, filter_data_quantized,
bias_dims_data, bias_data, bias_data_quantized, output_dims_data,
expected_output_data, expected_output_data_quantized, output_data,
output_scale, output_zero_point, conv_params, filter_packed_type);
}
void TestDepthwiseConvQuantizedPerChannel(
int* input_dims_data, const float* input_data, int16_t* input_quantized,
float input_scale, int input_zero_point, int* filter_dims_data,
const float* filter_data, int8_t* filter_data_quantized,
int* bias_dims_data, const float* bias_data, int64_t* bias_data_quantized,
int* output_dims_data, const float* expected_output_data,
int16_t* expected_output_data_quantized, int16_t* output_data,
float output_scale, int output_zero_point,
TfLiteDepthwiseConvParams* conv_params,
TfLiteType filter_packed_type = kTfLiteNoType) {
return TestDepthwiseConvQuantizedPerChannel<int16_t, int64_t>(
input_dims_data, input_data, input_quantized, input_scale,
input_zero_point, filter_dims_data, filter_data, filter_data_quantized,
bias_dims_data, bias_data, bias_data_quantized, output_dims_data,
expected_output_data, expected_output_data_quantized, output_data,
output_scale, output_zero_point, conv_params, filter_packed_type);
}
// Xtensa kernels do not support float activations., and the corresponding tests
// are disabled. As a result, helper functions that are only needed for float
// kernel tests also need to be ifdef'd out to avoid build errors due to unused
// functions.
#if !defined(XTENSA)
void TestDepthwiseConvFloat(int* input_dims_data, const float* input_data,
int* filter_dims_data, const float* filter_data,
int* bias_dims_data, const float* bias_data,
const float* expected_output_data,
int* output_dims_data,
TfLiteDepthwiseConvParams* conv_params,
float* output_data) {
TfLiteIntArray* input_dims = IntArrayFromInts(input_dims_data);
TfLiteIntArray* filter_dims = IntArrayFromInts(filter_dims_data);
TfLiteIntArray* bias_dims = IntArrayFromInts(bias_dims_data);
TfLiteIntArray* output_dims = IntArrayFromInts(output_dims_data);
const int output_dims_count = ElementCount(*output_dims);
constexpr int inputs_size = 3;
constexpr int outputs_size = 1;
constexpr int tensors_size = inputs_size + outputs_size;
TfLiteTensor tensors[tensors_size] = {
CreateTensor(input_data, input_dims),
CreateTensor(filter_data, filter_dims),
CreateTensor(bias_data, bias_dims),
CreateTensor(output_data, output_dims),
};
ValidateDepthwiseConvGoldens(expected_output_data, output_dims_count,
conv_params, 1e-5, tensors_size, tensors);
}
#endif // !defined(XTENSA)
} // namespace
} // namespace testing
} // namespace tflite
TF_LITE_MICRO_TESTS_BEGIN
#if !defined(XTENSA) // TODO(b/170322965): xtensa kernels are less general than
// reference kernels and we ifdef out test cases that are
// currently known to fail.
TF_LITE_MICRO_TEST(SimpleTest) {
int input_shape[] = {4, 1, 3, 2, 2};
const float input_values[] = {1, 2, 7, 8, 3, 4, 9, 10, 5, 6, 11, 12};
int filter_shape[] = {4, 1, 2, 2, 4};
const float filter_values[] = {1, 2, 3, 4, -9, 10, -11, 12,
5, 6, 7, 8, 13, -14, 15, -16};
int bias_shape[] = {4, 1, 1, 1, 4};
const float bias_values[] = {1, 2, 3, 4};
const float golden[] = {
71, -34, 99, -20, 91, -26, 127, -4,
};
int output_shape[] = {4, 1, 2, 1, 4};
const int output_dims_count = 8;
float output_data[output_dims_count];
TfLiteDepthwiseConvParams conv_params;
conv_params.activation = kTfLiteActNone;
conv_params.dilation_width_factor = 1;
conv_params.dilation_height_factor = 1;
conv_params.stride_height = 1;
conv_params.stride_width = 1;
tflite::testing::TestDepthwiseConvFloat(
input_shape, input_values, filter_shape, filter_values, bias_shape,
bias_values, golden, output_shape, &conv_params, output_data);
}
TF_LITE_MICRO_TEST(SimpleTestRelu) {
int input_shape[] = {4, 1, 3, 2, 2};
const float input_values[] = {1, 2, 7, 8, 3, 4, 9, 10, 5, 6, 11, 12};
int filter_shape[] = {4, 1, 2, 2, 4};
const float filter_values[] = {1, 2, 3, 4, -9, 10, -11, 12,
5, 6, 7, 8, 13, -14, 15, -16};
int bias_shape[] = {4, 1, 1, 1, 4};
const float bias_values[] = {1, 2, 3, 4};
int output_shape[] = {4, 1, 2, 1, 4};
const int output_dims_count = 8;
const float golden_relu[] = {71, 0, 99, 0, 91, 0, 127, 0};
float output_data[output_dims_count];
TfLiteDepthwiseConvParams conv_params;
conv_params.activation = kTfLiteActRelu;
conv_params.dilation_width_factor = 1;
conv_params.dilation_height_factor = 1;
conv_params.stride_height = 1;
conv_params.stride_width = 1;
tflite::testing::TestDepthwiseConvFloat(
input_shape, input_values, filter_shape, filter_values, bias_shape,
bias_values, golden_relu, output_shape, &conv_params, output_data);
}
TF_LITE_MICRO_TEST(SimpleTestQuantizedPerChannelDepthMultiplier1) {
const int input_elements = 12;
int input_shape[] = {4, 1, 3, 2, 2};
const float input_values[] = {1, 2, 7, 8, 3, 4, 9, 10, 5, 6, 11, 12};
const int filter_elements = 8;
int filter_shape[] = {4, 1, 2, 2, 2};
const float filter_values[] = {1, 2, 3, 4, -9, 10, -11, 12};
const int bias_elements = 2;
int bias_shape[] = {4, 1, 1, 1, 2};
const int output_elements = 4;
const float bias_values[] = {1, 2};
const float golden[] = {
-103,
127,
-128,
127,
};
int output_shape[] = {4, 1, 2, 1, 2};
const int output_dims_count = 4;
int8_t output_data[output_dims_count];
const float input_scale = 1.0f;
const float output_scale = 1.0f;
const int input_zero_point = 0;
const int output_zero_point = 0;
int8_t input_quantized[input_elements];
int8_t filter_quantized[filter_elements];
int32_t bias_quantized[bias_elements];
int8_t golden_quantized[output_elements];
TfLiteDepthwiseConvParams conv_params;
conv_params.activation = kTfLiteActNone;
conv_params.dilation_width_factor = 1;
conv_params.dilation_height_factor = 1;
conv_params.stride_height = 1;
conv_params.stride_width = 1;
tflite::testing::TestDepthwiseConvQuantizedPerChannel(
input_shape, input_values, input_quantized, input_scale, input_zero_point,
filter_shape, filter_values, filter_quantized, bias_shape, bias_values,
bias_quantized, output_shape, golden, golden_quantized, output_data,
output_scale, output_zero_point, &conv_params);
}
TF_LITE_MICRO_TEST(TestQuantizedPerChannelDepthMultiplier1Relu6) {
const int input_elements = 24;
int input_shape[] = {4, 1, 3, 2, 4};
const float input_values[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
const int filter_elements = 16;
int filter_shape[] = {4, 1, 2, 2, 4};
const float filter_values[] = {0, 1, 8, -2, -1, 2, -10, 0,
-1, 3, -18, 0, 0, 4, 20, -3};
const int bias_elements = 4;
int bias_shape[] = {4, 1, 1, 1, 4};
const int output_elements = 8;
const float bias_values[] = {1, 2, 3, 4};
const float golden[] = {
0, 6, 3, 0, 0, 6, 3, 0,
};
int output_shape[] = {4, 1, 2, 1, 4};
int8_t output_data[output_elements];
const float input_scale = 0.023529f;
const float output_scale = 0.023529f;
const int input_zero_point = -128;
const int output_zero_point = -128;
int8_t input_quantized[input_elements];
int8_t filter_quantized[filter_elements];
int32_t bias_quantized[bias_elements];
int8_t golden_quantized[output_elements];
TfLiteDepthwiseConvParams conv_params;
conv_params.activation = kTfLiteActRelu6;
conv_params.dilation_width_factor = 1;
conv_params.dilation_height_factor = 1;
conv_params.stride_height = 1;
conv_params.stride_width = 1;
tflite::testing::TestDepthwiseConvQuantizedPerChannel(
input_shape, input_values, input_quantized, input_scale, input_zero_point,
filter_shape, filter_values, filter_quantized, bias_shape, bias_values,
bias_quantized, output_shape, golden, golden_quantized, output_data,
output_scale, output_zero_point, &conv_params);
}
TF_LITE_MICRO_TEST(SimpleTestDilatedQuantizedPerChannel) {
const int input_elements = 48;
int input_shape[] = {4, 1, 4, 6, 2};
const float input_values[] = {1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, // h = 0
3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, // h = 1
1, 2, 3, 4, 5, 6, 2, 6, 2, 4, 4, 2, // h = 2
3, 2, 6, 5, 1, 4, 1, 2, 1, 4, 6, 3}; // h = 3
const int filter_elements = 16;
int filter_shape[] = {4, 1, 2, 2, 4};
const float filter_values[] = {1, 2, 3, 4, -9, 10, -11, 12,
5, 6, 7, 8, 13, -14, 15, -16};
const int bias_elements = 4;
int bias_shape[] = {4, 1, 1, 1, 4};
const int output_elements = 24;
const float bias_values[] = {1, 2, 3, 4};
const float golden[] = {
15, 2, 88, -48, 25, 14, 72, 0, 61, -2, 56, 48, // h = 0
-4, 52, 12, 48, 11, 70, 63, 40, 51, -30, 41, 48 // h = 1
};
int output_shape[] = {4, 1, 2, 3, 4};
int8_t output_data[output_elements];
const float input_scale = 0.5;
const float output_scale = 1.0f;
const int input_zero_point = 0;
const int output_zero_point = 0;
int8_t input_quantized[input_elements];
int8_t filter_quantized[filter_elements];
int32_t bias_quantized[bias_elements];
int8_t golden_quantized[output_elements];
TfLiteDepthwiseConvParams conv_params;
conv_params.activation = kTfLiteActNone;
conv_params.dilation_width_factor = 3;
conv_params.dilation_height_factor = 2;
conv_params.stride_height = 1;
conv_params.stride_width = 1;
tflite::testing::TestDepthwiseConvQuantizedPerChannel(
input_shape, input_values, input_quantized, input_scale, input_zero_point,
filter_shape, filter_values, filter_quantized, bias_shape, bias_values,
bias_quantized, output_shape, golden, golden_quantized, output_data,
output_scale, output_zero_point, &conv_params);
}
TF_LITE_MICRO_TEST(TestQuantizedPerChannelCompareWithFloat) {
int input_dims[] = {4, 1, 2, 3, 2};
const float input_data[] = {3, 2, 1, -1, -2, -3, 4, 3, 2, -2, -3, -4};
int filter_dims[] = {4, 1, 2, 2, 4};
const float filter_data[] = {1, 2, 3, 4, 3, 4, 5, 6, 7, 8, 5, 6, 3, 4, 1, 2};
int bias_dims[] = {4, 1, 1, 1, 4};
const float bias_data[] = {3, -2, 4, 6};
int output_dims[] = {4, 1, 1, 2, 4};
const float golden[] = {43, 48, 18, 22, 3, -4, -28, -36};
const int input_size = 12;
const int filter_size = 16;
const int output_size = 8;
const int bias_size = 4;
int8_t input_quantized[input_size];
int8_t filter_quantized[filter_size];
int32_t bias_quantized[bias_size];
int8_t golden_quantized[output_size];
int8_t output_data[output_size];
float output_float[output_size];
const float input_scale = 0.5;
const float output_scale = 1.0;
const int input_zero_point = 0;
const int output_zero_point = 0;
TfLiteDepthwiseConvParams conv_params;
conv_params.activation = kTfLiteActNone;
conv_params.dilation_width_factor = 1;
conv_params.dilation_height_factor = 1;
conv_params.stride_height = 1;
conv_params.stride_width = 1;
tflite::testing::TestDepthwiseConvQuantizedPerChannel(
input_dims, input_data, input_quantized, input_scale, input_zero_point,
filter_dims, filter_data, filter_quantized, bias_dims, bias_data,
bias_quantized, output_dims, golden, golden_quantized, output_data,
output_scale, output_zero_point, &conv_params);
tflite::testing::TestDepthwiseConvFloat(
input_dims, input_data, filter_dims, filter_data, bias_dims, bias_data,
golden, output_dims, &conv_params, output_float);
}
TF_LITE_MICRO_TEST(PerChannelBroadcastQuantizationParams) {
const float input_scale = 1.0f;
const float filter_scale = 1.0f;
const float output_scale = 1.0f;
const int input_elements = 12;
int input_shape[] = {4, 1, 3, 2, 2};
const float input_values[] = {1, 2, 7, 8, 3, 4, 9, 10, 5, 6, 11, 12};
const int filter_elements = 16;
int filter_shape[] = {4, 1, 2, 2, 4};
const float filter_values[] = {1, 2, 3, 4, -9, 10, -11, 12,
5, 6, 7, 8, 13, -14, 15, -16};
const int bias_elements = 4;
int bias_shape[] = {4, 1, 1, 1, 4};
const int output_elements = 8;
const float bias_values[] = {1, 2, 3, 4};
const float golden[] = {
71, -34, 99, -20, 91, -26, 127, -4,
};
int output_shape[] = {4, 1, 2, 1, 4};
const int output_dims_count = 8;
int8_t output_data[output_dims_count];
int8_t input_quantized[input_elements];
int8_t filter_quantized[filter_elements];
int32_t bias_quantized[bias_elements];
int8_t golden_quantized[output_elements];
TfLiteIntArray* input_dims = tflite::testing::IntArrayFromInts(input_shape);
TfLiteIntArray* filter_dims = tflite::testing::IntArrayFromInts(filter_shape);
TfLiteIntArray* bias_dims = tflite::testing::IntArrayFromInts(bias_shape);
TfLiteIntArray* output_dims = tflite::testing::IntArrayFromInts(output_shape);
// Create per-layer quantized int8_t input tensor.
TfLiteTensor input_tensor = tflite::testing::CreateQuantizedTensor(
input_values, input_quantized, input_dims, input_scale, 0);
int input_zero_points[2] = {1, 0};
float input_scales[2] = {1, input_scale};
TfLiteAffineQuantization input_quant = {
tflite::testing::FloatArrayFromFloats(input_scales),
tflite::testing::IntArrayFromInts(input_zero_points), 0};
input_tensor.quantization = {kTfLiteAffineQuantization, &input_quant};
// Create per-layer quantized int8_t filter tensor.
TfLiteTensor filter_tensor = tflite::testing::CreateQuantizedTensor(
filter_values, filter_quantized, filter_dims, filter_scale, 0);
int filter_zero_points[2] = {1, 0};
float filter_scales[2] = {1, filter_scale};
TfLiteAffineQuantization filter_quant = {
tflite::testing::FloatArrayFromFloats(filter_scales),
tflite::testing::IntArrayFromInts(filter_zero_points), 0};
filter_tensor.quantization = {kTfLiteAffineQuantization, &filter_quant};
// Create per-layer quantized int32_t bias tensor.
tflite::SymmetricQuantize(bias_values, bias_quantized, bias_elements,
input_scale * output_scale);
TfLiteTensor bias_tensor =
tflite::testing::CreateTensor(bias_quantized, bias_dims);
int bias_zero_points[2] = {1, 0};
float bias_scales[2] = {1, input_scale * filter_scale};
TfLiteAffineQuantization bias_quant = {
tflite::testing::FloatArrayFromFloats(bias_scales),
tflite::testing::IntArrayFromInts(bias_zero_points), 0};
bias_tensor.quantization = {kTfLiteAffineQuantization, &bias_quant};
// Create per-layer quantized int8_t output tensor.
TfLiteTensor output_tensor = tflite::testing::CreateQuantizedTensor(
output_data, output_dims, output_scale, 0);
int output_zero_points[2] = {1, 0};
float output_scales[2] = {1, output_scale};
TfLiteAffineQuantization output_quant = {
tflite::testing::FloatArrayFromFloats(output_scales),
tflite::testing::IntArrayFromInts(output_zero_points), 0};
output_tensor.quantization = {kTfLiteAffineQuantization, &output_quant};
constexpr int inputs_size = 3;
constexpr int outputs_size = 1;
constexpr int tensors_size = inputs_size + outputs_size;
TfLiteTensor tensors[tensors_size] = {
input_tensor,
filter_tensor,
bias_tensor,
output_tensor,
};
tflite::Quantize(golden, golden_quantized, output_dims_count, output_scale,
0);
TfLiteDepthwiseConvParams conv_params;
conv_params.activation = kTfLiteActNone;
conv_params.dilation_width_factor = 1;
conv_params.dilation_height_factor = 1;
conv_params.stride_height = 1;
conv_params.stride_width = 1;
TF_LITE_MICRO_EXPECT_EQ(
kTfLiteOk, tflite::testing::ValidateDepthwiseConvGoldens(
golden_quantized, output_dims_count, &conv_params, 1e-5,
tensors_size, tensors));
}
#endif // !defined(XTENSA)
TF_LITE_MICRO_TEST(FilterDimsNotMatchingAffineQuantization) {
int input_shape[] = {4, 1, 2, 3, 2};
const float input_data[] = {3, 2, 1, -1, -2, -3, 4, 3, 2, -2, -3, -4};
int filter_shape[] = {4, 1, 2, 2, 4};
const float filter_data[] = {1, 2, 3, 4, 3, 4, 5, 6, 7, 8, 5, 6, 3, 4, 1, 2};
int bias_shape[] = {4, 1, 1, 1, 4};
const float bias_data[] = {3, -2, 4, 6};
int output_shape[] = {4, 1, 1, 2, 4};
const int input_size = 12;
const int filter_size = 16;
const int output_size = 8;
const int bias_size = 4;
int8_t input_quantized[input_size];
int8_t filter_quantized[filter_size];
int32_t bias_quantized[bias_size];
int8_t golden_quantized[output_size] = {};
int zero_points[bias_size + 1];
float scales[bias_size + 1];
int8_t output_data[output_size];
const float input_scale = 0.5;
const float output_scale = 1.0;
const int input_zero_point = 0;
const int output_zero_point = 0;
TfLiteIntArray* input_dims = tflite::testing::IntArrayFromInts(input_shape);
TfLiteIntArray* filter_dims = tflite::testing::IntArrayFromInts(filter_shape);
TfLiteIntArray* bias_dims = tflite::testing::IntArrayFromInts(bias_shape);
TfLiteIntArray* output_dims = tflite::testing::IntArrayFromInts(output_shape);
int filter_zero_points[5];
float filter_scales[5];
TfLiteAffineQuantization filter_quant;
TfLiteAffineQuantization bias_quant;
TfLiteTensor input_tensor = tflite::testing::CreateQuantizedTensor(
input_data, input_quantized, input_dims, input_scale, input_zero_point);
TfLiteTensor filter_tensor =
tflite::testing::CreateSymmetricPerChannelQuantizedTensor(
filter_data, filter_quantized, filter_dims, filter_scales,
filter_zero_points, &filter_quant, 0 /* quantized dimension */);
TfLiteTensor bias_tensor =
tflite::testing::CreatePerChannelQuantizedBiasTensor(
bias_data, bias_quantized, bias_dims, input_scale, &filter_scales[1],
scales, zero_points, &bias_quant, 0);
TfLiteTensor output_tensor = tflite::testing::CreateQuantizedTensor(
output_data, output_dims, output_scale, output_zero_point);
float input_scales[] = {1, input_scale};
int input_zero_points[] = {1, input_zero_point};
TfLiteAffineQuantization input_quant = {
tflite::testing::FloatArrayFromFloats(input_scales),
tflite::testing::IntArrayFromInts(input_zero_points), 0};
input_tensor.quantization = {kTfLiteAffineQuantization, &input_quant};
constexpr int inputs_size = 3;
constexpr int outputs_size = 1;
constexpr int tensors_size = inputs_size + outputs_size;
TfLiteTensor tensors[tensors_size] = {
input_tensor,
filter_tensor,
bias_tensor,
output_tensor,
};
TfLiteDepthwiseConvParams conv_params;
conv_params.activation = kTfLiteActNone;
conv_params.dilation_width_factor = 1;
conv_params.dilation_height_factor = 1;
conv_params.stride_height = 1;
conv_params.stride_width = 1;
// Set filter quant to mismatched dimension.
TfLiteAffineQuantization* quant = reinterpret_cast<TfLiteAffineQuantization*>(
filter_tensor.quantization.params);
quant->scale->size = 2;
TF_LITE_MICRO_EXPECT_EQ(kTfLiteError,
tflite::testing::ValidateDepthwiseConvGoldens(
golden_quantized, output_size, &conv_params, 1e-5,
tensors_size, tensors));
// Set scale back to correct dimension, and make zero point array too short.
quant->scale->size = filter_shape[0];
quant->zero_point->size = 2;
TF_LITE_MICRO_EXPECT_EQ(kTfLiteError,
tflite::testing::ValidateDepthwiseConvGoldens(
golden_quantized, output_size, &conv_params, 1e-5,
tensors_size, tensors));
}
TF_LITE_MICRO_TEST(Int8Input32x4Filter32x4ShouldMatchGolden) {
const int input_elements = 32 * 4;
const int filter_elements = 32 * 4;
const int bias_elements = 32;
const int output_elements = 32;
int input_shape[] = {4, 1, 4, 1, 32};
int filter_shape[] = {4, 1, 4, 1, 32};
int bias_shape[] = {1, 32};
int output_shape[] = {4, 1, 1, 1, 32};
const float input_values[] = {
11.0589, 10.8824, 11.1766, 11.5295, 10.8236, 9.5295, 9.5295, 10.0001,
11.2354, 10.8824, 9.1765, 9.0589, 9.6471, 8.9412, 7.9412, 9.0001,
9.3530, 7.5295, 9.2354, 9.5883, 7.5883, 8.1765, 7.5883, 9.2942,
9.1177, 8.5883, 8.2354, 8.6471, 8.0589, 8.0001, 7.4118, 7.3530,
11.0001, 11.1177, 11.0589, 11.2354, 10.5883, 9.2942, 9.2942, 10.1177,
11.2354, 10.8824, 8.9412, 8.8236, 9.2354, 8.8824, 7.0001, 9.1177,
9.5883, 8.2354, 9.1765, 9.5295, 7.4118, 8.5883, 8.1177, 9.1765,
9.0001, 9.0589, 8.9412, 8.2942, 7.8824, 8.4118, 7.2942, 7.2354,
10.4118, 10.8824, 11.1177, 11.0001, 10.0001, 9.7060, 9.7648, 10.1766,
11.1766, 10.6471, 8.6471, 8.5295, 9.5295, 9.0001, 7.0001, 9.4118,
9.8236, 8.0001, 9.2354, 9.5883, 7.5295, 9.0001, 8.5295, 9.0589,
8.9412, 9.1177, 8.9412, 8.0001, 8.0589, 8.8824, 7.0589, 7.3530,
11.3530, 11.0589, 10.7060, 10.7648, 9.9413, 9.1177, 9.1177, 9.7648,
10.7060, 10.2354, 8.5883, 8.8236, 9.7648, 9.2942, 7.5295, 9.2354,
9.7060, 8.1177, 9.2942, 9.5883, 7.7648, 9.6471, 9.1177, 9.4707,
9.3530, 8.8236, 8.5295, 8.0589, 8.6471, 9.5883, 7.4118, 7.5883};
const float filter_values[] = {
-0.1617, -0.1948, 0.1419, -0.2311, -0.0891, 0.1551, 0.0033, 0.3037,
-0.1683, 0.1353, 0.1518, -0.1683, -0.1386, 0.1452, 0.1816, 0.1716,
-0.1948, 0.2080, 0.2245, -0.1981, -0.2410, 0.1849, 0.1981, 0.1584,
0.2509, 0.1783, -0.2146, -0.1518, 0.2080, -0.2872, 0.2014, 0.2476,
-0.4126, -0.0561, -0.3235, -0.0594, -0.0957, 0.2014, -0.1056, 0.1386,
-0.2542, -0.1617, 0.1287, -0.1816, -0.0363, 0.1419, -0.0594, 0.2344,
-0.0099, 0.4192, 0.1287, -0.2311, -0.2212, -0.0528, -0.2080, 0.1816,
-0.1452, 0.1221, 0.1254, -0.1056, -0.0759, 0.1221, 0.1023, 0.1485,
0.2707, 0.1716, -0.1882, -0.1783, 0.1650, -0.2740, 0.1915, 0.2080,
-0.2971, -0.2575, -0.3169, 0.0198, -0.0231, 0.2410, -0.0429, 0.0660,
-0.1816, 0.1981, 0.2014, -0.1386, -0.1915, 0.1716, 0.1320, 0.1419,
0.1320, 0.1353, -0.1386, -0.1716, 0.1320, -0.1650, 0.1386, 0.0825,
-0.1419, -0.1023, 0.1783, 0.0462, 0.2047, -0.2179, -0.1518, -0.1551,
0.1518, 0.3334, 0.3103, -0.2047, -0.2047, -0.0957, -0.1650, 0.1221,
0.0990, 0.1353, -0.1617, -0.1485, 0.1650, -0.1816, 0.1518, 0.1254,
-0.0363, -0.1254, 0.1386, 0.0429, 0.2113, -0.2839, -0.1056, -0.2278};
const float bias_values[] = {
0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000};
const float golden[] = {
-5.1194, -2.0075, -2.1751, -4.7958, 1.7073, -1.2963, -0.4641, 5.0416,
-6.4424, 0.3836, 2.4684, -4.7643, -3.8913, 3.8382, -0.5164, 5.4304,
-2.7400, 7.7016, 3.6115, -6.8545, -3.6290, 0.8509, 2.3247, 5.6117,
1.8215, 2.7645, -0.7032, -3.2156, 3.9689, -5.4583, 2.4346, 1.7731};
// Quantization Parameters. All scales except output are 1.0, and all zero
// points are 0. This direct-maps the values to floating point and makes it
// easy to reson about them.
const float input_scale = 0.058824;
const float filter_scale = 0.003301;
const float output_scale = 0.092596;
const int input_zero_point = -128;
const int output_zero_point = 0;
TfLiteIntArray* input_dims = tflite::testing::IntArrayFromInts(input_shape);
TfLiteIntArray* filter_dims = tflite::testing::IntArrayFromInts(filter_shape);
TfLiteIntArray* bias_dims = tflite::testing::IntArrayFromInts(bias_shape);
TfLiteIntArray* output_dims = tflite::testing::IntArrayFromInts(output_shape);
// Create per-tensor quantized int8_t input tensor.
int8_t input_quantized[input_elements];
TfLiteTensor input_tensor = tflite::testing::CreateQuantizedTensor(
input_values, input_quantized, input_dims, input_scale, input_zero_point);
// Set zero point and scale arrays with a single element for each.
int input_zero_points[] = {1, input_zero_point};
float input_scales[] = {1, input_scale};
TfLiteAffineQuantization input_quant = {
tflite::testing::FloatArrayFromFloats(input_scales),
tflite::testing::IntArrayFromInts(input_zero_points), 0};
input_tensor.quantization = {kTfLiteAffineQuantization, &input_quant};
// Create per-tensor quantized int8_t filter tensor.
int8_t filter_quantized[filter_elements];
TfLiteTensor filter_tensor = tflite::testing::CreateQuantizedTensor(
filter_values, filter_quantized, filter_dims, filter_scale, 0);
// Set zero point and scale arrays with a single element for each.
int filter_zero_points[] = {1, 0};
float filter_scales[] = {1, filter_scale};
TfLiteAffineQuantization filter_quant = {
tflite::testing::FloatArrayFromFloats(filter_scales),
tflite::testing::IntArrayFromInts(filter_zero_points), 0};
filter_tensor.quantization = {kTfLiteAffineQuantization, &filter_quant};
// Create per-tensor quantized int32_t bias tensor.
int32_t bias_quantized[bias_elements];
// See https://www.tensorflow.org/lite/performance/quantization_spec for a
// detailed explanation of why bias scale is input_scale * filter_scale.
tflite::SymmetricQuantize(bias_values, bias_quantized, bias_elements,
input_scale * output_scale);
TfLiteTensor bias_tensor =
tflite::testing::CreateTensor(bias_quantized, bias_dims);
// Set zero point and scale arrays with a single element for each.
int bias_zero_points[] = {1, 0};
float bias_scales[] = {1, input_scale * filter_scale};
TfLiteAffineQuantization bias_quant = {
tflite::testing::FloatArrayFromFloats(bias_scales),
tflite::testing::IntArrayFromInts(bias_zero_points), 0};
bias_tensor.quantization = {kTfLiteAffineQuantization, &bias_quant};
// Create per-tensor quantized int8_t output tensor.
int8_t output_quantized[output_elements];
TfLiteTensor output_tensor = tflite::testing::CreateQuantizedTensor(
output_quantized, output_dims, output_scale, output_zero_point);
// Set zero point and scale arrays with a single element for each.
int output_zero_points[] = {1, output_zero_point};
float output_scales[] = {1, output_scale};
TfLiteAffineQuantization output_quant = {
tflite::testing::FloatArrayFromFloats(output_scales),
tflite::testing::IntArrayFromInts(output_zero_points), 0};
output_tensor.quantization = {kTfLiteAffineQuantization, &output_quant};
// The 3 inputs include the input, filter and bias tensors.
constexpr int kInputsSize = 3;
constexpr int kOutputsSize = 1;
constexpr int kTensorsSize = kInputsSize + kOutputsSize;
TfLiteTensor tensors[kTensorsSize] = {
input_tensor,
filter_tensor,
bias_tensor,
output_tensor,
};
int8_t golden_quantized[output_elements];
tflite::Quantize(golden, golden_quantized, output_elements, output_scale, 0);
// Errors due to quantization should not exceed 1.
constexpr int kQuantizationTolerance = 1;
TfLiteDepthwiseConvParams conv_params;
conv_params.activation = kTfLiteActNone;
conv_params.dilation_width_factor = 1;
conv_params.dilation_height_factor = 1;
conv_params.stride_height = 1;
conv_params.stride_width = 1;
tflite::testing::ValidateDepthwiseConvGoldens(
golden_quantized, output_elements, &conv_params, kQuantizationTolerance,
kTensorsSize, tensors);
}
TF_LITE_MICRO_TEST(Int8Input32x1Filter32x1ShouldMatchGolden) {
const int input_elements = 32 * 1;
const int filter_elements = 32 * 1;
const int bias_elements = 32;
const int output_elements = 32;
int input_shape[] = {4, 1, 1, 1, 32};
int filter_shape[] = {4, 1, 1, 1, 32};
int bias_shape[] = {1, 32};
int output_shape[] = {4, 1, 1, 1, 32};
const float input_values[] = {
11.0589, 10.8824, 11.1766, 11.5295, 10.8236, 9.5295, 9.5295, 10.0001,
11.2354, 10.8824, 9.1765, 9.0589, 9.6471, 8.9412, 7.9412, 9.0001,
9.3530, 7.5295, 9.2354, 9.5883, 7.5883, 8.1765, 7.5883, 9.2942,
9.3530, 8.8236, 8.5295, 8.0589, 8.6471, 9.5883, 7.4118, 7.5883};
const float filter_values[] = {
-0.1419, -0.1023, 0.1783, 0.0462, 0.2047, -0.2179, -0.1518, -0.1551,
0.1518, 0.3334, 0.3103, -0.2047, -0.2047, -0.0957, -0.1650, 0.1221,
0.0990, 0.1353, -0.1617, -0.1485, 0.1650, -0.1816, 0.1518, 0.1254,
-0.0363, -0.1254, 0.1386, 0.0429, 0.2113, -0.2839, -0.1056, -0.2278};
const float bias_values[] = {
0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000,
0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000};
const float golden[] = {
-1.5741, -1.1112, 2.0371, 0.5556, 2.2223, -2.0371, -1.4815, -1.5741,
1.6667, 3.6112, 2.8705, -1.8519, -1.9445, -0.8334, -1.2963, 1.1112,
0.9260, 1.0186, -1.4815, -1.3889, 1.2963, -1.4815, 1.1112, 1.2037,
-0.3704, -1.1112, 1.2037, 0.3704, 1.8519, -2.6853, -0.7408, -1.7593};
// Quantization Parameters. All scales except output are 1.0, and all zero
// points are 0. This direct-maps the values to floating point and makes it
// easy to reson about them.
const float input_scale = 0.058824;
const float filter_scale = 0.003301;
const float output_scale = 0.092596;
const int input_zero_point = -128;
const int output_zero_point = 0;
TfLiteIntArray* input_dims = tflite::testing::IntArrayFromInts(input_shape);
TfLiteIntArray* filter_dims = tflite::testing::IntArrayFromInts(filter_shape);
TfLiteIntArray* bias_dims = tflite::testing::IntArrayFromInts(bias_shape);
TfLiteIntArray* output_dims = tflite::testing::IntArrayFromInts(output_shape);
// Create per-tensor quantized int8_t input tensor.
int8_t input_quantized[input_elements];
TfLiteTensor input_tensor = tflite::testing::CreateQuantizedTensor(
input_values, input_quantized, input_dims, input_scale, input_zero_point);
// Set zero point and scale arrays with a single element for each.
int input_zero_points[] = {1, input_zero_point};
float input_scales[] = {1, input_scale};
TfLiteAffineQuantization input_quant = {
tflite::testing::FloatArrayFromFloats(input_scales),
tflite::testing::IntArrayFromInts(input_zero_points), 0};
input_tensor.quantization = {kTfLiteAffineQuantization, &input_quant};
// Create per-tensor quantized int8_t filter tensor.
int8_t filter_quantized[filter_elements];
TfLiteTensor filter_tensor = tflite::testing::CreateQuantizedTensor(
filter_values, filter_quantized, filter_dims, filter_scale, 0);
// Set zero point and scale arrays with a single element for each.
int filter_zero_points[] = {1, 0};
float filter_scales[] = {1, filter_scale};
TfLiteAffineQuantization filter_quant = {
tflite::testing::FloatArrayFromFloats(filter_scales),
tflite::testing::IntArrayFromInts(filter_zero_points), 0};
filter_tensor.quantization = {kTfLiteAffineQuantization, &filter_quant};
// Create per-tensor quantized int32_t bias tensor.
int32_t bias_quantized[bias_elements];
// See https://www.tensorflow.org/lite/performance/quantization_spec for a
// detailed explanation of why bias scale is input_scale * filter_scale.
tflite::SymmetricQuantize(bias_values, bias_quantized, bias_elements,
input_scale * output_scale);
TfLiteTensor bias_tensor =
tflite::testing::CreateTensor(bias_quantized, bias_dims);
// Set zero point and scale arrays with a single element for each.
int bias_zero_points[] = {1, 0};
float bias_scales[] = {1, input_scale * filter_scale};
TfLiteAffineQuantization bias_quant = {
tflite::testing::FloatArrayFromFloats(bias_scales),
tflite::testing::IntArrayFromInts(bias_zero_points), 0};
bias_tensor.quantization = {kTfLiteAffineQuantization, &bias_quant};
// Create per-tensor quantized int8_t output tensor.
int8_t output_quantized[output_elements];
TfLiteTensor output_tensor = tflite::testing::CreateQuantizedTensor(
output_quantized, output_dims, output_scale, output_zero_point);
// Set zero point and scale arrays with a single element for each.
int output_zero_points[] = {1, output_zero_point};
float output_scales[] = {1, output_scale};
TfLiteAffineQuantization output_quant = {
tflite::testing::FloatArrayFromFloats(output_scales),
tflite::testing::IntArrayFromInts(output_zero_points), 0};
output_tensor.quantization = {kTfLiteAffineQuantization, &output_quant};
// The 3 inputs include the input, filter and bias tensors.
constexpr int kInputsSize = 3;
constexpr int kOutputsSize = 1;
constexpr int kTensorsSize = kInputsSize + kOutputsSize;
TfLiteTensor tensors[kTensorsSize] = {
input_tensor,
filter_tensor,
bias_tensor,
output_tensor,
};
int8_t golden_quantized[output_elements];
tflite::Quantize(golden, golden_quantized, output_elements, output_scale, 0);
// Errors due to quantization should not exceed 1.
constexpr int kQuantizationTolerance = 1;
TfLiteDepthwiseConvParams conv_params;
conv_params.activation = kTfLiteActNone;
conv_params.dilation_width_factor = 1;
conv_params.dilation_height_factor = 1;
conv_params.stride_height = 2;
conv_params.stride_width = 2;
TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk,
tflite::testing::ValidateDepthwiseConvGoldens(
golden_quantized, output_elements, &conv_params,
kQuantizationTolerance, kTensorsSize, tensors));
}
// TODO(b/268384678): xtensa vision p6 kernels break
// this test, will if def till properly investigated.
// Quantizing int8-ranged filter values down to int4 doesn't always yield the
// accuracy sufficient to meet the golden values. So this test was created by
// handcrafting filter values within the int4 range, and the golden data was
// obtained by running TestDepthwiseConvQuantizedPerChannel() with int8
// quantization, and ensuring that int4 quantization yields the same outputs.
TF_LITE_MICRO_TEST(SimpleTestQuantizedPerChannelInt4Filter) {
const int input_elements = 12;
int input_shape[] = {4, 1, 3, 2, 2};
const float input_values[] = {1, 2, 7, 8, 3, 4, 9, 10, 5, 6, 11, 12};
const int filter_elements = 16;
int filter_shape[] = {4, 1, 2, 2, 4};
const float filter_values[] = {1, 2, 3, 4, -5, 7, -6, 7,
5, 6, 7, 4, 2, -5, 4, 0};
const int bias_elements = 4;
int bias_shape[] = {4, 1, 1, 1, 4};
const int output_elements = 8;
const float bias_values[] = {1, 2, 3, 4};
const float golden[] = {
0, 26, 29, 84, 6, 46, 45, 114,
};
int output_shape[] = {4, 1, 2, 1, 4};
const int output_dims_count = 8;
int8_t output_data[output_dims_count];
const float input_scale = 0.5;
const float output_scale = 1.0f;
const int input_zero_point = 0;
const int output_zero_point = 0;
int8_t input_quantized[input_elements];
int8_t filter_quantized[filter_elements];
int32_t bias_quantized[bias_elements];
int8_t golden_quantized[output_elements];
TfLiteDepthwiseConvParams conv_params;
conv_params.activation = kTfLiteActNone;
conv_params.dilation_width_factor = 1;
conv_params.dilation_height_factor = 1;
conv_params.stride_height = 1;
conv_params.stride_width = 1;
tflite::testing::TestDepthwiseConvQuantizedPerChannel(
input_shape, input_values, input_quantized, input_scale, input_zero_point,
filter_shape, filter_values, filter_quantized, bias_shape, bias_values,
bias_quantized, output_shape, golden, golden_quantized, output_data,
output_scale, output_zero_point, &conv_params, kTfLiteInt4);
}
TF_LITE_MICRO_TEST(SimpleTestQuantizedPerChannel) {
const int input_elements = 12;
int input_shape[] = {4, 1, 3, 2, 2};
const float input_values[] = {1, 2, 7, 8, 3, 4, 9, 10, 5, 6, 11, 12};
const int filter_elements = 16;
int filter_shape[] = {4, 1, 2, 2, 4};
const float filter_values[] = {1, 2, 3, 4, -9, 10, -11, 12,
5, 6, 7, 8, 13, -14, 15, -16};
const int bias_elements = 4;
int bias_shape[] = {4, 1, 1, 1, 4};
const int output_elements = 8;
const float bias_values[] = {1, 2, 3, 4};
const float golden[] = {
71, -34, 99, -20, 91, -26, 127, -4,
};
int output_shape[] = {4, 1, 2, 1, 4};
const int output_dims_count = 8;
int8_t output_data[output_dims_count];
const float input_scale = 0.5;
const float output_scale = 1.0f;
const int input_zero_point = 0;
const int output_zero_point = 0;
int8_t input_quantized[input_elements];
int8_t filter_quantized[filter_elements];
int32_t bias_quantized[bias_elements];
int8_t golden_quantized[output_elements];
TfLiteDepthwiseConvParams conv_params;
conv_params.activation = kTfLiteActNone;
conv_params.dilation_width_factor = 1;
conv_params.dilation_height_factor = 1;
conv_params.stride_height = 1;
conv_params.stride_width = 1;
tflite::testing::TestDepthwiseConvQuantizedPerChannel(
input_shape, input_values, input_quantized, input_scale, input_zero_point,
filter_shape, filter_values, filter_quantized, bias_shape, bias_values,
bias_quantized, output_shape, golden, golden_quantized, output_data,
output_scale, output_zero_point, &conv_params);
}
TF_LITE_MICRO_TEST(SimpleTestQuantizedPerChannelInt16InputInt8Filter) {
const int input_elements = 12;
int input_shape[] = {4, 1, 3, 2, 2};
const float input_values[] = {-547, 108, -682, 540, -161, -539, 9, -482,
-859, 84, 153, -726, 523, 702, -172, -936};
const int filter_elements = 16;
int filter_shape[] = {4, 1, 2, 2, 4};
const float filter_values[] = {1, 2, 3, 4, -9, 10, -11, 12,
5, 6, 7, 8, 13, -14, 15, -16};
const int bias_elements = 4;
int bias_shape[] = {4, 1, 1, 1, 4};
const int output_elements = 8;
const float bias_values[] = {1, 2, 3, 4};
const float golden[] = {
4894, -9009, -16596, 10268, -2564, -7483, -6599, 4356,
};
int output_shape[] = {4, 1, 2, 1, 4};
const int output_dims_count = 8;
int16_t output_data[output_dims_count];
const float input_scale = 0.5;
const float output_scale = 1.0f;
const int input_zero_point = 0;
const int output_zero_point = 0;
int16_t input_quantized[input_elements];
int8_t filter_quantized[filter_elements];
int64_t bias_quantized[bias_elements];
int16_t golden_quantized[output_elements];
TfLiteDepthwiseConvParams conv_params;
conv_params.activation = kTfLiteActNone;
conv_params.dilation_width_factor = 1;
conv_params.dilation_height_factor = 1;
conv_params.stride_height = 1;
conv_params.stride_width = 1;
tflite::testing::TestDepthwiseConvQuantizedPerChannel(
input_shape, input_values, input_quantized, input_scale, input_zero_point,
filter_shape, filter_values, filter_quantized, bias_shape, bias_values,
bias_quantized, output_shape, golden, golden_quantized, output_data,
output_scale, output_zero_point, &conv_params);
}
TF_LITE_MICRO_TESTS_END