// // Copyright © 2017 Arm Ltd. All rights reserved. // SPDX-License-Identifier: MIT // #pragma once #include "BaseIterator.hpp" #include namespace { // Helper functions ported from the Android code base // Refer to: android/external/tensorflow/tensorflow/contrib/lite/kernels/internal/reference/portable_tensor_utils.cc void MatrixBatchVectorMultiplyAccumulate(armnn::Decoder& matrix, uint32_t mRows, uint32_t mCols, armnn::Decoder& vector, uint32_t nBatch, armnn::Encoder& outResult) { for (uint32_t b = 0; b < nBatch; b++) { for (uint32_t r = 0; r < mRows; r++) { vector += b * mCols; for (uint32_t c = 0; c < mCols; c++) { outResult.Set(outResult.Get() + matrix.Get() * vector.Get()); ++matrix; ++vector; } outResult += 1; vector -= (b+1) * mCols; } matrix -= (mRows * mCols); } outResult -= (mRows * nBatch); } void VectorBatchVectorAssign(armnn::Decoder& vector, uint32_t vSize, uint32_t nBatch, armnn::Encoder& outBatchVector) { for (uint32_t b = 0; b < nBatch; b++) { for (uint32_t v = 0; v < vSize; v++) { outBatchVector.Set(vector.Get()); ++outBatchVector; ++vector; } vector -= vSize; } outBatchVector -= (nBatch * vSize); } void VectorBatchVectorCwiseProductAccumulate(armnn::Decoder& vector, uint32_t vSize, armnn::Decoder& batchVector, uint32_t nBatch, armnn::Encoder& outResult) { for (uint32_t b = 0; b < nBatch; b++) { for (uint32_t v = 0; v < vSize; v++) { outResult.Set(outResult.Get() + vector.Get() * batchVector.Get()); ++outResult; ++vector; ++batchVector; } vector -= vSize; } batchVector -= vSize * nBatch; outResult -= vSize * nBatch; } void Sub1Vector(armnn::Decoder& vector, uint32_t vSize, armnn::Encoder& result) { for (uint32_t v = 0; v < vSize; v++) { result.Set(1.0f - vector.Get()); ++vector; ++result; } vector -= vSize; result -= vSize; } void VectorVectorCwiseProduct(armnn::Decoder& vector1, armnn::Decoder& vector2, uint32_t vSize, armnn::Encoder& outResult) { for (uint32_t v = 0; v < vSize; v++) { outResult.Set(vector1.Get() * vector2.Get()); ++outResult; ++vector1; ++vector2; } outResult -= vSize; vector1 -= vSize; vector2 -= vSize; } void VectorVectorCwiseProductAccumulate(armnn::Decoder& vector1, armnn::Decoder& vector2, uint32_t vSize, armnn::Encoder& outResult) { for (uint32_t v = 0; v < vSize; v++) { outResult.Set(outResult.Get() + vector1.Get() * vector2.Get()); ++outResult; ++vector1; ++vector2; } outResult -= vSize; vector1 -= vSize; vector2 -= vSize; } float Clip(float f, float absLimit) { float result = (absLimit < f) ? absLimit : f; result = (-absLimit > result) ? -absLimit : result; return result; } void ClipVector(armnn::Decoder& vector, uint32_t vSize, float absLimit, armnn::Encoder& outResult) { for (uint32_t v = 0; v < vSize; v++) { outResult.Set(Clip(vector.Get(), absLimit)); ++vector; ++outResult; } vector -= vSize; outResult -= vSize; } void CopyVector(armnn::Decoder& vector, uint32_t vSize, armnn::Encoder& outResult) { for (uint32_t v = 0; v < vSize; v++) { outResult.Set(vector.Get()); ++outResult; ++vector; } outResult -= vSize; vector -= vSize; } void SetActivationParameters(uint32_t activation, armnn::ActivationFunction& outArmnnActivation, float& outA, float& outB) { switch (activation) { case 0: // None outA = 0; outB = 0; return; case 1: // Relu outArmnnActivation = armnn::ActivationFunction::ReLu; outA = 0; outB = 0; return; case 3: // Relu6 outArmnnActivation = armnn::ActivationFunction::BoundedReLu; outA = 6; outB = 0; return; case 4: // Tanh outArmnnActivation = armnn::ActivationFunction::TanH; outA = 1; outB = 1; return; case 6: // Sigmoid outArmnnActivation = armnn::ActivationFunction::Sigmoid; outA = 0; outB = 0; return; default: throw armnn::Exception("Unsupported activation function: " + std::to_string(activation)); } } std::unique_ptr AssignScopedCpuTensorHandle(const armnn::ConstCpuTensorHandle* ptr) { if (!ptr) { return nullptr; } return std::make_unique(*ptr); } } // anonymous namespace