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