blob: 6687b1236dad31b98d5a11668532c2b46e7b087e [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-Tarcd700e42019-06-14 14:54:52 +0100109 LayerInputHandle input0 = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
110 LayerInputHandle input1 = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 1, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100111
112 if (!input0.IsValid() || !input1.IsValid())
113 {
114 return Fail("%s: Operation has invalid inputs", __func__);
115 }
116
117 // The FuseActivation parameter is always the input index 2
118 // and it should be optional
119 ActivationFn activationFunction;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100120 if (!GetOptionalInputActivation<hal_1_1::HalPolicy>(operation, 2, activationFunction, model, data))
arovir01b0717b52018-09-05 17:03:25 +0100121 {
122 return Fail("%s: Operation has invalid inputs", __func__);
123 }
124
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100125 const Operand* outputOperand = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
arovir01b0717b52018-09-05 17:03:25 +0100126 if (!outputOperand)
127 {
128 return false;
129 }
130
131 const armnn::TensorInfo& outInfo = GetTensorInfoForOperand(*outputOperand);
132
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100133 bool isSupported = false;
134 FORWARD_LAYER_SUPPORT_FUNC(__func__,
135 IsDivisionSupported,
136 data.m_Backends,
137 isSupported,
138 input0.GetTensorInfo(),
139 input1.GetTensorInfo(),
140 outInfo);
141 if (!isSupported)
arovir01b0717b52018-09-05 17:03:25 +0100142 {
143 return false;
144 }
145
146 armnn::IConnectableLayer* const startLayer = data.m_Network->AddDivisionLayer();
147 armnn::IConnectableLayer* const endLayer = ProcessActivation(outInfo, activationFunction, startLayer, data);
148
149 const armnn::TensorInfo& inputTensorInfo0 = input0.GetTensorInfo();
150 const armnn::TensorInfo& inputTensorInfo1 = input1.GetTensorInfo();
151
152 if (endLayer)
153 {
154 BroadcastTensor(input0, input1, startLayer, *data.m_Network);
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100155 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *endLayer, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100156 }
157
158 return Fail("%s: ProcessActivation failed", __func__);
159}
160
David Beck38e12942018-09-12 16:02:24 +0100161bool HalPolicy::ConvertSub(const Operation& operation, const Model& model, ConversionData& data)
162{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100163 LayerInputHandle input0 = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
164 LayerInputHandle input1 = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 1, model, data);
David Beck38e12942018-09-12 16:02:24 +0100165
166 if (!input0.IsValid() || !input1.IsValid())
167 {
168 return Fail("%s: Operation has invalid inputs", __func__);
169 }
170
171 // The FuseActivation parameter is always the input index 2
172 // and it should be optional
173 ActivationFn activationFunction;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100174 if (!GetOptionalInputActivation<hal_1_1::HalPolicy>(operation, 2, activationFunction, model, data))
David Beck38e12942018-09-12 16:02:24 +0100175 {
176 return Fail("%s: Operation has invalid inputs", __func__);
177 }
178
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100179 const Operand* outputOperand = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
David Beck38e12942018-09-12 16:02:24 +0100180 if (!outputOperand)
181 {
182 return false;
183 }
184
Sadik Armagan5e9521c2019-07-12 13:55:57 +0100185 armnn::TensorInfo outputInfo = GetTensorInfoForOperand(*outputOperand);
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +0100186 if (IsDynamicTensor(outputInfo))
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100187 {
Sadik Armagan5e9521c2019-07-12 13:55:57 +0100188 ALOGD("Output shape not set, will infer from inputs");
189 outputInfo.SetShape(InferSubOutputShape(input0.GetTensorInfo().GetShape(), input1.GetTensorInfo().GetShape()));
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100190 }
David Beck38e12942018-09-12 16:02:24 +0100191
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100192 bool isSupported = false;
193 FORWARD_LAYER_SUPPORT_FUNC(__func__,
194 IsSubtractionSupported,
195 data.m_Backends,
196 isSupported,
197 input0.GetTensorInfo(),
198 input1.GetTensorInfo(),
199 outputInfo);
200 if (!isSupported)
David Beck38e12942018-09-12 16:02:24 +0100201 {
202 return false;
203 }
204
205 armnn::IConnectableLayer* const startLayer = data.m_Network->AddSubtractionLayer();
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100206 armnn::IConnectableLayer* const endLayer = ProcessActivation(outputInfo, activationFunction, startLayer, data);
David Beck38e12942018-09-12 16:02:24 +0100207
208 const armnn::TensorInfo& inputTensorInfo0 = input0.GetTensorInfo();
209 const armnn::TensorInfo& inputTensorInfo1 = input1.GetTensorInfo();
210
211 if (endLayer)
212 {
213 BroadcastTensor(input0, input1, startLayer, *data.m_Network);
Sadik Armagan5e9521c2019-07-12 13:55:57 +0100214 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation,
215 0,
216 *endLayer,
217 model,
218 data,
219 armnn::Optional<armnn::TensorInfo>(outputInfo));
David Beck38e12942018-09-12 16:02:24 +0100220 }
221
222 return Fail("%s: ProcessActivation failed", __func__);
223}
224
narpra013c052562018-09-17 14:25:04 +0100225bool HalPolicy::ConvertMean(const Operation& operation, const Model& model, ConversionData& data)
226{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100227 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
narpra013c052562018-09-17 14:25:04 +0100228 if (!input.IsValid())
229 {
230 return Fail("%s: Operation has invalid inputs", __func__);
231 }
232
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100233 const Operand* axisOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
Matteo Martincighae622b72018-10-23 18:25:38 +0100234 if (!axisOperand)
235 {
236 return Fail("%s: Could not read input 1", __func__);
237 }
238
239 std::vector<int32_t> axis;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100240 if (!GetTensorInt32Values<hal_1_1::HalPolicy>(*axisOperand, axis, model, data))
Matteo Martincighae622b72018-10-23 18:25:38 +0100241 {
242 return Fail("%s: Input 1 has invalid values", __func__);
243 }
244
245 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
246
247 // Convert the axis to unsigned int and remove duplicates.
248 unsigned int rank = inputInfo.GetNumDimensions();
249 std::set<unsigned int> uniqueAxis;
250 std::transform(axis.begin(), axis.end(),
251 std::inserter(uniqueAxis, uniqueAxis.begin()),
252 [rank](int i) -> unsigned int { return (i + rank) % rank; });
253
254 // Get the "keep dims" flag.
255 int32_t keepDims = 0;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100256 if (!GetInputInt32<hal_1_1::HalPolicy>(operation, 2, keepDims, model, data))
Matteo Martincighae622b72018-10-23 18:25:38 +0100257 {
258 return Fail("%s: Could not read input 2", __func__);
259 }
narpra013c052562018-09-17 14:25:04 +0100260
261 armnn::MeanDescriptor descriptor;
Matteo Martincighae622b72018-10-23 18:25:38 +0100262 descriptor.m_Axis.assign(uniqueAxis.begin(), uniqueAxis.end());
263 descriptor.m_KeepDims = keepDims > 0;
narpra013c052562018-09-17 14:25:04 +0100264
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100265 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
narpra013c052562018-09-17 14:25:04 +0100266 if (!output)
267 {
268 return Fail("%s: Could not read output 0", __func__);
269 }
270
271 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
272
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100273 bool isSupported = false;
274 FORWARD_LAYER_SUPPORT_FUNC(__func__,
275 IsMeanSupported,
276 data.m_Backends,
277 isSupported,
278 inputInfo,
279 outputInfo,
280 descriptor);
281 if (!isSupported)
narpra013c052562018-09-17 14:25:04 +0100282 {
283 return false;
284 }
285
286 armnn::IConnectableLayer* const layer = data.m_Network->AddMeanLayer(descriptor);
narpra0196bedf02018-09-26 16:57:28 +0100287 assert(layer != nullptr);
288 input.Connect(layer->GetInputSlot(0));
narpra013c052562018-09-17 14:25:04 +0100289
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100290 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
narpra013c052562018-09-17 14:25:04 +0100291}
292
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100293bool HalPolicy::ConvertPad(const Operation& operation, const Model& model, ConversionData& data)
294{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100295 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100296 if (!input.IsValid())
297 {
298 return Fail("%s: Operation has invalid inputs", __func__);
299 }
300
301 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100302 unsigned int rank = inputInfo.GetNumDimensions();
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100303
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100304 armnn::PadDescriptor descriptor;
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100305 if (!ConvertPaddings<hal_1_1::HalPolicy>(operation, model, data, rank, descriptor))
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100306 {
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100307 return Fail("%s: Could not convert paddings", __func__);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100308 }
309
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100310 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100311 if (!output)
312 {
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100313 return Fail("%s: Could not read output", __func__);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100314 }
315
Sadik Armagan310d8ff2019-07-11 10:53:38 +0100316 armnn::TensorInfo outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +0100317 if (IsDynamicTensor(outputInfo))
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100318 {
Sadik Armagan310d8ff2019-07-11 10:53:38 +0100319 ALOGD("Output shape not set, will infer from inputs");
320 outputInfo.SetShape(InferPadOutputShape(inputInfo.GetShape(), descriptor.m_PadList));
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100321 }
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100322
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100323 bool isSupported = false;
324 FORWARD_LAYER_SUPPORT_FUNC(__func__,
325 IsPadSupported,
326 data.m_Backends,
327 isSupported,
328 inputInfo,
329 outputInfo,
330 descriptor);
331 if (!isSupported)
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100332 {
333 return false;
334 }
335
336 armnn::IConnectableLayer* const layer = data.m_Network->AddPadLayer(descriptor);
337 assert(layer != nullptr);
338 input.Connect(layer->GetInputSlot(0));
339 layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
340
Sadik Armagan310d8ff2019-07-11 10:53:38 +0100341 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation,
342 0,
343 *layer,
344 model,
345 data,
346 armnn::Optional<armnn::TensorInfo>(outputInfo));
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100347}
348
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000349bool HalPolicy::ConvertSpaceToBatchNd(const Operation& operation, const Model& model, ConversionData& data)
350{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100351 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000352
353 if (!input.IsValid())
354 {
355 return Fail("%s: Operation has invalid inputs", __func__);
356 }
357
358 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
359 unsigned int rank = inputInfo.GetNumDimensions();
360 unsigned int spatialDim = rank - 2;
361
362 if (rank != 4)
363 {
364 Fail("%s: Only inputs with rank 4 are supported", __func__);
365 }
366
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100367 const Operand* blockShapeOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
368 const Operand* paddingsOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 2, model);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000369
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100370 armnn::TensorShape blockShapeOperandShape = GetTensorShapeForOperand(*blockShapeOperand);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000371 if (blockShapeOperandShape.GetNumDimensions() != 1 || blockShapeOperandShape.GetNumElements() != spatialDim)
372 {
373 return Fail("%s: Operation has invalid block shape operand: expected shape [%d]", __func__, spatialDim);
374 }
375
376 std::vector<int32_t> blockShape;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100377 GetTensorInt32Values<hal_1_1::HalPolicy>(*blockShapeOperand, blockShape, model, data);
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000378 if (std::any_of(blockShape.cbegin(), blockShape.cend(), [](int32_t i){ return i < 1; }))
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000379 {
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000380 return Fail("%s: Block shape must be at least 1 in all dimensions.", __func__);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000381 }
382
383 armnn::TensorShape paddingsOperandShape = GetTensorShapeForOperand(*paddingsOperand);
384 if (paddingsOperandShape.GetNumDimensions() != 2 || paddingsOperandShape.GetNumElements() != 2 * spatialDim)
385 {
386 return Fail("%s: Operation has invalid paddings operand: expected shape [%d, 2]", __func__, spatialDim);
387 }
388
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000389 std::vector<std::pair<unsigned int, unsigned int>> paddingList;
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000390 std::vector<int32_t> paddings;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100391 GetTensorInt32Values<hal_1_1::HalPolicy>(*paddingsOperand, paddings, model, data);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000392 for (unsigned int i = 0; i < paddings.size() - 1; i += 2)
393 {
394 int paddingBeforeInput = paddings[i];
395 int paddingAfterInput = paddings[i + 1];
396 if (paddingBeforeInput < 0 || paddingAfterInput < 0)
397 {
398 return Fail("%s: Operation has invalid paddings operand, invalid padding values.", __func__);
399 }
400
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000401 paddingList.emplace_back((unsigned int) paddingBeforeInput, (unsigned int) paddingAfterInput);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000402 }
403
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000404 armnn::SpaceToBatchNdDescriptor descriptor;
405 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
406 descriptor.m_BlockShape.assign(blockShape.cbegin(), blockShape.cend());
407 descriptor.m_PadList.assign(paddingList.cbegin(), paddingList.cend());
408
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100409 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000410 if (!output)
411 {
412 return Fail("%s: Could not read output 0", __func__);
413 }
414
415 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100416
417 bool isSupported = false;
418 FORWARD_LAYER_SUPPORT_FUNC(__func__,
419 IsSpaceToBatchNdSupported,
420 data.m_Backends,
421 isSupported,
422 inputInfo,
423 outputInfo,
424 descriptor);
425 if (!isSupported)
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000426 {
427 return false;
428 }
429
430 armnn::IConnectableLayer* const layer = data.m_Network->AddSpaceToBatchNdLayer(descriptor);
431 assert(layer != nullptr);
432 input.Connect(layer->GetInputSlot(0));
433
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100434 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000435}
436
saoste01b8471482018-10-10 09:44:51 +0100437bool HalPolicy::ConvertSqueeze(const Operation& operation, const Model& model, ConversionData& data)
438{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100439 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
saoste01b8471482018-10-10 09:44:51 +0100440
441 if (!input.IsValid())
442 {
443 return Fail("%s: Operation has invalid inputs", __func__);
444 }
445
446 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
447
448 unsigned int rank = inputInfo.GetNumDimensions();
saoste01fe463152018-10-18 17:49:56 +0100449 if (rank > 4)
saoste01b8471482018-10-10 09:44:51 +0100450 {
saoste01fe463152018-10-18 17:49:56 +0100451 Fail("%s: Inputs with rank greater than 4 are not supported", __func__);
saoste01b8471482018-10-10 09:44:51 +0100452 }
453
454 // NOTE: Axis is an optional parameter to SQUEEZE, therefore we do not want to generate a failure
455 // if the operand index is out of bounds.
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100456 const Operand* axisOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model, false);
saoste01b8471482018-10-10 09:44:51 +0100457
saoste01fe463152018-10-18 17:49:56 +0100458 const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
459
saoste01b8471482018-10-10 09:44:51 +0100460 std::vector<int32_t> axis;
saoste01fe463152018-10-18 17:49:56 +0100461 if (!axisOperand)
saoste01b8471482018-10-10 09:44:51 +0100462 {
463 axis.assign(dimensionSequence,
saoste01fe463152018-10-18 17:49:56 +0100464 dimensionSequence + rank);
saoste01b8471482018-10-10 09:44:51 +0100465 }
466 else
467 {
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100468 GetTensorInt32Values<hal_1_1::HalPolicy>(*axisOperand, axis, model, data);
saoste01b8471482018-10-10 09:44:51 +0100469 }
470
saoste01b8471482018-10-10 09:44:51 +0100471
saoste01a893efa2018-10-13 11:56:12 +0100472 std::vector<uint32_t> outputDims;
saoste01fe463152018-10-18 17:49:56 +0100473 for (unsigned int i = 0; i < rank; i++)
saoste01a893efa2018-10-13 11:56:12 +0100474 {
475 bool skipSqueeze = (std::find(axis.begin(), axis.end(), i) == axis.end());
476 auto currentDimension = inputInfo.GetShape()[i];
saoste01b8471482018-10-10 09:44:51 +0100477 if (skipSqueeze || currentDimension != 1)
478 {
479 outputDims.push_back(currentDimension);
480 }
481 }
482
saoste01fe463152018-10-18 17:49:56 +0100483 armnn::TensorShape outShape = armnn::TensorShape(outputDims.size(), outputDims.data());
saoste01b8471482018-10-10 09:44:51 +0100484
485 armnn::TensorInfo outputInfo = inputInfo;
486 outputInfo.SetShape(outShape);
487
488 armnn::ReshapeDescriptor reshapeDesc;
489 reshapeDesc.m_TargetShape = outputInfo.GetShape();
490
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100491 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
saoste01b8471482018-10-10 09:44:51 +0100492 if (!output)
493 {
494 return Fail("%s: Could not read output 0", __func__);
495 }
496
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100497 bool isSupported = false;
498 FORWARD_LAYER_SUPPORT_FUNC(__func__,
499 IsReshapeSupported,
500 data.m_Backends,
501 isSupported,
502 inputInfo,
503 reshapeDesc);
504 if (!isSupported)
saoste01b8471482018-10-10 09:44:51 +0100505 {
506 return false;
507 }
508
509 armnn::IConnectableLayer* const layer = data.m_Network->AddReshapeLayer(reshapeDesc);
510 assert(layer != nullptr);
511 input.Connect(layer->GetInputSlot(0));
saoste01fe463152018-10-18 17:49:56 +0100512
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100513 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
saoste01fe463152018-10-18 17:49:56 +0100514}
515
Sadik Armagan758eee82018-11-15 15:34:49 +0000516bool HalPolicy::ConvertStridedSlice(const Operation& operation, const Model& model, ConversionData& data)
517{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100518 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
Sadik Armagan758eee82018-11-15 15:34:49 +0000519 if (!input.IsValid())
520 {
521 return Fail("%s: Operation has invalid inputs", __func__);
522 }
523 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
524
525 unsigned int rank = inputInfo.GetNumDimensions();
526 if (rank > 4)
527 {
528 Fail("%s: Inputs with rank greater than 4 are not supported", __func__);
529 }
530
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100531 const Operand* beginOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
532 const Operand* endOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 2, model);
533 const Operand* stridesOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 3, model);
Sadik Armagan758eee82018-11-15 15:34:49 +0000534
535 std::vector<int32_t> beginValues;
536 std::vector<int32_t> endValues;
537 std::vector<int32_t> stridesValues;
538
539 // The length of the beginOperand, endOperand and stridesOperand must be of a rank(input)
540 auto ValidateInputOperands = [&] (const Operand& operand, std::vector<int32_t>& operandValues)
541 {
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100542 if (!GetTensorInt32Values<hal_1_1::HalPolicy>(operand, operandValues, model, data))
Sadik Armagan758eee82018-11-15 15:34:49 +0000543 {
544 return false;
545 }
546
547 if (operandValues.size() != rank)
548 {
549 return false;
550 }
551
552 return true;
553 };
554
555 if (!ValidateInputOperands(*beginOperand, beginValues)
556 || !ValidateInputOperands(*endOperand, endValues)
557 || !ValidateInputOperands(*stridesOperand, stridesValues))
558 {
559 return Fail("%s: Operation has invalid input operand", __func__);
560 }
561
562 // Stride cannot have value '0'
563 if (std::any_of(stridesValues.cbegin(), stridesValues.cend(), [](int32_t i){ return i == 0; }))
564 {
565 return Fail("%s: Stride must be non-zero value.", __func__);
566 }
567
568 armnn::StridedSliceDescriptor descriptor;
569 descriptor.m_Begin.assign(beginValues.cbegin(), beginValues.cend());
570 descriptor.m_End.assign(endValues.cbegin(), endValues.cend());
571 descriptor.m_Stride.assign(stridesValues.cbegin(), stridesValues.cend());
572 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
573
574 // Get the "begin_mask", "end_mask", and "shrink_axis_mask" flags
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100575 if (!GetInputInt32<hal_1_1::HalPolicy>(operation, 4, descriptor.m_BeginMask, model, data) ||
576 !GetInputInt32<hal_1_1::HalPolicy>(operation, 5, descriptor.m_EndMask, model, data) ||
577 !GetInputInt32<hal_1_1::HalPolicy>(operation, 6, descriptor.m_ShrinkAxisMask, model, data))
Sadik Armagan758eee82018-11-15 15:34:49 +0000578 {
579 return Fail("%s: Operation has invalid inputs", __func__);
580 }
581
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100582 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
Sadik Armagan758eee82018-11-15 15:34:49 +0000583 if (!output)
584 {
585 return Fail("%s: Could not read output 0", __func__);
586 }
587 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
588
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100589 bool isSupported = false;
590 FORWARD_LAYER_SUPPORT_FUNC(__func__,
591 IsStridedSliceSupported,
592 data.m_Backends,
593 isSupported,
594 inputInfo,
595 outputInfo,
596 descriptor);
597 if (!isSupported)
Sadik Armagan758eee82018-11-15 15:34:49 +0000598 {
599 return false;
600 }
601
602 armnn::IConnectableLayer* const layer = data.m_Network->AddStridedSliceLayer(descriptor);
603 assert(layer != nullptr);
604 input.Connect(layer->GetInputSlot(0));
605
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100606 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
Sadik Armagan758eee82018-11-15 15:34:49 +0000607}
608
saoste01fe463152018-10-18 17:49:56 +0100609bool HalPolicy::ConvertTranspose(const Operation& operation, const Model& model, ConversionData& data)
610{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100611 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
saoste01fe463152018-10-18 17:49:56 +0100612
613 if (!input.IsValid())
614 {
615 return Fail("%s: Operation has invalid inputs", __func__);
616 }
617
618 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
619
620 unsigned int rank = inputInfo.GetNumDimensions();
621 if (rank > 4)
622 {
623 Fail("%s: Inputs with rank greater than 4 are not supported", __func__);
624 }
625
626 // NOTE: Axis is an optional parameter to TRANSPOSE, therefore we do not want to generate a failure
627 // if the operand index is out of bounds.
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100628 const Operand* permOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model, false);
saoste01fe463152018-10-18 17:49:56 +0100629
630 std::vector<int32_t> perm(rank);
631 if (!permOperand)
632 {
633 // NOTE: If perm is not given, it is set to (n-1...0), where n is the rank of the tensor
634 for (unsigned int i = rank; i > 0; i--)
635 {
636 perm[rank - i] = boost::numeric_cast<int> (i - 1);
637 }
638 }
639 else
640 {
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100641 GetTensorInt32Values<hal_1_1::HalPolicy>(*permOperand, perm, model, data);
saoste01fe463152018-10-18 17:49:56 +0100642 }
643
644 std::vector<uint32_t> outputDims(perm.begin(), perm.begin() + rank);
645
646 auto permutationVector = armnn::PermutationVector(outputDims.data(), outputDims.size());
647 if (!permutationVector.IsEqual(NHWCToArmNN)
648 && !permutationVector.IsEqual(ArmNNToNHWC)
649 && !permutationVector.IsEqual({ 3, 2, 0, 1 }))
650 {
651 return Fail("%s: Only [0, 3, 1, 2], [0, 2, 3, 1] and [3, 2, 0, 1] permutations are supported.", __func__);
652 }
653
654 armnn::PermuteDescriptor permuteDesc;
655 permuteDesc.m_DimMappings = permutationVector;
656
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100657 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
saoste01fe463152018-10-18 17:49:56 +0100658 if (!output)
659 {
660 return Fail("%s: Could not read output 0", __func__);
661 }
662
663 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
664
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100665 bool isSupported = false;
666 FORWARD_LAYER_SUPPORT_FUNC(__func__,
667 IsPermuteSupported,
668 data.m_Backends,
669 isSupported,
670 inputInfo,
671 outputInfo,
672 permuteDesc);
673 if (!isSupported)
saoste01fe463152018-10-18 17:49:56 +0100674 {
675 return false;
676 }
677
678 armnn::IConnectableLayer* const layer = data.m_Network->AddPermuteLayer(permuteDesc);
679 assert(layer != nullptr);
680 input.Connect(layer->GetInputSlot(0));
saoste01b8471482018-10-10 09:44:51 +0100681
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100682 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
saoste01b8471482018-10-10 09:44:51 +0100683}
684
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000685bool HalPolicy::ConvertBatchToSpaceNd(const Operation& operation, const Model& model, ConversionData& data)
686{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100687 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000688 if (!input.IsValid())
689 {
690 return Fail("%s: Operation has invalid inputs", __func__);
691 }
692
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100693 const Operand* blockOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000694 if (!blockOperand)
695 {
696 return Fail("%s: Could not read input 1", __func__);
697 }
698
699 // Convert the block operand to int32
700 std::vector<int32_t> block;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100701 if (!GetTensorInt32Values<hal_1_1::HalPolicy>(*blockOperand, block, model, data))
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000702 {
703 return Fail("%s: Input 1 has invalid values", __func__);
704 }
705
706 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
707
708 unsigned int rank = inputInfo.GetNumDimensions();
709 if (rank != 4)
710 {
711 Fail("%s: Only inputs with rank equal to 4 are supported", __func__);
712 }
713
714 if (std::any_of(block.cbegin(), block.cend(), [](int32_t i){ return i < 1; }))
715 {
716 return Fail("%s: Block sizes for each spatial dimension of the input tensor must be"
717 " greater than or equal to 1", __func__);
718 }
719
720 armnn::BatchToSpaceNdDescriptor batchToSpaceNdDesc;
721 batchToSpaceNdDesc.m_BlockShape.assign(block.cbegin(), block.cend());
722 batchToSpaceNdDesc.m_DataLayout = armnn::DataLayout::NHWC;
723
724 // Setting crops to 0,0 0,0 as it is not supported in Android NN API
725 batchToSpaceNdDesc.m_Crops = {{0, 0}, {0, 0}};
726
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100727 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000728 if (!output)
729 {
730 return Fail("%s: Could not read output 0", __func__);
731 }
732
733 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
734
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100735 bool isSupported = false;
736 FORWARD_LAYER_SUPPORT_FUNC(__func__,
737 IsBatchToSpaceNdSupported,
738 data.m_Backends,
739 isSupported,
740 inputInfo,
741 outputInfo,
742 batchToSpaceNdDesc);
743 if (!isSupported)
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000744 {
745 return false;
746 }
747
748 armnn::IConnectableLayer* const layer = data.m_Network->AddBatchToSpaceNdLayer(batchToSpaceNdDesc);
749 assert(layer != nullptr);
750 input.Connect(layer->GetInputSlot(0));
751
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100752 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000753}
754
arovir01b0717b52018-09-05 17:03:25 +0100755} // namespace hal_1_1
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100756} // namespace armnn_driver