blob: db0e2a2d629bd20e1ebab7966bab099dedeaff6f [file] [log] [blame]
arovir01b0717b52018-09-05 17:03:25 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "HalPolicy.hpp"
7
Matthew Benthamf61c2702019-04-23 16:43:27 +01008#include <armnn/Optional.hpp>
9
10#include "FullyConnected.hpp"
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +010011#include "Utils.hpp"
arovir015602b192018-10-04 16:15:02 +010012
arovir01b0717b52018-09-05 17:03:25 +010013namespace armnn_driver
14{
15namespace hal_1_0
16{
17
18bool HalPolicy::ConvertOperation(const Operation& operation, const Model& model, ConversionData& data)
19{
20 switch (operation.type)
21 {
22 case V1_0::OperationType::ADD:
23 return ConvertAdd(operation, model, data);
24 case V1_0::OperationType::AVERAGE_POOL_2D:
25 return ConvertAveragePool2d(operation, model, data);
26 case V1_0::OperationType::CONCATENATION:
27 return ConvertConcatenation(operation, model, data);
28 case V1_0::OperationType::CONV_2D:
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +010029 return ConvertConv2d(operation, model, data);
arovir01b0717b52018-09-05 17:03:25 +010030 case V1_0::OperationType::DEPTHWISE_CONV_2D:
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +010031 return ConvertDepthwiseConv2d(operation, model, data);
David Monahanacf479a2019-05-29 14:27:04 +010032 case V1_0::OperationType::DEQUANTIZE:
33 return ConvertDequantize(operation, model, data);
arovir01b0717b52018-09-05 17:03:25 +010034 case V1_0::OperationType::FLOOR:
35 return ConvertFloor(operation, model, data);
36 case V1_0::OperationType::FULLY_CONNECTED:
37 return ConvertFullyConnected(operation, model, data);
38 case V1_0::OperationType::LOCAL_RESPONSE_NORMALIZATION:
39 return ConvertLocalResponseNormalization(operation, model, data);
40 case V1_0::OperationType::LOGISTIC:
41 return ConvertLogistic(operation, model, data);
42 case V1_0::OperationType::LSTM:
43 return ConvertLstm(operation, model, data);
44 case V1_0::OperationType::L2_NORMALIZATION:
45 return ConvertL2Normalization(operation, model, data);
46 case V1_0::OperationType::L2_POOL_2D:
47 return ConvertL2Pool2d(operation, model, data);
48 case V1_0::OperationType::MAX_POOL_2D:
49 return ConvertMaxPool2d(operation, model, data);
50 case V1_0::OperationType::MUL:
51 return ConvertMul(operation, model, data);
52 case V1_0::OperationType::RELU:
53 return ConvertReLu(operation, model, data);
54 case V1_0::OperationType::RELU1:
55 return ConvertReLu1(operation, model, data);
56 case V1_0::OperationType::RELU6:
57 return ConvertReLu6(operation, model, data);
58 case V1_0::OperationType::SOFTMAX:
59 return ConvertSoftmax(operation, model, data);
Keith Davisa6bc52f2019-06-26 09:39:49 +010060 case V1_0::OperationType::SPACE_TO_DEPTH:
61 return ConvertSpaceToDepth(operation, model, data);
arovir01b0717b52018-09-05 17:03:25 +010062 case V1_0::OperationType::TANH:
63 return ConvertTanH(operation, model, data);
64 case V1_0::OperationType::RESHAPE:
65 return ConvertReshape(operation, model, data);
66 case V1_0::OperationType::RESIZE_BILINEAR:
67 return ConvertResizeBilinear(operation, model, data);
68 default:
69 return Fail("%s: Operation type %s not supported in ArmnnDriver",
70 __func__, toString(operation.type).c_str());
71 }
72}
73
Mike Kellyb5fdf382019-06-11 16:35:25 +010074bool HalPolicy::ValidateConv2dParameters(const Operation &operation)
75{
76 if (operation.inputs.size() != 10 && operation.inputs.size() != 7)
77 {
78 return Fail("%s: Unsupported number of operation inputs", __func__);
79 }
80 return true;
81}
82
83bool HalPolicy::ValidateDepthwiseConv2dParameters(const Operation &operation)
84{
85 if (operation.inputs.size() != 11 && operation.inputs.size() != 8)
86 {
87 return Fail("%s: Unsupported number of operation inputs", __func__);
88 }
89 return true;
90}
91
arovir01b0717b52018-09-05 17:03:25 +010092bool HalPolicy::ConvertAdd(const Operation& operation, const Model& model, ConversionData& data)
93{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +010094 ALOGV("hal_1_0::HalPolicy::ConvertAdd()");
95
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +010096 LayerInputHandle input0 = ConvertToLayerInputHandle<hal_1_0::HalPolicy>(operation, 0, model, data);
97 LayerInputHandle input1 = ConvertToLayerInputHandle<hal_1_0::HalPolicy>(operation, 1, model, data);
arovir01b0717b52018-09-05 17:03:25 +010098
99 if (!input0.IsValid() || !input1.IsValid())
100 {
101 return Fail("%s: Operation has invalid inputs", __func__);
102 }
103
104 // The FuseActivation parameter is always the input index 2
105 // and it should be optional
106 ActivationFn activationFunction;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100107 if (!GetOptionalInputActivation<hal_1_0::HalPolicy>(operation, 2, activationFunction, model, data))
arovir01b0717b52018-09-05 17:03:25 +0100108 {
109 return Fail("%s: Operation has invalid inputs", __func__);
110 }
111
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100112 const Operand* outputOperand = GetOutputOperand<hal_1_0::HalPolicy>(operation, 0, model);
arovir01b0717b52018-09-05 17:03:25 +0100113 if (!outputOperand)
114 {
115 return false;
116 }
117
Aron Virginas-Tar4b862132019-07-24 16:26:57 +0100118 const armnn::TensorInfo& inputInfo0 = input0.GetTensorInfo();
119 const armnn::TensorInfo& inputInfo1 = input1.GetTensorInfo();
120
121 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*outputOperand);
122 if (IsDynamicTensor(outputInfo))
123 {
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +0100124 return Fail("%s: Dynamic output tensors are not supported", __func__);
Aron Virginas-Tar4b862132019-07-24 16:26:57 +0100125 }
arovir01b0717b52018-09-05 17:03:25 +0100126
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100127 bool isSupported = false;
128 FORWARD_LAYER_SUPPORT_FUNC(__func__,
129 IsAdditionSupported,
130 data.m_Backends,
131 isSupported,
Aron Virginas-Tar4b862132019-07-24 16:26:57 +0100132 inputInfo0,
133 inputInfo1,
134 outputInfo);
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100135 if (!isSupported)
arovir01b0717b52018-09-05 17:03:25 +0100136 {
137 return false;
138 }
139
140 armnn::IConnectableLayer* const startLayer = data.m_Network->AddAdditionLayer();
Aron Virginas-Tar4b862132019-07-24 16:26:57 +0100141 armnn::IConnectableLayer* const endLayer = ProcessActivation(outputInfo, activationFunction, startLayer, data);
arovir01b0717b52018-09-05 17:03:25 +0100142
143 if (endLayer != nullptr)
144 {
145 BroadcastTensor(input0, input1, startLayer, *data.m_Network);
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100146 return SetupAndTrackLayerOutputSlot<hal_1_0::HalPolicy>(operation, 0, *endLayer, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100147 }
148 else
149 {
150 return Fail("%s: ProcessActivation failed", __func__);
151 }
152}
153
154bool HalPolicy::ConvertAveragePool2d(const Operation& operation, const Model& model, ConversionData& data)
155{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100156 ALOGV("hal_1_0::HalPolicy::ConvertAveragePool2d()");
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100157 return ConvertPooling2d<hal_1_0::HalPolicy>(operation, __func__, armnn::PoolingAlgorithm::Average, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100158}
159
160bool HalPolicy::ConvertConcatenation(const Operation& operation, const Model& model, ConversionData& data)
161{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100162 ALOGV("hal_1_0::HalPolicy::ConvertConcatenation()");
163
arovir01b0717b52018-09-05 17:03:25 +0100164 // The first N (0..N-1) inputs are tensors. The Nth input is the concatenation axis.
165 if (operation.inputs.size() <= 1)
166 {
167 return Fail("%s: Operation has insufficient arguments", __func__);
168 }
169
170 // Get inputs and outputs
171 const std::size_t numInputTensors = operation.inputs.size() - 1;
172
173 int32_t concatDim;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100174 if (!GetInputScalar<hal_1_0::HalPolicy>(operation, numInputTensors, OperandType::INT32, concatDim, model, data))
arovir01b0717b52018-09-05 17:03:25 +0100175 {
176 return Fail("%s: Operation has invalid inputs", __func__);
177 }
178
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100179 const Operand* const outputOperand = GetOutputOperand<hal_1_0::HalPolicy>(operation, 0, model);
arovir01b0717b52018-09-05 17:03:25 +0100180 if (!outputOperand)
181 {
182 return Fail("%s: Operation has no outputs", __func__);
183 }
184
185
186 armnn::TensorInfo outputInfo = GetTensorInfoForOperand(*outputOperand);
187 armnn::TensorShape outputShape = outputInfo.GetShape();
188
189 //
190 // handle negative concat dims along the lines of tensorflow as described here:
191 // https://www.tensorflow.org/api_docs/python/tf/concat
192 // "negative axis refers to axis + rank(values)-th dimension"
193 //
194 if (concatDim < 0)
195 {
196 concatDim += outputShape.GetNumDimensions();
197 }
198
199 if (concatDim >= static_cast<int32_t>(outputShape.GetNumDimensions()) || concatDim < 0)
200 {
201 return Fail("%s: Operation has invalid concat axis: %d", __func__, concatDim);
202 }
203
204 std::vector<LayerInputHandle> inputHandles;
205 std::vector<armnn::TensorShape> inputShapes;
206
207 inputHandles.reserve(numInputTensors);
208 inputShapes.reserve(numInputTensors);
209
210 bool inputsHaveBeenReshaped = false;
211 unsigned int tensorDimensionsAdded = 0;
212
213 for (uint32_t i = 0; i < numInputTensors; ++i)
214 {
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100215 const Operand* const operand = GetInputOperand<hal_1_0::HalPolicy>(operation, i, model);
arovir01b0717b52018-09-05 17:03:25 +0100216 if (!operand)
217 {
218 return Fail("%s: Operation has invalid inputs", __func__);
219 }
220
221 armnn::TensorShape operandShape = GetTensorShapeForOperand(*operand);
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100222 LayerInputHandle operandInputHandle =
223 ConvertToLayerInputHandle<hal_1_0::HalPolicy>(operation, i, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100224
225 if (operandShape.GetNumDimensions() == 0)
226 {
227 return Fail("%s: Operands with rank 0 are not supported", __func__);
228 }
229
230 if (RequiresReshape(operandShape))
231 {
232 inputsHaveBeenReshaped = true;
233
234 armnn::TensorInfo reshapeInfo = operandInputHandle.GetTensorInfo();
235
236 // Expand the tensor to three dimensions
237 if (operandShape.GetNumDimensions() == 2)
238 {
239 reshapeInfo.SetShape(armnn::TensorShape({1, operandShape[0], operandShape[1]}));
240 tensorDimensionsAdded = 1;
241 }
242 else
243 {
244 reshapeInfo.SetShape(armnn::TensorShape({1, 1, operandShape[0]}));
245 tensorDimensionsAdded = 2;
246 }
247
248 armnn::IConnectableLayer& newReshape = AddReshapeLayer(
249 *data.m_Network,
250 operandInputHandle,
251 reshapeInfo
252 );
253
254 // Point to the reshape operation rather then the input operation
255 operandShape = reshapeInfo.GetShape();
256 operandInputHandle = LayerInputHandle(true, &newReshape.GetOutputSlot(0), reshapeInfo);
257 }
258
259 inputShapes.emplace_back(operandShape);
260 inputHandles.emplace_back(operandInputHandle);
261
262 if (!inputHandles.back().IsValid())
263 {
264 return Fail("%s: Operation has invalid inputs", __func__);
265 }
266 }
267
268 BOOST_ASSERT(inputShapes.size() == inputHandles.size());
269
270 if (inputsHaveBeenReshaped)
271 {
272 // Adjust the concatenation dimension by the amount of dimensions added (if any)
273 concatDim += tensorDimensionsAdded;
274
275 // Add extra dimensions to the output shape to reflect the addition of the reshape layers
276 if (tensorDimensionsAdded == 1)
277 {
278 outputShape = armnn::TensorShape({1, outputShape[0], outputShape[1]});
279 }
280 else if (tensorDimensionsAdded == 2)
281 {
narpra01f176d5a2018-11-18 20:17:48 +0000282 outputShape = armnn::TensorShape({1, 1, outputShape[0]});
arovir01b0717b52018-09-05 17:03:25 +0100283 }
284 }
285
narpra01f176d5a2018-11-18 20:17:48 +0000286 // Check if permutations is required and get the pair of permutations required for the concatenation.
287 // Permutation is required when the concat dimension is 2 for a 4D tensor or 1 for a 3D tensor.
arovir01b0717b52018-09-05 17:03:25 +0100288 std::pair<armnn::PermutationVector, armnn::PermutationVector> permutationPair =
289 std::make_pair(IdentityPermutation4D, IdentityPermutation4D);
290
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100291 bool needPermute =
292 CreateConcatPermutationParameters(inputShapes[0].GetNumDimensions(), concatDim, permutationPair);
arovir01b0717b52018-09-05 17:03:25 +0100293
narpra01f176d5a2018-11-18 20:17:48 +0000294 if (needPermute)
295 {
296 outputShape = armnnUtils::Permuted(outputShape, permutationPair.first);
297 }
298
arovir01b0717b52018-09-05 17:03:25 +0100299 outputInfo.SetShape(outputShape);
300
301 // this is no-op for identity swizzles, otherwise it replaces both
302 // the handles and shapes with the swizzled layer output handles and shapes
303 SwizzleInputs(*data.m_Network, inputHandles, inputShapes, permutationPair.first);
304
Jim Flynn7b1e41f2019-05-22 18:00:04 +0100305 // Create an armnn concat layer descriptor - this will also perform validation on the input shapes
306 armnn::OriginsDescriptor concatDescriptor;
narpra01f176d5a2018-11-18 20:17:48 +0000307
arovir01b0717b52018-09-05 17:03:25 +0100308 try
309 {
Jim Flynn7b1e41f2019-05-22 18:00:04 +0100310 // The concat descriptor is always created across the only supported concat dimension
narpra01f176d5a2018-11-18 20:17:48 +0000311 // which is 0, 1 or 3 for a 4-D tensor, or 0 or 2 for a 3-D tensor.
Jim Flynn7b1e41f2019-05-22 18:00:04 +0100312 concatDescriptor =
Jim Flynn52aa9352019-05-20 12:52:30 +0100313 armnn::CreateDescriptorForConcatenation(inputShapes.begin(), inputShapes.end(), concatDim);
arovir01b0717b52018-09-05 17:03:25 +0100314 }
315 catch (const armnn::Exception& error)
316 {
Jim Flynn7b1e41f2019-05-22 18:00:04 +0100317 return Fail("%s: Error preparing concat descriptor. %s", __func__, error.what());
arovir01b0717b52018-09-05 17:03:25 +0100318 }
319
320 // Validate the output shape is correct given the input shapes based on the
narpra01f176d5a2018-11-18 20:17:48 +0000321 // only valid concat dimension which is 0, 1 or 3 for a 4-D tensor, or 0 or 2 for a 3-D tensor.
arovir01b0717b52018-09-05 17:03:25 +0100322 if (!ValidateConcatOutputShape(inputShapes, outputShape, concatDim))
323 {
324 return Fail("%s: Error validating the output shape for concat", __func__);
325 }
326
327 std::vector<const armnn::TensorInfo*> inputTensorInfos;
328 std::transform(inputHandles.begin(), inputHandles.end(), std::back_inserter(inputTensorInfos),
329 [](const LayerInputHandle& h) -> const armnn::TensorInfo*{ return &h.GetTensorInfo(); });
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100330
331 bool isSupported = false;
332 FORWARD_LAYER_SUPPORT_FUNC(__func__,
333 IsConcatSupported,
334 data.m_Backends,
335 isSupported,
336 inputTensorInfos,
337 outputInfo,
338 concatDescriptor);
339 if (!isSupported)
arovir01b0717b52018-09-05 17:03:25 +0100340 {
341 return false;
342 }
343
Jim Flynn7b1e41f2019-05-22 18:00:04 +0100344 armnn::IConnectableLayer* layer = data.m_Network->AddConcatLayer(concatDescriptor);
arovir01b0717b52018-09-05 17:03:25 +0100345 assert(layer != nullptr);
346 layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
347
348 // Connect inputs to the layer
349 const int numInputSlots = layer->GetNumInputSlots();
350 assert(static_cast<std::size_t>(numInputSlots) == inputHandles.size());
351 for (int i = 0; i < numInputSlots; ++i)
352 {
353 // connect the input directly to the merge (concat) layer
354 inputHandles[static_cast<unsigned int>(i)].Connect(layer->GetInputSlot(i));
355 }
356
narpra01f176d5a2018-11-18 20:17:48 +0000357 if (needPermute)
358 {
359 // Add permutation layer and connect the output to it, the permutation becomes the output layer
360 armnn::IConnectableLayer& deswizzleLayer = AddPermuteLayer(*data.m_Network,
361 layer->GetOutputSlot(0),
362 permutationPair.second);
363 layer = &deswizzleLayer;
364 }
arovir01b0717b52018-09-05 17:03:25 +0100365
366 if (inputsHaveBeenReshaped)
367 {
368 armnn::TensorInfo afterConcatInfo = layer->GetOutputSlot(0).GetTensorInfo();
369
370 // Undo the reshape knowing the amount of dimensions added
371 if (tensorDimensionsAdded == 1)
372 {
373 afterConcatInfo.SetShape(armnn::TensorShape({ afterConcatInfo.GetShape()[1],
374 afterConcatInfo.GetShape()[2] }));
375 }
376 else if (tensorDimensionsAdded == 2)
377 {
narpra01f176d5a2018-11-18 20:17:48 +0000378 afterConcatInfo.SetShape(armnn::TensorShape({ afterConcatInfo.GetShape()[2] }));
arovir01b0717b52018-09-05 17:03:25 +0100379 }
380
381 layer = &AddReshapeLayer(
382 *data.m_Network,
383 layer->GetOutputSlot(0),
384 afterConcatInfo
385 );
386 }
387
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100388 return SetupAndTrackLayerOutputSlot<hal_1_0::HalPolicy>(operation, 0, *layer, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100389}
390
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100391bool HalPolicy::ConvertConv2d(const Operation& operation, const Model& model, ConversionData& data)
392{
393 ALOGV("hal_1_0::HalPolicy::ConvertConv2d()");
394 return ValidateConv2dParameters(operation) && ::ConvertConv2d<hal_1_0::HalPolicy>(operation, model, data);
395}
396
397bool HalPolicy::ConvertDepthwiseConv2d(const Operation& operation, const Model& model, ConversionData& data)
398{
399 ALOGV("hal_1_0::HalPolicy::ConvertDepthwiseConv2d()");
400 return ValidateDepthwiseConv2dParameters(operation) &&
401 ::ConvertDepthwiseConv2d<hal_1_0::HalPolicy>(operation, model, data);
402}
403
David Monahanacf479a2019-05-29 14:27:04 +0100404bool HalPolicy::ConvertDequantize(const Operation& operation, const Model& model, ConversionData& data)
405{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100406 ALOGV("hal_1_0::HalPolicy::ConvertDequantize()");
David Monahanacf479a2019-05-29 14:27:04 +0100407
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100408 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_0::HalPolicy>(operation, 0, model, data);
David Monahanacf479a2019-05-29 14:27:04 +0100409 if (!input.IsValid())
410 {
411 return Fail("%s: Operation has invalid input", __func__);
412 }
413
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100414 const Operand* const outputOperand = GetOutputOperand<hal_1_0::HalPolicy>(operation, 0, model);
David Monahanacf479a2019-05-29 14:27:04 +0100415 if (!outputOperand)
416 {
417 return Fail("%s: Operation has invalid outputs", __func__);
418 }
419
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +0100420 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*outputOperand);
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +0100421 if (IsDynamicTensor(outputInfo))
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100422 {
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +0100423 return Fail("%s: Dynamic output tensors are not supported", __func__);
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100424 }
425
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100426 bool isSupported = false;
427 FORWARD_LAYER_SUPPORT_FUNC(__func__,
428 IsDequantizeSupported,
429 data.m_Backends,
430 isSupported,
431 input.GetTensorInfo(),
432 GetTensorInfoForOperand(*outputOperand));
433 if (!isSupported)
David Monahanacf479a2019-05-29 14:27:04 +0100434 {
435 return false;
436 }
437
438 armnn::IConnectableLayer* const layer = data.m_Network->AddDequantizeLayer();
439 assert(layer != nullptr);
440 input.Connect(layer->GetInputSlot(0));
441
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +0100442 return SetupAndTrackLayerOutputSlot<hal_1_0::HalPolicy>(operation, 0, *layer, model, data);
David Monahanacf479a2019-05-29 14:27:04 +0100443}
444
arovir01b0717b52018-09-05 17:03:25 +0100445bool HalPolicy::ConvertFloor(const Operation& operation, const Model& model, ConversionData& data)
446{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100447 ALOGV("hal_1_0::HalPolicy::ConvertFloor()");
448
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100449 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_0::HalPolicy>(operation, 0, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100450 if (!input.IsValid())
451 {
452 return Fail("%s: Operation has invalid inputs", __func__);
453 }
454
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100455 const Operand* const outputOperand = GetOutputOperand<hal_1_0::HalPolicy>(operation, 0, model);
arovir01b0717b52018-09-05 17:03:25 +0100456 if (!outputOperand)
457 {
458 return Fail("%s: Operation has invalid outputs", __func__);
459 }
460
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +0100461 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*outputOperand);
462 if (IsDynamicTensor(outputInfo))
463 {
464 return Fail("%s: Dynamic output tensors are not supported", __func__);
465 }
466
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100467 bool isSupported = false;
468 FORWARD_LAYER_SUPPORT_FUNC(__func__,
469 IsFloorSupported,
470 data.m_Backends,
471 isSupported,
472 input.GetTensorInfo(),
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +0100473 outputInfo);
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100474 if (!isSupported)
arovir01b0717b52018-09-05 17:03:25 +0100475 {
476 return false;
477 }
478
479 armnn::IConnectableLayer* layer = data.m_Network->AddFloorLayer();
480 assert(layer != nullptr);
481 input.Connect(layer->GetInputSlot(0));
482
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100483 return SetupAndTrackLayerOutputSlot<hal_1_0::HalPolicy>(operation, 0, *layer, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100484}
485
486bool HalPolicy::ConvertFullyConnected(const Operation& operation, const Model& model, ConversionData& data)
487{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100488 ALOGV("hal_1_0::HalPolicy::ConvertFullyConnected()");
489
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100490 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_0::HalPolicy>(operation, 0, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100491 if (!input.IsValid())
492 {
493 return Fail("%s: Operation has invalid inputs", __func__);
494 }
495
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100496 const Operand* output = GetOutputOperand<hal_1_0::HalPolicy>(operation, 0, model);
arovir01b0717b52018-09-05 17:03:25 +0100497 if (!output)
498 {
499 return Fail("%s: Could not read output 0", __func__);
500 }
501
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +0100502 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
503 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
FinnWilliamsArm92ec7252019-07-16 12:15:18 +0100504
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +0100505 if (IsDynamicTensor(outputInfo))
FinnWilliamsArm92ec7252019-07-16 12:15:18 +0100506 {
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +0100507 return Fail("%s: Dynamic output tensors are not supported", __func__);
FinnWilliamsArm92ec7252019-07-16 12:15:18 +0100508 }
arovir01b0717b52018-09-05 17:03:25 +0100509
510 // ArmNN does not currently support non-fixed weights or bias
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100511 ConstTensorPin weightsPin =
512 ConvertOperationInputToConstTensorPin<hal_1_0::HalPolicy>(operation, 1, model, data); // 2D
513 ConstTensorPin biasPin =
514 ConvertOperationInputToConstTensorPin<hal_1_0::HalPolicy>(operation, 2, model, data); // 1D
arovir01b0717b52018-09-05 17:03:25 +0100515
516 if (!weightsPin.IsValid() || !biasPin.IsValid())
517 {
518 return Fail("%s: Operation has invalid inputs", __func__);
519 }
520
521 armnn::ConstTensor weights = weightsPin.GetConstTensor();
522 armnn::ConstTensor bias = biasPin.GetConstTensor();
arovir01b0717b52018-09-05 17:03:25 +0100523 armnn::TensorInfo reshapedInfo = inputInfo;
Matthew Benthamf61c2702019-04-23 16:43:27 +0100524
525 try
arovir01b0717b52018-09-05 17:03:25 +0100526 {
Matthew Benthamf61c2702019-04-23 16:43:27 +0100527 reshapedInfo.SetShape(FlattenFullyConnectedInput(inputInfo.GetShape(), weights.GetInfo().GetShape()));
528 } catch (const std::exception &e) {
529 return Fail("%s: %s", __func__, e.what());
arovir01b0717b52018-09-05 17:03:25 +0100530 }
531
532 // ensuring that the bias value is within 1% of the weights input (small float differences can exist)
533 SanitizeBiasQuantizationScale(bias.GetInfo(), weights.GetInfo(), reshapedInfo);
534
535 ActivationFn activationFunction;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100536 if (!GetInputActivationFunction<hal_1_0::HalPolicy>(operation, 3, activationFunction, model, data))
arovir01b0717b52018-09-05 17:03:25 +0100537 {
538 return Fail("%s: Operation has invalid inputs", __func__);
539 }
540
541 armnn::FullyConnectedDescriptor desc;
542 desc.m_TransposeWeightMatrix = true;
543 desc.m_BiasEnabled = true;
544
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100545 bool isSupported = false;
546 FORWARD_LAYER_SUPPORT_FUNC(__func__,
547 IsFullyConnectedSupported,
548 data.m_Backends,
549 isSupported,
550 reshapedInfo,
551 outputInfo,
552 weights.GetInfo(),
553 bias.GetInfo(),
554 desc);
555 if (!isSupported)
arovir01b0717b52018-09-05 17:03:25 +0100556 {
557 return false;
558 }
559
Matteo Martincighba01f372019-05-14 13:28:21 +0100560 armnn::IConnectableLayer* startLayer =
561 data.m_Network->AddFullyConnectedLayer(desc, weights, armnn::Optional<armnn::ConstTensor>(bias));
arovir01b0717b52018-09-05 17:03:25 +0100562 armnn::IConnectableLayer* endLayer = ProcessActivation(outputInfo, activationFunction, startLayer, data);
563
564 if (endLayer != nullptr)
565 {
566 if (inputInfo.GetNumDimensions() > 2U)
567 {
568 armnn::ReshapeDescriptor reshapeDescriptor;
569 reshapeDescriptor.m_TargetShape = reshapedInfo.GetShape();
570
571 armnn::IConnectableLayer* reshapeLayer = data.m_Network->AddReshapeLayer(reshapeDescriptor);
572 assert(reshapeLayer != nullptr);
573 input.Connect(reshapeLayer->GetInputSlot(0));
574 reshapeLayer->GetOutputSlot(0).SetTensorInfo(reshapedInfo);
575 reshapeLayer->GetOutputSlot(0).Connect(startLayer->GetInputSlot(0));
576 }
577 else
578 {
579 input.Connect(startLayer->GetInputSlot(0));
580 }
581
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +0100582 return SetupAndTrackLayerOutputSlot<hal_1_0::HalPolicy>(operation, 0, *endLayer, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100583 }
584 else
585 {
586 return Fail("%s: ProcessActivation failed", __func__);
587 }
588}
589
590bool HalPolicy::ConvertLocalResponseNormalization(const Operation& operation,
591 const Model& model,
592 ConversionData& data)
593{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100594 ALOGV("hal_1_0::HalPolicy::ConvertLocalResponseNormalization()");
595
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100596 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_0::HalPolicy>(operation, 0, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100597 if (!input.IsValid())
598 {
599 return Fail("%s: Operation has invalid inputs", __func__);
600 }
601
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100602 const Operand* output = GetOutputOperand<hal_1_0::HalPolicy>(operation, 0, model);
arovir01b0717b52018-09-05 17:03:25 +0100603 if (!output)
604 {
605 return Fail("%s: Could not read output 0", __func__);
606 }
607
narpra012fb804a2018-10-22 14:52:32 +0100608 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
arovir01b0717b52018-09-05 17:03:25 +0100609 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
610
arovir01b0717b52018-09-05 17:03:25 +0100611 armnn::NormalizationDescriptor descriptor;
612
narpra012fb804a2018-10-22 14:52:32 +0100613 descriptor.m_DataLayout = armnn::DataLayout::NHWC;
arovir01b0717b52018-09-05 17:03:25 +0100614 descriptor.m_NormChannelType = armnn::NormalizationAlgorithmChannel::Across;
narpra012fb804a2018-10-22 14:52:32 +0100615 descriptor.m_NormMethodType = armnn::NormalizationAlgorithmMethod::LocalBrightness;
arovir01b0717b52018-09-05 17:03:25 +0100616
617 if (!input.IsValid() ||
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100618 !GetInputScalar<hal_1_0::HalPolicy>(operation, 1, OperandType::INT32, descriptor.m_NormSize, model, data) ||
619 !GetInputFloat32<hal_1_0::HalPolicy>(operation, 2, descriptor.m_K, model, data) ||
620 !GetInputFloat32<hal_1_0::HalPolicy>(operation, 3, descriptor.m_Alpha, model, data) ||
621 !GetInputFloat32<hal_1_0::HalPolicy>(operation, 4, descriptor.m_Beta, model, data))
arovir01b0717b52018-09-05 17:03:25 +0100622 {
623 return Fail("%s: Operation has invalid inputs", __func__);
624 }
625
626 // ArmNN expects normSize to be the full size of the normalization
627 // window rather than the radius as in AndroidNN.
628 descriptor.m_NormSize = 1 + (2 * descriptor.m_NormSize);
629
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100630 bool isSupported = false;
631 FORWARD_LAYER_SUPPORT_FUNC(__func__,
632 IsNormalizationSupported,
633 data.m_Backends,
634 isSupported,
635 inputInfo,
636 outputInfo,
637 descriptor);
638 if (!isSupported)
arovir01b0717b52018-09-05 17:03:25 +0100639 {
640 return false;
641 }
642
643
644 armnn::IConnectableLayer* layer = data.m_Network->AddNormalizationLayer(descriptor);
645 assert(layer != nullptr);
narpra012fb804a2018-10-22 14:52:32 +0100646 input.Connect(layer->GetInputSlot(0));
arovir01b0717b52018-09-05 17:03:25 +0100647
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100648 return SetupAndTrackLayerOutputSlot<hal_1_0::HalPolicy>(operation, 0, *layer, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100649}
650
651bool HalPolicy::ConvertLogistic(const Operation& operation, const Model& model, ConversionData& data)
652{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100653 ALOGV("hal_1_0::HalPolicy::ConvertLogistic()");
654
arovir01b0717b52018-09-05 17:03:25 +0100655 armnn::ActivationDescriptor desc;
656 desc.m_Function = armnn::ActivationFunction::Sigmoid;
657
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100658 return ConvertToActivation<hal_1_0::HalPolicy>(operation, __func__, desc, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100659}
660
661bool HalPolicy::ConvertLstm(const Operation& operation, const Model& model, ConversionData& data)
662{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100663 ALOGV("hal_1_0::HalPolicy::ConvertLstm()");
664
arovir01b0717b52018-09-05 17:03:25 +0100665 // Inputs:
666 // 00: The input: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, input_size], where
667 // “batch_size” corresponds to the batching dimension, and “input_size” is the size of the input.
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100668 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_0::HalPolicy>(operation, 0, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100669 if (!input.IsValid())
670 {
671 return Fail("%s: Could not read input 0: input", __func__);
672 }
673 // 18: The output state: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, output_size].
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100674 LayerInputHandle outputStateIn = ConvertToLayerInputHandle<hal_1_0::HalPolicy>(operation, 18, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100675 if (!outputStateIn.IsValid())
676 {
677 return Fail("%s: Could not read input 18: outputStateIn", __func__);
678 }
679 // 19: The cell state: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, num_units].
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100680 LayerInputHandle cellStateIn = ConvertToLayerInputHandle<hal_1_0::HalPolicy>(operation, 19, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100681 if (!cellStateIn.IsValid())
682 {
683 return Fail("%s: Could not read input 19: cellStateIn", __func__);
684 }
685
686 // Get the mandatory input tensors:
687 // 02: The input-to-forget weights: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
688 // [num_units, input_size].
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100689 const ConstTensorPin inputToForgetWeightsPin =
690 ConvertOperationInputToConstTensorPin<hal_1_0::HalPolicy>(operation, 2, model, data);
691 // 03: The input-to-cell weights: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
692 // [num_units, input_size].
693 const ConstTensorPin inputToCellWeightsPin =
694 ConvertOperationInputToConstTensorPin<hal_1_0::HalPolicy>(operation, 3, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100695 // 04: The input-to-output weights: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
696 // [num_units, input_size].
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100697 const ConstTensorPin inputToOutputWeightsPin =
698 ConvertOperationInputToConstTensorPin<hal_1_0::HalPolicy>(operation, 4, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100699 // 06: The recurrent-to-forget weights: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
700 // [num_units, output_size].
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100701 const ConstTensorPin recurrentToForgetWeightsPin =
702 ConvertOperationInputToConstTensorPin<hal_1_0::HalPolicy>(operation, 6, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100703 // 07: The recurrent-to-cell weights: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
704 // [num_units, output_size].
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100705 const ConstTensorPin recurrentToCellWeightsPin =
706 ConvertOperationInputToConstTensorPin<hal_1_0::HalPolicy>(operation, 7, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100707 // 08: The recurrent-to-output weights: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
708 // [num_units, output_size].
709 const ConstTensorPin recurrentToOutputWeightsPin =
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100710 ConvertOperationInputToConstTensorPin<hal_1_0::HalPolicy>(operation, 8, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100711 // 13: The forget gate bias: A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100712 const ConstTensorPin forgetGateBiasPin =
713 ConvertOperationInputToConstTensorPin<hal_1_0::HalPolicy>(operation, 13, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100714 // 14: The cell bias: A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100715 const ConstTensorPin cellBiasPin =
716 ConvertOperationInputToConstTensorPin<hal_1_0::HalPolicy>(operation, 14, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100717 // 15: The output gate bias: A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100718 const ConstTensorPin outputGateBiasPin =
719 ConvertOperationInputToConstTensorPin<hal_1_0::HalPolicy>(operation, 15, model, data);
arovir01b0717b52018-09-05 17:03:25 +0100720
721 if (!inputToForgetWeightsPin.IsValid() ||
722 !inputToCellWeightsPin.IsValid() ||
723 !inputToOutputWeightsPin.IsValid() ||
724 !recurrentToForgetWeightsPin.IsValid() ||
725 !recurrentToCellWeightsPin.IsValid() ||
726 !recurrentToOutputWeightsPin.IsValid() ||
727 !forgetGateBiasPin.IsValid() ||
728 !cellBiasPin.IsValid() ||
729 !outputGateBiasPin.IsValid())
730 {
731 return Fail("%s: Operation has invalid tensor inputs", __func__);
732 }
733
734 // Get the optional input tensors:
735 // 01: The input-to-input weights: Optional. A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
736 // [num_units, input_size], where “num_units” corresponds to the number of cell units.
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100737 const ConstTensorPin inputToInputWeightsPin =
738 ConvertOperationInputToConstTensorPin<hal_1_0::HalPolicy>(operation,
739 1,
740 model,
741 data,
742 g_DontPermute,
743 nullptr,
744 true);
745
arovir01b0717b52018-09-05 17:03:25 +0100746 // 05: The recurrent-to-input weights: Optional. A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
747 // [num_units, output_size], where “output_size” corresponds to either the number of cell units (i.e.,
748 // “num_units”), or the second dimension of the “projection_weights”, if defined.
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100749 const ConstTensorPin recurrentToInputWeightsPin =
750 ConvertOperationInputToConstTensorPin<hal_1_0::HalPolicy>(operation,
751 5,
752 model,
753 data,
754 g_DontPermute,
755 nullptr,
756 true);
757
arovir01b0717b52018-09-05 17:03:25 +0100758 // 09: The cell-to-input weights: Optional. A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100759 const ConstTensorPin cellToInputWeightsPin =
760 ConvertOperationInputToConstTensorPin<hal_1_0::HalPolicy>(operation,
761 9,
762 model,
763 data,
764 g_DontPermute,
765 nullptr,
766 true);
767
arovir01b0717b52018-09-05 17:03:25 +0100768 // 10: The cell-to-forget weights: Optional. A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100769 const ConstTensorPin cellToForgetWeightsPin =
770 ConvertOperationInputToConstTensorPin<hal_1_0::HalPolicy>(operation,
771 10,
772 model,
773 data,
774 g_DontPermute,
775 nullptr,
776 true);
777
arovir01b0717b52018-09-05 17:03:25 +0100778 // 11: The cell-to-output weights: Optional. A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100779 const ConstTensorPin cellToOutputWeightsPin =
780 ConvertOperationInputToConstTensorPin<hal_1_0::HalPolicy>(operation,
781 11,
782 model,
783 data,
784 g_DontPermute,
785 nullptr,
786 true);
787
arovir01b0717b52018-09-05 17:03:25 +0100788 // 12: The input gate bias: Optional. A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100789 const ConstTensorPin inputGateBiasPin =
790 ConvertOperationInputToConstTensorPin<hal_1_0::HalPolicy>(operation,
791 12,
792 model,
793 data,
794 g_DontPermute,
795 nullptr,
796 true);
797
arovir01b0717b52018-09-05 17:03:25 +0100798 // 16: The projection weights: Optional. A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
799 // [output_size, num_units].
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100800 const ConstTensorPin projectionWeightsPin =
801 ConvertOperationInputToConstTensorPin<hal_1_0::HalPolicy>(operation,
802 16,
803 model,
804 data,
805 g_DontPermute,
806 nullptr,
807 true);
808
arovir01b0717b52018-09-05 17:03:25 +0100809 // 17: The projection bias: Optional. A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [output_size].
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100810 const ConstTensorPin projectionBiasPin =
811 ConvertOperationInputToConstTensorPin<hal_1_0::HalPolicy>(operation,
812 17,
813 model,
814 data,
815 g_DontPermute,
816 nullptr,
817 true);
arovir01b0717b52018-09-05 17:03:25 +0100818
819 if ((!inputToInputWeightsPin.IsValid() && !inputToInputWeightsPin.IsOptional()) ||
820 (!recurrentToInputWeightsPin.IsValid() && !recurrentToInputWeightsPin.IsOptional()) ||
821 (!cellToInputWeightsPin.IsValid() && !cellToInputWeightsPin.IsOptional()) ||
822 (!cellToForgetWeightsPin.IsValid() && !cellToForgetWeightsPin.IsOptional()) ||
823 (!cellToOutputWeightsPin.IsValid() && !cellToOutputWeightsPin.IsOptional()) ||
824 (!inputGateBiasPin.IsValid() && !inputGateBiasPin.IsOptional()) ||
825 (!projectionWeightsPin.IsValid() && !projectionWeightsPin.IsOptional()) ||
826 (!projectionBiasPin.IsValid() && !projectionBiasPin.IsOptional()))
827 {
828 return Fail("%s: Operation has invalid tensor inputs", __func__);
829 }
830
831 // Get the mandatory input scalars (actually 1-D tensors of size 1):
832 // 20: The activation function: A value indicating the activation function:
833 // 0: None; 1: Relu; 3: Relu6; 4: Tanh; 6: Sigmoid.
834 // 21: The clipping threshold: for the cell state, such that values are bound within [-cell_clip, cell_clip].
835 // If set to 0.0 then clipping is disabled.
836 // 22: The clipping threshold: for the output from the projection layer, such that values are bound within
837 // [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled.
838 ActivationFn activation;
839 float cellClip;
840 float projClip;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100841 if (!GetInputActivationFunctionFromTensor<hal_1_0::HalPolicy>(operation, 20, activation, model, data) ||
842 !GetInputScalar<hal_1_0::HalPolicy>(operation, 21, OperandType::FLOAT32, cellClip, model, data) ||
843 !GetInputScalar<hal_1_0::HalPolicy>(operation, 22, OperandType::FLOAT32, projClip, model, data))
arovir01b0717b52018-09-05 17:03:25 +0100844 {
845 return Fail("%s: Operation has invalid scalar inputs", __func__);
846 }
847
848 // Outputs:
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100849 // 00: The scratch buffer: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, num_units * 4]
850 // with CIFG, or [batch_size, num_units * 3] without CIFG.
851 const Operand* scratchBuffer = GetOutputOperand<hal_1_0::HalPolicy>(operation, 0, model);
arovir01b0717b52018-09-05 17:03:25 +0100852 if (!scratchBuffer)
853 {
854 return Fail("%s: Could not read output 0: scratchBuffer", __func__);
855 }
856 // 01: The output state (out): A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, output_size].
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100857 const Operand* outputStateOut = GetOutputOperand<hal_1_0::HalPolicy>(operation, 1, model);
arovir01b0717b52018-09-05 17:03:25 +0100858 if (!outputStateOut)
859 {
860 return Fail("%s: Could not read output 1: outputStateOut", __func__);
861 }
862 // 02: The cell state (out): A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, num_units].
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100863 const Operand* cellStateOut = GetOutputOperand<hal_1_0::HalPolicy>(operation, 2, model);
arovir01b0717b52018-09-05 17:03:25 +0100864 if (!cellStateOut)
865 {
866 return Fail("%s: Could not read output 2: cellStateOut", __func__);
867 }
868 // 03: The output: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, output_size]. This is
869 // effectively the same as the current “output state (out)” value.
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +0100870 const Operand* output = GetOutputOperand<hal_1_0::HalPolicy>(operation, 3, model);
arovir01b0717b52018-09-05 17:03:25 +0100871 if (!output)
872 {
873 return Fail("%s: Could not read output 3: output", __func__);
874 }
875
876 // set the params structure for the AddLstmLayer call
877 armnn::LstmInputParams params;
878 params.m_InputToInputWeights = inputToInputWeightsPin.GetConstTensorPtr();
879 params.m_InputToForgetWeights = inputToForgetWeightsPin.GetConstTensorPtr();
880 params.m_InputToCellWeights = inputToCellWeightsPin.GetConstTensorPtr();
881 params.m_InputToOutputWeights = inputToOutputWeightsPin.GetConstTensorPtr();
882 params.m_RecurrentToInputWeights = recurrentToInputWeightsPin.GetConstTensorPtr();
883 params.m_RecurrentToForgetWeights = recurrentToForgetWeightsPin.GetConstTensorPtr();
884 params.m_RecurrentToCellWeights = recurrentToCellWeightsPin.GetConstTensorPtr();
885 params.m_RecurrentToOutputWeights = recurrentToOutputWeightsPin.GetConstTensorPtr();
886 params.m_CellToInputWeights = cellToInputWeightsPin.GetConstTensorPtr();
887 params.m_CellToForgetWeights = cellToForgetWeightsPin.GetConstTensorPtr();
888 params.m_CellToOutputWeights = cellToOutputWeightsPin.GetConstTensorPtr();
889 params.m_InputGateBias = inputGateBiasPin.GetConstTensorPtr();
890 params.m_ForgetGateBias = forgetGateBiasPin.GetConstTensorPtr();
891 params.m_CellBias = cellBiasPin.GetConstTensorPtr();
892 params.m_OutputGateBias = outputGateBiasPin.GetConstTensorPtr();
893 params.m_ProjectionWeights = projectionWeightsPin.GetConstTensorPtr();
894 params.m_ProjectionBias = projectionBiasPin.GetConstTensorPtr();
895
896 // set the layer descriptor
897 armnn::LstmDescriptor desc;
898 desc.m_ActivationFunc = activation;
899 desc.m_ClippingThresCell = cellClip;
900 desc.m_ClippingThresProj = projClip;
901 desc.m_CifgEnabled = (params.m_InputToInputWeights == nullptr ||
902 params.m_RecurrentToInputWeights == nullptr ||
903 params.m_InputGateBias == nullptr);
904 desc.m_PeepholeEnabled = (params.m_CellToForgetWeights != nullptr ||
905 params.m_CellToOutputWeights != nullptr);
906 desc.m_ProjectionEnabled = (params.m_ProjectionWeights != nullptr);
907
908 // validate the optional input groups
909 if (desc.m_CifgEnabled &&
910 (params.m_InputToInputWeights != nullptr ||
911 params.m_RecurrentToInputWeights != nullptr ||
912 params.m_InputGateBias != nullptr))
913 {
914 return Fail("%s: All, or none, of input-to-input weights, recurrent-to-input weights,"
915 " and input gate bias must be provided", __func__);
916 }
917
918 if (!desc.m_ProjectionEnabled && params.m_ProjectionBias != nullptr)
919 {
920 return Fail("%s: projection bias should not be provided without projection weights", __func__);
921 }
922
923 if (desc.m_PeepholeEnabled &&
924 (params.m_CellToForgetWeights == nullptr ||
925 params.m_CellToOutputWeights == nullptr ||
926 (!desc.m_CifgEnabled && params.m_CellToInputWeights == nullptr)))
927 {
928 return Fail("%s: All, or none, of cell-to-forget weights and cell-to-output weights must be provided"
929 " and, if CIFG is not enabled, cell-to-input weights must also be provided", __func__);
930 }
931
932 // Check if the layer is supported
933 // Inputs
934 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
935 const armnn::TensorInfo& outputStateInInfo = outputStateIn.GetTensorInfo();
936 const armnn::TensorInfo& cellStateInInfo = cellStateIn.GetTensorInfo();
937
938 // Outputs
939 const armnn::TensorInfo& scratchBufferInfo = GetTensorInfoForOperand(*scratchBuffer);
940 const armnn::TensorInfo& outputStateOutInfo = GetTensorInfoForOperand(*outputStateOut);
941 const armnn::TensorInfo& cellStateOutInfo = GetTensorInfoForOperand(*cellStateOut);
942 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
943
944 // Basic parameters
Ferran Balaguer177fa0b2019-07-02 17:34:46 +0100945 armnn::LstmInputParamsInfo paramsInfo;
946 paramsInfo.m_InputToForgetWeights = &(params.m_InputToForgetWeights->GetInfo());
947 paramsInfo.m_InputToCellWeights = &(params.m_InputToCellWeights->GetInfo());
948 paramsInfo.m_InputToOutputWeights = &(params.m_InputToOutputWeights->GetInfo());
949 paramsInfo.m_RecurrentToForgetWeights = &(params.m_RecurrentToForgetWeights->GetInfo());
950 paramsInfo.m_RecurrentToCellWeights = &(params.m_RecurrentToCellWeights->GetInfo());
951 paramsInfo.m_RecurrentToOutputWeights = &(params.m_RecurrentToOutputWeights->GetInfo());
952 paramsInfo.m_ForgetGateBias = &(params.m_ForgetGateBias->GetInfo());
953 paramsInfo.m_CellBias = &(params.m_CellBias->GetInfo());
954 paramsInfo.m_OutputGateBias = &(params.m_OutputGateBias->GetInfo());
arovir01b0717b52018-09-05 17:03:25 +0100955
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100956 // Optional parameters
arovir01b0717b52018-09-05 17:03:25 +0100957 if(!desc.m_CifgEnabled)
958 {
Ferran Balaguer177fa0b2019-07-02 17:34:46 +0100959 paramsInfo.m_InputToInputWeights = &(params.m_InputToInputWeights->GetInfo());
960 paramsInfo.m_RecurrentToInputWeights = &(params.m_RecurrentToInputWeights->GetInfo());
arovir01b0717b52018-09-05 17:03:25 +0100961 if (params.m_CellToInputWeights != nullptr)
962 {
Ferran Balaguer177fa0b2019-07-02 17:34:46 +0100963 paramsInfo.m_CellToInputWeights = &(params.m_CellToInputWeights->GetInfo());
arovir01b0717b52018-09-05 17:03:25 +0100964 }
Ferran Balaguer177fa0b2019-07-02 17:34:46 +0100965 paramsInfo.m_InputGateBias = &(params.m_InputGateBias->GetInfo());
arovir01b0717b52018-09-05 17:03:25 +0100966 }
967
968 if(desc.m_ProjectionEnabled)
969 {
Ferran Balaguer177fa0b2019-07-02 17:34:46 +0100970 paramsInfo.m_ProjectionWeights = &(params.m_ProjectionWeights->GetInfo());
arovir01b0717b52018-09-05 17:03:25 +0100971 if (params.m_ProjectionBias != nullptr)
972 {
Ferran Balaguer177fa0b2019-07-02 17:34:46 +0100973 paramsInfo.m_ProjectionBias = &(params.m_ProjectionBias->GetInfo());
arovir01b0717b52018-09-05 17:03:25 +0100974 }
975 }
976
977 if(desc.m_PeepholeEnabled)
978 {
Ferran Balaguer177fa0b2019-07-02 17:34:46 +0100979 paramsInfo.m_CellToForgetWeights = &(params.m_CellToForgetWeights->GetInfo());
980 paramsInfo.m_CellToOutputWeights = &(params.m_CellToOutputWeights->GetInfo());
arovir01b0717b52018-09-05 17:03:25 +0100981 }
982
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100983 bool isSupported = false;
984 FORWARD_LAYER_SUPPORT_FUNC(__func__,
985 IsLstmSupported,
986 data.m_Backends,
987 isSupported,
988 inputInfo,
989 outputStateInInfo,
990 cellStateInInfo,
991 scratchBufferInfo,
992 outputStateOutInfo,
993 cellStateOutInfo,
994 outputInfo,
995 desc,
996 paramsInfo);
997 if (!isSupported)
arovir01b0717b52018-09-05 17:03:25 +0100998 {
999 return false;
1000 }
1001
1002 // Add the layer
1003 armnn::IConnectableLayer* layer = data.m_Network->AddLstmLayer(desc, params, "Lstm");
1004
1005 input.Connect(layer->GetInputSlot(0));
1006 outputStateIn.Connect(layer->GetInputSlot(1));
1007 cellStateIn.Connect(layer->GetInputSlot(2));
1008
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +01001009 return (SetupAndTrackLayerOutputSlot<hal_1_0::HalPolicy>(operation, 0, *layer, 0, model, data) &&
1010 SetupAndTrackLayerOutputSlot<hal_1_0::HalPolicy>(operation, 1, *layer, 1, model, data) &&
1011 SetupAndTrackLayerOutputSlot<hal_1_0::HalPolicy>(operation, 2, *layer, 2, model, data) &&
1012 SetupAndTrackLayerOutputSlot<hal_1_0::HalPolicy>(operation, 3, *layer, 3, model, data));
arovir01b0717b52018-09-05 17:03:25 +01001013}
1014
1015bool HalPolicy::ConvertL2Normalization(const Operation& operation, const Model& model, ConversionData& data)
1016{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001017 ALOGV("hal_1_0::HalPolicy::ConvertL2Normalization()");
1018
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +01001019 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_0::HalPolicy>(operation, 0, model, data);
arovir01b0717b52018-09-05 17:03:25 +01001020 if (!input.IsValid())
1021 {
1022 return Fail("%s: Operation has invalid inputs", __func__);
1023 }
1024
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +01001025 const Operand* output = GetOutputOperand<hal_1_0::HalPolicy>(operation, 0, model);
arovir01b0717b52018-09-05 17:03:25 +01001026 if (!output)
1027 {
1028 return Fail("%s: Could not read output 0", __func__);
1029 }
1030
1031 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001032 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
arovir01b0717b52018-09-05 17:03:25 +01001033
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +01001034 if (IsDynamicTensor(outputInfo))
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +01001035 {
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001036 return Fail("%s: Dynamic output tensors are not supported", __func__);
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +01001037 }
1038
Matteo Martincigh58f71092018-09-25 15:58:52 +01001039 armnn::L2NormalizationDescriptor desc;
Matteo Martincigh5e0ed9f2018-10-01 09:26:32 +01001040 desc.m_DataLayout = armnn::DataLayout::NHWC;
Matteo Martincigh58f71092018-09-25 15:58:52 +01001041
Ferran Balaguerd30093c2019-07-09 17:04:47 +01001042 bool isSupported = false;
1043 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1044 IsL2NormalizationSupported,
1045 data.m_Backends,
1046 isSupported,
1047 inputInfo,
1048 outputInfo,
1049 desc);
1050 if (!isSupported)
arovir01b0717b52018-09-05 17:03:25 +01001051 {
1052 return false;
1053 }
1054
Matteo Martincigh58f71092018-09-25 15:58:52 +01001055 armnn::IConnectableLayer* layer = data.m_Network->AddL2NormalizationLayer(desc);
arovir01b0717b52018-09-05 17:03:25 +01001056 assert(layer != nullptr);
Matteo Martincigh5e0ed9f2018-10-01 09:26:32 +01001057 input.Connect(layer->GetInputSlot(0));
arovir01b0717b52018-09-05 17:03:25 +01001058
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001059 return SetupAndTrackLayerOutputSlot<hal_1_0::HalPolicy>(operation, 0, *layer, model, data);
arovir01b0717b52018-09-05 17:03:25 +01001060}
1061
1062bool HalPolicy::ConvertL2Pool2d(const Operation& operation, const Model& model, ConversionData& data)
1063{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001064 ALOGV("hal_1_0::HalPolicy::ConvertL2Pool2d()");
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +01001065 return ConvertPooling2d<hal_1_0::HalPolicy>(operation, __func__, armnn::PoolingAlgorithm::L2, model, data);
arovir01b0717b52018-09-05 17:03:25 +01001066}
1067
1068bool HalPolicy::ConvertMaxPool2d(const Operation& operation, const Model& model, ConversionData& data)
1069{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001070 ALOGV("hal_1_0::HalPolicy::ConvertMaxPool2d()");
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +01001071 return ConvertPooling2d<hal_1_0::HalPolicy>(operation, __func__, armnn::PoolingAlgorithm::Max, model, data);
arovir01b0717b52018-09-05 17:03:25 +01001072}
1073
1074bool HalPolicy::ConvertMul(const Operation& operation, const Model& model, ConversionData& data)
1075{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001076 ALOGV("hal_1_0::HalPolicy::ConvertMul()");
1077
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +01001078 LayerInputHandle input0 = ConvertToLayerInputHandle<hal_1_0::HalPolicy>(operation, 0, model, data);
1079 LayerInputHandle input1 = ConvertToLayerInputHandle<hal_1_0::HalPolicy>(operation, 1, model, data);
arovir01b0717b52018-09-05 17:03:25 +01001080
1081 if (!input0.IsValid() || !input1.IsValid())
1082 {
1083 return Fail("%s: Operation has invalid inputs", __func__);
1084 }
1085
1086 // The FuseActivation parameter is always the input index 2
1087 // and it should be optional
1088 ActivationFn activationFunction;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +01001089 if (!GetOptionalInputActivation<hal_1_0::HalPolicy>(operation, 2, activationFunction, model, data))
arovir01b0717b52018-09-05 17:03:25 +01001090 {
1091 return Fail("%s: Operation has invalid inputs", __func__);
1092 }
1093
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +01001094 const Operand* outputOperand = GetOutputOperand<hal_1_0::HalPolicy>(operation, 0, model);
arovir01b0717b52018-09-05 17:03:25 +01001095
1096 if (outputOperand == nullptr)
1097 {
1098 return false;
1099 }
1100
1101 const armnn::TensorInfo& outInfo = GetTensorInfoForOperand(*outputOperand);
1102
Ferran Balaguerd30093c2019-07-09 17:04:47 +01001103 bool isSupported = false;
1104 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1105 IsMultiplicationSupported,
1106 data.m_Backends,
1107 isSupported,
1108 input0.GetTensorInfo(),
1109 input1.GetTensorInfo(),
1110 outInfo);
1111 if (!isSupported)
arovir01b0717b52018-09-05 17:03:25 +01001112 {
1113 return false;
1114 }
1115
1116 armnn::IConnectableLayer* const startLayer = data.m_Network->AddMultiplicationLayer();
1117 armnn::IConnectableLayer* const endLayer = ProcessActivation(outInfo, activationFunction, startLayer, data);
1118
1119 const armnn::TensorInfo& inputTensorInfo0 = input0.GetTensorInfo();
1120 const armnn::TensorInfo& inputTensorInfo1 = input1.GetTensorInfo();
1121
1122 if (endLayer != nullptr)
1123 {
1124 BroadcastTensor(input0, input1, startLayer, *data.m_Network);
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +01001125 return SetupAndTrackLayerOutputSlot<hal_1_0::HalPolicy>(operation, 0, *endLayer, model, data);
arovir01b0717b52018-09-05 17:03:25 +01001126 }
1127 else
1128 {
1129 return Fail("%s: ProcessActivation failed", __func__);
1130 }
1131}
1132
1133bool HalPolicy::ConvertReLu(const Operation& operation, const Model& model, ConversionData& data)
1134{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001135 ALOGV("hal_1_0::HalPolicy::ConvertReLu()");
Sadik Armagan61113162019-07-25 09:09:40 +01001136 return ::ConvertReLu<hal_1_0::HalPolicy>(operation, model, data);
arovir01b0717b52018-09-05 17:03:25 +01001137}
1138
1139bool HalPolicy::ConvertReLu1(const Operation& operation, const Model& model, ConversionData& data)
1140{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001141 ALOGV("hal_1_0::HalPolicy::ConvertReLu1()");
Sadik Armagan61113162019-07-25 09:09:40 +01001142 return ::ConvertReLu1<hal_1_0::HalPolicy>(operation, model, data);
arovir01b0717b52018-09-05 17:03:25 +01001143}
1144
1145bool HalPolicy::ConvertReLu6(const Operation& operation, const Model& model, ConversionData& data)
1146{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001147 ALOGV("hal_1_0::HalPolicy::ConvertReLu6()");
Sadik Armagan61113162019-07-25 09:09:40 +01001148 return ::ConvertReLu6<hal_1_0::HalPolicy>(operation, model, data);
arovir01b0717b52018-09-05 17:03:25 +01001149}
1150
1151bool HalPolicy::ConvertSoftmax(const Operation& operation, const Model& model, ConversionData& data)
1152{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001153 ALOGV("hal_1_0::HalPolicy::ConvertSoftmax()");
1154
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +01001155 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_0::HalPolicy>(operation, 0, model, data);
arovir01b0717b52018-09-05 17:03:25 +01001156 if (!input.IsValid())
1157 {
1158 return Fail("%s: Operation has invalid inputs", __func__);
1159 }
1160
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +01001161 const Operand* outputOperand = GetOutputOperand<hal_1_0::HalPolicy>(operation, 0, model);
arovir01b0717b52018-09-05 17:03:25 +01001162 if (!outputOperand)
1163 {
1164 return Fail("%s: Operation has no outputs", __func__);
1165 }
1166
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001167 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*outputOperand);
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +01001168 if (IsDynamicTensor(outputInfo))
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +01001169 {
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001170 return Fail("%s: Dynamic output tensors are not supported", __func__);
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +01001171 }
arovir01b0717b52018-09-05 17:03:25 +01001172
1173 armnn::SoftmaxDescriptor desc;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +01001174 if (!GetInputFloat32<hal_1_0::HalPolicy>(operation, 1, desc.m_Beta, model, data))
arovir01b0717b52018-09-05 17:03:25 +01001175 {
1176 return Fail("%s: Operation has invalid inputs", __func__);
1177 }
1178
Ferran Balaguerd30093c2019-07-09 17:04:47 +01001179 bool isSupported = false;
1180 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1181 IsSoftmaxSupported,
1182 data.m_Backends,
1183 isSupported,
1184 input.GetTensorInfo(),
1185 outputInfo,
1186 desc);
1187 if (!isSupported)
arovir01b0717b52018-09-05 17:03:25 +01001188 {
1189 return false;
1190 }
1191
1192 armnn::IConnectableLayer* layer = data.m_Network->AddSoftmaxLayer(desc);
1193 assert(layer != nullptr);
1194 input.Connect(layer->GetInputSlot(0));
1195
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001196 return SetupAndTrackLayerOutputSlot<hal_1_0::HalPolicy>(operation, 0, *layer, model, data);
arovir01b0717b52018-09-05 17:03:25 +01001197}
1198
Keith Davisa6bc52f2019-06-26 09:39:49 +01001199bool HalPolicy::ConvertSpaceToDepth(const Operation& operation, const Model& model, ConversionData& data)
1200{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001201 ALOGV("hal_1_0::HalPolicy::ConvertSpaceToDepth()");
Keith Davisa6bc52f2019-06-26 09:39:49 +01001202
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001203 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_0::HalPolicy>(operation, 0, model, data);
Keith Davisa6bc52f2019-06-26 09:39:49 +01001204 if (!input.IsValid() )
1205 {
1206 return Fail("%s: Operation has invalid inputs", __func__);
1207 }
1208
1209 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
1210 unsigned int rank = inputInfo.GetNumDimensions();
1211
1212 if (rank != 4)
1213 {
1214 return Fail("%s: Only inputs with rank 4 are supported", __func__);
1215 }
1216
1217 armnn::SpaceToDepthDescriptor desc;
1218 bool dataLayoutCheck;
1219
1220 GetInputScalar<hal_1_0::HalPolicy>(operation, 1, OperandType::INT32, desc.m_BlockSize, model, data);
1221
1222 if (desc.m_BlockSize <= 1)
1223 {
1224 return Fail("%s: Block size must be at least 1 in all dimensions");
1225 }
1226
1227 const Operand* output = GetOutputOperand<hal_1_0::HalPolicy>(operation, 0, model);
1228 if (!output)
1229 {
1230 return Fail("%s: Could not read output 0", __func__);
1231 }
1232
1233 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Ferran Balaguerd30093c2019-07-09 17:04:47 +01001234
1235 bool isSupported = false;
1236 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1237 IsSpaceToDepthSupported,
1238 data.m_Backends,
1239 isSupported,
1240 inputInfo,
1241 outputInfo,
1242 desc);
1243 if (!isSupported)
Keith Davisa6bc52f2019-06-26 09:39:49 +01001244 {
1245 return false;
1246 }
1247
1248 armnn::IConnectableLayer* const layer = data.m_Network->AddSpaceToDepthLayer(desc);
1249 assert(layer != nullptr);
1250 input.Connect(layer->GetInputSlot(0));
1251
1252 return SetupAndTrackLayerOutputSlot<hal_1_0::HalPolicy>(operation, 0, *layer, model, data);
1253}
1254
arovir01b0717b52018-09-05 17:03:25 +01001255bool HalPolicy::ConvertTanH(const Operation& operation, const Model& model, ConversionData& data)
1256{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001257 ALOGV("hal_1_0::HalPolicy::ConvertTanH()");
Sadik Armagan61113162019-07-25 09:09:40 +01001258 return ::ConvertTanH<hal_1_0::HalPolicy>(operation, model, data);
arovir01b0717b52018-09-05 17:03:25 +01001259}
1260
1261bool HalPolicy::ConvertReshape(const Operation& operation, const Model& model, ConversionData& data)
1262{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001263 ALOGV("hal_1_0::HalPolicy::ConvertReshape()");
1264
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +01001265 const Operand* inputOperand = GetInputOperand<hal_1_0::HalPolicy>(operation, 0, model);
1266 const Operand* requestedShapeOperand = GetInputOperand<hal_1_0::HalPolicy>(operation, 1, model);
1267 const Operand* outputOperand = GetOutputOperand<hal_1_0::HalPolicy>(operation, 0, model);
arovir01b0717b52018-09-05 17:03:25 +01001268
1269 if (inputOperand == nullptr
1270 || requestedShapeOperand == nullptr
1271 || outputOperand == nullptr)
1272 {
1273 return Fail("%s: Operation has invalid inputs", __func__);
1274 }
1275
1276
1277 if (requestedShapeOperand->dimensions.size() != 1)
1278 {
1279 return Fail("%s: Input 1 expected to be one-dimensional (found %i dimensions)",
1280 __func__, requestedShapeOperand->dimensions.size());
1281 }
1282
1283 std::vector<int32_t> targetDimensions;
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +01001284 if (!GetTensorInt32Values<hal_1_0::HalPolicy>(*requestedShapeOperand, targetDimensions, model, data))
arovir01b0717b52018-09-05 17:03:25 +01001285 {
1286 return Fail("%s: Could not read values of input 1", __func__);
1287 }
1288
1289 const Shape inputOperandShape = GetOperandShape(*inputOperand);
1290
1291 Shape requestedShape;
1292 // targetDimensions may contain special values (e.g. -1). reshapePrepare() is an AndroidNN provided utility
1293 // function that resolves these values into a fully specified tensor shape.
1294 if (!reshapePrepare(inputOperandShape, targetDimensions.data(), targetDimensions.size(), &requestedShape))
1295 {
1296 return Fail("%s: Failed to resolve the requested shape", __func__);
1297 }
1298
1299 const Shape outputOperandShape = GetOperandShape(*outputOperand);
1300 if (!SameShape(requestedShape, outputOperandShape))
1301 {
1302 return Fail("%s: Shape of output operand does not match resolved requested shape", __func__);
1303 }
1304
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +01001305 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_0::HalPolicy>(operation, 0, model, data);
arovir01b0717b52018-09-05 17:03:25 +01001306 if (!input.IsValid())
1307 {
1308 return Fail("%s: Could not read input 0", __func__);
1309 }
1310
arovir01b0717b52018-09-05 17:03:25 +01001311 armnn::ReshapeDescriptor reshapeDescriptor;
1312 reshapeDescriptor.m_TargetShape = armnn::TensorShape(requestedShape.dimensions.size(),
1313 requestedShape.dimensions.data());
1314
Ferran Balaguerd30093c2019-07-09 17:04:47 +01001315 bool isSupported = false;
1316 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1317 IsReshapeSupported,
1318 data.m_Backends,
1319 isSupported,
1320 input.GetTensorInfo(),
1321 reshapeDescriptor);
1322 if (!isSupported)
Matteo Martincigh265d1ad2019-01-08 18:14:53 +00001323 {
1324 return false;
1325 }
1326
arovir01b0717b52018-09-05 17:03:25 +01001327 armnn::IConnectableLayer* layer = data.m_Network->AddReshapeLayer(reshapeDescriptor);
1328 assert(layer != nullptr);
1329 input.Connect(layer->GetInputSlot(0));
1330
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +01001331 return SetupAndTrackLayerOutputSlot<hal_1_0::HalPolicy>(operation, 0, *layer, model, data);
arovir01b0717b52018-09-05 17:03:25 +01001332}
1333
1334bool HalPolicy::ConvertResizeBilinear(const Operation& operation, const Model& model, ConversionData& data)
1335{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001336 ALOGV("hal_1_0::HalPolicy::ConvertResizeBilinear()");
1337
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +01001338 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_0::HalPolicy>(operation, 0, model, data);
arovir01b0717b52018-09-05 17:03:25 +01001339 if (!input.IsValid())
1340 {
1341 return Fail("%s: Could not read input 0", __func__);
1342 }
1343
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +01001344 const Operand* output = GetOutputOperand<hal_1_0::HalPolicy>(operation, 0, model);
arovir01b0717b52018-09-05 17:03:25 +01001345 if (!output)
1346 {
1347 return Fail("%s: Could not read output 0", __func__);
1348 }
1349
1350 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
1351 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
1352
Aron Virginas-Tara5daf862019-07-01 19:07:20 +01001353 armnn::ResizeDescriptor desc;
1354 desc.m_Method = armnn::ResizeMethod::Bilinear;
Mohamed Nour Abouelseoud81afa302018-10-29 14:32:55 +00001355 desc.m_DataLayout = armnn::DataLayout::NHWC;
arovir01b0717b52018-09-05 17:03:25 +01001356
Ferran Balaguerd30093c2019-07-09 17:04:47 +01001357 bool isSupported = false;
1358 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1359 IsResizeSupported,
1360 data.m_Backends,
1361 isSupported,
1362 inputInfo,
1363 outputInfo,
1364 desc);
1365 if (!isSupported)
arovir01b0717b52018-09-05 17:03:25 +01001366 {
1367 return false;
1368 }
1369
Aron Virginas-Tar535607d2019-07-03 15:46:15 +01001370 if (!GetInputScalar<hal_1_0::HalPolicy>(operation, 1, OperandType::INT32, desc.m_TargetWidth, model, data) ||
1371 !GetInputScalar<hal_1_0::HalPolicy>(operation, 2, OperandType::INT32, desc.m_TargetHeight, model, data))
arovir01b0717b52018-09-05 17:03:25 +01001372 {
1373 return Fail("%s: Operation has invalid inputs", __func__);
1374 }
1375
Aron Virginas-Tara5daf862019-07-01 19:07:20 +01001376 armnn::IConnectableLayer* layer = data.m_Network->AddResizeLayer(desc);
Mohamed Nour Abouelseoud81afa302018-10-29 14:32:55 +00001377
arovir01b0717b52018-09-05 17:03:25 +01001378 assert(layer != nullptr);
arovir01b0717b52018-09-05 17:03:25 +01001379
Mohamed Nour Abouelseoud81afa302018-10-29 14:32:55 +00001380 layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1381 input.Connect(layer->GetInputSlot(0));
arovir01b0717b52018-09-05 17:03:25 +01001382
Aron Virginas-Tarcd700e42019-06-14 14:54:52 +01001383 return SetupAndTrackLayerOutputSlot<hal_1_0::HalPolicy>(operation, 0, *layer, model, data);
arovir01b0717b52018-09-05 17:03:25 +01001384
1385}
1386
1387} // namespace hal_1_0
Matteo Martincigh58f71092018-09-25 15:58:52 +01001388} // namespace armnn_driver