From c8847efacb25bb08984c49a65b9f3e25d6d3e064 Mon Sep 17 00:00:00 2001 From: Jens Elofsson Date: Mon, 25 Mar 2019 14:34:10 +0100 Subject: [PATCH 1/6] Tensorflow Lite Micro-port of the Conv-kernel. --- .../micro/kernels/all_ops_resolver.cc | 6 + .../lite/experimental/micro/kernels/conv.cc | 216 ++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 tensorflow/lite/experimental/micro/kernels/conv.cc diff --git a/tensorflow/lite/experimental/micro/kernels/all_ops_resolver.cc b/tensorflow/lite/experimental/micro/kernels/all_ops_resolver.cc index b733949e45df9c..443ea94e6df5f4 100644 --- a/tensorflow/lite/experimental/micro/kernels/all_ops_resolver.cc +++ b/tensorflow/lite/experimental/micro/kernels/all_ops_resolver.cc @@ -29,6 +29,11 @@ TfLiteRegistration* Micro_Register_FULLY_CONNECTED() { TfLiteRegistration* Register_SOFTMAX(); TfLiteRegistration* Micro_Register_SOFTMAX() { return Register_SOFTMAX(); } +TfLiteRegistration* Register_CONV_2D(); +TfLiteRegistration* Micro_Register_CONV_2D() { + return Register_CONV_2D(); +} + AllOpsResolver::AllOpsResolver() { AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Micro_Register_DEPTHWISE_CONV_2D()); @@ -36,6 +41,7 @@ AllOpsResolver::AllOpsResolver() { /* min_version */ 1, /* max_version */ 2); AddBuiltin(BuiltinOperator_SOFTMAX, Micro_Register_SOFTMAX()); + AddBuiltin(BuiltinOperator_CONV_2D, Micro_Register_CONV_2D()); } } // namespace micro diff --git a/tensorflow/lite/experimental/micro/kernels/conv.cc b/tensorflow/lite/experimental/micro/kernels/conv.cc new file mode 100644 index 00000000000000..c8a9caeff75a3b --- /dev/null +++ b/tensorflow/lite/experimental/micro/kernels/conv.cc @@ -0,0 +1,216 @@ +/* Copyright 2019 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/kernels/internal/reference/conv.h" +#include "tensorflow/lite/c/builtin_op_data.h" +#include "tensorflow/lite/c/c_api_internal.h" +#include "tensorflow/lite/kernels/internal/common.h" +#include "tensorflow/lite/kernels/internal/quantization_util.h" +#include "tensorflow/lite/kernels/internal/tensor_ctypes.h" +#include "tensorflow/lite/kernels/kernel_util.h" +#include "tensorflow/lite/kernels/padding.h" + +namespace tflite { +namespace ops { +namespace micro { +namespace conv { + +constexpr int kInputTensor = 0; +constexpr int kFilterTensor = 1; +constexpr int kBiasTensor = 2; +constexpr int kOutputTensor = 0; + +// This file has 2 implementation of Conv. + +const int kTensorNotAllocated = -1; + +struct OpData { + TfLitePaddingValues padding; + // The scaling factor from input to output (aka the 'real multiplier') can + // be represented as a fixed point multiplier plus a left shift. + int32_t output_multiplier; + int output_shift; + + // The range of the fused activation layer. For example for kNone and + // uint8_t these would be 0 and 255. + int32_t output_activation_min; + int32_t output_activation_max; +}; + +inline PaddingType RuntimePaddingType(TfLitePadding padding) { + switch (padding) { + case TfLitePadding::kTfLitePaddingSame: + return PaddingType::kSame; + case TfLitePadding::kTfLitePaddingValid: + return PaddingType::kValid; + case TfLitePadding::kTfLitePaddingUnknown: + default: + return PaddingType::kNone; + } +} + +TfLiteStatus CalculateOpData(TfLiteContext* context, TfLiteNode* node, + TfLiteConvParams* params, int width, int height, + int filter_width, int filter_height, int out_width, + int out_height, const TfLiteType data_type, + OpData* data) { + data->padding.height = + ComputePadding(params->stride_height, params->dilation_height_factor, + height, filter_height, out_height); + data->padding.width = + ComputePadding(params->stride_width, params->dilation_width_factor, width, + filter_width, out_width); + + // Note that quantized inference requires that all tensors have their + // parameters set. This is usually done during quantized training. + if (data_type != kTfLiteFloat32) { + const TfLiteTensor* input = GetInput(context, node, kInputTensor); + const TfLiteTensor* filter = GetInput(context, node, kFilterTensor); + const TfLiteTensor* bias = + GetOptionalInputTensor(context, node, kBiasTensor); + TfLiteTensor* output = GetOutput(context, node, kOutputTensor); + + double real_multiplier = 0.0; + TF_LITE_ENSURE_STATUS(GetQuantizedConvolutionMultipler( + context, input, filter, bias, output, &real_multiplier)); + int exponent; + QuantizeMultiplier(real_multiplier, &data->output_multiplier, &exponent); + data->output_shift = -exponent; + + CalculateActivationRangeQuantized(context, params->activation, output, + &data->output_activation_min, + &data->output_activation_max); + } + return kTfLiteOk; +} + +void* Init(TfLiteContext* context, const char* buffer, size_t length) { + return nullptr; +} + +void Free(TfLiteContext* context, void* buffer) {} + +TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) { + return kTfLiteOk; +} + +void EvalQuantized(TfLiteContext* context, TfLiteNode* node, + TfLiteConvParams* params, OpData* data, + const TfLiteTensor* input, const TfLiteTensor* filter, + const TfLiteTensor* bias, TfLiteTensor* im2col, + TfLiteTensor* hwcn_weights, TfLiteTensor* output) { + const int32_t input_offset = -input->params.zero_point; + const int32_t filter_offset = -filter->params.zero_point; + const int32_t output_offset = output->params.zero_point; + + ConvParams op_params; + op_params.padding_type = RuntimePaddingType(params->padding); + op_params.padding_values.width = data->padding.width; + op_params.padding_values.height = data->padding.height; + op_params.stride_width = params->stride_width; + op_params.stride_height = params->stride_height; + op_params.dilation_width_factor = params->dilation_width_factor; + op_params.dilation_height_factor = params->dilation_height_factor; + op_params.input_offset = input_offset; + op_params.weights_offset = filter_offset; + op_params.output_offset = output_offset; + op_params.output_multiplier = data->output_multiplier; + op_params.output_shift = -data->output_shift; + op_params.quantized_activation_min = data->output_activation_min; + op_params.quantized_activation_max = data->output_activation_max; + reference_ops::Conv(op_params, GetTensorShape(input), + GetTensorData(input), GetTensorShape(filter), + GetTensorData(filter), GetTensorShape(bias), + GetTensorData(bias), GetTensorShape(output), + GetTensorData(output), GetTensorShape(im2col), + GetTensorData(im2col), nullptr); +} + +void EvalFloat(TfLiteContext* context, TfLiteNode* node, + TfLiteConvParams* params, OpData* data, + const TfLiteTensor* input, const TfLiteTensor* filter, + const TfLiteTensor* bias, TfLiteTensor* im2col, + TfLiteTensor* hwcn_weights, TfLiteTensor* output) { + float output_activation_min, output_activation_max; + CalculateActivationRange(params->activation, &output_activation_min, + &output_activation_max); + + ConvParams op_params; + op_params.padding_type = RuntimePaddingType(params->padding); + op_params.padding_values.width = data->padding.width; + op_params.padding_values.height = data->padding.height; + op_params.stride_width = params->stride_width; + op_params.stride_height = params->stride_height; + op_params.dilation_width_factor = params->dilation_width_factor; + op_params.dilation_height_factor = params->dilation_height_factor; + op_params.float_activation_min = output_activation_min; + op_params.float_activation_max = output_activation_max; + + reference_ops::Conv(op_params, GetTensorShape(input), + GetTensorData(input), GetTensorShape(filter), + GetTensorData(filter), GetTensorShape(bias), + GetTensorData(bias), GetTensorShape(output), + GetTensorData(output), GetTensorShape(im2col), + GetTensorData(im2col)); +} + +TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { + auto* params = reinterpret_cast(node->builtin_data); + + TfLiteTensor* output = GetOutput(context, node, kOutputTensor); + const TfLiteTensor* input = GetInput(context, node, kInputTensor); + const TfLiteTensor* filter = GetInput(context, node, kFilterTensor); + const TfLiteTensor* bias = GetOptionalInputTensor(context, node, kBiasTensor); + + int input_width = input->dims->data[2]; + int input_height = input->dims->data[1]; + int filter_width = filter->dims->data[2]; + int filter_height = filter->dims->data[1]; + int output_width = output->dims->data[2]; + int output_height = output->dims->data[1]; + + OpData data; + TF_LITE_ENSURE_STATUS(CalculateOpData( + context, node, params, input_width, input_height, filter_width, + filter_height, output_width, output_height, input->type, &data)); + + switch (input->type) { // Already know in/out types are same. + case kTfLiteFloat32: + EvalFloat(context, node, params, &data, input, filter, bias, nullptr, + nullptr, output); + break; + case kTfLiteUInt8: + EvalQuantized(context, node, params, &data, input, filter, bias, nullptr, + nullptr, output); + break; + default: + context->ReportError(context, "Type %d not currently supported.", + input->type); + return kTfLiteError; + } + return kTfLiteOk; +} + +} // namespace conv + +TfLiteRegistration* Register_CONV_2D() { + static TfLiteRegistration r = {conv::Init, conv::Free, conv::Prepare, + conv::Eval}; + return &r; +} + +} // namespace micro +} // namespace ops +} // namespace tflite From c0ba417406c81d108f62228bc4f83188b6a9892e Mon Sep 17 00:00:00 2001 From: Jens Elofsson Date: Wed, 27 Mar 2019 10:34:52 +0100 Subject: [PATCH 2/6] Testcases for the Conv-kernel in Tensorflow Lite Micro. --- .../experimental/micro/kernels/conv_test.cc | 329 ++++++++++++++++++ 1 file changed, 329 insertions(+) create mode 100644 tensorflow/lite/experimental/micro/kernels/conv_test.cc diff --git a/tensorflow/lite/experimental/micro/kernels/conv_test.cc b/tensorflow/lite/experimental/micro/kernels/conv_test.cc new file mode 100644 index 00000000000000..537c9e4dba827f --- /dev/null +++ b/tensorflow/lite/experimental/micro/kernels/conv_test.cc @@ -0,0 +1,329 @@ +/* Copyright 2019 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/c_api_internal.h" +#include "tensorflow/lite/experimental/micro/kernels/all_ops_resolver.h" +#include "tensorflow/lite/experimental/micro/simple_tensor_allocator.h" +#include "tensorflow/lite/experimental/micro/testing/micro_test.h" +#include "tensorflow/lite/experimental/micro/testing/test_utils.h" + +namespace tflite { +namespace testing { +namespace { + +void TestConvFloat(std::initializer_list input_dims_data, + std::initializer_list input_data, + std::initializer_list filter_dims_data, + std::initializer_list filter_data, + std::initializer_list bias_dims_data, + std::initializer_list bias_data, + std::initializer_list output_dims_data, + std::initializer_list expected_output_data, + TfLiteFusedActivation activation, float* output_data) { + TfLiteIntArray* input_dims = IntArrayFromInitializer(input_dims_data); + TfLiteIntArray* filter_dims = IntArrayFromInitializer(filter_dims_data); + TfLiteIntArray* bias_dims = IntArrayFromInitializer(bias_dims_data); + TfLiteIntArray* output_dims = IntArrayFromInitializer(output_dims_data); + const int output_dims_count = ElementCount(*output_dims); + + ::tflite::ops::micro::AllOpsResolver resolver; + + constexpr int inputs_size = 3; + constexpr int outputs_size = 1; + constexpr int tensors_size = inputs_size + outputs_size; + TfLiteTensor tensors[tensors_size] = { + CreateFloatTensor(input_data, input_dims, "input_tensor"), + CreateFloatTensor(filter_data, filter_dims, "filter_tensor"), + CreateFloatTensor(bias_data, bias_dims, "bias_tensor"), + CreateFloatTensor(output_data, output_dims, "output_tensor"), + }; + + TfLiteContext context; + PopulateContext(tensors, tensors_size, &context); + + const TfLiteRegistration* registration = + resolver.FindOp(tflite::BuiltinOperator_CONV_2D, 1); + + TF_LITE_MICRO_EXPECT_NE(nullptr, registration); + + int input_depth = input_dims->data[3]; + int output_depth = output_dims->data[3]; + int depth_mul = output_depth / input_depth; + + TfLiteConvParams builtin_data = { + .padding = kTfLitePaddingValid, + .stride_width = 2, + .stride_height = 2, + .dilation_width_factor = 1, + .dilation_height_factor = 1, + .activation = kTfLiteActNone, + }; + + const char* init_data = reinterpret_cast(&builtin_data); + size_t init_data_size = 0; + void* user_data = nullptr; + + if (registration->init) { + user_data = registration->init(&context, init_data, init_data_size); + } + + 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); + int temporaries_array_data[] = {0}; + TfLiteIntArray* temporaries_array = IntArrayFromInts(temporaries_array_data); + + TfLiteNode node; + node.inputs = inputs_array; + node.outputs = outputs_array; + node.temporaries = temporaries_array; + node.user_data = user_data; + node.builtin_data = reinterpret_cast(&builtin_data); + node.custom_initial_data = nullptr; + node.custom_initial_data_size = 0; + node.delegate = 0; + + if (registration->prepare) { + TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, registration->prepare(&context, &node)); + } + TF_LITE_MICRO_EXPECT_NE(nullptr, registration->invoke); + TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, registration->invoke(&context, &node)); + + if (registration->free) { + registration->free(&context, user_data); + } + + for (int i = 0; i < output_dims_count; ++i) { + TF_LITE_MICRO_EXPECT_NEAR(expected_output_data.begin()[i], output_data[i], + 1e-5f); + } +} + +void TestConvQuantized( + std::initializer_list input_dims_data, + std::initializer_list input_data, float input_min, float input_max, + std::initializer_list filter_dims_data, + std::initializer_list filter_data, float filter_min, + float filter_max, std::initializer_list bias_dims_data, + std::initializer_list bias_data, float bias_min, float bias_max, + std::initializer_list output_dims_data, + std::initializer_list expected_output_data, float output_min, + float output_max, TfLiteFusedActivation activation, uint8_t* output_data) { + TfLiteIntArray* input_dims = IntArrayFromInitializer(input_dims_data); + TfLiteIntArray* filter_dims = IntArrayFromInitializer(filter_dims_data); + TfLiteIntArray* bias_dims = IntArrayFromInitializer(bias_dims_data); + TfLiteIntArray* output_dims = IntArrayFromInitializer(output_dims_data); + const int output_dims_count = ElementCount(*output_dims); + + ::tflite::ops::micro::AllOpsResolver resolver; + + const int intput_dims_count = ElementCount(*input_dims); + + constexpr int inputs_size = 3; + constexpr int outputs_size = 1; + constexpr int tensors_size = inputs_size + outputs_size; + TfLiteTensor tensors[tensors_size] = { + CreateQuantizedTensor(input_data, input_dims, "input_tensor", input_min, + input_max), + CreateQuantizedTensor(filter_data, filter_dims, "filter_tensor", + filter_min, filter_max), + CreateQuantized32Tensor(bias_data, bias_dims, "bias_tensor", bias_min, + bias_max), + CreateQuantizedTensor(output_data, output_dims, "output_tensor", + output_min, output_max), + }; + + TfLiteContext context; + PopulateContext(tensors, tensors_size, &context); + + const TfLiteRegistration* registration = + resolver.FindOp(tflite::BuiltinOperator_CONV_2D, 1); + + TF_LITE_MICRO_EXPECT_NE(nullptr, registration); + + int input_depth = input_dims->data[3]; + int output_depth = output_dims->data[3]; + int depth_mul = output_depth / input_depth; + + TfLiteConvParams builtin_data = { + .padding = kTfLitePaddingSame, + .stride_width = 2, + .stride_height = 2, + .dilation_width_factor = 1, + .dilation_height_factor = 1, + .activation = kTfLiteActNone, + }; + + const char* init_data = reinterpret_cast(&builtin_data); + size_t init_data_size = 0; + void* user_data = nullptr; + + if (registration->init) { + user_data = registration->init(&context, init_data, init_data_size); + } + + 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); + int temporaries_array_data[] = {0}; + TfLiteIntArray* temporaries_array = IntArrayFromInts(temporaries_array_data); + + TfLiteNode node; + node.inputs = inputs_array; + node.outputs = outputs_array; + node.temporaries = temporaries_array; + node.user_data = user_data; + node.builtin_data = reinterpret_cast(&builtin_data); + node.custom_initial_data = nullptr; + node.custom_initial_data_size = 0; + node.delegate = 0; + + if (registration->prepare) { + TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, registration->prepare(&context, &node)); + } + TF_LITE_MICRO_EXPECT_NE(nullptr, registration->invoke); + TF_LITE_MICRO_EXPECT_EQ(kTfLiteOk, registration->invoke(&context, &node)); + + if (registration->free) { + registration->free(&context, user_data); + } + + for (int i = 0; i < output_dims_count; ++i) { + TF_LITE_MICRO_EXPECT_EQ(expected_output_data.begin()[i], output_data[i]); + } +} + +} // namespace +} // namespace testing +} // namespace tflite + +TF_LITE_MICRO_TESTS_BEGIN + +TF_LITE_MICRO_TEST(SimpleTestFloat) { + const int output_dims_count = 12; + float output_data[output_dims_count]; + tflite::testing::TestConvFloat({4, 2, 2, 4, 1}, // Input shape + { + // Input values + // First batch + 1, 1, 1, 1, // row = 1 + 2, 2, 2, 2, // row = 2 + // Second batch + 1, 2, 3, 4, // row = 1 + 1, 2, 3, 4, // row = 2 + }, + {4, 3, 2, 2, 1}, // Filters shape + { + 1, 2, 3, 4, // first 2x2 filter + -1, 1, -1, 1, // second 2x2 filter + -1, -1, 1, 1, // third 2x2 filter + }, + {1, 3}, // Bias shape + {1, 2, 3}, // Bias values + {4, 2, 1, 2, 3}, // output dims + { + 18, 2, 5, // first batch, left + 18, 2, 5, // first batch, right + 17, 4, 3, // second batch, left + 37, 4, 3, // second batch, right + }, + kTfLiteActNone, output_data); +} + +TF_LITE_MICRO_TEST(InputAndFilterSameWidthHeight) { + const int output_dims_count(2); + float output_data[output_dims_count]; + + tflite::testing::TestConvFloat({4, 2, 2, 4, 1}, // Input shape + { + // Input values + // First batch + 1, 1, 1, 1, // row = 1 + 2, 2, 2, 2, // row = 2 + // Second batch + 1, 2, 3, 4, // row = 1 + 1, 2, 3, 4, // row = 2 + }, + {4, 1, 2, 4, 1}, // Filters shape + { + // Filters values + 1, 2, 3, 4, // row = 1 + -1, -1, 1, 1, // row = 2 + }, + {1, 1}, // Bias shape + {0}, // Bias values + {4, 2, 1, 1, 1}, // output dims + {10, 34}, // output + kTfLiteActNone, output_data); +} + +TF_LITE_MICRO_TEST(SimpleTestQuantized) { + using tflite::testing::F2Q; + using tflite::testing::F2Q32; + + const int output_dims_count = 12; + uint8_t output_data[output_dims_count]; + + const float input_min = -63.5; + const float input_max = 64; + const float filter_min = -63.5; + const float filter_max = 64; + const float bias_min = 0.0f; + const float bias_max = 64.0f * (1 << 24); + const float output_min = -127; + const float output_max = 128; + + tflite::testing::TestConvQuantized( + {4, 2, 2, 4, 1}, + { + F2Q(1, input_min, input_max), F2Q(1, input_min, input_max), + F2Q(1, input_min, input_max), F2Q(1, input_min, input_max), + F2Q(2, input_min, input_max), F2Q(2, input_min, input_max), + F2Q(2, input_min, input_max), F2Q(2, input_min, input_max), + F2Q(1, input_min, input_max), F2Q(2, input_min, input_max), + F2Q(3, input_min, input_max), F2Q(4, input_min, input_max), + F2Q(1, input_min, input_max), F2Q(2, input_min, input_max), + F2Q(3, input_min, input_max), F2Q(4, input_min, input_max), + }, + input_min, input_max, {4, 3, 2, 2, 1}, + { + F2Q(1, filter_min, filter_max), F2Q(2, filter_min, filter_max), + F2Q(3, filter_min, filter_max), F2Q(4, filter_min, filter_max), + F2Q(-1, filter_min, filter_max), F2Q(1, filter_min, filter_max), + F2Q(-1, filter_min, filter_max), F2Q(1, filter_min, filter_max), + F2Q(-1, filter_min, filter_max), F2Q(-1, filter_min, filter_max), + F2Q(1, filter_min, filter_max), F2Q(1, filter_min, filter_max), + }, + input_min, input_max, {1, 3}, + { + F2Q32(1, bias_min, bias_max), F2Q32(2, bias_min, bias_max), + F2Q32(3, bias_min, bias_max), + }, + bias_min, bias_max, {4, 2, 1, 2, 3}, + { + F2Q(18, output_min, output_max), F2Q(2, output_min, output_max), + F2Q(5, output_min, output_max), F2Q(18, output_min, output_max), + F2Q(2, output_min, output_max), F2Q(5, output_min, output_max), + F2Q(17, output_min, output_max), F2Q(4, output_min, output_max), + F2Q(3, output_min, output_max), F2Q(37, output_min, output_max), + F2Q(4, output_min, output_max), F2Q(3, output_min, output_max), + }, + output_min, output_max, kTfLiteActNone, output_data); +} + +TF_LITE_MICRO_TESTS_END From 812731d38d086e8d6192fbea0281957314bf552c Mon Sep 17 00:00:00 2001 From: Jens Elofsson Date: Wed, 3 Apr 2019 16:49:01 +0200 Subject: [PATCH 3/6] Add the conv kernel to the BUILD file. --- tensorflow/lite/experimental/micro/kernels/BUILD | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tensorflow/lite/experimental/micro/kernels/BUILD b/tensorflow/lite/experimental/micro/kernels/BUILD index 451eed28528fa5..3ae760ca1ed781 100644 --- a/tensorflow/lite/experimental/micro/kernels/BUILD +++ b/tensorflow/lite/experimental/micro/kernels/BUILD @@ -13,6 +13,7 @@ load( cc_library( name = "micro_ops", srcs = [ + "conv.cc", "depthwise_conv.cc", "fully_connected.cc", "softmax.cc", @@ -133,3 +134,16 @@ tflite_micro_cc_test( "//tensorflow/lite/experimental/micro/testing:micro_test", ], ) + +tflite_micro_cc_test( + name = "conv_test", + srcs = [ + "conv_test.cc", + ], + deps = [ + ":all_ops_resolver", + "//tensorflow/lite/c:c_api_internal", + "//tensorflow/lite/experimental/micro:micro_framework", + "//tensorflow/lite/experimental/micro/testing:micro_test", + ], +) From f201da5ecde677c74afe1ca326c5ca1648d0a5fa Mon Sep 17 00:00:00 2001 From: Jens Elofsson Date: Tue, 23 Apr 2019 13:37:01 +0200 Subject: [PATCH 4/6] Fix compile warnings and pass the correct parameter to TestConvQuantized. --- .../lite/experimental/micro/kernels/conv_test.cc | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/tensorflow/lite/experimental/micro/kernels/conv_test.cc b/tensorflow/lite/experimental/micro/kernels/conv_test.cc index 537c9e4dba827f..2818290288dd70 100644 --- a/tensorflow/lite/experimental/micro/kernels/conv_test.cc +++ b/tensorflow/lite/experimental/micro/kernels/conv_test.cc @@ -59,10 +59,6 @@ void TestConvFloat(std::initializer_list input_dims_data, TF_LITE_MICRO_EXPECT_NE(nullptr, registration); - int input_depth = input_dims->data[3]; - int output_depth = output_dims->data[3]; - int depth_mul = output_depth / input_depth; - TfLiteConvParams builtin_data = { .padding = kTfLitePaddingValid, .stride_width = 2, @@ -131,8 +127,6 @@ void TestConvQuantized( ::tflite::ops::micro::AllOpsResolver resolver; - const int intput_dims_count = ElementCount(*input_dims); - constexpr int inputs_size = 3; constexpr int outputs_size = 1; constexpr int tensors_size = inputs_size + outputs_size; @@ -155,10 +149,6 @@ void TestConvQuantized( TF_LITE_MICRO_EXPECT_NE(nullptr, registration); - int input_depth = input_dims->data[3]; - int output_depth = output_dims->data[3]; - int depth_mul = output_depth / input_depth; - TfLiteConvParams builtin_data = { .padding = kTfLitePaddingSame, .stride_width = 2, @@ -309,7 +299,7 @@ TF_LITE_MICRO_TEST(SimpleTestQuantized) { F2Q(-1, filter_min, filter_max), F2Q(-1, filter_min, filter_max), F2Q(1, filter_min, filter_max), F2Q(1, filter_min, filter_max), }, - input_min, input_max, {1, 3}, + filter_min, filter_max, {1, 3}, { F2Q32(1, bias_min, bias_max), F2Q32(2, bias_min, bias_max), F2Q32(3, bias_min, bias_max), From b486d3d2ab82487fc0cf4e86dab90adae2f3f249 Mon Sep 17 00:00:00 2001 From: Jens Elofsson Date: Mon, 6 May 2019 09:09:55 +0200 Subject: [PATCH 5/6] Add conv.cc to portable_optimized_micro_ops. --- tensorflow/lite/experimental/micro/kernels/BUILD | 1 + 1 file changed, 1 insertion(+) diff --git a/tensorflow/lite/experimental/micro/kernels/BUILD b/tensorflow/lite/experimental/micro/kernels/BUILD index e9508077f41dcc..d864b82b88a3b7 100644 --- a/tensorflow/lite/experimental/micro/kernels/BUILD +++ b/tensorflow/lite/experimental/micro/kernels/BUILD @@ -54,6 +54,7 @@ cc_library( "fully_connected.cc", "pooling.cc", "portable_optimized/depthwise_conv.cc", + "conv.cc", "softmax.cc", ], hdrs = [ From 8e56e4a4a149c042d4f67bb168fc18e190aa71ed Mon Sep 17 00:00:00 2001 From: Jens Elofsson Date: Tue, 7 May 2019 16:35:05 +0200 Subject: [PATCH 6/6] Correct BUILD file with buildifier. --- tensorflow/lite/experimental/micro/kernels/BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tensorflow/lite/experimental/micro/kernels/BUILD b/tensorflow/lite/experimental/micro/kernels/BUILD index d864b82b88a3b7..1ff15e9abf0b34 100644 --- a/tensorflow/lite/experimental/micro/kernels/BUILD +++ b/tensorflow/lite/experimental/micro/kernels/BUILD @@ -51,10 +51,10 @@ cc_library( cc_library( name = "portable_optimized_micro_ops", srcs = [ + "conv.cc", "fully_connected.cc", "pooling.cc", "portable_optimized/depthwise_conv.cc", - "conv.cc", "softmax.cc", ], hdrs = [