// // Copyright © 2022 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // #include "TosaRefLayerSupport.hpp" #include #include #include #include #include #include #include #include namespace armnn { static bool RunTosaLayerChecksSingleDataType(TosaSerializationOperator* op, const std::vector& inputs, const std::vector& outputs, const std::vector& supportedAttributes, const std::vector& supportedTypes, Optional reasonIfUnsupported) { bool supported = true; std::string opString = TosaOpToString(op->GetOp()); // Check Attribute from operator (GetAttribute) supported &= CheckSupportRule(TosaOperatorAttributeOfAny(op, supportedAttributes), reasonIfUnsupported, std::string("TOSA Reference Operator: " + opString + " has an unsupported attribute.").c_str()); for (auto input : inputs) { std::string dataTypeCode = std::to_string(input->GetDtype()); // Check Dtype from tensor (GetDtype) supported &= CheckSupportRule(TosaTypeAnyOf(input, supportedTypes), reasonIfUnsupported, std::string("TOSA Reference Operator: " + opString + " for input: " + input->GetName() + " has an unsupported data type: " + dataTypeCode).c_str()); // Check Shape from tensor (GetShape) supported &= CheckSupportRule(TosaTensorNumDimensionsWithinBounds(input), reasonIfUnsupported, std::string("Tosa Reference Operator: " + opString + " for input: " + input->GetName() + " exceeds MaxNumOfTensorDimensions.").c_str()); } for (auto output : outputs) { std::string dataTypeCode = std::to_string(output->GetDtype()); // Check Dtype from tensor (GetDtype) supported &= CheckSupportRule(TosaTypeAnyOf(output, supportedTypes), reasonIfUnsupported, std::string("TOSA Reference Operator: " + opString + " for output: " + output->GetName() + " has an unsupported data type: " + dataTypeCode).c_str()); // Check Shape from tensor (GetShape) supported &= CheckSupportRule(TosaTensorNumDimensionsWithinBounds(output), reasonIfUnsupported, std::string("Tosa Reference Operator: " + opString + " for output: " + output->GetName() + " exceeds MaxNumOfTensorDimensions.").c_str()); } return supported; } static bool RunTosaLayerChecksInputOutputDataType(TosaSerializationOperator* op, const std::vector& inputs, const std::vector& outputs, const std::vector& supportedAttributes, const std::vector>& supportedMappingTypes, Optional reasonIfUnsupported) { bool supported = true; std::string opString = TosaOpToString(op->GetOp()); // Check Attribute from operator (GetAttribute) supported &= CheckSupportRule(TosaOperatorAttributeOfAny(op, supportedAttributes), reasonIfUnsupported, std::string("TOSA Reference Operator: " + opString + " has an unsupported attribute.").c_str()); supported &= CheckSupportRule(TosaAssertSize(inputs, outputs), reasonIfUnsupported, std::string("TOSA Reference Operator: " + opString + " must have 1-to-1 mapping of inputs-to-outputs.").c_str()); for (uint32_t i = 0; i < inputs.size(); i++) { auto input = inputs[i]; auto output = outputs[i]; std::string inputDataTypeCode = std::to_string(input->GetDtype()); std::string outputDataTypeCode = std::to_string(output->GetDtype()); std::tuple mappingType(input->GetDtype(), output->GetDtype()); // Check Dtype from tensor (GetDtype) supported &= CheckSupportRule(TosaContainerContains(mappingType, supportedMappingTypes), reasonIfUnsupported, std::string("TOSA Reference Operator: " + opString + " for input: " + input->GetName() + " and output: " + output->GetName() + " has an unsupported input data type: " + inputDataTypeCode + " to output data type: " + outputDataTypeCode).c_str()); // Check Shape from tensor (GetShape) supported &= CheckSupportRule(TosaTensorNumDimensionsWithinBounds(input), reasonIfUnsupported, std::string("Tosa Reference Operator: " + opString + " for input: " + input->GetName() + " exceeds MaxNumOfTensorDimensions.").c_str()); // Check Shape from tensor (GetShape) supported &= CheckSupportRule(TosaTensorNumDimensionsWithinBounds(output), reasonIfUnsupported, std::string("Tosa Reference Operator: " + opString + " for output: " + output->GetName() + " exceeds MaxNumOfTensorDimensions.").c_str()); } return supported; } static bool IsTosaLayerSupported(TosaSerializationOperator* op, const std::vector& inputs, const std::vector& outputs, Optional reasonIfUnsupported) { switch(op->GetOp()) { case tosa::Op_ADD: { std::vector supportedAttributes = { Attribute_NONE }; // Only Int32, Fp32 and Fp16 are currently supported by the TOSA Reference Model. std::vector supportedTypes = { DType_INT32, DType_FP16, DType_FP32 }; // Check the attribute, data types and bounds for inputs and outputs. return RunTosaLayerChecksSingleDataType(op, inputs, outputs, supportedAttributes, supportedTypes, reasonIfUnsupported); } case tosa::Op_AVG_POOL2D: { std::vector supportedAttributes = { Attribute_PoolAttribute }; std::vector> supportedTypesMapping = { std::tuple(DType_FP16, DType_FP16), std::tuple(DType_FP16, DType_FP32), std::tuple(DType_FP32, DType_FP32), std::tuple(DType_INT8, DType_INT32), std::tuple(DType_INT16, DType_INT32) }; // Check the attribute, data types and bounds for inputs and outputs. return RunTosaLayerChecksInputOutputDataType(op, inputs, outputs, supportedAttributes, supportedTypesMapping, reasonIfUnsupported); } case tosa::Op_MAX_POOL2D: { std::vector supportedAttributes = { Attribute_PoolAttribute }; std::vector supportedTypes = { DType_FP16, DType_FP32, DType_INT8, DType_INT16 }; // Check the attribute, data types and bounds for inputs and outputs. return RunTosaLayerChecksSingleDataType(op, inputs, outputs, supportedAttributes, supportedTypes, reasonIfUnsupported); } case tosa::Op_PAD: { std::vector supportedAttributes = { Attribute_PadAttribute }; std::vector supportedTypes = { DType_FP16, DType_FP32, DType_INT8, DType_INT16, DType_INT32, DType_BOOL }; // Check the attribute, data types and bounds for inputs and outputs. return RunTosaLayerChecksSingleDataType(op, inputs, outputs, supportedAttributes, supportedTypes, reasonIfUnsupported); } default: SetValueChecked(reasonIfUnsupported, "Operation is currently unsupported by the TOSA Reference Backend."); return false; } } bool TosaRefLayerSupport::IsLayerSupported(const LayerType& type, const std::vector& infos, const BaseDescriptor& descriptor, const Optional& lstmParamsInfo, const Optional& quantizedLstmInputParamsInfo, Optional reasonIfUnsupported) const { IgnoreUnused(lstmParamsInfo); IgnoreUnused(quantizedLstmInputParamsInfo); std::vector inputInfos; std::vector outputInfos; switch (type) { case LayerType::Addition: // Setup inputs and outputs inputInfos.push_back(&infos[0]); inputInfos.push_back(&infos[1]); outputInfos.push_back(&infos[2]); break; case LayerType::Input: case LayerType::Output: return true; case LayerType::Pooling2d: // Setup inputs and outputs inputInfos.push_back(&infos[0]); outputInfos.push_back(&infos[1]); break; default: break; } auto mappings = GetTosaMapping(type, inputInfos, outputInfos, descriptor, false); if (mappings->GetName() == "") { // There currently isn't a TOSA mapping for this layer, as the default was returned. return false; } // Loop through block and get each tensor and operator for (long unsigned int i = 0; i < mappings->GetOperators().size(); ++i) { // While looping over operators check for op_UNKNOWN which is unsupported if (mappings->GetOperators()[i]->GetOp() == tosa::Op_UNKNOWN) { return false; } // Loop over operators and get GetInput/OutputTensorNames, loop over resulting names and // use GetTensorByName to pass pointers to tensors on to the IsTosaLayerSupported() std::vector inputTensorsVect; for (const auto& name : mappings->GetOperators()[i]->GetInputTensorNames()) { inputTensorsVect.push_back(mappings->GetTensorByName(name)); } std::vector outputTensorsVect; for (const auto& name : mappings->GetOperators()[i]->GetOutputTensorNames()) { outputTensorsVect.push_back(mappings->GetTensorByName(name)); } if (!IsTosaLayerSupported(mappings->GetOperators()[i], inputTensorsVect, outputTensorsVect, reasonIfUnsupported)) { return false; } } return true; } } // namespace armnn