| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include "edge-impulse-sdk/tensorflow/lite/kernels/internal/reference/arg_min_max.h" |
|
|
| #include "edge-impulse-sdk/tensorflow/lite/c/builtin_op_data.h" |
| #include "edge-impulse-sdk/tensorflow/lite/c/common.h" |
| #include "edge-impulse-sdk/tensorflow/lite/kernels/internal/reference/comparisons.h" |
| #include "edge-impulse-sdk/tensorflow/lite/kernels/internal/tensor_ctypes.h" |
| #include "edge-impulse-sdk/tensorflow/lite/kernels/kernel_util.h" |
| #include "edge-impulse-sdk/tensorflow/lite/micro/kernels/kernel_util.h" |
| #include "edge-impulse-sdk/tensorflow/lite/micro/micro_log.h" |
|
|
| namespace tflite { |
|
|
| namespace { |
|
|
| constexpr int kInputTensor = 0; |
| constexpr int kAxis = 1; |
| constexpr int kOutputTensor = 0; |
|
|
| template <typename T1, typename T2, typename T3> |
| inline void ArgMinMaxHelper(const RuntimeShape& input1_shape, |
| const T1* input1_data, const T3* input2_data, |
| const RuntimeShape& output_shape, T2* output_data, |
| bool is_arg_max) { |
| |
| |
| |
| if (is_arg_max) { |
| reference_ops::ArgMinMax(input1_shape, input1_data, input2_data, |
| output_shape, output_data, |
| reference_ops::GreaterFn<T1>); |
| } else { |
| reference_ops::ArgMinMax(input1_shape, input1_data, input2_data, |
| output_shape, output_data, |
| reference_ops::LessFn<T1>); |
| } |
| } |
|
|
| TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node, bool is_arg_max) { |
| const TfLiteEvalTensor* input = |
| tflite::micro::GetEvalInput(context, node, kInputTensor); |
| const TfLiteEvalTensor* axis = |
| tflite::micro::GetEvalInput(context, node, kAxis); |
| TfLiteEvalTensor* output = |
| tflite::micro::GetEvalOutput(context, node, kOutputTensor); |
|
|
| #define TF_LITE_ARG_MIN_MAX(data_type, axis_type, output_type) \ |
| ArgMinMaxHelper(tflite::micro::GetTensorShape(input), \ |
| tflite::micro::GetTensorData<data_type>(input), \ |
| tflite::micro::GetTensorData<axis_type>(axis), \ |
| tflite::micro::GetTensorShape(output), \ |
| tflite::micro::GetTensorData<output_type>(output), \ |
| is_arg_max) |
| if (axis->type == kTfLiteInt32) { |
| if (output->type == kTfLiteInt32) { |
| switch (input->type) { |
| case kTfLiteFloat32: |
| TF_LITE_ARG_MIN_MAX(float, int32_t, int32_t); |
| break; |
| case kTfLiteInt8: |
| TF_LITE_ARG_MIN_MAX(int8_t, int32_t, int32_t); |
| break; |
| case kTfLiteInt32: |
| TF_LITE_ARG_MIN_MAX(int32_t, int32_t, int32_t); |
| break; |
| default: |
| MicroPrintf( |
| "Only float32, uint8_t and int8_t are " |
| "supported currently, got %s.", |
| TfLiteTypeGetName(input->type)); |
| return kTfLiteError; |
| } |
| } else { |
| MicroPrintf("Only int32_t are supported currently, got %s.", |
| TfLiteTypeGetName(output->type)); |
| return kTfLiteError; |
| } |
| } else { |
| MicroPrintf("Only int32_t are supported currently, got %s.", |
| TfLiteTypeGetName(axis->type)); |
| return kTfLiteError; |
| } |
|
|
| #undef TF_LITE_ARG_MIN_MAX |
|
|
| return kTfLiteOk; |
| } |
|
|
| TfLiteStatus ArgMinEval(TfLiteContext* context, TfLiteNode* node) { |
| return Eval(context, node, false); |
| } |
|
|
| TfLiteStatus ArgMaxEval(TfLiteContext* context, TfLiteNode* node) { |
| return Eval(context, node, true); |
| } |
|
|
| } |
|
|
| TfLiteRegistration Register_ARG_MAX() { |
| return tflite::micro::RegisterOp(nullptr, nullptr, ArgMaxEval); |
| } |
|
|
| TfLiteRegistration Register_ARG_MIN() { |
| return tflite::micro::RegisterOp(nullptr, nullptr, ArgMinEval); |
| } |
|
|
| } |
|
|