blob: c5df72a77b9b01b2ba70b93fdc12bf0929f37174 [file] [log] [blame]
arovir01b0717b52018-09-05 17:03:25 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "HalPolicy.hpp"
7
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +01008#include "OutputShapeUtils.hpp"
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +01009#include "Utils.hpp"
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +010010
arovir01b0717b52018-09-05 17:03:25 +010011#include "../1.0/HalPolicy.hpp"
12
Éanna Ó Catháin2fc21f72019-05-13 11:01:33 +010013namespace
14{
15static std::vector<V1_0::OperationType> opsEquivalentInV10({
16 V1_0::OperationType::ADD,
17 V1_0::OperationType::AVERAGE_POOL_2D,
18 V1_0::OperationType::CONCATENATION,
19 V1_0::OperationType::CONV_2D,
20 V1_0::OperationType::DEPTHWISE_CONV_2D,
David Monahand5bfae12019-05-30 12:07:44 +010021 V1_0::OperationType::DEQUANTIZE,
Éanna Ó Catháin2fc21f72019-05-13 11:01:33 +010022 V1_0::OperationType::FLOOR,
23 V1_0::OperationType::FULLY_CONNECTED,
24 V1_0::OperationType::LOCAL_RESPONSE_NORMALIZATION,
25 V1_0::OperationType::LOGISTIC,
26 V1_0::OperationType::LSTM,
27 V1_0::OperationType::L2_NORMALIZATION,
28 V1_0::OperationType::L2_POOL_2D,
29 V1_0::OperationType::MAX_POOL_2D,
30 V1_0::OperationType::MUL,
31 V1_0::OperationType::RELU,
32 V1_0::OperationType::RELU1,
33 V1_0::OperationType::RELU6,
34 V1_0::OperationType::SOFTMAX,
Keith Davisa6bc52f2019-06-26 09:39:49 +010035 V1_0::OperationType::SPACE_TO_DEPTH,
Éanna Ó Catháin2fc21f72019-05-13 11:01:33 +010036 V1_0::OperationType::TANH,
37 V1_0::OperationType::RESHAPE,
38 V1_0::OperationType::RESIZE_BILINEAR,
39});
40
41bool CompliantWithVersion10(const V1_1::Operation & operation)
42{
43 std::vector<V1_0::OperationType>::iterator it;
44 it = std::find(opsEquivalentInV10.begin(), opsEquivalentInV10.end(),
45 static_cast<V1_0::OperationType>(operation.type));
46
47 if(it != opsEquivalentInV10.end())
48 {
49 return true;
50 }
51 return false;
52}
53
54V1_0::Operation ConvertOperationToVersion10(const V1_1::Operation & operation)
55{
56 V1_0::Operation v10Operation;
57 v10Operation.type = static_cast<V1_0::OperationType>(operation.type);
58 v10Operation.inputs = operation.inputs;
59 v10Operation.outputs = operation.outputs;
60 return v10Operation;
61}
62}
63
arovir01b0717b52018-09-05 17:03:25 +010064namespace armnn_driver
65{
66namespace hal_1_1
67{
68
69bool HalPolicy::ConvertOperation(const Operation& operation, const Model& model, ConversionData& data)
70{
Éanna Ó Catháin2fc21f72019-05-13 11:01:33 +010071 if (CompliantWithVersion10(operation))
arovir01b0717b52018-09-05 17:03:25 +010072 {
Éanna Ó Catháin2fc21f72019-05-13 11:01:33 +010073 hal_1_0::HalPolicy::Operation v10Operation = ConvertOperationToVersion10(operation);
arovir01b0717b52018-09-05 17:03:25 +010074 hal_1_0::HalPolicy::Model v10Model = convertToV1_0(model);
75
76 return hal_1_0::HalPolicy::ConvertOperation(v10Operation, v10Model, data);
77 }
78 else
79 {
80 switch (operation.type)
81 {
82 case V1_1::OperationType::DIV:
83 return ConvertDiv(operation, model, data);
David Beck38e12942018-09-12 16:02:24 +010084 case V1_1::OperationType::SUB:
85 return ConvertSub(operation, model, data);
narpra013c052562018-09-17 14:25:04 +010086 case V1_1::OperationType::MEAN:
87 return ConvertMean(operation, model, data);
Nina Drozd62a4a9f2018-10-01 14:20:25 +010088 case V1_1::OperationType::PAD:
89 return ConvertPad(operation, model, data);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +000090 case V1_1::OperationType::SPACE_TO_BATCH_ND:
91 return ConvertSpaceToBatchNd(operation, model, data);
saoste01b8471482018-10-10 09:44:51 +010092 case V1_1::OperationType::SQUEEZE:
93 return ConvertSqueeze(operation, model, data);
Sadik Armagan758eee82018-11-15 15:34:49 +000094 case V1_1::OperationType::STRIDED_SLICE:
95 return ConvertStridedSlice(operation, model, data);
saoste01fe463152018-10-18 17:49:56 +010096 case V1_1::OperationType::TRANSPOSE:
97 return ConvertTranspose(operation, model, data);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +000098 case V1_1::OperationType::BATCH_TO_SPACE_ND:
99 return ConvertBatchToSpaceNd(operation, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100100 default:
101 return Fail("%s: Operation type %s not supported in ArmnnDriver",
102 __func__, toString(operation.type).c_str());
103 }
104 }
105}
106
107bool HalPolicy::ConvertDiv(const Operation& operation, const Model& model, ConversionData& data)
108{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100109 ALOGV("hal_1_1::HalPolicy::ConvertDiv()");
110
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100111 LayerInputHandle input0 = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
112 LayerInputHandle input1 = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 1, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100113
114 if (!input0.IsValid() || !input1.IsValid())
115 {
116 return Fail("%s: Operation has invalid inputs", __func__);
117 }
118
119 // The FuseActivation parameter is always the input index 2
120 // and it should be optional
121 ActivationFn activationFunction;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100122 if (!GetOptionalInputActivation<hal_1_1::HalPolicy>(operation, 2, activationFunction, model, data))
arovir01b0717b52018-09-05 17:03:25 +0100123 {
124 return Fail("%s: Operation has invalid inputs", __func__);
125 }
126
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100127 const Operand* outputOperand = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
arovir01b0717b52018-09-05 17:03:25 +0100128 if (!outputOperand)
129 {
130 return false;
131 }
132
133 const armnn::TensorInfo& outInfo = GetTensorInfoForOperand(*outputOperand);
134
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100135 bool isSupported = false;
136 FORWARD_LAYER_SUPPORT_FUNC(__func__,
137 IsDivisionSupported,
138 data.m_Backends,
139 isSupported,
140 input0.GetTensorInfo(),
141 input1.GetTensorInfo(),
142 outInfo);
143 if (!isSupported)
arovir01b0717b52018-09-05 17:03:25 +0100144 {
145 return false;
146 }
147
148 armnn::IConnectableLayer* const startLayer = data.m_Network->AddDivisionLayer();
149 armnn::IConnectableLayer* const endLayer = ProcessActivation(outInfo, activationFunction, startLayer, data);
150
151 const armnn::TensorInfo& inputTensorInfo0 = input0.GetTensorInfo();
152 const armnn::TensorInfo& inputTensorInfo1 = input1.GetTensorInfo();
153
154 if (endLayer)
155 {
156 BroadcastTensor(input0, input1, startLayer, *data.m_Network);
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100157 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *endLayer, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100158 }
159
160 return Fail("%s: ProcessActivation failed", __func__);
161}
162
David Beck38e12942018-09-12 16:02:24 +0100163bool HalPolicy::ConvertSub(const Operation& operation, const Model& model, ConversionData& data)
164{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100165 ALOGV("hal_1_1::HalPolicy::ConvertSub()");
166
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100167 LayerInputHandle input0 = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
168 LayerInputHandle input1 = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 1, model, data);
David Beck38e12942018-09-12 16:02:24 +0100169
170 if (!input0.IsValid() || !input1.IsValid())
171 {
172 return Fail("%s: Operation has invalid inputs", __func__);
173 }
174
175 // The FuseActivation parameter is always the input index 2
176 // and it should be optional
177 ActivationFn activationFunction;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100178 if (!GetOptionalInputActivation<hal_1_1::HalPolicy>(operation, 2, activationFunction, model, data))
David Beck38e12942018-09-12 16:02:24 +0100179 {
180 return Fail("%s: Operation has invalid inputs", __func__);
181 }
182
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100183 const Operand* outputOperand = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
David Beck38e12942018-09-12 16:02:24 +0100184 if (!outputOperand)
185 {
186 return false;
187 }
188
Sadik Armagan5e9521c2019-07-12 13:55:57 +0100189 armnn::TensorInfo outputInfo = GetTensorInfoForOperand(*outputOperand);
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +0100190 if (IsDynamicTensor(outputInfo))
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100191 {
Sadik Armagan5e9521c2019-07-12 13:55:57 +0100192 ALOGD("Output shape not set, will infer from inputs");
193 outputInfo.SetShape(InferSubOutputShape(input0.GetTensorInfo().GetShape(), input1.GetTensorInfo().GetShape()));
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100194 }
David Beck38e12942018-09-12 16:02:24 +0100195
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100196 bool isSupported = false;
197 FORWARD_LAYER_SUPPORT_FUNC(__func__,
198 IsSubtractionSupported,
199 data.m_Backends,
200 isSupported,
201 input0.GetTensorInfo(),
202 input1.GetTensorInfo(),
203 outputInfo);
204 if (!isSupported)
David Beck38e12942018-09-12 16:02:24 +0100205 {
206 return false;
207 }
208
209 armnn::IConnectableLayer* const startLayer = data.m_Network->AddSubtractionLayer();
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100210 armnn::IConnectableLayer* const endLayer = ProcessActivation(outputInfo, activationFunction, startLayer, data);
David Beck38e12942018-09-12 16:02:24 +0100211
212 const armnn::TensorInfo& inputTensorInfo0 = input0.GetTensorInfo();
213 const armnn::TensorInfo& inputTensorInfo1 = input1.GetTensorInfo();
214
215 if (endLayer)
216 {
217 BroadcastTensor(input0, input1, startLayer, *data.m_Network);
Sadik Armagan5e9521c2019-07-12 13:55:57 +0100218 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation,
219 0,
220 *endLayer,
221 model,
222 data,
223 armnn::Optional<armnn::TensorInfo>(outputInfo));
David Beck38e12942018-09-12 16:02:24 +0100224 }
225
226 return Fail("%s: ProcessActivation failed", __func__);
227}
228
narpra013c052562018-09-17 14:25:04 +0100229bool HalPolicy::ConvertMean(const Operation& operation, const Model& model, ConversionData& data)
230{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100231 ALOGV("hal_1_1::HalPolicy::ConvertMean()");
232
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100233 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
narpra013c052562018-09-17 14:25:04 +0100234 if (!input.IsValid())
235 {
236 return Fail("%s: Operation has invalid inputs", __func__);
237 }
238
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100239 const Operand* axisOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
Matteo Martincighae622b72018-10-23 18:25:38 +0100240 if (!axisOperand)
241 {
242 return Fail("%s: Could not read input 1", __func__);
243 }
244
245 std::vector<int32_t> axis;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100246 if (!GetTensorInt32Values<hal_1_1::HalPolicy>(*axisOperand, axis, model, data))
Matteo Martincighae622b72018-10-23 18:25:38 +0100247 {
248 return Fail("%s: Input 1 has invalid values", __func__);
249 }
250
251 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
252
253 // Convert the axis to unsigned int and remove duplicates.
254 unsigned int rank = inputInfo.GetNumDimensions();
255 std::set<unsigned int> uniqueAxis;
256 std::transform(axis.begin(), axis.end(),
257 std::inserter(uniqueAxis, uniqueAxis.begin()),
258 [rank](int i) -> unsigned int { return (i + rank) % rank; });
259
260 // Get the "keep dims" flag.
261 int32_t keepDims = 0;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100262 if (!GetInputInt32<hal_1_1::HalPolicy>(operation, 2, keepDims, model, data))
Matteo Martincighae622b72018-10-23 18:25:38 +0100263 {
264 return Fail("%s: Could not read input 2", __func__);
265 }
narpra013c052562018-09-17 14:25:04 +0100266
267 armnn::MeanDescriptor descriptor;
Matteo Martincighae622b72018-10-23 18:25:38 +0100268 descriptor.m_Axis.assign(uniqueAxis.begin(), uniqueAxis.end());
269 descriptor.m_KeepDims = keepDims > 0;
narpra013c052562018-09-17 14:25:04 +0100270
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100271 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
narpra013c052562018-09-17 14:25:04 +0100272 if (!output)
273 {
274 return Fail("%s: Could not read output 0", __func__);
275 }
276
277 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
278
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100279 bool isSupported = false;
280 FORWARD_LAYER_SUPPORT_FUNC(__func__,
281 IsMeanSupported,
282 data.m_Backends,
283 isSupported,
284 inputInfo,
285 outputInfo,
286 descriptor);
287 if (!isSupported)
narpra013c052562018-09-17 14:25:04 +0100288 {
289 return false;
290 }
291
292 armnn::IConnectableLayer* const layer = data.m_Network->AddMeanLayer(descriptor);
narpra0196bedf02018-09-26 16:57:28 +0100293 assert(layer != nullptr);
294 input.Connect(layer->GetInputSlot(0));
narpra013c052562018-09-17 14:25:04 +0100295
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100296 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
narpra013c052562018-09-17 14:25:04 +0100297}
298
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100299bool HalPolicy::ConvertPad(const Operation& operation, const Model& model, ConversionData& data)
300{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100301 ALOGV("hal_1_1::HalPolicy::ConvertPad()");
302
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100303 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100304 if (!input.IsValid())
305 {
306 return Fail("%s: Operation has invalid inputs", __func__);
307 }
308
309 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100310 unsigned int rank = inputInfo.GetNumDimensions();
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100311
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100312 armnn::PadDescriptor descriptor;
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100313 if (!ConvertPaddings<hal_1_1::HalPolicy>(operation, model, data, rank, descriptor))
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100314 {
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100315 return Fail("%s: Could not convert paddings", __func__);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100316 }
317
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100318 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100319 if (!output)
320 {
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100321 return Fail("%s: Could not read output", __func__);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100322 }
323
Sadik Armagan310d8ff2019-07-11 10:53:38 +0100324 armnn::TensorInfo outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +0100325 if (IsDynamicTensor(outputInfo))
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100326 {
Sadik Armagan310d8ff2019-07-11 10:53:38 +0100327 ALOGD("Output shape not set, will infer from inputs");
328 outputInfo.SetShape(InferPadOutputShape(inputInfo.GetShape(), descriptor.m_PadList));
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100329 }
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100330
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100331 bool isSupported = false;
332 FORWARD_LAYER_SUPPORT_FUNC(__func__,
333 IsPadSupported,
334 data.m_Backends,
335 isSupported,
336 inputInfo,
337 outputInfo,
338 descriptor);
339 if (!isSupported)
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100340 {
341 return false;
342 }
343
344 armnn::IConnectableLayer* const layer = data.m_Network->AddPadLayer(descriptor);
345 assert(layer != nullptr);
346 input.Connect(layer->GetInputSlot(0));
347 layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
348
Sadik Armagan310d8ff2019-07-11 10:53:38 +0100349 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation,
350 0,
351 *layer,
352 model,
353 data,
354 armnn::Optional<armnn::TensorInfo>(outputInfo));
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100355}
356
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000357bool HalPolicy::ConvertSpaceToBatchNd(const Operation& operation, const Model& model, ConversionData& data)
358{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100359 ALOGV("hal_1_1::HalPolicy::ConvertSpaceToBatchNd()");
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000360
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100361 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000362 if (!input.IsValid())
363 {
364 return Fail("%s: Operation has invalid inputs", __func__);
365 }
366
367 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
368 unsigned int rank = inputInfo.GetNumDimensions();
369 unsigned int spatialDim = rank - 2;
370
371 if (rank != 4)
372 {
373 Fail("%s: Only inputs with rank 4 are supported", __func__);
374 }
375
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100376 const Operand* blockShapeOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
377 const Operand* paddingsOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 2, model);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000378
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100379 armnn::TensorShape blockShapeOperandShape = GetTensorShapeForOperand(*blockShapeOperand);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000380 if (blockShapeOperandShape.GetNumDimensions() != 1 || blockShapeOperandShape.GetNumElements() != spatialDim)
381 {
382 return Fail("%s: Operation has invalid block shape operand: expected shape [%d]", __func__, spatialDim);
383 }
384
385 std::vector<int32_t> blockShape;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100386 GetTensorInt32Values<hal_1_1::HalPolicy>(*blockShapeOperand, blockShape, model, data);
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000387 if (std::any_of(blockShape.cbegin(), blockShape.cend(), [](int32_t i){ return i < 1; }))
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000388 {
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000389 return Fail("%s: Block shape must be at least 1 in all dimensions.", __func__);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000390 }
391
392 armnn::TensorShape paddingsOperandShape = GetTensorShapeForOperand(*paddingsOperand);
393 if (paddingsOperandShape.GetNumDimensions() != 2 || paddingsOperandShape.GetNumElements() != 2 * spatialDim)
394 {
395 return Fail("%s: Operation has invalid paddings operand: expected shape [%d, 2]", __func__, spatialDim);
396 }
397
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000398 std::vector<std::pair<unsigned int, unsigned int>> paddingList;
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000399 std::vector<int32_t> paddings;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100400 GetTensorInt32Values<hal_1_1::HalPolicy>(*paddingsOperand, paddings, model, data);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000401 for (unsigned int i = 0; i < paddings.size() - 1; i += 2)
402 {
403 int paddingBeforeInput = paddings[i];
404 int paddingAfterInput = paddings[i + 1];
405 if (paddingBeforeInput < 0 || paddingAfterInput < 0)
406 {
407 return Fail("%s: Operation has invalid paddings operand, invalid padding values.", __func__);
408 }
409
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000410 paddingList.emplace_back((unsigned int) paddingBeforeInput, (unsigned int) paddingAfterInput);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000411 }
412
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000413 armnn::SpaceToBatchNdDescriptor descriptor;
414 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
415 descriptor.m_BlockShape.assign(blockShape.cbegin(), blockShape.cend());
416 descriptor.m_PadList.assign(paddingList.cbegin(), paddingList.cend());
417
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100418 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000419 if (!output)
420 {
421 return Fail("%s: Could not read output 0", __func__);
422 }
423
424 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100425
426 bool isSupported = false;
427 FORWARD_LAYER_SUPPORT_FUNC(__func__,
428 IsSpaceToBatchNdSupported,
429 data.m_Backends,
430 isSupported,
431 inputInfo,
432 outputInfo,
433 descriptor);
434 if (!isSupported)
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000435 {
436 return false;
437 }
438
439 armnn::IConnectableLayer* const layer = data.m_Network->AddSpaceToBatchNdLayer(descriptor);
440 assert(layer != nullptr);
441 input.Connect(layer->GetInputSlot(0));
442
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100443 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000444}
445
saoste01b8471482018-10-10 09:44:51 +0100446bool HalPolicy::ConvertSqueeze(const Operation& operation, const Model& model, ConversionData& data)
447{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100448 ALOGV("hal_1_1::HalPolicy::ConvertSqueeze()");
saoste01b8471482018-10-10 09:44:51 +0100449
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100450 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
saoste01b8471482018-10-10 09:44:51 +0100451 if (!input.IsValid())
452 {
453 return Fail("%s: Operation has invalid inputs", __func__);
454 }
455
456 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
457
458 unsigned int rank = inputInfo.GetNumDimensions();
saoste01fe463152018-10-18 17:49:56 +0100459 if (rank > 4)
saoste01b8471482018-10-10 09:44:51 +0100460 {
saoste01fe463152018-10-18 17:49:56 +0100461 Fail("%s: Inputs with rank greater than 4 are not supported", __func__);
saoste01b8471482018-10-10 09:44:51 +0100462 }
463
464 // NOTE: Axis is an optional parameter to SQUEEZE, therefore we do not want to generate a failure
465 // if the operand index is out of bounds.
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100466 const Operand* axisOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model, false);
saoste01b8471482018-10-10 09:44:51 +0100467
saoste01fe463152018-10-18 17:49:56 +0100468 const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
469
saoste01b8471482018-10-10 09:44:51 +0100470 std::vector<int32_t> axis;
saoste01fe463152018-10-18 17:49:56 +0100471 if (!axisOperand)
saoste01b8471482018-10-10 09:44:51 +0100472 {
473 axis.assign(dimensionSequence,
saoste01fe463152018-10-18 17:49:56 +0100474 dimensionSequence + rank);
saoste01b8471482018-10-10 09:44:51 +0100475 }
476 else
477 {
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100478 GetTensorInt32Values<hal_1_1::HalPolicy>(*axisOperand, axis, model, data);
saoste01b8471482018-10-10 09:44:51 +0100479 }
480
saoste01b8471482018-10-10 09:44:51 +0100481
saoste01a893efa2018-10-13 11:56:12 +0100482 std::vector<uint32_t> outputDims;
saoste01fe463152018-10-18 17:49:56 +0100483 for (unsigned int i = 0; i < rank; i++)
saoste01a893efa2018-10-13 11:56:12 +0100484 {
485 bool skipSqueeze = (std::find(axis.begin(), axis.end(), i) == axis.end());
486 auto currentDimension = inputInfo.GetShape()[i];
saoste01b8471482018-10-10 09:44:51 +0100487 if (skipSqueeze || currentDimension != 1)
488 {
489 outputDims.push_back(currentDimension);
490 }
491 }
492
saoste01fe463152018-10-18 17:49:56 +0100493 armnn::TensorShape outShape = armnn::TensorShape(outputDims.size(), outputDims.data());
saoste01b8471482018-10-10 09:44:51 +0100494
495 armnn::TensorInfo outputInfo = inputInfo;
496 outputInfo.SetShape(outShape);
497
498 armnn::ReshapeDescriptor reshapeDesc;
499 reshapeDesc.m_TargetShape = outputInfo.GetShape();
500
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100501 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
saoste01b8471482018-10-10 09:44:51 +0100502 if (!output)
503 {
504 return Fail("%s: Could not read output 0", __func__);
505 }
506
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100507 bool isSupported = false;
508 FORWARD_LAYER_SUPPORT_FUNC(__func__,
509 IsReshapeSupported,
510 data.m_Backends,
511 isSupported,
512 inputInfo,
513 reshapeDesc);
514 if (!isSupported)
saoste01b8471482018-10-10 09:44:51 +0100515 {
516 return false;
517 }
518
519 armnn::IConnectableLayer* const layer = data.m_Network->AddReshapeLayer(reshapeDesc);
520 assert(layer != nullptr);
521 input.Connect(layer->GetInputSlot(0));
saoste01fe463152018-10-18 17:49:56 +0100522
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100523 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
saoste01fe463152018-10-18 17:49:56 +0100524}
525
Sadik Armagan758eee82018-11-15 15:34:49 +0000526bool HalPolicy::ConvertStridedSlice(const Operation& operation, const Model& model, ConversionData& data)
527{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100528 ALOGV("hal_1_1::HalPolicy::ConvertStridedSlice()");
529
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100530 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
Sadik Armagan758eee82018-11-15 15:34:49 +0000531 if (!input.IsValid())
532 {
533 return Fail("%s: Operation has invalid inputs", __func__);
534 }
Sadik Armagan758eee82018-11-15 15:34:49 +0000535
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100536 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
Sadik Armagan758eee82018-11-15 15:34:49 +0000537 unsigned int rank = inputInfo.GetNumDimensions();
538 if (rank > 4)
539 {
540 Fail("%s: Inputs with rank greater than 4 are not supported", __func__);
541 }
542
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100543 const Operand* beginOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
544 const Operand* endOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 2, model);
545 const Operand* stridesOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 3, model);
Sadik Armagan758eee82018-11-15 15:34:49 +0000546
547 std::vector<int32_t> beginValues;
548 std::vector<int32_t> endValues;
549 std::vector<int32_t> stridesValues;
550
551 // The length of the beginOperand, endOperand and stridesOperand must be of a rank(input)
552 auto ValidateInputOperands = [&] (const Operand& operand, std::vector<int32_t>& operandValues)
553 {
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100554 if (!GetTensorInt32Values<hal_1_1::HalPolicy>(operand, operandValues, model, data))
Sadik Armagan758eee82018-11-15 15:34:49 +0000555 {
556 return false;
557 }
558
559 if (operandValues.size() != rank)
560 {
561 return false;
562 }
563
564 return true;
565 };
566
567 if (!ValidateInputOperands(*beginOperand, beginValues)
568 || !ValidateInputOperands(*endOperand, endValues)
569 || !ValidateInputOperands(*stridesOperand, stridesValues))
570 {
571 return Fail("%s: Operation has invalid input operand", __func__);
572 }
573
574 // Stride cannot have value '0'
575 if (std::any_of(stridesValues.cbegin(), stridesValues.cend(), [](int32_t i){ return i == 0; }))
576 {
577 return Fail("%s: Stride must be non-zero value.", __func__);
578 }
579
580 armnn::StridedSliceDescriptor descriptor;
581 descriptor.m_Begin.assign(beginValues.cbegin(), beginValues.cend());
582 descriptor.m_End.assign(endValues.cbegin(), endValues.cend());
583 descriptor.m_Stride.assign(stridesValues.cbegin(), stridesValues.cend());
584 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
585
586 // Get the "begin_mask", "end_mask", and "shrink_axis_mask" flags
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100587 if (!GetInputInt32<hal_1_1::HalPolicy>(operation, 4, descriptor.m_BeginMask, model, data) ||
588 !GetInputInt32<hal_1_1::HalPolicy>(operation, 5, descriptor.m_EndMask, model, data) ||
589 !GetInputInt32<hal_1_1::HalPolicy>(operation, 6, descriptor.m_ShrinkAxisMask, model, data))
Sadik Armagan758eee82018-11-15 15:34:49 +0000590 {
591 return Fail("%s: Operation has invalid inputs", __func__);
592 }
593
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100594 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
Sadik Armagan758eee82018-11-15 15:34:49 +0000595 if (!output)
596 {
597 return Fail("%s: Could not read output 0", __func__);
598 }
599 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
600
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100601 bool isSupported = false;
602 FORWARD_LAYER_SUPPORT_FUNC(__func__,
603 IsStridedSliceSupported,
604 data.m_Backends,
605 isSupported,
606 inputInfo,
607 outputInfo,
608 descriptor);
609 if (!isSupported)
Sadik Armagan758eee82018-11-15 15:34:49 +0000610 {
611 return false;
612 }
613
614 armnn::IConnectableLayer* const layer = data.m_Network->AddStridedSliceLayer(descriptor);
615 assert(layer != nullptr);
616 input.Connect(layer->GetInputSlot(0));
617
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100618 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
Sadik Armagan758eee82018-11-15 15:34:49 +0000619}
620
saoste01fe463152018-10-18 17:49:56 +0100621bool HalPolicy::ConvertTranspose(const Operation& operation, const Model& model, ConversionData& data)
622{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100623 ALOGV("hal_1_1::HalPolicy::ConvertTranspose()");
saoste01fe463152018-10-18 17:49:56 +0100624
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100625 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
saoste01fe463152018-10-18 17:49:56 +0100626 if (!input.IsValid())
627 {
628 return Fail("%s: Operation has invalid inputs", __func__);
629 }
630
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100631 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
saoste01fe463152018-10-18 17:49:56 +0100632 unsigned int rank = inputInfo.GetNumDimensions();
633 if (rank > 4)
634 {
635 Fail("%s: Inputs with rank greater than 4 are not supported", __func__);
636 }
637
638 // NOTE: Axis is an optional parameter to TRANSPOSE, therefore we do not want to generate a failure
639 // if the operand index is out of bounds.
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100640 const Operand* permOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model, false);
saoste01fe463152018-10-18 17:49:56 +0100641
642 std::vector<int32_t> perm(rank);
643 if (!permOperand)
644 {
645 // NOTE: If perm is not given, it is set to (n-1...0), where n is the rank of the tensor
646 for (unsigned int i = rank; i > 0; i--)
647 {
648 perm[rank - i] = boost::numeric_cast<int> (i - 1);
649 }
650 }
651 else
652 {
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100653 GetTensorInt32Values<hal_1_1::HalPolicy>(*permOperand, perm, model, data);
saoste01fe463152018-10-18 17:49:56 +0100654 }
655
656 std::vector<uint32_t> outputDims(perm.begin(), perm.begin() + rank);
657
658 auto permutationVector = armnn::PermutationVector(outputDims.data(), outputDims.size());
659 if (!permutationVector.IsEqual(NHWCToArmNN)
660 && !permutationVector.IsEqual(ArmNNToNHWC)
661 && !permutationVector.IsEqual({ 3, 2, 0, 1 }))
662 {
663 return Fail("%s: Only [0, 3, 1, 2], [0, 2, 3, 1] and [3, 2, 0, 1] permutations are supported.", __func__);
664 }
665
666 armnn::PermuteDescriptor permuteDesc;
667 permuteDesc.m_DimMappings = permutationVector;
668
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100669 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
saoste01fe463152018-10-18 17:49:56 +0100670 if (!output)
671 {
672 return Fail("%s: Could not read output 0", __func__);
673 }
674
675 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
676
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100677 bool isSupported = false;
678 FORWARD_LAYER_SUPPORT_FUNC(__func__,
679 IsPermuteSupported,
680 data.m_Backends,
681 isSupported,
682 inputInfo,
683 outputInfo,
684 permuteDesc);
685 if (!isSupported)
saoste01fe463152018-10-18 17:49:56 +0100686 {
687 return false;
688 }
689
690 armnn::IConnectableLayer* const layer = data.m_Network->AddPermuteLayer(permuteDesc);
691 assert(layer != nullptr);
692 input.Connect(layer->GetInputSlot(0));
saoste01b8471482018-10-10 09:44:51 +0100693
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100694 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
saoste01b8471482018-10-10 09:44:51 +0100695}
696
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000697bool HalPolicy::ConvertBatchToSpaceNd(const Operation& operation, const Model& model, ConversionData& data)
698{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100699 ALOGV("hal_1_1::HalPolicy::ConvertBatchToSpaceNd()");
700
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100701 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000702 if (!input.IsValid())
703 {
704 return Fail("%s: Operation has invalid inputs", __func__);
705 }
706
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100707 const Operand* blockOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000708 if (!blockOperand)
709 {
710 return Fail("%s: Could not read input 1", __func__);
711 }
712
713 // Convert the block operand to int32
714 std::vector<int32_t> block;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100715 if (!GetTensorInt32Values<hal_1_1::HalPolicy>(*blockOperand, block, model, data))
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000716 {
717 return Fail("%s: Input 1 has invalid values", __func__);
718 }
719
720 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
721
722 unsigned int rank = inputInfo.GetNumDimensions();
723 if (rank != 4)
724 {
725 Fail("%s: Only inputs with rank equal to 4 are supported", __func__);
726 }
727
728 if (std::any_of(block.cbegin(), block.cend(), [](int32_t i){ return i < 1; }))
729 {
730 return Fail("%s: Block sizes for each spatial dimension of the input tensor must be"
731 " greater than or equal to 1", __func__);
732 }
733
734 armnn::BatchToSpaceNdDescriptor batchToSpaceNdDesc;
735 batchToSpaceNdDesc.m_BlockShape.assign(block.cbegin(), block.cend());
736 batchToSpaceNdDesc.m_DataLayout = armnn::DataLayout::NHWC;
737
738 // Setting crops to 0,0 0,0 as it is not supported in Android NN API
739 batchToSpaceNdDesc.m_Crops = {{0, 0}, {0, 0}};
740
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100741 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000742 if (!output)
743 {
744 return Fail("%s: Could not read output 0", __func__);
745 }
746
747 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
748
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100749 bool isSupported = false;
750 FORWARD_LAYER_SUPPORT_FUNC(__func__,
751 IsBatchToSpaceNdSupported,
752 data.m_Backends,
753 isSupported,
754 inputInfo,
755 outputInfo,
756 batchToSpaceNdDesc);
757 if (!isSupported)
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000758 {
759 return false;
760 }
761
762 armnn::IConnectableLayer* const layer = data.m_Network->AddBatchToSpaceNdLayer(batchToSpaceNdDesc);
763 assert(layer != nullptr);
764 input.Connect(layer->GetInputSlot(0));
765
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100766 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000767}
768
arovir01b0717b52018-09-05 17:03:25 +0100769} // namespace hal_1_1
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100770} // namespace armnn_driver