1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 // Contains the implementation of the operations.
18
19 #define LOG_TAG "Operations"
20
21 #include "Operations.h"
22 #include "OperationsUtils.h"
23
24 #include "internal/optimized/optimized_ops.h"
25
26 namespace android {
27 namespace nn {
addFloat32(const float * in1,const Shape & shape1,const float * in2,const Shape & shape2,int32_t activation,float * out,const Shape & shapeOut)28 bool addFloat32(const float* in1, const Shape& shape1,
29 const float* in2, const Shape& shape2,
30 int32_t activation,
31 float* out, const Shape& shapeOut) {
32 bool needBroadcast = !SameShape(shape1, shape2);
33
34 #define ANDROID_NN_NORMAL_ADD(activation) \
35 optimized_ops::Add<FusedActivationFunctionType::activation>( \
36 in1, convertShapeToDims(shape1), \
37 in2, convertShapeToDims(shape2), \
38 out, convertShapeToDims(shapeOut))
39
40 #define ANDROID_NN_BROADCAST_ADD(activation) \
41 optimized_ops::BroadcastAdd<FusedActivationFunctionType::activation>( \
42 in1, convertShapeToDims(shape1), \
43 in2, convertShapeToDims(shape2), \
44 out, convertShapeToDims(shapeOut))
45
46 if (needBroadcast) {
47 ANDROID_NN_MACRO_DISPATCH(ANDROID_NN_BROADCAST_ADD)
48 } else {
49 ANDROID_NN_MACRO_DISPATCH(ANDROID_NN_NORMAL_ADD)
50 }
51
52 #undef ANDROID_NN_NORMAL_ADD
53 #undef ANDROID_NN_BROADCAST_ADD
54 return true;
55 }
56
addQuant8(const uint8_t * in1,const Shape & shape1,const uint8_t * in2,const Shape & shape2,int32_t activation,uint8_t * out,const Shape & shapeOut)57 bool addQuant8(const uint8_t* in1, const Shape& shape1,
58 const uint8_t* in2, const Shape& shape2,
59 int32_t activation,
60 uint8_t* out, const Shape& shapeOut) {
61 bool needBroadcast = !SameShape(shape1, shape2);
62
63 const int32_t input1_offset = -shape1.offset;
64 const int32_t input2_offset = -shape2.offset;
65 const int32_t output_offset = shapeOut.offset;
66 const int left_shift = 20;
67 const double twice_max_input_scale = 2 * std::max(shape1.scale, shape2.scale);
68 const double real_input1_multiplier = shape1.scale / twice_max_input_scale;
69 const double real_input2_multiplier = shape2.scale / twice_max_input_scale;
70 const double real_output_multiplier =
71 twice_max_input_scale /
72 ((1 << left_shift) * shapeOut.scale);
73
74 int32_t input1_multiplier;
75 int32_t input1_shift;
76 if (!QuantizeMultiplierSmallerThanOne(real_input1_multiplier,
77 &input1_multiplier, &input1_shift)) {
78 return false;
79 }
80 int32_t input2_multiplier;
81 int32_t input2_shift;
82 if (!QuantizeMultiplierSmallerThanOne(real_input2_multiplier,
83 &input2_multiplier, &input2_shift)) {
84 return false;
85 }
86 int32_t output_multiplier;
87 int32_t output_shift;
88 if (!QuantizeMultiplierSmallerThanOne(real_output_multiplier,
89 &output_multiplier, &output_shift)) {
90 return false;
91 }
92 int32_t output_activation_min;
93 int32_t output_activation_max;
94 CalculateActivationRangeUint8(activation, shapeOut,
95 &output_activation_min,
96 &output_activation_max);
97
98 #define ANDROID_NN_NORMAL_ADD(activation) \
99 optimized_ops::Add<FusedActivationFunctionType::activation>( \
100 left_shift, \
101 in1, convertShapeToDims(shape1), \
102 input1_offset, input1_multiplier, input1_shift, \
103 in2, convertShapeToDims(shape2), \
104 input2_offset, input2_multiplier, input2_shift, \
105 output_offset, output_multiplier, output_shift, \
106 output_activation_min, output_activation_max, \
107 out, convertShapeToDims(shapeOut))
108
109 #define ANDROID_NN_BROADCAST_ADD(activation) \
110 optimized_ops::BroadcastAdd<FusedActivationFunctionType::activation>( \
111 left_shift, \
112 in1, convertShapeToDims(shape1), \
113 input1_offset, input1_multiplier, input1_shift, \
114 in2, convertShapeToDims(shape2), \
115 input2_offset, input2_multiplier, input2_shift, \
116 output_offset, output_multiplier, output_shift, \
117 output_activation_min, output_activation_max, \
118 out, convertShapeToDims(shapeOut))
119
120 if (needBroadcast) {
121 ANDROID_NN_MACRO_DISPATCH(ANDROID_NN_BROADCAST_ADD)
122 } else {
123 ANDROID_NN_MACRO_DISPATCH(ANDROID_NN_NORMAL_ADD)
124 }
125
126 #undef ANDROID_NN_NORMAL_ADD
127 #undef ANDROID_NN_BROADCAST_ADD
128 return true;
129 }
130
mulFloat32(const float * in1,const Shape & shape1,const float * in2,const Shape & shape2,int32_t activation,float * out,const Shape & shapeOut)131 bool mulFloat32(const float* in1, const Shape& shape1,
132 const float* in2, const Shape& shape2,
133 int32_t activation,
134 float* out, const Shape& shapeOut) {
135 bool needBroadcast = !SameShape(shape1, shape2);
136
137 #define ANDROID_NN_NORMAL_MUL(activation) \
138 optimized_ops::Mul<FusedActivationFunctionType::activation>( \
139 in1, convertShapeToDims(shape1), \
140 in2, convertShapeToDims(shape2), \
141 out, convertShapeToDims(shapeOut))
142
143 #define ANDROID_NN_BROADCAST_MUL(activation) \
144 optimized_ops::BroadcastMul<FusedActivationFunctionType::activation>( \
145 in1, convertShapeToDims(shape1), \
146 in2, convertShapeToDims(shape2), \
147 out, convertShapeToDims(shapeOut))
148
149 if (needBroadcast) {
150 ANDROID_NN_MACRO_DISPATCH(ANDROID_NN_BROADCAST_MUL)
151 } else {
152 ANDROID_NN_MACRO_DISPATCH(ANDROID_NN_NORMAL_MUL)
153 }
154
155 #undef ANDROID_NN_NORMAL_MUL
156 #undef ANDROID_NN_BROADCAST_MUL
157 return true;
158 }
159
mulQuant8(const uint8_t * in1,const Shape & shape1,const uint8_t * in2,const Shape & shape2,int32_t activation,uint8_t * out,const Shape & shapeOut)160 bool mulQuant8(const uint8_t* in1, const Shape& shape1,
161 const uint8_t* in2, const Shape& shape2,
162 int32_t activation,
163 uint8_t* out, const Shape& shapeOut) {
164 const int32_t input1_offset = -shape1.offset;
165 const int32_t input2_offset = -shape2.offset;
166 const int32_t output_offset = shapeOut.offset;
167 const double input_product_scale = shape1.scale * shape2.scale;
168 const double real_multiplier = input_product_scale / shapeOut.scale;
169 int32 output_multiplier;
170 int output_shift;
171 if (!QuantizeMultiplierSmallerThanOne(real_multiplier, &output_multiplier,
172 &output_shift)) {
173 return false;
174 }
175 int32_t output_activation_min;
176 int32_t output_activation_max;
177 CalculateActivationRangeUint8(activation, shapeOut,
178 &output_activation_min,
179 &output_activation_max);
180
181 // Use BROADCAST version to handle the normal case until we have a optimized Mul.
182 #define ANDROID_NN_BROADCAST_MUL(activation) \
183 optimized_ops::BroadcastMul<FusedActivationFunctionType::activation>( \
184 in1, convertShapeToDims(shape1), input1_offset, \
185 in2, convertShapeToDims(shape2), input2_offset, \
186 output_offset, output_multiplier, output_shift, \
187 output_activation_min, output_activation_max, \
188 out, convertShapeToDims(shapeOut))
189
190 ANDROID_NN_MACRO_DISPATCH(ANDROID_NN_BROADCAST_MUL)
191
192 #undef ANDROID_NN_NORMAL_MUL
193 #undef ANDROID_NN_BROADCAST_MUL
194 return true;
195 }
196
floorFloat32(const float * inputData,float * outputData,const Shape & shape)197 bool floorFloat32(const float* inputData,
198 float* outputData,
199 const Shape& shape) {
200 Dims<4> dim = convertShapeToDims(shape);
201 optimized_ops::Floor(inputData, dim, outputData, dim);
202 return true;
203 }
204
dequantizeQuant8ToFloat32(const uint8_t * inputData,float * outputData,const Shape & shape)205 bool dequantizeQuant8ToFloat32(const uint8_t* inputData,
206 float* outputData,
207 const Shape& shape) {
208 Dims<4> dim = convertShapeToDims(shape);
209 optimized_ops::Dequantize(inputData, dim,
210 shape.offset, shape.scale,
211 outputData, dim);
212 return true;
213 }
214
215 } // namespace nn
216 } // namespace android
217