blob: e058e0262ba4d09b60211d0550e206b734262bcb [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
8#include "../1.0/HalPolicy.hpp"
9#include "../1.1/HalPolicy.hpp"
10
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +010011#include <DataLayoutIndexed.hpp>
12
13#include <cmath>
14
Mike Kellyb5fdf382019-06-11 16:35:25 +010015namespace armnn_driver
16{
17namespace hal_1_2
18{
19
20bool HandledByV1_0(V1_2::OperationType operationType)
21{
22 switch (static_cast<V1_0::OperationType>(operationType))
23 {
24 case V1_0::OperationType::ADD:
25 case V1_0::OperationType::AVERAGE_POOL_2D:
26 case V1_0::OperationType::CONCATENATION:
27 case V1_0::OperationType::DEPTH_TO_SPACE:
28 case V1_0::OperationType::DEQUANTIZE:
29 case V1_0::OperationType::EMBEDDING_LOOKUP:
30 case V1_0::OperationType::FLOOR:
31 case V1_0::OperationType::FULLY_CONNECTED:
32 case V1_0::OperationType::HASHTABLE_LOOKUP:
33 case V1_0::OperationType::L2_NORMALIZATION:
34 case V1_0::OperationType::L2_POOL_2D:
35 case V1_0::OperationType::LOCAL_RESPONSE_NORMALIZATION:
36 case V1_0::OperationType::LOGISTIC:
37 case V1_0::OperationType::LSH_PROJECTION:
38 case V1_0::OperationType::LSTM:
39 case V1_0::OperationType::MAX_POOL_2D:
40 case V1_0::OperationType::MUL:
41 case V1_0::OperationType::RELU:
42 case V1_0::OperationType::RELU1:
43 case V1_0::OperationType::RELU6:
44 case V1_0::OperationType::RESHAPE:
Mike Kellyb5fdf382019-06-11 16:35:25 +010045 case V1_0::OperationType::RNN:
46 case V1_0::OperationType::SOFTMAX:
47 case V1_0::OperationType::SPACE_TO_DEPTH:
48 case V1_0::OperationType::SVDF:
49 case V1_0::OperationType::TANH:
50 case V1_0::OperationType::OEM_OPERATION:
51 return true;
52 default:
53 return false;
54 }
55}
56
57bool HandledByV1_1(V1_2::OperationType operationType)
58{
59 if (HandledByV1_0(operationType))
60 {
61 return true;
62 }
63 switch (static_cast<V1_1::OperationType>(operationType))
64 {
65 case V1_1::OperationType::BATCH_TO_SPACE_ND:
66 case V1_1::OperationType::DIV:
67 case V1_1::OperationType::MEAN:
68 case V1_1::OperationType::PAD:
69 case V1_1::OperationType::SPACE_TO_BATCH_ND:
70 case V1_1::OperationType::SQUEEZE:
71 case V1_1::OperationType::STRIDED_SLICE:
72 case V1_1::OperationType::SUB:
73 case V1_1::OperationType::TRANSPOSE:
74 return true;
75 default:
76 return false;
77 }
78}
79
80bool HandledByV1_0(const V1_2::Operation& operation)
81{
82 return HandledByV1_0(operation.type);
83}
84
85bool HandledByV1_1(const V1_2::Operation& operation)
86{
87 return HandledByV1_1(operation.type);
88}
89
90V1_0::OperationType CastToV1_0(V1_2::OperationType type)
91{
92 return static_cast<V1_0::OperationType>(type);
93}
94
95V1_1::OperationType CastToV1_1(V1_2::OperationType type)
96{
97 return static_cast<V1_1::OperationType>(type);
98}
99
100V1_0::Operation ConvertToV1_0(const V1_2::Operation& operation)
101{
102 V1_0::Operation op;
103 op.type = CastToV1_0(operation.type);
104 op.inputs = operation.inputs;
105 op.outputs = operation.outputs;
106 return op;
107}
108
109V1_1::Operation ConvertToV1_1(const V1_2::Operation& operation)
110{
111 V1_1::Operation op;
112 op.type = CastToV1_1(operation.type);
113 op.inputs = operation.inputs;
114 op.outputs = operation.outputs;
115 return op;
116}
117
118bool HalPolicy::ConvertOperation(const Operation& operation, const Model& model, ConversionData& data)
119{
120 if (HandledByV1_0(operation) && compliantWithV1_0(model))
121 {
122 hal_1_0::HalPolicy::Operation v10Operation = ConvertToV1_0(operation);
123 hal_1_0::HalPolicy::Model v10Model = convertToV1_0(model);
124
125 return hal_1_0::HalPolicy::ConvertOperation(v10Operation, v10Model, data);
126 }
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100127
128 if (HandledByV1_1(operation) && compliantWithV1_1(model))
Mike Kellyb5fdf382019-06-11 16:35:25 +0100129 {
130 hal_1_1::HalPolicy::Operation v11Operation = ConvertToV1_1(operation);
131 hal_1_1::HalPolicy::Model v11Model = convertToV1_1(model);
132
133 return hal_1_1::HalPolicy::ConvertOperation(v11Operation, v11Model, data);
134 }
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100135
Mike Kellyb5fdf382019-06-11 16:35:25 +0100136 switch (operation.type)
137 {
138 case V1_2::OperationType::CONV_2D:
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100139 return ConvertConv2d(operation, model, data);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100140 case V1_2::OperationType::DEPTHWISE_CONV_2D:
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100141 return ConvertDepthwiseConv2d(operation, model, data);
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100142 case V1_2::OperationType::PRELU:
143 return ConvertPrelu(operation, model, data);
Aron Virginas-Tarfb2fa292019-07-04 11:59:48 +0100144 case V1_2::OperationType::RESIZE_BILINEAR:
145 return ConvertResize(operation, model, data, armnn::ResizeMethod::Bilinear);
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +0100146 case V1_2::OperationType::RESIZE_NEAREST_NEIGHBOR:
Aron Virginas-Tarfb2fa292019-07-04 11:59:48 +0100147 return ConvertResize(operation, model, data, armnn::ResizeMethod::NearestNeighbor);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100148 default:
149 return Fail("%s: Operation type %s not supported in ArmnnDriver",
150 __func__, toString(operation.type).c_str());
151 }
152}
153
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100154bool HalPolicy::ConvertConv2d(const Operation& operation, const Model& model, ConversionData& data)
155{
156 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
157 if (!input.IsValid())
158 {
159 return Fail("%s: Operation has invalid inputs", __func__);
160 }
161
162 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
163 if (!output)
164 {
165 return Fail("%s: Could not read output 0", __func__);
166 }
167
168 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
169 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
170
171 // ArmNN does not currently support non-fixed weights or bias
172 const ConstTensorPin weightsPin =
173 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 1, model, data);
174 const ConstTensorPin biasPin =
175 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 2, model, data);
176
177 if (!weightsPin.IsValid())
178 {
179 return Fail("%s: Operation has invalid weights", __func__);
180 }
181
182 if (!biasPin.IsValid())
183 {
184 return Fail("%s: Operation has invalid biases", __func__);
185 }
186
187 armnn::ConstTensor weights = weightsPin.GetConstTensor();
188 armnn::ConstTensor bias = biasPin.GetConstTensor();
189 SanitizeBiasQuantizationScale(bias.GetInfo(), weights.GetInfo(), inputInfo);
190
191 armnn::Convolution2dDescriptor desc;
192 desc.m_DataLayout = armnn::DataLayout::NHWC;
193 ActivationFn activation;
194
195 // Determine whether padding is implicit or explicit
196 bool implicitPadding = operation.inputs.size() == 7 ||
197 (operation.inputs.size() >= 8 &&
198 GetInputOperand<hal_1_2::HalPolicy>(operation, 7, model)->type == OperandType::BOOL);
199
200 if (implicitPadding)
201 {
202 android::nn::PaddingScheme paddingScheme;
203 if (!GetInputPaddingScheme<hal_1_2::HalPolicy>(operation, 3, paddingScheme, model, data) ||
204 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_StrideX, model, data) ||
205 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_StrideY, model, data) ||
206 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 6, activation, model, data) ||
207 !GetOptionalConvolutionDilationParams<hal_1_2::HalPolicy>(operation, 8, desc, model, data))
208 {
209 return Fail("%s: Operation has invalid inputs (implicit padding)", __func__);
210 }
211
212 const uint32_t kernelX = weights.GetShape()[2];
213 const uint32_t kernelY = weights.GetShape()[1];
214 const uint32_t inputX = inputInfo.GetShape()[2];
215 const uint32_t inputY = inputInfo.GetShape()[1];
216
217 CalcPadding(inputX, kernelX, desc.m_StrideX, desc.m_PadLeft, desc.m_PadRight, paddingScheme);
218 CalcPadding(inputY, kernelY, desc.m_StrideY, desc.m_PadTop, desc.m_PadBottom, paddingScheme);
219
220 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 7, model, data);
221 }
222 else if (operation.inputs.size() >= 10)
223 {
224 // explicit padding
225 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 3, OperandType::INT32, desc.m_PadLeft, model, data) ||
226 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_PadRight, model, data) ||
227 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_PadTop, model, data) ||
228 !GetInputScalar<hal_1_2::HalPolicy>(operation, 6, OperandType::INT32, desc.m_PadBottom, model, data) ||
229 !GetInputScalar<hal_1_2::HalPolicy>(operation, 7, OperandType::INT32, desc.m_StrideX, model, data) ||
230 !GetInputScalar<hal_1_2::HalPolicy>(operation, 8, OperandType::INT32, desc.m_StrideY, model, data) ||
231 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 9, activation, model, data) ||
232 !GetOptionalConvolutionDilationParams<hal_1_2::HalPolicy>(operation, 11, desc, model, data))
233 {
234 return Fail("%s: Operation has invalid inputs (explicit padding)", __func__);
235 }
236 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 10, model, data);
237 }
238 else
239 {
240 return Fail("%s: Unsupported number of operation inputs", __func__);
241 }
242
243 desc.m_BiasEnabled = true;
244 armnn::Optional<armnn::TensorInfo> biases(bias.GetInfo());
245
246 if (!IsLayerSupportedForAnyBackend(__func__,
247 armnn::IsConvolution2dSupported,
248 data.m_Backends,
249 inputInfo,
250 outputInfo,
251 desc,
252 weights.GetInfo(),
253 biases))
254 {
255 return false;
256 }
257
258 armnn::IConnectableLayer* startLayer =
259 data.m_Network->AddConvolution2dLayer(desc, weights, armnn::Optional<armnn::ConstTensor>(bias));
260
261 if (!startLayer)
262 {
263 return Fail("%s: AddConvolution2dLayer failed", __func__);
264 }
265
266 armnn::IConnectableLayer* endLayer = ProcessActivation(outputInfo, activation, startLayer, data);
267
268 if (!endLayer)
269 {
270 return Fail("%s: ProcessActivation failed", __func__);
271 }
272
273 input.Connect(startLayer->GetInputSlot(0));
274
275 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *endLayer, model, data);
276}
277
278bool HalPolicy::ConvertDepthwiseConv2d(const Operation& operation, const Model& model, ConversionData& data)
279{
280 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
281
282 if (!input.IsValid())
283 {
284 return Fail("%s: Operation has invalid inputs", __func__);
285 }
286
287 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
288
289 if (!output)
290 {
291 return Fail("%s: Could not read output 0", __func__);
292 }
293
294 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
295 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
296
297 // ArmNN does not currently support non-fixed weights or bias
298 // Find the shape of the weights tensor. In AndroidNN this will be [ 1, H, W, I * M ]
299 const Operand* weightsOperand = GetInputOperand<hal_1_2::HalPolicy>(operation, 1, model);
300
301 if (weightsOperand == nullptr)
302 {
303 return Fail("%s: Operand is invalid", __func__);
304 }
305 armnn::DepthwiseConvolution2dDescriptor desc;
306 desc.m_DataLayout = armnn::DataLayout::NHWC;
307
308 // Determine whether padding is implicit or explicit
309 bool implicitPadding = operation.inputs.size() == 8 ||
310 (operation.inputs.size() >= 9 &&
311 GetInputOperand<hal_1_2::HalPolicy>(operation, 8, model)->type == OperandType::BOOL);
312
313 // Look ahead to find the optional DataLayout, if present
314 const uint32_t dataLayoutFlagIndex = implicitPadding ? 8 : 11;
315 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, dataLayoutFlagIndex, model, data);
316
317 armnnUtils::DataLayoutIndexed dataLayoutIndexed(desc.m_DataLayout);
318 unsigned int channelsIndex = dataLayoutIndexed.GetChannelsIndex();
319 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
320 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
321
322 // Reinterpret weight data as [ H, W, I, M ]
323 armnn::TensorShape weightsShape({ weightsOperand->dimensions[1],
324 weightsOperand->dimensions[2],
325 inputInfo.GetShape()[channelsIndex],
326 weightsOperand->dimensions[3] / inputInfo.GetShape()[channelsIndex] });
327
328 // Swizzle weight data [ H, W, I, M ] -> [ M, I, H, W ]
329 const armnn::PermutationVector HWIMToMIHW = { 2U, 3U, 1U, 0U };
330
331 const ConstTensorPin weightsPin =
332 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
333 1,
334 model,
335 data,
336 HWIMToMIHW,
337 &weightsShape);
338
339 // Bias is a 1D tensor
340 const ConstTensorPin biasPin =
341 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 2, model, data);
342
343 if (!weightsPin.IsValid())
344 {
345 return Fail("%s: Operation has invalid weights", __func__);
346 }
347
348 if (!biasPin.IsValid())
349 {
350 return Fail("%s: Operation has invalid biases", __func__);
351 }
352
353 armnn::ConstTensor weights = weightsPin.GetConstTensor();
354 armnn::ConstTensor bias = biasPin.GetConstTensor();
355 SanitizeBiasQuantizationScale(bias.GetInfo(), weights.GetInfo(), inputInfo);
356
357 ActivationFn activation;
358
359 if (implicitPadding)
360 {
361 android::nn::PaddingScheme paddingScheme;
362 if (!GetInputPaddingScheme<hal_1_2::HalPolicy>(operation, 3, paddingScheme, model, data) ||
363 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_StrideX, model, data) ||
364 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_StrideY, model, data) ||
365 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 7, activation, model, data) ||
366 !GetOptionalConvolutionDilationParams<hal_1_2::HalPolicy>(operation, 9, desc, model, data))
367 {
368 return Fail("%s: Operation has invalid inputs (implicit padding)", __func__);
369 }
370
371 const uint32_t kernelX = weights.GetShape()[3];
372 const uint32_t kernelY = weights.GetShape()[2];
373 const uint32_t inputX = inputInfo.GetShape()[widthIndex];
374 const uint32_t inputY = inputInfo.GetShape()[heightIndex];
375
376 CalcPadding(inputX, kernelX, desc.m_StrideX, desc.m_PadLeft, desc.m_PadRight, paddingScheme);
377 CalcPadding(inputY, kernelY, desc.m_StrideY, desc.m_PadTop, desc.m_PadBottom, paddingScheme);
378 }
379 else if (operation.inputs.size() >= 11)
380 {
381 // explicit padding
382 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 3, OperandType::INT32, desc.m_PadLeft, model, data) ||
383 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_PadRight, model, data) ||
384 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_PadTop, model, data) ||
385 !GetInputScalar<hal_1_2::HalPolicy>(operation, 6, OperandType::INT32, desc.m_PadBottom, model, data) ||
386 !GetInputScalar<hal_1_2::HalPolicy>(operation, 7, OperandType::INT32, desc.m_StrideX, model, data) ||
387 !GetInputScalar<hal_1_2::HalPolicy>(operation, 8, OperandType::INT32, desc.m_StrideY, model, data) ||
388 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 10, activation, model, data) ||
389 !GetOptionalConvolutionDilationParams<hal_1_2::HalPolicy>(operation, 12, desc, model, data))
390 {
391 return Fail("%s: Operation has invalid inputs (explicit padding)", __func__);
392 }
393 }
394 else
395 {
396 return Fail("%s: Unsupported number of operation inputs", __func__);
397 }
398
399 desc.m_BiasEnabled = true;
400 armnn::Optional<armnn::TensorInfo> biases(bias.GetInfo());
401
402 if (!IsLayerSupportedForAnyBackend(__func__,
403 armnn::IsDepthwiseConvolutionSupported,
404 data.m_Backends,
405 inputInfo,
406 outputInfo,
407 desc,
408 weights.GetInfo(),
409 biases))
410 {
411 return false;
412 }
413
414 armnn::IConnectableLayer* startLayer =
415 data.m_Network->AddDepthwiseConvolution2dLayer(desc, weights, armnn::Optional<armnn::ConstTensor>(bias));
416 if (!startLayer)
417 {
418 return Fail("%s: AddDepthwiseConvolution2dLayer failed", __func__);
419 }
420
421 armnn::IConnectableLayer* endLayer = ProcessActivation(outputInfo, activation, startLayer, data);
422 if (!endLayer)
423 {
424 return Fail("%s: ProcessActivation failed", __func__);
425 }
426
427 input.Connect(startLayer->GetInputSlot(0));
428
429 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *endLayer, model, data);
430}
431
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100432bool HalPolicy::ConvertPrelu(const Operation& operation, const Model& model, ConversionData& data)
433{
434 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
435 LayerInputHandle alpha = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 1, model, data);
436
437 if (!input.IsValid() || !alpha.IsValid())
438 {
439 return Fail("%s: Operation has invalid inputs", __func__);
440 }
441
442 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
443
444 if (!output)
445 {
Matteo Martincigh0bd89a82019-07-02 16:53:10 +0100446 return Fail("%s: Could not read output", __func__);
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100447 }
448
449 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
450 const armnn::TensorInfo& alphaInfo = alpha.GetTensorInfo();
451 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
452
453 if (!IsLayerSupportedForAnyBackend(__func__,
454 armnn::IsPreluSupported,
455 data.m_Backends,
456 inputInfo,
457 alphaInfo,
458 outputInfo))
459 {
460 return false;
461 }
462
463 armnn::IConnectableLayer* const layer = data.m_Network->AddPreluLayer();
464
465 if (!layer)
466 {
467 return Fail("%s: AddPreluLayer failed", __func__);
468 }
469
Matteo Martincigh0bd89a82019-07-02 16:53:10 +0100470 BroadcastTensor(input, alpha, layer, *data.m_Network);
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100471
472 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
473}
474
Aron Virginas-Tarfb2fa292019-07-04 11:59:48 +0100475bool HalPolicy::ConvertResize(const Operation& operation,
476 const Model& model,
477 ConversionData& data,
478 armnn::ResizeMethod resizeMethod)
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +0100479{
480 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
481 if (!input.IsValid())
482 {
483 return Fail("%s: Could not read input 0", __func__);
484 }
485
486 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
487 if (!output)
488 {
489 return Fail("%s: Could not read output 0", __func__);
490 }
491
492 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
493 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
494
495 armnn::ResizeDescriptor descriptor;
Aron Virginas-Tarfb2fa292019-07-04 11:59:48 +0100496 descriptor.m_Method = resizeMethod;
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +0100497 descriptor.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 3, model, data);
498
499 OperandType operandType1;
500 OperandType operandType2;
501
502 if (!GetOperandType<hal_1_2::HalPolicy>(operation, 1, model, operandType1) ||
503 !GetOperandType<hal_1_2::HalPolicy>(operation, 2, model, operandType2))
504 {
505 return Fail("%s: Operation has invalid inputs", __func__);
506 }
507
508 if (operandType1 != operandType2)
509 {
510 return Fail("%s: Operation has invalid inputs. Type of input 1 and 2 should be the same", __func__);
511 }
512
513 if (operandType1 == OperandType::INT32)
514 {
515 // Case 1: resizing by shape
516 int32_t targetWidth = 0;
517 int32_t targetHeight = 0;
518
519 if (!GetInputInt32<hal_1_2::HalPolicy>(operation, 1, targetWidth, model, data) ||
520 !GetInputInt32<hal_1_2::HalPolicy>(operation, 2, targetHeight, model, data))
521 {
522 return Fail("%s: Operation has invalid inputs for resizing by shape", __func__);
523 }
524
525 if (targetWidth < 0 || targetHeight < 0)
526 {
527 return Fail("%s: Operation has invalid inputs for resizing by shape. "
528 "Target width/height cannot be < 0", __func__);
529 }
530
531 descriptor.m_TargetWidth = static_cast<uint32_t>(targetWidth);
532 descriptor.m_TargetWidth = static_cast<uint32_t>(targetHeight);
533 }
534 else if (operandType1 == OperandType::FLOAT32)
535 {
536 // Case 2: resizing by scale
537 float widthScale = 1.0f;
538 float heightScale = 1.0f;
539
540 if (!GetInputFloat32<hal_1_2::HalPolicy>(operation, 1, widthScale, model, data) ||
541 !GetInputFloat32<hal_1_2::HalPolicy>(operation, 2, heightScale, model, data))
542 {
543 return Fail("%s: Operation has invalid inputs for resizing by scale", __func__);
544 }
545
546 const armnn::TensorShape& inputShape = inputInfo.GetShape();
547 armnnUtils::DataLayoutIndexed dataLayoutIndexed(descriptor.m_DataLayout);
548
549 float width = inputShape[dataLayoutIndexed.GetWidthIndex()];
550 float height = inputShape[dataLayoutIndexed.GetHeightIndex()];
551
552 descriptor.m_TargetWidth = std::floor(width * widthScale);
553 descriptor.m_TargetHeight = std::floor(height * heightScale);
554 }
555 else
556 {
557 // NOTE: FLOAT16 scales are not supported
558 return false;
559 }
560
561 if (!IsLayerSupportedForAnyBackend(__func__,
562 armnn::IsResizeSupported,
563 data.m_Backends,
564 inputInfo,
565 outputInfo,
566 descriptor))
567 {
568 return false;
569 }
570
571 armnn::IConnectableLayer* layer = data.m_Network->AddResizeLayer(descriptor);
572
573 assert(layer != nullptr);
574
575 layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
576 input.Connect(layer->GetInputSlot(0));
577
578 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
579}
580
Mike Kellyb5fdf382019-06-11 16:35:25 +0100581} // namespace hal_1_2
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100582} // namespace armnn_driver