Add LeakyRelu kernel for Kelvin - LeakyRelu kernel, which supports float32, int8, int16. int8 and int16 are implemented using Kelvin's vector instruction set. Change-Id: Ica7879102ddd728343f0f5c7c4942d79509d4d77
diff --git a/tensorflow/lite/micro/kernels/kelvin/leaky_relu.cc b/tensorflow/lite/micro/kernels/kelvin/leaky_relu.cc new file mode 100644 index 0000000..25a8853 --- /dev/null +++ b/tensorflow/lite/micro/kernels/kelvin/leaky_relu.cc
@@ -0,0 +1,82 @@ +// Copyright 2023 Google LLC +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 + +#include "tensorflow/lite/kernels/internal/reference/leaky_relu.h" + +#include "tensorflow/lite/c/common.h" +#include "tensorflow/lite/micro/kernels/kernel_util.h" +#include "tensorflow/lite/micro/kernels/leaky_relu.h" +#include "tensorflow/lite/micro/micro_log.h" +#include "tflm/opt/opt.h" + +namespace tflite { + +namespace { +void* LeakyReluInit(TfLiteContext* context, const char* buffer, size_t length) { + TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr); + return context->AllocatePersistentBuffer(context, sizeof(LeakyReluOpData)); +} + +TfLiteStatus LeakyReluEval(TfLiteContext* context, TfLiteNode* node) { + const TfLiteEvalTensor* input = + tflite::micro::GetEvalInput(context, node, kInputTensor); + TfLiteEvalTensor* output = + tflite::micro::GetEvalOutput(context, node, kOutputTensor); + const LeakyReluOpData& data = *static_cast<LeakyReluOpData*>(node->user_data); + + // Kelvin's vector ISA is used to implement Int8 and Int16. + // Float32 uses the reference op. + switch (input->type) { + case kTfLiteFloat32: { + LeakyReluParams op_params = {}; + const auto* params = + static_cast<TfLiteLeakyReluParams*>(node->builtin_data); + + op_params.alpha = params->alpha; + reference_ops::LeakyRelu(op_params, tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorData<float>(input), + tflite::micro::GetTensorShape(output), + tflite::micro::GetTensorData<float>(output)); + return kTfLiteOk; + } break; + case kTfLiteInt8: { + kelvin::opt::leaky_relu_s8( + tflite::micro::GetTensorData<int8_t>(input), + tflite::micro::GetTensorData<int8_t>(output), + MatchingFlatSize(tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorShape(output)), + data.input_zero_point, data.output_zero_point, + data.output_multiplier_alpha, data.output_shift_alpha, + data.output_multiplier_identity, data.output_shift_identity); + return kTfLiteOk; + } break; + case kTfLiteInt16: { + kelvin::opt::leaky_relu_s16( + tflite::micro::GetTensorData<int16_t>(input), + tflite::micro::GetTensorData<int16_t>(output), + MatchingFlatSize(tflite::micro::GetTensorShape(input), + tflite::micro::GetTensorShape(output)), + data.input_zero_point, data.output_zero_point, + data.output_multiplier_alpha, data.output_shift_alpha, + data.output_multiplier_identity, data.output_shift_identity); + return kTfLiteOk; + } break; + default: + MicroPrintf( + "Only float32, int8, int16 are supported by LEAKY_RELU, got %s.", + TfLiteTypeGetName(input->type)); + return kTfLiteError; + } + + return kTfLiteError; +} + +} // namespace + +TFLMRegistration Register_LEAKY_RELU() { + return tflite::micro::RegisterOp(LeakyReluInit, LeakyReluPrepare, + LeakyReluEval); +} + +} // namespace tflite