blob: d7f4bbb8653cd8d8896a67f9d746a26097a5ba18 [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"
9
arovir01b0717b52018-09-05 17:03:25 +010010#include "../1.0/HalPolicy.hpp"
11
Éanna Ó Catháin2fc21f72019-05-13 11:01:33 +010012namespace
13{
14static std::vector<V1_0::OperationType> opsEquivalentInV10({
15 V1_0::OperationType::ADD,
16 V1_0::OperationType::AVERAGE_POOL_2D,
17 V1_0::OperationType::CONCATENATION,
18 V1_0::OperationType::CONV_2D,
19 V1_0::OperationType::DEPTHWISE_CONV_2D,
David Monahand5bfae12019-05-30 12:07:44 +010020 V1_0::OperationType::DEQUANTIZE,
Éanna Ó Catháin2fc21f72019-05-13 11:01:33 +010021 V1_0::OperationType::FLOOR,
22 V1_0::OperationType::FULLY_CONNECTED,
23 V1_0::OperationType::LOCAL_RESPONSE_NORMALIZATION,
24 V1_0::OperationType::LOGISTIC,
25 V1_0::OperationType::LSTM,
26 V1_0::OperationType::L2_NORMALIZATION,
27 V1_0::OperationType::L2_POOL_2D,
28 V1_0::OperationType::MAX_POOL_2D,
29 V1_0::OperationType::MUL,
30 V1_0::OperationType::RELU,
31 V1_0::OperationType::RELU1,
32 V1_0::OperationType::RELU6,
33 V1_0::OperationType::SOFTMAX,
Keith Davisa6bc52f2019-06-26 09:39:49 +010034 V1_0::OperationType::SPACE_TO_DEPTH,
Éanna Ó Catháin2fc21f72019-05-13 11:01:33 +010035 V1_0::OperationType::TANH,
36 V1_0::OperationType::RESHAPE,
37 V1_0::OperationType::RESIZE_BILINEAR,
38});
39
40bool CompliantWithVersion10(const V1_1::Operation & operation)
41{
42 std::vector<V1_0::OperationType>::iterator it;
43 it = std::find(opsEquivalentInV10.begin(), opsEquivalentInV10.end(),
44 static_cast<V1_0::OperationType>(operation.type));
45
46 if(it != opsEquivalentInV10.end())
47 {
48 return true;
49 }
50 return false;
51}
52
53V1_0::Operation ConvertOperationToVersion10(const V1_1::Operation & operation)
54{
55 V1_0::Operation v10Operation;
56 v10Operation.type = static_cast<V1_0::OperationType>(operation.type);
57 v10Operation.inputs = operation.inputs;
58 v10Operation.outputs = operation.outputs;
59 return v10Operation;
60}
61}
62
arovir01b0717b52018-09-05 17:03:25 +010063namespace armnn_driver
64{
65namespace hal_1_1
66{
67
68bool HalPolicy::ConvertOperation(const Operation& operation, const Model& model, ConversionData& data)
69{
Éanna Ó Catháin2fc21f72019-05-13 11:01:33 +010070 if (CompliantWithVersion10(operation))
arovir01b0717b52018-09-05 17:03:25 +010071 {
Éanna Ó Catháin2fc21f72019-05-13 11:01:33 +010072 hal_1_0::HalPolicy::Operation v10Operation = ConvertOperationToVersion10(operation);
arovir01b0717b52018-09-05 17:03:25 +010073 hal_1_0::HalPolicy::Model v10Model = convertToV1_0(model);
74
75 return hal_1_0::HalPolicy::ConvertOperation(v10Operation, v10Model, data);
76 }
77 else
78 {
79 switch (operation.type)
80 {
81 case V1_1::OperationType::DIV:
82 return ConvertDiv(operation, model, data);
David Beck38e12942018-09-12 16:02:24 +010083 case V1_1::OperationType::SUB:
84 return ConvertSub(operation, model, data);
narpra013c052562018-09-17 14:25:04 +010085 case V1_1::OperationType::MEAN:
86 return ConvertMean(operation, model, data);
Nina Drozd62a4a9f2018-10-01 14:20:25 +010087 case V1_1::OperationType::PAD:
88 return ConvertPad(operation, model, data);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +000089 case V1_1::OperationType::SPACE_TO_BATCH_ND:
90 return ConvertSpaceToBatchNd(operation, model, data);
saoste01b8471482018-10-10 09:44:51 +010091 case V1_1::OperationType::SQUEEZE:
92 return ConvertSqueeze(operation, model, data);
Sadik Armagan758eee82018-11-15 15:34:49 +000093 case V1_1::OperationType::STRIDED_SLICE:
94 return ConvertStridedSlice(operation, model, data);
saoste01fe463152018-10-18 17:49:56 +010095 case V1_1::OperationType::TRANSPOSE:
96 return ConvertTranspose(operation, model, data);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +000097 case V1_1::OperationType::BATCH_TO_SPACE_ND:
98 return ConvertBatchToSpaceNd(operation, model, data);
arovir01b0717b52018-09-05 17:03:25 +010099 default:
100 return Fail("%s: Operation type %s not supported in ArmnnDriver",
101 __func__, toString(operation.type).c_str());
102 }
103 }
104}
105
106bool HalPolicy::ConvertDiv(const Operation& operation, const Model& model, ConversionData& data)
107{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100108 LayerInputHandle input0 = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
109 LayerInputHandle input1 = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 1, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100110
111 if (!input0.IsValid() || !input1.IsValid())
112 {
113 return Fail("%s: Operation has invalid inputs", __func__);
114 }
115
116 // The FuseActivation parameter is always the input index 2
117 // and it should be optional
118 ActivationFn activationFunction;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100119 if (!GetOptionalInputActivation<hal_1_1::HalPolicy>(operation, 2, activationFunction, model, data))
arovir01b0717b52018-09-05 17:03:25 +0100120 {
121 return Fail("%s: Operation has invalid inputs", __func__);
122 }
123
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100124 const Operand* outputOperand = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
arovir01b0717b52018-09-05 17:03:25 +0100125 if (!outputOperand)
126 {
127 return false;
128 }
129
130 const armnn::TensorInfo& outInfo = GetTensorInfoForOperand(*outputOperand);
131
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100132 bool isSupported = false;
133 FORWARD_LAYER_SUPPORT_FUNC(__func__,
134 IsDivisionSupported,
135 data.m_Backends,
136 isSupported,
137 input0.GetTensorInfo(),
138 input1.GetTensorInfo(),
139 outInfo);
140 if (!isSupported)
arovir01b0717b52018-09-05 17:03:25 +0100141 {
142 return false;
143 }
144
145 armnn::IConnectableLayer* const startLayer = data.m_Network->AddDivisionLayer();
146 armnn::IConnectableLayer* const endLayer = ProcessActivation(outInfo, activationFunction, startLayer, data);
147
148 const armnn::TensorInfo& inputTensorInfo0 = input0.GetTensorInfo();
149 const armnn::TensorInfo& inputTensorInfo1 = input1.GetTensorInfo();
150
151 if (endLayer)
152 {
153 BroadcastTensor(input0, input1, startLayer, *data.m_Network);
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100154 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *endLayer, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100155 }
156
157 return Fail("%s: ProcessActivation failed", __func__);
158}
159
David Beck38e12942018-09-12 16:02:24 +0100160bool HalPolicy::ConvertSub(const Operation& operation, const Model& model, ConversionData& data)
161{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100162 LayerInputHandle input0 = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
163 LayerInputHandle input1 = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 1, model, data);
David Beck38e12942018-09-12 16:02:24 +0100164
165 if (!input0.IsValid() || !input1.IsValid())
166 {
167 return Fail("%s: Operation has invalid inputs", __func__);
168 }
169
170 // The FuseActivation parameter is always the input index 2
171 // and it should be optional
172 ActivationFn activationFunction;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100173 if (!GetOptionalInputActivation<hal_1_1::HalPolicy>(operation, 2, activationFunction, model, data))
David Beck38e12942018-09-12 16:02:24 +0100174 {
175 return Fail("%s: Operation has invalid inputs", __func__);
176 }
177
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100178 const Operand* outputOperand = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
David Beck38e12942018-09-12 16:02:24 +0100179 if (!outputOperand)
180 {
181 return false;
182 }
183
Sadik Armagan5e9521c2019-07-12 13:55:57 +0100184 armnn::TensorInfo outputInfo = GetTensorInfoForOperand(*outputOperand);
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100185 if (IsDynamicOutput(outputInfo))
186 {
Sadik Armagan5e9521c2019-07-12 13:55:57 +0100187 ALOGD("Output shape not set, will infer from inputs");
188 outputInfo.SetShape(InferSubOutputShape(input0.GetTensorInfo().GetShape(), input1.GetTensorInfo().GetShape()));
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100189 }
David Beck38e12942018-09-12 16:02:24 +0100190
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100191 bool isSupported = false;
192 FORWARD_LAYER_SUPPORT_FUNC(__func__,
193 IsSubtractionSupported,
194 data.m_Backends,
195 isSupported,
196 input0.GetTensorInfo(),
197 input1.GetTensorInfo(),
198 outputInfo);
199 if (!isSupported)
David Beck38e12942018-09-12 16:02:24 +0100200 {
201 return false;
202 }
203
204 armnn::IConnectableLayer* const startLayer = data.m_Network->AddSubtractionLayer();
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100205 armnn::IConnectableLayer* const endLayer = ProcessActivation(outputInfo, activationFunction, startLayer, data);
David Beck38e12942018-09-12 16:02:24 +0100206
207 const armnn::TensorInfo& inputTensorInfo0 = input0.GetTensorInfo();
208 const armnn::TensorInfo& inputTensorInfo1 = input1.GetTensorInfo();
209
210 if (endLayer)
211 {
212 BroadcastTensor(input0, input1, startLayer, *data.m_Network);
Sadik Armagan5e9521c2019-07-12 13:55:57 +0100213 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation,
214 0,
215 *endLayer,
216 model,
217 data,
218 armnn::Optional<armnn::TensorInfo>(outputInfo));
David Beck38e12942018-09-12 16:02:24 +0100219 }
220
221 return Fail("%s: ProcessActivation failed", __func__);
222}
223
narpra013c052562018-09-17 14:25:04 +0100224bool HalPolicy::ConvertMean(const Operation& operation, const Model& model, ConversionData& data)
225{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100226 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
narpra013c052562018-09-17 14:25:04 +0100227 if (!input.IsValid())
228 {
229 return Fail("%s: Operation has invalid inputs", __func__);
230 }
231
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100232 const Operand* axisOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
Matteo Martincighae622b72018-10-23 18:25:38 +0100233 if (!axisOperand)
234 {
235 return Fail("%s: Could not read input 1", __func__);
236 }
237
238 std::vector<int32_t> axis;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100239 if (!GetTensorInt32Values<hal_1_1::HalPolicy>(*axisOperand, axis, model, data))
Matteo Martincighae622b72018-10-23 18:25:38 +0100240 {
241 return Fail("%s: Input 1 has invalid values", __func__);
242 }
243
244 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
245
246 // Convert the axis to unsigned int and remove duplicates.
247 unsigned int rank = inputInfo.GetNumDimensions();
248 std::set<unsigned int> uniqueAxis;
249 std::transform(axis.begin(), axis.end(),
250 std::inserter(uniqueAxis, uniqueAxis.begin()),
251 [rank](int i) -> unsigned int { return (i + rank) % rank; });
252
253 // Get the "keep dims" flag.
254 int32_t keepDims = 0;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100255 if (!GetInputInt32<hal_1_1::HalPolicy>(operation, 2, keepDims, model, data))
Matteo Martincighae622b72018-10-23 18:25:38 +0100256 {
257 return Fail("%s: Could not read input 2", __func__);
258 }
narpra013c052562018-09-17 14:25:04 +0100259
260 armnn::MeanDescriptor descriptor;
Matteo Martincighae622b72018-10-23 18:25:38 +0100261 descriptor.m_Axis.assign(uniqueAxis.begin(), uniqueAxis.end());
262 descriptor.m_KeepDims = keepDims > 0;
narpra013c052562018-09-17 14:25:04 +0100263
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100264 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
narpra013c052562018-09-17 14:25:04 +0100265 if (!output)
266 {
267 return Fail("%s: Could not read output 0", __func__);
268 }
269
270 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
271
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100272 bool isSupported = false;
273 FORWARD_LAYER_SUPPORT_FUNC(__func__,
274 IsMeanSupported,
275 data.m_Backends,
276 isSupported,
277 inputInfo,
278 outputInfo,
279 descriptor);
280 if (!isSupported)
narpra013c052562018-09-17 14:25:04 +0100281 {
282 return false;
283 }
284
285 armnn::IConnectableLayer* const layer = data.m_Network->AddMeanLayer(descriptor);
narpra0196bedf02018-09-26 16:57:28 +0100286 assert(layer != nullptr);
287 input.Connect(layer->GetInputSlot(0));
narpra013c052562018-09-17 14:25:04 +0100288
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100289 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
narpra013c052562018-09-17 14:25:04 +0100290}
291
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100292bool HalPolicy::ConvertPad(const Operation& operation, const Model& model, ConversionData& data)
293{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100294 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100295 if (!input.IsValid())
296 {
297 return Fail("%s: Operation has invalid inputs", __func__);
298 }
299
300 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100301 unsigned int rank = inputInfo.GetNumDimensions();
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100302
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100303 armnn::PadDescriptor descriptor;
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100304 if (!ConvertPaddings<hal_1_1::HalPolicy>(operation, model, data, rank, descriptor))
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100305 {
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100306 return Fail("%s: Could not convert paddings", __func__);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100307 }
308
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100309 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100310 if (!output)
311 {
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100312 return Fail("%s: Could not read output", __func__);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100313 }
314
Sadik Armagan310d8ff2019-07-11 10:53:38 +0100315 armnn::TensorInfo outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100316 if (IsDynamicOutput(outputInfo))
317 {
Sadik Armagan310d8ff2019-07-11 10:53:38 +0100318 ALOGD("Output shape not set, will infer from inputs");
319 outputInfo.SetShape(InferPadOutputShape(inputInfo.GetShape(), descriptor.m_PadList));
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100320 }
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100321
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100322 bool isSupported = false;
323 FORWARD_LAYER_SUPPORT_FUNC(__func__,
324 IsPadSupported,
325 data.m_Backends,
326 isSupported,
327 inputInfo,
328 outputInfo,
329 descriptor);
330 if (!isSupported)
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100331 {
332 return false;
333 }
334
335 armnn::IConnectableLayer* const layer = data.m_Network->AddPadLayer(descriptor);
336 assert(layer != nullptr);
337 input.Connect(layer->GetInputSlot(0));
338 layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
339
Sadik Armagan310d8ff2019-07-11 10:53:38 +0100340 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation,
341 0,
342 *layer,
343 model,
344 data,
345 armnn::Optional<armnn::TensorInfo>(outputInfo));
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100346}
347
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000348bool HalPolicy::ConvertSpaceToBatchNd(const Operation& operation, const Model& model, ConversionData& data)
349{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100350 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000351
352 if (!input.IsValid())
353 {
354 return Fail("%s: Operation has invalid inputs", __func__);
355 }
356
357 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
358 unsigned int rank = inputInfo.GetNumDimensions();
359 unsigned int spatialDim = rank - 2;
360
361 if (rank != 4)
362 {
363 Fail("%s: Only inputs with rank 4 are supported", __func__);
364 }
365
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100366 const Operand* blockShapeOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
367 const Operand* paddingsOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 2, model);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000368
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100369 armnn::TensorShape blockShapeOperandShape = GetTensorShapeForOperand(*blockShapeOperand);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000370 if (blockShapeOperandShape.GetNumDimensions() != 1 || blockShapeOperandShape.GetNumElements() != spatialDim)
371 {
372 return Fail("%s: Operation has invalid block shape operand: expected shape [%d]", __func__, spatialDim);
373 }
374
375 std::vector<int32_t> blockShape;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100376 GetTensorInt32Values<hal_1_1::HalPolicy>(*blockShapeOperand, blockShape, model, data);
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000377 if (std::any_of(blockShape.cbegin(), blockShape.cend(), [](int32_t i){ return i < 1; }))
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000378 {
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000379 return Fail("%s: Block shape must be at least 1 in all dimensions.", __func__);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000380 }
381
382 armnn::TensorShape paddingsOperandShape = GetTensorShapeForOperand(*paddingsOperand);
383 if (paddingsOperandShape.GetNumDimensions() != 2 || paddingsOperandShape.GetNumElements() != 2 * spatialDim)
384 {
385 return Fail("%s: Operation has invalid paddings operand: expected shape [%d, 2]", __func__, spatialDim);
386 }
387
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000388 std::vector<std::pair<unsigned int, unsigned int>> paddingList;
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000389 std::vector<int32_t> paddings;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100390 GetTensorInt32Values<hal_1_1::HalPolicy>(*paddingsOperand, paddings, model, data);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000391 for (unsigned int i = 0; i < paddings.size() - 1; i += 2)
392 {
393 int paddingBeforeInput = paddings[i];
394 int paddingAfterInput = paddings[i + 1];
395 if (paddingBeforeInput < 0 || paddingAfterInput < 0)
396 {
397 return Fail("%s: Operation has invalid paddings operand, invalid padding values.", __func__);
398 }
399
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000400 paddingList.emplace_back((unsigned int) paddingBeforeInput, (unsigned int) paddingAfterInput);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000401 }
402
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000403 armnn::SpaceToBatchNdDescriptor descriptor;
404 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
405 descriptor.m_BlockShape.assign(blockShape.cbegin(), blockShape.cend());
406 descriptor.m_PadList.assign(paddingList.cbegin(), paddingList.cend());
407
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100408 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000409 if (!output)
410 {
411 return Fail("%s: Could not read output 0", __func__);
412 }
413
414 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100415
416 bool isSupported = false;
417 FORWARD_LAYER_SUPPORT_FUNC(__func__,
418 IsSpaceToBatchNdSupported,
419 data.m_Backends,
420 isSupported,
421 inputInfo,
422 outputInfo,
423 descriptor);
424 if (!isSupported)
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000425 {
426 return false;
427 }
428
429 armnn::IConnectableLayer* const layer = data.m_Network->AddSpaceToBatchNdLayer(descriptor);
430 assert(layer != nullptr);
431 input.Connect(layer->GetInputSlot(0));
432
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100433 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000434}
435
saoste01b8471482018-10-10 09:44:51 +0100436bool HalPolicy::ConvertSqueeze(const Operation& operation, const Model& model, ConversionData& data)
437{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100438 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
saoste01b8471482018-10-10 09:44:51 +0100439
440 if (!input.IsValid())
441 {
442 return Fail("%s: Operation has invalid inputs", __func__);
443 }
444
445 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
446
447 unsigned int rank = inputInfo.GetNumDimensions();
saoste01fe463152018-10-18 17:49:56 +0100448 if (rank > 4)
saoste01b8471482018-10-10 09:44:51 +0100449 {
saoste01fe463152018-10-18 17:49:56 +0100450 Fail("%s: Inputs with rank greater than 4 are not supported", __func__);
saoste01b8471482018-10-10 09:44:51 +0100451 }
452
453 // NOTE: Axis is an optional parameter to SQUEEZE, therefore we do not want to generate a failure
454 // if the operand index is out of bounds.
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100455 const Operand* axisOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model, false);
saoste01b8471482018-10-10 09:44:51 +0100456
saoste01fe463152018-10-18 17:49:56 +0100457 const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
458
saoste01b8471482018-10-10 09:44:51 +0100459 std::vector<int32_t> axis;
saoste01fe463152018-10-18 17:49:56 +0100460 if (!axisOperand)
saoste01b8471482018-10-10 09:44:51 +0100461 {
462 axis.assign(dimensionSequence,
saoste01fe463152018-10-18 17:49:56 +0100463 dimensionSequence + rank);
saoste01b8471482018-10-10 09:44:51 +0100464 }
465 else
466 {
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100467 GetTensorInt32Values<hal_1_1::HalPolicy>(*axisOperand, axis, model, data);
saoste01b8471482018-10-10 09:44:51 +0100468 }
469
saoste01b8471482018-10-10 09:44:51 +0100470
saoste01a893efa2018-10-13 11:56:12 +0100471 std::vector<uint32_t> outputDims;
saoste01fe463152018-10-18 17:49:56 +0100472 for (unsigned int i = 0; i < rank; i++)
saoste01a893efa2018-10-13 11:56:12 +0100473 {
474 bool skipSqueeze = (std::find(axis.begin(), axis.end(), i) == axis.end());
475 auto currentDimension = inputInfo.GetShape()[i];
saoste01b8471482018-10-10 09:44:51 +0100476 if (skipSqueeze || currentDimension != 1)
477 {
478 outputDims.push_back(currentDimension);
479 }
480 }
481
saoste01fe463152018-10-18 17:49:56 +0100482 armnn::TensorShape outShape = armnn::TensorShape(outputDims.size(), outputDims.data());
saoste01b8471482018-10-10 09:44:51 +0100483
484 armnn::TensorInfo outputInfo = inputInfo;
485 outputInfo.SetShape(outShape);
486
487 armnn::ReshapeDescriptor reshapeDesc;
488 reshapeDesc.m_TargetShape = outputInfo.GetShape();
489
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100490 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
saoste01b8471482018-10-10 09:44:51 +0100491 if (!output)
492 {
493 return Fail("%s: Could not read output 0", __func__);
494 }
495
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100496 bool isSupported = false;
497 FORWARD_LAYER_SUPPORT_FUNC(__func__,
498 IsReshapeSupported,
499 data.m_Backends,
500 isSupported,
501 inputInfo,
502 reshapeDesc);
503 if (!isSupported)
saoste01b8471482018-10-10 09:44:51 +0100504 {
505 return false;
506 }
507
508 armnn::IConnectableLayer* const layer = data.m_Network->AddReshapeLayer(reshapeDesc);
509 assert(layer != nullptr);
510 input.Connect(layer->GetInputSlot(0));
saoste01fe463152018-10-18 17:49:56 +0100511
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100512 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
saoste01fe463152018-10-18 17:49:56 +0100513}
514
Sadik Armagan758eee82018-11-15 15:34:49 +0000515bool HalPolicy::ConvertStridedSlice(const Operation& operation, const Model& model, ConversionData& data)
516{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100517 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
Sadik Armagan758eee82018-11-15 15:34:49 +0000518 if (!input.IsValid())
519 {
520 return Fail("%s: Operation has invalid inputs", __func__);
521 }
522 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
523
524 unsigned int rank = inputInfo.GetNumDimensions();
525 if (rank > 4)
526 {
527 Fail("%s: Inputs with rank greater than 4 are not supported", __func__);
528 }
529
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100530 const Operand* beginOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
531 const Operand* endOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 2, model);
532 const Operand* stridesOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 3, model);
Sadik Armagan758eee82018-11-15 15:34:49 +0000533
534 std::vector<int32_t> beginValues;
535 std::vector<int32_t> endValues;
536 std::vector<int32_t> stridesValues;
537
538 // The length of the beginOperand, endOperand and stridesOperand must be of a rank(input)
539 auto ValidateInputOperands = [&] (const Operand& operand, std::vector<int32_t>& operandValues)
540 {
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100541 if (!GetTensorInt32Values<hal_1_1::HalPolicy>(operand, operandValues, model, data))
Sadik Armagan758eee82018-11-15 15:34:49 +0000542 {
543 return false;
544 }
545
546 if (operandValues.size() != rank)
547 {
548 return false;
549 }
550
551 return true;
552 };
553
554 if (!ValidateInputOperands(*beginOperand, beginValues)
555 || !ValidateInputOperands(*endOperand, endValues)
556 || !ValidateInputOperands(*stridesOperand, stridesValues))
557 {
558 return Fail("%s: Operation has invalid input operand", __func__);
559 }
560
561 // Stride cannot have value '0'
562 if (std::any_of(stridesValues.cbegin(), stridesValues.cend(), [](int32_t i){ return i == 0; }))
563 {
564 return Fail("%s: Stride must be non-zero value.", __func__);
565 }
566
567 armnn::StridedSliceDescriptor descriptor;
568 descriptor.m_Begin.assign(beginValues.cbegin(), beginValues.cend());
569 descriptor.m_End.assign(endValues.cbegin(), endValues.cend());
570 descriptor.m_Stride.assign(stridesValues.cbegin(), stridesValues.cend());
571 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
572
573 // Get the "begin_mask", "end_mask", and "shrink_axis_mask" flags
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100574 if (!GetInputInt32<hal_1_1::HalPolicy>(operation, 4, descriptor.m_BeginMask, model, data) ||
575 !GetInputInt32<hal_1_1::HalPolicy>(operation, 5, descriptor.m_EndMask, model, data) ||
576 !GetInputInt32<hal_1_1::HalPolicy>(operation, 6, descriptor.m_ShrinkAxisMask, model, data))
Sadik Armagan758eee82018-11-15 15:34:49 +0000577 {
578 return Fail("%s: Operation has invalid inputs", __func__);
579 }
580
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100581 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
Sadik Armagan758eee82018-11-15 15:34:49 +0000582 if (!output)
583 {
584 return Fail("%s: Could not read output 0", __func__);
585 }
586 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
587
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100588 bool isSupported = false;
589 FORWARD_LAYER_SUPPORT_FUNC(__func__,
590 IsStridedSliceSupported,
591 data.m_Backends,
592 isSupported,
593 inputInfo,
594 outputInfo,
595 descriptor);
596 if (!isSupported)
Sadik Armagan758eee82018-11-15 15:34:49 +0000597 {
598 return false;
599 }
600
601 armnn::IConnectableLayer* const layer = data.m_Network->AddStridedSliceLayer(descriptor);
602 assert(layer != nullptr);
603 input.Connect(layer->GetInputSlot(0));
604
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100605 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
Sadik Armagan758eee82018-11-15 15:34:49 +0000606}
607
saoste01fe463152018-10-18 17:49:56 +0100608bool HalPolicy::ConvertTranspose(const Operation& operation, const Model& model, ConversionData& data)
609{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100610 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
saoste01fe463152018-10-18 17:49:56 +0100611
612 if (!input.IsValid())
613 {
614 return Fail("%s: Operation has invalid inputs", __func__);
615 }
616
617 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
618
619 unsigned int rank = inputInfo.GetNumDimensions();
620 if (rank > 4)
621 {
622 Fail("%s: Inputs with rank greater than 4 are not supported", __func__);
623 }
624
625 // NOTE: Axis is an optional parameter to TRANSPOSE, therefore we do not want to generate a failure
626 // if the operand index is out of bounds.
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100627 const Operand* permOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model, false);
saoste01fe463152018-10-18 17:49:56 +0100628
629 std::vector<int32_t> perm(rank);
630 if (!permOperand)
631 {
632 // NOTE: If perm is not given, it is set to (n-1...0), where n is the rank of the tensor
633 for (unsigned int i = rank; i > 0; i--)
634 {
635 perm[rank - i] = boost::numeric_cast<int> (i - 1);
636 }
637 }
638 else
639 {
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100640 GetTensorInt32Values<hal_1_1::HalPolicy>(*permOperand, perm, model, data);
saoste01fe463152018-10-18 17:49:56 +0100641 }
642
643 std::vector<uint32_t> outputDims(perm.begin(), perm.begin() + rank);
644
645 auto permutationVector = armnn::PermutationVector(outputDims.data(), outputDims.size());
646 if (!permutationVector.IsEqual(NHWCToArmNN)
647 && !permutationVector.IsEqual(ArmNNToNHWC)
648 && !permutationVector.IsEqual({ 3, 2, 0, 1 }))
649 {
650 return Fail("%s: Only [0, 3, 1, 2], [0, 2, 3, 1] and [3, 2, 0, 1] permutations are supported.", __func__);
651 }
652
653 armnn::PermuteDescriptor permuteDesc;
654 permuteDesc.m_DimMappings = permutationVector;
655
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100656 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
saoste01fe463152018-10-18 17:49:56 +0100657 if (!output)
658 {
659 return Fail("%s: Could not read output 0", __func__);
660 }
661
662 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
663
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100664 bool isSupported = false;
665 FORWARD_LAYER_SUPPORT_FUNC(__func__,
666 IsPermuteSupported,
667 data.m_Backends,
668 isSupported,
669 inputInfo,
670 outputInfo,
671 permuteDesc);
672 if (!isSupported)
saoste01fe463152018-10-18 17:49:56 +0100673 {
674 return false;
675 }
676
677 armnn::IConnectableLayer* const layer = data.m_Network->AddPermuteLayer(permuteDesc);
678 assert(layer != nullptr);
679 input.Connect(layer->GetInputSlot(0));
saoste01b8471482018-10-10 09:44:51 +0100680
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100681 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
saoste01b8471482018-10-10 09:44:51 +0100682}
683
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000684bool HalPolicy::ConvertBatchToSpaceNd(const Operation& operation, const Model& model, ConversionData& data)
685{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100686 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000687 if (!input.IsValid())
688 {
689 return Fail("%s: Operation has invalid inputs", __func__);
690 }
691
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100692 const Operand* blockOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000693 if (!blockOperand)
694 {
695 return Fail("%s: Could not read input 1", __func__);
696 }
697
698 // Convert the block operand to int32
699 std::vector<int32_t> block;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100700 if (!GetTensorInt32Values<hal_1_1::HalPolicy>(*blockOperand, block, model, data))
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000701 {
702 return Fail("%s: Input 1 has invalid values", __func__);
703 }
704
705 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
706
707 unsigned int rank = inputInfo.GetNumDimensions();
708 if (rank != 4)
709 {
710 Fail("%s: Only inputs with rank equal to 4 are supported", __func__);
711 }
712
713 if (std::any_of(block.cbegin(), block.cend(), [](int32_t i){ return i < 1; }))
714 {
715 return Fail("%s: Block sizes for each spatial dimension of the input tensor must be"
716 " greater than or equal to 1", __func__);
717 }
718
719 armnn::BatchToSpaceNdDescriptor batchToSpaceNdDesc;
720 batchToSpaceNdDesc.m_BlockShape.assign(block.cbegin(), block.cend());
721 batchToSpaceNdDesc.m_DataLayout = armnn::DataLayout::NHWC;
722
723 // Setting crops to 0,0 0,0 as it is not supported in Android NN API
724 batchToSpaceNdDesc.m_Crops = {{0, 0}, {0, 0}};
725
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100726 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000727 if (!output)
728 {
729 return Fail("%s: Could not read output 0", __func__);
730 }
731
732 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
733
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100734 bool isSupported = false;
735 FORWARD_LAYER_SUPPORT_FUNC(__func__,
736 IsBatchToSpaceNdSupported,
737 data.m_Backends,
738 isSupported,
739 inputInfo,
740 outputInfo,
741 batchToSpaceNdDesc);
742 if (!isSupported)
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000743 {
744 return false;
745 }
746
747 armnn::IConnectableLayer* const layer = data.m_Network->AddBatchToSpaceNdLayer(batchToSpaceNdDesc);
748 assert(layer != nullptr);
749 input.Connect(layer->GetInputSlot(0));
750
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100751 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000752}
753
arovir01b0717b52018-09-05 17:03:25 +0100754} // namespace hal_1_1
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100755} // namespace armnn_driver