blob: daa27f63dc6dae1061b41269c180b53da11c04cc [file] [log] [blame]
Francis Murtagh9270d9e2022-08-12 13:54:17 +01001//
2// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "TosaRefLayerSupport.hpp"
7#include <tosaCommon/TosaMappings.hpp>
8
9#include <armnn/Types.hpp>
10#include <armnn/utility/IgnoreUnused.hpp>
11#include <tosaCommon/TosaLayerSupportRules.hpp>
12#include <LayerSupportCommon.hpp>
13
14#include <vector>
15#include <array>
Cathal Corbettbd18eab2022-11-15 12:56:16 +000016#include <tuple>
Francis Murtagh9270d9e2022-08-12 13:54:17 +010017
18namespace armnn
19{
20
Cathal Corbettbd18eab2022-11-15 12:56:16 +000021static bool RunTosaLayerChecksSingleDataType(TosaSerializationOperator* op,
22 const std::vector<TosaSerializationTensor*>& inputs,
23 const std::vector<TosaSerializationTensor*>& outputs,
24 const std::vector<Attribute>& supportedAttributes,
25 const std::vector<DType>& supportedTypes,
26 Optional<string&> reasonIfUnsupported)
Matthew Sloyan2523b792022-11-14 10:18:01 +000027{
28 bool supported = true;
29
Cathal Corbettbd18eab2022-11-15 12:56:16 +000030 std::string opString = TosaOpToString(op->GetOp());
Matthew Sloyan2523b792022-11-14 10:18:01 +000031
32 // Check Attribute from operator (GetAttribute)
33 supported &= CheckSupportRule(TosaOperatorAttributeOfAny(op, supportedAttributes), reasonIfUnsupported,
Cathal Corbettbd18eab2022-11-15 12:56:16 +000034 std::string("TOSA Reference Operator: " + opString +
Matthew Sloyan2523b792022-11-14 10:18:01 +000035 " has an unsupported attribute.").c_str());
36
37 for (auto input : inputs)
38 {
Cathal Corbettb30e6552022-12-07 11:50:50 +000039 std::string dataTypeCode = TosaDTypeToString(input->GetDtype());
Matthew Sloyan2523b792022-11-14 10:18:01 +000040
41 // Check Dtype from tensor (GetDtype)
42 supported &= CheckSupportRule(TosaTypeAnyOf(input, supportedTypes),
43 reasonIfUnsupported,
Cathal Corbettbd18eab2022-11-15 12:56:16 +000044 std::string("TOSA Reference Operator: " + opString + " for input: " +
Matthew Sloyan2523b792022-11-14 10:18:01 +000045 input->GetName() + " has an unsupported data type: " +
46 dataTypeCode).c_str());
47
48 // Check Shape from tensor (GetShape)
49 supported &= CheckSupportRule(TosaTensorNumDimensionsWithinBounds(input),
50 reasonIfUnsupported,
Cathal Corbettbd18eab2022-11-15 12:56:16 +000051 std::string("Tosa Reference Operator: " + opString + " for input: " +
Matthew Sloyan2523b792022-11-14 10:18:01 +000052 input->GetName() + " exceeds MaxNumOfTensorDimensions.").c_str());
53 }
54
55 for (auto output : outputs)
56 {
Cathal Corbettb30e6552022-12-07 11:50:50 +000057 std::string dataTypeCode = TosaDTypeToString(output->GetDtype());
Matthew Sloyan2523b792022-11-14 10:18:01 +000058
59 // Check Dtype from tensor (GetDtype)
60 supported &= CheckSupportRule(TosaTypeAnyOf(output, supportedTypes),
61 reasonIfUnsupported,
Cathal Corbettbd18eab2022-11-15 12:56:16 +000062 std::string("TOSA Reference Operator: " + opString + " for output: " +
Matthew Sloyan2523b792022-11-14 10:18:01 +000063 output->GetName() + " has an unsupported data type: " +
64 dataTypeCode).c_str());
65
66 // Check Shape from tensor (GetShape)
67 supported &= CheckSupportRule(TosaTensorNumDimensionsWithinBounds(output),
68 reasonIfUnsupported,
Cathal Corbettbd18eab2022-11-15 12:56:16 +000069 std::string("Tosa Reference Operator: " + opString + " for output: " +
Matthew Sloyan2523b792022-11-14 10:18:01 +000070 output->GetName() + " exceeds MaxNumOfTensorDimensions.").c_str());
71 }
72
73 return supported;
74}
75
Cathal Corbettbd18eab2022-11-15 12:56:16 +000076static bool RunTosaLayerChecksInputOutputDataType(TosaSerializationOperator* op,
77 const std::vector<TosaSerializationTensor*>& inputs,
78 const std::vector<TosaSerializationTensor*>& outputs,
79 const std::vector<Attribute>& supportedAttributes,
80 const std::vector<std::tuple<DType,DType>>& supportedMappingTypes,
81 Optional<string&> reasonIfUnsupported)
82{
83 bool supported = true;
84
85 std::string opString = TosaOpToString(op->GetOp());
86
87 // Check Attribute from operator (GetAttribute)
88 supported &= CheckSupportRule(TosaOperatorAttributeOfAny(op, supportedAttributes), reasonIfUnsupported,
89 std::string("TOSA Reference Operator: " + opString +
90 " has an unsupported attribute.").c_str());
91
92 supported &= CheckSupportRule(TosaAssertSize(inputs, outputs), reasonIfUnsupported,
93 std::string("TOSA Reference Operator: " + opString +
94 " must have 1-to-1 mapping of inputs-to-outputs.").c_str());
95
96 for (uint32_t i = 0; i < inputs.size(); i++)
97 {
98 auto input = inputs[i];
99 auto output = outputs[i];
Cathal Corbettb30e6552022-12-07 11:50:50 +0000100 std::string inputDataTypeCode = TosaDTypeToString(input->GetDtype());
101 std::string outputDataTypeCode = TosaDTypeToString(output->GetDtype());
Cathal Corbettbd18eab2022-11-15 12:56:16 +0000102 std::tuple<DType, DType> mappingType(input->GetDtype(), output->GetDtype());
103
104 // Check Dtype from tensor (GetDtype)
Matthew Sloyanc5fe6e72022-11-25 16:10:00 +0000105 supported &= CheckSupportRule(TosaContainerContainsTwoTypes(mappingType, supportedMappingTypes),
Cathal Corbettbd18eab2022-11-15 12:56:16 +0000106 reasonIfUnsupported,
107 std::string("TOSA Reference Operator: " + opString + " for input: " +
108 input->GetName() + " and output: " + output->GetName() +
109 " has an unsupported input data type: " + inputDataTypeCode +
110 " to output data type: " + outputDataTypeCode).c_str());
111
112 // Check Shape from tensor (GetShape)
113 supported &= CheckSupportRule(TosaTensorNumDimensionsWithinBounds(input),
114 reasonIfUnsupported,
115 std::string("Tosa Reference Operator: " + opString + " for input: " +
116 input->GetName() + " exceeds MaxNumOfTensorDimensions.").c_str());
117
118 // Check Shape from tensor (GetShape)
119 supported &= CheckSupportRule(TosaTensorNumDimensionsWithinBounds(output),
120 reasonIfUnsupported,
121 std::string("Tosa Reference Operator: " + opString + " for output: " +
122 output->GetName() + " exceeds MaxNumOfTensorDimensions.").c_str());
123 }
124
125 return supported;
126}
127
Matthew Sloyanc5fe6e72022-11-25 16:10:00 +0000128static bool RunTosaLayerChecksInputWeightsOutputDataType(
129 TosaSerializationOperator* op,
130 const std::vector<TosaSerializationTensor*>& inputs,
131 const std::vector<TosaSerializationTensor*>& outputs,
132 const std::vector<Attribute>& supportedAttributes,
133 const std::vector<std::tuple<DType, DType, DType>>& supportedMappingTypes,
134 Optional<string&> reasonIfUnsupported)
135{
136 bool supported = true;
137
138 std::string opString = TosaOpToString(op->GetOp());
139
140 // Check Attribute from operator (GetAttribute)
141 supported &= CheckSupportRule(TosaOperatorAttributeOfAny(op, supportedAttributes), reasonIfUnsupported,
142 std::string("TOSA Reference Operator: " + opString +
143 " has an unsupported attribute.").c_str());
144
145 // Check combination of input, weights and output types.
146 // Bias is the same as output type, so it is covered.
147 std::tuple<DType, DType, DType> mappingTypes(inputs[0]->GetDtype(), inputs[1]->GetDtype(), outputs[0]->GetDtype());
148
149 // Check Dtype from tensor (GetDtype)
150 supported &= CheckSupportRule(TosaContainerContainsThreeTypes(mappingTypes, supportedMappingTypes),
151 reasonIfUnsupported,
152 std::string("TOSA Reference Operator: " + opString + " for input 0: " +
153 inputs[0]->GetName() + ", input 1: " + inputs[1]->GetName() +
154 " and output: " + outputs[0]->GetName() +
155 " has an unsupported input data type combination.").c_str());
156
157 for (auto input : inputs)
158 {
159 // Check Shape from tensor (GetShape)
160 supported &= CheckSupportRule(TosaTensorNumDimensionsWithinBounds(input),
161 reasonIfUnsupported,
162 std::string("Tosa Reference Operator: " + opString + " for input: " +
163 input->GetName() + " exceeds MaxNumOfTensorDimensions.").c_str());
164 }
165
166 for (auto output : outputs)
167 {
168 // Check Shape from tensor (GetShape)
169 supported &= CheckSupportRule(TosaTensorNumDimensionsWithinBounds(output),
170 reasonIfUnsupported,
171 std::string("Tosa Reference Operator: " + opString + " for output: " +
172 output->GetName() + " exceeds MaxNumOfTensorDimensions.").c_str());
173 }
174
175 return supported;
176}
177
178
179
Francis Murtagh9270d9e2022-08-12 13:54:17 +0100180static bool IsTosaLayerSupported(TosaSerializationOperator* op,
181 const std::vector<TosaSerializationTensor*>& inputs,
182 const std::vector<TosaSerializationTensor*>& outputs,
183 Optional<string&> reasonIfUnsupported)
184{
185 switch(op->GetOp())
186 {
187 case tosa::Op_ADD:
188 {
Matthew Sloyanc5fe6e72022-11-25 16:10:00 +0000189 std::vector<Attribute> supportedAttributes = { Attribute_NONE };
Francis Murtagh9270d9e2022-08-12 13:54:17 +0100190
Matthew Sloyan2523b792022-11-14 10:18:01 +0000191 // Only Int32, Fp32 and Fp16 are currently supported by the TOSA Reference Model.
192 std::vector<DType> supportedTypes =
Matthew Sloyanda824cc2022-10-10 12:43:20 +0100193 {
Matthew Sloyanda824cc2022-10-10 12:43:20 +0100194 DType_INT32,
195 DType_FP16,
196 DType_FP32
197 };
Francis Murtagh9270d9e2022-08-12 13:54:17 +0100198
Matthew Sloyan2523b792022-11-14 10:18:01 +0000199 // Check the attribute, data types and bounds for inputs and outputs.
Matthew Sloyanc5fe6e72022-11-25 16:10:00 +0000200 return RunTosaLayerChecksSingleDataType(
201 op, inputs, outputs, supportedAttributes, supportedTypes, reasonIfUnsupported);
202 }
203 case tosa::Op_CONST:
204 {
205 std::vector<Attribute> supportedAttributes = { Attribute_NONE };
206
207 std::vector<DType> supportedTypes =
208 {
209 DType_FP16,
210 DType_FP32,
211 DType_UINT8,
212 DType_INT8,
213 DType_INT16,
214 DType_INT32,
215 DType_BOOL
216 };
217
218 // Check the attribute, data types and bounds for inputs and outputs.
219 return RunTosaLayerChecksSingleDataType(
220 op, inputs, outputs, supportedAttributes, supportedTypes, reasonIfUnsupported);
221 }
222 case tosa::Op_CONV2D:
223 {
224 std::vector<Attribute> supportedAttributes = { Attribute_ConvAttribute };
225
226 std::vector<std::tuple<DType, DType, DType>> supportedTypesMapping =
227 {
228 std::tuple<DType, DType, DType>(DType_FP16, DType_FP16, DType_FP16),
229 std::tuple<DType, DType, DType>(DType_FP16, DType_FP16, DType_FP32),
230 std::tuple<DType, DType, DType>(DType_FP32, DType_FP32, DType_FP32),
231 std::tuple<DType, DType, DType>(DType_INT8, DType_INT8, DType_INT32)
232 };
233
234 return RunTosaLayerChecksInputWeightsOutputDataType(
235 op, inputs, outputs, supportedAttributes, supportedTypesMapping, reasonIfUnsupported);
Cathal Corbettbd18eab2022-11-15 12:56:16 +0000236 }
237 case tosa::Op_AVG_POOL2D:
238 {
Matthew Sloyanc5fe6e72022-11-25 16:10:00 +0000239 std::vector<Attribute> supportedAttributes = { Attribute_PoolAttribute };
Francis Murtagh9270d9e2022-08-12 13:54:17 +0100240
Cathal Corbettbd18eab2022-11-15 12:56:16 +0000241 std::vector<std::tuple<DType, DType>> supportedTypesMapping =
242 {
243 std::tuple<DType, DType>(DType_FP16, DType_FP16),
244 std::tuple<DType, DType>(DType_FP16, DType_FP32),
245 std::tuple<DType, DType>(DType_FP32, DType_FP32),
246 std::tuple<DType, DType>(DType_INT8, DType_INT32),
247 std::tuple<DType, DType>(DType_INT16, DType_INT32)
248 };
249
250 // Check the attribute, data types and bounds for inputs and outputs.
Matthew Sloyanc5fe6e72022-11-25 16:10:00 +0000251 return RunTosaLayerChecksInputOutputDataType(
252 op, inputs, outputs, supportedAttributes, supportedTypesMapping, reasonIfUnsupported);
Cathal Corbettbd18eab2022-11-15 12:56:16 +0000253 }
254 case tosa::Op_MAX_POOL2D:
255 {
Matthew Sloyanc5fe6e72022-11-25 16:10:00 +0000256 std::vector<Attribute> supportedAttributes = { Attribute_PoolAttribute };
Cathal Corbettbd18eab2022-11-15 12:56:16 +0000257
258 std::vector<DType> supportedTypes =
259 {
260 DType_FP16,
261 DType_FP32,
262 DType_INT8,
263 DType_INT16
264 };
265
266 // Check the attribute, data types and bounds for inputs and outputs.
Matthew Sloyanc5fe6e72022-11-25 16:10:00 +0000267 return RunTosaLayerChecksSingleDataType(
268 op, inputs, outputs, supportedAttributes, supportedTypes, reasonIfUnsupported);
Cathal Corbettbd18eab2022-11-15 12:56:16 +0000269 }
270 case tosa::Op_PAD:
271 {
Matthew Sloyanc5fe6e72022-11-25 16:10:00 +0000272 std::vector<Attribute> supportedAttributes = { Attribute_PadAttribute };
Cathal Corbettbd18eab2022-11-15 12:56:16 +0000273
274 std::vector<DType> supportedTypes =
275 {
276 DType_FP16,
277 DType_FP32,
278 DType_INT8,
279 DType_INT16,
280 DType_INT32,
281 DType_BOOL
282 };
283
284 // Check the attribute, data types and bounds for inputs and outputs.
Matthew Sloyanc5fe6e72022-11-25 16:10:00 +0000285 return RunTosaLayerChecksSingleDataType(
286 op, inputs, outputs, supportedAttributes, supportedTypes, reasonIfUnsupported);
Francis Murtagh9270d9e2022-08-12 13:54:17 +0100287 }
Cathal Corbettb30e6552022-12-07 11:50:50 +0000288 case tosa::Op_RESHAPE:
289 {
290 std::vector<Attribute> supportedAttributes = { Attribute_ReshapeAttribute };
291
292 std::vector<DType> supportedTypes =
293 {
294 DType_FP16,
295 DType_FP32,
296 DType_INT8,
297 DType_INT16,
298 DType_INT32,
299 DType_BOOL
300 };
301
302 // Check the attribute, data types and bounds for inputs and outputs.
303 return RunTosaLayerChecksSingleDataType(
304 op, inputs, outputs, supportedAttributes, supportedTypes, reasonIfUnsupported);
305 }
Cathal Corbett3b9acd52022-12-09 12:17:27 +0000306 case tosa::Op_SLICE:
307 {
308 std::vector<Attribute> supportedAttributes = { Attribute_SliceAttribute };
309
310 std::vector<DType> supportedTypes =
311 {
312 DType_FP16,
313 DType_FP32,
314 DType_INT8,
315 DType_INT16,
316 DType_INT32,
317 DType_BOOL
318 };
319
320 // Check the attribute, data types and bounds for inputs and outputs.
321 return RunTosaLayerChecksSingleDataType(
322 op, inputs, outputs, supportedAttributes, supportedTypes, reasonIfUnsupported);
323 }
Francis Murtagh9270d9e2022-08-12 13:54:17 +0100324 default:
325 SetValueChecked(reasonIfUnsupported, "Operation is currently unsupported by the TOSA Reference Backend.");
326 return false;
327 }
328}
329
330bool TosaRefLayerSupport::IsLayerSupported(const LayerType& type,
331 const std::vector<TensorInfo>& infos,
332 const BaseDescriptor& descriptor,
333 const Optional<LstmInputParamsInfo>& lstmParamsInfo,
334 const Optional<QuantizedLstmInputParamsInfo>& quantizedLstmInputParamsInfo,
335 Optional<std::string&> reasonIfUnsupported) const
336{
337 IgnoreUnused(lstmParamsInfo);
338 IgnoreUnused(quantizedLstmInputParamsInfo);
339
Matthew Sloyan164bf4f2022-10-28 18:02:17 +0100340 std::vector<const TensorInfo*> inputInfos;
341 std::vector<const TensorInfo*> outputInfos;
Francis Murtagh9270d9e2022-08-12 13:54:17 +0100342
Matthew Sloyan164bf4f2022-10-28 18:02:17 +0100343 switch (type)
344 {
Matthew Sloyanc5fe6e72022-11-25 16:10:00 +0000345 case LayerType::Input:
346 case LayerType::Output:
347 return true;
Matthew Sloyan164bf4f2022-10-28 18:02:17 +0100348 case LayerType::Addition:
349 // Setup inputs and outputs
350 inputInfos.push_back(&infos[0]);
351 inputInfos.push_back(&infos[1]);
352 outputInfos.push_back(&infos[2]);
353 break;
Matthew Sloyanc5fe6e72022-11-25 16:10:00 +0000354 case LayerType::Constant:
355 outputInfos.push_back(&infos[0]);
356 break;
357 case LayerType::Convolution2d:
358 {
359 inputInfos.push_back(&infos[0]); // input
360 outputInfos.push_back(&infos[1]); // output
361 inputInfos.push_back(&infos[2]); // weights
362
363 auto conv2dDesc = PolymorphicDowncast<const Convolution2dDescriptor*>(&descriptor);
364 if(conv2dDesc->m_BiasEnabled)
365 {
366 inputInfos.push_back(&infos[3]); // bias
367 }
368 break;
369 }
Cathal Corbettbd18eab2022-11-15 12:56:16 +0000370 case LayerType::Pooling2d:
Cathal Corbettb30e6552022-12-07 11:50:50 +0000371 case LayerType::Reshape:
Cathal Corbett3b9acd52022-12-09 12:17:27 +0000372 case LayerType::Slice:
Cathal Corbettbd18eab2022-11-15 12:56:16 +0000373 // Setup inputs and outputs
374 inputInfos.push_back(&infos[0]);
375 outputInfos.push_back(&infos[1]);
376 break;
Matthew Sloyan164bf4f2022-10-28 18:02:17 +0100377 default:
378 break;
379 }
Francis Murtagh9270d9e2022-08-12 13:54:17 +0100380
Matthew Sloyanc5fe6e72022-11-25 16:10:00 +0000381 auto mappings = GetTosaMapping(nullptr, type, inputInfos, outputInfos, descriptor);
Matthew Sloyan164bf4f2022-10-28 18:02:17 +0100382 if (mappings->GetName() == "")
383 {
384 // There currently isn't a TOSA mapping for this layer, as the default was returned.
385 return false;
386 }
Francis Murtagh9270d9e2022-08-12 13:54:17 +0100387
388 // Loop through block and get each tensor and operator
389 for (long unsigned int i = 0; i < mappings->GetOperators().size(); ++i)
390 {
391 // While looping over operators check for op_UNKNOWN which is unsupported
Matthew Sloyan164bf4f2022-10-28 18:02:17 +0100392 if (mappings->GetOperators()[i]->GetOp() == tosa::Op_UNKNOWN) { return false; }
Francis Murtagh9270d9e2022-08-12 13:54:17 +0100393
394 // Loop over operators and get GetInput/OutputTensorNames, loop over resulting names and
395 // use GetTensorByName to pass pointers to tensors on to the IsTosaLayerSupported()
396 std::vector<TosaSerializationTensor*> inputTensorsVect;
397 for (const auto& name : mappings->GetOperators()[i]->GetInputTensorNames())
398 {
399 inputTensorsVect.push_back(mappings->GetTensorByName(name));
400 }
401
402 std::vector<TosaSerializationTensor*> outputTensorsVect;
403 for (const auto& name : mappings->GetOperators()[i]->GetOutputTensorNames())
404 {
405 outputTensorsVect.push_back(mappings->GetTensorByName(name));
406 }
407
408 if (!IsTosaLayerSupported(mappings->GetOperators()[i],
409 inputTensorsVect,
410 outputTensorsVect,
411 reasonIfUnsupported))
412 {
413 return false;
414 }
415 }
416 return true;
417}
418
419} // namespace armnn