blob: 9f2c9be17f5e70fb0c5b62b3df9801edfdbf08a9 [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
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100132 if (!IsLayerSupportedForAnyBackend(__func__,
133 armnn::IsDivisionSupported,
134 data.m_Backends,
135 input0.GetTensorInfo(),
136 input1.GetTensorInfo(),
137 outInfo))
arovir01b0717b52018-09-05 17:03:25 +0100138 {
139 return false;
140 }
141
142 armnn::IConnectableLayer* const startLayer = data.m_Network->AddDivisionLayer();
143 armnn::IConnectableLayer* const endLayer = ProcessActivation(outInfo, activationFunction, startLayer, data);
144
145 const armnn::TensorInfo& inputTensorInfo0 = input0.GetTensorInfo();
146 const armnn::TensorInfo& inputTensorInfo1 = input1.GetTensorInfo();
147
148 if (endLayer)
149 {
150 BroadcastTensor(input0, input1, startLayer, *data.m_Network);
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100151 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *endLayer, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100152 }
153
154 return Fail("%s: ProcessActivation failed", __func__);
155}
156
David Beck38e12942018-09-12 16:02:24 +0100157bool HalPolicy::ConvertSub(const Operation& operation, const Model& model, ConversionData& data)
158{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100159 LayerInputHandle input0 = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
160 LayerInputHandle input1 = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 1, model, data);
David Beck38e12942018-09-12 16:02:24 +0100161
162 if (!input0.IsValid() || !input1.IsValid())
163 {
164 return Fail("%s: Operation has invalid inputs", __func__);
165 }
166
167 // The FuseActivation parameter is always the input index 2
168 // and it should be optional
169 ActivationFn activationFunction;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100170 if (!GetOptionalInputActivation<hal_1_1::HalPolicy>(operation, 2, activationFunction, model, data))
David Beck38e12942018-09-12 16:02:24 +0100171 {
172 return Fail("%s: Operation has invalid inputs", __func__);
173 }
174
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100175 const Operand* outputOperand = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
David Beck38e12942018-09-12 16:02:24 +0100176 if (!outputOperand)
177 {
178 return false;
179 }
180
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100181 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*outputOperand);
182 if (IsDynamicOutput(outputInfo))
183 {
184 return Fail("%s: Dynamic output not supported", __func__);
185 }
David Beck38e12942018-09-12 16:02:24 +0100186
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100187 if (!IsLayerSupportedForAnyBackend(__func__,
188 armnn::IsSubtractionSupported,
189 data.m_Backends,
190 input0.GetTensorInfo(),
191 input1.GetTensorInfo(),
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100192 outputInfo))
David Beck38e12942018-09-12 16:02:24 +0100193 {
194 return false;
195 }
196
197 armnn::IConnectableLayer* const startLayer = data.m_Network->AddSubtractionLayer();
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100198 armnn::IConnectableLayer* const endLayer = ProcessActivation(outputInfo, activationFunction, startLayer, data);
David Beck38e12942018-09-12 16:02:24 +0100199
200 const armnn::TensorInfo& inputTensorInfo0 = input0.GetTensorInfo();
201 const armnn::TensorInfo& inputTensorInfo1 = input1.GetTensorInfo();
202
203 if (endLayer)
204 {
205 BroadcastTensor(input0, input1, startLayer, *data.m_Network);
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100206 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *endLayer, model, data);
David Beck38e12942018-09-12 16:02:24 +0100207 }
208
209 return Fail("%s: ProcessActivation failed", __func__);
210}
211
narpra013c052562018-09-17 14:25:04 +0100212bool HalPolicy::ConvertMean(const Operation& operation, const Model& model, ConversionData& data)
213{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100214 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
narpra013c052562018-09-17 14:25:04 +0100215 if (!input.IsValid())
216 {
217 return Fail("%s: Operation has invalid inputs", __func__);
218 }
219
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100220 const Operand* axisOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
Matteo Martincighae622b72018-10-23 18:25:38 +0100221 if (!axisOperand)
222 {
223 return Fail("%s: Could not read input 1", __func__);
224 }
225
226 std::vector<int32_t> axis;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100227 if (!GetTensorInt32Values<hal_1_1::HalPolicy>(*axisOperand, axis, model, data))
Matteo Martincighae622b72018-10-23 18:25:38 +0100228 {
229 return Fail("%s: Input 1 has invalid values", __func__);
230 }
231
232 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
233
234 // Convert the axis to unsigned int and remove duplicates.
235 unsigned int rank = inputInfo.GetNumDimensions();
236 std::set<unsigned int> uniqueAxis;
237 std::transform(axis.begin(), axis.end(),
238 std::inserter(uniqueAxis, uniqueAxis.begin()),
239 [rank](int i) -> unsigned int { return (i + rank) % rank; });
240
241 // Get the "keep dims" flag.
242 int32_t keepDims = 0;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100243 if (!GetInputInt32<hal_1_1::HalPolicy>(operation, 2, keepDims, model, data))
Matteo Martincighae622b72018-10-23 18:25:38 +0100244 {
245 return Fail("%s: Could not read input 2", __func__);
246 }
narpra013c052562018-09-17 14:25:04 +0100247
248 armnn::MeanDescriptor descriptor;
Matteo Martincighae622b72018-10-23 18:25:38 +0100249 descriptor.m_Axis.assign(uniqueAxis.begin(), uniqueAxis.end());
250 descriptor.m_KeepDims = keepDims > 0;
narpra013c052562018-09-17 14:25:04 +0100251
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100252 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
narpra013c052562018-09-17 14:25:04 +0100253 if (!output)
254 {
255 return Fail("%s: Could not read output 0", __func__);
256 }
257
258 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
259
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100260 if (!IsLayerSupportedForAnyBackend(__func__,
261 armnn::IsMeanSupported,
262 data.m_Backends,
263 inputInfo,
264 outputInfo,
265 descriptor))
narpra013c052562018-09-17 14:25:04 +0100266 {
267 return false;
268 }
269
270 armnn::IConnectableLayer* const layer = data.m_Network->AddMeanLayer(descriptor);
narpra0196bedf02018-09-26 16:57:28 +0100271 assert(layer != nullptr);
272 input.Connect(layer->GetInputSlot(0));
narpra013c052562018-09-17 14:25:04 +0100273
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100274 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
narpra013c052562018-09-17 14:25:04 +0100275}
276
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100277bool HalPolicy::ConvertPad(const Operation& operation, const Model& model, ConversionData& data)
278{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100279 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100280 if (!input.IsValid())
281 {
282 return Fail("%s: Operation has invalid inputs", __func__);
283 }
284
285 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100286 unsigned int rank = inputInfo.GetNumDimensions();
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100287
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100288 armnn::PadDescriptor descriptor;
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100289 if (!ConvertPaddings<hal_1_1::HalPolicy>(operation, model, data, rank, descriptor))
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100290 {
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100291 return Fail("%s: Could not convert paddings", __func__);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100292 }
293
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100294 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100295 if (!output)
296 {
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100297 return Fail("%s: Could not read output", __func__);
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100298 }
299
Sadik Armagan310d8ff2019-07-11 10:53:38 +0100300 armnn::TensorInfo outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100301 if (IsDynamicOutput(outputInfo))
302 {
Sadik Armagan310d8ff2019-07-11 10:53:38 +0100303 ALOGD("Output shape not set, will infer from inputs");
304 outputInfo.SetShape(InferPadOutputShape(inputInfo.GetShape(), descriptor.m_PadList));
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100305 }
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100306
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100307 if (!IsLayerSupportedForAnyBackend(__func__,
308 armnn::IsPadSupported,
309 data.m_Backends,
310 inputInfo,
311 outputInfo,
312 descriptor))
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100313 {
314 return false;
315 }
316
317 armnn::IConnectableLayer* const layer = data.m_Network->AddPadLayer(descriptor);
318 assert(layer != nullptr);
319 input.Connect(layer->GetInputSlot(0));
320 layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
321
Sadik Armagan310d8ff2019-07-11 10:53:38 +0100322 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation,
323 0,
324 *layer,
325 model,
326 data,
327 armnn::Optional<armnn::TensorInfo>(outputInfo));
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100328}
329
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000330bool HalPolicy::ConvertSpaceToBatchNd(const Operation& operation, const Model& model, ConversionData& data)
331{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100332 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000333
334 if (!input.IsValid())
335 {
336 return Fail("%s: Operation has invalid inputs", __func__);
337 }
338
339 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
340 unsigned int rank = inputInfo.GetNumDimensions();
341 unsigned int spatialDim = rank - 2;
342
343 if (rank != 4)
344 {
345 Fail("%s: Only inputs with rank 4 are supported", __func__);
346 }
347
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100348 const Operand* blockShapeOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
349 const Operand* paddingsOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 2, model);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000350
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100351 armnn::TensorShape blockShapeOperandShape = GetTensorShapeForOperand(*blockShapeOperand);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000352 if (blockShapeOperandShape.GetNumDimensions() != 1 || blockShapeOperandShape.GetNumElements() != spatialDim)
353 {
354 return Fail("%s: Operation has invalid block shape operand: expected shape [%d]", __func__, spatialDim);
355 }
356
357 std::vector<int32_t> blockShape;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100358 GetTensorInt32Values<hal_1_1::HalPolicy>(*blockShapeOperand, blockShape, model, data);
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000359 if (std::any_of(blockShape.cbegin(), blockShape.cend(), [](int32_t i){ return i < 1; }))
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000360 {
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000361 return Fail("%s: Block shape must be at least 1 in all dimensions.", __func__);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000362 }
363
364 armnn::TensorShape paddingsOperandShape = GetTensorShapeForOperand(*paddingsOperand);
365 if (paddingsOperandShape.GetNumDimensions() != 2 || paddingsOperandShape.GetNumElements() != 2 * spatialDim)
366 {
367 return Fail("%s: Operation has invalid paddings operand: expected shape [%d, 2]", __func__, spatialDim);
368 }
369
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000370 std::vector<std::pair<unsigned int, unsigned int>> paddingList;
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000371 std::vector<int32_t> paddings;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100372 GetTensorInt32Values<hal_1_1::HalPolicy>(*paddingsOperand, paddings, model, data);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000373 for (unsigned int i = 0; i < paddings.size() - 1; i += 2)
374 {
375 int paddingBeforeInput = paddings[i];
376 int paddingAfterInput = paddings[i + 1];
377 if (paddingBeforeInput < 0 || paddingAfterInput < 0)
378 {
379 return Fail("%s: Operation has invalid paddings operand, invalid padding values.", __func__);
380 }
381
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000382 paddingList.emplace_back((unsigned int) paddingBeforeInput, (unsigned int) paddingAfterInput);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000383 }
384
Sadik Armagan8bef7b32018-12-20 14:14:12 +0000385 armnn::SpaceToBatchNdDescriptor descriptor;
386 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
387 descriptor.m_BlockShape.assign(blockShape.cbegin(), blockShape.cend());
388 descriptor.m_PadList.assign(paddingList.cbegin(), paddingList.cend());
389
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100390 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000391 if (!output)
392 {
393 return Fail("%s: Could not read output 0", __func__);
394 }
395
396 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100397 if (!IsLayerSupportedForAnyBackend(__func__,
398 armnn::IsSpaceToBatchNdSupported,
399 data.m_Backends,
400 inputInfo,
401 outputInfo,
402 descriptor))
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000403 {
404 return false;
405 }
406
407 armnn::IConnectableLayer* const layer = data.m_Network->AddSpaceToBatchNdLayer(descriptor);
408 assert(layer != nullptr);
409 input.Connect(layer->GetInputSlot(0));
410
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100411 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
Nattapat Chaimanowong81a68342018-11-05 14:04:47 +0000412}
413
saoste01b8471482018-10-10 09:44:51 +0100414bool HalPolicy::ConvertSqueeze(const Operation& operation, const Model& model, ConversionData& data)
415{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100416 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
saoste01b8471482018-10-10 09:44:51 +0100417
418 if (!input.IsValid())
419 {
420 return Fail("%s: Operation has invalid inputs", __func__);
421 }
422
423 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
424
425 unsigned int rank = inputInfo.GetNumDimensions();
saoste01fe463152018-10-18 17:49:56 +0100426 if (rank > 4)
saoste01b8471482018-10-10 09:44:51 +0100427 {
saoste01fe463152018-10-18 17:49:56 +0100428 Fail("%s: Inputs with rank greater than 4 are not supported", __func__);
saoste01b8471482018-10-10 09:44:51 +0100429 }
430
431 // NOTE: Axis is an optional parameter to SQUEEZE, therefore we do not want to generate a failure
432 // if the operand index is out of bounds.
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100433 const Operand* axisOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model, false);
saoste01b8471482018-10-10 09:44:51 +0100434
saoste01fe463152018-10-18 17:49:56 +0100435 const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
436
saoste01b8471482018-10-10 09:44:51 +0100437 std::vector<int32_t> axis;
saoste01fe463152018-10-18 17:49:56 +0100438 if (!axisOperand)
saoste01b8471482018-10-10 09:44:51 +0100439 {
440 axis.assign(dimensionSequence,
saoste01fe463152018-10-18 17:49:56 +0100441 dimensionSequence + rank);
saoste01b8471482018-10-10 09:44:51 +0100442 }
443 else
444 {
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100445 GetTensorInt32Values<hal_1_1::HalPolicy>(*axisOperand, axis, model, data);
saoste01b8471482018-10-10 09:44:51 +0100446 }
447
saoste01b8471482018-10-10 09:44:51 +0100448
saoste01a893efa2018-10-13 11:56:12 +0100449 std::vector<uint32_t> outputDims;
saoste01fe463152018-10-18 17:49:56 +0100450 for (unsigned int i = 0; i < rank; i++)
saoste01a893efa2018-10-13 11:56:12 +0100451 {
452 bool skipSqueeze = (std::find(axis.begin(), axis.end(), i) == axis.end());
453 auto currentDimension = inputInfo.GetShape()[i];
saoste01b8471482018-10-10 09:44:51 +0100454 if (skipSqueeze || currentDimension != 1)
455 {
456 outputDims.push_back(currentDimension);
457 }
458 }
459
saoste01fe463152018-10-18 17:49:56 +0100460 armnn::TensorShape outShape = armnn::TensorShape(outputDims.size(), outputDims.data());
saoste01b8471482018-10-10 09:44:51 +0100461
462 armnn::TensorInfo outputInfo = inputInfo;
463 outputInfo.SetShape(outShape);
464
465 armnn::ReshapeDescriptor reshapeDesc;
466 reshapeDesc.m_TargetShape = outputInfo.GetShape();
467
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100468 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
saoste01b8471482018-10-10 09:44:51 +0100469 if (!output)
470 {
471 return Fail("%s: Could not read output 0", __func__);
472 }
473
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100474 if (!IsLayerSupportedForAnyBackend(__func__,
475 armnn::IsReshapeSupported,
476 data.m_Backends,
477 inputInfo,
478 reshapeDesc))
saoste01b8471482018-10-10 09:44:51 +0100479 {
480 return false;
481 }
482
483 armnn::IConnectableLayer* const layer = data.m_Network->AddReshapeLayer(reshapeDesc);
484 assert(layer != nullptr);
485 input.Connect(layer->GetInputSlot(0));
saoste01fe463152018-10-18 17:49:56 +0100486
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100487 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
saoste01fe463152018-10-18 17:49:56 +0100488}
489
Sadik Armagan758eee82018-11-15 15:34:49 +0000490bool HalPolicy::ConvertStridedSlice(const Operation& operation, const Model& model, ConversionData& data)
491{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100492 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
Sadik Armagan758eee82018-11-15 15:34:49 +0000493 if (!input.IsValid())
494 {
495 return Fail("%s: Operation has invalid inputs", __func__);
496 }
497 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
498
499 unsigned int rank = inputInfo.GetNumDimensions();
500 if (rank > 4)
501 {
502 Fail("%s: Inputs with rank greater than 4 are not supported", __func__);
503 }
504
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100505 const Operand* beginOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
506 const Operand* endOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 2, model);
507 const Operand* stridesOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 3, model);
Sadik Armagan758eee82018-11-15 15:34:49 +0000508
509 std::vector<int32_t> beginValues;
510 std::vector<int32_t> endValues;
511 std::vector<int32_t> stridesValues;
512
513 // The length of the beginOperand, endOperand and stridesOperand must be of a rank(input)
514 auto ValidateInputOperands = [&] (const Operand& operand, std::vector<int32_t>& operandValues)
515 {
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100516 if (!GetTensorInt32Values<hal_1_1::HalPolicy>(operand, operandValues, model, data))
Sadik Armagan758eee82018-11-15 15:34:49 +0000517 {
518 return false;
519 }
520
521 if (operandValues.size() != rank)
522 {
523 return false;
524 }
525
526 return true;
527 };
528
529 if (!ValidateInputOperands(*beginOperand, beginValues)
530 || !ValidateInputOperands(*endOperand, endValues)
531 || !ValidateInputOperands(*stridesOperand, stridesValues))
532 {
533 return Fail("%s: Operation has invalid input operand", __func__);
534 }
535
536 // Stride cannot have value '0'
537 if (std::any_of(stridesValues.cbegin(), stridesValues.cend(), [](int32_t i){ return i == 0; }))
538 {
539 return Fail("%s: Stride must be non-zero value.", __func__);
540 }
541
542 armnn::StridedSliceDescriptor descriptor;
543 descriptor.m_Begin.assign(beginValues.cbegin(), beginValues.cend());
544 descriptor.m_End.assign(endValues.cbegin(), endValues.cend());
545 descriptor.m_Stride.assign(stridesValues.cbegin(), stridesValues.cend());
546 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
547
548 // Get the "begin_mask", "end_mask", and "shrink_axis_mask" flags
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100549 if (!GetInputInt32<hal_1_1::HalPolicy>(operation, 4, descriptor.m_BeginMask, model, data) ||
550 !GetInputInt32<hal_1_1::HalPolicy>(operation, 5, descriptor.m_EndMask, model, data) ||
551 !GetInputInt32<hal_1_1::HalPolicy>(operation, 6, descriptor.m_ShrinkAxisMask, model, data))
Sadik Armagan758eee82018-11-15 15:34:49 +0000552 {
553 return Fail("%s: Operation has invalid inputs", __func__);
554 }
555
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100556 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
Sadik Armagan758eee82018-11-15 15:34:49 +0000557 if (!output)
558 {
559 return Fail("%s: Could not read output 0", __func__);
560 }
561 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
562
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100563 if (!IsLayerSupportedForAnyBackend(__func__,
564 armnn::IsStridedSliceSupported,
565 data.m_Backends,
566 inputInfo,
567 outputInfo,
568 descriptor))
Sadik Armagan758eee82018-11-15 15:34:49 +0000569 {
570 return false;
571 }
572
573 armnn::IConnectableLayer* const layer = data.m_Network->AddStridedSliceLayer(descriptor);
574 assert(layer != nullptr);
575 input.Connect(layer->GetInputSlot(0));
576
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100577 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
Sadik Armagan758eee82018-11-15 15:34:49 +0000578}
579
saoste01fe463152018-10-18 17:49:56 +0100580bool HalPolicy::ConvertTranspose(const Operation& operation, const Model& model, ConversionData& data)
581{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100582 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
saoste01fe463152018-10-18 17:49:56 +0100583
584 if (!input.IsValid())
585 {
586 return Fail("%s: Operation has invalid inputs", __func__);
587 }
588
589 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
590
591 unsigned int rank = inputInfo.GetNumDimensions();
592 if (rank > 4)
593 {
594 Fail("%s: Inputs with rank greater than 4 are not supported", __func__);
595 }
596
597 // NOTE: Axis is an optional parameter to TRANSPOSE, therefore we do not want to generate a failure
598 // if the operand index is out of bounds.
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100599 const Operand* permOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model, false);
saoste01fe463152018-10-18 17:49:56 +0100600
601 std::vector<int32_t> perm(rank);
602 if (!permOperand)
603 {
604 // NOTE: If perm is not given, it is set to (n-1...0), where n is the rank of the tensor
605 for (unsigned int i = rank; i > 0; i--)
606 {
607 perm[rank - i] = boost::numeric_cast<int> (i - 1);
608 }
609 }
610 else
611 {
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100612 GetTensorInt32Values<hal_1_1::HalPolicy>(*permOperand, perm, model, data);
saoste01fe463152018-10-18 17:49:56 +0100613 }
614
615 std::vector<uint32_t> outputDims(perm.begin(), perm.begin() + rank);
616
617 auto permutationVector = armnn::PermutationVector(outputDims.data(), outputDims.size());
618 if (!permutationVector.IsEqual(NHWCToArmNN)
619 && !permutationVector.IsEqual(ArmNNToNHWC)
620 && !permutationVector.IsEqual({ 3, 2, 0, 1 }))
621 {
622 return Fail("%s: Only [0, 3, 1, 2], [0, 2, 3, 1] and [3, 2, 0, 1] permutations are supported.", __func__);
623 }
624
625 armnn::PermuteDescriptor permuteDesc;
626 permuteDesc.m_DimMappings = permutationVector;
627
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100628 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
saoste01fe463152018-10-18 17:49:56 +0100629 if (!output)
630 {
631 return Fail("%s: Could not read output 0", __func__);
632 }
633
634 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
635
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100636 if (!IsLayerSupportedForAnyBackend(__func__,
637 armnn::IsPermuteSupported,
638 data.m_Backends,
639 inputInfo,
640 outputInfo,
641 permuteDesc))
saoste01fe463152018-10-18 17:49:56 +0100642 {
643 return false;
644 }
645
646 armnn::IConnectableLayer* const layer = data.m_Network->AddPermuteLayer(permuteDesc);
647 assert(layer != nullptr);
648 input.Connect(layer->GetInputSlot(0));
saoste01b8471482018-10-10 09:44:51 +0100649
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100650 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
saoste01b8471482018-10-10 09:44:51 +0100651}
652
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000653bool HalPolicy::ConvertBatchToSpaceNd(const Operation& operation, const Model& model, ConversionData& data)
654{
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100655 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_1::HalPolicy>(operation, 0, model, data);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000656 if (!input.IsValid())
657 {
658 return Fail("%s: Operation has invalid inputs", __func__);
659 }
660
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100661 const Operand* blockOperand = GetInputOperand<hal_1_1::HalPolicy>(operation, 1, model);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000662 if (!blockOperand)
663 {
664 return Fail("%s: Could not read input 1", __func__);
665 }
666
667 // Convert the block operand to int32
668 std::vector<int32_t> block;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100669 if (!GetTensorInt32Values<hal_1_1::HalPolicy>(*blockOperand, block, model, data))
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000670 {
671 return Fail("%s: Input 1 has invalid values", __func__);
672 }
673
674 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
675
676 unsigned int rank = inputInfo.GetNumDimensions();
677 if (rank != 4)
678 {
679 Fail("%s: Only inputs with rank equal to 4 are supported", __func__);
680 }
681
682 if (std::any_of(block.cbegin(), block.cend(), [](int32_t i){ return i < 1; }))
683 {
684 return Fail("%s: Block sizes for each spatial dimension of the input tensor must be"
685 " greater than or equal to 1", __func__);
686 }
687
688 armnn::BatchToSpaceNdDescriptor batchToSpaceNdDesc;
689 batchToSpaceNdDesc.m_BlockShape.assign(block.cbegin(), block.cend());
690 batchToSpaceNdDesc.m_DataLayout = armnn::DataLayout::NHWC;
691
692 // Setting crops to 0,0 0,0 as it is not supported in Android NN API
693 batchToSpaceNdDesc.m_Crops = {{0, 0}, {0, 0}};
694
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100695 const Operand* output = GetOutputOperand<hal_1_1::HalPolicy>(operation, 0, model);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000696 if (!output)
697 {
698 return Fail("%s: Could not read output 0", __func__);
699 }
700
701 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
702
Nattapat Chaimanowongd5fd9762019-04-04 13:33:10 +0100703 if (!IsLayerSupportedForAnyBackend(__func__,
704 armnn::IsBatchToSpaceNdSupported,
705 data.m_Backends,
706 inputInfo,
707 outputInfo,
708 batchToSpaceNdDesc))
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000709 {
710 return false;
711 }
712
713 armnn::IConnectableLayer* const layer = data.m_Network->AddBatchToSpaceNdLayer(batchToSpaceNdDesc);
714 assert(layer != nullptr);
715 input.Connect(layer->GetInputSlot(0));
716
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100717 return SetupAndTrackLayerOutputSlot<hal_1_1::HalPolicy>(operation, 0, *layer, model, data);
Éanna Ó Catháin2cd99b92018-11-14 14:33:52 +0000718}
719
arovir01b0717b52018-09-05 17:03:25 +0100720} // namespace hal_1_1
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100721} // namespace armnn_driver