blob: cdf8c0f4e84c6986c42f945886cc56bc851414a8 [file] [log] [blame]
Mike Kellyb5fdf382019-06-11 16:35:25 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "HalPolicy.hpp"
7
Aron Virginas-Tarf03fcf02019-07-09 17:44:24 +01008#include "OutputShapeUtils.hpp"
9
Mike Kellyb5fdf382019-06-11 16:35:25 +010010#include "../1.0/HalPolicy.hpp"
11#include "../1.1/HalPolicy.hpp"
12
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +010013#include <DataLayoutIndexed.hpp>
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +010014#include <Half.hpp>
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +010015
16#include <cmath>
17
Mike Kellyb5fdf382019-06-11 16:35:25 +010018namespace armnn_driver
19{
20namespace hal_1_2
21{
22
23bool HandledByV1_0(V1_2::OperationType operationType)
24{
25 switch (static_cast<V1_0::OperationType>(operationType))
26 {
27 case V1_0::OperationType::ADD:
28 case V1_0::OperationType::AVERAGE_POOL_2D:
29 case V1_0::OperationType::CONCATENATION:
30 case V1_0::OperationType::DEPTH_TO_SPACE:
31 case V1_0::OperationType::DEQUANTIZE:
32 case V1_0::OperationType::EMBEDDING_LOOKUP:
33 case V1_0::OperationType::FLOOR:
34 case V1_0::OperationType::FULLY_CONNECTED:
35 case V1_0::OperationType::HASHTABLE_LOOKUP:
36 case V1_0::OperationType::L2_NORMALIZATION:
37 case V1_0::OperationType::L2_POOL_2D:
38 case V1_0::OperationType::LOCAL_RESPONSE_NORMALIZATION:
39 case V1_0::OperationType::LOGISTIC:
40 case V1_0::OperationType::LSH_PROJECTION:
41 case V1_0::OperationType::LSTM:
42 case V1_0::OperationType::MAX_POOL_2D:
43 case V1_0::OperationType::MUL:
44 case V1_0::OperationType::RELU:
45 case V1_0::OperationType::RELU1:
46 case V1_0::OperationType::RELU6:
47 case V1_0::OperationType::RESHAPE:
Mike Kellyb5fdf382019-06-11 16:35:25 +010048 case V1_0::OperationType::RNN:
49 case V1_0::OperationType::SOFTMAX:
50 case V1_0::OperationType::SPACE_TO_DEPTH:
51 case V1_0::OperationType::SVDF:
52 case V1_0::OperationType::TANH:
53 case V1_0::OperationType::OEM_OPERATION:
54 return true;
55 default:
56 return false;
57 }
58}
59
60bool HandledByV1_1(V1_2::OperationType operationType)
61{
62 if (HandledByV1_0(operationType))
63 {
64 return true;
65 }
66 switch (static_cast<V1_1::OperationType>(operationType))
67 {
68 case V1_1::OperationType::BATCH_TO_SPACE_ND:
69 case V1_1::OperationType::DIV:
70 case V1_1::OperationType::MEAN:
71 case V1_1::OperationType::PAD:
72 case V1_1::OperationType::SPACE_TO_BATCH_ND:
73 case V1_1::OperationType::SQUEEZE:
74 case V1_1::OperationType::STRIDED_SLICE:
75 case V1_1::OperationType::SUB:
76 case V1_1::OperationType::TRANSPOSE:
77 return true;
78 default:
79 return false;
80 }
81}
82
83bool HandledByV1_0(const V1_2::Operation& operation)
84{
85 return HandledByV1_0(operation.type);
86}
87
88bool HandledByV1_1(const V1_2::Operation& operation)
89{
90 return HandledByV1_1(operation.type);
91}
92
93V1_0::OperationType CastToV1_0(V1_2::OperationType type)
94{
95 return static_cast<V1_0::OperationType>(type);
96}
97
98V1_1::OperationType CastToV1_1(V1_2::OperationType type)
99{
100 return static_cast<V1_1::OperationType>(type);
101}
102
103V1_0::Operation ConvertToV1_0(const V1_2::Operation& operation)
104{
105 V1_0::Operation op;
106 op.type = CastToV1_0(operation.type);
107 op.inputs = operation.inputs;
108 op.outputs = operation.outputs;
109 return op;
110}
111
112V1_1::Operation ConvertToV1_1(const V1_2::Operation& operation)
113{
114 V1_1::Operation op;
115 op.type = CastToV1_1(operation.type);
116 op.inputs = operation.inputs;
117 op.outputs = operation.outputs;
118 return op;
119}
120
121bool HalPolicy::ConvertOperation(const Operation& operation, const Model& model, ConversionData& data)
122{
123 if (HandledByV1_0(operation) && compliantWithV1_0(model))
124 {
125 hal_1_0::HalPolicy::Operation v10Operation = ConvertToV1_0(operation);
126 hal_1_0::HalPolicy::Model v10Model = convertToV1_0(model);
127
128 return hal_1_0::HalPolicy::ConvertOperation(v10Operation, v10Model, data);
129 }
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100130
131 if (HandledByV1_1(operation) && compliantWithV1_1(model))
Mike Kellyb5fdf382019-06-11 16:35:25 +0100132 {
133 hal_1_1::HalPolicy::Operation v11Operation = ConvertToV1_1(operation);
134 hal_1_1::HalPolicy::Model v11Model = convertToV1_1(model);
135
136 return hal_1_1::HalPolicy::ConvertOperation(v11Operation, v11Model, data);
137 }
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100138
Mike Kellyb5fdf382019-06-11 16:35:25 +0100139 switch (operation.type)
140 {
141 case V1_2::OperationType::CONV_2D:
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100142 return ConvertConv2d(operation, model, data);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100143 case V1_2::OperationType::DEPTHWISE_CONV_2D:
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100144 return ConvertDepthwiseConv2d(operation, model, data);
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100145 case V1_2::OperationType::PAD_V2:
146 return ConvertPadV2(operation, model, data);
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100147 case V1_2::OperationType::PRELU:
148 return ConvertPrelu(operation, model, data);
Aron Virginas-Tarfb2fa292019-07-04 11:59:48 +0100149 case V1_2::OperationType::RESIZE_BILINEAR:
150 return ConvertResize(operation, model, data, armnn::ResizeMethod::Bilinear);
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +0100151 case V1_2::OperationType::RESIZE_NEAREST_NEIGHBOR:
Aron Virginas-Tarfb2fa292019-07-04 11:59:48 +0100152 return ConvertResize(operation, model, data, armnn::ResizeMethod::NearestNeighbor);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100153 default:
154 return Fail("%s: Operation type %s not supported in ArmnnDriver",
155 __func__, toString(operation.type).c_str());
156 }
157}
158
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100159bool HalPolicy::ConvertConv2d(const Operation& operation, const Model& model, ConversionData& data)
160{
161 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
162 if (!input.IsValid())
163 {
164 return Fail("%s: Operation has invalid inputs", __func__);
165 }
166
167 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
168 if (!output)
169 {
170 return Fail("%s: Could not read output 0", __func__);
171 }
172
173 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
174 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
175
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100176 if (IsDynamicOutput(outputInfo))
177 {
178 return Fail("%s: Dynamic output not supported", __func__);
179 }
180
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100181 // ArmNN does not currently support non-fixed weights or bias
182 const ConstTensorPin weightsPin =
183 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 1, model, data);
184 const ConstTensorPin biasPin =
185 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 2, model, data);
186
187 if (!weightsPin.IsValid())
188 {
189 return Fail("%s: Operation has invalid weights", __func__);
190 }
191
192 if (!biasPin.IsValid())
193 {
194 return Fail("%s: Operation has invalid biases", __func__);
195 }
196
197 armnn::ConstTensor weights = weightsPin.GetConstTensor();
198 armnn::ConstTensor bias = biasPin.GetConstTensor();
199 SanitizeBiasQuantizationScale(bias.GetInfo(), weights.GetInfo(), inputInfo);
200
201 armnn::Convolution2dDescriptor desc;
202 desc.m_DataLayout = armnn::DataLayout::NHWC;
203 ActivationFn activation;
204
205 // Determine whether padding is implicit or explicit
206 bool implicitPadding = operation.inputs.size() == 7 ||
207 (operation.inputs.size() >= 8 &&
208 GetInputOperand<hal_1_2::HalPolicy>(operation, 7, model)->type == OperandType::BOOL);
209
210 if (implicitPadding)
211 {
212 android::nn::PaddingScheme paddingScheme;
213 if (!GetInputPaddingScheme<hal_1_2::HalPolicy>(operation, 3, paddingScheme, model, data) ||
214 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_StrideX, model, data) ||
215 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_StrideY, model, data) ||
216 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 6, activation, model, data) ||
217 !GetOptionalConvolutionDilationParams<hal_1_2::HalPolicy>(operation, 8, desc, model, data))
218 {
219 return Fail("%s: Operation has invalid inputs (implicit padding)", __func__);
220 }
221
222 const uint32_t kernelX = weights.GetShape()[2];
223 const uint32_t kernelY = weights.GetShape()[1];
224 const uint32_t inputX = inputInfo.GetShape()[2];
225 const uint32_t inputY = inputInfo.GetShape()[1];
226
227 CalcPadding(inputX, kernelX, desc.m_StrideX, desc.m_PadLeft, desc.m_PadRight, paddingScheme);
228 CalcPadding(inputY, kernelY, desc.m_StrideY, desc.m_PadTop, desc.m_PadBottom, paddingScheme);
229
230 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 7, model, data);
231 }
232 else if (operation.inputs.size() >= 10)
233 {
234 // explicit padding
235 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 3, OperandType::INT32, desc.m_PadLeft, model, data) ||
236 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_PadRight, model, data) ||
237 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_PadTop, model, data) ||
238 !GetInputScalar<hal_1_2::HalPolicy>(operation, 6, OperandType::INT32, desc.m_PadBottom, model, data) ||
239 !GetInputScalar<hal_1_2::HalPolicy>(operation, 7, OperandType::INT32, desc.m_StrideX, model, data) ||
240 !GetInputScalar<hal_1_2::HalPolicy>(operation, 8, OperandType::INT32, desc.m_StrideY, model, data) ||
241 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 9, activation, model, data) ||
242 !GetOptionalConvolutionDilationParams<hal_1_2::HalPolicy>(operation, 11, desc, model, data))
243 {
244 return Fail("%s: Operation has invalid inputs (explicit padding)", __func__);
245 }
246 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 10, model, data);
247 }
248 else
249 {
250 return Fail("%s: Unsupported number of operation inputs", __func__);
251 }
252
253 desc.m_BiasEnabled = true;
254 armnn::Optional<armnn::TensorInfo> biases(bias.GetInfo());
255
256 if (!IsLayerSupportedForAnyBackend(__func__,
257 armnn::IsConvolution2dSupported,
258 data.m_Backends,
259 inputInfo,
260 outputInfo,
261 desc,
262 weights.GetInfo(),
263 biases))
264 {
265 return false;
266 }
267
268 armnn::IConnectableLayer* startLayer =
269 data.m_Network->AddConvolution2dLayer(desc, weights, armnn::Optional<armnn::ConstTensor>(bias));
270
271 if (!startLayer)
272 {
273 return Fail("%s: AddConvolution2dLayer failed", __func__);
274 }
275
276 armnn::IConnectableLayer* endLayer = ProcessActivation(outputInfo, activation, startLayer, data);
277
278 if (!endLayer)
279 {
280 return Fail("%s: ProcessActivation failed", __func__);
281 }
282
283 input.Connect(startLayer->GetInputSlot(0));
284
285 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *endLayer, model, data);
286}
287
288bool HalPolicy::ConvertDepthwiseConv2d(const Operation& operation, const Model& model, ConversionData& data)
289{
290 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
291
292 if (!input.IsValid())
293 {
294 return Fail("%s: Operation has invalid inputs", __func__);
295 }
296
297 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
298
299 if (!output)
300 {
301 return Fail("%s: Could not read output 0", __func__);
302 }
303
304 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
305 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
306
307 // ArmNN does not currently support non-fixed weights or bias
308 // Find the shape of the weights tensor. In AndroidNN this will be [ 1, H, W, I * M ]
309 const Operand* weightsOperand = GetInputOperand<hal_1_2::HalPolicy>(operation, 1, model);
310
311 if (weightsOperand == nullptr)
312 {
313 return Fail("%s: Operand is invalid", __func__);
314 }
315 armnn::DepthwiseConvolution2dDescriptor desc;
316 desc.m_DataLayout = armnn::DataLayout::NHWC;
317
318 // Determine whether padding is implicit or explicit
319 bool implicitPadding = operation.inputs.size() == 8 ||
320 (operation.inputs.size() >= 9 &&
321 GetInputOperand<hal_1_2::HalPolicy>(operation, 8, model)->type == OperandType::BOOL);
322
323 // Look ahead to find the optional DataLayout, if present
324 const uint32_t dataLayoutFlagIndex = implicitPadding ? 8 : 11;
325 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, dataLayoutFlagIndex, model, data);
326
327 armnnUtils::DataLayoutIndexed dataLayoutIndexed(desc.m_DataLayout);
328 unsigned int channelsIndex = dataLayoutIndexed.GetChannelsIndex();
329 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
330 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
331
332 // Reinterpret weight data as [ H, W, I, M ]
333 armnn::TensorShape weightsShape({ weightsOperand->dimensions[1],
334 weightsOperand->dimensions[2],
335 inputInfo.GetShape()[channelsIndex],
336 weightsOperand->dimensions[3] / inputInfo.GetShape()[channelsIndex] });
337
338 // Swizzle weight data [ H, W, I, M ] -> [ M, I, H, W ]
339 const armnn::PermutationVector HWIMToMIHW = { 2U, 3U, 1U, 0U };
340
341 const ConstTensorPin weightsPin =
342 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
343 1,
344 model,
345 data,
346 HWIMToMIHW,
347 &weightsShape);
348
349 // Bias is a 1D tensor
350 const ConstTensorPin biasPin =
351 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 2, model, data);
352
353 if (!weightsPin.IsValid())
354 {
355 return Fail("%s: Operation has invalid weights", __func__);
356 }
357
358 if (!biasPin.IsValid())
359 {
360 return Fail("%s: Operation has invalid biases", __func__);
361 }
362
363 armnn::ConstTensor weights = weightsPin.GetConstTensor();
364 armnn::ConstTensor bias = biasPin.GetConstTensor();
365 SanitizeBiasQuantizationScale(bias.GetInfo(), weights.GetInfo(), inputInfo);
366
367 ActivationFn activation;
368
369 if (implicitPadding)
370 {
371 android::nn::PaddingScheme paddingScheme;
372 if (!GetInputPaddingScheme<hal_1_2::HalPolicy>(operation, 3, paddingScheme, model, data) ||
373 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_StrideX, model, data) ||
374 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_StrideY, model, data) ||
375 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 7, activation, model, data) ||
376 !GetOptionalConvolutionDilationParams<hal_1_2::HalPolicy>(operation, 9, desc, model, data))
377 {
378 return Fail("%s: Operation has invalid inputs (implicit padding)", __func__);
379 }
380
381 const uint32_t kernelX = weights.GetShape()[3];
382 const uint32_t kernelY = weights.GetShape()[2];
383 const uint32_t inputX = inputInfo.GetShape()[widthIndex];
384 const uint32_t inputY = inputInfo.GetShape()[heightIndex];
385
386 CalcPadding(inputX, kernelX, desc.m_StrideX, desc.m_PadLeft, desc.m_PadRight, paddingScheme);
387 CalcPadding(inputY, kernelY, desc.m_StrideY, desc.m_PadTop, desc.m_PadBottom, paddingScheme);
388 }
389 else if (operation.inputs.size() >= 11)
390 {
391 // explicit padding
392 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 3, OperandType::INT32, desc.m_PadLeft, model, data) ||
393 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_PadRight, model, data) ||
394 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_PadTop, model, data) ||
395 !GetInputScalar<hal_1_2::HalPolicy>(operation, 6, OperandType::INT32, desc.m_PadBottom, model, data) ||
396 !GetInputScalar<hal_1_2::HalPolicy>(operation, 7, OperandType::INT32, desc.m_StrideX, model, data) ||
397 !GetInputScalar<hal_1_2::HalPolicy>(operation, 8, OperandType::INT32, desc.m_StrideY, model, data) ||
398 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 10, activation, model, data) ||
399 !GetOptionalConvolutionDilationParams<hal_1_2::HalPolicy>(operation, 12, desc, model, data))
400 {
401 return Fail("%s: Operation has invalid inputs (explicit padding)", __func__);
402 }
403 }
404 else
405 {
406 return Fail("%s: Unsupported number of operation inputs", __func__);
407 }
408
409 desc.m_BiasEnabled = true;
410 armnn::Optional<armnn::TensorInfo> biases(bias.GetInfo());
411
412 if (!IsLayerSupportedForAnyBackend(__func__,
413 armnn::IsDepthwiseConvolutionSupported,
414 data.m_Backends,
415 inputInfo,
416 outputInfo,
417 desc,
418 weights.GetInfo(),
419 biases))
420 {
421 return false;
422 }
423
424 armnn::IConnectableLayer* startLayer =
425 data.m_Network->AddDepthwiseConvolution2dLayer(desc, weights, armnn::Optional<armnn::ConstTensor>(bias));
426 if (!startLayer)
427 {
428 return Fail("%s: AddDepthwiseConvolution2dLayer failed", __func__);
429 }
430
431 armnn::IConnectableLayer* endLayer = ProcessActivation(outputInfo, activation, startLayer, data);
432 if (!endLayer)
433 {
434 return Fail("%s: ProcessActivation failed", __func__);
435 }
436
437 input.Connect(startLayer->GetInputSlot(0));
438
439 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *endLayer, model, data);
440}
441
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100442bool HalPolicy::ConvertPadV2(const Operation& operation, const Model& model, ConversionData& data)
443{
444 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
445 if (!input.IsValid())
446 {
447 return Fail("%s: Could not read input 0", __func__);
448 }
449
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100450 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
451 if (!output)
452 {
453 return Fail("%s: Could not read output", __func__);
454 }
455
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100456 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
457 unsigned int rank = inputInfo.GetNumDimensions();
458
459 armnn::PadDescriptor descriptor;
460 if (!ConvertPaddings<hal_1_2::HalPolicy>(operation, model, data, rank, descriptor))
461 {
462 return Fail("%s: Could not convert paddings", __func__);
463 }
464
Sadik Armagan310d8ff2019-07-11 10:53:38 +0100465 armnn::TensorInfo outputInfo = GetTensorInfoForOperand(*output);
466 if (IsDynamicOutput(outputInfo))
467 {
468 ALOGD("Output shape not set, will infer from inputs");
469 outputInfo.SetShape(InferPadOutputShape(inputInfo.GetShape(), descriptor.m_PadList));
470 }
471
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100472 // Determine type of padding value
473 OperandType operandType0;
474 OperandType operandType2;
475
476 if (!GetOperandType<hal_1_2::HalPolicy>(operation, 0, model, operandType0) ||
477 !GetOperandType<hal_1_2::HalPolicy>(operation, 2, model, operandType2))
478 {
479 return Fail("%s: Operation has invalid inputs", __func__);
480 }
481
482 // Read value to use for padding
483 if (operandType0 == OperandType::TENSOR_FLOAT16 && operandType2 == OperandType::FLOAT16)
484 {
485 armnn::Half f16PadValue;
486 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 2, operandType2, f16PadValue, model, data))
487 {
488 return Fail("%s: Could not read input 2 (FLOAT16)", __func__);
489 }
490
491 descriptor.m_PadValue = f16PadValue;
492 }
493 else if (operandType0 == OperandType::TENSOR_FLOAT32 && operandType2 == OperandType::FLOAT32)
494 {
495 if (!GetInputFloat32<hal_1_2::HalPolicy>(operation, 2, descriptor.m_PadValue, model, data))
496 {
497 return Fail("%s: Could not read input 2 (FLOAT32)", __func__);
498 }
499 }
500 else if (operandType0 == OperandType::TENSOR_QUANT8_ASYMM && operandType2 == OperandType::INT32)
501 {
502 int32_t quantizedPadValue = 0;
503 if (!GetInputInt32<hal_1_2::HalPolicy>(operation, 2, quantizedPadValue, model, data))
504 {
505 return Fail("%s: Could not read input 2 (INT32)", __func__);
506 }
507
508 descriptor.m_PadValue = armnn::Dequantize(quantizedPadValue,
509 inputInfo.GetQuantizationScale(),
510 inputInfo.GetQuantizationOffset());
511 }
512 else
513 {
514 return Fail("%s: Operation has invalid inputs: type mismatch", __func__);
515 }
516
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100517 if (!IsLayerSupportedForAnyBackend(__func__,
518 armnn::IsPadSupported,
519 data.m_Backends,
520 inputInfo,
521 outputInfo,
522 descriptor))
523 {
524 return false;
525 }
526
527 armnn::IConnectableLayer* const layer = data.m_Network->AddPadLayer(descriptor);
528 assert(layer != nullptr);
529 input.Connect(layer->GetInputSlot(0));
530 layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
531
Sadik Armagan310d8ff2019-07-11 10:53:38 +0100532 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation,
533 0,
534 *layer,
535 model,
536 data,
537 armnn::Optional<armnn::TensorInfo>(outputInfo));
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100538}
539
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100540bool HalPolicy::ConvertPrelu(const Operation& operation, const Model& model, ConversionData& data)
541{
542 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
543 LayerInputHandle alpha = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 1, model, data);
544
545 if (!input.IsValid() || !alpha.IsValid())
546 {
547 return Fail("%s: Operation has invalid inputs", __func__);
548 }
549
550 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
551
552 if (!output)
553 {
Matteo Martincigh0bd89a82019-07-02 16:53:10 +0100554 return Fail("%s: Could not read output", __func__);
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100555 }
556
557 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
558 const armnn::TensorInfo& alphaInfo = alpha.GetTensorInfo();
Aron Virginas-Tarf03fcf02019-07-09 17:44:24 +0100559
560 armnn::TensorInfo outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100561 if (IsDynamicOutput(outputInfo))
Aron Virginas-Tarf03fcf02019-07-09 17:44:24 +0100562 {
563 ALOGD("Output shape not set, will infer from inputs");
564 outputInfo.SetShape(InferPreluOutputShape(inputInfo.GetShape(), alphaInfo.GetShape()));
565 }
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100566
567 if (!IsLayerSupportedForAnyBackend(__func__,
568 armnn::IsPreluSupported,
569 data.m_Backends,
570 inputInfo,
571 alphaInfo,
572 outputInfo))
573 {
574 return false;
575 }
576
577 armnn::IConnectableLayer* const layer = data.m_Network->AddPreluLayer();
578
579 if (!layer)
580 {
581 return Fail("%s: AddPreluLayer failed", __func__);
582 }
583
Matteo Martincigh0bd89a82019-07-02 16:53:10 +0100584 BroadcastTensor(input, alpha, layer, *data.m_Network);
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100585
Aron Virginas-Tarf03fcf02019-07-09 17:44:24 +0100586 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation,
587 0,
588 *layer,
589 model,
590 data,
591 armnn::Optional<armnn::TensorInfo>(outputInfo));
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100592}
593
Aron Virginas-Tarfb2fa292019-07-04 11:59:48 +0100594bool HalPolicy::ConvertResize(const Operation& operation,
595 const Model& model,
596 ConversionData& data,
597 armnn::ResizeMethod resizeMethod)
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +0100598{
599 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
600 if (!input.IsValid())
601 {
602 return Fail("%s: Could not read input 0", __func__);
603 }
604
605 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
606 if (!output)
607 {
608 return Fail("%s: Could not read output 0", __func__);
609 }
610
611 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
612 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
613
614 armnn::ResizeDescriptor descriptor;
Aron Virginas-Tarfb2fa292019-07-04 11:59:48 +0100615 descriptor.m_Method = resizeMethod;
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +0100616 descriptor.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 3, model, data);
617
618 OperandType operandType1;
619 OperandType operandType2;
620
621 if (!GetOperandType<hal_1_2::HalPolicy>(operation, 1, model, operandType1) ||
622 !GetOperandType<hal_1_2::HalPolicy>(operation, 2, model, operandType2))
623 {
624 return Fail("%s: Operation has invalid inputs", __func__);
625 }
626
627 if (operandType1 != operandType2)
628 {
629 return Fail("%s: Operation has invalid inputs. Type of input 1 and 2 should be the same", __func__);
630 }
631
632 if (operandType1 == OperandType::INT32)
633 {
634 // Case 1: resizing by shape
635 int32_t targetWidth = 0;
636 int32_t targetHeight = 0;
637
638 if (!GetInputInt32<hal_1_2::HalPolicy>(operation, 1, targetWidth, model, data) ||
639 !GetInputInt32<hal_1_2::HalPolicy>(operation, 2, targetHeight, model, data))
640 {
641 return Fail("%s: Operation has invalid inputs for resizing by shape", __func__);
642 }
643
644 if (targetWidth < 0 || targetHeight < 0)
645 {
646 return Fail("%s: Operation has invalid inputs for resizing by shape. "
647 "Target width/height cannot be < 0", __func__);
648 }
649
650 descriptor.m_TargetWidth = static_cast<uint32_t>(targetWidth);
651 descriptor.m_TargetWidth = static_cast<uint32_t>(targetHeight);
652 }
653 else if (operandType1 == OperandType::FLOAT32)
654 {
655 // Case 2: resizing by scale
656 float widthScale = 1.0f;
657 float heightScale = 1.0f;
658
659 if (!GetInputFloat32<hal_1_2::HalPolicy>(operation, 1, widthScale, model, data) ||
660 !GetInputFloat32<hal_1_2::HalPolicy>(operation, 2, heightScale, model, data))
661 {
662 return Fail("%s: Operation has invalid inputs for resizing by scale", __func__);
663 }
664
665 const armnn::TensorShape& inputShape = inputInfo.GetShape();
666 armnnUtils::DataLayoutIndexed dataLayoutIndexed(descriptor.m_DataLayout);
667
668 float width = inputShape[dataLayoutIndexed.GetWidthIndex()];
669 float height = inputShape[dataLayoutIndexed.GetHeightIndex()];
670
671 descriptor.m_TargetWidth = std::floor(width * widthScale);
672 descriptor.m_TargetHeight = std::floor(height * heightScale);
673 }
674 else
675 {
676 // NOTE: FLOAT16 scales are not supported
677 return false;
678 }
679
680 if (!IsLayerSupportedForAnyBackend(__func__,
681 armnn::IsResizeSupported,
682 data.m_Backends,
683 inputInfo,
684 outputInfo,
685 descriptor))
686 {
687 return false;
688 }
689
690 armnn::IConnectableLayer* layer = data.m_Network->AddResizeLayer(descriptor);
691
692 assert(layer != nullptr);
693
694 layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
695 input.Connect(layer->GetInputSlot(0));
696
697 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
698}
699
Keith Davisa6bc52f2019-06-26 09:39:49 +0100700bool HalPolicy::ConvertSpaceToDepth(const Operation& operation, const Model& model, ConversionData& data)
701{
702 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
703
704 if (!input.IsValid() )
705 {
706 return Fail("%s: Operation has invalid inputs", __func__);
707 }
708
709 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
710 unsigned int rank = inputInfo.GetNumDimensions();
711
712 if (rank != 4)
713 {
714 return Fail("%s: Only inputs with rank 4 are supported", __func__);
715 }
716
717 armnn::SpaceToDepthDescriptor desc;
718
719 GetInputScalar<hal_1_2::HalPolicy>(operation, 1, OperandType::INT32, desc.m_BlockSize, model, data);
720
721 if (desc.m_BlockSize <= 1)
722 {
723 return Fail("%s: Block size must be at least 1 in all dimensions");
724 }
725
726 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 2, model, data);
727
728 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
729 if (!output)
730 {
731 return Fail("%s: Could not read output 0", __func__);
732 }
733
734 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
735 if (!IsLayerSupportedForAnyBackend(__func__,
736 armnn::IsSpaceToDepthSupported,
737 data.m_Backends,
738 inputInfo,
739 outputInfo,
740 desc))
741 {
742 return false;
743 }
744
745 armnn::IConnectableLayer* const layer = data.m_Network->AddSpaceToDepthLayer(desc);
746 assert(layer != nullptr);
747 input.Connect(layer->GetInputSlot(0));
748
749 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
750}
751
Mike Kellyb5fdf382019-06-11 16:35:25 +0100752} // namespace hal_1_2
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100753} // namespace armnn_driver