blob: f901a31be21791e76726f50c9484b26511bcfc17 [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 Charlin3b959602019-10-31 17:05:47 +0000423 if ( weightsOperand->dimensions[0] != 1)
424 {
425 return Fail("%s: Invalid weights; for depthwise convolution, dimension 0 must be 1 but it is %i",
426 __func__, weightsOperand->dimensions[0] );
427 }
428
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100429 DepthwiseConvolution2dDescriptor desc;
430 desc.m_DataLayout = DataLayout::NHWC;
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100431
432 // Determine whether padding is implicit or explicit
433 bool implicitPadding = operation.inputs.size() == 8 ||
434 (operation.inputs.size() >= 9 &&
435 GetInputOperand<hal_1_2::HalPolicy>(operation, 8, model)->type == OperandType::BOOL);
436
437 // Look ahead to find the optional DataLayout, if present
438 const uint32_t dataLayoutFlagIndex = implicitPadding ? 8 : 11;
439 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, dataLayoutFlagIndex, model, data);
440
441 armnnUtils::DataLayoutIndexed dataLayoutIndexed(desc.m_DataLayout);
442 unsigned int channelsIndex = dataLayoutIndexed.GetChannelsIndex();
443 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
444 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
445
446 // Reinterpret weight data as [ H, W, I, M ]
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100447 TensorShape weightsShape({ weightsOperand->dimensions[1],
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100448 weightsOperand->dimensions[2],
449 inputInfo.GetShape()[channelsIndex],
450 weightsOperand->dimensions[3] / inputInfo.GetShape()[channelsIndex] });
451
452 // Swizzle weight data [ H, W, I, M ] -> [ M, I, H, W ]
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100453 const PermutationVector HWIMToMIHW = { 2U, 3U, 1U, 0U };
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100454
455 const ConstTensorPin weightsPin =
456 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
457 1,
458 model,
459 data,
460 HWIMToMIHW,
461 &weightsShape);
462
463 // Bias is a 1D tensor
464 const ConstTensorPin biasPin =
465 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 2, model, data);
466
467 if (!weightsPin.IsValid())
468 {
469 return Fail("%s: Operation has invalid weights", __func__);
470 }
471
472 if (!biasPin.IsValid())
473 {
474 return Fail("%s: Operation has invalid biases", __func__);
475 }
476
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100477 ConstTensor weights = weightsPin.GetConstTensor();
478 ConstTensor bias = biasPin.GetConstTensor();
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100479 SanitizeBiasQuantizationScale(bias.GetInfo(), weights.GetInfo(), inputInfo);
480
481 ActivationFn activation;
482
483 if (implicitPadding)
484 {
485 android::nn::PaddingScheme paddingScheme;
486 if (!GetInputPaddingScheme<hal_1_2::HalPolicy>(operation, 3, paddingScheme, model, data) ||
487 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_StrideX, model, data) ||
488 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_StrideY, model, data) ||
489 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 7, activation, model, data) ||
490 !GetOptionalConvolutionDilationParams<hal_1_2::HalPolicy>(operation, 9, desc, model, data))
491 {
492 return Fail("%s: Operation has invalid inputs (implicit padding)", __func__);
493 }
494
495 const uint32_t kernelX = weights.GetShape()[3];
496 const uint32_t kernelY = weights.GetShape()[2];
497 const uint32_t inputX = inputInfo.GetShape()[widthIndex];
498 const uint32_t inputY = inputInfo.GetShape()[heightIndex];
499
Mike Kelly86b36d42019-07-12 16:39:33 +0100500 CalcPadding(inputX, kernelX, desc.m_StrideX, desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, paddingScheme);
501 CalcPadding(inputY, kernelY, desc.m_StrideY, desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, paddingScheme);
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100502 }
503 else if (operation.inputs.size() >= 11)
504 {
505 // explicit padding
506 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 3, OperandType::INT32, desc.m_PadLeft, model, data) ||
507 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_PadRight, model, data) ||
508 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_PadTop, model, data) ||
509 !GetInputScalar<hal_1_2::HalPolicy>(operation, 6, OperandType::INT32, desc.m_PadBottom, model, data) ||
510 !GetInputScalar<hal_1_2::HalPolicy>(operation, 7, OperandType::INT32, desc.m_StrideX, model, data) ||
511 !GetInputScalar<hal_1_2::HalPolicy>(operation, 8, OperandType::INT32, desc.m_StrideY, model, data) ||
512 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 10, activation, model, data) ||
513 !GetOptionalConvolutionDilationParams<hal_1_2::HalPolicy>(operation, 12, desc, model, data))
514 {
515 return Fail("%s: Operation has invalid inputs (explicit padding)", __func__);
516 }
517 }
518 else
519 {
520 return Fail("%s: Unsupported number of operation inputs", __func__);
521 }
522
523 desc.m_BiasEnabled = true;
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100524 Optional<TensorInfo> biases(bias.GetInfo());
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100525
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100526 bool isSupported = false;
527 FORWARD_LAYER_SUPPORT_FUNC(__func__,
528 IsDepthwiseConvolutionSupported,
529 data.m_Backends,
530 isSupported,
531 inputInfo,
532 outputInfo,
533 desc,
534 weights.GetInfo(),
535 biases);
Aron Virginas-Tar9fd37392019-07-15 18:04:32 +0100536
Ferran Balaguerd30093c2019-07-09 17:04:47 +0100537 if (!isSupported)
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100538 {
539 return false;
540 }
541
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100542 IConnectableLayer* startLayer =
543 data.m_Network->AddDepthwiseConvolution2dLayer(desc, weights, Optional<ConstTensor>(bias));
Aron Virginas-Tar9fd37392019-07-15 18:04:32 +0100544
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100545 if (!startLayer)
546 {
547 return Fail("%s: AddDepthwiseConvolution2dLayer failed", __func__);
548 }
549
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100550 IConnectableLayer* endLayer = ProcessActivation(outputInfo, activation, startLayer, data);
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100551 if (!endLayer)
552 {
553 return Fail("%s: ProcessActivation failed", __func__);
554 }
555
556 input.Connect(startLayer->GetInputSlot(0));
557
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +0100558 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *endLayer, model, data);
Aron Virginas-Tar24e699d2019-06-17 14:47:46 +0100559}
560
Mike Kelly46272802019-08-14 17:00:48 +0100561bool HalPolicy::ConvertDequantize(const Operation& operation, const Model& model, ConversionData& data)
562{
563 ALOGV("hal_1_2::HalPolicy::ConvertDequantize()");
564 return ::ConvertDequantize<hal_1_2::HalPolicy>(operation, model, data);
565}
566
567bool HalPolicy::ConvertDiv(const Operation& operation, const Model& model, ConversionData& data)
568{
569 ALOGV("hal_1_2::HalPolicy::ConvertDiv()");
570 return ::ConvertDiv<hal_1_2::HalPolicy>(operation, model, data);
571}
572
Narumol Prangnawarat85f96542019-09-12 16:26:29 +0100573bool HalPolicy::ConvertExpandDims(const Operation& operation, const Model& model, ConversionData& data)
574{
575 ALOGV("hal_1_2::HalPolicy::ConvertExpandDims()");
576
577 LayerInputHandle input = ConvertToLayerInputHandle<HalPolicy>(operation, 0, model, data);
578
579 if (!input.IsValid())
580 {
581 return Fail("%s: Operation has invalid input", __func__);
582 }
583
584 const Operand* output = GetOutputOperand<HalPolicy>(operation, 0, model);
585 if (!output)
586 {
587 return Fail("%s: Operation has invalid output", __func__);
588 }
589
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100590 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Narumol Prangnawarat85f96542019-09-12 16:26:29 +0100591 if (IsDynamicTensor(outputInfo))
592 {
593 return Fail("%s: Dynamic output tensors are not supported", __func__);
594 }
595
596 int32_t axis;
597 if (!GetInputScalar<HalPolicy>(operation, 1, OperandType::INT32, axis, model, data))
598 {
599 return Fail("%s: failed to get axis input value", __func__);
600 }
601
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100602 TensorShape targetShape;
Narumol Prangnawarat85f96542019-09-12 16:26:29 +0100603
604 try
605 {
606 targetShape = armnnUtils::ExpandDims(input.GetTensorInfo().GetShape(), axis);
607 }
608 catch (const std::exception &e)
609 {
610 return Fail("%s: %s", __func__, e.what());
611 }
612
613 if (targetShape != outputInfo.GetShape())
614 {
615 return Fail("%s: Shape of the output operand does not match the resolved expanded shape", __func__);
616 }
617
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100618 ReshapeDescriptor reshapeDescriptor;
Narumol Prangnawarat85f96542019-09-12 16:26:29 +0100619 reshapeDescriptor.m_TargetShape = targetShape;
620
621 bool isSupported = false;
622 FORWARD_LAYER_SUPPORT_FUNC(__func__,
623 IsReshapeSupported,
624 data.m_Backends,
625 isSupported,
626 input.GetTensorInfo(),
627 reshapeDescriptor);
628
629 if (!isSupported)
630 {
631 return false;
632 }
633
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100634 IConnectableLayer* layer = data.m_Network->AddReshapeLayer(reshapeDescriptor);
Narumol Prangnawarat85f96542019-09-12 16:26:29 +0100635 assert(layer != nullptr);
636 input.Connect(layer->GetInputSlot(0));
637
638 return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data);
639}
640
Mike Kelly46272802019-08-14 17:00:48 +0100641bool HalPolicy::ConvertFloor(const Operation& operation, const Model& model, ConversionData& data)
642{
643 ALOGV("hal_1_2::HalPolicy::ConvertFloor()");
644 return ::ConvertFloor<hal_1_2::HalPolicy>(operation, model, data);
645}
646
647bool HalPolicy::ConvertFullyConnected(const Operation& operation, const Model& model, ConversionData& data)
648{
649 ALOGV("hal_1_2::HalPolicy::ConvertFullyConnected()");
650 return ::ConvertFullyConnected<hal_1_2::HalPolicy>(operation, model, data);
651}
652
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100653bool HalPolicy::ConvertGroupedConv2d(const Operation& operation, const Model& model, ConversionData& data)
654{
655 ALOGV("hal_1_2::HalPolicy::ConvertGroupedConv2d()");
656
657 //
658 // Parse data
659 //
660 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
661 if (!input.IsValid())
662 {
663 return Fail("%s: Operation has invalid inputs", __func__);
664 }
665 const TensorInfo& inputInfo = input.GetTensorInfo();
666
667 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
668 if (!output)
669 {
670 return Fail("%s: Could not read output 0", __func__);
671 }
672 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
673 if (IsDynamicTensor(outputInfo))
674 {
675 return Fail("%s: Dynamic output tensors are not supported", __func__);
676 }
677
678 // Look ahead to determine data layout
679 DataLayout dataLayout = DataLayout::NHWC;
680 if (operation.inputs.size() == 12)
681 {
682 dataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 11, model, data);
683 }
684 else
685 {
686 dataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 8, model, data);
687 }
688
689 // NOTE:
690 // NNAPI weights are always OHWI, i.e. [depth_out, filter_height, filter_width, depth_group],
691 // but Arm NN expects the filter's height and width indices to match the input's height and
692 // width indices so when the DataLayout is NCHW, we need to permute the weights to OIHW
693 const PermutationVector ohwiToOihw = { 0u, 2u, 3u, 1u };
694 const ConstTensorPin weightsPin = (dataLayout == DataLayout::NCHW) ?
695 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 1, model, data, ohwiToOihw) :
696 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 1, model, data);
697 const ConstTensorPin biasesPin =
698 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 2, model, data);
699 if (!weightsPin.IsValid() || !biasesPin.IsValid())
700 {
701 return Fail("%s: Operation has invalid inputs", __func__);
702 }
703
704 ConstTensor weights = weightsPin.GetConstTensor();
Aron Virginas-Tar60a346b2019-11-07 14:49:26 +0000705 ConstTensor biases = biasesPin.GetConstTensor();
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100706 SanitizeBiasQuantizationScale(biases.GetInfo(), weights.GetInfo(), inputInfo);
707
708 const TensorShape& inputShape = inputInfo.GetShape();
709 const TensorShape& outputShape = outputInfo.GetShape();
710 const TensorShape& weightsShape = weights.GetShape();
711 const TensorShape& biasesShape = biases.GetShape();
712
713 armnnUtils::DataLayoutIndexed dataLayoutIndexed(dataLayout);
714 const unsigned int channelsIndex = dataLayoutIndexed.GetChannelsIndex();
715 const unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
716 const unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
717
718 Convolution2dDescriptor desc;
719 desc.m_DataLayout = dataLayout;
720 desc.m_BiasEnabled = true;
721
722 int numGroups;
723 ActivationFn activation;
724
725 if (operation.inputs.size() == 12)
726 {
727 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 3, OperandType::INT32, desc.m_PadLeft, model, data) ||
728 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_PadRight, model, data) ||
729 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_PadTop, model, data) ||
730 !GetInputScalar<hal_1_2::HalPolicy>(operation, 6, OperandType::INT32, desc.m_PadBottom, model, data) ||
731 !GetInputScalar<hal_1_2::HalPolicy>(operation, 7, OperandType::INT32, desc.m_StrideX, model, data) ||
732 !GetInputScalar<hal_1_2::HalPolicy>(operation, 8, OperandType::INT32, desc.m_StrideY, model, data) ||
733 !GetInputScalar<hal_1_2::HalPolicy>(operation, 9, OperandType::INT32, numGroups, model, data) ||
734 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 10, activation, model, data))
735 {
736 return Fail("%s: Operation has invalid inputs (explicit padding)", __func__);
737 }
738
739 }
740 else if (operation.inputs.size() == 9)
741 {
742 android::nn::PaddingScheme paddingScheme;
743 if (!GetInputPaddingScheme<hal_1_2::HalPolicy>(operation, 3, paddingScheme, model, data) ||
744 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_StrideX, model, data) ||
745 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_StrideY, model, data) ||
746 !GetInputScalar<hal_1_2::HalPolicy>(operation, 6, OperandType::INT32, numGroups, model, data) ||
747 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 7, activation, model, data))
748 {
749 return Fail("%s: Operation has invalid inputs (implicit padding)", __func__);
750 }
751
752 const uint32_t inputX = inputInfo.GetShape()[widthIndex];
753 const uint32_t inputY = inputInfo.GetShape()[heightIndex];
754
755 const uint32_t kernelX = weightsShape[widthIndex];
756 const uint32_t kernelY = weightsShape[heightIndex];
757
758 CalcPadding(inputX, kernelX, desc.m_StrideX, desc.m_PadLeft, desc.m_PadRight, paddingScheme);
759 CalcPadding(inputY, kernelY, desc.m_StrideY, desc.m_PadTop, desc.m_PadBottom, paddingScheme);
760 }
761 else
762 {
763 return Fail("%s: Unsupported number of operation inputs", __func__);
764 }
765
766 const unsigned int outputChannels = outputShape[channelsIndex];
767
768 const unsigned int channelsPerGroup = weightsShape[channelsIndex];
769 const unsigned int channelMultiplier = outputChannels / numGroups;
770
771 //
772 // Validate all relevant inputs
773 //
774 if (numGroups <= 0)
775 {
776 return Fail("%s: Number of groups must be greater than 0. Got: %d", __func__, numGroups);
777 }
778
779 if (outputChannels % numGroups != 0u)
780 {
781 return Fail("%s: Output channels must be divisible by the number of groups", __func__);
782 }
783
784 //
785 // Set up Splitter layer
786 //
787 unsigned int splitterDimSizes[4] = { inputShape[0], inputShape[1], inputShape[2], inputShape[3] };
788 splitterDimSizes[channelsIndex] /= numGroups; // split in depth
789
790 TensorInfo splitterOutputInfo(4,
791 splitterDimSizes,
792 inputInfo.GetDataType(),
793 inputInfo.GetQuantizationScale(),
794 inputInfo.GetQuantizationOffset());
795
796 std::vector<std::reference_wrapper<TensorInfo>> splitterOutputInfos(numGroups, std::ref(splitterOutputInfo));
797
798 ViewsDescriptor splitterDesc(numGroups);
799 for (unsigned int group = 0u; group < numGroups; ++group)
800 {
801 splitterDesc.SetViewOriginCoord(group, channelsIndex, splitterDimSizes[channelsIndex] * group);
802 for (unsigned int dimIdx = 0u; dimIdx < 4u; dimIdx++)
803 {
804 splitterDesc.SetViewSize(group, dimIdx, splitterDimSizes[dimIdx]);
805 }
806 }
807
808 bool isSupported = false;
809 FORWARD_LAYER_SUPPORT_FUNC(__func__,
810 IsSplitterSupported,
811 data.m_Backends,
812 isSupported,
813 inputInfo,
814 splitterOutputInfos,
815 splitterDesc);
816 if (!isSupported)
817 {
818 return false;
819 }
820
821 IConnectableLayer* splitterLayer = data.m_Network->AddSplitterLayer(splitterDesc);
822 if (!splitterLayer)
823 {
824 return Fail("%s: Failed to add SplitterLayer", __func__);
825 }
826
827 input.Connect(splitterLayer->GetInputSlot(0));
828 for (unsigned int group = 0u; group < splitterLayer->GetNumOutputSlots(); ++group)
829 {
830 splitterLayer->GetOutputSlot(group).SetTensorInfo(splitterOutputInfo);
831 }
832
833 //
834 // Set up Convolution2d layers for each group
835 //
Aron Virginas-Tar60a346b2019-11-07 14:49:26 +0000836
837 // Set up group tensor shapes
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100838 TensorShape groupInputShape(inputShape);
839 groupInputShape[channelsIndex] = channelsPerGroup;
840
841 TensorShape groupOutputShape(outputShape);
842 groupOutputShape[channelsIndex] = 1;
843
844 TensorShape groupWeightsShape(weightsShape);
845 groupWeightsShape[0] /= channelMultiplier * numGroups;
846
847 TensorShape groupBiasesShape({ 1 });
848
Aron Virginas-Tar60a346b2019-11-07 14:49:26 +0000849 // Set up group tensor infos
850 TensorInfo groupInputInfo(inputInfo);
851 groupInputInfo.SetShape(groupInputShape);
852
853 const TensorInfo& weightsInfo = weights.GetInfo();
854 TensorInfo groupWeightsInfo(weightsInfo);
855 groupWeightsInfo.SetShape(groupWeightsShape);
856
857 const TensorInfo& biasesInfo = biases.GetInfo();
858 TensorInfo groupBiasesInfo(biasesInfo);
859 groupBiasesInfo.SetShape(groupBiasesShape);
860
861 TensorInfo groupOutputInfo(outputInfo);
862 groupOutputInfo.SetShape(groupOutputShape);
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100863
864 const unsigned int weightsDataTypeSize = GetDataTypeSize(groupWeightsInfo.GetDataType());
865 const unsigned int biasesDataTypeSize = GetDataTypeSize(groupBiasesInfo.GetDataType());
866
Aron Virginas-Tar60a346b2019-11-07 14:49:26 +0000867 std::vector<IConnectableLayer*> convLayers(numGroups * channelMultiplier, nullptr);
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100868 for (unsigned int group = 0u; group < numGroups; ++group)
869 {
870 for (unsigned int m = 0u; m < channelMultiplier; ++m)
871 {
872 auto index = group * channelMultiplier + m;
873
874 const unsigned int weightsDataOffset = groupWeightsShape.GetNumElements() * index * weightsDataTypeSize;
875 const unsigned int biasesDataOffset = groupBiasesShape.GetNumElements() * index * biasesDataTypeSize;
876
Aron Virginas-Tar60a346b2019-11-07 14:49:26 +0000877 if (weightsInfo.HasPerAxisQuantization())
878 {
879 // Extract per-axis quantization scales for group weights
880 const std::vector<float>& weightsQuantScales = weightsInfo.GetQuantizationScales();
881 groupWeightsInfo.SetQuantizationScales(
882 std::vector<float>(weightsQuantScales.begin() + index,
883 weightsQuantScales.begin() + index + groupWeightsShape[0]));
884
885 // Extract per-axis quantization scales for group biases
886 const std::vector<float>& biasesQuantScales = biasesInfo.GetQuantizationScales();
887 groupBiasesInfo.SetQuantizationScales(
888 std::vector<float>(biasesQuantScales.begin() + index,
889 biasesQuantScales.begin() + index + groupWeightsShape[0]));
890 }
891
Teresa Charlin8f6429d2019-10-01 13:10:15 +0100892 // Extract weights and biases data for current group convolution
893 ConstTensor groupWeights(groupWeightsInfo,
894 static_cast<const void *>(reinterpret_cast<const char *>(weights.GetMemoryArea()) +
895 weightsDataOffset));
896 ConstTensor groupBiases(groupBiasesInfo,
897 static_cast<const void *>(reinterpret_cast<const char *>(biases.GetMemoryArea()) +
898 biasesDataOffset));
899
900 isSupported = false;
901 FORWARD_LAYER_SUPPORT_FUNC(__func__,
902 IsConvolution2dSupported,
903 data.m_Backends,
904 isSupported,
905 groupInputInfo,
906 groupOutputInfo,
907 desc,
908 groupWeightsInfo,
909 Optional<TensorInfo>(groupBiasesInfo));
910 if (!isSupported)
911 {
912 return false;
913 }
914
915 IConnectableLayer *convLayer =
916 data.m_Network->AddConvolution2dLayer(desc, groupWeights, Optional<ConstTensor>(groupBiases));
917 if (!convLayer)
918 {
919 return Fail("%s: AddConvolution2dLayer failed", __func__);
920 }
921
922 splitterLayer->GetOutputSlot(group).Connect(convLayer->GetInputSlot(0));
923 convLayer->GetOutputSlot(0).SetTensorInfo(groupOutputInfo);
924
925 convLayers[index] = convLayer;
926 }
927 }
928
929 //
930 // Set up Concat layer
931 //
932 ConcatDescriptor concatDescriptor(outputInfo.GetShape()[channelsIndex]);
933 for (unsigned int group = 0u; group < numGroups; ++group)
934 {
935 for (unsigned int m = 0u; m < channelMultiplier; ++m)
936 {
937 auto index = group * channelMultiplier + m;
938 concatDescriptor.SetViewOriginCoord(index, channelsIndex, index);
939 concatDescriptor.SetConcatAxis(channelsIndex);
940 }
941 }
942
943 isSupported = false;
944 FORWARD_LAYER_SUPPORT_FUNC(__func__,
945 IsConcatSupported,
946 data.m_Backends,
947 isSupported,
948 std::vector<const TensorInfo*>(numGroups * channelMultiplier, &groupOutputInfo),
949 outputInfo,
950 concatDescriptor);
951 if (!isSupported)
952 {
953 return false;
954 }
955
956 IConnectableLayer* concatLayer = data.m_Network->AddConcatLayer(concatDescriptor);
957 if (!concatLayer)
958 {
959 return Fail("%s: AddConcatLayer failed", __func__);
960 }
961
962 for (unsigned int group = 0u; group < numGroups; ++group)
963 {
964 for (unsigned int m = 0u; m < channelMultiplier; ++m)
965 {
966 auto index = group * channelMultiplier + m;
967 convLayers[index]->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(index));
968 }
969 }
970 concatLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
971
972 //
973 // Set up Activation layer (if it is set)
974 //
975 IConnectableLayer* endLayer = ProcessActivation(outputInfo, activation, concatLayer, data);
976 if (!endLayer)
977 {
978 return Fail("%s: ProcessActivation failed", __func__);
979 }
980
981 return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *endLayer, model, data);
982}
983
Aron Virginas-Tara2a73802019-10-09 15:30:40 +0100984bool HalPolicy::ConvertInstanceNormalization(const Operation& operation, const Model& model, ConversionData& data)
985{
986 ALOGV("hal_1_2::HalPolicy::ConvertInstanceNormalization()");
987
988 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
989 if (!input.IsValid())
990 {
991 return Fail("%s: Operation has an invalid input 0", __func__);
992 }
993
994 const Operand* output = GetOutputOperand<HalPolicy>(operation, 0, model);
995 if (!output)
996 {
997 return Fail("%s: Operation has an invalid output", __func__);
998 }
999
1000 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
1001 if (IsDynamicTensor(outputInfo))
1002 {
1003 return Fail("%s: Dynamic output tensors are not supported", __func__);
1004 }
1005
1006 // Determine data type of input tensor
1007 OperandType inputType;
1008 if (!GetOperandType<hal_1_2::HalPolicy>(operation, 0, model, inputType))
1009 {
1010 return Fail("%s: Operation has invalid inputs", __func__);
1011 }
1012
1013 InstanceNormalizationDescriptor desc;
1014
1015 // Read gamma, beta & epsilon
1016 if (inputType == OperandType::TENSOR_FLOAT16)
1017 {
1018 Half fp16Gamma;
1019 Half fp16Beta;
1020 Half fp16Epsilon;
1021
1022 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 1, OperandType::FLOAT16, fp16Gamma, model, data) ||
1023 !GetInputScalar<hal_1_2::HalPolicy>(operation, 2, OperandType::FLOAT16, fp16Beta, model, data) ||
1024 !GetInputScalar<hal_1_2::HalPolicy>(operation, 3, OperandType::FLOAT16, fp16Epsilon, model, data))
1025 {
1026 return Fail("%s: Operation has invalid inputs (FLOAT16)", __func__);
1027 }
1028
1029 desc.m_Gamma = static_cast<float>(fp16Gamma);
1030 desc.m_Beta = static_cast<float>(fp16Beta);
1031 desc.m_Eps = static_cast<float>(fp16Epsilon);
1032 }
1033 else if (inputType == OperandType::TENSOR_FLOAT32)
1034 {
1035 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 1, OperandType::FLOAT32, desc.m_Gamma, model, data) ||
1036 !GetInputScalar<hal_1_2::HalPolicy>(operation, 2, OperandType::FLOAT32, desc.m_Beta, model, data) ||
1037 !GetInputScalar<hal_1_2::HalPolicy>(operation, 3, OperandType::FLOAT32, desc.m_Eps, model, data))
1038 {
1039 return Fail("%s: Operation has invalid inputs (FLOAT32)", __func__);
1040 }
1041 }
1042 else
1043 {
1044 return Fail("%s: Unsupported input tensor type: %d", __func__, inputType);
1045 }
1046
1047 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 4, model, data);
1048
1049 bool isSupported = false;
1050 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1051 IsInstanceNormalizationSupported,
1052 data.m_Backends,
1053 isSupported,
1054 input.GetTensorInfo(),
1055 outputInfo,
1056 desc);
1057 if (!isSupported)
1058 {
1059 return false;
1060 }
1061
1062 IConnectableLayer* layer = data.m_Network->AddInstanceNormalizationLayer(desc);
1063 input.Connect(layer->GetInputSlot(0));
1064
1065 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
1066}
1067
Mike Kelly46272802019-08-14 17:00:48 +01001068bool HalPolicy::ConvertL2Normalization(const Operation& operation, const Model& model, ConversionData& data)
1069{
1070 ALOGV("hal_1_2::HalPolicy::ConvertL2Normalization()");
1071 return ::ConvertL2Normalization<hal_1_2::HalPolicy>(operation, model, data);
1072}
1073
Sadik Armagan15d63e22019-07-26 16:59:35 +01001074bool HalPolicy::ConvertL2Pool2d(const Operation& operation, const Model& model, ConversionData& data)
1075{
1076 ALOGV("hal_1_2::HalPolicy::ConvertL2Pool2d()");
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001077 return ConvertPooling2d<hal_1_2::HalPolicy>(operation, __func__, PoolingAlgorithm::L2, model, data);
Sadik Armagan15d63e22019-07-26 16:59:35 +01001078}
1079
Mike Kelly46272802019-08-14 17:00:48 +01001080bool HalPolicy::ConvertLocalResponseNormalization(const Operation& operation,
1081 const Model& model,
1082 ConversionData& data)
1083{
1084 ALOGV("hal_1_2::HalPolicy::ConvertLocalResponseNormalization()");
1085 return ::ConvertLocalResponseNormalization<hal_1_2::HalPolicy>(operation, model, data);
1086}
1087
1088bool HalPolicy::ConvertLogistic(const Operation& operation, const Model& model, ConversionData& data)
1089{
1090 ALOGV("hal_1_2::HalPolicy::ConvertLogistic()");
1091 return ::ConvertLogistic<hal_1_2::HalPolicy>(operation, model, data);
1092}
1093
Aron Virginas-Tar75e67792019-10-15 13:33:03 +01001094bool HalPolicy::ConvertLogSoftmax(const Operation& operation, const Model& model, ConversionData& data)
1095{
1096 ALOGV("hal_1_2::HalPolicy::ConvertLogSoftmax()");
1097
1098 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
1099 if (!input.IsValid())
1100 {
1101 return Fail("%s: Failed to read input 0", __func__);
1102 }
1103
1104 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1105 if (!output)
1106 {
1107 return Fail("%s: Failed to read output", __func__);
1108 }
1109
1110 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
1111 if (IsDynamicTensor(outputInfo))
1112 {
1113 return Fail("%s: Dynamic output tensors are not supported", __func__);
1114 }
1115
1116 // Determine data type of input tensor
1117 OperandType inputType;
1118 if (!GetOperandType<hal_1_2::HalPolicy>(operation, 0, model, inputType))
1119 {
1120 return Fail("%s: Operation has invalid inputs", __func__);
1121 }
1122
1123 LogSoftmaxDescriptor descriptor;
1124
1125 // Read beta
1126 if (inputType == OperandType::TENSOR_FLOAT16)
1127 {
1128 Half fp16Beta;
1129 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 1, OperandType::FLOAT16, fp16Beta, model, data))
1130 {
1131 return Fail("%s: Failed to read input 1 (FLOAT16)", __func__);
1132 }
1133
1134 descriptor.m_Beta = static_cast<float>(fp16Beta);
1135 }
1136 else if (inputType == OperandType::TENSOR_FLOAT32)
1137 {
1138 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 1, OperandType::FLOAT32, descriptor.m_Beta, model, data))
1139 {
1140 return Fail("%s: Failed to read input 1 (FLOAT32)", __func__);
1141 }
1142 }
1143 else
1144 {
1145 return Fail("%s: Unsupported input tensor type: %d", __func__, inputType);
1146 }
1147
1148 // Read axis
1149 if (!GetInputInt32<hal_1_2::HalPolicy>(operation, 2, descriptor.m_Axis, model, data))
1150 {
1151 return Fail("%s: Failed to read input 2", __func__);
1152 }
1153
1154 bool isSupported = false;
1155 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1156 IsLogSoftmaxSupported,
1157 data.m_Backends,
1158 isSupported,
1159 input.GetTensorInfo(),
1160 outputInfo,
1161 descriptor);
1162 if (!isSupported)
1163 {
1164 return false;
1165 }
1166
Aron Virginas-Tar3e0982b2019-10-29 14:25:09 +00001167 IConnectableLayer* layer = data.m_Network->AddLogSoftmaxLayer(descriptor);
Aron Virginas-Tar75e67792019-10-15 13:33:03 +01001168 if (!layer)
1169 {
1170 return Fail("%s: AddLogSoftmaxLayer() returned nullptr", __func__);
1171 }
1172
1173 input.Connect(layer->GetInputSlot(0));
1174
1175 return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data);
1176}
1177
Sadik Armagan15d63e22019-07-26 16:59:35 +01001178bool HalPolicy::ConvertMaxPool2d(const Operation& operation, const Model& model, ConversionData& data)
1179{
1180 ALOGV("hal_1_2::HalPolicy::ConvertMaxPool2d()");
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001181 return ConvertPooling2d<hal_1_2::HalPolicy>(operation, __func__, PoolingAlgorithm::Max, model, data);
Sadik Armagan15d63e22019-07-26 16:59:35 +01001182}
1183
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +01001184bool HalPolicy::ConvertMaximum(const Operation& operation, const Model& model, ConversionData& data)
1185{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001186 ALOGV("hal_1_2::HalPolicy::ConvertMaximum()");
1187
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +01001188 LayerInputHandle input0 = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
1189 LayerInputHandle input1 = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 1, model, data);
1190
1191 if (!input0.IsValid() || !input1.IsValid())
1192 {
1193 return Fail("%s: Operation has invalid inputs", __func__);
1194 }
1195
1196 const Operand* outputOperand = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1197 if (!outputOperand)
1198 {
1199 return Fail("%s: Could not read output", __func__);
1200 }
1201
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001202 const TensorInfo& outInfo = GetTensorInfoForOperand(*outputOperand);
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +01001203 if (IsDynamicTensor(outInfo))
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +01001204 {
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001205 return Fail("%s: Dynamic output tensors are not supported", __func__);
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +01001206 }
1207
Aron Virginas-Tard7593232019-07-16 13:17:06 +01001208 bool isSupported = false;
1209 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1210 IsMaximumSupported,
1211 data.m_Backends,
1212 isSupported,
1213 input0.GetTensorInfo(),
1214 input1.GetTensorInfo(),
1215 outInfo);
1216
1217 if (!isSupported)
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +01001218 {
1219 return false;
1220 }
1221
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001222 IConnectableLayer* layer = data.m_Network->AddMaximumLayer();
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +01001223 assert(layer != nullptr);
Sadik Armagan64b19b52019-08-19 09:49:58 +01001224 bool isReshapeSupported = BroadcastTensor(input0, input1, layer, data);
1225 if (!isReshapeSupported)
1226 {
1227 return false;
1228 }
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +01001229
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001230 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
Narumol Prangnawarat95b1ef62019-07-15 12:02:20 +01001231}
1232
Mike Kelly46272802019-08-14 17:00:48 +01001233bool HalPolicy::ConvertMean(const Operation& operation, const Model& model, ConversionData& data)
1234{
1235 ALOGV("hal_1_2::HalPolicy::ConvertMean()");
1236 return ::ConvertMean<hal_1_2::HalPolicy>(operation, model, data);
1237}
1238
Ellen Norris-Thompson1cb29aa2019-07-11 17:27:37 +01001239bool HalPolicy::ConvertMinimum(const Operation& operation, const Model& model, ConversionData& data)
1240{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001241 ALOGV("hal_1_2::HalPolicy::ConvertMinimum()");
1242
Ellen Norris-Thompson1cb29aa2019-07-11 17:27:37 +01001243 LayerInputHandle input0 = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
1244 LayerInputHandle input1 = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 1, model, data);
1245
1246 if (!input0.IsValid() || !input1.IsValid())
1247 {
1248 return Fail("%s: Operation has invalid inputs", __func__);
1249 }
1250
1251 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1252 if (!output)
1253 {
1254 return Fail("%s: Could not read output 0", __func__);
1255 }
1256
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001257 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +01001258 if (IsDynamicTensor(outputInfo))
Ellen Norris-Thompson1cb29aa2019-07-11 17:27:37 +01001259 {
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001260 return Fail("%s: Dynamic output tensors are not supported", __func__);
Ellen Norris-Thompson1cb29aa2019-07-11 17:27:37 +01001261 }
1262
1263 bool isSupported = false;
1264 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1265 IsMinimumSupported,
1266 data.m_Backends,
1267 isSupported,
1268 input0.GetTensorInfo(),
1269 input1.GetTensorInfo(),
1270 outputInfo);
1271
1272 if (!isSupported)
1273 {
1274 return false;
1275 }
1276
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001277 IConnectableLayer* const layer = data.m_Network->AddMinimumLayer();
Ellen Norris-Thompson1cb29aa2019-07-11 17:27:37 +01001278 assert(layer != nullptr);
Sadik Armagan64b19b52019-08-19 09:49:58 +01001279 bool isReshapeSupported = BroadcastTensor(input0, input1, layer, data);
1280 if (!isReshapeSupported)
1281 {
1282 return false;
1283 }
Ellen Norris-Thompson1cb29aa2019-07-11 17:27:37 +01001284
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001285 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
Ellen Norris-Thompson1cb29aa2019-07-11 17:27:37 +01001286}
1287
Mike Kelly46272802019-08-14 17:00:48 +01001288bool HalPolicy::ConvertMul(const Operation& operation, const Model& model, ConversionData& data)
1289{
1290 ALOGV("hal_1_2::HalPolicy::ConvertMul()");
1291 return ::ConvertMul<hal_1_2::HalPolicy>(operation, model, data);
1292}
1293
Aron Virginas-Tarc921f6b2019-07-25 10:14:33 +01001294bool HalPolicy::ConvertPad(const Operation& operation, const Model& model, ConversionData& data)
1295{
1296 ALOGV("hal_1_2::HalPolicy::ConvertPad()");
1297 return ::ConvertPad<hal_1_2::HalPolicy>(operation, model, data);
1298}
1299
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001300bool HalPolicy::ConvertPadV2(const Operation& operation, const Model& model, ConversionData& data)
1301{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001302 ALOGV("hal_1_2::HalPolicy::ConvertPadV2()");
1303
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001304 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
1305 if (!input.IsValid())
1306 {
1307 return Fail("%s: Could not read input 0", __func__);
1308 }
1309
Aron Virginas-Tar366e0a62019-07-10 13:01:41 +01001310 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1311 if (!output)
1312 {
1313 return Fail("%s: Could not read output", __func__);
1314 }
1315
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001316 const TensorInfo& inputInfo = input.GetTensorInfo();
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001317 unsigned int rank = inputInfo.GetNumDimensions();
1318
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001319 PadDescriptor descriptor;
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001320 if (!ConvertPaddings<hal_1_2::HalPolicy>(operation, model, data, rank, descriptor))
1321 {
1322 return Fail("%s: Could not convert paddings", __func__);
1323 }
1324
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001325 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +01001326 if (IsDynamicTensor(outputInfo))
Sadik Armagan310d8ff2019-07-11 10:53:38 +01001327 {
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001328 return Fail("%s: Dynamic output tensors are not supported", __func__);
Sadik Armagan310d8ff2019-07-11 10:53:38 +01001329 }
1330
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001331 // Determine type of padding value
1332 OperandType operandType0;
1333 OperandType operandType2;
1334
1335 if (!GetOperandType<hal_1_2::HalPolicy>(operation, 0, model, operandType0) ||
1336 !GetOperandType<hal_1_2::HalPolicy>(operation, 2, model, operandType2))
1337 {
1338 return Fail("%s: Operation has invalid inputs", __func__);
1339 }
1340
1341 // Read value to use for padding
1342 if (operandType0 == OperandType::TENSOR_FLOAT16 && operandType2 == OperandType::FLOAT16)
1343 {
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001344 Half f16PadValue;
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001345 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 2, operandType2, f16PadValue, model, data))
1346 {
1347 return Fail("%s: Could not read input 2 (FLOAT16)", __func__);
1348 }
1349
1350 descriptor.m_PadValue = f16PadValue;
1351 }
1352 else if (operandType0 == OperandType::TENSOR_FLOAT32 && operandType2 == OperandType::FLOAT32)
1353 {
1354 if (!GetInputFloat32<hal_1_2::HalPolicy>(operation, 2, descriptor.m_PadValue, model, data))
1355 {
1356 return Fail("%s: Could not read input 2 (FLOAT32)", __func__);
1357 }
1358 }
1359 else if (operandType0 == OperandType::TENSOR_QUANT8_ASYMM && operandType2 == OperandType::INT32)
1360 {
Mike Kelly3c673942019-07-25 09:26:06 +01001361 int32_t intPadValue = 0;
1362 if (!GetInputInt32<hal_1_2::HalPolicy>(operation, 2, intPadValue, model, data))
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001363 {
1364 return Fail("%s: Could not read input 2 (INT32)", __func__);
1365 }
Mike Kelly3c673942019-07-25 09:26:06 +01001366 descriptor.m_PadValue = intPadValue;
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001367 }
1368 else
1369 {
1370 return Fail("%s: Operation has invalid inputs: type mismatch", __func__);
1371 }
1372
Ferran Balaguerd30093c2019-07-09 17:04:47 +01001373 bool isSupported = false;
1374 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1375 IsPadSupported,
1376 data.m_Backends,
1377 isSupported,
1378 inputInfo,
1379 outputInfo,
1380 descriptor);
1381 if (!isSupported)
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001382 {
1383 return false;
1384 }
1385
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001386 IConnectableLayer* const layer = data.m_Network->AddPadLayer(descriptor);
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001387 assert(layer != nullptr);
1388 input.Connect(layer->GetInputSlot(0));
1389 layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1390
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001391 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
Aron Virginas-Tarcb8ac842019-07-05 15:47:07 +01001392}
1393
Matteo Martincigh17ffff32019-06-27 14:12:55 +01001394bool HalPolicy::ConvertPrelu(const Operation& operation, const Model& model, ConversionData& data)
1395{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001396 ALOGV("hal_1_2::HalPolicy::ConvertPrelu()");
1397
Matteo Martincigh17ffff32019-06-27 14:12:55 +01001398 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
1399 LayerInputHandle alpha = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 1, model, data);
1400
1401 if (!input.IsValid() || !alpha.IsValid())
1402 {
1403 return Fail("%s: Operation has invalid inputs", __func__);
1404 }
1405
1406 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1407
1408 if (!output)
1409 {
Matteo Martincigh0bd89a82019-07-02 16:53:10 +01001410 return Fail("%s: Could not read output", __func__);
Matteo Martincigh17ffff32019-06-27 14:12:55 +01001411 }
1412
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001413 const TensorInfo& inputInfo = input.GetTensorInfo();
1414 const TensorInfo& alphaInfo = alpha.GetTensorInfo();
1415 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tarf03fcf02019-07-09 17:44:24 +01001416
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +01001417 if (IsDynamicTensor(outputInfo))
Aron Virginas-Tarf03fcf02019-07-09 17:44:24 +01001418 {
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001419 return Fail("%s: Dynamic output tensors are not supported", __func__);
Aron Virginas-Tarf03fcf02019-07-09 17:44:24 +01001420 }
Matteo Martincigh17ffff32019-06-27 14:12:55 +01001421
Ferran Balaguerd30093c2019-07-09 17:04:47 +01001422 bool isSupported = false;
1423 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1424 IsPreluSupported,
1425 data.m_Backends,
1426 isSupported,
1427 inputInfo,
1428 alphaInfo,
1429 outputInfo);
1430 if (!isSupported)
Matteo Martincigh17ffff32019-06-27 14:12:55 +01001431 {
1432 return false;
1433 }
1434
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001435 IConnectableLayer* const layer = data.m_Network->AddPreluLayer();
Matteo Martincigh17ffff32019-06-27 14:12:55 +01001436
1437 if (!layer)
1438 {
1439 return Fail("%s: AddPreluLayer failed", __func__);
1440 }
1441
Sadik Armagan64b19b52019-08-19 09:49:58 +01001442 bool isReshapeSupported = BroadcastTensor(input, alpha, layer, data);
1443 if (!isReshapeSupported)
1444 {
1445 return false;
1446 }
Matteo Martincigh17ffff32019-06-27 14:12:55 +01001447
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001448 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
Matteo Martincigh17ffff32019-06-27 14:12:55 +01001449}
1450
Sadik Armagan5a476a82019-07-30 09:43:18 +01001451bool HalPolicy::ConvertQuantize(const Operation& operation, const Model& model, ConversionData& data)
1452{
1453 ALOGV("hal_1_2::HalPolicy::ConvertQuantize()");
1454
1455 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
1456 if (!input.IsValid())
1457 {
1458 return Fail("%s: Operation has invalid input", __func__);
1459 }
1460
1461 const Operand* const outputOperand = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1462 if (!outputOperand)
1463 {
1464 return Fail("%s: Operation has invalid outputs", __func__);
1465 }
1466
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001467 const TensorInfo& outputInfo = GetTensorInfoForOperand(*outputOperand);
Sadik Armagan5a476a82019-07-30 09:43:18 +01001468 if (IsDynamicTensor(outputInfo))
1469 {
1470 return Fail("%s: Dynamic output tensors are not supported", __func__);
1471 }
1472
1473 bool isSupported = false;
1474 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1475 IsQuantizeSupported,
1476 data.m_Backends,
1477 isSupported,
1478 input.GetTensorInfo(),
1479 outputInfo);
1480 if (!isSupported)
1481 {
1482 return false;
1483 }
1484
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001485 IConnectableLayer* const layer = data.m_Network->AddQuantizeLayer();
Sadik Armagan5a476a82019-07-30 09:43:18 +01001486 assert(layer != nullptr);
1487 input.Connect(layer->GetInputSlot(0));
1488
1489 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
1490}
1491
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001492bool HalPolicy::ConvertQuantizedLstm(const Operation& operation, const Model& model, ConversionData& data)
1493{
1494 ALOGV("hal_1_2::HalPolicy::ConvertQuantizedLstm()");
1495
1496 //Inputs:
1497 // 0: The input: A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape [numBatches, inputSize]
1498 // specifying the input to the LSTM cell. Tensor is quantized with a fixed quantization range of -1, 127/128.
1499 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
1500 if (!input.IsValid())
1501 {
1502 return Fail("%s: Could not read input 0: input", __func__);
1503 }
1504
1505 //13: The previous cell state: A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT16_SYMM and shape
1506 // [numBatches, outputSize] specifying the cell state from the previous time step of the LSTM cell.
1507 // It is quantized using a quantization range of -2^4, 2^4 * 32767/32768.
1508 LayerInputHandle previousCellStateIn = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 13, model, data);
1509 if (!previousCellStateIn.IsValid())
1510 {
1511 return Fail("%s: Could not read input 13: previousCellStateIn", __func__);
1512 }
1513
1514 // 14: The previous output state: A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape
1515 // [numBathes, outputSize] specifying the output of the LSTM cell from previous time-step. Tensor
1516 // is quantized with a fixed quantization range of -1, 127/128.
1517 LayerInputHandle previousOutputIn = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 14, model, data);
1518 if (!previousOutputIn.IsValid())
1519 {
1520 return Fail("%s: Could not read input 14: previousOutputIn", __func__);
1521 }
1522
1523 // Get the input tensors:
1524 // 1: The input-to-input weights. A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape
1525 // [outputSize, inputSize] specifying input-to-input part of weights for fully-connected layer inside the
1526 // LSTM cell. Quantization zero point and scale must be the same across all the weights.
1527 const ConstTensorPin inputToInputWeightsPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001528 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 1, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001529
1530 // 2: The input-to-forget weights. A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape
1531 // [outputSize, inputSize] specifying input-to-forget part of weights for fully-connected layer inside the
1532 // LSTM cell. Quantization zero point and scale must be the same across all the weights.
1533 const ConstTensorPin inputToForgetWeightsPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001534 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 2, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001535
1536 // 3: The input-to-cell weights. A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape
1537 // [outputSize, inputSize] specifying input-to-cell part of weights for fully-connected layer inside the
1538 // LSTM cell. Quantization zero point and scale must be the same across all the weights.
1539 const ConstTensorPin inputToCellWeightsPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001540 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 3, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001541
1542 // 4: The input-to-output weights. A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape
1543 // [outputSize, inputSize] specifying input-to-output part of weights for fully-connected layer inside the
1544 // LSTM cell. Quantization zero point and scale must be the same across all the weights.
1545 const ConstTensorPin inputToOutputWeightsPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001546 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 4, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001547
1548 // 5: The recurrent-to-input weights. A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape
1549 // [outputSize, outputSize] specifying recurrent-to-input part of weights for fully-connected layer inside
1550 // the LSTM cell. Quantization zero point and scale must be the same across all the weights.
1551 const ConstTensorPin recurrentToInputWeightsPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001552 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 5, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001553
1554 // 6: The recurrent-to-forget weights. A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape
1555 // [outputSize, outputSize] specifying recurrent-to-forget part of weights for fully-connected layer inside
1556 // the LSTM cell. Quantization zero point and scale must be the same across all the weights.
1557 const ConstTensorPin recurrentToForgetWeightsPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001558 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 6, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001559
1560 // 7: The recurrent-to-cell weights. A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape
1561 // [outputSize, outputSize] specifying recurrent-to-cell part of weights for fully-connected layer inside
1562 // the LSTM cell. Quantization zero point and scale must be the same across all the weights.
1563 const ConstTensorPin recurrentToCellWeightsPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001564 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 7, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001565
1566 // 8: The recurrent-to-output weights. A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape
1567 // [outputSize, outputSize] specifying recurrent-to-output part of weights for fully-connected layer inside
1568 // the LSTM cell. Quantization zero point and scale must be the same across all the weights.
1569 const ConstTensorPin recurrentToOutputWeightsPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001570 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 8, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001571
1572 // 9: The input gate bias. A 1-D tensor of type ANEURALNETWORKS_TENSOR_INT32 and shape [outputSize] specifying the
1573 // bias for the fully-connected layer inside the LSTM cell. Bias is quantized with scale being a product
1574 // of input and weights scales and zeroPoint equal to 0.
1575 const ConstTensorPin inputGateBiasPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001576 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 9, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001577
1578 // 10: The forget gate bias. A 1-D tensor of type ANEURALNETWORKS_TENSOR_INT32 and shape [outputSize] specifying
1579 // the bias for the fully-connected layer inside the LSTM cell. Bias is quantized with scale being a product
1580 // of input and weights scales and zeroPoint equal to 0.
1581 const ConstTensorPin forgetGateBiasPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001582 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 10, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001583
1584 // 11:The cell bias. A 1-D tensor of type ANEURALNETWORKS_TENSOR_INT32 and shape [outputSize] specifying the bias
1585 // for the fully-connected layer inside the LSTM cell. Bias is quantized with scale being a product of input
1586 // and weights scales and zeroPoint equal to 0.
1587 const ConstTensorPin cellBiasPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001588 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 11, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001589
1590 // 12:The output gate bias. A 1-D tensor of type ANEURALNETWORKS_TENSOR_INT32 and shape [outputSize] specifying
1591 // the bias for the fully-connected layer inside the LSTM cell. Bias is quantized with scale being a product
1592 // of input and weights scales and zeroPoint equal to 0.
1593 const ConstTensorPin outputGateBiasPin =
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001594 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 12, model, data);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001595
1596 if (!inputToInputWeightsPin.IsValid() ||
1597 !inputToForgetWeightsPin.IsValid() ||
1598 !inputToCellWeightsPin.IsValid() ||
1599 !inputToOutputWeightsPin.IsValid() ||
1600 !recurrentToInputWeightsPin.IsValid() ||
1601 !recurrentToForgetWeightsPin.IsValid() ||
1602 !recurrentToCellWeightsPin.IsValid() ||
1603 !recurrentToOutputWeightsPin.IsValid() ||
1604 !inputGateBiasPin.IsValid() ||
1605 !forgetGateBiasPin.IsValid() ||
1606 !cellBiasPin.IsValid() ||
1607 !outputGateBiasPin.IsValid())
1608 {
1609 return Fail("%s: Operation has invalid tensor inputs", __func__);
1610 }
1611
1612 // Outputs:
1613 // 0: The cell state: A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT16_SYMM and shape [numBatches, outputSize]
1614 // which contains a cell state from the current time step. Tensor is quantized using a quantization range
1615 // of -2^4, 2^4 * 32767/32768.
1616 const Operand* cellStateOut = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1617 if (!cellStateOut)
1618 {
1619 return Fail("%s: Could not read output 0: cellStateOut", __func__);
1620 }
1621
1622 // 1: The output: A 2-D tensor of type ANEURALNETWORKS_TENSOR_QUANT8_ASYMM and shape [numBathes, outputSize] which
1623 // contains the output value. Tensor is quantized with a fixed quantization range of -1, 127/128.
1624 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 1, model);
1625 if (!output)
1626 {
1627 return Fail("%s: Could not read output 1: output", __func__);
1628 }
1629
1630 // Inputs
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001631 const TensorInfo& inputInfo = input.GetTensorInfo();
1632 const TensorInfo& previousCellStateInInfo = previousCellStateIn.GetTensorInfo();
1633 const TensorInfo& previousOutputInInfo = previousOutputIn.GetTensorInfo();
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001634
1635 // Outputs
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001636 const TensorInfo& cellStateOutInfo = GetTensorInfoForOperand(*cellStateOut);
1637 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001638
1639 // Dynamic tensors currently not supported
1640 if (IsDynamicTensor(cellStateOutInfo) || IsDynamicTensor(outputInfo))
1641 {
1642 return Fail("%s: Dynamic output tensors are not supported", __func__);
1643 }
1644
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001645 QuantizedLstmInputParams params;
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001646
1647 params.m_InputToInputWeights = inputToInputWeightsPin.GetConstTensorPtr();
1648 params.m_InputToForgetWeights = inputToForgetWeightsPin.GetConstTensorPtr();
1649 params.m_InputToCellWeights = inputToCellWeightsPin.GetConstTensorPtr();
1650 params.m_InputToOutputWeights = inputToOutputWeightsPin.GetConstTensorPtr();
1651 params.m_RecurrentToInputWeights = recurrentToInputWeightsPin.GetConstTensorPtr();
1652 params.m_RecurrentToForgetWeights = recurrentToForgetWeightsPin.GetConstTensorPtr();
1653 params.m_RecurrentToCellWeights = recurrentToCellWeightsPin.GetConstTensorPtr();
1654 params.m_RecurrentToOutputWeights = recurrentToOutputWeightsPin.GetConstTensorPtr();
1655 params.m_InputGateBias = inputGateBiasPin.GetConstTensorPtr();
1656 params.m_ForgetGateBias = forgetGateBiasPin.GetConstTensorPtr();
1657 params.m_CellBias = cellBiasPin.GetConstTensorPtr();
1658 params.m_OutputGateBias = outputGateBiasPin.GetConstTensorPtr();
1659
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001660 QuantizedLstmInputParamsInfo paramsInfo;
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001661 paramsInfo.m_InputToInputWeights = &(params.m_InputToInputWeights->GetInfo());
1662 paramsInfo.m_InputToForgetWeights = &(params.m_InputToForgetWeights->GetInfo());
1663 paramsInfo.m_InputToCellWeights = &(params.m_InputToCellWeights->GetInfo());
1664 paramsInfo.m_InputToOutputWeights = &(params.m_InputToOutputWeights->GetInfo());
1665 paramsInfo.m_RecurrentToInputWeights = &(params.m_RecurrentToInputWeights->GetInfo());
1666 paramsInfo.m_RecurrentToForgetWeights = &(params.m_RecurrentToForgetWeights->GetInfo());
1667 paramsInfo.m_RecurrentToCellWeights = &(params.m_RecurrentToCellWeights->GetInfo());
1668 paramsInfo.m_RecurrentToOutputWeights = &(params.m_RecurrentToOutputWeights->GetInfo());
1669 paramsInfo.m_InputGateBias = &(params.m_InputGateBias->GetInfo());
1670 paramsInfo.m_ForgetGateBias = &(params.m_ForgetGateBias->GetInfo());
1671 paramsInfo.m_CellBias = &(params.m_CellBias->GetInfo());
1672 paramsInfo.m_OutputGateBias = &(params.m_OutputGateBias->GetInfo());
1673
1674 bool isSupported = false;
1675 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1676 IsQuantizedLstmSupported,
1677 data.m_Backends,
1678 isSupported,
1679 inputInfo,
1680 previousCellStateInInfo,
1681 previousOutputInInfo,
1682 cellStateOutInfo,
1683 outputInfo,
1684 paramsInfo);
1685
1686 if (!isSupported)
1687 {
1688 return false;
1689 }
1690
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001691 IConnectableLayer* const layer = data.m_Network->AddQuantizedLstmLayer(params, "QuantizedLstm");
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001692 input.Connect(layer->GetInputSlot(0));
Ellen Norris-Thompsona3d7fad2019-08-05 14:20:32 +01001693 previousCellStateIn.Connect(layer->GetInputSlot(1));
1694 previousOutputIn.Connect(layer->GetInputSlot(2));
Ellen Norris-Thompson7efb46d2019-07-24 17:39:19 +01001695
1696 return (SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, 0, model, data) &&
1697 SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 1, *layer, 1, model, data));
1698}
1699
Sadik Armagan61113162019-07-25 09:09:40 +01001700bool HalPolicy::ConvertReLu(const Operation& operation, const Model& model, ConversionData& data)
1701{
1702 ALOGV("hal_1_2::HalPolicy::ConvertReLu()");
1703 return ::ConvertReLu<hal_1_2::HalPolicy>(operation, model, data);
1704}
1705
1706bool HalPolicy::ConvertReLu1(const Operation& operation, const Model& model, ConversionData& data)
1707{
1708 ALOGV("hal_1_2::HalPolicy::ConvertReLu1()");
1709 return ::ConvertReLu1<hal_1_2::HalPolicy>(operation, model, data);
1710}
1711
1712bool HalPolicy::ConvertReLu6(const Operation& operation, const Model& model, ConversionData& data)
1713{
1714 ALOGV("hal_1_2::HalPolicy::ConvertReLu6()");
1715 return ::ConvertReLu6<hal_1_2::HalPolicy>(operation, model, data);
1716}
1717
Mike Kelly46272802019-08-14 17:00:48 +01001718bool HalPolicy::ConvertReshape(const Operation& operation, const Model& model, ConversionData& data)
1719{
1720 ALOGV("hal_1_2::HalPolicy::ConvertReshape()");
1721 return ::ConvertReshape<hal_1_2::HalPolicy>(operation, model, data);
1722}
1723
Aron Virginas-Tarfb2fa292019-07-04 11:59:48 +01001724bool HalPolicy::ConvertResize(const Operation& operation,
1725 const Model& model,
1726 ConversionData& data,
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001727 ResizeMethod resizeMethod)
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +01001728{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001729 ALOGV("hal_1_2::HalPolicy::ConvertResize()");
Aron Virginas-Tar7d2ccfd2019-10-29 14:03:51 +00001730 ALOGV("resizeMethod = %s", GetResizeMethodAsCString(resizeMethod));
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001731
1732 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +01001733 if (!input.IsValid())
1734 {
1735 return Fail("%s: Could not read input 0", __func__);
1736 }
1737
1738 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1739 if (!output)
1740 {
1741 return Fail("%s: Could not read output 0", __func__);
1742 }
1743
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001744 const TensorInfo& inputInfo = input.GetTensorInfo();
1745 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001746
1747 if (IsDynamicTensor(outputInfo))
1748 {
1749 return Fail("%s: Dynamic output tensors are not supported", __func__);
1750 }
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +01001751
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001752 ResizeDescriptor descriptor;
Aron Virginas-Tarfb2fa292019-07-04 11:59:48 +01001753 descriptor.m_Method = resizeMethod;
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +01001754 descriptor.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 3, model, data);
1755
1756 OperandType operandType1;
1757 OperandType operandType2;
1758
1759 if (!GetOperandType<hal_1_2::HalPolicy>(operation, 1, model, operandType1) ||
1760 !GetOperandType<hal_1_2::HalPolicy>(operation, 2, model, operandType2))
1761 {
1762 return Fail("%s: Operation has invalid inputs", __func__);
1763 }
1764
1765 if (operandType1 != operandType2)
1766 {
1767 return Fail("%s: Operation has invalid inputs. Type of input 1 and 2 should be the same", __func__);
1768 }
1769
1770 if (operandType1 == OperandType::INT32)
1771 {
1772 // Case 1: resizing by shape
1773 int32_t targetWidth = 0;
1774 int32_t targetHeight = 0;
1775
1776 if (!GetInputInt32<hal_1_2::HalPolicy>(operation, 1, targetWidth, model, data) ||
1777 !GetInputInt32<hal_1_2::HalPolicy>(operation, 2, targetHeight, model, data))
1778 {
1779 return Fail("%s: Operation has invalid inputs for resizing by shape", __func__);
1780 }
1781
1782 if (targetWidth < 0 || targetHeight < 0)
1783 {
1784 return Fail("%s: Operation has invalid inputs for resizing by shape. "
1785 "Target width/height cannot be < 0", __func__);
1786 }
1787
1788 descriptor.m_TargetWidth = static_cast<uint32_t>(targetWidth);
Teresa Charlin9843c012019-07-19 12:18:35 +01001789 descriptor.m_TargetHeight = static_cast<uint32_t>(targetHeight);
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +01001790 }
1791 else if (operandType1 == OperandType::FLOAT32)
1792 {
1793 // Case 2: resizing by scale
1794 float widthScale = 1.0f;
1795 float heightScale = 1.0f;
1796
1797 if (!GetInputFloat32<hal_1_2::HalPolicy>(operation, 1, widthScale, model, data) ||
1798 !GetInputFloat32<hal_1_2::HalPolicy>(operation, 2, heightScale, model, data))
1799 {
1800 return Fail("%s: Operation has invalid inputs for resizing by scale", __func__);
1801 }
1802
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001803 const TensorShape& inputShape = inputInfo.GetShape();
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +01001804 armnnUtils::DataLayoutIndexed dataLayoutIndexed(descriptor.m_DataLayout);
1805
1806 float width = inputShape[dataLayoutIndexed.GetWidthIndex()];
1807 float height = inputShape[dataLayoutIndexed.GetHeightIndex()];
1808
1809 descriptor.m_TargetWidth = std::floor(width * widthScale);
1810 descriptor.m_TargetHeight = std::floor(height * heightScale);
1811 }
1812 else
1813 {
1814 // NOTE: FLOAT16 scales are not supported
1815 return false;
1816 }
1817
Ferran Balaguerd30093c2019-07-09 17:04:47 +01001818 bool isSupported = false;
1819 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1820 IsResizeSupported,
1821 data.m_Backends,
1822 isSupported,
1823 inputInfo,
1824 outputInfo,
1825 descriptor);
Aron Virginas-Tarbe5d3562019-07-16 11:32:29 +01001826
Ferran Balaguerd30093c2019-07-09 17:04:47 +01001827 if (!isSupported)
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +01001828 {
1829 return false;
1830 }
1831
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001832 IConnectableLayer* layer = data.m_Network->AddResizeLayer(descriptor);
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +01001833
1834 assert(layer != nullptr);
1835
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +01001836 input.Connect(layer->GetInputSlot(0));
1837
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001838 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
Aron Virginas-Tar7a6d11b2019-07-03 15:27:08 +01001839}
1840
Aron Virginas-Tarfa6544e2019-09-10 14:42:22 +01001841bool HalPolicy::ConvertRsqrt(const Operation& operation, const Model& model, ConversionData& data)
1842{
1843 ALOGV("hal_1_2::HalPolicy::ConvertRsqrt()");
1844
1845 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
1846 if (!input.IsValid())
1847 {
1848 return Fail("%s: Operation has invalid input", __func__);
1849 }
1850
1851 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1852 if (!output)
1853 {
1854 return Fail("%s: Could not read output 0", __func__);
1855 }
1856
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001857 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tarfa6544e2019-09-10 14:42:22 +01001858 if (IsDynamicTensor(outputInfo))
1859 {
1860 return Fail("%s: Dynamic output tensors are not supported", __func__);
1861 }
1862
1863 bool isSupported = false;
1864 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1865 IsRsqrtSupported,
1866 data.m_Backends,
1867 isSupported,
1868 input.GetTensorInfo(),
1869 outputInfo);
1870
1871 if (!isSupported)
1872 {
1873 return false;
1874 }
1875
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001876 IConnectableLayer* const layer = data.m_Network->AddRsqrtLayer();
Aron Virginas-Tarfa6544e2019-09-10 14:42:22 +01001877 assert(layer != nullptr);
1878 input.Connect(layer->GetInputSlot(0));
1879
1880 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
1881}
1882
Finn Williamsd74c5052019-07-30 17:06:00 +01001883bool HalPolicy::ConvertSpaceToBatchNd(const Operation& operation, const Model& model, ConversionData& data)
1884{
1885 ALOGV("hal_1_2::HalPolicy::ConvertSpaceToBatchNd()");
1886 return ::ConvertSpaceToBatchNd<hal_1_2::HalPolicy>(operation, model, data);
1887}
1888
Keith Davisa6bc52f2019-06-26 09:39:49 +01001889bool HalPolicy::ConvertSpaceToDepth(const Operation& operation, const Model& model, ConversionData& data)
1890{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001891 ALOGV("hal_1_2::HalPolicy::ConvertSpaceToDepth()");
Keith Davisa6bc52f2019-06-26 09:39:49 +01001892
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001893 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
Keith Davisa6bc52f2019-06-26 09:39:49 +01001894 if (!input.IsValid() )
1895 {
1896 return Fail("%s: Operation has invalid inputs", __func__);
1897 }
1898
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001899 const TensorInfo& inputInfo = input.GetTensorInfo();
Keith Davisa6bc52f2019-06-26 09:39:49 +01001900 unsigned int rank = inputInfo.GetNumDimensions();
Keith Davisa6bc52f2019-06-26 09:39:49 +01001901 if (rank != 4)
1902 {
1903 return Fail("%s: Only inputs with rank 4 are supported", __func__);
1904 }
1905
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001906 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1907 if (!output)
1908 {
1909 return Fail("%s: Could not read output 0", __func__);
1910 }
1911
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001912 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001913 if (IsDynamicTensor(outputInfo))
1914 {
1915 return Fail("%s: Dynamic output tensors are not supported", __func__);
1916 }
1917
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001918 SpaceToDepthDescriptor desc;
Keith Davisa6bc52f2019-06-26 09:39:49 +01001919
1920 GetInputScalar<hal_1_2::HalPolicy>(operation, 1, OperandType::INT32, desc.m_BlockSize, model, data);
1921
1922 if (desc.m_BlockSize <= 1)
1923 {
1924 return Fail("%s: Block size must be at least 1 in all dimensions");
1925 }
1926
1927 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 2, model, data);
1928
Ferran Balaguerd30093c2019-07-09 17:04:47 +01001929 bool isSupported = false;
1930 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1931 IsSpaceToDepthSupported,
1932 data.m_Backends,
1933 isSupported,
1934 inputInfo,
1935 outputInfo,
1936 desc);
1937 if (!isSupported)
Keith Davisa6bc52f2019-06-26 09:39:49 +01001938 {
1939 return false;
1940 }
1941
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001942 IConnectableLayer* const layer = data.m_Network->AddSpaceToDepthLayer(desc);
Keith Davisa6bc52f2019-06-26 09:39:49 +01001943 assert(layer != nullptr);
1944 input.Connect(layer->GetInputSlot(0));
1945
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001946 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
Keith Davisa6bc52f2019-06-26 09:39:49 +01001947}
1948
Francis Murtagh074c25a2019-07-22 16:40:57 +01001949bool HalPolicy::ConvertSoftmax(const Operation& operation, const Model& model, ConversionData& data)
1950{
Aron Virginas-Tar29404fb2019-07-24 13:55:31 +01001951 ALOGV("hal_1_2::HalPolicy::ConvertSoftmax()");
1952
Francis Murtagh074c25a2019-07-22 16:40:57 +01001953 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
1954 if (!input.IsValid())
1955 {
1956 return Fail("%s: Operation has invalid inputs", __func__);
1957 }
1958
1959 const Operand* outputOperand = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
1960 if (!outputOperand)
1961 {
1962 return Fail("%s: Operation has no outputs", __func__);
1963 }
1964
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001965 const TensorInfo& outputInfo = GetTensorInfoForOperand(*outputOperand);
Aron Virginas-Tar573a8fa2019-07-23 14:01:37 +01001966 if (IsDynamicTensor(outputInfo))
Francis Murtagh074c25a2019-07-22 16:40:57 +01001967 {
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01001968 return Fail("%s: Dynamic output tensors are not supported", __func__);
Francis Murtagh074c25a2019-07-22 16:40:57 +01001969 }
1970
Teresa Charlin8f6429d2019-10-01 13:10:15 +01001971 SoftmaxDescriptor desc;
Francis Murtagh074c25a2019-07-22 16:40:57 +01001972 if (!GetInputFloat32<hal_1_2::HalPolicy>(operation, 1, desc.m_Beta, model, data))
1973 {
1974 return Fail("%s: Operation has invalid inputs", __func__);
1975 }
1976
1977 if (operation.inputs.size() > 2 && !GetInputScalar<hal_1_2::HalPolicy>(operation,
1978 2,
1979 HalPolicy::OperandType::INT32,
1980 desc.m_Axis,
1981 model,
1982 data))
1983 {
1984 return Fail("%s: Operation has invalid inputs", __func__);
1985 }
1986
Narumol Prangnawarat52dc5272019-08-06 17:34:26 +01001987 if (input.GetTensorInfo().GetNumDimensions() > 2 ||
1988 !(desc.m_Axis == 1 ||
1989 (desc.m_Axis < 0 && static_cast<int>(input.GetTensorInfo().GetNumDimensions()) + desc.m_Axis == 1)))
1990 {
1991 return Fail("%s: Unsupported input greater than 2D or axis != 1", __func__);
1992 }
1993
Francis Murtagh074c25a2019-07-22 16:40:57 +01001994 bool isSupported = false;
1995 FORWARD_LAYER_SUPPORT_FUNC(__func__,
1996 IsSoftmaxSupported,
1997 data.m_Backends,
1998 isSupported,
1999 input.GetTensorInfo(),
2000 outputInfo,
2001 desc);
2002 if (!isSupported)
2003 {
2004 return false;
2005 }
2006
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002007 IConnectableLayer* layer = data.m_Network->AddSoftmaxLayer(desc);
Francis Murtagh074c25a2019-07-22 16:40:57 +01002008 assert(layer != nullptr);
2009 input.Connect(layer->GetInputSlot(0));
2010
Aron Virginas-Tarb7421e52019-07-26 13:14:39 +01002011 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, model, data);
Francis Murtagh074c25a2019-07-22 16:40:57 +01002012}
2013
Mike Kelly0a879362019-07-29 16:56:31 +01002014bool HalPolicy::ConvertSub(const Operation& operation, const Model& model, ConversionData& data)
2015{
2016 ALOGV("hal_1_2::HalPolicy::ConvertSub()");
2017 return ::ConvertSub<hal_1_2::HalPolicy>(operation, model, data);
2018}
2019
Sadik Armagan61113162019-07-25 09:09:40 +01002020bool HalPolicy::ConvertTanH(const Operation& operation, const Model& model, ConversionData& data)
2021{
2022 ALOGV("hal_1_2::HalPolicy::ConvertTanH()");
2023 return ::ConvertTanH<hal_1_2::HalPolicy>(operation, model, data);
2024}
2025
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002026bool HalPolicy::ConvertLstm(const Operation& operation, const Model& model, ConversionData& data)
2027{
Pablo Tellofb45e2f2019-10-18 16:51:57 +01002028 ALOGV("hal_1_2::HalPolicy::ConvertLstm()");
2029
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002030 // Inputs:
2031 // 00: The input: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, input_size], where
2032 // “batch_size” corresponds to the batching dimension, and “input_size” is the size of the input.
2033 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
2034 if (!input.IsValid())
2035 {
2036 return Fail("%s: Could not read input 0: input", __func__);
2037 }
2038 // 18: The output state: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, output_size].
2039 LayerInputHandle outputStateIn = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 18, model, data);
2040 if (!outputStateIn.IsValid())
2041 {
2042 return Fail("%s: Could not read input 18: outputStateIn", __func__);
2043 }
2044 // 19: The cell state: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, num_units].
2045 LayerInputHandle cellStateIn = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 19, model, data);
2046 if (!cellStateIn.IsValid())
2047 {
2048 return Fail("%s: Could not read input 19: cellStateIn", __func__);
2049 }
2050
2051 // Get the mandatory input tensors:
2052 // 02: The input-to-forget weights: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
2053 // [num_units, input_size].
2054 const ConstTensorPin inputToForgetWeightsPin =
Pablo Tellofb45e2f2019-10-18 16:51:57 +01002055 (DequantizeAndMakeConstTensorPin<hal_1_2::HalPolicy>(operation, model, data, 2));
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002056 // 03: The input-to-cell weights: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
2057 // [num_units, input_size].
2058 const ConstTensorPin inputToCellWeightsPin =
Pablo Tellofb45e2f2019-10-18 16:51:57 +01002059 (DequantizeAndMakeConstTensorPin<hal_1_2::HalPolicy>(operation, model, data, 3));
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002060 // 04: The input-to-output weights: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
2061 // [num_units, input_size].
2062 const ConstTensorPin inputToOutputWeightsPin =
Pablo Tellofb45e2f2019-10-18 16:51:57 +01002063 (DequantizeAndMakeConstTensorPin<hal_1_2::HalPolicy>(operation, model, data, 4));
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002064 // 06: The recurrent-to-forget weights: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
2065 // [num_units, output_size].
2066 const ConstTensorPin recurrentToForgetWeightsPin =
Pablo Tellofb45e2f2019-10-18 16:51:57 +01002067 (DequantizeAndMakeConstTensorPin<hal_1_2::HalPolicy>(operation, model, data, 6));
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002068 // 07: The recurrent-to-cell weights: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
2069 // [num_units, output_size].
2070 const ConstTensorPin recurrentToCellWeightsPin =
Pablo Tellofb45e2f2019-10-18 16:51:57 +01002071 (DequantizeAndMakeConstTensorPin<hal_1_2::HalPolicy>(operation, model, data, 7));
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002072 // 08: The recurrent-to-output weights: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
2073 // [num_units, output_size].
2074 const ConstTensorPin recurrentToOutputWeightsPin =
Pablo Tellofb45e2f2019-10-18 16:51:57 +01002075 (DequantizeAndMakeConstTensorPin<hal_1_2::HalPolicy>(operation, model, data, 8));
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002076 // 13: The forget gate bias: A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
2077 const ConstTensorPin forgetGateBiasPin =
2078 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 13, model, data);
2079 // 14: The cell bias: A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
2080 const ConstTensorPin cellBiasPin =
2081 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 14, model, data);
2082 // 15: The output gate bias: A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
2083 const ConstTensorPin outputGateBiasPin =
2084 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 15, model, data);
2085
2086 if (!inputToForgetWeightsPin.IsValid() ||
2087 !inputToCellWeightsPin.IsValid() ||
2088 !inputToOutputWeightsPin.IsValid() ||
2089 !recurrentToForgetWeightsPin.IsValid() ||
2090 !recurrentToCellWeightsPin.IsValid() ||
2091 !recurrentToOutputWeightsPin.IsValid() ||
2092 !forgetGateBiasPin.IsValid() ||
2093 !cellBiasPin.IsValid() ||
2094 !outputGateBiasPin.IsValid())
2095 {
2096 return Fail("%s: Operation has invalid tensor inputs", __func__);
2097 }
2098
2099 // Get the optional input tensors:
2100 // 01: The input-to-input weights: Optional. A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
2101 // [num_units, input_size], where “num_units” corresponds to the number of cell units.
2102 const ConstTensorPin inputToInputWeightsPin =
Pablo Tellofb45e2f2019-10-18 16:51:57 +01002103 (DequantizeAndMakeConstTensorPin<hal_1_2::HalPolicy>(operation, model, data, 1, true));
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002104 // 05: The recurrent-to-input weights: Optional. A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
2105 // [num_units, output_size], where “output_size” corresponds to either the number of cell units (i.e.,
2106 // “num_units”), or the second dimension of the “projection_weights”, if defined.
2107 const ConstTensorPin recurrentToInputWeightsPin =
Pablo Tellofb45e2f2019-10-18 16:51:57 +01002108 (DequantizeAndMakeConstTensorPin<hal_1_2::HalPolicy>(operation, model, data, 5, true));
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002109 // 09: The cell-to-input weights: Optional. A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
2110 const ConstTensorPin cellToInputWeightsPin =
Pablo Tellofb45e2f2019-10-18 16:51:57 +01002111 (DequantizeAndMakeConstTensorPin<hal_1_2::HalPolicy>(operation, model, data, 9, true));
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002112 // 10: The cell-to-forget weights: Optional. A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
2113 const ConstTensorPin cellToForgetWeightsPin =
Pablo Tellofb45e2f2019-10-18 16:51:57 +01002114 (DequantizeAndMakeConstTensorPin<hal_1_2::HalPolicy>(operation, model, data, 10, true));
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002115 // 11: The cell-to-output weights: Optional. A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
2116 const ConstTensorPin cellToOutputWeightsPin =
Pablo Tellofb45e2f2019-10-18 16:51:57 +01002117 (DequantizeAndMakeConstTensorPin<hal_1_2::HalPolicy>(operation, model, data, 11, true));
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002118 // 12: The input gate bias: Optional. A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
2119 const ConstTensorPin inputGateBiasPin =
2120 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
2121 12,
2122 model,
2123 data,
2124 g_DontPermute,
2125 nullptr,
2126 true);
2127
2128 // 16: The projection weights: Optional. A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
2129 // [output_size, num_units].
2130 const ConstTensorPin projectionWeightsPin =
Pablo Tellofb45e2f2019-10-18 16:51:57 +01002131 (DequantizeAndMakeConstTensorPin<hal_1_2::HalPolicy>(operation, model, data, 16, true));
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002132 // 17: The projection bias: Optional. A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [output_size].
2133 const ConstTensorPin projectionBiasPin =
2134 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
2135 17,
2136 model,
2137 data,
2138 g_DontPermute,
2139 nullptr,
2140 true);
2141
2142 if ((!inputToInputWeightsPin.IsValid() && !inputToInputWeightsPin.IsOptional()) ||
2143 (!recurrentToInputWeightsPin.IsValid() && !recurrentToInputWeightsPin.IsOptional()) ||
2144 (!cellToInputWeightsPin.IsValid() && !cellToInputWeightsPin.IsOptional()) ||
2145 (!cellToForgetWeightsPin.IsValid() && !cellToForgetWeightsPin.IsOptional()) ||
2146 (!cellToOutputWeightsPin.IsValid() && !cellToOutputWeightsPin.IsOptional()) ||
2147 (!inputGateBiasPin.IsValid() && !inputGateBiasPin.IsOptional()) ||
2148 (!projectionWeightsPin.IsValid() && !projectionWeightsPin.IsOptional()) ||
2149 (!projectionBiasPin.IsValid() && !projectionBiasPin.IsOptional()))
2150 {
2151 return Fail("%s: Operation has invalid tensor inputs", __func__);
2152 }
2153
2154 // Get the mandatory input scalars (actually 1-D tensors of size 1):
2155 // 20: The activation function: A value indicating the activation function:
2156 // 0: None; 1: Relu; 3: Relu6; 4: Tanh; 6: Sigmoid.
2157 // 21: The clipping threshold: for the cell state, such that values are bound within [-cell_clip, cell_clip].
2158 // If set to 0.0 then clipping is disabled.
2159 // 22: The clipping threshold: for the output from the projection layer, such that values are bound within
2160 // [-proj_clip, proj_clip]. If set to 0.0 then clipping is disabled.
2161 ActivationFn activation;
2162 float cellClip;
2163 float projClip;
2164 if (!GetInputActivationFunctionFromTensor<hal_1_2::HalPolicy>(operation, 20, activation, model, data) ||
2165 !GetInputScalar<hal_1_2::HalPolicy>(operation, 21, OperandType::FLOAT32, cellClip, model, data) ||
2166 !GetInputScalar<hal_1_2::HalPolicy>(operation, 22, OperandType::FLOAT32, projClip, model, data))
2167 {
2168 return Fail("%s: Operation has invalid scalar inputs", __func__);
2169 }
2170
2171 // Get the normalization tensors
2172 // 23: The input layer normalization weights. A 1-D tensor of shape [num_units].
2173 // Used to rescale normalized inputs to activation at input gate.
Pablo Tellofb45e2f2019-10-18 16:51:57 +01002174 const ConstTensorPin inputLayerNormWeightsPin
2175 (DequantizeAndMakeConstTensorPin<hal_1_2::HalPolicy>(operation, model, data, 23, true));
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002176
2177 // 24: The forget layer normalization weights. A 1-D tensor of shape [num_units].
2178 // Used to rescale normalized inputs to activation at forget gate.
2179 const ConstTensorPin forgetLayerNormWeightsPin =
2180 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
2181 24,
2182 model,
2183 data,
2184 g_DontPermute,
2185 nullptr,
2186 true);
2187
2188 // 25: The cell layer normalization weights. A 1-D tensor of shape [num_units].
2189 // Used to rescale normalized inputs to activation at cell gate.
2190 const ConstTensorPin cellLayerNormWeightsPin =
2191 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
2192 25,
2193 model,
2194 data,
2195 g_DontPermute,
2196 nullptr,
2197 true);
2198
2199 // 26: The output layer normalization weights. A 1-D tensor of shape [num_units].
2200 // Used to rescale normalized inputs to activation at output gate.
2201 const ConstTensorPin outputLayerNormWeightsPin =
2202 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation,
2203 26,
2204 model,
2205 data,
2206 g_DontPermute,
2207 nullptr,
2208 true);
2209
2210 // Outputs:
2211 // 00: The scratch buffer: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, num_units * 4]
2212 // with CIFG, or [batch_size, num_units * 3] without CIFG.
2213 const Operand* scratchBuffer = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
2214 if (!scratchBuffer)
2215 {
2216 return Fail("%s: Could not read output 0: scratchBuffer", __func__);
2217 }
2218 // 01: The output state (out): A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, output_size].
2219 const Operand* outputStateOut = GetOutputOperand<hal_1_2::HalPolicy>(operation, 1, model);
2220 if (!outputStateOut)
2221 {
2222 return Fail("%s: Could not read output 1: outputStateOut", __func__);
2223 }
2224 // 02: The cell state (out): A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, num_units].
2225 const Operand* cellStateOut = GetOutputOperand<hal_1_2::HalPolicy>(operation, 2, model);
2226 if (!cellStateOut)
2227 {
2228 return Fail("%s: Could not read output 2: cellStateOut", __func__);
2229 }
2230 // 03: The output: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, output_size]. This is
2231 // effectively the same as the current “output state (out)” value.
2232 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 3, model);
2233 if (!output)
2234 {
2235 return Fail("%s: Could not read output 3: output", __func__);
2236 }
2237
2238 // set the params structure for the AddLstmLayer call
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002239 LstmInputParams params;
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002240 params.m_InputToInputWeights = inputToInputWeightsPin.GetConstTensorPtr();
2241 params.m_InputToForgetWeights = inputToForgetWeightsPin.GetConstTensorPtr();
2242 params.m_InputToCellWeights = inputToCellWeightsPin.GetConstTensorPtr();
2243 params.m_InputToOutputWeights = inputToOutputWeightsPin.GetConstTensorPtr();
2244 params.m_RecurrentToInputWeights = recurrentToInputWeightsPin.GetConstTensorPtr();
2245 params.m_RecurrentToForgetWeights = recurrentToForgetWeightsPin.GetConstTensorPtr();
2246 params.m_RecurrentToCellWeights = recurrentToCellWeightsPin.GetConstTensorPtr();
2247 params.m_RecurrentToOutputWeights = recurrentToOutputWeightsPin.GetConstTensorPtr();
2248 params.m_CellToInputWeights = cellToInputWeightsPin.GetConstTensorPtr();
2249 params.m_CellToForgetWeights = cellToForgetWeightsPin.GetConstTensorPtr();
2250 params.m_CellToOutputWeights = cellToOutputWeightsPin.GetConstTensorPtr();
2251 params.m_InputGateBias = inputGateBiasPin.GetConstTensorPtr();
2252 params.m_ForgetGateBias = forgetGateBiasPin.GetConstTensorPtr();
2253 params.m_CellBias = cellBiasPin.GetConstTensorPtr();
2254 params.m_OutputGateBias = outputGateBiasPin.GetConstTensorPtr();
2255 params.m_ProjectionWeights = projectionWeightsPin.GetConstTensorPtr();
2256 params.m_ProjectionBias = projectionBiasPin.GetConstTensorPtr();
2257 params.m_InputLayerNormWeights = inputLayerNormWeightsPin.GetConstTensorPtr();
2258 params.m_ForgetLayerNormWeights = forgetLayerNormWeightsPin.GetConstTensorPtr();
2259 params.m_CellLayerNormWeights = cellLayerNormWeightsPin.GetConstTensorPtr();
2260 params.m_OutputLayerNormWeights = outputLayerNormWeightsPin.GetConstTensorPtr();
2261
2262 // set the layer descriptor
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002263 LstmDescriptor desc;
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002264 desc.m_ActivationFunc = activation;
2265 desc.m_ClippingThresCell = cellClip;
2266 desc.m_ClippingThresProj = projClip;
2267 desc.m_CifgEnabled = (params.m_InputToInputWeights == nullptr ||
2268 params.m_RecurrentToInputWeights == nullptr ||
2269 params.m_InputGateBias == nullptr);
2270 desc.m_PeepholeEnabled = (params.m_CellToForgetWeights != nullptr ||
2271 params.m_CellToOutputWeights != nullptr);
2272 desc.m_ProjectionEnabled = (params.m_ProjectionWeights != nullptr);
2273 desc.m_LayerNormEnabled = (params.m_InputLayerNormWeights != nullptr ||
2274 params.m_ForgetLayerNormWeights != nullptr ||
2275 params.m_CellLayerNormWeights != nullptr ||
2276 params.m_OutputLayerNormWeights != nullptr);
2277
2278 // validate the optional input groups
2279 if (desc.m_CifgEnabled &&
2280 (params.m_InputToInputWeights != nullptr ||
2281 params.m_RecurrentToInputWeights != nullptr ||
2282 params.m_InputGateBias != nullptr))
2283 {
2284 return Fail("%s: All, or none, of input-to-input weights, recurrent-to-input weights,"
2285 " and input gate bias must be provided", __func__);
2286 }
2287
2288 if (!desc.m_ProjectionEnabled && params.m_ProjectionBias != nullptr)
2289 {
2290 return Fail("%s: projection bias should not be provided without projection weights", __func__);
2291 }
2292
2293 if (desc.m_PeepholeEnabled &&
2294 (params.m_CellToForgetWeights == nullptr ||
2295 params.m_CellToOutputWeights == nullptr ||
2296 (!desc.m_CifgEnabled && params.m_CellToInputWeights == nullptr)))
2297 {
2298 return Fail("%s: All, or none, of cell-to-forget weights and cell-to-output weights must be provided"
2299 " and, if CIFG is not enabled, cell-to-input weights must also be provided", __func__);
2300 }
2301
2302 if (desc.m_LayerNormEnabled &&
2303 (params.m_ForgetLayerNormWeights == nullptr ||
2304 params.m_CellLayerNormWeights == nullptr ||
2305 params.m_OutputLayerNormWeights == nullptr ||
2306 (!desc.m_CifgEnabled && params.m_InputLayerNormWeights == nullptr)))
2307 {
2308 return Fail("%s: All, or none, of forget-norm weights, cell-norm weights and output-norm weights must be"
2309 " provided and, if CIFG is not enabled, input-norm weights must also be provided", __func__);
2310 }
2311
2312 // Check if the layer is supported
2313 // Inputs
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002314 const TensorInfo& inputInfo = input.GetTensorInfo();
2315 const TensorInfo& outputStateInInfo = outputStateIn.GetTensorInfo();
2316 const TensorInfo& cellStateInInfo = cellStateIn.GetTensorInfo();
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002317
2318 // Outputs
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002319 const TensorInfo& scratchBufferInfo = GetTensorInfoForOperand(*scratchBuffer);
2320 const TensorInfo& outputStateOutInfo = GetTensorInfoForOperand(*outputStateOut);
2321 const TensorInfo& cellStateOutInfo = GetTensorInfoForOperand(*cellStateOut);
2322 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002323
Ferran Balaguera4a629a2019-07-30 10:16:13 +01002324 if (IsDynamicTensor(scratchBufferInfo) ||
2325 IsDynamicTensor(outputStateOutInfo) ||
2326 IsDynamicTensor(cellStateOutInfo) ||
2327 IsDynamicTensor(outputInfo))
2328 {
Pablo Tellofb45e2f2019-10-18 16:51:57 +01002329 return Fail("%s: Dynamic output tensors are not supported %d %d %d %d", __func__,
2330 IsDynamicTensor(scratchBufferInfo), IsDynamicTensor(outputStateOutInfo),
2331 IsDynamicTensor(cellStateOutInfo), IsDynamicTensor(outputInfo));
Ferran Balaguera4a629a2019-07-30 10:16:13 +01002332 }
2333
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002334 // Basic parameters
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002335 LstmInputParamsInfo paramsInfo;
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002336 paramsInfo.m_InputToForgetWeights = &(params.m_InputToForgetWeights->GetInfo());
2337 paramsInfo.m_InputToCellWeights = &(params.m_InputToCellWeights->GetInfo());
2338 paramsInfo.m_InputToOutputWeights = &(params.m_InputToOutputWeights->GetInfo());
2339 paramsInfo.m_RecurrentToForgetWeights = &(params.m_RecurrentToForgetWeights->GetInfo());
2340 paramsInfo.m_RecurrentToCellWeights = &(params.m_RecurrentToCellWeights->GetInfo());
2341 paramsInfo.m_RecurrentToOutputWeights = &(params.m_RecurrentToOutputWeights->GetInfo());
2342 paramsInfo.m_ForgetGateBias = &(params.m_ForgetGateBias->GetInfo());
2343 paramsInfo.m_CellBias = &(params.m_CellBias->GetInfo());
2344 paramsInfo.m_OutputGateBias = &(params.m_OutputGateBias->GetInfo());
2345
2346 // Optional parameters
2347 if(!desc.m_CifgEnabled)
2348 {
2349 paramsInfo.m_InputToInputWeights = &(params.m_InputToInputWeights->GetInfo());
2350 paramsInfo.m_RecurrentToInputWeights = &(params.m_RecurrentToInputWeights->GetInfo());
2351 if (params.m_CellToInputWeights != nullptr)
2352 {
2353 paramsInfo.m_CellToInputWeights = &(params.m_CellToInputWeights->GetInfo());
2354 }
2355 paramsInfo.m_InputGateBias = &(params.m_InputGateBias->GetInfo());
2356 }
2357
2358 if(desc.m_ProjectionEnabled)
2359 {
2360 paramsInfo.m_ProjectionWeights = &(params.m_ProjectionWeights->GetInfo());
2361 if (params.m_ProjectionBias != nullptr)
2362 {
2363 paramsInfo.m_ProjectionBias = &(params.m_ProjectionBias->GetInfo());
2364 }
2365 }
2366
2367 if(desc.m_PeepholeEnabled)
2368 {
2369 paramsInfo.m_CellToForgetWeights = &(params.m_CellToForgetWeights->GetInfo());
2370 paramsInfo.m_CellToOutputWeights = &(params.m_CellToOutputWeights->GetInfo());
2371 }
2372
2373 if (desc.m_LayerNormEnabled)
2374 {
2375 if(!desc.m_CifgEnabled)
2376 {
2377 paramsInfo.m_InputLayerNormWeights = &(params.m_InputLayerNormWeights->GetInfo());
2378 }
2379 paramsInfo.m_ForgetLayerNormWeights = &(params.m_ForgetLayerNormWeights->GetInfo());
2380 paramsInfo.m_CellLayerNormWeights = &(params.m_CellLayerNormWeights->GetInfo());
2381 paramsInfo.m_OutputLayerNormWeights = &(params.m_OutputLayerNormWeights->GetInfo());
2382 }
2383
2384 bool isSupported = false;
2385 FORWARD_LAYER_SUPPORT_FUNC(__func__,
2386 IsLstmSupported,
2387 data.m_Backends,
2388 isSupported,
2389 inputInfo,
2390 outputStateInInfo,
2391 cellStateInInfo,
2392 scratchBufferInfo,
2393 outputStateOutInfo,
2394 cellStateOutInfo,
2395 outputInfo,
2396 desc,
2397 paramsInfo);
2398 if (!isSupported)
2399 {
2400 return false;
2401 }
2402
2403 // Add the layer
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002404 IConnectableLayer* layer = data.m_Network->AddLstmLayer(desc, params, "Lstm");
Ferran Balaguerb2397fd2019-07-25 12:12:39 +01002405
2406 input.Connect(layer->GetInputSlot(0));
2407 outputStateIn.Connect(layer->GetInputSlot(1));
2408 cellStateIn.Connect(layer->GetInputSlot(2));
2409
2410 return (SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *layer, 0, model, data) &&
2411 SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 1, *layer, 1, model, data) &&
2412 SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 2, *layer, 2, model, data) &&
2413 SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 3, *layer, 3, model, data));
2414}
2415
Sadik Armagan701d9a02019-09-04 15:16:18 +01002416bool HalPolicy::ConvertSqrt(const Operation& operation, const Model& model, ConversionData& data)
2417{
2418 ALOGV("hal_1_2::HalPolicy::ConvertSqrt()");
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002419 ActivationDescriptor desc;
2420 desc.m_Function = ActivationFunction::Sqrt;
Sadik Armagan701d9a02019-09-04 15:16:18 +01002421
2422 return ::ConvertToActivation<hal_1_2::HalPolicy>(operation, __func__, desc, model, data);
2423}
2424
Mike Kelly46272802019-08-14 17:00:48 +01002425bool HalPolicy::ConvertSqueeze(const Operation& operation, const Model& model, ConversionData& data)
2426{
Sadik Armagan701d9a02019-09-04 15:16:18 +01002427 ALOGV("hal_1_2::HalPolicy::ConvertSqueeze()");
Mike Kelly46272802019-08-14 17:00:48 +01002428 return ::ConvertSqueeze<hal_1_2::HalPolicy>(operation, model, data);
2429}
2430
2431bool HalPolicy::ConvertStridedSlice(const Operation& operation, const Model& model, ConversionData& data)
2432{
Sadik Armagan701d9a02019-09-04 15:16:18 +01002433 ALOGV("hal_1_2::HalPolicy::ConvertStridedSlice()");
Mike Kelly46272802019-08-14 17:00:48 +01002434 return ::ConvertStridedSlice<hal_1_2::HalPolicy>(operation, model, data);
2435}
2436
2437bool HalPolicy::ConvertTranspose(const Operation& operation, const Model& model, ConversionData& data)
2438{
Sadik Armagan701d9a02019-09-04 15:16:18 +01002439 ALOGV("hal_1_2::HalPolicy::ConvertTranspose()");
Mike Kelly46272802019-08-14 17:00:48 +01002440 return ::ConvertTranspose<hal_1_2::HalPolicy>(operation, model, data);
2441}
2442
Aron Virginas-Tar8b991682019-07-31 12:54:59 +01002443bool HalPolicy::ConvertTransposeConv2d(const Operation& operation, const Model& model, ConversionData& data)
David Monahan613b49c2019-06-27 11:37:47 +01002444{
2445 LayerInputHandle input = ConvertToLayerInputHandle<hal_1_2::HalPolicy>(operation, 0, model, data);
2446
2447 if (!input.IsValid())
2448 {
2449 return Fail("%s: Operation has invalid inputs", __func__);
2450 }
2451
2452 const Operand* output = GetOutputOperand<hal_1_2::HalPolicy>(operation, 0, model);
2453
2454 if (!output)
2455 {
2456 return Fail("%s: Could not read output 0", __func__);
2457 }
2458
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002459 const TensorInfo& inputInfo = input.GetTensorInfo();
2460 const TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
David Monahan613b49c2019-06-27 11:37:47 +01002461 if (IsDynamicTensor(outputInfo))
2462 {
2463 return Fail("%s: Dynamic output tensors are not supported", __func__);
2464 }
2465
2466 // ArmNN does not currently support non-fixed weights or bias
2467 // Find the shape of the weights tensor. In AndroidNN this will be [ 1, H, W, I * M ]
2468 const Operand* weightsOperand = GetInputOperand<hal_1_2::HalPolicy>(operation, 1, model);
2469
2470 if (weightsOperand == nullptr)
2471 {
2472 return Fail("%s: Operand is invalid", __func__);
2473 }
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002474 TransposeConvolution2dDescriptor desc;
2475 desc.m_DataLayout = DataLayout::NHWC;
David Monahan613b49c2019-06-27 11:37:47 +01002476
2477 // Determine whether padding is implicit or explicit
2478 bool implicitPadding = operation.inputs.size() == 9;
2479
2480 if (implicitPadding )
2481 {
2482 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 8, model, data);
2483 }
2484 else
2485 {
2486 desc.m_DataLayout = OptionalDataLayout<hal_1_2::HalPolicy>(operation, 10, model, data);
2487 }
2488
2489 armnnUtils::DataLayoutIndexed dataLayoutIndexed(desc.m_DataLayout);
2490 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
2491 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
2492
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002493 const PermutationVector OHWIToOIHW = {0, 2, 3, 1};
David Monahan613b49c2019-06-27 11:37:47 +01002494
2495 // The shape of the weight is [depth_out, filter_height, filter_width, depth_in].
2496 // We have to permute it to OIHW if the data layout is NCHW.
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002497 const ConstTensorPin weightsPin = (desc.m_DataLayout == DataLayout::NCHW) ?
David Monahan613b49c2019-06-27 11:37:47 +01002498 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 1, model, data, OHWIToOIHW) :
2499 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 1, model, data);
2500
2501 // Bias is a 1D tensor
2502 const ConstTensorPin biasPin =
2503 ConvertOperationInputToConstTensorPin<hal_1_2::HalPolicy>(operation, 2, model, data);
2504
2505 if (!weightsPin.IsValid())
2506 {
2507 return Fail("%s: Operation has invalid weights", __func__);
2508 }
2509
2510 if (!biasPin.IsValid())
2511 {
2512 return Fail("%s: Operation has invalid biases", __func__);
2513 }
2514
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002515 ConstTensor weights = weightsPin.GetConstTensor();
2516 ConstTensor bias = biasPin.GetConstTensor();
David Monahan613b49c2019-06-27 11:37:47 +01002517 SanitizeBiasQuantizationScale(bias.GetInfo(), weights.GetInfo(), inputInfo);
2518
2519 ActivationFn activation;
2520
2521 if (implicitPadding)
2522 {
Sadik Armagan3e3003e2019-08-13 12:54:34 +01002523 int32_t strideX{0};
2524 int32_t strideY{0};
2525 int32_t padLeft{0};
2526 int32_t padRight{0};
2527 int32_t padTop{0};
2528 int32_t padBottom{0};
2529
David Monahan613b49c2019-06-27 11:37:47 +01002530 android::nn::PaddingScheme paddingScheme;
2531 if (!GetInputPaddingScheme<hal_1_2::HalPolicy>(operation, 4, paddingScheme, model, data) ||
Sadik Armagan3e3003e2019-08-13 12:54:34 +01002532 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, strideX, model, data) ||
2533 !GetInputScalar<hal_1_2::HalPolicy>(operation, 6, OperandType::INT32, strideY, model, data) ||
David Monahan613b49c2019-06-27 11:37:47 +01002534 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 7, activation, model, data))
2535 {
2536 return Fail("%s: Operation has invalid inputs (implicit padding)", __func__);
2537 }
2538
2539 const uint32_t kernelX = weights.GetShape()[widthIndex];
2540 const uint32_t kernelY = weights.GetShape()[heightIndex];
Narumol Prangnawaratc8bdb392019-08-01 15:51:44 +01002541 const uint32_t outputX = outputInfo.GetShape()[widthIndex];
2542 const uint32_t outputY = outputInfo.GetShape()[heightIndex];
David Monahan613b49c2019-06-27 11:37:47 +01002543
Narumol Prangnawaratc8bdb392019-08-01 15:51:44 +01002544 CalcPaddingTransposeConv(outputX, kernelX, desc.m_StrideX, padLeft, padRight, paddingScheme);
2545 CalcPaddingTransposeConv(outputY, kernelY, desc.m_StrideY, padTop, padBottom, paddingScheme);
2546
2547 // NOTE: The Android NN API allows for negative padding values in TransposeConv2d,
2548 // but Arm NN only supports values >= 0
2549 if (padLeft < 0 || padRight < 0 || padTop < 0 || padBottom < 0)
2550 {
2551 return Fail("%s: Negative padding values are not supported", __func__);
2552 }
2553
Sadik Armagan3e3003e2019-08-13 12:54:34 +01002554 desc.m_StrideX = boost::numeric_cast<uint32_t>(strideX);
2555 desc.m_StrideY = boost::numeric_cast<uint32_t>(strideY);
Narumol Prangnawaratc8bdb392019-08-01 15:51:44 +01002556 desc.m_PadLeft = boost::numeric_cast<uint32_t>(padLeft);
2557 desc.m_PadRight = boost::numeric_cast<uint32_t>(padRight);
2558 desc.m_PadTop = boost::numeric_cast<uint32_t>(padTop);
2559 desc.m_PadBottom = boost::numeric_cast<uint32_t>(padBottom);
David Monahan613b49c2019-06-27 11:37:47 +01002560 }
2561 else if (operation.inputs.size() == 11)
2562 {
2563 // explicit padding
2564 if (!GetInputScalar<hal_1_2::HalPolicy>(operation, 3, OperandType::INT32, desc.m_PadLeft, model, data) ||
2565 !GetInputScalar<hal_1_2::HalPolicy>(operation, 4, OperandType::INT32, desc.m_PadRight, model, data) ||
2566 !GetInputScalar<hal_1_2::HalPolicy>(operation, 5, OperandType::INT32, desc.m_PadTop, model, data) ||
2567 !GetInputScalar<hal_1_2::HalPolicy>(operation, 6, OperandType::INT32, desc.m_PadBottom, model, data) ||
2568 !GetInputScalar<hal_1_2::HalPolicy>(operation, 7, OperandType::INT32, desc.m_StrideX, model, data) ||
2569 !GetInputScalar<hal_1_2::HalPolicy>(operation, 8, OperandType::INT32, desc.m_StrideY, model, data) ||
2570 !GetInputActivationFunction<hal_1_2::HalPolicy>(operation, 9, activation, model, data))
2571 {
2572 return Fail("%s: Operation has invalid inputs (explicit padding)", __func__);
2573 }
2574 }
2575 else
2576 {
2577 return Fail("%s: Unsupported number of operation inputs", __func__);
2578 }
2579
2580 desc.m_BiasEnabled = true;
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002581 Optional<TensorInfo> biases(bias.GetInfo());
David Monahan613b49c2019-06-27 11:37:47 +01002582
2583 bool isSupported = false;
2584 FORWARD_LAYER_SUPPORT_FUNC(__func__,
2585 IsTransposeConvolution2dSupported,
2586 data.m_Backends,
2587 isSupported,
2588 inputInfo,
2589 outputInfo,
2590 desc,
2591 weights.GetInfo(),
2592 biases);
2593 if (!isSupported)
2594 {
2595 return false;
2596 }
2597
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002598 IConnectableLayer* startLayer =
2599 data.m_Network->AddTransposeConvolution2dLayer(desc, weights, Optional<ConstTensor>(bias));
David Monahan613b49c2019-06-27 11:37:47 +01002600 if (!startLayer)
2601 {
2602 return Fail("%s: AddTransposeConvolution2dLayer failed", __func__);
2603 }
2604
Teresa Charlin8f6429d2019-10-01 13:10:15 +01002605 IConnectableLayer* endLayer = ProcessActivation(outputInfo, activation, startLayer, data);
David Monahan613b49c2019-06-27 11:37:47 +01002606 if (!endLayer)
2607 {
2608 return Fail("%s: ProcessActivation failed", __func__);
2609 }
2610
2611 input.Connect(startLayer->GetInputSlot(0));
2612
2613 return SetupAndTrackLayerOutputSlot<hal_1_2::HalPolicy>(operation, 0, *endLayer, model, data);
2614}
2615
Mike Kellyb5fdf382019-06-11 16:35:25 +01002616} // namespace hal_1_2
Matteo Martincigh17ffff32019-06-27 14:12:55 +01002617} // namespace armnn_driver