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 #include "CpuOperationUtils.h" 18 #include "Operations.h" 19 20 #include <algorithm> 21 #include <cmath> 22 #include "tensorflow/lite/kernels/internal/optimized/optimized_ops.h" 23 24 #include "Tracing.h" 25 26 namespace android { 27 namespace nn { 28 29 inline bool localResponseNormFloat32Impl(const float* inputData, const Shape& inputShape, 30 int32_t radius, float bias, float alpha, float beta, 31 int32_t axis, float* outputData, 32 const Shape& outputShape) { 33 NNTRACE_TRANS("localResponseNormFloat32"); 34 const uint32_t outerSize = getNumberOfElements(inputShape, 0, axis); 35 const uint32_t axisSize = getSizeOfDimension(inputShape, axis); 36 const uint32_t innerSize = 37 getNumberOfElements(inputShape, axis + 1, getNumberOfDimensions(inputShape)); 38 for (uint32_t outer = 0; outer < outerSize; ++outer) { 39 const float* inputBase = inputData + outer * axisSize * innerSize; 40 float* outputBase = outputData + outer * axisSize * innerSize; 41 for (uint32_t inner = 0; inner < innerSize; ++inner, ++inputBase, ++outputBase) { 42 for (int32_t i = 0; i < axisSize; i++) { 43 const int32_t dBegin = std::max(0, i - radius); 44 // Add 1 on dEnd to comply with optimized_ops in TFLite 45 const int32_t dEnd = std::min(static_cast<int32_t>(axisSize), i + radius + 1); 46 float sum = 0.0f; 47 for (int32_t d = dBegin; d < dEnd; d++) { 48 float val = inputBase[d * innerSize]; 49 sum += val * val; 50 } 51 float multiplier = std::pow(bias + alpha * sum, -beta); 52 outputBase[i * innerSize] = inputBase[i * innerSize] * multiplier; 53 } 54 } 55 } 56 return true; 57 } 58 59 bool localResponseNormFloat16(const _Float16* inputData, const Shape& inputShape, int32_t radius, 60 float bias, float alpha, float beta, int32_t axis, 61 _Float16* outputData, const Shape& outputShape) { 62 NNTRACE_TRANS("localResponseNormFloat16"); 63 std::vector<float> inputDataFloat32(getNumberOfElements(inputShape)); 64 convertFloat16ToFloat32(inputData, &inputDataFloat32); 65 std::vector<float> outputDataFloat32(getNumberOfElements(outputShape)); 66 67 localResponseNormFloat32(inputDataFloat32.data(), inputShape, radius, bias, alpha, beta, axis, 68 outputDataFloat32.data(), outputShape); 69 convertFloat32ToFloat16(outputDataFloat32, outputData); 70 71 return true; 72 } 73 74 bool localResponseNormFloat32(const float* inputData, const Shape& inputShape, int32_t radius, 75 float bias, float alpha, float beta, int32_t axis, float* outputData, 76 const Shape& outputShape) { 77 int32_t ndim = getNumberOfDimensions(inputShape); 78 NN_CHECK(handleNegativeAxis(inputShape, &axis)); 79 // TFLite optimized implementation only supports computation along the last axis 80 if (axis == ndim - 1) { 81 NNTRACE_COMP("optimized_ops::LocalResponseNormalization::float"); 82 tflite::LocalResponseNormalizationParams param = { 83 .range = radius, .bias = bias, .alpha = alpha, .beta = beta}; 84 tflite::optimized_ops::LocalResponseNormalization( 85 param, convertShapeToTflshape(inputShape), inputData, 86 convertShapeToTflshape(outputShape), outputData); 87 return true; 88 } else { 89 return localResponseNormFloat32Impl(inputData, inputShape, radius, bias, alpha, beta, axis, 90 outputData, outputShape); 91 } 92 } 93 } // namespace nn 94 } // namespace android 95