blob: 9d9b1a0a411b476fdd3a765d24e630413c3aeb00 [file] [log] [blame]
Jan Eilers38e05bd2019-06-26 13:10:09 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6//#pragma once
7
8#include "LstmUtils.hpp"
9#include "BaseIterator.hpp"
Colm Donelan0c479742021-12-10 12:43:54 +000010#include <armnn/backends/TensorHandle.hpp>
Jan Eilers38e05bd2019-06-26 13:10:09 +010011
12
13// Helper functions ported from the Android code base
14// Refer to: android/external/tensorflow/tensorflow/contrib/lite/kernels/internal/reference/portable_tensor_utils.cc
15
16void VectorBatchVectorAdd(armnn::Decoder<float>& vector,
17 uint32_t vSize,
18 armnn::Decoder<float>& batchVector,
19 uint32_t nBatch,
20 armnn::Encoder<float>& outResult )
21{
22 for (uint32_t b = 0; b < nBatch; b++)
23 {
24 for (uint32_t v = 0; v < vSize; v++)
25 {
26 outResult.Set(batchVector.Get() + vector.Get());
27 ++outResult;
28 ++vector;
29 ++batchVector;
30 }
31 vector -= vSize;
32 }
33 batchVector -= vSize * nBatch;
34 outResult -= vSize * nBatch;
35}
36
37
38// Layer norm for each batch.
39// normalization_epsilon is added to avoid divergence.
40void MeanStddevNormalization(armnn::Decoder<float>& input_vector,
41 armnn::Encoder<float>& output_vector,
42 uint32_t v_size,
43 uint32_t n_batch,
44 float normalization_epsilon)
45{
46 for (uint32_t batch = 0; batch < n_batch; ++batch) {
47 float sum = 0.0f;
48 float sum_sq = 0.0f;
49 for (uint32_t i = 0; i < v_size; ++i) {
50 sum += input_vector.Get();
51 sum_sq += input_vector.Get() * input_vector.Get();
52 ++input_vector;
53 }
54 input_vector -= v_size;
55
56 const float mean = sum / static_cast<float>(v_size);
57 float stddev_inv = 0.0f;
58 const float variance = sum_sq / static_cast<float>(v_size) - mean * mean;
59 if (variance == 0) {
60 stddev_inv = 1.0f / std::sqrt(normalization_epsilon);
61 } else {
62 stddev_inv = 1.0f / std::sqrt(variance);
63 }
64
65 for (uint32_t i = 0; i < v_size; ++i) {
66 output_vector.Set((input_vector.Get() - mean) * stddev_inv);
67 ++output_vector;
68 ++input_vector;
69 }
70 // Don't reset iterator to handle next batch
71 }
72 output_vector -= v_size * n_batch;
73 input_vector -= v_size * n_batch;
74}
75
76void ZeroVector(armnn::Encoder<float>& vector,
77 uint32_t vSize)
78{
79 for (uint32_t v = 0; v < vSize; v++)
80 {
81 vector.Set(0.0f);
82 ++vector;
83 }
84 vector -= vSize;
85}
86
87void MatrixBatchVectorMultiplyAccumulate(armnn::Decoder<float>& matrix,
88 uint32_t mRows,
89 uint32_t mCols,
90 armnn::Decoder<float>& vector,
91 uint32_t nBatch,
92 armnn::Encoder<float>& outResult)
93{
94 for (uint32_t b = 0; b < nBatch; b++)
95 {
96 for (uint32_t r = 0; r < mRows; r++)
97 {
98 vector += b * mCols;
99 for (uint32_t c = 0; c < mCols; c++)
100 {
101 outResult.Set(outResult.Get() + matrix.Get() * vector.Get());
102 ++matrix;
103 ++vector;
104 }
105 outResult += 1;
106 vector -= (b+1) * mCols;
107 }
108 matrix -= (mRows * mCols);
109 }
110 outResult -= (mRows * nBatch);
111}
112
113void VectorBatchVectorAssign(armnn::Decoder<float>& vector,
114 uint32_t vSize,
115 uint32_t nBatch,
116 armnn::Encoder<float>& outBatchVector)
117{
118 for (uint32_t b = 0; b < nBatch; b++)
119 {
120 for (uint32_t v = 0; v < vSize; v++)
121 {
122 outBatchVector.Set(vector.Get());
123 ++outBatchVector;
124 ++vector;
125 }
126 vector -= vSize;
127 }
128 outBatchVector -= (nBatch * vSize);
129}
130
131void VectorBatchVectorCwiseProductAccumulate(armnn::Decoder<float>& vector,
132 uint32_t vSize,
133 armnn::Decoder<float>& batchVector,
134 uint32_t nBatch,
135 armnn::Encoder<float>& outResult)
136{
137 for (uint32_t b = 0; b < nBatch; b++)
138 {
139 for (uint32_t v = 0; v < vSize; v++)
140 {
141 outResult.Set(outResult.Get() + vector.Get() * batchVector.Get());
142 ++outResult;
143 ++vector;
144 ++batchVector;
145 }
146 vector -= vSize;
147 }
148 batchVector -= vSize * nBatch;
149 outResult -= vSize * nBatch;
150}
151
152void VectorBatchVectorCwiseProduct(armnn::Decoder<float>& vector,
153 uint32_t vSize,
154 armnn::Decoder<float>& batchVector,
155 uint32_t nBatch,
156 armnn::Encoder<float>& outResult)
157{
158 for (uint32_t b = 0; b < nBatch; b++)
159 {
160 for (uint32_t v = 0; v < vSize; v++)
161 {
162 outResult.Set(vector.Get() * batchVector.Get());
163 ++outResult;
164 ++vector;
165 ++batchVector;
166 }
167 vector -= vSize;
168 }
169 batchVector -= vSize * nBatch;
170 outResult -= vSize * nBatch;
171}
172
173void Sub1Vector(armnn::Decoder<float>& vector,
174 uint32_t vSize,
175 armnn::Encoder<float>& result)
176{
177 for (uint32_t v = 0; v < vSize; v++)
178 {
179 result.Set(1.0f - vector.Get());
180 ++vector;
181 ++result;
182 }
183 vector -= vSize;
184 result -= vSize;
185}
186
187void VectorVectorCwiseProduct(armnn::Decoder<float>& vector1,
188 armnn::Decoder<float>& vector2,
189 uint32_t vSize,
190 armnn::Encoder<float>& outResult)
191{
192 for (uint32_t v = 0; v < vSize; v++)
193 {
194 outResult.Set(vector1.Get() * vector2.Get());
195 ++outResult;
196 ++vector1;
197 ++vector2;
198 }
199 outResult -= vSize;
200 vector1 -= vSize;
201 vector2 -= vSize;
202}
203
204void VectorVectorCwiseProductAccumulate(armnn::Decoder<float>& vector1,
205 armnn::Decoder<float>& vector2,
206 uint32_t vSize,
207 armnn::Encoder<float>& outResult)
208{
209 for (uint32_t v = 0; v < vSize; v++)
210 {
211 outResult.Set(outResult.Get() + vector1.Get() * vector2.Get());
212 ++outResult;
213 ++vector1;
214 ++vector2;
215 }
216 outResult -= vSize;
217 vector1 -= vSize;
218 vector2 -= vSize;
219}
220
221float Clip(float f,
222 float absLimit)
223{
224 float result = (absLimit < f) ? absLimit : f;
225 result = (-absLimit > result) ? -absLimit : result;
226 return result;
227}
228
229void ClipVector(armnn::Decoder<float>& vector,
230 uint32_t vSize,
231 float absLimit,
232 armnn::Encoder<float>& outResult)
233{
234 for (uint32_t v = 0; v < vSize; v++)
235 {
236 outResult.Set(Clip(vector.Get(), absLimit));
237 ++vector;
238 ++outResult;
239 }
240 vector -= vSize;
241 outResult -= vSize;
242}
243
244void CopyVector(armnn::Decoder<float>& vector,
245 uint32_t vSize,
246 armnn::Encoder<float>& outResult)
247{
248 for (uint32_t v = 0; v < vSize; v++)
249 {
250 outResult.Set(vector.Get());
251 ++outResult;
252 ++vector;
253 }
254 outResult -= vSize;
255 vector -= vSize;
256}
257
258void SetActivationParameters(uint32_t activation,
259 armnn::ActivationFunction& outArmnnActivation,
260 float& outA,
261 float& outB)
262{
263 switch (activation)
264 {
265 case 0: // None
266 outA = 0;
267 outB = 0;
268 return;
269
270 case 1: // Relu
271 outArmnnActivation = armnn::ActivationFunction::ReLu;
272 outA = 0;
273 outB = 0;
274 return;
275
276 case 3: // Relu6
277 outArmnnActivation = armnn::ActivationFunction::BoundedReLu;
278 outA = 6;
279 outB = 0;
280 return;
281
282 case 4: // Tanh
283 outArmnnActivation = armnn::ActivationFunction::TanH;
284 outA = 1;
285 outB = 1;
286 return;
287
288 case 6: // Sigmoid
289 outArmnnActivation = armnn::ActivationFunction::Sigmoid;
290 outA = 0;
291 outB = 0;
292 return;
293
294 default:
295 throw armnn::Exception("Unsupported activation function: " + std::to_string(activation));
296 }
297}
298
James Conroy1f58f032021-04-27 17:13:27 +0100299std::unique_ptr<armnn::ScopedTensorHandle> AssignScopedTensorHandle(const armnn::ConstTensorHandle *ptr)
Jan Eilers38e05bd2019-06-26 13:10:09 +0100300{
301 if (!ptr)
302 {
303 return nullptr;
304 }
305
James Conroy1f58f032021-04-27 17:13:27 +0100306 return std::make_unique<armnn::ScopedTensorHandle>(*ptr);
Jan Eilers38e05bd2019-06-26 13:10:09 +0100307}