1 /* Copyright 2019 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15
16 #include "tensorflow/lite/kernels/internal/reference/hard_swish.h"
17
18 #include "tensorflow/lite/c/builtin_op_data.h"
19 #include "tensorflow/lite/c/common.h"
20 #include "tensorflow/lite/kernels/internal/common.h"
21 #include "tensorflow/lite/kernels/internal/quantization_util.h"
22 #include "tensorflow/lite/kernels/internal/tensor_ctypes.h"
23 #include "tensorflow/lite/kernels/internal/types.h"
24 #include "tensorflow/lite/kernels/kernel_util.h"
25 #include "tensorflow/lite/kernels/op_macros.h"
26 #include "tensorflow/lite/micro/kernels/kernel_util.h"
27 #include "tensorflow/lite/micro/micro_utils.h"
28
29 namespace tflite {
30 namespace ops {
31 namespace micro {
32 namespace hard_swish {
33
34 constexpr int kInputTensor = 0;
35 constexpr int kOutputTensor = 0;
36
HardSwishInit(TfLiteContext * context,const char * buffer,size_t length)37 void* HardSwishInit(TfLiteContext* context, const char* buffer, size_t length) {
38 TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr);
39 return context->AllocatePersistentBuffer(context, sizeof(HardSwishParams));
40 }
41
HardSwishPrepare(TfLiteContext * context,TfLiteNode * node)42 TfLiteStatus HardSwishPrepare(TfLiteContext* context, TfLiteNode* node) {
43 TFLITE_DCHECK(node->user_data != nullptr);
44 TF_LITE_ENSURE_EQ(context, NumInputs(node), 1);
45 TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1);
46
47 const TfLiteTensor* input = GetInput(context, node, kInputTensor);
48 TF_LITE_ENSURE(context, input != nullptr);
49 TfLiteTensor* output = GetOutput(context, node, kOutputTensor);
50 TF_LITE_ENSURE(context, output != nullptr);
51
52 if (input->type == kTfLiteUInt8 || input->type == kTfLiteInt8) {
53 HardSwishParams* params = static_cast<HardSwishParams*>(node->user_data);
54
55 params->input_zero_point = input->params.zero_point;
56 params->output_zero_point = output->params.zero_point;
57
58 const float input_scale = input->params.scale;
59 const float hires_input_scale = (1.0f / 128.0f) * input_scale;
60 const float reluish_scale = 3.0f / 32768.0f;
61 const float output_scale = output->params.scale;
62
63 const double output_multiplier =
64 static_cast<double>(hires_input_scale / output_scale);
65 int32_t output_multiplier_fixedpoint_int32;
66 QuantizeMultiplier(output_multiplier, &output_multiplier_fixedpoint_int32,
67 ¶ms->output_multiplier_exponent);
68 DownScaleInt32ToInt16Multiplier(
69 output_multiplier_fixedpoint_int32,
70 ¶ms->output_multiplier_fixedpoint_int16);
71
72 TF_LITE_ENSURE(context, params->output_multiplier_exponent <= 0);
73
74 const double reluish_multiplier =
75 static_cast<double>(hires_input_scale / reluish_scale);
76 int32_t reluish_multiplier_fixedpoint_int32;
77 QuantizeMultiplier(reluish_multiplier, &reluish_multiplier_fixedpoint_int32,
78 ¶ms->reluish_multiplier_exponent);
79 DownScaleInt32ToInt16Multiplier(
80 reluish_multiplier_fixedpoint_int32,
81 ¶ms->reluish_multiplier_fixedpoint_int16);
82 }
83
84 return kTfLiteOk;
85 }
86
HardSwishEval(TfLiteContext * context,TfLiteNode * node)87 TfLiteStatus HardSwishEval(TfLiteContext* context, TfLiteNode* node) {
88 const TfLiteEvalTensor* input =
89 tflite::micro::GetEvalInput(context, node, kInputTensor);
90 TfLiteEvalTensor* output =
91 tflite::micro::GetEvalOutput(context, node, kOutputTensor);
92 HardSwishParams* params = static_cast<HardSwishParams*>(node->user_data);
93
94 switch (input->type) {
95 case kTfLiteFloat32: {
96 tflite::reference_ops::HardSwish<float>(
97 tflite::micro::GetTensorShape(input),
98 tflite::micro::GetTensorData<float>(input),
99 tflite::micro::GetTensorShape(output),
100 tflite::micro::GetTensorData<float>(output));
101 } break;
102 case kTfLiteUInt8: {
103 tflite::reference_ops::HardSwish<uint8_t>(
104 *params, tflite::micro::GetTensorShape(input),
105 tflite::micro::GetTensorData<uint8_t>(input),
106 tflite::micro::GetTensorShape(output),
107 tflite::micro::GetTensorData<uint8_t>(output));
108 } break;
109 case kTfLiteInt8: {
110 tflite::reference_ops::HardSwish<int8_t>(
111 *params, tflite::micro::GetTensorShape(input),
112 tflite::micro::GetTensorData<int8_t>(input),
113 tflite::micro::GetTensorShape(output),
114 tflite::micro::GetTensorData<int8_t>(output));
115 } break;
116 default: {
117 TF_LITE_KERNEL_LOG(
118 context,
119 "Only float32/int8_t/uint8_t are supported currently, got %s",
120 TfLiteTypeGetName(input->type));
121 return kTfLiteError;
122 }
123 }
124 return kTfLiteOk;
125 }
126
127 } // namespace hard_swish
128
Register_HARD_SWISH()129 TfLiteRegistration Register_HARD_SWISH() {
130 return {/*init=*/hard_swish::HardSwishInit,
131 /*free=*/nullptr,
132 /*prepare=*/hard_swish::HardSwishPrepare,
133 /*invoke=*/hard_swish::HardSwishEval,
134 /*profiling_string=*/nullptr,
135 /*builtin_code=*/0,
136 /*custom_name=*/nullptr,
137 /*version=*/0};
138 }
139
140 } // namespace micro
141 } // namespace ops
142 } // namespace tflite
143