From b13e49836a92241d653e96225552bd8df3bfd92e Mon Sep 17 00:00:00 2001 From: Advait Jain Date: Wed, 7 Oct 2020 13:37:00 -0700 Subject: [PATCH] Switch TFLM Conv2D kernels to flat namespace. This is incremental progress towards a flat namespace for TFLM. See https://abseil.io/tips/130 for more context. Best effort change to the arc_mli implementation. All the others (reference, cmsis-nn and xtensa_hifimini build). PiperOrigin-RevId: 335942662 Change-Id: I97271a681f46337a7c49f3fdf89ae73567b2ed7d --- tensorflow/lite/micro/kernels/arc_mli/conv.cc | 14 +-- .../lite/micro/kernels/cmsis-nn/conv.cc | 14 +-- tensorflow/lite/micro/kernels/conv.cc | 14 +-- tensorflow/lite/micro/kernels/conv_test.cc | 3 +- tensorflow/lite/micro/kernels/micro_ops.h | 2 +- .../micro/kernels/xtensa_hifimini/conv.cc | 106 ++++++++---------- .../lite/micro/micro_mutable_op_resolver.h | 4 +- 7 files changed, 66 insertions(+), 91 deletions(-) diff --git a/tensorflow/lite/micro/kernels/arc_mli/conv.cc b/tensorflow/lite/micro/kernels/arc_mli/conv.cc index 2bdbe679087..55ef2650bef 100644 --- a/tensorflow/lite/micro/kernels/arc_mli/conv.cc +++ b/tensorflow/lite/micro/kernels/arc_mli/conv.cc @@ -30,9 +30,7 @@ limitations under the License. #include "tensorflow/lite/micro/kernels/arc_mli/scratch_buffers.h" namespace tflite { -namespace ops { -namespace micro { -namespace conv { +namespace { constexpr int kInputTensor = 0; constexpr int kFilterTensor = 1; @@ -498,19 +496,17 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { return kTfLiteOk; } -} // namespace conv +} // namespace TfLiteRegistration Register_CONV_2D() { - return {/*init=*/conv::Init, + return {/*init=*/Init, /*free=*/nullptr, - /*prepare=*/conv::Prepare, - /*invoke=*/conv::Eval, + /*prepare=*/Prepare, + /*invoke=*/Eval, /*profiling_string=*/nullptr, /*builtin_code=*/0, /*custom_name=*/nullptr, /*version=*/0}; } -} // namespace micro -} // namespace ops } // namespace tflite diff --git a/tensorflow/lite/micro/kernels/cmsis-nn/conv.cc b/tensorflow/lite/micro/kernels/cmsis-nn/conv.cc index 143a9f2566f..80a0a2ae748 100644 --- a/tensorflow/lite/micro/kernels/cmsis-nn/conv.cc +++ b/tensorflow/lite/micro/kernels/cmsis-nn/conv.cc @@ -28,9 +28,7 @@ limitations under the License. #include "tensorflow/lite/micro/kernels/kernel_util.h" namespace tflite { -namespace ops { -namespace micro { -namespace conv { +namespace { constexpr int kInputTensor = 0; constexpr int kFilterTensor = 1; @@ -442,19 +440,17 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { return kTfLiteOk; } -} // namespace conv +} // namespace TfLiteRegistration Register_CONV_2D() { - return {/*init=*/conv::Init, + return {/*init=*/Init, /*free=*/nullptr, - /*prepare=*/conv::Prepare, - /*invoke=*/conv::Eval, + /*prepare=*/Prepare, + /*invoke=*/Eval, /*profiling_string=*/nullptr, /*builtin_code=*/0, /*custom_name=*/nullptr, /*version=*/0}; } -} // namespace micro -} // namespace ops } // namespace tflite diff --git a/tensorflow/lite/micro/kernels/conv.cc b/tensorflow/lite/micro/kernels/conv.cc index 180fe6b3223..9b1b1148176 100644 --- a/tensorflow/lite/micro/kernels/conv.cc +++ b/tensorflow/lite/micro/kernels/conv.cc @@ -26,9 +26,7 @@ limitations under the License. #include "tensorflow/lite/micro/kernels/kernel_util.h" namespace tflite { -namespace ops { -namespace micro { -namespace conv { +namespace { constexpr int kInputTensor = 0; constexpr int kFilterTensor = 1; @@ -322,19 +320,17 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { return kTfLiteOk; } -} // namespace conv +} // namespace TfLiteRegistration Register_CONV_2D() { - return {/*init=*/conv::Init, + return {/*init=*/Init, /*free=*/nullptr, - /*prepare=*/conv::Prepare, - /*invoke=*/conv::Eval, + /*prepare=*/Prepare, + /*invoke=*/Eval, /*profiling_string=*/nullptr, /*builtin_code=*/0, /*custom_name=*/nullptr, /*version=*/0}; } -} // namespace micro -} // namespace ops } // namespace tflite diff --git a/tensorflow/lite/micro/kernels/conv_test.cc b/tensorflow/lite/micro/kernels/conv_test.cc index be646d63659..b2c85cc2c57 100644 --- a/tensorflow/lite/micro/kernels/conv_test.cc +++ b/tensorflow/lite/micro/kernels/conv_test.cc @@ -59,8 +59,7 @@ TfLiteStatus ValidateConvGoldens(TfLiteTensor* tensors, int tensors_size, int outputs_array_data[] = {1, 3}; TfLiteIntArray* outputs_array = IntArrayFromInts(outputs_array_data); - const TfLiteRegistration registration = - tflite::ops::micro::Register_CONV_2D(); + const TfLiteRegistration registration = Register_CONV_2D(); micro::KernelRunner runner( registration, tensors, tensors_size, inputs_array, outputs_array, reinterpret_cast(conv_params), micro_test::reporter); diff --git a/tensorflow/lite/micro/kernels/micro_ops.h b/tensorflow/lite/micro/kernels/micro_ops.h index eb413355837..b21a12109b3 100644 --- a/tensorflow/lite/micro/kernels/micro_ops.h +++ b/tensorflow/lite/micro/kernels/micro_ops.h @@ -31,6 +31,7 @@ namespace tflite { // (https://abseil.io/tips/130). Any new ops (or cleanup of existing ops should // have their Register function declarations in the tflite namespace. +TfLiteRegistration Register_CONV_2D(); TfLiteRegistration Register_SHAPE(); namespace ops { @@ -44,7 +45,6 @@ TfLiteRegistration Register_AVERAGE_POOL_2D(); TfLiteRegistration Register_CEIL(); // TODO(b/160234179): Change custom OPs to also return by value. TfLiteRegistration* Register_CIRCULAR_BUFFER(); -TfLiteRegistration Register_CONV_2D(); TfLiteRegistration Register_CONCATENATION(); TfLiteRegistration Register_COS(); TfLiteRegistration Register_DEPTHWISE_CONV_2D(); diff --git a/tensorflow/lite/micro/kernels/xtensa_hifimini/conv.cc b/tensorflow/lite/micro/kernels/xtensa_hifimini/conv.cc index 273a2fad583..b9f7c8a0f43 100644 --- a/tensorflow/lite/micro/kernels/xtensa_hifimini/conv.cc +++ b/tensorflow/lite/micro/kernels/xtensa_hifimini/conv.cc @@ -28,11 +28,37 @@ limitations under the License. #include "tensorflow/lite/micro/kernels/xtensa_hifimini/fixedpoint_utils.h" namespace tflite { -namespace ops { -namespace micro { -namespace conv { -namespace xtensa { -namespace hifimini { +namespace { + +constexpr int kInputTensor = 0; +constexpr int kFilterTensor = 1; +constexpr int kBiasTensor = 2; +constexpr int kOutputTensor = 0; + +// Conv is quantized along dimension 0: +// https://www.tensorflow.org/lite/performance/quantization_spec +constexpr int kConvQuantizedDimension = 0; + +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; + + // Cached tensor zero point values for quantized operations. + int32_t input_zero_point; + int32_t output_zero_point; + + // Per channel output multiplier and shift. + int32_t* per_channel_output_multiplier; + int32_t* per_channel_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; +}; void ConvPerChannel(const ConvParams& params, const int32_t* output_multiplier, const int32_t* output_shift, @@ -146,7 +172,7 @@ void ConvPerChannel(const ConvParams& params, const int32_t* output_multiplier, // Apply quantized multiplier and accumulate result at 48bit // alignment: - acc_56 = micro::xtensa::hifimini::MultiplyByQuantizedMultiplier( + acc_56 = ops::micro::xtensa::hifimini::MultiplyByQuantizedMultiplier( acc_24x2, output_multiplier[out_channel], output_shift[out_channel]); @@ -223,7 +249,7 @@ inline void Conv1x32Input32x32Filter( // Apply quantized multiplier and accumulate result at 48bit alignment. // Convert the (unsigned) 32-bit multiplier down to a 24-bit multiplier. - acc_56 = micro::xtensa::hifimini::MultiplyByQuantizedMultiplier( + acc_56 = ops::micro::xtensa::hifimini::MultiplyByQuantizedMultiplier( acc_24x2, output_multiplier[ch] >> 8, output_shift[ch]); // Add output offset, cap activation, and assign to the output: @@ -235,39 +261,6 @@ inline void Conv1x32Input32x32Filter( } } -} // namespace hifimini -} // namespace xtensa - -constexpr int kInputTensor = 0; -constexpr int kFilterTensor = 1; -constexpr int kBiasTensor = 2; -constexpr int kOutputTensor = 0; - -// Conv is quantized along dimension 0: -// https://www.tensorflow.org/lite/performance/quantization_spec -constexpr int kConvQuantizedDimension = 0; - -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; - - // Cached tensor zero point values for quantized operations. - int32_t input_zero_point; - int32_t output_zero_point; - - // Per channel output multiplier and shift. - int32_t* per_channel_output_multiplier; - int32_t* per_channel_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; -}; - TfLiteStatus CalculateOpData(TfLiteContext* context, TfLiteNode* node, TfLiteConvParams* params, int width, int height, int filter_width, int filter_height, int out_width, @@ -386,16 +379,16 @@ void EvalQuantizedPerChannel(TfLiteContext* context, TfLiteNode* node, op_params.quantized_activation_min = data->output_activation_min; op_params.quantized_activation_max = data->output_activation_max; - xtensa::hifimini::ConvPerChannel( - op_params, data->per_channel_output_multiplier, - data->per_channel_output_shift, tflite::micro::GetTensorShape(input), - tflite::micro::GetTensorData(input), - tflite::micro::GetTensorShape(filter), - tflite::micro::GetTensorData(filter), - tflite::micro::GetTensorShape(bias), - tflite::micro::GetTensorData(bias), - tflite::micro::GetTensorShape(output), - tflite::micro::GetTensorData(output)); + ConvPerChannel(op_params, data->per_channel_output_multiplier, + data->per_channel_output_shift, + tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData(input), + tflite::micro::GetTensorShape(filter), + tflite::micro::GetTensorData(filter), + tflite::micro::GetTensorShape(bias), + tflite::micro::GetTensorData(bias), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData(output)); } TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { @@ -420,7 +413,7 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { if (input_dims[0] == 1 && input_dims[1] == 1 && input_dims[2] == 1 && input_dims[3] == 32 && filter_dims[0] == 32 && filter_dims[1] == 1 && filter_dims[2] == 1 && filter_dims[3] == 32) { - xtensa::hifimini::Conv1x32Input32x32Filter( + Conv1x32Input32x32Filter( -op_data->input_zero_point, op_data->output_zero_point, op_data->output_activation_min, op_data->output_activation_max, op_data->per_channel_output_multiplier, @@ -447,20 +440,17 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) { } return kTfLiteOk; } - -} // namespace conv +} // namespace TfLiteRegistration Register_CONV_2D() { - return {/*init=*/conv::Init, + return {/*init=*/Init, /*free=*/nullptr, - /*prepare=*/conv::Prepare, - /*invoke=*/conv::Eval, + /*prepare=*/Prepare, + /*invoke=*/Eval, /*profiling_string=*/nullptr, /*builtin_code=*/0, /*custom_name=*/nullptr, /*version=*/0}; } -} // namespace micro -} // namespace ops } // namespace tflite diff --git a/tensorflow/lite/micro/micro_mutable_op_resolver.h b/tensorflow/lite/micro/micro_mutable_op_resolver.h index 84fb7e81a51..c8475aadd19 100644 --- a/tensorflow/lite/micro/micro_mutable_op_resolver.h +++ b/tensorflow/lite/micro/micro_mutable_op_resolver.h @@ -150,8 +150,7 @@ class MicroMutableOpResolver : public MicroOpResolver { } TfLiteStatus AddConv2D() { - return AddBuiltin(BuiltinOperator_CONV_2D, - tflite::ops::micro::Register_CONV_2D(), ParseConv2D); + return AddBuiltin(BuiltinOperator_CONV_2D, Register_CONV_2D(), ParseConv2D); } TfLiteStatus AddCos() { @@ -465,7 +464,6 @@ class MicroMutableOpResolver : public MicroOpResolver { unsigned int num_buitin_ops_ = 0; ErrorReporter* error_reporter_; - }; }; // namespace tflite