blob: 86b3bb78da79f55bbb42f9e5010a52401e2ee927 [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-Tar573a8fa2019-07-23 14:01:37 +01008#include "Utils.hpp"
Aron Virginas-Tarf03fcf02019-07-09 17:44:24 +01009
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +010010#include <DataLayoutIndexed.hpp>
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +010011#include <Half.hpp>
Narumol Prangnawarat85f96542019-09-12 16:26:29 +010012#include <TensorUtils.hpp>
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +010013
Teresa Charlin8f6429d2019-10-01 13:10:15 +010014#include <armnn/TypesUtils.hpp>
15
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +010016#include <cmath>
Aron Virginas-Tar3e0982b2019-10-29 14:25:09 +000017#include <string>
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +010018
Mike Kellyb5fdf382019-06-11 16:35:25 +010019namespace armnn_driver
20{
21namespace hal_1_2
22{
23
Teresa Charlin8f6429d2019-10-01 13:10:15 +010024using namespace armnn;
25
Mike Kellyb5fdf382019-06-11 16:35:25 +010026bool HalPolicy::ConvertOperation(const Operation& operation, const Model& model, ConversionData& data)
27{
Mike Kellyb5fdf382019-06-11 16:35:25 +010028 switch (operation.type)
29 {
Kevin May407718f2019-09-09 14:46:41 +010030 case V1_2::OperationType::ABS:
31 return ConvertAbs(operation, model, data);
Mike Kelly46272802019-08-14 17:00:48 +010032 case V1_2::OperationType::ADD:
33 return ConvertAdd(operation, model, data);
Sadik Armagan15d63e22019-07-26 16:59:35 +010034 case V1_2::OperationType::AVERAGE_POOL_2D:
35 return ConvertAveragePool2d(operation, model, data);
Finn Williams23b87b32019-07-30 11:44:05 +010036 case V1_2::OperationType::BATCH_TO_SPACE_ND:
37 return ConvertBatchToSpaceNd(operation, model, data);
Mike Kellyb8805202019-07-31 17:25:43 +010038 case V1_2::OperationType::CONCATENATION:
39 return ConvertConcatenation(operation, model, data);
Mike Kellyb5fdf382019-06-11 16:35:25 +010040 case V1_2::OperationType::CONV_2D:
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +010041 return ConvertConv2d(operation, model, data);
Aron Virginas-Tar8edb16d2019-10-01 13:34:59 +010042 case V1_2::OperationType::DEPTH_TO_SPACE:
43 return ConvertDepthToSpace(operation, model, data);
Mike Kellyb5fdf382019-06-11 16:35:25 +010044 case V1_2::OperationType::DEPTHWISE_CONV_2D:
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +010045 return ConvertDepthwiseConv2d(operation, model, data);
Mike Kelly46272802019-08-14 17:00:48 +010046 case V1_2::OperationType::DEQUANTIZE:
47 return ConvertDequantize(operation, model, data);
48 case V1_2::OperationType::DIV:
49 return ConvertDiv(operation, model, data);
Aron Virginas-Tar3e0982b2019-10-29 14:25:09 +000050 case V1_2::OperationType::EQUAL:
51 return ConvertComparison(operation, model, data, ComparisonOperation::Equal);
Narumol Prangnawarat85f96542019-09-12 16:26:29 +010052 case V1_2::OperationType::EXPAND_DIMS:
53 return ConvertExpandDims(operation, model, data);
Mike Kelly46272802019-08-14 17:00:48 +010054 case V1_2::OperationType::FLOOR:
55 return ConvertFloor(operation, model, data);
56 case V1_2::OperationType::FULLY_CONNECTED:
57 return ConvertFullyConnected(operation, model, data);
Aron Virginas-Tar3e0982b2019-10-29 14:25:09 +000058 case V1_2::OperationType::GREATER:
59 return ConvertComparison(operation, model, data, ComparisonOperation::Greater);
60 case V1_2::OperationType::GREATER_EQUAL:
61 return ConvertComparison(operation, model, data, ComparisonOperation::GreaterOrEqual);
Teresa Charlin8f6429d2019-10-01 13:10:15 +010062 case V1_2::OperationType::GROUPED_CONV_2D:
63 return ConvertGroupedConv2d(operation, model, data);
Aron Virginas-Tara2a73802019-10-09 15:30:40 +010064 case V1_2::OperationType::INSTANCE_NORMALIZATION:
65 return ConvertInstanceNormalization(operation, model, data);
Mike Kelly46272802019-08-14 17:00:48 +010066 case V1_2::OperationType::L2_NORMALIZATION:
67 return ConvertL2Normalization(operation, model, data);
Sadik Armagan15d63e22019-07-26 16:59:35 +010068 case V1_2::OperationType::L2_POOL_2D:
69 return ConvertL2Pool2d(operation, model, data);
Aron Virginas-Tar3e0982b2019-10-29 14:25:09 +000070 case V1_2::OperationType::LESS:
71 return ConvertComparison(operation, model, data, ComparisonOperation::Less);
72 case V1_2::OperationType::LESS_EQUAL:
73 return ConvertComparison(operation, model, data, ComparisonOperation::LessOrEqual);
Mike Kelly46272802019-08-14 17:00:48 +010074 case V1_2::OperationType::LOCAL_RESPONSE_NORMALIZATION:
75 return ConvertLocalResponseNormalization(operation, model, data);
76 case V1_2::OperationType::LOGISTIC:
77 return ConvertLogistic(operation, model, data);
Aron Virginas-Tar75e67792019-10-15 13:33:03 +010078 case V1_2::OperationType::LOG_SOFTMAX:
79 return ConvertLogSoftmax(operation, model, data);
Mike Kelly46272802019-08-14 17:00:48 +010080 case V1_2::OperationType::LSTM:
81 return ConvertLstm(operation, model, data);
Sadik Armagan15d63e22019-07-26 16:59:35 +010082 case V1_2::OperationType::MAX_POOL_2D:
83 return ConvertMaxPool2d(operation, model, data);
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +010084 case V1_2::OperationType::MAXIMUM:
85 return ConvertMaximum(operation, model, data);
Mike Kelly46272802019-08-14 17:00:48 +010086 case V1_2::OperationType::MEAN:
87 return ConvertMean(operation, model, data);
Ellen Norris-Thompson1cb29aa2019-07-11 17:27:37 +010088 case V1_2::OperationType::MINIMUM:
89 return ConvertMinimum(operation, model, data);
Mike Kelly46272802019-08-14 17:00:48 +010090 case V1_2::OperationType::MUL:
91 return ConvertMul(operation, model, data);
Aron Virginas-Tar3e0982b2019-10-29 14:25:09 +000092 case V1_2::OperationType::NOT_EQUAL:
93 return ConvertComparison(operation, model, data, ComparisonOperation::NotEqual);
Mike Kelly3c673942019-07-25 09:26:06 +010094 case V1_2::OperationType::PAD:
Aron Virginas-Tarc921f6b2019-07-25 10:14:33 +010095 return ConvertPad(operation, model, data);
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +010096 case V1_2::OperationType::PAD_V2:
97 return ConvertPadV2(operation, model, data);
Matteo Martincigh17ffff32019-06-27 14:12:55 +010098 case V1_2::OperationType::PRELU:
99 return ConvertPrelu(operation, model, data);
Sadik Armagan5a476a82019-07-30 09:43:18 +0100100 case V1_2::OperationType::QUANTIZE:
101 return ConvertQuantize(operation, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +0100102 case V1_2::OperationType::QUANTIZED_16BIT_LSTM:
103 return ConvertQuantizedLstm(operation, model, data);
Sadik Armagan61113162019-07-25 09:09:40 +0100104 case V1_2::OperationType::RELU:
105 return ConvertReLu(operation, model, data);
106 case V1_2::OperationType::RELU1:
107 return ConvertReLu1(operation, model, data);
108 case V1_2::OperationType::RELU6:
109 return ConvertReLu6(operation, model, data);
Mike Kelly46272802019-08-14 17:00:48 +0100110 case V1_2::OperationType::RESHAPE:
111 return ConvertReshape(operation, model, data);
Aron Virginas-Tarfb2fa292019-07-04 11:59:48 +0100112 case V1_2::OperationType::RESIZE_BILINEAR:
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100113 return ConvertResize(operation, model, data, ResizeMethod::Bilinear);
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +0100114 case V1_2::OperationType::RESIZE_NEAREST_NEIGHBOR:
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100115 return ConvertResize(operation, model, data, ResizeMethod::NearestNeighbor);
Aron Virginas-Tarfa6544e2019-09-10 14:42:22 +0100116 case V1_2::OperationType::RSQRT:
117 return ConvertRsqrt(operation, model, data);
Sadik Armagan701d9a02019-09-04 15:16:18 +0100118 case V1_2::OperationType::SQRT:
119 return ConvertSqrt(operation, model, data);
Mike Kelly46272802019-08-14 17:00:48 +0100120 case V1_2::OperationType::SQUEEZE:
121 return ConvertSqueeze(operation, model, data);
122 case V1_2::OperationType::STRIDED_SLICE:
123 return ConvertStridedSlice(operation, model, data);
124 case V1_2::OperationType::TRANSPOSE:
125 return ConvertTranspose(operation, model, data);
David Monahan613b49c2019-06-27 11:37:47 +0100126 case V1_2::OperationType::TRANSPOSE_CONV_2D:
Aron Virginas-Tar8b991682019-07-31 12:54:59 +0100127 return ConvertTransposeConv2d(operation, model, data);
Francis Murtagh074c25a2019-07-22 16:40:57 +0100128 case V1_2::OperationType::SOFTMAX:
129 return ConvertSoftmax(operation, model, data);
Finn Williamsd74c5052019-07-30 17:06:00 +0100130 case V1_2::OperationType::SPACE_TO_BATCH_ND :
131 return ConvertSpaceToBatchNd(operation, model, data);
Aron Virginas-Tarad1ab532019-07-25 11:24:42 +0100132 case V1_2::OperationType::SPACE_TO_DEPTH:
133 return ConvertSpaceToDepth(operation, model, data);
Mike Kelly0a879362019-07-29 16:56:31 +0100134 case V1_2::OperationType::SUB:
135 return ConvertSub(operation, model, data);
Sadik Armagan61113162019-07-25 09:09:40 +0100136 case V1_2::OperationType::TANH:
137 return ConvertTanH(operation, model, data);
Mike Kellyb5fdf382019-06-11 16:35:25 +0100138 default:
139 return Fail("%s: Operation type %s not supported in ArmnnDriver",
140 __func__, toString(operation.type).c_str());
141 }
142}
143
Kevin May407718f2019-09-09 14:46:41 +0100144bool HalPolicy::ConvertAbs(const Operation& operation, const Model& model, ConversionData& data)
145{
146 ALOGV("hal_1_2::HalPolicy::ConvertAbs()");
147 return ::ConvertAbs<hal_1_2::HalPolicy>(operation, model, data);
148}
149
Mike Kelly46272802019-08-14 17:00:48 +0100150bool HalPolicy::ConvertAdd(const Operation& operation, const Model& model, ConversionData& data)
151{
152 ALOGV("hal_1_2::HalPolicy::ConvertAdd()");
153 return ::ConvertAdd<hal_1_2::HalPolicy>(operation, model, data);
154}
155
Sadik Armagan15d63e22019-07-26 16:59:35 +0100156bool HalPolicy::ConvertAveragePool2d(const Operation& operation, const Model& model, ConversionData& data)
157{
158 ALOGV("hal_1_2::HalPolicy::ConvertAveragePool2d()");
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100159 return ConvertPooling2d<hal_1_2::HalPolicy>(operation, __func__, PoolingAlgorithm::Average, model, data);
Sadik Armagan15d63e22019-07-26 16:59:35 +0100160}
161
Finn Williams23b87b32019-07-30 11:44:05 +0100162bool HalPolicy::ConvertBatchToSpaceNd(const Operation& operation, const Model& model, ConversionData& data)
163{
164 ALOGV("hal_1_2::HalPolicy::ConvertBatchToSpaceNd()");
165 return ::ConvertBatchToSpaceNd<hal_1_2::HalPolicy>(operation, model, data);
166}
167
Aron Virginas-Tar3e0982b2019-10-29 14:25:09 +0000168bool HalPolicy::ConvertComparison(const Operation& operation,
169 const Model& model,
170 ConversionData& data,
171 ComparisonOperation comparisonOperation)
172{
173 ALOGV("hal_1_2::HalPolicy::ConvertComparison()");
174 ALOGV("comparisonOperation = %s", GetComparisonOperationAsCString(comparisonOperation));
175
176 LayerInputHandle input0 = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
177 LayerInputHandle input1 = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 1, model, data);
178
179 if (!(input0.IsValid() && input1.IsValid()))
180 {
181 return Fail("%s: Operation has invalid inputs", __func__);
182 }
183
184 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
185 if (!output)
186 {
187 return Fail("%s: Could not read output 0", __func__);
188 }
189
190 const TensorInfo& inputInfo0 = input0.GetTensorInfo();
191 const TensorInfo& inputInfo1 = input1.GetTensorInfo();
192 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
193
194 if (IsDynamicTensor(outputInfo))
195 {
196 return Fail("%s: Dynamic output tensors are not supported", __func__);
197 }
198
199 ComparisonDescriptor descriptor(comparisonOperation);
200
201 bool isSupported = false;
202 FORWARD_LAYER_SUPPORT_FUNC(__func__,
203 IsComparisonSupported,
204 data.m_Backends,
205 isSupported,
206 inputInfo0,
207 inputInfo1,
208 outputInfo,
209 descriptor);
210
211 if (!isSupported)
212 {
213 return false;
214 }
215
216 IConnectableLayer* layer = data.m_Network->AddComparisonLayer(descriptor);
217 assert(layer != nullptr);
218
219 input0.Connect(layer->GetInputSlot(0));
220 input1.Connect(layer->GetInputSlot(1));
221
222 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
223}
224
Mike Kellyb8805202019-07-31 17:25:43 +0100225bool HalPolicy::ConvertConcatenation(const Operation& operation, const Model& model, ConversionData& data)
226{
227 ALOGV("hal_1_2::HalPolicy::ConvertConcatenation()");
228 return ::ConvertConcatenation<hal_1_2::HalPolicy>(operation, model, data);
229}
230
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100231bool HalPolicy::ConvertConv2d(const Operation& operation, const Model& model, ConversionData& data)
232{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100233 ALOGV("hal_1_2::HalPolicy::ConvertConv2d()");
234
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100235 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
236 if (!input.IsValid())
237 {
238 return Fail("%s: Operation has invalid inputs", __func__);
239 }
240
241 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
242 if (!output)
243 {
244 return Fail("%s: Could not read output 0", __func__);
245 }
246
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100247 const TensorInfo& inputInfo = input.GetTensorInfo();
248 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +0100249
250 if (IsDynamicTensor(outputInfo))
251 {
252 return Fail("%s: Dynamic output tensors are not supported", __func__);
253 }
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +0100254
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100255 Convolution2dDescriptor desc;
256 desc.m_DataLayout = DataLayout::NHWC;
Mike Kellye1d60bb2019-07-11 11:44:52 +0100257
258 // Determine whether padding is implicit or explicit
259 bool implicitPadding = operation.inputs.size() == 7 ||
260 (operation.inputs.size() >= 8 &&
261 GetInputOperand<hal_1_2::HalPolicy>(operation, 7, model)->type == OperandType::BOOL);
262
263 if (implicitPadding)
264 {
265 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 7, model, data);
266 }
267 else if (operation.inputs.size() >= 10)
268 {
269 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 10, model, data);
270 }
271
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100272 const PermutationVector OHWIToOIHW = {0, 2, 3, 1};
Mike Kellye1d60bb2019-07-11 11:44:52 +0100273
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100274 // ArmNN does not currently support non-fixed weights or bias
Mike Kellye1d60bb2019-07-11 11:44:52 +0100275 // The NNAPI filter is always OHWI [depth_out, filter_height, filter_width, depth_in] but ArmNN expects the
276 // filter's height and width indices to match the input's height and width indices so we permute it to OIHW if
277 // the DataLayout is NCHW
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100278 const ConstTensorPin weightsPin = (desc.m_DataLayout == DataLayout::NCHW) ?
Mike Kellye1d60bb2019-07-11 11:44:52 +0100279 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 1, model, data, OHWIToOIHW) :
280 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 1, model, data);
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100281 const ConstTensorPin biasPin =
Mike Kellye1d60bb2019-07-11 11:44:52 +0100282 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 2, model, data);
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100283
284 if (!weightsPin.IsValid())
285 {
286 return Fail("%s: Operation has invalid weights", __func__);
287 }
288
289 if (!biasPin.IsValid())
290 {
291 return Fail("%s: Operation has invalid biases", __func__);
292 }
293
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100294 ConstTensor weights = weightsPin.GetConstTensor();
295 ConstTensor bias = biasPin.GetConstTensor();
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100296 SanitizeBiasQuantizationScale(bias.GetInfo(), weights.GetInfo(), inputInfo);
297
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100298 ActivationFn activation;
299
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100300 if (implicitPadding)
301 {
302 android::nn::PaddingScheme paddingScheme;
303 if (!GetInputPaddingScheme<hal_1_2::HalPolicy>(operation, 3, paddingScheme, model, data) ||
304 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_StrideX, model, data) ||
305 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_StrideY, model, data) ||
306 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 6, activation, model, data) ||
307 !GetOptionalConvolutionDilationParams<hal_1_2::HalPolicy>(operation, 8, desc, model, data))
308 {
309 return Fail("%s: Operation has invalid inputs (implicit padding)", __func__);
310 }
311
Mike Kellye1d60bb2019-07-11 11:44:52 +0100312 armnnUtils::DataLayoutIndexed dataLayoutIndexed(desc.m_DataLayout);
313 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
314 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
315 const uint32_t kernelX = weights.GetShape()[widthIndex];
316 const uint32_t kernelY = weights.GetShape()[heightIndex];
317 const uint32_t inputX = inputInfo.GetShape()[widthIndex];
318 const uint32_t inputY = inputInfo.GetShape()[heightIndex];
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100319
Mike Kelly86b36d42019-07-12 16:39:33 +0100320 CalcPadding(inputX, kernelX, desc.m_StrideX, desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, paddingScheme);
321 CalcPadding(inputY, kernelY, desc.m_StrideY, desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, paddingScheme);
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100322
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100323 }
324 else if (operation.inputs.size() >= 10)
325 {
326 // explicit padding
327 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 3, OperandType::INT32, desc.m_PadLeft, model, data) ||
328 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_PadRight, model, data) ||
329 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_PadTop, model, data) ||
330 !GetInputScalar<hal_1_2::HalPolicy>(operation, 6, OperandType::INT32, desc.m_PadBottom, model, data) ||
331 !GetInputScalar<hal_1_2::HalPolicy>(operation, 7, OperandType::INT32, desc.m_StrideX, model, data) ||
332 !GetInputScalar<hal_1_2::HalPolicy>(operation, 8, OperandType::INT32, desc.m_StrideY, model, data) ||
333 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 9, activation, model, data) ||
334 !GetOptionalConvolutionDilationParams<hal_1_2::HalPolicy>(operation, 11, desc, model, data))
335 {
336 return Fail("%s: Operation has invalid inputs (explicit padding)", __func__);
337 }
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100338 }
339 else
340 {
341 return Fail("%s: Unsupported number of operation inputs", __func__);
342 }
343
344 desc.m_BiasEnabled = true;
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100345 Optional<TensorInfo> biases(bias.GetInfo());
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100346
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100347 bool isSupported = false;
348 FORWARD_LAYER_SUPPORT_FUNC(__func__,
349 IsConvolution2dSupported,
350 data.m_Backends,
351 isSupported,
352 inputInfo,
353 outputInfo,
354 desc,
355 weights.GetInfo(),
356 biases);
Aron Virginas-Tar2b173122019-07-15 14:29:09 +0100357
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100358 if (!isSupported)
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100359 {
360 return false;
361 }
362
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100363 IConnectableLayer* startLayer =
364 data.m_Network->AddConvolution2dLayer(desc, weights, Optional<ConstTensor>(bias));
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100365
366 if (!startLayer)
367 {
368 return Fail("%s: AddConvolution2dLayer failed", __func__);
369 }
370
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100371 IConnectableLayer* endLayer = ProcessActivation(outputInfo, activation, startLayer, data);
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100372
373 if (!endLayer)
374 {
375 return Fail("%s: ProcessActivation failed", __func__);
376 }
377
378 input.Connect(startLayer->GetInputSlot(0));
379
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +0100380 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *endLayer, model, data);
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100381}
382
Aron Virginas-Tar8edb16d2019-10-01 13:34:59 +0100383bool HalPolicy::ConvertDepthToSpace(const Operation& operation, const Model& model, ConversionData& data)
384{
385 ALOGV("hal_1_2::HalPolicy::ConvertDepthToSpace()");
386 return ::ConvertDepthToSpace<hal_1_2::HalPolicy>(operation, model, data);
387}
388
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100389bool HalPolicy::ConvertDepthwiseConv2d(const Operation& operation, const Model& model, ConversionData& data)
390{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +0100391 ALOGV("hal_1_2::HalPolicy::ConvertDepthwiseConv2d()");
392
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100393 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
394
395 if (!input.IsValid())
396 {
397 return Fail("%s: Operation has invalid inputs", __func__);
398 }
399
400 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
401
402 if (!output)
403 {
404 return Fail("%s: Could not read output 0", __func__);
405 }
406
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100407 const TensorInfo& inputInfo = input.GetTensorInfo();
408 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +0100409
410 if (IsDynamicTensor(outputInfo))
411 {
412 return Fail("%s: Dynamic output tensors are not supported", __func__);
413 }
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100414
415 // ArmNN does not currently support non-fixed weights or bias
416 // Find the shape of the weights tensor. In AndroidNN this will be [ 1, H, W, I * M ]
417 const Operand* weightsOperand = GetInputOperand<hal_1_2::HalPolicy>(operation, 1, model);
418
419 if (weightsOperand == nullptr)
420 {
421 return Fail("%s: Operand is invalid", __func__);
422 }
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100423 DepthwiseConvolution2dDescriptor desc;
424 desc.m_DataLayout = DataLayout::NHWC;
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100425
426 // Determine whether padding is implicit or explicit
427 bool implicitPadding = operation.inputs.size() == 8 ||
428 (operation.inputs.size() >= 9 &&
429 GetInputOperand<hal_1_2::HalPolicy>(operation, 8, model)->type == OperandType::BOOL);
430
431 // Look ahead to find the optional DataLayout, if present
432 const uint32_t dataLayoutFlagIndex = implicitPadding ? 8 : 11;
433 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, dataLayoutFlagIndex, model, data);
434
435 armnnUtils::DataLayoutIndexed dataLayoutIndexed(desc.m_DataLayout);
436 unsigned int channelsIndex = dataLayoutIndexed.GetChannelsIndex();
437 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
438 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
439
440 // Reinterpret weight data as [ H, W, I, M ]
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100441 TensorShape weightsShape({ weightsOperand->dimensions[1],
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100442 weightsOperand->dimensions[2],
443 inputInfo.GetShape()[channelsIndex],
444 weightsOperand->dimensions[3] / inputInfo.GetShape()[channelsIndex] });
445
446 // Swizzle weight data [ H, W, I, M ] -> [ M, I, H, W ]
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100447 const PermutationVector HWIMToMIHW = { 2U, 3U, 1U, 0U };
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100448
449 const ConstTensorPin weightsPin =
450 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
451 1,
452 model,
453 data,
454 HWIMToMIHW,
455 &weightsShape);
456
457 // Bias is a 1D tensor
458 const ConstTensorPin biasPin =
459 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 2, model, data);
460
461 if (!weightsPin.IsValid())
462 {
463 return Fail("%s: Operation has invalid weights", __func__);
464 }
465
466 if (!biasPin.IsValid())
467 {
468 return Fail("%s: Operation has invalid biases", __func__);
469 }
470
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100471 ConstTensor weights = weightsPin.GetConstTensor();
472 ConstTensor bias = biasPin.GetConstTensor();
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100473 SanitizeBiasQuantizationScale(bias.GetInfo(), weights.GetInfo(), inputInfo);
474
475 ActivationFn activation;
476
477 if (implicitPadding)
478 {
479 android::nn::PaddingScheme paddingScheme;
480 if (!GetInputPaddingScheme<hal_1_2::HalPolicy>(operation, 3, paddingScheme, model, data) ||
481 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_StrideX, model, data) ||
482 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_StrideY, model, data) ||
483 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 7, activation, model, data) ||
484 !GetOptionalConvolutionDilationParams<hal_1_2::HalPolicy>(operation, 9, desc, model, data))
485 {
486 return Fail("%s: Operation has invalid inputs (implicit padding)", __func__);
487 }
488
489 const uint32_t kernelX = weights.GetShape()[3];
490 const uint32_t kernelY = weights.GetShape()[2];
491 const uint32_t inputX = inputInfo.GetShape()[widthIndex];
492 const uint32_t inputY = inputInfo.GetShape()[heightIndex];
493
Mike Kelly86b36d42019-07-12 16:39:33 +0100494 CalcPadding(inputX, kernelX, desc.m_StrideX, desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, paddingScheme);
495 CalcPadding(inputY, kernelY, desc.m_StrideY, desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, paddingScheme);
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100496 }
497 else if (operation.inputs.size() >= 11)
498 {
499 // explicit padding
500 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 3, OperandType::INT32, desc.m_PadLeft, model, data) ||
501 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_PadRight, model, data) ||
502 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_PadTop, model, data) ||
503 !GetInputScalar<hal_1_2::HalPolicy>(operation, 6, OperandType::INT32, desc.m_PadBottom, model, data) ||
504 !GetInputScalar<hal_1_2::HalPolicy>(operation, 7, OperandType::INT32, desc.m_StrideX, model, data) ||
505 !GetInputScalar<hal_1_2::HalPolicy>(operation, 8, OperandType::INT32, desc.m_StrideY, model, data) ||
506 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 10, activation, model, data) ||
507 !GetOptionalConvolutionDilationParams<hal_1_2::HalPolicy>(operation, 12, desc, model, data))
508 {
509 return Fail("%s: Operation has invalid inputs (explicit padding)", __func__);
510 }
511 }
512 else
513 {
514 return Fail("%s: Unsupported number of operation inputs", __func__);
515 }
516
517 desc.m_BiasEnabled = true;
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100518 Optional<TensorInfo> biases(bias.GetInfo());
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100519
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100520 bool isSupported = false;
521 FORWARD_LAYER_SUPPORT_FUNC(__func__,
522 IsDepthwiseConvolutionSupported,
523 data.m_Backends,
524 isSupported,
525 inputInfo,
526 outputInfo,
527 desc,
528 weights.GetInfo(),
529 biases);
Aron Virginas-Tar9fd37392019-07-15 18:04:32 +0100530
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100531 if (!isSupported)
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100532 {
533 return false;
534 }
535
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100536 IConnectableLayer* startLayer =
537 data.m_Network->AddDepthwiseConvolution2dLayer(desc, weights, Optional<ConstTensor>(bias));
Aron Virginas-Tar9fd37392019-07-15 18:04:32 +0100538
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100539 if (!startLayer)
540 {
541 return Fail("%s: AddDepthwiseConvolution2dLayer failed", __func__);
542 }
543
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100544 IConnectableLayer* endLayer = ProcessActivation(outputInfo, activation, startLayer, data);
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100545 if (!endLayer)
546 {
547 return Fail("%s: ProcessActivation failed", __func__);
548 }
549
550 input.Connect(startLayer->GetInputSlot(0));
551
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +0100552 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *endLayer, model, data);
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100553}
554
Mike Kelly46272802019-08-14 17:00:48 +0100555bool HalPolicy::ConvertDequantize(const Operation& operation, const Model& model, ConversionData& data)
556{
557 ALOGV("hal_1_2::HalPolicy::ConvertDequantize()");
558 return ::ConvertDequantize<hal_1_2::HalPolicy>(operation, model, data);
559}
560
561bool HalPolicy::ConvertDiv(const Operation& operation, const Model& model, ConversionData& data)
562{
563 ALOGV("hal_1_2::HalPolicy::ConvertDiv()");
564 return ::ConvertDiv<hal_1_2::HalPolicy>(operation, model, data);
565}
566
Narumol Prangnawarat85f96542019-09-12 16:26:29 +0100567bool HalPolicy::ConvertExpandDims(const Operation& operation, const Model& model, ConversionData& data)
568{
569 ALOGV("hal_1_2::HalPolicy::ConvertExpandDims()");
570
571 LayerInputHandle input = ConvertToLayerInputHandle<HalPolicy>(operation, 0, model, data);
572
573 if (!input.IsValid())
574 {
575 return Fail("%s: Operation has invalid input", __func__);
576 }
577
578 const Operand* output = GetOutputOperand<HalPolicy>(operation, 0, model);
579 if (!output)
580 {
581 return Fail("%s: Operation has invalid output", __func__);
582 }
583
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100584 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Narumol Prangnawarat85f96542019-09-12 16:26:29 +0100585 if (IsDynamicTensor(outputInfo))
586 {
587 return Fail("%s: Dynamic output tensors are not supported", __func__);
588 }
589
590 int32_t axis;
591 if (!GetInputScalar<HalPolicy>(operation, 1, OperandType::INT32, axis, model, data))
592 {
593 return Fail("%s: failed to get axis input value", __func__);
594 }
595
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100596 TensorShape targetShape;
Narumol Prangnawarat85f96542019-09-12 16:26:29 +0100597
598 try
599 {
600 targetShape = armnnUtils::ExpandDims(input.GetTensorInfo().GetShape(), axis);
601 }
602 catch (const std::exception &e)
603 {
604 return Fail("%s: %s", __func__, e.what());
605 }
606
607 if (targetShape != outputInfo.GetShape())
608 {
609 return Fail("%s: Shape of the output operand does not match the resolved expanded shape", __func__);
610 }
611
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100612 ReshapeDescriptor reshapeDescriptor;
Narumol Prangnawarat85f96542019-09-12 16:26:29 +0100613 reshapeDescriptor.m_TargetShape = targetShape;
614
615 bool isSupported = false;
616 FORWARD_LAYER_SUPPORT_FUNC(__func__,
617 IsReshapeSupported,
618 data.m_Backends,
619 isSupported,
620 input.GetTensorInfo(),
621 reshapeDescriptor);
622
623 if (!isSupported)
624 {
625 return false;
626 }
627
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100628 IConnectableLayer* layer = data.m_Network->AddReshapeLayer(reshapeDescriptor);
Narumol Prangnawarat85f96542019-09-12 16:26:29 +0100629 assert(layer != nullptr);
630 input.Connect(layer->GetInputSlot(0));
631
632 return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data);
633}
634
Mike Kelly46272802019-08-14 17:00:48 +0100635bool HalPolicy::ConvertFloor(const Operation& operation, const Model& model, ConversionData& data)
636{
637 ALOGV("hal_1_2::HalPolicy::ConvertFloor()");
638 return ::ConvertFloor<hal_1_2::HalPolicy>(operation, model, data);
639}
640
641bool HalPolicy::ConvertFullyConnected(const Operation& operation, const Model& model, ConversionData& data)
642{
643 ALOGV("hal_1_2::HalPolicy::ConvertFullyConnected()");
644 return ::ConvertFullyConnected<hal_1_2::HalPolicy>(operation, model, data);
645}
646
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100647bool HalPolicy::ConvertGroupedConv2d(const Operation& operation, const Model& model, ConversionData& data)
648{
649 ALOGV("hal_1_2::HalPolicy::ConvertGroupedConv2d()");
650
651 //
652 // Parse data
653 //
654 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
655 if (!input.IsValid())
656 {
657 return Fail("%s: Operation has invalid inputs", __func__);
658 }
659 const TensorInfo& inputInfo = input.GetTensorInfo();
660
661 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
662 if (!output)
663 {
664 return Fail("%s: Could not read output 0", __func__);
665 }
666 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
667 if (IsDynamicTensor(outputInfo))
668 {
669 return Fail("%s: Dynamic output tensors are not supported", __func__);
670 }
671
672 // Look ahead to determine data layout
673 DataLayout dataLayout = DataLayout::NHWC;
674 if (operation.inputs.size() == 12)
675 {
676 dataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 11, model, data);
677 }
678 else
679 {
680 dataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 8, model, data);
681 }
682
683 // NOTE:
684 // NNAPI weights are always OHWI, i.e. [depth_out, filter_height, filter_width, depth_group],
685 // but Arm NN expects the filter's height and width indices to match the input's height and
686 // width indices so when the DataLayout is NCHW, we need to permute the weights to OIHW
687 const PermutationVector ohwiToOihw = { 0u, 2u, 3u, 1u };
688 const ConstTensorPin weightsPin = (dataLayout == DataLayout::NCHW) ?
689 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 1, model, data, ohwiToOihw) :
690 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 1, model, data);
691 const ConstTensorPin biasesPin =
692 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 2, model, data);
693 if (!weightsPin.IsValid() || !biasesPin.IsValid())
694 {
695 return Fail("%s: Operation has invalid inputs", __func__);
696 }
697
698 ConstTensor weights = weightsPin.GetConstTensor();
699 ConstTensor biases = biasesPin.GetConstTensor();
700 SanitizeBiasQuantizationScale(biases.GetInfo(), weights.GetInfo(), inputInfo);
701
702 const TensorShape& inputShape = inputInfo.GetShape();
703 const TensorShape& outputShape = outputInfo.GetShape();
704 const TensorShape& weightsShape = weights.GetShape();
705 const TensorShape& biasesShape = biases.GetShape();
706
707 armnnUtils::DataLayoutIndexed dataLayoutIndexed(dataLayout);
708 const unsigned int channelsIndex = dataLayoutIndexed.GetChannelsIndex();
709 const unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
710 const unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
711
712 Convolution2dDescriptor desc;
713 desc.m_DataLayout = dataLayout;
714 desc.m_BiasEnabled = true;
715
716 int numGroups;
717 ActivationFn activation;
718
719 if (operation.inputs.size() == 12)
720 {
721 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 3, OperandType::INT32, desc.m_PadLeft, model, data) ||
722 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_PadRight, model, data) ||
723 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_PadTop, model, data) ||
724 !GetInputScalar<hal_1_2::HalPolicy>(operation, 6, OperandType::INT32, desc.m_PadBottom, model, data) ||
725 !GetInputScalar<hal_1_2::HalPolicy>(operation, 7, OperandType::INT32, desc.m_StrideX, model, data) ||
726 !GetInputScalar<hal_1_2::HalPolicy>(operation, 8, OperandType::INT32, desc.m_StrideY, model, data) ||
727 !GetInputScalar<hal_1_2::HalPolicy>(operation, 9, OperandType::INT32, numGroups, model, data) ||
728 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 10, activation, model, data))
729 {
730 return Fail("%s: Operation has invalid inputs (explicit padding)", __func__);
731 }
732
733 }
734 else if (operation.inputs.size() == 9)
735 {
736 android::nn::PaddingScheme paddingScheme;
737 if (!GetInputPaddingScheme<hal_1_2::HalPolicy>(operation, 3, paddingScheme, model, data) ||
738 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_StrideX, model, data) ||
739 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_StrideY, model, data) ||
740 !GetInputScalar<hal_1_2::HalPolicy>(operation, 6, OperandType::INT32, numGroups, model, data) ||
741 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 7, activation, model, data))
742 {
743 return Fail("%s: Operation has invalid inputs (implicit padding)", __func__);
744 }
745
746 const uint32_t inputX = inputInfo.GetShape()[widthIndex];
747 const uint32_t inputY = inputInfo.GetShape()[heightIndex];
748
749 const uint32_t kernelX = weightsShape[widthIndex];
750 const uint32_t kernelY = weightsShape[heightIndex];
751
752 CalcPadding(inputX, kernelX, desc.m_StrideX, desc.m_PadLeft, desc.m_PadRight, paddingScheme);
753 CalcPadding(inputY, kernelY, desc.m_StrideY, desc.m_PadTop, desc.m_PadBottom, paddingScheme);
754 }
755 else
756 {
757 return Fail("%s: Unsupported number of operation inputs", __func__);
758 }
759
760 const unsigned int outputChannels = outputShape[channelsIndex];
761
762 const unsigned int channelsPerGroup = weightsShape[channelsIndex];
763 const unsigned int channelMultiplier = outputChannels / numGroups;
764
765 //
766 // Validate all relevant inputs
767 //
768 if (numGroups <= 0)
769 {
770 return Fail("%s: Number of groups must be greater than 0. Got: %d", __func__, numGroups);
771 }
772
773 if (outputChannels % numGroups != 0u)
774 {
775 return Fail("%s: Output channels must be divisible by the number of groups", __func__);
776 }
777
778 //
779 // Set up Splitter layer
780 //
781 unsigned int splitterDimSizes[4] = { inputShape[0], inputShape[1], inputShape[2], inputShape[3] };
782 splitterDimSizes[channelsIndex] /= numGroups; // split in depth
783
784 TensorInfo splitterOutputInfo(4,
785 splitterDimSizes,
786 inputInfo.GetDataType(),
787 inputInfo.GetQuantizationScale(),
788 inputInfo.GetQuantizationOffset());
789
790 std::vector<std::reference_wrapper<TensorInfo>> splitterOutputInfos(numGroups, std::ref(splitterOutputInfo));
791
792 ViewsDescriptor splitterDesc(numGroups);
793 for (unsigned int group = 0u; group < numGroups; ++group)
794 {
795 splitterDesc.SetViewOriginCoord(group, channelsIndex, splitterDimSizes[channelsIndex] * group);
796 for (unsigned int dimIdx = 0u; dimIdx < 4u; dimIdx++)
797 {
798 splitterDesc.SetViewSize(group, dimIdx, splitterDimSizes[dimIdx]);
799 }
800 }
801
802 bool isSupported = false;
803 FORWARD_LAYER_SUPPORT_FUNC(__func__,
804 IsSplitterSupported,
805 data.m_Backends,
806 isSupported,
807 inputInfo,
808 splitterOutputInfos,
809 splitterDesc);
810 if (!isSupported)
811 {
812 return false;
813 }
814
815 IConnectableLayer* splitterLayer = data.m_Network->AddSplitterLayer(splitterDesc);
816 if (!splitterLayer)
817 {
818 return Fail("%s: Failed to add SplitterLayer", __func__);
819 }
820
821 input.Connect(splitterLayer->GetInputSlot(0));
822 for (unsigned int group = 0u; group < splitterLayer->GetNumOutputSlots(); ++group)
823 {
824 splitterLayer->GetOutputSlot(group).SetTensorInfo(splitterOutputInfo);
825 }
826
827 //
828 // Set up Convolution2d layers for each group
829 //
830 TensorShape groupInputShape(inputShape);
831 groupInputShape[channelsIndex] = channelsPerGroup;
832
833 TensorShape groupOutputShape(outputShape);
834 groupOutputShape[channelsIndex] = 1;
835
836 TensorShape groupWeightsShape(weightsShape);
837 groupWeightsShape[0] /= channelMultiplier * numGroups;
838
839 TensorShape groupBiasesShape({ 1 });
840
841 const TensorInfo groupInputInfo (groupInputShape,
842 inputInfo.GetDataType(),
843 inputInfo.GetQuantizationScale(),
844 inputInfo.GetQuantizationOffset());
845 const TensorInfo groupWeightsInfo(groupWeightsShape,
846 weights.GetInfo().GetDataType(),
847 weights.GetInfo().GetQuantizationScale(),
848 weights.GetInfo().GetQuantizationOffset());
849 const TensorInfo groupBiasesInfo (groupBiasesShape,
850 biases.GetInfo().GetDataType(),
851 biases.GetInfo().GetQuantizationScale(),
852 biases.GetInfo().GetQuantizationOffset());
853 const TensorInfo groupOutputInfo (groupOutputShape,
854 outputInfo.GetDataType(),
855 outputInfo.GetQuantizationScale(),
856 outputInfo.GetQuantizationOffset());
857
858 const unsigned int weightsDataTypeSize = GetDataTypeSize(groupWeightsInfo.GetDataType());
859 const unsigned int biasesDataTypeSize = GetDataTypeSize(groupBiasesInfo.GetDataType());
860
861 std::vector<IConnectableLayer*> convLayers(numGroups*channelMultiplier, nullptr);
862 for (unsigned int group = 0u; group < numGroups; ++group)
863 {
864 for (unsigned int m = 0u; m < channelMultiplier; ++m)
865 {
866 auto index = group * channelMultiplier + m;
867
868 const unsigned int weightsDataOffset = groupWeightsShape.GetNumElements() * index * weightsDataTypeSize;
869 const unsigned int biasesDataOffset = groupBiasesShape.GetNumElements() * index * biasesDataTypeSize;
870
871 // Extract weights and biases data for current group convolution
872 ConstTensor groupWeights(groupWeightsInfo,
873 static_cast<const void *>(reinterpret_cast<const char *>(weights.GetMemoryArea()) +
874 weightsDataOffset));
875 ConstTensor groupBiases(groupBiasesInfo,
876 static_cast<const void *>(reinterpret_cast<const char *>(biases.GetMemoryArea()) +
877 biasesDataOffset));
878
879 isSupported = false;
880 FORWARD_LAYER_SUPPORT_FUNC(__func__,
881 IsConvolution2dSupported,
882 data.m_Backends,
883 isSupported,
884 groupInputInfo,
885 groupOutputInfo,
886 desc,
887 groupWeightsInfo,
888 Optional<TensorInfo>(groupBiasesInfo));
889 if (!isSupported)
890 {
891 return false;
892 }
893
894 IConnectableLayer *convLayer =
895 data.m_Network->AddConvolution2dLayer(desc, groupWeights, Optional<ConstTensor>(groupBiases));
896 if (!convLayer)
897 {
898 return Fail("%s: AddConvolution2dLayer failed", __func__);
899 }
900
901 splitterLayer->GetOutputSlot(group).Connect(convLayer->GetInputSlot(0));
902 convLayer->GetOutputSlot(0).SetTensorInfo(groupOutputInfo);
903
904 convLayers[index] = convLayer;
905 }
906 }
907
908 //
909 // Set up Concat layer
910 //
911 ConcatDescriptor concatDescriptor(outputInfo.GetShape()[channelsIndex]);
912 for (unsigned int group = 0u; group < numGroups; ++group)
913 {
914 for (unsigned int m = 0u; m < channelMultiplier; ++m)
915 {
916 auto index = group * channelMultiplier + m;
917 concatDescriptor.SetViewOriginCoord(index, channelsIndex, index);
918 concatDescriptor.SetConcatAxis(channelsIndex);
919 }
920 }
921
922 isSupported = false;
923 FORWARD_LAYER_SUPPORT_FUNC(__func__,
924 IsConcatSupported,
925 data.m_Backends,
926 isSupported,
927 std::vector<const TensorInfo*>(numGroups * channelMultiplier, &groupOutputInfo),
928 outputInfo,
929 concatDescriptor);
930 if (!isSupported)
931 {
932 return false;
933 }
934
935 IConnectableLayer* concatLayer = data.m_Network->AddConcatLayer(concatDescriptor);
936 if (!concatLayer)
937 {
938 return Fail("%s: AddConcatLayer failed", __func__);
939 }
940
941 for (unsigned int group = 0u; group < numGroups; ++group)
942 {
943 for (unsigned int m = 0u; m < channelMultiplier; ++m)
944 {
945 auto index = group * channelMultiplier + m;
946 convLayers[index]->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(index));
947 }
948 }
949 concatLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
950
951 //
952 // Set up Activation layer (if it is set)
953 //
954 IConnectableLayer* endLayer = ProcessActivation(outputInfo, activation, concatLayer, data);
955 if (!endLayer)
956 {
957 return Fail("%s: ProcessActivation failed", __func__);
958 }
959
960 return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *endLayer, model, data);
961}
962
Aron Virginas-Tara2a73802019-10-09 15:30:40 +0100963bool HalPolicy::ConvertInstanceNormalization(const Operation& operation, const Model& model, ConversionData& data)
964{
965 ALOGV("hal_1_2::HalPolicy::ConvertInstanceNormalization()");
966
967 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
968 if (!input.IsValid())
969 {
970 return Fail("%s: Operation has an invalid input 0", __func__);
971 }
972
973 const Operand* output = GetOutputOperand<HalPolicy>(operation, 0, model);
974 if (!output)
975 {
976 return Fail("%s: Operation has an invalid output", __func__);
977 }
978
979 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
980 if (IsDynamicTensor(outputInfo))
981 {
982 return Fail("%s: Dynamic output tensors are not supported", __func__);
983 }
984
985 // Determine data type of input tensor
986 OperandType inputType;
987 if (!GetOperandType<hal_1_2::HalPolicy>(operation, 0, model, inputType))
988 {
989 return Fail("%s: Operation has invalid inputs", __func__);
990 }
991
992 InstanceNormalizationDescriptor desc;
993
994 // Read gamma, beta & epsilon
995 if (inputType == OperandType::TENSOR_FLOAT16)
996 {
997 Half fp16Gamma;
998 Half fp16Beta;
999 Half fp16Epsilon;
1000
1001 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 1, OperandType::FLOAT16, fp16Gamma, model, data) ||
1002 !GetInputScalar<hal_1_2::HalPolicy>(operation, 2, OperandType::FLOAT16, fp16Beta, model, data) ||
1003 !GetInputScalar<hal_1_2::HalPolicy>(operation, 3, OperandType::FLOAT16, fp16Epsilon, model, data))
1004 {
1005 return Fail("%s: Operation has invalid inputs (FLOAT16)", __func__);
1006 }
1007
1008 desc.m_Gamma = static_cast<float>(fp16Gamma);
1009 desc.m_Beta = static_cast<float>(fp16Beta);
1010 desc.m_Eps = static_cast<float>(fp16Epsilon);
1011 }
1012 else if (inputType == OperandType::TENSOR_FLOAT32)
1013 {
1014 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 1, OperandType::FLOAT32, desc.m_Gamma, model, data) ||
1015 !GetInputScalar<hal_1_2::HalPolicy>(operation, 2, OperandType::FLOAT32, desc.m_Beta, model, data) ||
1016 !GetInputScalar<hal_1_2::HalPolicy>(operation, 3, OperandType::FLOAT32, desc.m_Eps, model, data))
1017 {
1018 return Fail("%s: Operation has invalid inputs (FLOAT32)", __func__);
1019 }
1020 }
1021 else
1022 {
1023 return Fail("%s: Unsupported input tensor type: %d", __func__, inputType);
1024 }
1025
1026 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 4, model, data);
1027
1028 bool isSupported = false;
1029 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1030 IsInstanceNormalizationSupported,
1031 data.m_Backends,
1032 isSupported,
1033 input.GetTensorInfo(),
1034 outputInfo,
1035 desc);
1036 if (!isSupported)
1037 {
1038 return false;
1039 }
1040
1041 IConnectableLayer* layer = data.m_Network->AddInstanceNormalizationLayer(desc);
1042 input.Connect(layer->GetInputSlot(0));
1043
1044 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
1045}
1046
Mike Kelly46272802019-08-14 17:00:48 +01001047bool HalPolicy::ConvertL2Normalization(const Operation& operation, const Model& model, ConversionData& data)
1048{
1049 ALOGV("hal_1_2::HalPolicy::ConvertL2Normalization()");
1050 return ::ConvertL2Normalization<hal_1_2::HalPolicy>(operation, model, data);
1051}
1052
Sadik Armagan15d63e22019-07-26 16:59:35 +01001053bool HalPolicy::ConvertL2Pool2d(const Operation& operation, const Model& model, ConversionData& data)
1054{
1055 ALOGV("hal_1_2::HalPolicy::ConvertL2Pool2d()");
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001056 return ConvertPooling2d<hal_1_2::HalPolicy>(operation, __func__, PoolingAlgorithm::L2, model, data);
Sadik Armagan15d63e22019-07-26 16:59:35 +01001057}
1058
Mike Kelly46272802019-08-14 17:00:48 +01001059bool HalPolicy::ConvertLocalResponseNormalization(const Operation& operation,
1060 const Model& model,
1061 ConversionData& data)
1062{
1063 ALOGV("hal_1_2::HalPolicy::ConvertLocalResponseNormalization()");
1064 return ::ConvertLocalResponseNormalization<hal_1_2::HalPolicy>(operation, model, data);
1065}
1066
1067bool HalPolicy::ConvertLogistic(const Operation& operation, const Model& model, ConversionData& data)
1068{
1069 ALOGV("hal_1_2::HalPolicy::ConvertLogistic()");
1070 return ::ConvertLogistic<hal_1_2::HalPolicy>(operation, model, data);
1071}
1072
Aron Virginas-Tar75e67792019-10-15 13:33:03 +01001073bool HalPolicy::ConvertLogSoftmax(const Operation& operation, const Model& model, ConversionData& data)
1074{
1075 ALOGV("hal_1_2::HalPolicy::ConvertLogSoftmax()");
1076
1077 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
1078 if (!input.IsValid())
1079 {
1080 return Fail("%s: Failed to read input 0", __func__);
1081 }
1082
1083 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1084 if (!output)
1085 {
1086 return Fail("%s: Failed to read output", __func__);
1087 }
1088
1089 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
1090 if (IsDynamicTensor(outputInfo))
1091 {
1092 return Fail("%s: Dynamic output tensors are not supported", __func__);
1093 }
1094
1095 // Determine data type of input tensor
1096 OperandType inputType;
1097 if (!GetOperandType<hal_1_2::HalPolicy>(operation, 0, model, inputType))
1098 {
1099 return Fail("%s: Operation has invalid inputs", __func__);
1100 }
1101
1102 LogSoftmaxDescriptor descriptor;
1103
1104 // Read beta
1105 if (inputType == OperandType::TENSOR_FLOAT16)
1106 {
1107 Half fp16Beta;
1108 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 1, OperandType::FLOAT16, fp16Beta, model, data))
1109 {
1110 return Fail("%s: Failed to read input 1 (FLOAT16)", __func__);
1111 }
1112
1113 descriptor.m_Beta = static_cast<float>(fp16Beta);
1114 }
1115 else if (inputType == OperandType::TENSOR_FLOAT32)
1116 {
1117 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 1, OperandType::FLOAT32, descriptor.m_Beta, model, data))
1118 {
1119 return Fail("%s: Failed to read input 1 (FLOAT32)", __func__);
1120 }
1121 }
1122 else
1123 {
1124 return Fail("%s: Unsupported input tensor type: %d", __func__, inputType);
1125 }
1126
1127 // Read axis
1128 if (!GetInputInt32<hal_1_2::HalPolicy>(operation, 2, descriptor.m_Axis, model, data))
1129 {
1130 return Fail("%s: Failed to read input 2", __func__);
1131 }
1132
1133 bool isSupported = false;
1134 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1135 IsLogSoftmaxSupported,
1136 data.m_Backends,
1137 isSupported,
1138 input.GetTensorInfo(),
1139 outputInfo,
1140 descriptor);
1141 if (!isSupported)
1142 {
1143 return false;
1144 }
1145
Aron Virginas-Tar3e0982b2019-10-29 14:25:09 +00001146 IConnectableLayer* layer = data.m_Network->AddLogSoftmaxLayer(descriptor);
Aron Virginas-Tar75e67792019-10-15 13:33:03 +01001147 if (!layer)
1148 {
1149 return Fail("%s: AddLogSoftmaxLayer() returned nullptr", __func__);
1150 }
1151
1152 input.Connect(layer->GetInputSlot(0));
1153
1154 return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data);
1155}
1156
Sadik Armagan15d63e22019-07-26 16:59:35 +01001157bool HalPolicy::ConvertMaxPool2d(const Operation& operation, const Model& model, ConversionData& data)
1158{
1159 ALOGV("hal_1_2::HalPolicy::ConvertMaxPool2d()");
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001160 return ConvertPooling2d<hal_1_2::HalPolicy>(operation, __func__, PoolingAlgorithm::Max, model, data);
Sadik Armagan15d63e22019-07-26 16:59:35 +01001161}
1162
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +01001163bool HalPolicy::ConvertMaximum(const Operation& operation, const Model& model, ConversionData& data)
1164{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001165 ALOGV("hal_1_2::HalPolicy::ConvertMaximum()");
1166
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +01001167 LayerInputHandle input0 = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
1168 LayerInputHandle input1 = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 1, model, data);
1169
1170 if (!input0.IsValid() || !input1.IsValid())
1171 {
1172 return Fail("%s: Operation has invalid inputs", __func__);
1173 }
1174
1175 const Operand* outputOperand = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1176 if (!outputOperand)
1177 {
1178 return Fail("%s: Could not read output", __func__);
1179 }
1180
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001181 const TensorInfo& outInfo = GetTensorInfoForOperand(*outputOperand);
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +01001182 if (IsDynamicTensor(outInfo))
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +01001183 {
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001184 return Fail("%s: Dynamic output tensors are not supported", __func__);
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +01001185 }
1186
Aron Virginas-Tard7593232019-07-16 13:17:06 +01001187 bool isSupported = false;
1188 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1189 IsMaximumSupported,
1190 data.m_Backends,
1191 isSupported,
1192 input0.GetTensorInfo(),
1193 input1.GetTensorInfo(),
1194 outInfo);
1195
1196 if (!isSupported)
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +01001197 {
1198 return false;
1199 }
1200
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001201 IConnectableLayer* layer = data.m_Network->AddMaximumLayer();
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +01001202 assert(layer != nullptr);
Sadik Armagan64b19b52019-08-19 09:49:58 +01001203 bool isReshapeSupported = BroadcastTensor(input0, input1, layer, data);
1204 if (!isReshapeSupported)
1205 {
1206 return false;
1207 }
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +01001208
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001209 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +01001210}
1211
Mike Kelly46272802019-08-14 17:00:48 +01001212bool HalPolicy::ConvertMean(const Operation& operation, const Model& model, ConversionData& data)
1213{
1214 ALOGV("hal_1_2::HalPolicy::ConvertMean()");
1215 return ::ConvertMean<hal_1_2::HalPolicy>(operation, model, data);
1216}
1217
Ellen Norris-Thompson1cb29aa2019-07-11 17:27:37 +01001218bool HalPolicy::ConvertMinimum(const Operation& operation, const Model& model, ConversionData& data)
1219{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001220 ALOGV("hal_1_2::HalPolicy::ConvertMinimum()");
1221
Ellen Norris-Thompson1cb29aa2019-07-11 17:27:37 +01001222 LayerInputHandle input0 = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
1223 LayerInputHandle input1 = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 1, model, data);
1224
1225 if (!input0.IsValid() || !input1.IsValid())
1226 {
1227 return Fail("%s: Operation has invalid inputs", __func__);
1228 }
1229
1230 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1231 if (!output)
1232 {
1233 return Fail("%s: Could not read output 0", __func__);
1234 }
1235
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001236 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +01001237 if (IsDynamicTensor(outputInfo))
Ellen Norris-Thompson1cb29aa2019-07-11 17:27:37 +01001238 {
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001239 return Fail("%s: Dynamic output tensors are not supported", __func__);
Ellen Norris-Thompson1cb29aa2019-07-11 17:27:37 +01001240 }
1241
1242 bool isSupported = false;
1243 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1244 IsMinimumSupported,
1245 data.m_Backends,
1246 isSupported,
1247 input0.GetTensorInfo(),
1248 input1.GetTensorInfo(),
1249 outputInfo);
1250
1251 if (!isSupported)
1252 {
1253 return false;
1254 }
1255
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001256 IConnectableLayer* const layer = data.m_Network->AddMinimumLayer();
Ellen Norris-Thompson1cb29aa2019-07-11 17:27:37 +01001257 assert(layer != nullptr);
Sadik Armagan64b19b52019-08-19 09:49:58 +01001258 bool isReshapeSupported = BroadcastTensor(input0, input1, layer, data);
1259 if (!isReshapeSupported)
1260 {
1261 return false;
1262 }
Ellen Norris-Thompson1cb29aa2019-07-11 17:27:37 +01001263
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001264 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
Ellen Norris-Thompson1cb29aa2019-07-11 17:27:37 +01001265}
1266
Mike Kelly46272802019-08-14 17:00:48 +01001267bool HalPolicy::ConvertMul(const Operation& operation, const Model& model, ConversionData& data)
1268{
1269 ALOGV("hal_1_2::HalPolicy::ConvertMul()");
1270 return ::ConvertMul<hal_1_2::HalPolicy>(operation, model, data);
1271}
1272
Aron Virginas-Tarc921f6b2019-07-25 10:14:33 +01001273bool HalPolicy::ConvertPad(const Operation& operation, const Model& model, ConversionData& data)
1274{
1275 ALOGV("hal_1_2::HalPolicy::ConvertPad()");
1276 return ::ConvertPad<hal_1_2::HalPolicy>(operation, model, data);
1277}
1278
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001279bool HalPolicy::ConvertPadV2(const Operation& operation, const Model& model, ConversionData& data)
1280{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001281 ALOGV("hal_1_2::HalPolicy::ConvertPadV2()");
1282
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001283 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
1284 if (!input.IsValid())
1285 {
1286 return Fail("%s: Could not read input 0", __func__);
1287 }
1288
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +01001289 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1290 if (!output)
1291 {
1292 return Fail("%s: Could not read output", __func__);
1293 }
1294
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001295 const TensorInfo& inputInfo = input.GetTensorInfo();
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001296 unsigned int rank = inputInfo.GetNumDimensions();
1297
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001298 PadDescriptor descriptor;
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001299 if (!ConvertPaddings<hal_1_2::HalPolicy>(operation, model, data, rank, descriptor))
1300 {
1301 return Fail("%s: Could not convert paddings", __func__);
1302 }
1303
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001304 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +01001305 if (IsDynamicTensor(outputInfo))
Sadik Armagan310d8ff2019-07-11 10:53:38 +01001306 {
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001307 return Fail("%s: Dynamic output tensors are not supported", __func__);
Sadik Armagan310d8ff2019-07-11 10:53:38 +01001308 }
1309
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001310 // Determine type of padding value
1311 OperandType operandType0;
1312 OperandType operandType2;
1313
1314 if (!GetOperandType<hal_1_2::HalPolicy>(operation, 0, model, operandType0) ||
1315 !GetOperandType<hal_1_2::HalPolicy>(operation, 2, model, operandType2))
1316 {
1317 return Fail("%s: Operation has invalid inputs", __func__);
1318 }
1319
1320 // Read value to use for padding
1321 if (operandType0 == OperandType::TENSOR_FLOAT16 && operandType2 == OperandType::FLOAT16)
1322 {
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001323 Half f16PadValue;
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001324 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 2, operandType2, f16PadValue, model, data))
1325 {
1326 return Fail("%s: Could not read input 2 (FLOAT16)", __func__);
1327 }
1328
1329 descriptor.m_PadValue = f16PadValue;
1330 }
1331 else if (operandType0 == OperandType::TENSOR_FLOAT32 && operandType2 == OperandType::FLOAT32)
1332 {
1333 if (!GetInputFloat32<hal_1_2::HalPolicy>(operation, 2, descriptor.m_PadValue, model, data))
1334 {
1335 return Fail("%s: Could not read input 2 (FLOAT32)", __func__);
1336 }
1337 }
1338 else if (operandType0 == OperandType::TENSOR_QUANT8_ASYMM && operandType2 == OperandType::INT32)
1339 {
Mike Kelly3c673942019-07-25 09:26:06 +01001340 int32_t intPadValue = 0;
1341 if (!GetInputInt32<hal_1_2::HalPolicy>(operation, 2, intPadValue, model, data))
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001342 {
1343 return Fail("%s: Could not read input 2 (INT32)", __func__);
1344 }
Mike Kelly3c673942019-07-25 09:26:06 +01001345 descriptor.m_PadValue = intPadValue;
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001346 }
1347 else
1348 {
1349 return Fail("%s: Operation has invalid inputs: type mismatch", __func__);
1350 }
1351
Ferran Balaguerd30093c2019-07-09 17:04:47 +01001352 bool isSupported = false;
1353 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1354 IsPadSupported,
1355 data.m_Backends,
1356 isSupported,
1357 inputInfo,
1358 outputInfo,
1359 descriptor);
1360 if (!isSupported)
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001361 {
1362 return false;
1363 }
1364
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001365 IConnectableLayer* const layer = data.m_Network->AddPadLayer(descriptor);
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001366 assert(layer != nullptr);
1367 input.Connect(layer->GetInputSlot(0));
1368 layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1369
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001370 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001371}
1372
Matteo Martincigh17ffff32019-06-27 14:12:55 +01001373bool HalPolicy::ConvertPrelu(const Operation& operation, const Model& model, ConversionData& data)
1374{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001375 ALOGV("hal_1_2::HalPolicy::ConvertPrelu()");
1376
Matteo Martincigh17ffff32019-06-27 14:12:55 +01001377 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
1378 LayerInputHandle alpha = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 1, model, data);
1379
1380 if (!input.IsValid() || !alpha.IsValid())
1381 {
1382 return Fail("%s: Operation has invalid inputs", __func__);
1383 }
1384
1385 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1386
1387 if (!output)
1388 {
Matteo Martincigh0bd89a82019-07-02 16:53:10 +01001389 return Fail("%s: Could not read output", __func__);
Matteo Martincigh17ffff32019-06-27 14:12:55 +01001390 }
1391
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001392 const TensorInfo& inputInfo = input.GetTensorInfo();
1393 const TensorInfo& alphaInfo = alpha.GetTensorInfo();
1394 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tarf03fcf02019-07-09 17:44:24 +01001395
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +01001396 if (IsDynamicTensor(outputInfo))
Aron Virginas-Tarf03fcf02019-07-09 17:44:24 +01001397 {
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001398 return Fail("%s: Dynamic output tensors are not supported", __func__);
Aron Virginas-Tarf03fcf02019-07-09 17:44:24 +01001399 }
Matteo Martincigh17ffff32019-06-27 14:12:55 +01001400
Ferran Balaguerd30093c2019-07-09 17:04:47 +01001401 bool isSupported = false;
1402 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1403 IsPreluSupported,
1404 data.m_Backends,
1405 isSupported,
1406 inputInfo,
1407 alphaInfo,
1408 outputInfo);
1409 if (!isSupported)
Matteo Martincigh17ffff32019-06-27 14:12:55 +01001410 {
1411 return false;
1412 }
1413
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001414 IConnectableLayer* const layer = data.m_Network->AddPreluLayer();
Matteo Martincigh17ffff32019-06-27 14:12:55 +01001415
1416 if (!layer)
1417 {
1418 return Fail("%s: AddPreluLayer failed", __func__);
1419 }
1420
Sadik Armagan64b19b52019-08-19 09:49:58 +01001421 bool isReshapeSupported = BroadcastTensor(input, alpha, layer, data);
1422 if (!isReshapeSupported)
1423 {
1424 return false;
1425 }
Matteo Martincigh17ffff32019-06-27 14:12:55 +01001426
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001427 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
Matteo Martincigh17ffff32019-06-27 14:12:55 +01001428}
1429
Sadik Armagan5a476a82019-07-30 09:43:18 +01001430bool HalPolicy::ConvertQuantize(const Operation& operation, const Model& model, ConversionData& data)
1431{
1432 ALOGV("hal_1_2::HalPolicy::ConvertQuantize()");
1433
1434 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
1435 if (!input.IsValid())
1436 {
1437 return Fail("%s: Operation has invalid input", __func__);
1438 }
1439
1440 const Operand* const outputOperand = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1441 if (!outputOperand)
1442 {
1443 return Fail("%s: Operation has invalid outputs", __func__);
1444 }
1445
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001446 const TensorInfo& outputInfo = GetTensorInfoForOperand(*outputOperand);
Sadik Armagan5a476a82019-07-30 09:43:18 +01001447 if (IsDynamicTensor(outputInfo))
1448 {
1449 return Fail("%s: Dynamic output tensors are not supported", __func__);
1450 }
1451
1452 bool isSupported = false;
1453 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1454 IsQuantizeSupported,
1455 data.m_Backends,
1456 isSupported,
1457 input.GetTensorInfo(),
1458 outputInfo);
1459 if (!isSupported)
1460 {
1461 return false;
1462 }
1463
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001464 IConnectableLayer* const layer = data.m_Network->AddQuantizeLayer();
Sadik Armagan5a476a82019-07-30 09:43:18 +01001465 assert(layer != nullptr);
1466 input.Connect(layer->GetInputSlot(0));
1467
1468 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
1469}
1470
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001471bool HalPolicy::ConvertQuantizedLstm(const Operation& operation, const Model& model, ConversionData& data)
1472{
1473 ALOGV("hal_1_2::HalPolicy::ConvertQuantizedLstm()");
1474
1475 //Inputs:
1476 // 0: The input: A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape [numBatches, inputSize]
1477 // specifying the input to the LSTM cell. Tensor is quantized with a fixed quantization range of -1, 127/128.
1478 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
1479 if (!input.IsValid())
1480 {
1481 return Fail("%s: Could not read input 0: input", __func__);
1482 }
1483
1484 //13: The previous cell state: A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT16_SYMM and shape
1485 // [numBatches, outputSize] specifying the cell state from the previous time step of the LSTM cell.
1486 // It is quantized using a quantization range of -2^4, 2^4 * 32767/32768.
1487 LayerInputHandle previousCellStateIn = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 13, model, data);
1488 if (!previousCellStateIn.IsValid())
1489 {
1490 return Fail("%s: Could not read input 13: previousCellStateIn", __func__);
1491 }
1492
1493 // 14: The previous output state: A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape
1494 // [numBathes, outputSize] specifying the output of the LSTM cell from previous time-step. Tensor
1495 // is quantized with a fixed quantization range of -1, 127/128.
1496 LayerInputHandle previousOutputIn = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 14, model, data);
1497 if (!previousOutputIn.IsValid())
1498 {
1499 return Fail("%s: Could not read input 14: previousOutputIn", __func__);
1500 }
1501
1502 // Get the input tensors:
1503 // 1: The input-to-input weights. A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape
1504 // [outputSize, inputSize] specifying input-to-input part of weights for fully-connected layer inside the
1505 // LSTM cell. Quantization zero point and scale must be the same across all the weights.
1506 const ConstTensorPin inputToInputWeightsPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001507 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 1, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001508
1509 // 2: The input-to-forget weights. A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape
1510 // [outputSize, inputSize] specifying input-to-forget part of weights for fully-connected layer inside the
1511 // LSTM cell. Quantization zero point and scale must be the same across all the weights.
1512 const ConstTensorPin inputToForgetWeightsPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001513 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 2, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001514
1515 // 3: The input-to-cell weights. A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape
1516 // [outputSize, inputSize] specifying input-to-cell part of weights for fully-connected layer inside the
1517 // LSTM cell. Quantization zero point and scale must be the same across all the weights.
1518 const ConstTensorPin inputToCellWeightsPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001519 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 3, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001520
1521 // 4: The input-to-output weights. A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape
1522 // [outputSize, inputSize] specifying input-to-output part of weights for fully-connected layer inside the
1523 // LSTM cell. Quantization zero point and scale must be the same across all the weights.
1524 const ConstTensorPin inputToOutputWeightsPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001525 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 4, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001526
1527 // 5: The recurrent-to-input weights. A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape
1528 // [outputSize, outputSize] specifying recurrent-to-input part of weights for fully-connected layer inside
1529 // the LSTM cell. Quantization zero point and scale must be the same across all the weights.
1530 const ConstTensorPin recurrentToInputWeightsPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001531 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 5, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001532
1533 // 6: The recurrent-to-forget weights. A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape
1534 // [outputSize, outputSize] specifying recurrent-to-forget part of weights for fully-connected layer inside
1535 // the LSTM cell. Quantization zero point and scale must be the same across all the weights.
1536 const ConstTensorPin recurrentToForgetWeightsPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001537 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 6, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001538
1539 // 7: The recurrent-to-cell weights. A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape
1540 // [outputSize, outputSize] specifying recurrent-to-cell part of weights for fully-connected layer inside
1541 // the LSTM cell. Quantization zero point and scale must be the same across all the weights.
1542 const ConstTensorPin recurrentToCellWeightsPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001543 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 7, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001544
1545 // 8: The recurrent-to-output weights. A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape
1546 // [outputSize, outputSize] specifying recurrent-to-output part of weights for fully-connected layer inside
1547 // the LSTM cell. Quantization zero point and scale must be the same across all the weights.
1548 const ConstTensorPin recurrentToOutputWeightsPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001549 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 8, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001550
1551 // 9: The input gate bias. A 1-D tensor of type ANEURALNETWORKS_TENSOR_INT32 and shape [outputSize] specifying the
1552 // bias for the fully-connected layer inside the LSTM cell. Bias is quantized with scale being a product
1553 // of input and weights scales and zeroPoint equal to 0.
1554 const ConstTensorPin inputGateBiasPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001555 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 9, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001556
1557 // 10: The forget gate bias. A 1-D tensor of type ANEURALNETWORKS_TENSOR_INT32 and shape [outputSize] specifying
1558 // the bias for the fully-connected layer inside the LSTM cell. Bias is quantized with scale being a product
1559 // of input and weights scales and zeroPoint equal to 0.
1560 const ConstTensorPin forgetGateBiasPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001561 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 10, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001562
1563 // 11:The cell bias. A 1-D tensor of type ANEURALNETWORKS_TENSOR_INT32 and shape [outputSize] specifying the bias
1564 // for the fully-connected layer inside the LSTM cell. Bias is quantized with scale being a product of input
1565 // and weights scales and zeroPoint equal to 0.
1566 const ConstTensorPin cellBiasPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001567 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 11, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001568
1569 // 12:The output gate bias. A 1-D tensor of type ANEURALNETWORKS_TENSOR_INT32 and shape [outputSize] specifying
1570 // the bias for the fully-connected layer inside the LSTM cell. Bias is quantized with scale being a product
1571 // of input and weights scales and zeroPoint equal to 0.
1572 const ConstTensorPin outputGateBiasPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001573 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 12, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001574
1575 if (!inputToInputWeightsPin.IsValid() ||
1576 !inputToForgetWeightsPin.IsValid() ||
1577 !inputToCellWeightsPin.IsValid() ||
1578 !inputToOutputWeightsPin.IsValid() ||
1579 !recurrentToInputWeightsPin.IsValid() ||
1580 !recurrentToForgetWeightsPin.IsValid() ||
1581 !recurrentToCellWeightsPin.IsValid() ||
1582 !recurrentToOutputWeightsPin.IsValid() ||
1583 !inputGateBiasPin.IsValid() ||
1584 !forgetGateBiasPin.IsValid() ||
1585 !cellBiasPin.IsValid() ||
1586 !outputGateBiasPin.IsValid())
1587 {
1588 return Fail("%s: Operation has invalid tensor inputs", __func__);
1589 }
1590
1591 // Outputs:
1592 // 0: The cell state: A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT16_SYMM and shape [numBatches, outputSize]
1593 // which contains a cell state from the current time step. Tensor is quantized using a quantization range
1594 // of -2^4, 2^4 * 32767/32768.
1595 const Operand* cellStateOut = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1596 if (!cellStateOut)
1597 {
1598 return Fail("%s: Could not read output 0: cellStateOut", __func__);
1599 }
1600
1601 // 1: The output: A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape [numBathes, outputSize] which
1602 // contains the output value. Tensor is quantized with a fixed quantization range of -1, 127/128.
1603 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 1, model);
1604 if (!output)
1605 {
1606 return Fail("%s: Could not read output 1: output", __func__);
1607 }
1608
1609 // Inputs
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001610 const TensorInfo& inputInfo = input.GetTensorInfo();
1611 const TensorInfo& previousCellStateInInfo = previousCellStateIn.GetTensorInfo();
1612 const TensorInfo& previousOutputInInfo = previousOutputIn.GetTensorInfo();
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001613
1614 // Outputs
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001615 const TensorInfo& cellStateOutInfo = GetTensorInfoForOperand(*cellStateOut);
1616 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001617
1618 // Dynamic tensors currently not supported
1619 if (IsDynamicTensor(cellStateOutInfo) || IsDynamicTensor(outputInfo))
1620 {
1621 return Fail("%s: Dynamic output tensors are not supported", __func__);
1622 }
1623
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001624 QuantizedLstmInputParams params;
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001625
1626 params.m_InputToInputWeights = inputToInputWeightsPin.GetConstTensorPtr();
1627 params.m_InputToForgetWeights = inputToForgetWeightsPin.GetConstTensorPtr();
1628 params.m_InputToCellWeights = inputToCellWeightsPin.GetConstTensorPtr();
1629 params.m_InputToOutputWeights = inputToOutputWeightsPin.GetConstTensorPtr();
1630 params.m_RecurrentToInputWeights = recurrentToInputWeightsPin.GetConstTensorPtr();
1631 params.m_RecurrentToForgetWeights = recurrentToForgetWeightsPin.GetConstTensorPtr();
1632 params.m_RecurrentToCellWeights = recurrentToCellWeightsPin.GetConstTensorPtr();
1633 params.m_RecurrentToOutputWeights = recurrentToOutputWeightsPin.GetConstTensorPtr();
1634 params.m_InputGateBias = inputGateBiasPin.GetConstTensorPtr();
1635 params.m_ForgetGateBias = forgetGateBiasPin.GetConstTensorPtr();
1636 params.m_CellBias = cellBiasPin.GetConstTensorPtr();
1637 params.m_OutputGateBias = outputGateBiasPin.GetConstTensorPtr();
1638
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001639 QuantizedLstmInputParamsInfo paramsInfo;
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001640 paramsInfo.m_InputToInputWeights = &(params.m_InputToInputWeights->GetInfo());
1641 paramsInfo.m_InputToForgetWeights = &(params.m_InputToForgetWeights->GetInfo());
1642 paramsInfo.m_InputToCellWeights = &(params.m_InputToCellWeights->GetInfo());
1643 paramsInfo.m_InputToOutputWeights = &(params.m_InputToOutputWeights->GetInfo());
1644 paramsInfo.m_RecurrentToInputWeights = &(params.m_RecurrentToInputWeights->GetInfo());
1645 paramsInfo.m_RecurrentToForgetWeights = &(params.m_RecurrentToForgetWeights->GetInfo());
1646 paramsInfo.m_RecurrentToCellWeights = &(params.m_RecurrentToCellWeights->GetInfo());
1647 paramsInfo.m_RecurrentToOutputWeights = &(params.m_RecurrentToOutputWeights->GetInfo());
1648 paramsInfo.m_InputGateBias = &(params.m_InputGateBias->GetInfo());
1649 paramsInfo.m_ForgetGateBias = &(params.m_ForgetGateBias->GetInfo());
1650 paramsInfo.m_CellBias = &(params.m_CellBias->GetInfo());
1651 paramsInfo.m_OutputGateBias = &(params.m_OutputGateBias->GetInfo());
1652
1653 bool isSupported = false;
1654 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1655 IsQuantizedLstmSupported,
1656 data.m_Backends,
1657 isSupported,
1658 inputInfo,
1659 previousCellStateInInfo,
1660 previousOutputInInfo,
1661 cellStateOutInfo,
1662 outputInfo,
1663 paramsInfo);
1664
1665 if (!isSupported)
1666 {
1667 return false;
1668 }
1669
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001670 IConnectableLayer* const layer = data.m_Network->AddQuantizedLstmLayer(params, "QuantizedLstm");
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001671 input.Connect(layer->GetInputSlot(0));
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001672 previousCellStateIn.Connect(layer->GetInputSlot(1));
1673 previousOutputIn.Connect(layer->GetInputSlot(2));
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001674
1675 return (SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, 0, model, data) &&
1676 SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 1, *layer, 1, model, data));
1677}
1678
Sadik Armagan61113162019-07-25 09:09:40 +01001679bool HalPolicy::ConvertReLu(const Operation& operation, const Model& model, ConversionData& data)
1680{
1681 ALOGV("hal_1_2::HalPolicy::ConvertReLu()");
1682 return ::ConvertReLu<hal_1_2::HalPolicy>(operation, model, data);
1683}
1684
1685bool HalPolicy::ConvertReLu1(const Operation& operation, const Model& model, ConversionData& data)
1686{
1687 ALOGV("hal_1_2::HalPolicy::ConvertReLu1()");
1688 return ::ConvertReLu1<hal_1_2::HalPolicy>(operation, model, data);
1689}
1690
1691bool HalPolicy::ConvertReLu6(const Operation& operation, const Model& model, ConversionData& data)
1692{
1693 ALOGV("hal_1_2::HalPolicy::ConvertReLu6()");
1694 return ::ConvertReLu6<hal_1_2::HalPolicy>(operation, model, data);
1695}
1696
Mike Kelly46272802019-08-14 17:00:48 +01001697bool HalPolicy::ConvertReshape(const Operation& operation, const Model& model, ConversionData& data)
1698{
1699 ALOGV("hal_1_2::HalPolicy::ConvertReshape()");
1700 return ::ConvertReshape<hal_1_2::HalPolicy>(operation, model, data);
1701}
1702
Aron Virginas-Tarfb2fa292019-07-04 11:59:48 +01001703bool HalPolicy::ConvertResize(const Operation& operation,
1704 const Model& model,
1705 ConversionData& data,
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001706 ResizeMethod resizeMethod)
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +01001707{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001708 ALOGV("hal_1_2::HalPolicy::ConvertResize()");
Aron Virginas-Tar7d2ccfd2019-10-29 14:03:51 +00001709 ALOGV("resizeMethod = %s", GetResizeMethodAsCString(resizeMethod));
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001710
1711 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +01001712 if (!input.IsValid())
1713 {
1714 return Fail("%s: Could not read input 0", __func__);
1715 }
1716
1717 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1718 if (!output)
1719 {
1720 return Fail("%s: Could not read output 0", __func__);
1721 }
1722
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001723 const TensorInfo& inputInfo = input.GetTensorInfo();
1724 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001725
1726 if (IsDynamicTensor(outputInfo))
1727 {
1728 return Fail("%s: Dynamic output tensors are not supported", __func__);
1729 }
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +01001730
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001731 ResizeDescriptor descriptor;
Aron Virginas-Tarfb2fa292019-07-04 11:59:48 +01001732 descriptor.m_Method = resizeMethod;
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +01001733 descriptor.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 3, model, data);
1734
1735 OperandType operandType1;
1736 OperandType operandType2;
1737
1738 if (!GetOperandType<hal_1_2::HalPolicy>(operation, 1, model, operandType1) ||
1739 !GetOperandType<hal_1_2::HalPolicy>(operation, 2, model, operandType2))
1740 {
1741 return Fail("%s: Operation has invalid inputs", __func__);
1742 }
1743
1744 if (operandType1 != operandType2)
1745 {
1746 return Fail("%s: Operation has invalid inputs. Type of input 1 and 2 should be the same", __func__);
1747 }
1748
1749 if (operandType1 == OperandType::INT32)
1750 {
1751 // Case 1: resizing by shape
1752 int32_t targetWidth = 0;
1753 int32_t targetHeight = 0;
1754
1755 if (!GetInputInt32<hal_1_2::HalPolicy>(operation, 1, targetWidth, model, data) ||
1756 !GetInputInt32<hal_1_2::HalPolicy>(operation, 2, targetHeight, model, data))
1757 {
1758 return Fail("%s: Operation has invalid inputs for resizing by shape", __func__);
1759 }
1760
1761 if (targetWidth < 0 || targetHeight < 0)
1762 {
1763 return Fail("%s: Operation has invalid inputs for resizing by shape. "
1764 "Target width/height cannot be < 0", __func__);
1765 }
1766
1767 descriptor.m_TargetWidth = static_cast<uint32_t>(targetWidth);
Teresa Charlin9843c012019-07-19 12:18:35 +01001768 descriptor.m_TargetHeight = static_cast<uint32_t>(targetHeight);
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +01001769 }
1770 else if (operandType1 == OperandType::FLOAT32)
1771 {
1772 // Case 2: resizing by scale
1773 float widthScale = 1.0f;
1774 float heightScale = 1.0f;
1775
1776 if (!GetInputFloat32<hal_1_2::HalPolicy>(operation, 1, widthScale, model, data) ||
1777 !GetInputFloat32<hal_1_2::HalPolicy>(operation, 2, heightScale, model, data))
1778 {
1779 return Fail("%s: Operation has invalid inputs for resizing by scale", __func__);
1780 }
1781
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001782 const TensorShape& inputShape = inputInfo.GetShape();
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +01001783 armnnUtils::DataLayoutIndexed dataLayoutIndexed(descriptor.m_DataLayout);
1784
1785 float width = inputShape[dataLayoutIndexed.GetWidthIndex()];
1786 float height = inputShape[dataLayoutIndexed.GetHeightIndex()];
1787
1788 descriptor.m_TargetWidth = std::floor(width * widthScale);
1789 descriptor.m_TargetHeight = std::floor(height * heightScale);
1790 }
1791 else
1792 {
1793 // NOTE: FLOAT16 scales are not supported
1794 return false;
1795 }
1796
Ferran Balaguerd30093c2019-07-09 17:04:47 +01001797 bool isSupported = false;
1798 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1799 IsResizeSupported,
1800 data.m_Backends,
1801 isSupported,
1802 inputInfo,
1803 outputInfo,
1804 descriptor);
Aron Virginas-Tarbe5d3562019-07-16 11:32:29 +01001805
Ferran Balaguerd30093c2019-07-09 17:04:47 +01001806 if (!isSupported)
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +01001807 {
1808 return false;
1809 }
1810
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001811 IConnectableLayer* layer = data.m_Network->AddResizeLayer(descriptor);
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +01001812
1813 assert(layer != nullptr);
1814
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +01001815 input.Connect(layer->GetInputSlot(0));
1816
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001817 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +01001818}
1819
Aron Virginas-Tarfa6544e2019-09-10 14:42:22 +01001820bool HalPolicy::ConvertRsqrt(const Operation& operation, const Model& model, ConversionData& data)
1821{
1822 ALOGV("hal_1_2::HalPolicy::ConvertRsqrt()");
1823
1824 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
1825 if (!input.IsValid())
1826 {
1827 return Fail("%s: Operation has invalid input", __func__);
1828 }
1829
1830 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1831 if (!output)
1832 {
1833 return Fail("%s: Could not read output 0", __func__);
1834 }
1835
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001836 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tarfa6544e2019-09-10 14:42:22 +01001837 if (IsDynamicTensor(outputInfo))
1838 {
1839 return Fail("%s: Dynamic output tensors are not supported", __func__);
1840 }
1841
1842 bool isSupported = false;
1843 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1844 IsRsqrtSupported,
1845 data.m_Backends,
1846 isSupported,
1847 input.GetTensorInfo(),
1848 outputInfo);
1849
1850 if (!isSupported)
1851 {
1852 return false;
1853 }
1854
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001855 IConnectableLayer* const layer = data.m_Network->AddRsqrtLayer();
Aron Virginas-Tarfa6544e2019-09-10 14:42:22 +01001856 assert(layer != nullptr);
1857 input.Connect(layer->GetInputSlot(0));
1858
1859 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
1860}
1861
Finn Williamsd74c5052019-07-30 17:06:00 +01001862bool HalPolicy::ConvertSpaceToBatchNd(const Operation& operation, const Model& model, ConversionData& data)
1863{
1864 ALOGV("hal_1_2::HalPolicy::ConvertSpaceToBatchNd()");
1865 return ::ConvertSpaceToBatchNd<hal_1_2::HalPolicy>(operation, model, data);
1866}
1867
Keith Davisa6bc52f2019-06-26 09:39:49 +01001868bool HalPolicy::ConvertSpaceToDepth(const Operation& operation, const Model& model, ConversionData& data)
1869{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001870 ALOGV("hal_1_2::HalPolicy::ConvertSpaceToDepth()");
Keith Davisa6bc52f2019-06-26 09:39:49 +01001871
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001872 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
Keith Davisa6bc52f2019-06-26 09:39:49 +01001873 if (!input.IsValid() )
1874 {
1875 return Fail("%s: Operation has invalid inputs", __func__);
1876 }
1877
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001878 const TensorInfo& inputInfo = input.GetTensorInfo();
Keith Davisa6bc52f2019-06-26 09:39:49 +01001879 unsigned int rank = inputInfo.GetNumDimensions();
Keith Davisa6bc52f2019-06-26 09:39:49 +01001880 if (rank != 4)
1881 {
1882 return Fail("%s: Only inputs with rank 4 are supported", __func__);
1883 }
1884
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001885 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1886 if (!output)
1887 {
1888 return Fail("%s: Could not read output 0", __func__);
1889 }
1890
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001891 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001892 if (IsDynamicTensor(outputInfo))
1893 {
1894 return Fail("%s: Dynamic output tensors are not supported", __func__);
1895 }
1896
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001897 SpaceToDepthDescriptor desc;
Keith Davisa6bc52f2019-06-26 09:39:49 +01001898
1899 GetInputScalar<hal_1_2::HalPolicy>(operation, 1, OperandType::INT32, desc.m_BlockSize, model, data);
1900
1901 if (desc.m_BlockSize <= 1)
1902 {
1903 return Fail("%s: Block size must be at least 1 in all dimensions");
1904 }
1905
1906 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 2, model, data);
1907
Ferran Balaguerd30093c2019-07-09 17:04:47 +01001908 bool isSupported = false;
1909 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1910 IsSpaceToDepthSupported,
1911 data.m_Backends,
1912 isSupported,
1913 inputInfo,
1914 outputInfo,
1915 desc);
1916 if (!isSupported)
Keith Davisa6bc52f2019-06-26 09:39:49 +01001917 {
1918 return false;
1919 }
1920
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001921 IConnectableLayer* const layer = data.m_Network->AddSpaceToDepthLayer(desc);
Keith Davisa6bc52f2019-06-26 09:39:49 +01001922 assert(layer != nullptr);
1923 input.Connect(layer->GetInputSlot(0));
1924
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001925 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
Keith Davisa6bc52f2019-06-26 09:39:49 +01001926}
1927
Francis Murtagh074c25a2019-07-22 16:40:57 +01001928bool HalPolicy::ConvertSoftmax(const Operation& operation, const Model& model, ConversionData& data)
1929{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001930 ALOGV("hal_1_2::HalPolicy::ConvertSoftmax()");
1931
Francis Murtagh074c25a2019-07-22 16:40:57 +01001932 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
1933 if (!input.IsValid())
1934 {
1935 return Fail("%s: Operation has invalid inputs", __func__);
1936 }
1937
1938 const Operand* outputOperand = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1939 if (!outputOperand)
1940 {
1941 return Fail("%s: Operation has no outputs", __func__);
1942 }
1943
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001944 const TensorInfo& outputInfo = GetTensorInfoForOperand(*outputOperand);
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +01001945 if (IsDynamicTensor(outputInfo))
Francis Murtagh074c25a2019-07-22 16:40:57 +01001946 {
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001947 return Fail("%s: Dynamic output tensors are not supported", __func__);
Francis Murtagh074c25a2019-07-22 16:40:57 +01001948 }
1949
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001950 SoftmaxDescriptor desc;
Francis Murtagh074c25a2019-07-22 16:40:57 +01001951 if (!GetInputFloat32<hal_1_2::HalPolicy>(operation, 1, desc.m_Beta, model, data))
1952 {
1953 return Fail("%s: Operation has invalid inputs", __func__);
1954 }
1955
1956 if (operation.inputs.size() > 2 && !GetInputScalar<hal_1_2::HalPolicy>(operation,
1957 2,
1958 HalPolicy::OperandType::INT32,
1959 desc.m_Axis,
1960 model,
1961 data))
1962 {
1963 return Fail("%s: Operation has invalid inputs", __func__);
1964 }
1965
Narumol Prangnawarat52dc5272019-08-06 17:34:26 +01001966 if (input.GetTensorInfo().GetNumDimensions() > 2 ||
1967 !(desc.m_Axis == 1 ||
1968 (desc.m_Axis < 0 && static_cast<int>(input.GetTensorInfo().GetNumDimensions()) + desc.m_Axis == 1)))
1969 {
1970 return Fail("%s: Unsupported input greater than 2D or axis != 1", __func__);
1971 }
1972
Francis Murtagh074c25a2019-07-22 16:40:57 +01001973 bool isSupported = false;
1974 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1975 IsSoftmaxSupported,
1976 data.m_Backends,
1977 isSupported,
1978 input.GetTensorInfo(),
1979 outputInfo,
1980 desc);
1981 if (!isSupported)
1982 {
1983 return false;
1984 }
1985
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001986 IConnectableLayer* layer = data.m_Network->AddSoftmaxLayer(desc);
Francis Murtagh074c25a2019-07-22 16:40:57 +01001987 assert(layer != nullptr);
1988 input.Connect(layer->GetInputSlot(0));
1989
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001990 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
Francis Murtagh074c25a2019-07-22 16:40:57 +01001991}
1992
Mike Kelly0a879362019-07-29 16:56:31 +01001993bool HalPolicy::ConvertSub(const Operation& operation, const Model& model, ConversionData& data)
1994{
1995 ALOGV("hal_1_2::HalPolicy::ConvertSub()");
1996 return ::ConvertSub<hal_1_2::HalPolicy>(operation, model, data);
1997}
1998
Sadik Armagan61113162019-07-25 09:09:40 +01001999bool HalPolicy::ConvertTanH(const Operation& operation, const Model& model, ConversionData& data)
2000{
2001 ALOGV("hal_1_2::HalPolicy::ConvertTanH()");
2002 return ::ConvertTanH<hal_1_2::HalPolicy>(operation, model, data);
2003}
2004
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002005bool HalPolicy::ConvertLstm(const Operation& operation, const Model& model, ConversionData& data)
2006{
2007 // Inputs:
2008 // 00: The input: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, input_size], where
2009 // “batch_size” corresponds to the batching dimension, and “input_size” is the size of the input.
2010 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
2011 if (!input.IsValid())
2012 {
2013 return Fail("%s: Could not read input 0: input", __func__);
2014 }
2015 // 18: The output state: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, output_size].
2016 LayerInputHandle outputStateIn = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 18, model, data);
2017 if (!outputStateIn.IsValid())
2018 {
2019 return Fail("%s: Could not read input 18: outputStateIn", __func__);
2020 }
2021 // 19: The cell state: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, num_units].
2022 LayerInputHandle cellStateIn = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 19, model, data);
2023 if (!cellStateIn.IsValid())
2024 {
2025 return Fail("%s: Could not read input 19: cellStateIn", __func__);
2026 }
2027
2028 // Get the mandatory input tensors:
2029 // 02: The input-to-forget weights: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
2030 // [num_units, input_size].
2031 const ConstTensorPin inputToForgetWeightsPin =
2032 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 2, model, data);
2033 // 03: The input-to-cell weights: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
2034 // [num_units, input_size].
2035 const ConstTensorPin inputToCellWeightsPin =
2036 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 3, model, data);
2037 // 04: The input-to-output weights: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
2038 // [num_units, input_size].
2039 const ConstTensorPin inputToOutputWeightsPin =
2040 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 4, model, data);
2041 // 06: The recurrent-to-forget weights: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
2042 // [num_units, output_size].
2043 const ConstTensorPin recurrentToForgetWeightsPin =
2044 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 6, model, data);
2045 // 07: The recurrent-to-cell weights: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
2046 // [num_units, output_size].
2047 const ConstTensorPin recurrentToCellWeightsPin =
2048 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 7, model, data);
2049 // 08: The recurrent-to-output weights: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
2050 // [num_units, output_size].
2051 const ConstTensorPin recurrentToOutputWeightsPin =
2052 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 8, model, data);
2053 // 13: The forget gate bias: A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
2054 const ConstTensorPin forgetGateBiasPin =
2055 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 13, model, data);
2056 // 14: The cell bias: A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
2057 const ConstTensorPin cellBiasPin =
2058 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 14, model, data);
2059 // 15: The output gate bias: A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
2060 const ConstTensorPin outputGateBiasPin =
2061 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 15, model, data);
2062
2063 if (!inputToForgetWeightsPin.IsValid() ||
2064 !inputToCellWeightsPin.IsValid() ||
2065 !inputToOutputWeightsPin.IsValid() ||
2066 !recurrentToForgetWeightsPin.IsValid() ||
2067 !recurrentToCellWeightsPin.IsValid() ||
2068 !recurrentToOutputWeightsPin.IsValid() ||
2069 !forgetGateBiasPin.IsValid() ||
2070 !cellBiasPin.IsValid() ||
2071 !outputGateBiasPin.IsValid())
2072 {
2073 return Fail("%s: Operation has invalid tensor inputs", __func__);
2074 }
2075
2076 // Get the optional input tensors:
2077 // 01: The input-to-input weights: Optional. A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
2078 // [num_units, input_size], where “num_units” corresponds to the number of cell units.
2079 const ConstTensorPin inputToInputWeightsPin =
2080 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
2081 1,
2082 model,
2083 data,
2084 g_DontPermute,
2085 nullptr,
2086 true);
2087
2088 // 05: The recurrent-to-input weights: Optional. A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
2089 // [num_units, output_size], where “output_size” corresponds to either the number of cell units (i.e.,
2090 // “num_units”), or the second dimension of the “projection_weights”, if defined.
2091 const ConstTensorPin recurrentToInputWeightsPin =
2092 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
2093 5,
2094 model,
2095 data,
2096 g_DontPermute,
2097 nullptr,
2098 true);
2099
2100 // 09: The cell-to-input weights: Optional. A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
2101 const ConstTensorPin cellToInputWeightsPin =
2102 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
2103 9,
2104 model,
2105 data,
2106 g_DontPermute,
2107 nullptr,
2108 true);
2109
2110 // 10: The cell-to-forget weights: Optional. A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
2111 const ConstTensorPin cellToForgetWeightsPin =
2112 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
2113 10,
2114 model,
2115 data,
2116 g_DontPermute,
2117 nullptr,
2118 true);
2119
2120 // 11: The cell-to-output weights: Optional. A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
2121 const ConstTensorPin cellToOutputWeightsPin =
2122 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
2123 11,
2124 model,
2125 data,
2126 g_DontPermute,
2127 nullptr,
2128 true);
2129
2130 // 12: The input gate bias: Optional. A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
2131 const ConstTensorPin inputGateBiasPin =
2132 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
2133 12,
2134 model,
2135 data,
2136 g_DontPermute,
2137 nullptr,
2138 true);
2139
2140 // 16: The projection weights: Optional. A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
2141 // [output_size, num_units].
2142 const ConstTensorPin projectionWeightsPin =
2143 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
2144 16,
2145 model,
2146 data,
2147 g_DontPermute,
2148 nullptr,
2149 true);
2150
2151 // 17: The projection bias: Optional. A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [output_size].
2152 const ConstTensorPin projectionBiasPin =
2153 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
2154 17,
2155 model,
2156 data,
2157 g_DontPermute,
2158 nullptr,
2159 true);
2160
2161 if ((!inputToInputWeightsPin.IsValid() && !inputToInputWeightsPin.IsOptional()) ||
2162 (!recurrentToInputWeightsPin.IsValid() && !recurrentToInputWeightsPin.IsOptional()) ||
2163 (!cellToInputWeightsPin.IsValid() && !cellToInputWeightsPin.IsOptional()) ||
2164 (!cellToForgetWeightsPin.IsValid() && !cellToForgetWeightsPin.IsOptional()) ||
2165 (!cellToOutputWeightsPin.IsValid() && !cellToOutputWeightsPin.IsOptional()) ||
2166 (!inputGateBiasPin.IsValid() && !inputGateBiasPin.IsOptional()) ||
2167 (!projectionWeightsPin.IsValid() && !projectionWeightsPin.IsOptional()) ||
2168 (!projectionBiasPin.IsValid() && !projectionBiasPin.IsOptional()))
2169 {
2170 return Fail("%s: Operation has invalid tensor inputs", __func__);
2171 }
2172
2173 // Get the mandatory input scalars (actually 1-D tensors of size 1):
2174 // 20: The activation function: A value indicating the activation function:
2175 // 0: None; 1: Relu; 3: Relu6; 4: Tanh; 6: Sigmoid.
2176 // 21: The clipping threshold: for the cell state, such that values are bound within [-cell_clip, cell_clip].
2177 // If set to 0.0 then clipping is disabled.
2178 // 22: The clipping threshold: for the output from the projection layer, such that values are bound within
2179 // [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled.
2180 ActivationFn activation;
2181 float cellClip;
2182 float projClip;
2183 if (!GetInputActivationFunctionFromTensor<hal_1_2::HalPolicy>(operation, 20, activation, model, data) ||
2184 !GetInputScalar<hal_1_2::HalPolicy>(operation, 21, OperandType::FLOAT32, cellClip, model, data) ||
2185 !GetInputScalar<hal_1_2::HalPolicy>(operation, 22, OperandType::FLOAT32, projClip, model, data))
2186 {
2187 return Fail("%s: Operation has invalid scalar inputs", __func__);
2188 }
2189
2190 // Get the normalization tensors
2191 // 23: The input layer normalization weights. A 1-D tensor of shape [num_units].
2192 // Used to rescale normalized inputs to activation at input gate.
2193 const ConstTensorPin inputLayerNormWeightsPin =
2194 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
2195 23,
2196 model,
2197 data,
2198 g_DontPermute,
2199 nullptr,
2200 true);
2201
2202 // 24: The forget layer normalization weights. A 1-D tensor of shape [num_units].
2203 // Used to rescale normalized inputs to activation at forget gate.
2204 const ConstTensorPin forgetLayerNormWeightsPin =
2205 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
2206 24,
2207 model,
2208 data,
2209 g_DontPermute,
2210 nullptr,
2211 true);
2212
2213 // 25: The cell layer normalization weights. A 1-D tensor of shape [num_units].
2214 // Used to rescale normalized inputs to activation at cell gate.
2215 const ConstTensorPin cellLayerNormWeightsPin =
2216 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
2217 25,
2218 model,
2219 data,
2220 g_DontPermute,
2221 nullptr,
2222 true);
2223
2224 // 26: The output layer normalization weights. A 1-D tensor of shape [num_units].
2225 // Used to rescale normalized inputs to activation at output gate.
2226 const ConstTensorPin outputLayerNormWeightsPin =
2227 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
2228 26,
2229 model,
2230 data,
2231 g_DontPermute,
2232 nullptr,
2233 true);
2234
2235 // Outputs:
2236 // 00: The scratch buffer: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, num_units * 4]
2237 // with CIFG, or [batch_size, num_units * 3] without CIFG.
2238 const Operand* scratchBuffer = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
2239 if (!scratchBuffer)
2240 {
2241 return Fail("%s: Could not read output 0: scratchBuffer", __func__);
2242 }
2243 // 01: The output state (out): A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, output_size].
2244 const Operand* outputStateOut = GetOutputOperand<hal_1_2::HalPolicy>(operation, 1, model);
2245 if (!outputStateOut)
2246 {
2247 return Fail("%s: Could not read output 1: outputStateOut", __func__);
2248 }
2249 // 02: The cell state (out): A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, num_units].
2250 const Operand* cellStateOut = GetOutputOperand<hal_1_2::HalPolicy>(operation, 2, model);
2251 if (!cellStateOut)
2252 {
2253 return Fail("%s: Could not read output 2: cellStateOut", __func__);
2254 }
2255 // 03: The output: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, output_size]. This is
2256 // effectively the same as the current “output state (out)” value.
2257 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 3, model);
2258 if (!output)
2259 {
2260 return Fail("%s: Could not read output 3: output", __func__);
2261 }
2262
2263 // set the params structure for the AddLstmLayer call
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002264 LstmInputParams params;
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002265 params.m_InputToInputWeights = inputToInputWeightsPin.GetConstTensorPtr();
2266 params.m_InputToForgetWeights = inputToForgetWeightsPin.GetConstTensorPtr();
2267 params.m_InputToCellWeights = inputToCellWeightsPin.GetConstTensorPtr();
2268 params.m_InputToOutputWeights = inputToOutputWeightsPin.GetConstTensorPtr();
2269 params.m_RecurrentToInputWeights = recurrentToInputWeightsPin.GetConstTensorPtr();
2270 params.m_RecurrentToForgetWeights = recurrentToForgetWeightsPin.GetConstTensorPtr();
2271 params.m_RecurrentToCellWeights = recurrentToCellWeightsPin.GetConstTensorPtr();
2272 params.m_RecurrentToOutputWeights = recurrentToOutputWeightsPin.GetConstTensorPtr();
2273 params.m_CellToInputWeights = cellToInputWeightsPin.GetConstTensorPtr();
2274 params.m_CellToForgetWeights = cellToForgetWeightsPin.GetConstTensorPtr();
2275 params.m_CellToOutputWeights = cellToOutputWeightsPin.GetConstTensorPtr();
2276 params.m_InputGateBias = inputGateBiasPin.GetConstTensorPtr();
2277 params.m_ForgetGateBias = forgetGateBiasPin.GetConstTensorPtr();
2278 params.m_CellBias = cellBiasPin.GetConstTensorPtr();
2279 params.m_OutputGateBias = outputGateBiasPin.GetConstTensorPtr();
2280 params.m_ProjectionWeights = projectionWeightsPin.GetConstTensorPtr();
2281 params.m_ProjectionBias = projectionBiasPin.GetConstTensorPtr();
2282 params.m_InputLayerNormWeights = inputLayerNormWeightsPin.GetConstTensorPtr();
2283 params.m_ForgetLayerNormWeights = forgetLayerNormWeightsPin.GetConstTensorPtr();
2284 params.m_CellLayerNormWeights = cellLayerNormWeightsPin.GetConstTensorPtr();
2285 params.m_OutputLayerNormWeights = outputLayerNormWeightsPin.GetConstTensorPtr();
2286
2287 // set the layer descriptor
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002288 LstmDescriptor desc;
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002289 desc.m_ActivationFunc = activation;
2290 desc.m_ClippingThresCell = cellClip;
2291 desc.m_ClippingThresProj = projClip;
2292 desc.m_CifgEnabled = (params.m_InputToInputWeights == nullptr ||
2293 params.m_RecurrentToInputWeights == nullptr ||
2294 params.m_InputGateBias == nullptr);
2295 desc.m_PeepholeEnabled = (params.m_CellToForgetWeights != nullptr ||
2296 params.m_CellToOutputWeights != nullptr);
2297 desc.m_ProjectionEnabled = (params.m_ProjectionWeights != nullptr);
2298 desc.m_LayerNormEnabled = (params.m_InputLayerNormWeights != nullptr ||
2299 params.m_ForgetLayerNormWeights != nullptr ||
2300 params.m_CellLayerNormWeights != nullptr ||
2301 params.m_OutputLayerNormWeights != nullptr);
2302
2303 // validate the optional input groups
2304 if (desc.m_CifgEnabled &&
2305 (params.m_InputToInputWeights != nullptr ||
2306 params.m_RecurrentToInputWeights != nullptr ||
2307 params.m_InputGateBias != nullptr))
2308 {
2309 return Fail("%s: All, or none, of input-to-input weights, recurrent-to-input weights,"
2310 " and input gate bias must be provided", __func__);
2311 }
2312
2313 if (!desc.m_ProjectionEnabled && params.m_ProjectionBias != nullptr)
2314 {
2315 return Fail("%s: projection bias should not be provided without projection weights", __func__);
2316 }
2317
2318 if (desc.m_PeepholeEnabled &&
2319 (params.m_CellToForgetWeights == nullptr ||
2320 params.m_CellToOutputWeights == nullptr ||
2321 (!desc.m_CifgEnabled && params.m_CellToInputWeights == nullptr)))
2322 {
2323 return Fail("%s: All, or none, of cell-to-forget weights and cell-to-output weights must be provided"
2324 " and, if CIFG is not enabled, cell-to-input weights must also be provided", __func__);
2325 }
2326
2327 if (desc.m_LayerNormEnabled &&
2328 (params.m_ForgetLayerNormWeights == nullptr ||
2329 params.m_CellLayerNormWeights == nullptr ||
2330 params.m_OutputLayerNormWeights == nullptr ||
2331 (!desc.m_CifgEnabled && params.m_InputLayerNormWeights == nullptr)))
2332 {
2333 return Fail("%s: All, or none, of forget-norm weights, cell-norm weights and output-norm weights must be"
2334 " provided and, if CIFG is not enabled, input-norm weights must also be provided", __func__);
2335 }
2336
2337 // Check if the layer is supported
2338 // Inputs
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002339 const TensorInfo& inputInfo = input.GetTensorInfo();
2340 const TensorInfo& outputStateInInfo = outputStateIn.GetTensorInfo();
2341 const TensorInfo& cellStateInInfo = cellStateIn.GetTensorInfo();
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002342
2343 // Outputs
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002344 const TensorInfo& scratchBufferInfo = GetTensorInfoForOperand(*scratchBuffer);
2345 const TensorInfo& outputStateOutInfo = GetTensorInfoForOperand(*outputStateOut);
2346 const TensorInfo& cellStateOutInfo = GetTensorInfoForOperand(*cellStateOut);
2347 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002348
Ferran Balaguera4a629a2019-07-30 10:16:13 +01002349 if (IsDynamicTensor(scratchBufferInfo) ||
2350 IsDynamicTensor(outputStateOutInfo) ||
2351 IsDynamicTensor(cellStateOutInfo) ||
2352 IsDynamicTensor(outputInfo))
2353 {
2354 return Fail("%s: Dynamic output tensors are not supported", __func__);
2355 }
2356
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002357 // Basic parameters
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002358 LstmInputParamsInfo paramsInfo;
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002359 paramsInfo.m_InputToForgetWeights = &(params.m_InputToForgetWeights->GetInfo());
2360 paramsInfo.m_InputToCellWeights = &(params.m_InputToCellWeights->GetInfo());
2361 paramsInfo.m_InputToOutputWeights = &(params.m_InputToOutputWeights->GetInfo());
2362 paramsInfo.m_RecurrentToForgetWeights = &(params.m_RecurrentToForgetWeights->GetInfo());
2363 paramsInfo.m_RecurrentToCellWeights = &(params.m_RecurrentToCellWeights->GetInfo());
2364 paramsInfo.m_RecurrentToOutputWeights = &(params.m_RecurrentToOutputWeights->GetInfo());
2365 paramsInfo.m_ForgetGateBias = &(params.m_ForgetGateBias->GetInfo());
2366 paramsInfo.m_CellBias = &(params.m_CellBias->GetInfo());
2367 paramsInfo.m_OutputGateBias = &(params.m_OutputGateBias->GetInfo());
2368
2369 // Optional parameters
2370 if(!desc.m_CifgEnabled)
2371 {
2372 paramsInfo.m_InputToInputWeights = &(params.m_InputToInputWeights->GetInfo());
2373 paramsInfo.m_RecurrentToInputWeights = &(params.m_RecurrentToInputWeights->GetInfo());
2374 if (params.m_CellToInputWeights != nullptr)
2375 {
2376 paramsInfo.m_CellToInputWeights = &(params.m_CellToInputWeights->GetInfo());
2377 }
2378 paramsInfo.m_InputGateBias = &(params.m_InputGateBias->GetInfo());
2379 }
2380
2381 if(desc.m_ProjectionEnabled)
2382 {
2383 paramsInfo.m_ProjectionWeights = &(params.m_ProjectionWeights->GetInfo());
2384 if (params.m_ProjectionBias != nullptr)
2385 {
2386 paramsInfo.m_ProjectionBias = &(params.m_ProjectionBias->GetInfo());
2387 }
2388 }
2389
2390 if(desc.m_PeepholeEnabled)
2391 {
2392 paramsInfo.m_CellToForgetWeights = &(params.m_CellToForgetWeights->GetInfo());
2393 paramsInfo.m_CellToOutputWeights = &(params.m_CellToOutputWeights->GetInfo());
2394 }
2395
2396 if (desc.m_LayerNormEnabled)
2397 {
2398 if(!desc.m_CifgEnabled)
2399 {
2400 paramsInfo.m_InputLayerNormWeights = &(params.m_InputLayerNormWeights->GetInfo());
2401 }
2402 paramsInfo.m_ForgetLayerNormWeights = &(params.m_ForgetLayerNormWeights->GetInfo());
2403 paramsInfo.m_CellLayerNormWeights = &(params.m_CellLayerNormWeights->GetInfo());
2404 paramsInfo.m_OutputLayerNormWeights = &(params.m_OutputLayerNormWeights->GetInfo());
2405 }
2406
2407 bool isSupported = false;
2408 FORWARD_LAYER_SUPPORT_FUNC(__func__,
2409 IsLstmSupported,
2410 data.m_Backends,
2411 isSupported,
2412 inputInfo,
2413 outputStateInInfo,
2414 cellStateInInfo,
2415 scratchBufferInfo,
2416 outputStateOutInfo,
2417 cellStateOutInfo,
2418 outputInfo,
2419 desc,
2420 paramsInfo);
2421 if (!isSupported)
2422 {
2423 return false;
2424 }
2425
2426 // Add the layer
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002427 IConnectableLayer* layer = data.m_Network->AddLstmLayer(desc, params, "Lstm");
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002428
2429 input.Connect(layer->GetInputSlot(0));
2430 outputStateIn.Connect(layer->GetInputSlot(1));
2431 cellStateIn.Connect(layer->GetInputSlot(2));
2432
2433 return (SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, 0, model, data) &&
2434 SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 1, *layer, 1, model, data) &&
2435 SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 2, *layer, 2, model, data) &&
2436 SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 3, *layer, 3, model, data));
2437}
2438
Sadik Armagan701d9a02019-09-04 15:16:18 +01002439bool HalPolicy::ConvertSqrt(const Operation& operation, const Model& model, ConversionData& data)
2440{
2441 ALOGV("hal_1_2::HalPolicy::ConvertSqrt()");
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002442 ActivationDescriptor desc;
2443 desc.m_Function = ActivationFunction::Sqrt;
Sadik Armagan701d9a02019-09-04 15:16:18 +01002444
2445 return ::ConvertToActivation<hal_1_2::HalPolicy>(operation, __func__, desc, model, data);
2446}
2447
Mike Kelly46272802019-08-14 17:00:48 +01002448bool HalPolicy::ConvertSqueeze(const Operation& operation, const Model& model, ConversionData& data)
2449{
Sadik Armagan701d9a02019-09-04 15:16:18 +01002450 ALOGV("hal_1_2::HalPolicy::ConvertSqueeze()");
Mike Kelly46272802019-08-14 17:00:48 +01002451 return ::ConvertSqueeze<hal_1_2::HalPolicy>(operation, model, data);
2452}
2453
2454bool HalPolicy::ConvertStridedSlice(const Operation& operation, const Model& model, ConversionData& data)
2455{
Sadik Armagan701d9a02019-09-04 15:16:18 +01002456 ALOGV("hal_1_2::HalPolicy::ConvertStridedSlice()");
Mike Kelly46272802019-08-14 17:00:48 +01002457 return ::ConvertStridedSlice<hal_1_2::HalPolicy>(operation, model, data);
2458}
2459
2460bool HalPolicy::ConvertTranspose(const Operation& operation, const Model& model, ConversionData& data)
2461{
Sadik Armagan701d9a02019-09-04 15:16:18 +01002462 ALOGV("hal_1_2::HalPolicy::ConvertTranspose()");
Mike Kelly46272802019-08-14 17:00:48 +01002463 return ::ConvertTranspose<hal_1_2::HalPolicy>(operation, model, data);
2464}
2465
Aron Virginas-Tar8b991682019-07-31 12:54:59 +01002466bool HalPolicy::ConvertTransposeConv2d(const Operation& operation, const Model& model, ConversionData& data)
David Monahan613b49c2019-06-27 11:37:47 +01002467{
2468 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
2469
2470 if (!input.IsValid())
2471 {
2472 return Fail("%s: Operation has invalid inputs", __func__);
2473 }
2474
2475 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
2476
2477 if (!output)
2478 {
2479 return Fail("%s: Could not read output 0", __func__);
2480 }
2481
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002482 const TensorInfo& inputInfo = input.GetTensorInfo();
2483 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
David Monahan613b49c2019-06-27 11:37:47 +01002484 if (IsDynamicTensor(outputInfo))
2485 {
2486 return Fail("%s: Dynamic output tensors are not supported", __func__);
2487 }
2488
2489 // ArmNN does not currently support non-fixed weights or bias
2490 // Find the shape of the weights tensor. In AndroidNN this will be [ 1, H, W, I * M ]
2491 const Operand* weightsOperand = GetInputOperand<hal_1_2::HalPolicy>(operation, 1, model);
2492
2493 if (weightsOperand == nullptr)
2494 {
2495 return Fail("%s: Operand is invalid", __func__);
2496 }
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002497 TransposeConvolution2dDescriptor desc;
2498 desc.m_DataLayout = DataLayout::NHWC;
David Monahan613b49c2019-06-27 11:37:47 +01002499
2500 // Determine whether padding is implicit or explicit
2501 bool implicitPadding = operation.inputs.size() == 9;
2502
2503 if (implicitPadding )
2504 {
2505 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 8, model, data);
2506 }
2507 else
2508 {
2509 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 10, model, data);
2510 }
2511
2512 armnnUtils::DataLayoutIndexed dataLayoutIndexed(desc.m_DataLayout);
2513 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
2514 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
2515
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002516 const PermutationVector OHWIToOIHW = {0, 2, 3, 1};
David Monahan613b49c2019-06-27 11:37:47 +01002517
2518 // The shape of the weight is [depth_out, filter_height, filter_width, depth_in].
2519 // We have to permute it to OIHW if the data layout is NCHW.
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002520 const ConstTensorPin weightsPin = (desc.m_DataLayout == DataLayout::NCHW) ?
David Monahan613b49c2019-06-27 11:37:47 +01002521 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 1, model, data, OHWIToOIHW) :
2522 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 1, model, data);
2523
2524 // Bias is a 1D tensor
2525 const ConstTensorPin biasPin =
2526 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 2, model, data);
2527
2528 if (!weightsPin.IsValid())
2529 {
2530 return Fail("%s: Operation has invalid weights", __func__);
2531 }
2532
2533 if (!biasPin.IsValid())
2534 {
2535 return Fail("%s: Operation has invalid biases", __func__);
2536 }
2537
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002538 ConstTensor weights = weightsPin.GetConstTensor();
2539 ConstTensor bias = biasPin.GetConstTensor();
David Monahan613b49c2019-06-27 11:37:47 +01002540 SanitizeBiasQuantizationScale(bias.GetInfo(), weights.GetInfo(), inputInfo);
2541
2542 ActivationFn activation;
2543
2544 if (implicitPadding)
2545 {
Sadik Armagan3e3003e2019-08-13 12:54:34 +01002546 int32_t strideX{0};
2547 int32_t strideY{0};
2548 int32_t padLeft{0};
2549 int32_t padRight{0};
2550 int32_t padTop{0};
2551 int32_t padBottom{0};
2552
David Monahan613b49c2019-06-27 11:37:47 +01002553 android::nn::PaddingScheme paddingScheme;
2554 if (!GetInputPaddingScheme<hal_1_2::HalPolicy>(operation, 4, paddingScheme, model, data) ||
Sadik Armagan3e3003e2019-08-13 12:54:34 +01002555 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, strideX, model, data) ||
2556 !GetInputScalar<hal_1_2::HalPolicy>(operation, 6, OperandType::INT32, strideY, model, data) ||
David Monahan613b49c2019-06-27 11:37:47 +01002557 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 7, activation, model, data))
2558 {
2559 return Fail("%s: Operation has invalid inputs (implicit padding)", __func__);
2560 }
2561
2562 const uint32_t kernelX = weights.GetShape()[widthIndex];
2563 const uint32_t kernelY = weights.GetShape()[heightIndex];
Narumol Prangnawaratc8bdb392019-08-01 15:51:44 +01002564 const uint32_t outputX = outputInfo.GetShape()[widthIndex];
2565 const uint32_t outputY = outputInfo.GetShape()[heightIndex];
David Monahan613b49c2019-06-27 11:37:47 +01002566
Narumol Prangnawaratc8bdb392019-08-01 15:51:44 +01002567 CalcPaddingTransposeConv(outputX, kernelX, desc.m_StrideX, padLeft, padRight, paddingScheme);
2568 CalcPaddingTransposeConv(outputY, kernelY, desc.m_StrideY, padTop, padBottom, paddingScheme);
2569
2570 // NOTE: The Android NN API allows for negative padding values in TransposeConv2d,
2571 // but Arm NN only supports values >= 0
2572 if (padLeft < 0 || padRight < 0 || padTop < 0 || padBottom < 0)
2573 {
2574 return Fail("%s: Negative padding values are not supported", __func__);
2575 }
2576
Sadik Armagan3e3003e2019-08-13 12:54:34 +01002577 desc.m_StrideX = boost::numeric_cast<uint32_t>(strideX);
2578 desc.m_StrideY = boost::numeric_cast<uint32_t>(strideY);
Narumol Prangnawaratc8bdb392019-08-01 15:51:44 +01002579 desc.m_PadLeft = boost::numeric_cast<uint32_t>(padLeft);
2580 desc.m_PadRight = boost::numeric_cast<uint32_t>(padRight);
2581 desc.m_PadTop = boost::numeric_cast<uint32_t>(padTop);
2582 desc.m_PadBottom = boost::numeric_cast<uint32_t>(padBottom);
David Monahan613b49c2019-06-27 11:37:47 +01002583 }
2584 else if (operation.inputs.size() == 11)
2585 {
2586 // explicit padding
2587 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 3, OperandType::INT32, desc.m_PadLeft, model, data) ||
2588 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_PadRight, model, data) ||
2589 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_PadTop, model, data) ||
2590 !GetInputScalar<hal_1_2::HalPolicy>(operation, 6, OperandType::INT32, desc.m_PadBottom, model, data) ||
2591 !GetInputScalar<hal_1_2::HalPolicy>(operation, 7, OperandType::INT32, desc.m_StrideX, model, data) ||
2592 !GetInputScalar<hal_1_2::HalPolicy>(operation, 8, OperandType::INT32, desc.m_StrideY, model, data) ||
2593 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 9, activation, model, data))
2594 {
2595 return Fail("%s: Operation has invalid inputs (explicit padding)", __func__);
2596 }
2597 }
2598 else
2599 {
2600 return Fail("%s: Unsupported number of operation inputs", __func__);
2601 }
2602
2603 desc.m_BiasEnabled = true;
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002604 Optional<TensorInfo> biases(bias.GetInfo());
David Monahan613b49c2019-06-27 11:37:47 +01002605
2606 bool isSupported = false;
2607 FORWARD_LAYER_SUPPORT_FUNC(__func__,
2608 IsTransposeConvolution2dSupported,
2609 data.m_Backends,
2610 isSupported,
2611 inputInfo,
2612 outputInfo,
2613 desc,
2614 weights.GetInfo(),
2615 biases);
2616 if (!isSupported)
2617 {
2618 return false;
2619 }
2620
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002621 IConnectableLayer* startLayer =
2622 data.m_Network->AddTransposeConvolution2dLayer(desc, weights, Optional<ConstTensor>(bias));
David Monahan613b49c2019-06-27 11:37:47 +01002623 if (!startLayer)
2624 {
2625 return Fail("%s: AddTransposeConvolution2dLayer failed", __func__);
2626 }
2627
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002628 IConnectableLayer* endLayer = ProcessActivation(outputInfo, activation, startLayer, data);
David Monahan613b49c2019-06-27 11:37:47 +01002629 if (!endLayer)
2630 {
2631 return Fail("%s: ProcessActivation failed", __func__);
2632 }
2633
2634 input.Connect(startLayer->GetInputSlot(0));
2635
2636 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *endLayer, model, data);
2637}
2638
Mike Kellyb5fdf382019-06-11 16:35:25 +01002639} // namespace hal_1_2
Matteo Martincigh17ffff32019-06-27 14:12:55 +01002640} // namespace armnn_driver