blob: 0f00910fa0288f960684f3c2a4a792604b3fbad7 [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
8#include "../1.0/HalPolicy.hpp"
9
Éanna Ó Catháin2fc21f72019-05-13 11:01:33 +010010namespace
11{
12static std::vector<V1_0::OperationType> opsEquivalentInV10({
13 V1_0::OperationType::ADD,
14 V1_0::OperationType::AVERAGE_POOL_2D,
15 V1_0::OperationType::CONCATENATION,
16 V1_0::OperationType::CONV_2D,
17 V1_0::OperationType::DEPTHWISE_CONV_2D,
David Monahand5bfae12019-05-30 12:07:44 +010018 V1_0::OperationType::DEQUANTIZE,
Éanna Ó Catháin2fc21f72019-05-13 11:01:33 +010019 V1_0::OperationType::FLOOR,
20 V1_0::OperationType::FULLY_CONNECTED,
21 V1_0::OperationType::LOCAL_RESPONSE_NORMALIZATION,
22 V1_0::OperationType::LOGISTIC,
23 V1_0::OperationType::LSTM,
24 V1_0::OperationType::L2_NORMALIZATION,
25 V1_0::OperationType::L2_POOL_2D,
26 V1_0::OperationType::MAX_POOL_2D,
27 V1_0::OperationType::MUL,
28 V1_0::OperationType::RELU,
29 V1_0::OperationType::RELU1,
30 V1_0::OperationType::RELU6,
31 V1_0::OperationType::SOFTMAX,
32 V1_0::OperationType::TANH,
33 V1_0::OperationType::RESHAPE,
34 V1_0::OperationType::RESIZE_BILINEAR,
35});
36
37bool CompliantWithVersion10(const V1_1::Operation & operation)
38{
39 std::vector<V1_0::OperationType>::iterator it;
40 it = std::find(opsEquivalentInV10.begin(), opsEquivalentInV10.end(),
41 static_cast<V1_0::OperationType>(operation.type));
42
43 if(it != opsEquivalentInV10.end())
44 {
45 return true;
46 }
47 return false;
48}
49
50V1_0::Operation ConvertOperationToVersion10(const V1_1::Operation & operation)
51{
52 V1_0::Operation v10Operation;
53 v10Operation.type = static_cast<V1_0::OperationType>(operation.type);
54 v10Operation.inputs = operation.inputs;
55 v10Operation.outputs = operation.outputs;
56 return v10Operation;
57}
58}
59
arovir01b0717b52018-09-05 17:03:25 +010060namespace armnn_driver
61{
62namespace hal_1_1
63{
64
65bool HalPolicy::ConvertOperation(const Operation& operation, const Model& model, ConversionData& data)
66{
Éanna Ó Catháin2fc21f72019-05-13 11:01:33 +010067 if (CompliantWithVersion10(operation))
arovir01b0717b52018-09-05 17:03:25 +010068 {
Éanna Ó Catháin2fc21f72019-05-13 11:01:33 +010069 hal_1_0::HalPolicy::Operation v10Operation = ConvertOperationToVersion10(operation);
arovir01b0717b52018-09-05 17:03:25 +010070 hal_1_0::HalPolicy::Model v10Model = convertToV1_0(model);
71
72 return hal_1_0::HalPolicy::ConvertOperation(v10Operation, v10Model, data);
73 }
74 else
75 {
76 switch (operation.type)
77 {
78 case V1_1::OperationType::DIV:
79 return ConvertDiv(operation, model, data);
David Beck38e12942018-09-12 16:02:24 +010080 case V1_1::OperationType::SUB:
81 return ConvertSub(operation, model, data);
narpra013c052562018-09-17 14:25:04 +010082 case V1_1::OperationType::MEAN:
83 return ConvertMean(operation, model, data);
Nina Drozd62a4a9f2018-10-01 14:20:25 +010084 case V1_1::OperationType::PAD:
85 return ConvertPad(operation, model, data);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +000086 case V1_1::OperationType::SPACE_TO_BATCH_ND:
87 return ConvertSpaceToBatchNd(operation, model, data);
saoste01b8471482018-10-10 09:44:51 +010088 case V1_1::OperationType::SQUEEZE:
89 return ConvertSqueeze(operation, model, data);
Sadik Armagan758eee82018-11-15 15:34:49 +000090 case V1_1::OperationType::STRIDED_SLICE:
91 return ConvertStridedSlice(operation, model, data);
saoste01fe463152018-10-18 17:49:56 +010092 case V1_1::OperationType::TRANSPOSE:
93 return ConvertTranspose(operation, model, data);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +000094 case V1_1::OperationType::BATCH_TO_SPACE_ND:
95 return ConvertBatchToSpaceNd(operation, model, data);
arovir01b0717b52018-09-05 17:03:25 +010096 default:
97 return Fail("%s: Operation type %s not supported in ArmnnDriver",
98 __func__, toString(operation.type).c_str());
99 }
100 }
101}
102
103bool HalPolicy::ConvertDiv(const Operation& operation, const Model& model, ConversionData& data)
104{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100105 LayerInputHandle input0 = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
106 LayerInputHandle input1 = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 1, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100107
108 if (!input0.IsValid() || !input1.IsValid())
109 {
110 return Fail("%s: Operation has invalid inputs", __func__);
111 }
112
113 // The FuseActivation parameter is always the input index 2
114 // and it should be optional
115 ActivationFn activationFunction;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100116 if (!GetOptionalInputActivation<hal_1_1::HalPolicy>(operation, 2, activationFunction, model, data))
arovir01b0717b52018-09-05 17:03:25 +0100117 {
118 return Fail("%s: Operation has invalid inputs", __func__);
119 }
120
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100121 const Operand* outputOperand = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
arovir01b0717b52018-09-05 17:03:25 +0100122 if (!outputOperand)
123 {
124 return false;
125 }
126
127 const armnn::TensorInfo& outInfo = GetTensorInfoForOperand(*outputOperand);
128
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100129 if (!IsLayerSupportedForAnyBackend(__func__,
130 armnn::IsDivisionSupported,
131 data.m_Backends,
132 input0.GetTensorInfo(),
133 input1.GetTensorInfo(),
134 outInfo))
arovir01b0717b52018-09-05 17:03:25 +0100135 {
136 return false;
137 }
138
139 armnn::IConnectableLayer* const startLayer = data.m_Network->AddDivisionLayer();
140 armnn::IConnectableLayer* const endLayer = ProcessActivation(outInfo, activationFunction, startLayer, data);
141
142 const armnn::TensorInfo& inputTensorInfo0 = input0.GetTensorInfo();
143 const armnn::TensorInfo& inputTensorInfo1 = input1.GetTensorInfo();
144
145 if (endLayer)
146 {
147 BroadcastTensor(input0, input1, startLayer, *data.m_Network);
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100148 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *endLayer, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100149 }
150
151 return Fail("%s: ProcessActivation failed", __func__);
152}
153
David Beck38e12942018-09-12 16:02:24 +0100154bool HalPolicy::ConvertSub(const Operation& operation, const Model& model, ConversionData& data)
155{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100156 LayerInputHandle input0 = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
157 LayerInputHandle input1 = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 1, model, data);
David Beck38e12942018-09-12 16:02:24 +0100158
159 if (!input0.IsValid() || !input1.IsValid())
160 {
161 return Fail("%s: Operation has invalid inputs", __func__);
162 }
163
164 // The FuseActivation parameter is always the input index 2
165 // and it should be optional
166 ActivationFn activationFunction;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100167 if (!GetOptionalInputActivation<hal_1_1::HalPolicy>(operation, 2, activationFunction, model, data))
David Beck38e12942018-09-12 16:02:24 +0100168 {
169 return Fail("%s: Operation has invalid inputs", __func__);
170 }
171
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100172 const Operand* outputOperand = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
David Beck38e12942018-09-12 16:02:24 +0100173 if (!outputOperand)
174 {
175 return false;
176 }
177
178 const armnn::TensorInfo& outInfo = GetTensorInfoForOperand(*outputOperand);
179
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100180 if (!IsLayerSupportedForAnyBackend(__func__,
181 armnn::IsSubtractionSupported,
182 data.m_Backends,
183 input0.GetTensorInfo(),
184 input1.GetTensorInfo(),
185 outInfo))
David Beck38e12942018-09-12 16:02:24 +0100186 {
187 return false;
188 }
189
190 armnn::IConnectableLayer* const startLayer = data.m_Network->AddSubtractionLayer();
191 armnn::IConnectableLayer* const endLayer = ProcessActivation(outInfo, activationFunction, startLayer, data);
192
193 const armnn::TensorInfo& inputTensorInfo0 = input0.GetTensorInfo();
194 const armnn::TensorInfo& inputTensorInfo1 = input1.GetTensorInfo();
195
196 if (endLayer)
197 {
198 BroadcastTensor(input0, input1, startLayer, *data.m_Network);
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100199 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *endLayer, model, data);
David Beck38e12942018-09-12 16:02:24 +0100200 }
201
202 return Fail("%s: ProcessActivation failed", __func__);
203}
204
narpra013c052562018-09-17 14:25:04 +0100205bool HalPolicy::ConvertMean(const Operation& operation, const Model& model, ConversionData& data)
206{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100207 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
narpra013c052562018-09-17 14:25:04 +0100208 if (!input.IsValid())
209 {
210 return Fail("%s: Operation has invalid inputs", __func__);
211 }
212
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100213 const Operand* axisOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
Matteo Martincighae622b72018-10-23 18:25:38 +0100214 if (!axisOperand)
215 {
216 return Fail("%s: Could not read input 1", __func__);
217 }
218
219 std::vector<int32_t> axis;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100220 if (!GetTensorInt32Values<hal_1_1::HalPolicy>(*axisOperand, axis, model, data))
Matteo Martincighae622b72018-10-23 18:25:38 +0100221 {
222 return Fail("%s: Input 1 has invalid values", __func__);
223 }
224
225 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
226
227 // Convert the axis to unsigned int and remove duplicates.
228 unsigned int rank = inputInfo.GetNumDimensions();
229 std::set<unsigned int> uniqueAxis;
230 std::transform(axis.begin(), axis.end(),
231 std::inserter(uniqueAxis, uniqueAxis.begin()),
232 [rank](int i) -> unsigned int { return (i + rank) % rank; });
233
234 // Get the "keep dims" flag.
235 int32_t keepDims = 0;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100236 if (!GetInputInt32<hal_1_1::HalPolicy>(operation, 2, keepDims, model, data))
Matteo Martincighae622b72018-10-23 18:25:38 +0100237 {
238 return Fail("%s: Could not read input 2", __func__);
239 }
narpra013c052562018-09-17 14:25:04 +0100240
241 armnn::MeanDescriptor descriptor;
Matteo Martincighae622b72018-10-23 18:25:38 +0100242 descriptor.m_Axis.assign(uniqueAxis.begin(), uniqueAxis.end());
243 descriptor.m_KeepDims = keepDims > 0;
narpra013c052562018-09-17 14:25:04 +0100244
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100245 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
narpra013c052562018-09-17 14:25:04 +0100246 if (!output)
247 {
248 return Fail("%s: Could not read output 0", __func__);
249 }
250
251 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
252
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100253 if (!IsLayerSupportedForAnyBackend(__func__,
254 armnn::IsMeanSupported,
255 data.m_Backends,
256 inputInfo,
257 outputInfo,
258 descriptor))
narpra013c052562018-09-17 14:25:04 +0100259 {
260 return false;
261 }
262
263 armnn::IConnectableLayer* const layer = data.m_Network->AddMeanLayer(descriptor);
narpra0196bedf02018-09-26 16:57:28 +0100264 assert(layer != nullptr);
265 input.Connect(layer->GetInputSlot(0));
narpra013c052562018-09-17 14:25:04 +0100266
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100267 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
narpra013c052562018-09-17 14:25:04 +0100268}
269
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100270bool HalPolicy::ConvertPad(const Operation& operation, const Model& model, ConversionData& data)
271{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100272 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100273 if (!input.IsValid())
274 {
275 return Fail("%s: Operation has invalid inputs", __func__);
276 }
277
278 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100279 unsigned int rank = inputInfo.GetNumDimensions();
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100280
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100281 armnn::PadDescriptor descriptor;
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100282 if (!ConvertPaddings<hal_1_1::HalPolicy>(operation, model, data, rank, descriptor))
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100283 {
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100284 return Fail("%s: Could not convert paddings", __func__);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100285 }
286
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100287 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100288 if (!output)
289 {
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100290 return Fail("%s: Could not read output", __func__);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100291 }
292
293 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
294
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100295 if (!IsLayerSupportedForAnyBackend(__func__,
296 armnn::IsPadSupported,
297 data.m_Backends,
298 inputInfo,
299 outputInfo,
300 descriptor))
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100301 {
302 return false;
303 }
304
305 armnn::IConnectableLayer* const layer = data.m_Network->AddPadLayer(descriptor);
306 assert(layer != nullptr);
307 input.Connect(layer->GetInputSlot(0));
308 layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
309
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100310 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100311}
312
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000313bool HalPolicy::ConvertSpaceToBatchNd(const Operation& operation, const Model& model, ConversionData& data)
314{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100315 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000316
317 if (!input.IsValid())
318 {
319 return Fail("%s: Operation has invalid inputs", __func__);
320 }
321
322 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
323 unsigned int rank = inputInfo.GetNumDimensions();
324 unsigned int spatialDim = rank - 2;
325
326 if (rank != 4)
327 {
328 Fail("%s: Only inputs with rank 4 are supported", __func__);
329 }
330
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100331 const Operand* blockShapeOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
332 const Operand* paddingsOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 2, model);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000333
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100334 armnn::TensorShape blockShapeOperandShape = GetTensorShapeForOperand(*blockShapeOperand);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000335 if (blockShapeOperandShape.GetNumDimensions() != 1 || blockShapeOperandShape.GetNumElements() != spatialDim)
336 {
337 return Fail("%s: Operation has invalid block shape operand: expected shape [%d]", __func__, spatialDim);
338 }
339
340 std::vector<int32_t> blockShape;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100341 GetTensorInt32Values<hal_1_1::HalPolicy>(*blockShapeOperand, blockShape, model, data);
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000342 if (std::any_of(blockShape.cbegin(), blockShape.cend(), [](int32_t i){ return i < 1; }))
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000343 {
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000344 return Fail("%s: Block shape must be at least 1 in all dimensions.", __func__);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000345 }
346
347 armnn::TensorShape paddingsOperandShape = GetTensorShapeForOperand(*paddingsOperand);
348 if (paddingsOperandShape.GetNumDimensions() != 2 || paddingsOperandShape.GetNumElements() != 2 * spatialDim)
349 {
350 return Fail("%s: Operation has invalid paddings operand: expected shape [%d, 2]", __func__, spatialDim);
351 }
352
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000353 std::vector<std::pair<unsigned int, unsigned int>> paddingList;
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000354 std::vector<int32_t> paddings;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100355 GetTensorInt32Values<hal_1_1::HalPolicy>(*paddingsOperand, paddings, model, data);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000356 for (unsigned int i = 0; i < paddings.size() - 1; i += 2)
357 {
358 int paddingBeforeInput = paddings[i];
359 int paddingAfterInput = paddings[i + 1];
360 if (paddingBeforeInput < 0 || paddingAfterInput < 0)
361 {
362 return Fail("%s: Operation has invalid paddings operand, invalid padding values.", __func__);
363 }
364
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000365 paddingList.emplace_back((unsigned int) paddingBeforeInput, (unsigned int) paddingAfterInput);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000366 }
367
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000368 armnn::SpaceToBatchNdDescriptor descriptor;
369 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
370 descriptor.m_BlockShape.assign(blockShape.cbegin(), blockShape.cend());
371 descriptor.m_PadList.assign(paddingList.cbegin(), paddingList.cend());
372
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100373 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000374 if (!output)
375 {
376 return Fail("%s: Could not read output 0", __func__);
377 }
378
379 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100380 if (!IsLayerSupportedForAnyBackend(__func__,
381 armnn::IsSpaceToBatchNdSupported,
382 data.m_Backends,
383 inputInfo,
384 outputInfo,
385 descriptor))
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000386 {
387 return false;
388 }
389
390 armnn::IConnectableLayer* const layer = data.m_Network->AddSpaceToBatchNdLayer(descriptor);
391 assert(layer != nullptr);
392 input.Connect(layer->GetInputSlot(0));
393
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100394 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000395}
396
saoste01b8471482018-10-10 09:44:51 +0100397bool HalPolicy::ConvertSqueeze(const Operation& operation, const Model& model, ConversionData& data)
398{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100399 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
saoste01b8471482018-10-10 09:44:51 +0100400
401 if (!input.IsValid())
402 {
403 return Fail("%s: Operation has invalid inputs", __func__);
404 }
405
406 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
407
408 unsigned int rank = inputInfo.GetNumDimensions();
saoste01fe463152018-10-18 17:49:56 +0100409 if (rank > 4)
saoste01b8471482018-10-10 09:44:51 +0100410 {
saoste01fe463152018-10-18 17:49:56 +0100411 Fail("%s: Inputs with rank greater than 4 are not supported", __func__);
saoste01b8471482018-10-10 09:44:51 +0100412 }
413
414 // NOTE: Axis is an optional parameter to SQUEEZE, therefore we do not want to generate a failure
415 // if the operand index is out of bounds.
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100416 const Operand* axisOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model, false);
saoste01b8471482018-10-10 09:44:51 +0100417
saoste01fe463152018-10-18 17:49:56 +0100418 const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
419
saoste01b8471482018-10-10 09:44:51 +0100420 std::vector<int32_t> axis;
saoste01fe463152018-10-18 17:49:56 +0100421 if (!axisOperand)
saoste01b8471482018-10-10 09:44:51 +0100422 {
423 axis.assign(dimensionSequence,
saoste01fe463152018-10-18 17:49:56 +0100424 dimensionSequence + rank);
saoste01b8471482018-10-10 09:44:51 +0100425 }
426 else
427 {
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100428 GetTensorInt32Values<hal_1_1::HalPolicy>(*axisOperand, axis, model, data);
saoste01b8471482018-10-10 09:44:51 +0100429 }
430
saoste01b8471482018-10-10 09:44:51 +0100431
saoste01a893efa2018-10-13 11:56:12 +0100432 std::vector<uint32_t> outputDims;
saoste01fe463152018-10-18 17:49:56 +0100433 for (unsigned int i = 0; i < rank; i++)
saoste01a893efa2018-10-13 11:56:12 +0100434 {
435 bool skipSqueeze = (std::find(axis.begin(), axis.end(), i) == axis.end());
436 auto currentDimension = inputInfo.GetShape()[i];
saoste01b8471482018-10-10 09:44:51 +0100437 if (skipSqueeze || currentDimension != 1)
438 {
439 outputDims.push_back(currentDimension);
440 }
441 }
442
saoste01fe463152018-10-18 17:49:56 +0100443 armnn::TensorShape outShape = armnn::TensorShape(outputDims.size(), outputDims.data());
saoste01b8471482018-10-10 09:44:51 +0100444
445 armnn::TensorInfo outputInfo = inputInfo;
446 outputInfo.SetShape(outShape);
447
448 armnn::ReshapeDescriptor reshapeDesc;
449 reshapeDesc.m_TargetShape = outputInfo.GetShape();
450
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100451 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
saoste01b8471482018-10-10 09:44:51 +0100452 if (!output)
453 {
454 return Fail("%s: Could not read output 0", __func__);
455 }
456
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100457 if (!IsLayerSupportedForAnyBackend(__func__,
458 armnn::IsReshapeSupported,
459 data.m_Backends,
460 inputInfo,
461 reshapeDesc))
saoste01b8471482018-10-10 09:44:51 +0100462 {
463 return false;
464 }
465
466 armnn::IConnectableLayer* const layer = data.m_Network->AddReshapeLayer(reshapeDesc);
467 assert(layer != nullptr);
468 input.Connect(layer->GetInputSlot(0));
saoste01fe463152018-10-18 17:49:56 +0100469
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100470 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
saoste01fe463152018-10-18 17:49:56 +0100471}
472
Sadik Armagan758eee82018-11-15 15:34:49 +0000473bool HalPolicy::ConvertStridedSlice(const Operation& operation, const Model& model, ConversionData& data)
474{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100475 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
Sadik Armagan758eee82018-11-15 15:34:49 +0000476 if (!input.IsValid())
477 {
478 return Fail("%s: Operation has invalid inputs", __func__);
479 }
480 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
481
482 unsigned int rank = inputInfo.GetNumDimensions();
483 if (rank > 4)
484 {
485 Fail("%s: Inputs with rank greater than 4 are not supported", __func__);
486 }
487
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100488 const Operand* beginOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
489 const Operand* endOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 2, model);
490 const Operand* stridesOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 3, model);
Sadik Armagan758eee82018-11-15 15:34:49 +0000491
492 std::vector<int32_t> beginValues;
493 std::vector<int32_t> endValues;
494 std::vector<int32_t> stridesValues;
495
496 // The length of the beginOperand, endOperand and stridesOperand must be of a rank(input)
497 auto ValidateInputOperands = [&] (const Operand& operand, std::vector<int32_t>& operandValues)
498 {
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100499 if (!GetTensorInt32Values<hal_1_1::HalPolicy>(operand, operandValues, model, data))
Sadik Armagan758eee82018-11-15 15:34:49 +0000500 {
501 return false;
502 }
503
504 if (operandValues.size() != rank)
505 {
506 return false;
507 }
508
509 return true;
510 };
511
512 if (!ValidateInputOperands(*beginOperand, beginValues)
513 || !ValidateInputOperands(*endOperand, endValues)
514 || !ValidateInputOperands(*stridesOperand, stridesValues))
515 {
516 return Fail("%s: Operation has invalid input operand", __func__);
517 }
518
519 // Stride cannot have value '0'
520 if (std::any_of(stridesValues.cbegin(), stridesValues.cend(), [](int32_t i){ return i == 0; }))
521 {
522 return Fail("%s: Stride must be non-zero value.", __func__);
523 }
524
525 armnn::StridedSliceDescriptor descriptor;
526 descriptor.m_Begin.assign(beginValues.cbegin(), beginValues.cend());
527 descriptor.m_End.assign(endValues.cbegin(), endValues.cend());
528 descriptor.m_Stride.assign(stridesValues.cbegin(), stridesValues.cend());
529 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
530
531 // Get the "begin_mask", "end_mask", and "shrink_axis_mask" flags
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100532 if (!GetInputInt32<hal_1_1::HalPolicy>(operation, 4, descriptor.m_BeginMask, model, data) ||
533 !GetInputInt32<hal_1_1::HalPolicy>(operation, 5, descriptor.m_EndMask, model, data) ||
534 !GetInputInt32<hal_1_1::HalPolicy>(operation, 6, descriptor.m_ShrinkAxisMask, model, data))
Sadik Armagan758eee82018-11-15 15:34:49 +0000535 {
536 return Fail("%s: Operation has invalid inputs", __func__);
537 }
538
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100539 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
Sadik Armagan758eee82018-11-15 15:34:49 +0000540 if (!output)
541 {
542 return Fail("%s: Could not read output 0", __func__);
543 }
544 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
545
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100546 if (!IsLayerSupportedForAnyBackend(__func__,
547 armnn::IsStridedSliceSupported,
548 data.m_Backends,
549 inputInfo,
550 outputInfo,
551 descriptor))
Sadik Armagan758eee82018-11-15 15:34:49 +0000552 {
553 return false;
554 }
555
556 armnn::IConnectableLayer* const layer = data.m_Network->AddStridedSliceLayer(descriptor);
557 assert(layer != nullptr);
558 input.Connect(layer->GetInputSlot(0));
559
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100560 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
Sadik Armagan758eee82018-11-15 15:34:49 +0000561}
562
saoste01fe463152018-10-18 17:49:56 +0100563bool HalPolicy::ConvertTranspose(const Operation& operation, const Model& model, ConversionData& data)
564{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100565 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
saoste01fe463152018-10-18 17:49:56 +0100566
567 if (!input.IsValid())
568 {
569 return Fail("%s: Operation has invalid inputs", __func__);
570 }
571
572 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
573
574 unsigned int rank = inputInfo.GetNumDimensions();
575 if (rank > 4)
576 {
577 Fail("%s: Inputs with rank greater than 4 are not supported", __func__);
578 }
579
580 // NOTE: Axis is an optional parameter to TRANSPOSE, therefore we do not want to generate a failure
581 // if the operand index is out of bounds.
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100582 const Operand* permOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model, false);
saoste01fe463152018-10-18 17:49:56 +0100583
584 std::vector<int32_t> perm(rank);
585 if (!permOperand)
586 {
587 // NOTE: If perm is not given, it is set to (n-1...0), where n is the rank of the tensor
588 for (unsigned int i = rank; i > 0; i--)
589 {
590 perm[rank - i] = boost::numeric_cast<int> (i - 1);
591 }
592 }
593 else
594 {
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100595 GetTensorInt32Values<hal_1_1::HalPolicy>(*permOperand, perm, model, data);
saoste01fe463152018-10-18 17:49:56 +0100596 }
597
598 std::vector<uint32_t> outputDims(perm.begin(), perm.begin() + rank);
599
600 auto permutationVector = armnn::PermutationVector(outputDims.data(), outputDims.size());
601 if (!permutationVector.IsEqual(NHWCToArmNN)
602 && !permutationVector.IsEqual(ArmNNToNHWC)
603 && !permutationVector.IsEqual({ 3, 2, 0, 1 }))
604 {
605 return Fail("%s: Only [0, 3, 1, 2], [0, 2, 3, 1] and [3, 2, 0, 1] permutations are supported.", __func__);
606 }
607
608 armnn::PermuteDescriptor permuteDesc;
609 permuteDesc.m_DimMappings = permutationVector;
610
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100611 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
saoste01fe463152018-10-18 17:49:56 +0100612 if (!output)
613 {
614 return Fail("%s: Could not read output 0", __func__);
615 }
616
617 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
618
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100619 if (!IsLayerSupportedForAnyBackend(__func__,
620 armnn::IsPermuteSupported,
621 data.m_Backends,
622 inputInfo,
623 outputInfo,
624 permuteDesc))
saoste01fe463152018-10-18 17:49:56 +0100625 {
626 return false;
627 }
628
629 armnn::IConnectableLayer* const layer = data.m_Network->AddPermuteLayer(permuteDesc);
630 assert(layer != nullptr);
631 input.Connect(layer->GetInputSlot(0));
saoste01b8471482018-10-10 09:44:51 +0100632
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100633 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
saoste01b8471482018-10-10 09:44:51 +0100634}
635
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000636bool HalPolicy::ConvertBatchToSpaceNd(const Operation& operation, const Model& model, ConversionData& data)
637{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100638 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000639 if (!input.IsValid())
640 {
641 return Fail("%s: Operation has invalid inputs", __func__);
642 }
643
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100644 const Operand* blockOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000645 if (!blockOperand)
646 {
647 return Fail("%s: Could not read input 1", __func__);
648 }
649
650 // Convert the block operand to int32
651 std::vector<int32_t> block;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100652 if (!GetTensorInt32Values<hal_1_1::HalPolicy>(*blockOperand, block, model, data))
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000653 {
654 return Fail("%s: Input 1 has invalid values", __func__);
655 }
656
657 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
658
659 unsigned int rank = inputInfo.GetNumDimensions();
660 if (rank != 4)
661 {
662 Fail("%s: Only inputs with rank equal to 4 are supported", __func__);
663 }
664
665 if (std::any_of(block.cbegin(), block.cend(), [](int32_t i){ return i < 1; }))
666 {
667 return Fail("%s: Block sizes for each spatial dimension of the input tensor must be"
668 " greater than or equal to 1", __func__);
669 }
670
671 armnn::BatchToSpaceNdDescriptor batchToSpaceNdDesc;
672 batchToSpaceNdDesc.m_BlockShape.assign(block.cbegin(), block.cend());
673 batchToSpaceNdDesc.m_DataLayout = armnn::DataLayout::NHWC;
674
675 // Setting crops to 0,0 0,0 as it is not supported in Android NN API
676 batchToSpaceNdDesc.m_Crops = {{0, 0}, {0, 0}};
677
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100678 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000679 if (!output)
680 {
681 return Fail("%s: Could not read output 0", __func__);
682 }
683
684 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
685
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100686 if (!IsLayerSupportedForAnyBackend(__func__,
687 armnn::IsBatchToSpaceNdSupported,
688 data.m_Backends,
689 inputInfo,
690 outputInfo,
691 batchToSpaceNdDesc))
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000692 {
693 return false;
694 }
695
696 armnn::IConnectableLayer* const layer = data.m_Network->AddBatchToSpaceNdLayer(batchToSpaceNdDesc);
697 assert(layer != nullptr);
698 input.Connect(layer->GetInputSlot(0));
699
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100700 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000701}
702
arovir01b0717b52018-09-05 17:03:25 +0100703} // namespace hal_1_1
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100704} // namespace armnn_driver