blob: 2d6d79706b6dc68e53ff277d0520aa52d08254ed [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"
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +01009#include "Utils.hpp"
Aron Virginas-Tarf03fcf02019-07-09 17:44:24 +010010
Mike Kellyb5fdf382019-06-11 16:35:25 +010011#include "../1.0/HalPolicy.hpp"
12#include "../1.1/HalPolicy.hpp"
13
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +010014#include <DataLayoutIndexed.hpp>
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +010015#include <Half.hpp>
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +010016
17#include <cmath>
18
Mike Kellyb5fdf382019-06-11 16:35:25 +010019namespace armnn_driver
20{
21namespace hal_1_2
22{
23
24bool HandledByV1_0(V1_2::OperationType operationType)
25{
26 switch (static_cast<V1_0::OperationType>(operationType))
27 {
28 case V1_0::OperationType::ADD:
29 case V1_0::OperationType::AVERAGE_POOL_2D:
30 case V1_0::OperationType::CONCATENATION:
31 case V1_0::OperationType::DEPTH_TO_SPACE:
32 case V1_0::OperationType::DEQUANTIZE:
33 case V1_0::OperationType::EMBEDDING_LOOKUP:
34 case V1_0::OperationType::FLOOR:
35 case V1_0::OperationType::FULLY_CONNECTED:
36 case V1_0::OperationType::HASHTABLE_LOOKUP:
37 case V1_0::OperationType::L2_NORMALIZATION:
38 case V1_0::OperationType::L2_POOL_2D:
39 case V1_0::OperationType::LOCAL_RESPONSE_NORMALIZATION:
40 case V1_0::OperationType::LOGISTIC:
41 case V1_0::OperationType::LSH_PROJECTION:
42 case V1_0::OperationType::LSTM:
43 case V1_0::OperationType::MAX_POOL_2D:
44 case V1_0::OperationType::MUL:
45 case V1_0::OperationType::RELU:
46 case V1_0::OperationType::RELU1:
47 case V1_0::OperationType::RELU6:
48 case V1_0::OperationType::RESHAPE:
Mike Kellyb5fdf382019-06-11 16:35:25 +010049 case V1_0::OperationType::RNN:
Mike Kellyb5fdf382019-06-11 16:35:25 +010050 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:
Mike Kellyb5fdf382019-06-11 16:35:25 +010071 case V1_1::OperationType::SPACE_TO_BATCH_ND:
72 case V1_1::OperationType::SQUEEZE:
73 case V1_1::OperationType::STRIDED_SLICE:
74 case V1_1::OperationType::SUB:
75 case V1_1::OperationType::TRANSPOSE:
76 return true;
77 default:
78 return false;
79 }
80}
81
82bool HandledByV1_0(const V1_2::Operation& operation)
83{
84 return HandledByV1_0(operation.type);
85}
86
87bool HandledByV1_1(const V1_2::Operation& operation)
88{
89 return HandledByV1_1(operation.type);
90}
91
92V1_0::OperationType CastToV1_0(V1_2::OperationType type)
93{
94 return static_cast<V1_0::OperationType>(type);
95}
96
97V1_1::OperationType CastToV1_1(V1_2::OperationType type)
98{
99 return static_cast<V1_1::OperationType>(type);
100}
101
102V1_0::Operation ConvertToV1_0(const V1_2::Operation& operation)
103{
104 V1_0::Operation op;
105 op.type = CastToV1_0(operation.type);
106 op.inputs = operation.inputs;
107 op.outputs = operation.outputs;
108 return op;
109}
110
111V1_1::Operation ConvertToV1_1(const V1_2::Operation& operation)
112{
113 V1_1::Operation op;
114 op.type = CastToV1_1(operation.type);
115 op.inputs = operation.inputs;
116 op.outputs = operation.outputs;
117 return op;
118}
119
120bool HalPolicy::ConvertOperation(const Operation& operation, const Model& model, ConversionData& data)
121{
122 if (HandledByV1_0(operation) && compliantWithV1_0(model))
123 {
124 hal_1_0::HalPolicy::Operation v10Operation = ConvertToV1_0(operation);
125 hal_1_0::HalPolicy::Model v10Model = convertToV1_0(model);
126
127 return hal_1_0::HalPolicy::ConvertOperation(v10Operation, v10Model, data);
128 }
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100129
130 if (HandledByV1_1(operation) && compliantWithV1_1(model))
Mike Kellyb5fdf382019-06-11 16:35:25 +0100131 {
132 hal_1_1::HalPolicy::Operation v11Operation = ConvertToV1_1(operation);
133 hal_1_1::HalPolicy::Model v11Model = convertToV1_1(model);
134
135 return hal_1_1::HalPolicy::ConvertOperation(v11Operation, v11Model, data);
136 }
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100137
Mike Kellyb5fdf382019-06-11 16:35:25 +0100138 switch (operation.type)
139 {
140 case V1_2::OperationType::CONV_2D:
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100141 return ConvertConv2d(operation, model, data);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100142 case V1_2::OperationType::DEPTHWISE_CONV_2D:
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100143 return ConvertDepthwiseConv2d(operation, model, data);
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +0100144 case V1_2::OperationType::MAXIMUM:
145 return ConvertMaximum(operation, model, data);
Ellen Norris-Thompson1cb29aa2019-07-11 17:27:37 +0100146 case V1_2::OperationType::MINIMUM:
147 return ConvertMinimum(operation, model, data);
Mike Kelly3c673942019-07-25 09:26:06 +0100148 case V1_2::OperationType::PAD:
Aron Virginas-Tarc921f6b2019-07-25 10:14:33 +0100149 return ConvertPad(operation, model, data);
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100150 case V1_2::OperationType::PAD_V2:
151 return ConvertPadV2(operation, model, data);
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100152 case V1_2::OperationType::PRELU:
153 return ConvertPrelu(operation, model, data);
Aron Virginas-Tarfb2fa292019-07-04 11:59:48 +0100154 case V1_2::OperationType::RESIZE_BILINEAR:
155 return ConvertResize(operation, model, data, armnn::ResizeMethod::Bilinear);
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +0100156 case V1_2::OperationType::RESIZE_NEAREST_NEIGHBOR:
Aron Virginas-Tarfb2fa292019-07-04 11:59:48 +0100157 return ConvertResize(operation, model, data, armnn::ResizeMethod::NearestNeighbor);
Francis Murtagh074c25a2019-07-22 16:40:57 +0100158 case V1_2::OperationType::SOFTMAX:
159 return ConvertSoftmax(operation, model, data);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100160 default:
161 return Fail("%s: Operation type %s not supported in ArmnnDriver",
162 __func__, toString(operation.type).c_str());
163 }
164}
165
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100166bool HalPolicy::ConvertConv2d(const Operation& operation, const Model& model, ConversionData& data)
167{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100168 ALOGV("hal_1_2::HalPolicy::ConvertConv2d()");
169
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100170 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
171 if (!input.IsValid())
172 {
173 return Fail("%s: Operation has invalid inputs", __func__);
174 }
175
176 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
177 if (!output)
178 {
179 return Fail("%s: Could not read output 0", __func__);
180 }
181
Aron Virginas-Tar2b173122019-07-15 14:29:09 +0100182 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
183 armnn::TensorInfo outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100184
Mike Kellye1d60bb2019-07-11 11:44:52 +0100185 armnn::Convolution2dDescriptor desc;
186 desc.m_DataLayout = armnn::DataLayout::NHWC;
187
188 // Determine whether padding is implicit or explicit
189 bool implicitPadding = operation.inputs.size() == 7 ||
190 (operation.inputs.size() >= 8 &&
191 GetInputOperand<hal_1_2::HalPolicy>(operation, 7, model)->type == OperandType::BOOL);
192
193 if (implicitPadding)
194 {
195 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 7, model, data);
196 }
197 else if (operation.inputs.size() >= 10)
198 {
199 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 10, model, data);
200 }
201
202 const armnn::PermutationVector OHWIToOIHW = {0, 2, 3, 1};
203
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100204 // ArmNN does not currently support non-fixed weights or bias
Mike Kellye1d60bb2019-07-11 11:44:52 +0100205 // The NNAPI filter is always OHWI [depth_out, filter_height, filter_width, depth_in] but ArmNN expects the
206 // filter's height and width indices to match the input's height and width indices so we permute it to OIHW if
207 // the DataLayout is NCHW
208 const ConstTensorPin weightsPin = (desc.m_DataLayout == armnn::DataLayout::NCHW) ?
209 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 1, model, data, OHWIToOIHW) :
210 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 1, model, data);
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100211 const ConstTensorPin biasPin =
Mike Kellye1d60bb2019-07-11 11:44:52 +0100212 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 2, model, data);
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100213
214 if (!weightsPin.IsValid())
215 {
216 return Fail("%s: Operation has invalid weights", __func__);
217 }
218
219 if (!biasPin.IsValid())
220 {
221 return Fail("%s: Operation has invalid biases", __func__);
222 }
223
224 armnn::ConstTensor weights = weightsPin.GetConstTensor();
225 armnn::ConstTensor bias = biasPin.GetConstTensor();
226 SanitizeBiasQuantizationScale(bias.GetInfo(), weights.GetInfo(), inputInfo);
227
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100228 ActivationFn activation;
229
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100230 if (implicitPadding)
231 {
232 android::nn::PaddingScheme paddingScheme;
233 if (!GetInputPaddingScheme<hal_1_2::HalPolicy>(operation, 3, paddingScheme, model, data) ||
234 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_StrideX, model, data) ||
235 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_StrideY, model, data) ||
236 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 6, activation, model, data) ||
237 !GetOptionalConvolutionDilationParams<hal_1_2::HalPolicy>(operation, 8, desc, model, data))
238 {
239 return Fail("%s: Operation has invalid inputs (implicit padding)", __func__);
240 }
241
Mike Kellye1d60bb2019-07-11 11:44:52 +0100242 armnnUtils::DataLayoutIndexed dataLayoutIndexed(desc.m_DataLayout);
243 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
244 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
245 const uint32_t kernelX = weights.GetShape()[widthIndex];
246 const uint32_t kernelY = weights.GetShape()[heightIndex];
247 const uint32_t inputX = inputInfo.GetShape()[widthIndex];
248 const uint32_t inputY = inputInfo.GetShape()[heightIndex];
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100249
Mike Kelly86b36d42019-07-12 16:39:33 +0100250 CalcPadding(inputX, kernelX, desc.m_StrideX, desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, paddingScheme);
251 CalcPadding(inputY, kernelY, desc.m_StrideY, desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, paddingScheme);
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100252
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100253 }
254 else if (operation.inputs.size() >= 10)
255 {
256 // explicit padding
257 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 3, OperandType::INT32, desc.m_PadLeft, model, data) ||
258 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_PadRight, model, data) ||
259 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_PadTop, model, data) ||
260 !GetInputScalar<hal_1_2::HalPolicy>(operation, 6, OperandType::INT32, desc.m_PadBottom, model, data) ||
261 !GetInputScalar<hal_1_2::HalPolicy>(operation, 7, OperandType::INT32, desc.m_StrideX, model, data) ||
262 !GetInputScalar<hal_1_2::HalPolicy>(operation, 8, OperandType::INT32, desc.m_StrideY, model, data) ||
263 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 9, activation, model, data) ||
264 !GetOptionalConvolutionDilationParams<hal_1_2::HalPolicy>(operation, 11, desc, model, data))
265 {
266 return Fail("%s: Operation has invalid inputs (explicit padding)", __func__);
267 }
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100268 }
269 else
270 {
271 return Fail("%s: Unsupported number of operation inputs", __func__);
272 }
273
274 desc.m_BiasEnabled = true;
275 armnn::Optional<armnn::TensorInfo> biases(bias.GetInfo());
276
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +0100277 if (IsDynamicTensor(outputInfo))
Aron Virginas-Tar2b173122019-07-15 14:29:09 +0100278 {
279 try
280 {
281 ALOGD("Output shape not set, will infer from inputs");
282 outputInfo.SetShape(InferConvolution2dOutputShape(inputInfo.GetShape(),
283 weights.GetInfo().GetShape(),
284 desc));
285 }
286 catch (armnn::Exception& e)
287 {
288 return Fail("%s: Could not infer dynamic output shape: %s", __func__, e.what());
289 }
290 }
291
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100292 bool isSupported = false;
293 FORWARD_LAYER_SUPPORT_FUNC(__func__,
294 IsConvolution2dSupported,
295 data.m_Backends,
296 isSupported,
297 inputInfo,
298 outputInfo,
299 desc,
300 weights.GetInfo(),
301 biases);
Aron Virginas-Tar2b173122019-07-15 14:29:09 +0100302
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100303 if (!isSupported)
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100304 {
305 return false;
306 }
307
308 armnn::IConnectableLayer* startLayer =
309 data.m_Network->AddConvolution2dLayer(desc, weights, armnn::Optional<armnn::ConstTensor>(bias));
310
311 if (!startLayer)
312 {
313 return Fail("%s: AddConvolution2dLayer failed", __func__);
314 }
315
316 armnn::IConnectableLayer* endLayer = ProcessActivation(outputInfo, activation, startLayer, data);
317
318 if (!endLayer)
319 {
320 return Fail("%s: ProcessActivation failed", __func__);
321 }
322
323 input.Connect(startLayer->GetInputSlot(0));
324
Aron Virginas-Tar2b173122019-07-15 14:29:09 +0100325 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation,
326 0,
327 *endLayer,
328 model,
329 data,
330 armnn::Optional<armnn::TensorInfo>(outputInfo));
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100331}
332
333bool HalPolicy::ConvertDepthwiseConv2d(const Operation& operation, const Model& model, ConversionData& data)
334{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100335 ALOGV("hal_1_2::HalPolicy::ConvertDepthwiseConv2d()");
336
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100337 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
338
339 if (!input.IsValid())
340 {
341 return Fail("%s: Operation has invalid inputs", __func__);
342 }
343
344 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
345
346 if (!output)
347 {
348 return Fail("%s: Could not read output 0", __func__);
349 }
350
351 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100352
353 // ArmNN does not currently support non-fixed weights or bias
354 // Find the shape of the weights tensor. In AndroidNN this will be [ 1, H, W, I * M ]
355 const Operand* weightsOperand = GetInputOperand<hal_1_2::HalPolicy>(operation, 1, model);
356
357 if (weightsOperand == nullptr)
358 {
359 return Fail("%s: Operand is invalid", __func__);
360 }
361 armnn::DepthwiseConvolution2dDescriptor desc;
362 desc.m_DataLayout = armnn::DataLayout::NHWC;
363
364 // Determine whether padding is implicit or explicit
365 bool implicitPadding = operation.inputs.size() == 8 ||
366 (operation.inputs.size() >= 9 &&
367 GetInputOperand<hal_1_2::HalPolicy>(operation, 8, model)->type == OperandType::BOOL);
368
369 // Look ahead to find the optional DataLayout, if present
370 const uint32_t dataLayoutFlagIndex = implicitPadding ? 8 : 11;
371 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, dataLayoutFlagIndex, model, data);
372
373 armnnUtils::DataLayoutIndexed dataLayoutIndexed(desc.m_DataLayout);
374 unsigned int channelsIndex = dataLayoutIndexed.GetChannelsIndex();
375 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
376 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
377
378 // Reinterpret weight data as [ H, W, I, M ]
379 armnn::TensorShape weightsShape({ weightsOperand->dimensions[1],
380 weightsOperand->dimensions[2],
381 inputInfo.GetShape()[channelsIndex],
382 weightsOperand->dimensions[3] / inputInfo.GetShape()[channelsIndex] });
383
384 // Swizzle weight data [ H, W, I, M ] -> [ M, I, H, W ]
385 const armnn::PermutationVector HWIMToMIHW = { 2U, 3U, 1U, 0U };
386
387 const ConstTensorPin weightsPin =
388 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
389 1,
390 model,
391 data,
392 HWIMToMIHW,
393 &weightsShape);
394
395 // Bias is a 1D tensor
396 const ConstTensorPin biasPin =
397 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 2, model, data);
398
399 if (!weightsPin.IsValid())
400 {
401 return Fail("%s: Operation has invalid weights", __func__);
402 }
403
404 if (!biasPin.IsValid())
405 {
406 return Fail("%s: Operation has invalid biases", __func__);
407 }
408
409 armnn::ConstTensor weights = weightsPin.GetConstTensor();
410 armnn::ConstTensor bias = biasPin.GetConstTensor();
411 SanitizeBiasQuantizationScale(bias.GetInfo(), weights.GetInfo(), inputInfo);
412
413 ActivationFn activation;
414
415 if (implicitPadding)
416 {
417 android::nn::PaddingScheme paddingScheme;
418 if (!GetInputPaddingScheme<hal_1_2::HalPolicy>(operation, 3, paddingScheme, model, data) ||
419 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_StrideX, model, data) ||
420 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_StrideY, model, data) ||
421 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 7, activation, model, data) ||
422 !GetOptionalConvolutionDilationParams<hal_1_2::HalPolicy>(operation, 9, desc, model, data))
423 {
424 return Fail("%s: Operation has invalid inputs (implicit padding)", __func__);
425 }
426
427 const uint32_t kernelX = weights.GetShape()[3];
428 const uint32_t kernelY = weights.GetShape()[2];
429 const uint32_t inputX = inputInfo.GetShape()[widthIndex];
430 const uint32_t inputY = inputInfo.GetShape()[heightIndex];
431
Mike Kelly86b36d42019-07-12 16:39:33 +0100432 CalcPadding(inputX, kernelX, desc.m_StrideX, desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, paddingScheme);
433 CalcPadding(inputY, kernelY, desc.m_StrideY, desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, paddingScheme);
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100434 }
435 else if (operation.inputs.size() >= 11)
436 {
437 // explicit padding
438 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 3, OperandType::INT32, desc.m_PadLeft, model, data) ||
439 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_PadRight, model, data) ||
440 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_PadTop, model, data) ||
441 !GetInputScalar<hal_1_2::HalPolicy>(operation, 6, OperandType::INT32, desc.m_PadBottom, model, data) ||
442 !GetInputScalar<hal_1_2::HalPolicy>(operation, 7, OperandType::INT32, desc.m_StrideX, model, data) ||
443 !GetInputScalar<hal_1_2::HalPolicy>(operation, 8, OperandType::INT32, desc.m_StrideY, model, data) ||
444 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 10, activation, model, data) ||
445 !GetOptionalConvolutionDilationParams<hal_1_2::HalPolicy>(operation, 12, desc, model, data))
446 {
447 return Fail("%s: Operation has invalid inputs (explicit padding)", __func__);
448 }
449 }
450 else
451 {
452 return Fail("%s: Unsupported number of operation inputs", __func__);
453 }
454
455 desc.m_BiasEnabled = true;
456 armnn::Optional<armnn::TensorInfo> biases(bias.GetInfo());
457
Aron Virginas-Tar9fd37392019-07-15 18:04:32 +0100458 armnn::TensorInfo outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +0100459 if (IsDynamicTensor(outputInfo))
Aron Virginas-Tar9fd37392019-07-15 18:04:32 +0100460 {
461 try
462 {
463 ALOGD("Output shape not set, will infer from inputs");
464 outputInfo.SetShape(InferDepthwiseConvolution2dOutputShape(inputInfo.GetShape(),
465 weights.GetInfo().GetShape(),
466 desc));
467 }
468 catch (armnn::Exception& e)
469 {
470 return Fail("%s: Could not infer dynamic output shape: %s", __func__, e.what());
471 }
472 }
473
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100474 bool isSupported = false;
475 FORWARD_LAYER_SUPPORT_FUNC(__func__,
476 IsDepthwiseConvolutionSupported,
477 data.m_Backends,
478 isSupported,
479 inputInfo,
480 outputInfo,
481 desc,
482 weights.GetInfo(),
483 biases);
Aron Virginas-Tar9fd37392019-07-15 18:04:32 +0100484
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100485 if (!isSupported)
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100486 {
487 return false;
488 }
489
490 armnn::IConnectableLayer* startLayer =
491 data.m_Network->AddDepthwiseConvolution2dLayer(desc, weights, armnn::Optional<armnn::ConstTensor>(bias));
Aron Virginas-Tar9fd37392019-07-15 18:04:32 +0100492
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100493 if (!startLayer)
494 {
495 return Fail("%s: AddDepthwiseConvolution2dLayer failed", __func__);
496 }
497
498 armnn::IConnectableLayer* endLayer = ProcessActivation(outputInfo, activation, startLayer, data);
499 if (!endLayer)
500 {
501 return Fail("%s: ProcessActivation failed", __func__);
502 }
503
504 input.Connect(startLayer->GetInputSlot(0));
505
Aron Virginas-Tar9fd37392019-07-15 18:04:32 +0100506 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation,
507 0,
508 *endLayer,
509 model,
510 data,
511 armnn::Optional<armnn::TensorInfo>(outputInfo));
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100512}
513
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +0100514bool HalPolicy::ConvertMaximum(const Operation& operation, const Model& model, ConversionData& data)
515{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100516 ALOGV("hal_1_2::HalPolicy::ConvertMaximum()");
517
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +0100518 LayerInputHandle input0 = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
519 LayerInputHandle input1 = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 1, model, data);
520
521 if (!input0.IsValid() || !input1.IsValid())
522 {
523 return Fail("%s: Operation has invalid inputs", __func__);
524 }
525
526 const Operand* outputOperand = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
527 if (!outputOperand)
528 {
529 return Fail("%s: Could not read output", __func__);
530 }
531
Aron Virginas-Tard7593232019-07-16 13:17:06 +0100532 armnn::TensorInfo outInfo = GetTensorInfoForOperand(*outputOperand);
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +0100533 if (IsDynamicTensor(outInfo))
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +0100534 {
535 ALOGD("Output shape not set, will infer from inputs");
536 outInfo.SetShape(InferMaximumOutputShape(input0.GetTensorInfo().GetShape(), input1.GetTensorInfo().GetShape()));
537 }
538
Aron Virginas-Tard7593232019-07-16 13:17:06 +0100539 bool isSupported = false;
540 FORWARD_LAYER_SUPPORT_FUNC(__func__,
541 IsMaximumSupported,
542 data.m_Backends,
543 isSupported,
544 input0.GetTensorInfo(),
545 input1.GetTensorInfo(),
546 outInfo);
547
548 if (!isSupported)
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +0100549 {
550 return false;
551 }
552
553 armnn::IConnectableLayer* layer = data.m_Network->AddMaximumLayer();
554 assert(layer != nullptr);
555 BroadcastTensor(input0, input1, layer, *data.m_Network);
556
557 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation,
558 0,
559 *layer,
560 model,
561 data,
562 armnn::Optional<armnn::TensorInfo>(outInfo));
563}
564
Ellen Norris-Thompson1cb29aa2019-07-11 17:27:37 +0100565bool HalPolicy::ConvertMinimum(const Operation& operation, const Model& model, ConversionData& data)
566{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100567 ALOGV("hal_1_2::HalPolicy::ConvertMinimum()");
568
Ellen Norris-Thompson1cb29aa2019-07-11 17:27:37 +0100569 LayerInputHandle input0 = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
570 LayerInputHandle input1 = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 1, model, data);
571
572 if (!input0.IsValid() || !input1.IsValid())
573 {
574 return Fail("%s: Operation has invalid inputs", __func__);
575 }
576
577 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
578 if (!output)
579 {
580 return Fail("%s: Could not read output 0", __func__);
581 }
582
583 armnn::TensorInfo outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +0100584 if (IsDynamicTensor(outputInfo))
Ellen Norris-Thompson1cb29aa2019-07-11 17:27:37 +0100585 {
586 ALOGD("Output shape not set, will infer from inputs");
587 outputInfo.SetShape(InferMinimumOutputShape(input0.GetTensorInfo().GetShape(),
588 input1.GetTensorInfo().GetShape()));
589 }
590
591 bool isSupported = false;
592 FORWARD_LAYER_SUPPORT_FUNC(__func__,
593 IsMinimumSupported,
594 data.m_Backends,
595 isSupported,
596 input0.GetTensorInfo(),
597 input1.GetTensorInfo(),
598 outputInfo);
599
600 if (!isSupported)
601 {
602 return false;
603 }
604
605 armnn::IConnectableLayer* const layer = data.m_Network->AddMinimumLayer();
606 assert(layer != nullptr);
607 BroadcastTensor(input0, input1, layer, *data.m_Network);
608
609 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation,
610 0,
611 *layer,
612 model,
613 data,
614 armnn::Optional<armnn::TensorInfo>(outputInfo));
615}
616
Aron Virginas-Tarc921f6b2019-07-25 10:14:33 +0100617bool HalPolicy::ConvertPad(const Operation& operation, const Model& model, ConversionData& data)
618{
619 ALOGV("hal_1_2::HalPolicy::ConvertPad()");
620 return ::ConvertPad<hal_1_2::HalPolicy>(operation, model, data);
621}
622
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100623bool HalPolicy::ConvertPadV2(const Operation& operation, const Model& model, ConversionData& data)
624{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100625 ALOGV("hal_1_2::HalPolicy::ConvertPadV2()");
626
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100627 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
628 if (!input.IsValid())
629 {
630 return Fail("%s: Could not read input 0", __func__);
631 }
632
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100633 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
634 if (!output)
635 {
636 return Fail("%s: Could not read output", __func__);
637 }
638
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100639 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
640 unsigned int rank = inputInfo.GetNumDimensions();
641
642 armnn::PadDescriptor descriptor;
643 if (!ConvertPaddings<hal_1_2::HalPolicy>(operation, model, data, rank, descriptor))
644 {
645 return Fail("%s: Could not convert paddings", __func__);
646 }
647
Sadik Armagan310d8ff2019-07-11 10:53:38 +0100648 armnn::TensorInfo outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +0100649 if (IsDynamicTensor(outputInfo))
Sadik Armagan310d8ff2019-07-11 10:53:38 +0100650 {
651 ALOGD("Output shape not set, will infer from inputs");
652 outputInfo.SetShape(InferPadOutputShape(inputInfo.GetShape(), descriptor.m_PadList));
653 }
654
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100655 // Determine type of padding value
656 OperandType operandType0;
657 OperandType operandType2;
658
659 if (!GetOperandType<hal_1_2::HalPolicy>(operation, 0, model, operandType0) ||
660 !GetOperandType<hal_1_2::HalPolicy>(operation, 2, model, operandType2))
661 {
662 return Fail("%s: Operation has invalid inputs", __func__);
663 }
664
665 // Read value to use for padding
666 if (operandType0 == OperandType::TENSOR_FLOAT16 && operandType2 == OperandType::FLOAT16)
667 {
668 armnn::Half f16PadValue;
669 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 2, operandType2, f16PadValue, model, data))
670 {
671 return Fail("%s: Could not read input 2 (FLOAT16)", __func__);
672 }
673
674 descriptor.m_PadValue = f16PadValue;
675 }
676 else if (operandType0 == OperandType::TENSOR_FLOAT32 && operandType2 == OperandType::FLOAT32)
677 {
678 if (!GetInputFloat32<hal_1_2::HalPolicy>(operation, 2, descriptor.m_PadValue, model, data))
679 {
680 return Fail("%s: Could not read input 2 (FLOAT32)", __func__);
681 }
682 }
683 else if (operandType0 == OperandType::TENSOR_QUANT8_ASYMM && operandType2 == OperandType::INT32)
684 {
Mike Kelly3c673942019-07-25 09:26:06 +0100685 int32_t intPadValue = 0;
686 if (!GetInputInt32<hal_1_2::HalPolicy>(operation, 2, intPadValue, model, data))
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100687 {
688 return Fail("%s: Could not read input 2 (INT32)", __func__);
689 }
Mike Kelly3c673942019-07-25 09:26:06 +0100690 descriptor.m_PadValue = intPadValue;
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100691 }
692 else
693 {
694 return Fail("%s: Operation has invalid inputs: type mismatch", __func__);
695 }
696
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100697 bool isSupported = false;
698 FORWARD_LAYER_SUPPORT_FUNC(__func__,
699 IsPadSupported,
700 data.m_Backends,
701 isSupported,
702 inputInfo,
703 outputInfo,
704 descriptor);
705 if (!isSupported)
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100706 {
707 return false;
708 }
709
710 armnn::IConnectableLayer* const layer = data.m_Network->AddPadLayer(descriptor);
711 assert(layer != nullptr);
712 input.Connect(layer->GetInputSlot(0));
713 layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
714
Sadik Armagan310d8ff2019-07-11 10:53:38 +0100715 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation,
716 0,
717 *layer,
718 model,
719 data,
720 armnn::Optional<armnn::TensorInfo>(outputInfo));
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +0100721}
722
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100723bool HalPolicy::ConvertPrelu(const Operation& operation, const Model& model, ConversionData& data)
724{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100725 ALOGV("hal_1_2::HalPolicy::ConvertPrelu()");
726
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100727 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
728 LayerInputHandle alpha = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 1, model, data);
729
730 if (!input.IsValid() || !alpha.IsValid())
731 {
732 return Fail("%s: Operation has invalid inputs", __func__);
733 }
734
735 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
736
737 if (!output)
738 {
Matteo Martincigh0bd89a82019-07-02 16:53:10 +0100739 return Fail("%s: Could not read output", __func__);
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100740 }
741
742 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
743 const armnn::TensorInfo& alphaInfo = alpha.GetTensorInfo();
Aron Virginas-Tarf03fcf02019-07-09 17:44:24 +0100744
745 armnn::TensorInfo outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +0100746 if (IsDynamicTensor(outputInfo))
Aron Virginas-Tarf03fcf02019-07-09 17:44:24 +0100747 {
748 ALOGD("Output shape not set, will infer from inputs");
749 outputInfo.SetShape(InferPreluOutputShape(inputInfo.GetShape(), alphaInfo.GetShape()));
750 }
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100751
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100752 bool isSupported = false;
753 FORWARD_LAYER_SUPPORT_FUNC(__func__,
754 IsPreluSupported,
755 data.m_Backends,
756 isSupported,
757 inputInfo,
758 alphaInfo,
759 outputInfo);
760 if (!isSupported)
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100761 {
762 return false;
763 }
764
765 armnn::IConnectableLayer* const layer = data.m_Network->AddPreluLayer();
766
767 if (!layer)
768 {
769 return Fail("%s: AddPreluLayer failed", __func__);
770 }
771
Matteo Martincigh0bd89a82019-07-02 16:53:10 +0100772 BroadcastTensor(input, alpha, layer, *data.m_Network);
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100773
Aron Virginas-Tarf03fcf02019-07-09 17:44:24 +0100774 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation,
775 0,
776 *layer,
777 model,
778 data,
779 armnn::Optional<armnn::TensorInfo>(outputInfo));
Matteo Martincigh17ffff32019-06-27 14:12:55 +0100780}
781
Aron Virginas-Tarfb2fa292019-07-04 11:59:48 +0100782bool HalPolicy::ConvertResize(const Operation& operation,
783 const Model& model,
784 ConversionData& data,
785 armnn::ResizeMethod resizeMethod)
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +0100786{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100787 ALOGV("hal_1_2::HalPolicy::ConvertResize()");
788
789 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +0100790 if (!input.IsValid())
791 {
792 return Fail("%s: Could not read input 0", __func__);
793 }
794
795 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
796 if (!output)
797 {
798 return Fail("%s: Could not read output 0", __func__);
799 }
800
801 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
Aron Virginas-Tarbe5d3562019-07-16 11:32:29 +0100802 armnn::TensorInfo outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +0100803
804 armnn::ResizeDescriptor descriptor;
Aron Virginas-Tarfb2fa292019-07-04 11:59:48 +0100805 descriptor.m_Method = resizeMethod;
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +0100806 descriptor.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 3, model, data);
807
808 OperandType operandType1;
809 OperandType operandType2;
810
811 if (!GetOperandType<hal_1_2::HalPolicy>(operation, 1, model, operandType1) ||
812 !GetOperandType<hal_1_2::HalPolicy>(operation, 2, model, operandType2))
813 {
814 return Fail("%s: Operation has invalid inputs", __func__);
815 }
816
817 if (operandType1 != operandType2)
818 {
819 return Fail("%s: Operation has invalid inputs. Type of input 1 and 2 should be the same", __func__);
820 }
821
822 if (operandType1 == OperandType::INT32)
823 {
824 // Case 1: resizing by shape
825 int32_t targetWidth = 0;
826 int32_t targetHeight = 0;
827
828 if (!GetInputInt32<hal_1_2::HalPolicy>(operation, 1, targetWidth, model, data) ||
829 !GetInputInt32<hal_1_2::HalPolicy>(operation, 2, targetHeight, model, data))
830 {
831 return Fail("%s: Operation has invalid inputs for resizing by shape", __func__);
832 }
833
834 if (targetWidth < 0 || targetHeight < 0)
835 {
836 return Fail("%s: Operation has invalid inputs for resizing by shape. "
837 "Target width/height cannot be < 0", __func__);
838 }
839
840 descriptor.m_TargetWidth = static_cast<uint32_t>(targetWidth);
Teresa Charlin9843c012019-07-19 12:18:35 +0100841 descriptor.m_TargetHeight = static_cast<uint32_t>(targetHeight);
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +0100842 }
843 else if (operandType1 == OperandType::FLOAT32)
844 {
845 // Case 2: resizing by scale
846 float widthScale = 1.0f;
847 float heightScale = 1.0f;
848
849 if (!GetInputFloat32<hal_1_2::HalPolicy>(operation, 1, widthScale, model, data) ||
850 !GetInputFloat32<hal_1_2::HalPolicy>(operation, 2, heightScale, model, data))
851 {
852 return Fail("%s: Operation has invalid inputs for resizing by scale", __func__);
853 }
854
855 const armnn::TensorShape& inputShape = inputInfo.GetShape();
856 armnnUtils::DataLayoutIndexed dataLayoutIndexed(descriptor.m_DataLayout);
857
858 float width = inputShape[dataLayoutIndexed.GetWidthIndex()];
859 float height = inputShape[dataLayoutIndexed.GetHeightIndex()];
860
861 descriptor.m_TargetWidth = std::floor(width * widthScale);
862 descriptor.m_TargetHeight = std::floor(height * heightScale);
863 }
864 else
865 {
866 // NOTE: FLOAT16 scales are not supported
867 return false;
868 }
869
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +0100870 if (IsDynamicTensor(outputInfo))
Aron Virginas-Tarbe5d3562019-07-16 11:32:29 +0100871 {
872 try
873 {
874 ALOGD("Output shape not set, will infer from inputs");
875 outputInfo.SetShape(InferResizeOutputShape(inputInfo.GetShape(), descriptor));
876 }
877 catch (armnn::Exception& e)
878 {
879 return Fail("%s: Could not infer dynamic output shape: %s", __func__, e.what());
880 }
881 }
882
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100883 bool isSupported = false;
884 FORWARD_LAYER_SUPPORT_FUNC(__func__,
885 IsResizeSupported,
886 data.m_Backends,
887 isSupported,
888 inputInfo,
889 outputInfo,
890 descriptor);
Aron Virginas-Tarbe5d3562019-07-16 11:32:29 +0100891
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100892 if (!isSupported)
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +0100893 {
894 return false;
895 }
896
897 armnn::IConnectableLayer* layer = data.m_Network->AddResizeLayer(descriptor);
898
899 assert(layer != nullptr);
900
901 layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
902 input.Connect(layer->GetInputSlot(0));
903
Aron Virginas-Tarbe5d3562019-07-16 11:32:29 +0100904 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation,
905 0,
906 *layer,
907 model,
908 data,
909 armnn::Optional<armnn::TensorInfo>(outputInfo));
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +0100910}
911
Keith Davisa6bc52f2019-06-26 09:39:49 +0100912bool HalPolicy::ConvertSpaceToDepth(const Operation& operation, const Model& model, ConversionData& data)
913{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100914 ALOGV("hal_1_2::HalPolicy::ConvertSpaceToDepth()");
Keith Davisa6bc52f2019-06-26 09:39:49 +0100915
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100916 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
Keith Davisa6bc52f2019-06-26 09:39:49 +0100917 if (!input.IsValid() )
918 {
919 return Fail("%s: Operation has invalid inputs", __func__);
920 }
921
922 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
923 unsigned int rank = inputInfo.GetNumDimensions();
924
925 if (rank != 4)
926 {
927 return Fail("%s: Only inputs with rank 4 are supported", __func__);
928 }
929
930 armnn::SpaceToDepthDescriptor desc;
931
932 GetInputScalar<hal_1_2::HalPolicy>(operation, 1, OperandType::INT32, desc.m_BlockSize, model, data);
933
934 if (desc.m_BlockSize <= 1)
935 {
936 return Fail("%s: Block size must be at least 1 in all dimensions");
937 }
938
939 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 2, model, data);
940
941 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
942 if (!output)
943 {
944 return Fail("%s: Could not read output 0", __func__);
945 }
946
947 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100948
949 bool isSupported = false;
950 FORWARD_LAYER_SUPPORT_FUNC(__func__,
951 IsSpaceToDepthSupported,
952 data.m_Backends,
953 isSupported,
954 inputInfo,
955 outputInfo,
956 desc);
957 if (!isSupported)
Keith Davisa6bc52f2019-06-26 09:39:49 +0100958 {
959 return false;
960 }
961
962 armnn::IConnectableLayer* const layer = data.m_Network->AddSpaceToDepthLayer(desc);
963 assert(layer != nullptr);
964 input.Connect(layer->GetInputSlot(0));
965
966 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
967}
968
Francis Murtagh074c25a2019-07-22 16:40:57 +0100969bool HalPolicy::ConvertSoftmax(const Operation& operation, const Model& model, ConversionData& data)
970{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100971 ALOGV("hal_1_2::HalPolicy::ConvertSoftmax()");
972
Francis Murtagh074c25a2019-07-22 16:40:57 +0100973 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
974 if (!input.IsValid())
975 {
976 return Fail("%s: Operation has invalid inputs", __func__);
977 }
978
979 const Operand* outputOperand = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
980 if (!outputOperand)
981 {
982 return Fail("%s: Operation has no outputs", __func__);
983 }
984
985 armnn::TensorInfo outputInfo = GetTensorInfoForOperand(*outputOperand);
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +0100986 if (IsDynamicTensor(outputInfo))
Francis Murtagh074c25a2019-07-22 16:40:57 +0100987 {
988 ALOGD("Output shape not set, will infer from input");
989 outputInfo.SetShape(input.GetTensorInfo().GetShape());
990 }
991
992 armnn::SoftmaxDescriptor desc;
993 if (!GetInputFloat32<hal_1_2::HalPolicy>(operation, 1, desc.m_Beta, model, data))
994 {
995 return Fail("%s: Operation has invalid inputs", __func__);
996 }
997
998 if (operation.inputs.size() > 2 && !GetInputScalar<hal_1_2::HalPolicy>(operation,
999 2,
1000 HalPolicy::OperandType::INT32,
1001 desc.m_Axis,
1002 model,
1003 data))
1004 {
1005 return Fail("%s: Operation has invalid inputs", __func__);
1006 }
1007
1008 bool isSupported = false;
1009 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1010 IsSoftmaxSupported,
1011 data.m_Backends,
1012 isSupported,
1013 input.GetTensorInfo(),
1014 outputInfo,
1015 desc);
1016 if (!isSupported)
1017 {
1018 return false;
1019 }
1020
1021 armnn::IConnectableLayer* layer = data.m_Network->AddSoftmaxLayer(desc);
1022 assert(layer != nullptr);
1023 input.Connect(layer->GetInputSlot(0));
1024
1025 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation,
1026 0,
1027 *layer,
1028 model,
1029 data,
1030 armnn::Optional<armnn::TensorInfo>(outputInfo));
1031}
1032
Mike Kellyb5fdf382019-06-11 16:35:25 +01001033} // namespace hal_1_2
Matteo Martincigh17ffff32019-06-27 14:12:55 +01001034} // namespace armnn_driver