IVGCVSW-3296 Add CL backend support for ResizeNearestNeighbour
[platform/upstream/armnn.git] / src / backends / aclCommon / ArmComputeUtils.hpp
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 #pragma once
6
7 #include <armnn/Descriptors.hpp>
8 #include <armnn/Tensor.hpp>
9
10 #include <arm_compute/core/Types.h>
11
12 #include <boost/assert.hpp>
13
14 namespace armnn
15 {
16
17 inline arm_compute::NormalizationLayerInfo
18 CreateAclNormalizationLayerInfoForL2Normalization(const armnn::TensorInfo& tensorInfo,
19                                                   armnn::DataLayout dataLayout)
20 {
21     unsigned int depthDimension = dataLayout == armnn::DataLayout::NCHW ? 1 : 3;
22     const unsigned int depth = tensorInfo.GetShape()[depthDimension];
23
24     // At the time of writing, {CL|Neon}L2Normalization performs the reduction only along dimension 0. This version of
25     // L2 Normalization always performs the reduction along the depth axis, though. Thus, we repurpose
26     // {CL|Neon}NormalizationLayers to act as depthwise L2 normalizations by carefully chosing the normalization
27     // parameters.
28     //
29     // Please refer to both the reference implementation of the normalization layer and the implementation of
30     // {CL|Neon}NormalizationLayer when checking the derivations for the parameter values below.
31
32     // Make sure normalization covers the entire depth range. ACL requires the normalization size to be odd.
33     // CL: This does not result in extra kernel threads not doing any work: See usage of the RADIUS parameter in
34     // ACL's normalization_layer_cross_map() CL function.
35     const uint32_t normSize = depth * 2u + 1u;
36
37     // See ACL's NormalizationLayerInfo::scale_coeff() definition.
38     // For the reference implementation, to make alpha_ become 1, we'd have to use alpha = normSize instead.
39     const float alpha = 1.0f;
40
41     // Don't offset the reduction.
42     const float kappa = 0.0f;
43
44     // pow(reduction, -0.5) = 1 / sqrt(reduction)
45     const float beta = 0.5f;
46
47     return arm_compute::NormalizationLayerInfo(arm_compute::NormType::CROSS_MAP, normSize, alpha, beta, kappa, false);
48 }
49
50 inline arm_compute::ActivationLayerInfo::ActivationFunction
51 ConvertActivationFunctionToAclActivationFunction(ActivationFunction armnnFunction)
52 {
53     using AclActivationFunction = arm_compute::ActivationLayerInfo::ActivationFunction;
54
55     switch (armnnFunction)
56     {
57         case ActivationFunction::Linear:        return AclActivationFunction::LINEAR;
58         // Arm compute's 'logistic' function is non-parameterized, so it is exactly a sigmoid function.
59         case ActivationFunction::Sigmoid:       return AclActivationFunction::LOGISTIC;
60         case ActivationFunction::ReLu:          return AclActivationFunction::RELU;
61         case ActivationFunction::BoundedReLu:   return AclActivationFunction::LU_BOUNDED_RELU;
62         case ActivationFunction::SoftReLu:      return AclActivationFunction::SOFT_RELU;
63         case ActivationFunction::LeakyReLu:     return AclActivationFunction::LEAKY_RELU;
64         case ActivationFunction::Abs:           return AclActivationFunction::ABS;
65         case ActivationFunction::Sqrt:          return AclActivationFunction::SQRT;
66         case ActivationFunction::Square:        return AclActivationFunction::SQUARE;
67         case ActivationFunction::TanH:          return AclActivationFunction::TANH;
68         default:                                throw InvalidArgumentException("Unsupported activation function");
69     }
70 }
71
72 inline arm_compute::ActivationLayerInfo
73 ConvertActivationDescriptorToAclActivationLayerInfo(const ActivationDescriptor& actDesc)
74 {
75     return arm_compute::ActivationLayerInfo(ConvertActivationFunctionToAclActivationFunction(actDesc.m_Function),
76         actDesc.m_A, actDesc.m_B);
77 }
78
79 inline arm_compute::PoolingType ConvertPoolingAlgorithmToAclPoolingType(PoolingAlgorithm poolingAlgorithm)
80 {
81     using arm_compute::PoolingType;
82
83     switch (poolingAlgorithm)
84     {
85         case PoolingAlgorithm::Max:             return PoolingType::MAX;
86         case PoolingAlgorithm::Average:         return PoolingType::AVG;
87         case PoolingAlgorithm::L2:              return PoolingType::L2;
88         default:                                throw InvalidArgumentException("Unsupported pooling algorithm");
89     }
90 }
91
92 inline arm_compute::DimensionRoundingType ConvertOutputShapeRoundingToAclDimensionRoundingType(OutputShapeRounding
93                                                                                                               rounding)
94 {
95     using arm_compute::DimensionRoundingType;
96
97     switch (rounding)
98     {
99         case OutputShapeRounding::Ceiling:  return DimensionRoundingType::CEIL;
100         case OutputShapeRounding::Floor:    return DimensionRoundingType::FLOOR;
101         default:                            throw InvalidArgumentException("Unsupported Output Shape Rounding type");
102     }
103 }
104
105 inline arm_compute::NormType
106 ConvertNormalizationAlgorithmChannelToAclNormType(NormalizationAlgorithmChannel channelType)
107 {
108     using arm_compute::NormType;
109     switch (channelType)
110     {
111         case NormalizationAlgorithmChannel::Across: return NormType::CROSS_MAP;
112         case NormalizationAlgorithmChannel::Within: return NormType::IN_MAP_2D;
113         default:    throw InvalidArgumentException("Unsupported normalization algorithm channel type");
114     }
115 }
116
117 inline arm_compute::FullyConnectedLayerInfo
118 ConvertFullyConnectedDescriptorToAclFullyConnectedLayerInfo(const FullyConnectedDescriptor& fullyConnectedDesc)
119 {
120     arm_compute::FullyConnectedLayerInfo fc_info;
121     fc_info.transpose_weights = fullyConnectedDesc.m_TransposeWeightMatrix;
122     return fc_info;
123 }
124
125 inline arm_compute::InterpolationPolicy ConvertResizeMethodToAclInterpolationPolicy(ResizeMethod resizeMethod)
126 {
127     switch (resizeMethod)
128     {
129         case ResizeMethod::Bilinear:
130             return arm_compute::InterpolationPolicy::BILINEAR;
131         case ResizeMethod::NearestNeighbor:
132             return arm_compute::InterpolationPolicy::NEAREST_NEIGHBOR;
133         default:
134             throw InvalidArgumentException("Unsupported resize method");
135     }
136 }
137
138 inline unsigned int ComputeSoftmaxAclAxis(const armnn::TensorInfo& tensor)
139 {
140     unsigned int dim = tensor.GetNumDimensions();
141
142     BOOST_ASSERT(dim != 0);
143
144     // Currently ArmNN support axis 1.
145     return dim - 1;
146 }
147
148 inline std::set<unsigned int> ComputeSplitAxis(const armnn::SplitterDescriptor& desc, const TensorShape& input)
149 {
150     unsigned int numSplit = desc.GetNumViews();
151     unsigned int numDimensions = desc.GetNumDimensions();
152     std::set<unsigned int> splitAxis;
153
154     for (unsigned int i = 0; i < numSplit; ++i)
155     {
156         for (unsigned int dimIdx = 0; dimIdx < numDimensions; ++dimIdx)
157         {
158             if (desc.GetViewSizes(i)[dimIdx] != input[dimIdx])
159             {
160                 splitAxis.insert(dimIdx);
161             }
162         }
163     }
164     return splitAxis;
165 }
166
167 } // namespace armnn