blob: 9ca37ec0f57c3b14b2f9233c958615631f78e00d [file] [log] [blame]
arovir01b0717b52018-09-05 17:03:25 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "HalPolicy.hpp"
7
8#include "../1.0/HalPolicy.hpp"
9
10namespace armnn_driver
11{
12namespace hal_1_1
13{
14
15bool HalPolicy::ConvertOperation(const Operation& operation, const Model& model, ConversionData& data)
16{
17 if (compliantWithV1_0(operation))
18 {
19 hal_1_0::HalPolicy::Operation v10Operation = convertToV1_0(operation);
20 hal_1_0::HalPolicy::Model v10Model = convertToV1_0(model);
21
22 return hal_1_0::HalPolicy::ConvertOperation(v10Operation, v10Model, data);
23 }
24 else
25 {
26 switch (operation.type)
27 {
28 case V1_1::OperationType::DIV:
29 return ConvertDiv(operation, model, data);
David Beck38e12942018-09-12 16:02:24 +010030 case V1_1::OperationType::SUB:
31 return ConvertSub(operation, model, data);
narpra013c052562018-09-17 14:25:04 +010032 case V1_1::OperationType::MEAN:
33 return ConvertMean(operation, model, data);
Nina Drozd62a4a9f2018-10-01 14:20:25 +010034 case V1_1::OperationType::PAD:
35 return ConvertPad(operation, model, data);
saoste01b8471482018-10-10 09:44:51 +010036 case V1_1::OperationType::SQUEEZE:
37 return ConvertSqueeze(operation, model, data);
saoste01fe463152018-10-18 17:49:56 +010038 case V1_1::OperationType::TRANSPOSE:
39 return ConvertTranspose(operation, model, data);
arovir01b0717b52018-09-05 17:03:25 +010040 default:
41 return Fail("%s: Operation type %s not supported in ArmnnDriver",
42 __func__, toString(operation.type).c_str());
43 }
44 }
45}
46
47bool HalPolicy::ConvertDiv(const Operation& operation, const Model& model, ConversionData& data)
48{
49 LayerInputHandle input0 = ConvertToLayerInputHandle(operation, 0, model, data);
50 LayerInputHandle input1 = ConvertToLayerInputHandle(operation, 1, model, data);
51
52 if (!input0.IsValid() || !input1.IsValid())
53 {
54 return Fail("%s: Operation has invalid inputs", __func__);
55 }
56
57 // The FuseActivation parameter is always the input index 2
58 // and it should be optional
59 ActivationFn activationFunction;
60 if (!GetOptionalInputActivation(operation, 2, activationFunction, model, data))
61 {
62 return Fail("%s: Operation has invalid inputs", __func__);
63 }
64
65 const Operand* outputOperand = GetOutputOperand(operation, 0, model);
66 if (!outputOperand)
67 {
68 return false;
69 }
70
71 const armnn::TensorInfo& outInfo = GetTensorInfoForOperand(*outputOperand);
72
73 if (!IsLayerSupported(__func__,
74 armnn::IsDivisionSupported,
75 data.m_Compute,
76 input0.GetTensorInfo(),
77 input1.GetTensorInfo(),
78 outInfo))
79 {
80 return false;
81 }
82
83 armnn::IConnectableLayer* const startLayer = data.m_Network->AddDivisionLayer();
84 armnn::IConnectableLayer* const endLayer = ProcessActivation(outInfo, activationFunction, startLayer, data);
85
86 const armnn::TensorInfo& inputTensorInfo0 = input0.GetTensorInfo();
87 const armnn::TensorInfo& inputTensorInfo1 = input1.GetTensorInfo();
88
89 if (endLayer)
90 {
91 BroadcastTensor(input0, input1, startLayer, *data.m_Network);
92 return SetupAndTrackLayerOutputSlot(operation, 0, *endLayer, model, data);
93 }
94
95 return Fail("%s: ProcessActivation failed", __func__);
96}
97
David Beck38e12942018-09-12 16:02:24 +010098bool HalPolicy::ConvertSub(const Operation& operation, const Model& model, ConversionData& data)
99{
100 LayerInputHandle input0 = ConvertToLayerInputHandle(operation, 0, model, data);
101 LayerInputHandle input1 = ConvertToLayerInputHandle(operation, 1, model, data);
102
103 if (!input0.IsValid() || !input1.IsValid())
104 {
105 return Fail("%s: Operation has invalid inputs", __func__);
106 }
107
108 // The FuseActivation parameter is always the input index 2
109 // and it should be optional
110 ActivationFn activationFunction;
111 if (!GetOptionalInputActivation(operation, 2, activationFunction, model, data))
112 {
113 return Fail("%s: Operation has invalid inputs", __func__);
114 }
115
116 const Operand* outputOperand = GetOutputOperand(operation, 0, model);
117 if (!outputOperand)
118 {
119 return false;
120 }
121
122 const armnn::TensorInfo& outInfo = GetTensorInfoForOperand(*outputOperand);
123
124 if (!IsLayerSupported(__func__,
125 armnn::IsSubtractionSupported,
126 data.m_Compute,
127 input0.GetTensorInfo(),
128 input1.GetTensorInfo(),
129 outInfo))
130 {
131 return false;
132 }
133
134 armnn::IConnectableLayer* const startLayer = data.m_Network->AddSubtractionLayer();
135 armnn::IConnectableLayer* const endLayer = ProcessActivation(outInfo, activationFunction, startLayer, data);
136
137 const armnn::TensorInfo& inputTensorInfo0 = input0.GetTensorInfo();
138 const armnn::TensorInfo& inputTensorInfo1 = input1.GetTensorInfo();
139
140 if (endLayer)
141 {
142 BroadcastTensor(input0, input1, startLayer, *data.m_Network);
143 return SetupAndTrackLayerOutputSlot(operation, 0, *endLayer, model, data);
144 }
145
146 return Fail("%s: ProcessActivation failed", __func__);
147}
148
narpra013c052562018-09-17 14:25:04 +0100149bool HalPolicy::ConvertMean(const Operation& operation, const Model& model, ConversionData& data)
150{
151 LayerInputHandle input = ConvertToLayerInputHandle(operation, 0, model, data);
152
153 if (!input.IsValid())
154 {
155 return Fail("%s: Operation has invalid inputs", __func__);
156 }
157
158 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
159
160 armnn::MeanDescriptor descriptor;
161
162 const Operand* axisOperand = GetInputOperand(operation, 1, model);
163 if (axisOperand)
164 {
165 std::vector<int32_t> axis;
166 GetTensorInt32Values(*axisOperand, axis, model, data);
167 unsigned int rank = inputInfo.GetNumDimensions();
168 // convert the axis to unsigned int.
169 for (auto& i : axis)
170 {
171 unsigned int unsignedAxis = (i + rank) % rank;
172 if (std::find(descriptor.m_Axis.begin(), descriptor.m_Axis.end(), unsignedAxis) == descriptor.m_Axis.end())
173 {
174 descriptor.m_Axis.push_back(unsignedAxis);
175 }
176 }
177 }
178
179 int32_t keepDims;
180 GetInputInt32(operation, 2, keepDims, model, data);
181 if (keepDims > 0)
182 {
183 descriptor.m_KeepDims = true;
184 }
185
186 const Operand* output = GetOutputOperand(operation, 0, model);
187 if (!output)
188 {
189 return Fail("%s: Could not read output 0", __func__);
190 }
191
192 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
193
194 if (!IsLayerSupported(__func__,
195 armnn::IsMeanSupported,
196 data.m_Compute,
197 inputInfo,
198 outputInfo,
199 descriptor))
200 {
201 return false;
202 }
203
204 armnn::IConnectableLayer* const layer = data.m_Network->AddMeanLayer(descriptor);
narpra0196bedf02018-09-26 16:57:28 +0100205 assert(layer != nullptr);
206 input.Connect(layer->GetInputSlot(0));
207 layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
narpra013c052562018-09-17 14:25:04 +0100208
209 return SetupAndTrackLayerOutputSlot(operation, 0, *layer, model, data);
210}
211
Nina Drozd62a4a9f2018-10-01 14:20:25 +0100212bool HalPolicy::ConvertPad(const Operation& operation, const Model& model, ConversionData& data)
213{
214 LayerInputHandle input = ConvertToLayerInputHandle(operation, 0, model, data);
215
216 if (!input.IsValid())
217 {
218 return Fail("%s: Operation has invalid inputs", __func__);
219 }
220
221 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
222
223 const Operand* paddingsOperand = GetInputOperand(operation, 1, model);
224
225 if (!paddingsOperand)
226 {
227 return Fail("%s: Could not read paddings operand", __func__);
228 }
229
230 unsigned int rank = inputInfo.GetNumDimensions();
231 armnn::TensorShape paddingsOperandShape = GetTensorShapeForOperand(*paddingsOperand);
232 if (paddingsOperandShape.GetNumDimensions() != rank || paddingsOperandShape.GetNumElements() != 2)
233 {
234 return Fail("%s: Operation has invalid paddings operand: expected shape [%d, 2]", __func__, rank);
235 }
236
237 std::vector<int32_t> paddings;
238 GetTensorInt32Values(*paddingsOperand, paddings, model, data);
239
240 // add padding for each dimension of input tensor.
241 armnn::PadDescriptor descriptor;
242 for (unsigned int i = 0; i < paddings.size() - 1; i += 2)
243 {
244 int paddingBeforeInput = paddings[i];
245 int paddingAfterInput = paddings[i + 1];
246 if (paddingBeforeInput < 0 || paddingAfterInput < 0)
247 {
248 return Fail("%s: Operation has invalid paddings operand, invalid padding values.", __func__);
249 }
250 descriptor.m_PadList.emplace_back((unsigned int) paddingBeforeInput, (unsigned int) paddingAfterInput);
251 }
252
253 const Operand* output = GetOutputOperand(operation, 0, model);
254 if (!output)
255 {
256 return Fail("%s: Could not read output 0", __func__);
257 }
258
259 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
260
261 if (!IsLayerSupported(__func__,
262 armnn::IsPadSupported,
263 data.m_Compute,
264 inputInfo,
265 outputInfo,
266 descriptor))
267 {
268 return false;
269 }
270
271 armnn::IConnectableLayer* const layer = data.m_Network->AddPadLayer(descriptor);
272 assert(layer != nullptr);
273 input.Connect(layer->GetInputSlot(0));
274 layer->GetOutputSlot(0).SetTensorInfo(outputInfo);
275
276 return SetupAndTrackLayerOutputSlot(operation, 0, *layer, model, data);
277}
278
saoste01b8471482018-10-10 09:44:51 +0100279bool HalPolicy::ConvertSqueeze(const Operation& operation, const Model& model, ConversionData& data)
280{
saoste01b8471482018-10-10 09:44:51 +0100281 LayerInputHandle input = ConvertToLayerInputHandle(operation, 0, model, data);
282
283 if (!input.IsValid())
284 {
285 return Fail("%s: Operation has invalid inputs", __func__);
286 }
287
288 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
289
290 unsigned int rank = inputInfo.GetNumDimensions();
saoste01fe463152018-10-18 17:49:56 +0100291 if (rank > 4)
saoste01b8471482018-10-10 09:44:51 +0100292 {
saoste01fe463152018-10-18 17:49:56 +0100293 Fail("%s: Inputs with rank greater than 4 are not supported", __func__);
saoste01b8471482018-10-10 09:44:51 +0100294 }
295
296 // NOTE: Axis is an optional parameter to SQUEEZE, therefore we do not want to generate a failure
297 // if the operand index is out of bounds.
298 const Operand* axisOperand = GetInputOperand(operation, 1, model, false);
299
saoste01fe463152018-10-18 17:49:56 +0100300 const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
301
saoste01b8471482018-10-10 09:44:51 +0100302 std::vector<int32_t> axis;
saoste01fe463152018-10-18 17:49:56 +0100303 if (!axisOperand)
saoste01b8471482018-10-10 09:44:51 +0100304 {
305 axis.assign(dimensionSequence,
saoste01fe463152018-10-18 17:49:56 +0100306 dimensionSequence + rank);
saoste01b8471482018-10-10 09:44:51 +0100307 }
308 else
309 {
310 GetTensorInt32Values(*axisOperand, axis, model, data);
311 }
312
saoste01b8471482018-10-10 09:44:51 +0100313
saoste01a893efa2018-10-13 11:56:12 +0100314 std::vector<uint32_t> outputDims;
saoste01fe463152018-10-18 17:49:56 +0100315 for (unsigned int i = 0; i < rank; i++)
saoste01a893efa2018-10-13 11:56:12 +0100316 {
317 bool skipSqueeze = (std::find(axis.begin(), axis.end(), i) == axis.end());
318 auto currentDimension = inputInfo.GetShape()[i];
saoste01b8471482018-10-10 09:44:51 +0100319 if (skipSqueeze || currentDimension != 1)
320 {
321 outputDims.push_back(currentDimension);
322 }
323 }
324
saoste01fe463152018-10-18 17:49:56 +0100325 armnn::TensorShape outShape = armnn::TensorShape(outputDims.size(), outputDims.data());
saoste01b8471482018-10-10 09:44:51 +0100326
327 armnn::TensorInfo outputInfo = inputInfo;
328 outputInfo.SetShape(outShape);
329
330 armnn::ReshapeDescriptor reshapeDesc;
331 reshapeDesc.m_TargetShape = outputInfo.GetShape();
332
333 const Operand* output = GetOutputOperand(operation, 0, model);
334 if (!output)
335 {
336 return Fail("%s: Could not read output 0", __func__);
337 }
338
339 if (!IsLayerSupported(__func__,
340 armnn::IsReshapeSupported,
341 data.m_Compute,
342 inputInfo))
343 {
344 return false;
345 }
346
347 armnn::IConnectableLayer* const layer = data.m_Network->AddReshapeLayer(reshapeDesc);
348 assert(layer != nullptr);
349 input.Connect(layer->GetInputSlot(0));
saoste01fe463152018-10-18 17:49:56 +0100350
351 return SetupAndTrackLayerOutputSlot(operation, 0, *layer, model, data);
352}
353
354bool HalPolicy::ConvertTranspose(const Operation& operation, const Model& model, ConversionData& data)
355{
356 LayerInputHandle input = ConvertToLayerInputHandle(operation, 0, model, data);
357
358 if (!input.IsValid())
359 {
360 return Fail("%s: Operation has invalid inputs", __func__);
361 }
362
363 const armnn::TensorInfo& inputInfo = input.GetTensorInfo();
364
365 unsigned int rank = inputInfo.GetNumDimensions();
366 if (rank > 4)
367 {
368 Fail("%s: Inputs with rank greater than 4 are not supported", __func__);
369 }
370
371 // NOTE: Axis is an optional parameter to TRANSPOSE, therefore we do not want to generate a failure
372 // if the operand index is out of bounds.
373 const Operand* permOperand = GetInputOperand(operation, 1, model, false);
374
375 std::vector<int32_t> perm(rank);
376 if (!permOperand)
377 {
378 // NOTE: If perm is not given, it is set to (n-1...0), where n is the rank of the tensor
379 for (unsigned int i = rank; i > 0; i--)
380 {
381 perm[rank - i] = boost::numeric_cast<int> (i - 1);
382 }
383 }
384 else
385 {
386 GetTensorInt32Values(*permOperand, perm, model, data);
387 }
388
389 std::vector<uint32_t> outputDims(perm.begin(), perm.begin() + rank);
390
391 auto permutationVector = armnn::PermutationVector(outputDims.data(), outputDims.size());
392 if (!permutationVector.IsEqual(NHWCToArmNN)
393 && !permutationVector.IsEqual(ArmNNToNHWC)
394 && !permutationVector.IsEqual({ 3, 2, 0, 1 }))
395 {
396 return Fail("%s: Only [0, 3, 1, 2], [0, 2, 3, 1] and [3, 2, 0, 1] permutations are supported.", __func__);
397 }
398
399 armnn::PermuteDescriptor permuteDesc;
400 permuteDesc.m_DimMappings = permutationVector;
401
402 const Operand* output = GetOutputOperand(operation, 0, model);
403 if (!output)
404 {
405 return Fail("%s: Could not read output 0", __func__);
406 }
407
408 const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output);
409
410 if (!IsLayerSupported(__func__,
411 armnn::IsPermuteSupported,
412 data.m_Compute,
413 inputInfo,
414 outputInfo,
415 permuteDesc))
416 {
417 return false;
418 }
419
420 armnn::IConnectableLayer* const layer = data.m_Network->AddPermuteLayer(permuteDesc);
421 assert(layer != nullptr);
422 input.Connect(layer->GetInputSlot(0));
saoste01b8471482018-10-10 09:44:51 +0100423
424 return SetupAndTrackLayerOutputSlot(operation, 0, *layer, model, data);
425}
426
arovir01b0717b52018-09-05 17:03:25 +0100427} // namespace hal_1_1
saoste01b8471482018-10-10 09:44:51 +0100428} // namespace armnn_driver