• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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