blob: c691c5541538c84858aa99d94bd35b15132a0a64 [file] [log] [blame]
arovir01b0717b52018-09-05 17:03:25 +01001//
Cathal Corbett8de96f72022-09-01 13:34:59 +01002// Copyright © 2017,2022 Arm Ltd and Contributors. All rights reserved.
arovir01b0717b52018-09-05 17:03:25 +01003// SPDX-License-Identifier: MIT
4//
5
6#include "ConversionUtils.hpp"
Mike Kelly4a956582020-02-28 10:32:09 +00007#include <armnnUtils/Permute.hpp>
arovir01b0717b52018-09-05 17:03:25 +01008
9///
10/// Helper classes
11///
12
13namespace armnn_driver
14{
15
16LayerInputHandle::LayerInputHandle()
17 : m_OutputSlot(nullptr)
18 , m_Valid(false)
19{}
20
21LayerInputHandle::LayerInputHandle(bool valid, armnn::IOutputSlot* outputSlot, armnn::TensorInfo tensorInfo)
22 : m_OutputSlot(outputSlot)
23 , m_Valid(valid)
24 , m_TensorInfo(tensorInfo)
25{}
26
27bool LayerInputHandle::IsValid() const
28{
29 return m_Valid;
30}
31
32void LayerInputHandle::Connect(armnn::IInputSlot& inputSlot)
33{
Mike Kellye2d611e2021-10-14 12:35:58 +010034 if (!IsValid())
35 {
36 throw armnn::RuntimeException("LayerInputHandle is invalid");
37 }
38
arovir01b0717b52018-09-05 17:03:25 +010039 if (m_OutputSlot)
40 {
41 m_OutputSlot->Connect(inputSlot);
42 }
43}
44
Finn Williamsa4983ce2020-07-23 12:55:12 +010045void LayerInputHandle::Disconnect(armnn::IInputSlot& inputSlot)
46{
Mike Kellye2d611e2021-10-14 12:35:58 +010047 if (!IsValid())
48 {
49 throw armnn::RuntimeException("LayerInputHandle is invalid");
50 }
Finn Williamsa4983ce2020-07-23 12:55:12 +010051 if (m_OutputSlot)
52 {
53 m_OutputSlot->Disconnect(inputSlot);
54 }
55}
56
arovir01b0717b52018-09-05 17:03:25 +010057const armnn::TensorInfo& LayerInputHandle::GetTensorInfo() const
58{
59 return m_TensorInfo;
60}
61
Cathal Corbett915f2a72022-04-15 14:12:08 +010062void LayerInputHandle::SanitizeQuantizationScale(LayerInputHandle& weight,
63 LayerInputHandle& input)
64{
Colm Donelanbb7b2812022-05-09 17:52:23 +010065 if (m_OutputSlot)
66 {
67 armnn::TensorInfo weightInfo = weight.GetTensorInfo();
68 armnn::TensorInfo inputInfo = input.GetTensorInfo();
69 armnn::TensorInfo biasInfo = GetTensorInfo();
Cathal Corbett915f2a72022-04-15 14:12:08 +010070
Colm Donelanbb7b2812022-05-09 17:52:23 +010071 SanitizeBiasQuantizationScale(biasInfo, weightInfo, inputInfo);
Cathal Corbett915f2a72022-04-15 14:12:08 +010072
Colm Donelanbb7b2812022-05-09 17:52:23 +010073 m_TensorInfo = biasInfo;
74 m_OutputSlot->SetTensorInfo(biasInfo);
75 }
Cathal Corbett915f2a72022-04-15 14:12:08 +010076}
77
arovir01b0717b52018-09-05 17:03:25 +010078ConstTensorPin::ConstTensorPin(bool optional)
79 : m_Optional(optional)
80{}
81
Jan Eilersa71c0632021-04-12 13:12:19 +010082ConstTensorPin::ConstTensorPin(armnn::TensorInfo& tensorInfo,
arovir01b0717b52018-09-05 17:03:25 +010083 const void* valueStart,
84 uint32_t numBytes,
85 const armnn::PermutationVector& mappings)
Jim Flynn8920cae2021-05-13 15:48:45 +010086 : m_Optional(false)
arovir01b0717b52018-09-05 17:03:25 +010087{
Jan Eilers0b7a4192020-03-09 18:20:42 +000088 armnn::IgnoreUnused(numBytes);
Colm Donelanccfeb5e2021-03-30 15:30:13 +010089 if (tensorInfo.GetNumBytes() != numBytes)
90 {
91 ALOGW("The size of ConstTensor does not match its TensorInfo.");
92 }
arovir01b0717b52018-09-05 17:03:25 +010093
94 const bool needsSwizzling = (mappings.GetSize() > 0);
95 if (needsSwizzling)
96 {
97 m_SwizzledTensorData.resize(tensorInfo.GetNumBytes());
98 SwizzleAndroidNn4dTensorToArmNn(tensorInfo, valueStart, m_SwizzledTensorData.data(), mappings);
99
Jan Eilersa71c0632021-04-12 13:12:19 +0100100 m_ConstTensor = armnn::ConstTensor(tensorInfo, m_SwizzledTensorData.data());
arovir01b0717b52018-09-05 17:03:25 +0100101 }
102 else
103 {
104 m_ConstTensor = armnn::ConstTensor(tensorInfo, valueStart);
105 }
106}
107
108bool ConstTensorPin::IsValid() const
109{
110 return m_ConstTensor.GetMemoryArea() != nullptr;
111}
112
113bool ConstTensorPin::IsOptional() const
114{
115 return m_Optional;
116}
117
118const armnn::ConstTensor& ConstTensorPin::GetConstTensor() const
119{
120 return m_ConstTensor;
121}
122
123const armnn::ConstTensor* ConstTensorPin::GetConstTensorPtr() const
124{
125 if (IsValid() && m_ConstTensor.GetNumElements() > 0)
126 {
127 return &m_ConstTensor;
128 }
129 // tensor is either invalid, or has no elements (indicating an optional tensor that was not provided)
130 return nullptr;
131}
132
133///
134/// Utility functions
135///
136
137armnn::IConnectableLayer* ProcessActivation(const armnn::TensorInfo& tensorInfo,
138 ActivationFn activation,
139 armnn::IConnectableLayer* prevLayer,
140 ConversionData& data)
141{
Mike Kellye2d611e2021-10-14 12:35:58 +0100142 if (prevLayer->GetNumOutputSlots() != 1)
143 {
144 Fail("%s: Incorrect Number of OutputSlots expected 1 was %i", __func__, prevLayer->GetNumOutputSlots());
145 return nullptr;
146 }
arovir01b0717b52018-09-05 17:03:25 +0100147 prevLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
148
149 armnn::IConnectableLayer* activationLayer = prevLayer;
150
151 if (activation != ActivationFn::kActivationNone)
152 {
153 armnn::ActivationDescriptor activationDesc;
154 switch (activation)
155 {
156 case ActivationFn::kActivationRelu:
157 {
158 activationDesc.m_Function = armnn::ActivationFunction::ReLu;
159 break;
160 }
161 case ActivationFn::kActivationRelu1:
162 {
163 activationDesc.m_Function = armnn::ActivationFunction::BoundedReLu;
164 activationDesc.m_A = 1.0f;
165 activationDesc.m_B = -1.0f;
166 break;
167 }
168 case ActivationFn::kActivationRelu6:
169 {
170 activationDesc.m_Function = armnn::ActivationFunction::BoundedReLu;
171 activationDesc.m_A = 6.0f;
172 break;
173 }
174 case ActivationFn::kActivationSigmoid:
175 {
176 activationDesc.m_Function = armnn::ActivationFunction::Sigmoid;
177 break;
178 }
179 case ActivationFn::kActivationTanh:
180 {
181 activationDesc.m_Function = armnn::ActivationFunction::TanH;
182 activationDesc.m_A = 1.0f;
183 activationDesc.m_B = 1.0f;
184 break;
185 }
186 default:
187 {
188 Fail("%s: Invalid activation enum value %i", __func__, activation);
189 return nullptr;
190 }
191 }
192
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100193 bool isSupported = false;
Cathal Corbett8de96f72022-09-01 13:34:59 +0100194 armnn::BackendId setBackend;
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100195 FORWARD_LAYER_SUPPORT_FUNC(__func__,
196 IsActivationSupported,
197 data.m_Backends,
198 isSupported,
Cathal Corbett8de96f72022-09-01 13:34:59 +0100199 setBackend,
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100200 prevLayer->GetOutputSlot(0).GetTensorInfo(),
201 tensorInfo,
202 activationDesc);
203 if (!isSupported)
arovir01b0717b52018-09-05 17:03:25 +0100204 {
205 return nullptr;
206 }
207
208 activationLayer = data.m_Network->AddActivationLayer(activationDesc);
Cathal Corbett8de96f72022-09-01 13:34:59 +0100209 activationLayer->SetBackendId(setBackend);
arovir01b0717b52018-09-05 17:03:25 +0100210
211 prevLayer->GetOutputSlot(0).Connect(activationLayer->GetInputSlot(0));
212 activationLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
213 }
214
215 return activationLayer;
216}
217
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100218} // namespace armnn_driver