Imported Upstream version 1.7.0
[platform/core/ml/nnfw.git] / compute / cker / include / cker / PortableTensorUtils.h
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
3  * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #ifndef __NNFW_CKER_PORTABLE_TENSOR_UTILS_H__
19 #define __NNFW_CKER_PORTABLE_TENSOR_UTILS_H__
20
21 #include "cker/Types.h"
22 #include "cker/neon/neon_check.h"
23
24 #include <cstring>
25 #include <cmath>
26
27 namespace nnfw
28 {
29 namespace cker
30 {
31
32 class ActivationFunctor
33 {
34 public:
35   explicit ActivationFunctor(FusedActivationFunctionType act) : act_(act) {}
36
37   float operator()(float a) const
38   {
39     switch (act_)
40     {
41       case FusedActivationFunctionType::kNone:
42         return a;
43       case FusedActivationFunctionType::kRelu:
44         return a < 0.f ? 0.f : a;
45       case FusedActivationFunctionType::kRelu6:
46         return std::max(0.f, std::min(a, 6.f));
47       default:
48         // TODO(aselle): More informative fatal error!
49         exit(1);
50     }
51   }
52
53 private:
54   FusedActivationFunctionType act_;
55 };
56
57 void PortableVectorBatchVectorAssign(const float *vector, int v_size, int n_batch,
58                                      float *batch_vector)
59 {
60   for (int b = 0; b < n_batch; b++)
61   {
62     memcpy(batch_vector + b * v_size, vector, v_size * sizeof(float));
63   }
64 }
65
66 bool PortableIsZeroVector(const float *vector, int v_size)
67 {
68   for (int i = 0; i < v_size; ++i)
69   {
70     if (*vector++ != 0.0f)
71       return false;
72   }
73   return true;
74 }
75
76 void PortableApplyActivationToVector(const float *vector, int v_size,
77                                      FusedActivationFunctionType activation, float *result)
78 {
79   auto activation_func = ActivationFunctor(activation);
80   for (int v = 0; v < v_size; v++)
81   {
82     *result++ = (activation_func)(*vector++);
83   }
84 }
85
86 void PortableSymmetricQuantizeFloats(const float *values, const int size, int8_t *quantized_values,
87                                      float *min_value, float *max_value, float *scaling_factor)
88 {
89   auto minmax = std::minmax_element(values, values + size);
90   *min_value = *minmax.first;
91   *max_value = *minmax.second;
92   const int kScale = 127;
93   const float range = std::max(std::abs(*min_value), std::abs(*max_value));
94   if (range == 0)
95   {
96     memset(quantized_values, 0, size * sizeof(int8_t));
97     *scaling_factor = 1;
98     return;
99   }
100   *scaling_factor = range / kScale;
101   const float scaling_factor_inv = kScale / range;
102   for (int i = 0; i < size; ++i)
103   {
104     const int32_t quantized_value =
105         static_cast<int32_t>(std::round(values[i] * scaling_factor_inv));
106     // Clamp: just in case some odd numeric offset.
107     quantized_values[i] = std::min(kScale, std::max(-kScale, quantized_value));
108   }
109 }
110
111 void PortableMatrixBatchVectorMultiplyAccumulate(const int8_t *__restrict__ matrix,
112                                                  const int m_rows, const int m_cols,
113                                                  const int8_t *__restrict__ vectors,
114                                                  const float *scaling_factors, int n_batch,
115                                                  float *__restrict__ result, int result_stride)
116 {
117   int batch, row, col;
118   for (batch = 0; batch < n_batch; ++batch, vectors += m_cols)
119   {
120     const float batch_scaling_factor = scaling_factors[batch];
121     // Get the address of the first row.
122     const int8_t *row_ptr = matrix;
123     for (row = 0; row < m_rows; ++row, result += result_stride)
124     {
125       // Initialize the dot product sum for the row to 0.
126       int32_t dotprod = 0;
127 #if defined(__GNUC__)
128       // Prefetch the row to cache.
129       __builtin_prefetch(row_ptr, 0 /* prefetch for read */, 3 /* temporal locality */);
130 #endif
131       for (col = 0; col < m_cols; ++col, ++row_ptr)
132       {
133         dotprod += (*row_ptr) * (vectors[col]);
134       } // for col
135       *result += (dotprod * batch_scaling_factor);
136     } // for row
137   }   // for batch
138 }
139
140 void PortableMatrixBatchVectorMultiplyAccumulate(const int8_t *__restrict__ matrix,
141                                                  const int m_rows, const int m_cols,
142                                                  const int8_t *__restrict__ vector,
143                                                  const float *scaling_factors, int n_batch,
144                                                  int32_t *, float *__restrict__ result,
145                                                  int result_stride)
146 {
147   PortableMatrixBatchVectorMultiplyAccumulate(matrix, m_rows, m_cols, vector, scaling_factors,
148                                               n_batch, result, result_stride);
149 }
150
151 void PortableMatrixBatchVectorMultiplyAccumulate(const float *matrix, int m_rows, int m_cols,
152                                                  const float *vector, int n_batch, float *result,
153                                                  int result_stride)
154 {
155   float *result_in_batch = result;
156   for (int b = 0; b < n_batch; b++)
157   {
158     const float *matrix_ptr = matrix;
159     for (int r = 0; r < m_rows; r++)
160     {
161       float dot_prod = 0.0f;
162       const float *vector_in_batch = vector + b * m_cols;
163       for (int c = 0; c < m_cols; c++)
164       {
165         dot_prod += *matrix_ptr++ * *vector_in_batch++;
166       }
167       *result_in_batch += dot_prod;
168       result_in_batch += result_stride;
169     }
170   }
171 }
172
173 void PortableZeroVector(float *vector, int v_size) { std::fill_n(vector, v_size, 0); }
174
175 } // namespace cker
176 } // namespace nnfw
177
178 #endif // __NNFW_CKER_PORTABLE_TENSOR_UTILS_H__