1 /* Copyright 2018 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/maximum_minimum.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/kernel_util.h"
24 #include "tensorflow/lite/kernels/op_macros.h"
25 #include "tensorflow/lite/micro/kernels/kernel_util.h"
26
27 namespace tflite {
28 namespace ops {
29 namespace micro {
30 namespace maximum_minimum {
31 namespace {
32
33 // This file has a reference implementation of TFMaximum/TFMinimum.
34 enum KernelType {
35 kReference,
36 };
37
38 constexpr int kInputTensor1 = 0;
39 constexpr int kInputTensor2 = 1;
40 constexpr int kOutputTensor = 0;
41
42 struct OpContext {
OpContexttflite::ops::micro::maximum_minimum::__anon10e62ed20111::OpContext43 OpContext(TfLiteContext* context, TfLiteNode* node) {
44 input1 = tflite::micro::GetEvalInput(context, node, kInputTensor1);
45 input2 = tflite::micro::GetEvalInput(context, node, kInputTensor2);
46 output = tflite::micro::GetEvalOutput(context, node, kOutputTensor);
47 }
48 const TfLiteEvalTensor* input1;
49 const TfLiteEvalTensor* input2;
50 TfLiteEvalTensor* output;
51 };
52
53 struct MaximumOp {
54 template <typename data_type>
optflite::ops::micro::maximum_minimum::__anon10e62ed20111::MaximumOp55 static data_type op(data_type el1, data_type el2) {
56 return el1 > el2 ? el1 : el2;
57 }
58 };
59
60 struct MinimumOp {
61 template <typename data_type>
optflite::ops::micro::maximum_minimum::__anon10e62ed20111::MinimumOp62 static data_type op(data_type el1, data_type el2) {
63 return el1 < el2 ? el1 : el2;
64 }
65 };
66
67 } // namespace
68
69 template <typename data_type, typename op_type>
TFLiteOperation(TfLiteContext * context,TfLiteNode * node,const OpContext & op_context)70 void TFLiteOperation(TfLiteContext* context, TfLiteNode* node,
71 const OpContext& op_context) {
72 reference_ops::MaximumMinimumBroadcastSlow(
73 tflite::micro::GetTensorShape(op_context.input1),
74 tflite::micro::GetTensorData<data_type>(op_context.input1),
75 tflite::micro::GetTensorShape(op_context.input2),
76 tflite::micro::GetTensorData<data_type>(op_context.input2),
77 tflite::micro::GetTensorShape(op_context.output),
78 tflite::micro::GetTensorData<data_type>(op_context.output),
79 op_type::template op<data_type>);
80 }
81
82 template <KernelType kernel_type, typename OpType>
Eval(TfLiteContext * context,TfLiteNode * node)83 TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
84 OpContext op_context(context, node);
85
86 if (kernel_type == kReference) {
87 switch (op_context.output->type) {
88 case kTfLiteFloat32:
89 TFLiteOperation<float, OpType>(context, node, op_context);
90 break;
91 case kTfLiteUInt8:
92 TFLiteOperation<uint8_t, OpType>(context, node, op_context);
93 break;
94 case kTfLiteInt8:
95 TFLiteOperation<int8_t, OpType>(context, node, op_context);
96 break;
97 case kTfLiteInt32:
98 TFLiteOperation<int32_t, OpType>(context, node, op_context);
99 break;
100 case kTfLiteInt64:
101 TFLiteOperation<int64_t, OpType>(context, node, op_context);
102 break;
103 default:
104 TF_LITE_KERNEL_LOG(context,
105 "Type %s (%d) is not supported by Maximum/Minimum.",
106 TfLiteTypeGetName(op_context.output->type),
107 op_context.output->type);
108 return kTfLiteError;
109 }
110 } else {
111 TF_LITE_KERNEL_LOG(context,
112 "Kernel type not supported by Maximum/Minimum.");
113 return kTfLiteError;
114 }
115 return kTfLiteOk;
116 }
117
118 } // namespace maximum_minimum
119
Register_MAXIMUM()120 TfLiteRegistration Register_MAXIMUM() {
121 return {/*init=*/nullptr,
122 /*free=*/nullptr,
123 /*prepare=*/nullptr,
124 /*invoke=*/
125 maximum_minimum::Eval<maximum_minimum::kReference,
126 maximum_minimum::MaximumOp>,
127 /*profiling_string=*/nullptr,
128 /*builtin_code=*/0,
129 /*custom_name=*/nullptr,
130 /*version=*/0};
131 }
132
Register_MINIMUM()133 TfLiteRegistration Register_MINIMUM() {
134 return {/*init=*/nullptr,
135 /*free=*/nullptr,
136 /*prepare=*/nullptr,
137 /*invoke=*/
138 maximum_minimum::Eval<maximum_minimum::kReference,
139 maximum_minimum::MinimumOp>,
140 /*profiling_string=*/nullptr,
141 /*builtin_code=*/0,
142 /*custom_name=*/nullptr,
143 /*version=*/0};
144 }
145
146 } // namespace micro
147 } // namespace ops
148 } // namespace tflite
149