diff options
Diffstat (limited to 'ConversionUtils.hpp')
-rw-r--r-- | ConversionUtils.hpp | 750 |
1 files changed, 353 insertions, 397 deletions
diff --git a/ConversionUtils.hpp b/ConversionUtils.hpp index 439d4a4a..2e3a0424 100644 --- a/ConversionUtils.hpp +++ b/ConversionUtils.hpp @@ -1,5 +1,5 @@ // -// Copyright © 2017 Arm Ltd and Contributors. All rights reserved. +// Copyright © 2017-2023 Arm Ltd and Contributors. All rights reserved. // SPDX-License-Identifier: MIT // @@ -8,9 +8,7 @@ #include "Utils.hpp" #include <armnn/ArmNN.hpp> -#include <armnn/ILayerSupport.hpp> #include <armnn/BackendHelper.hpp> -#include <armnn/utility/Assert.hpp> #include <armnn/utility/IgnoreUnused.hpp> #include <armnn/utility/NumericCast.hpp> @@ -73,6 +71,9 @@ public: const armnn::TensorInfo& GetTensorInfo() const; + void SanitizeQuantizationScale(LayerInputHandle& weight, + LayerInputHandle& input); + private: armnn::IOutputSlot* m_OutputSlot; bool m_Valid; @@ -90,7 +91,7 @@ public: // @param valueStart Start address of tensor data. Belongs to one of the memory pools associated with // the model being converted. // @param numBytes Number of bytes for the tensor data. - ConstTensorPin(const armnn::TensorInfo& tensorInfo, const void* valueStart, uint32_t numBytes, + ConstTensorPin(armnn::TensorInfo& tensorInfo, const void* valueStart, uint32_t numBytes, const armnn::PermutationVector& mappings); ConstTensorPin(const ConstTensorPin& other) = delete; @@ -137,7 +138,7 @@ static bool Fail(const char* formatStr, Args&&... args) // Convenience macro to call an Is*Supported function and log caller name together with reason for lack of support. // Called as: FORWARD_LAYER_SUPPORT_FUNC(__func__, Is*Supported, backends, a, b, c, d, e) -#define FORWARD_LAYER_SUPPORT_FUNC(funcName, func, backends, supported, ...) \ +#define FORWARD_LAYER_SUPPORT_FUNC(funcName, func, backends, supported, setBackend, ...) \ try \ { \ for (auto&& backendId : backends) \ @@ -150,6 +151,7 @@ try \ layerSupportObject.func(__VA_ARGS__, armnn::Optional<std::string&>(reasonIfUnsupported)); \ if (supported) \ { \ + setBackend = backendId; \ break; \ } \ else \ @@ -278,7 +280,10 @@ armnn::IConnectableLayer& AddReshapeLayer(armnn::INetwork& network, reshapeDescriptor.m_TargetShape = reshapeInfo.GetShape(); armnn::IConnectableLayer* reshapeLayer = network.AddReshapeLayer(reshapeDescriptor); - ARMNN_ASSERT(reshapeLayer != nullptr); + if (!reshapeLayer) + { + throw armnn::RuntimeException("ReshapeLayer is null"); + } // Attach the input layer to the reshape layer inputLayer.Connect(reshapeLayer->GetInputSlot(0)); @@ -292,7 +297,10 @@ bool BroadcastTensor(LayerInputHandle& input0, armnn::IConnectableLayer* startLayer, ConversionData& data) { - ARMNN_ASSERT(startLayer != nullptr); + if (!startLayer) + { + throw armnn::RuntimeException("StartLayer is null"); + } const armnn::TensorInfo& inputInfo0 = input0.GetTensorInfo(); const armnn::TensorInfo& inputInfo1 = input1.GetTensorInfo(); @@ -335,10 +343,12 @@ bool BroadcastTensor(LayerInputHandle& input0, armnn::ReshapeDescriptor reshapeDescriptor; bool isSupported = false; + armnn::BackendId setBackend; FORWARD_LAYER_SUPPORT_FUNC(__func__, IsReshapeSupported, data.m_Backends, isSupported, + setBackend, smallInfo, reshapedInfo, reshapeDescriptor); @@ -347,8 +357,13 @@ bool BroadcastTensor(LayerInputHandle& input0, return false; } - ARMNN_ASSERT(data.m_Network != nullptr); + if (!data.m_Network) + { + throw armnn::RuntimeException("Network is null"); + } + armnn::IConnectableLayer& reshapeLayer = AddReshapeLayer(*data.m_Network, smallInputHandle, reshapedInfo); + reshapeLayer.SetBackendId(setBackend); if (input0IsSmaller) { @@ -473,7 +488,8 @@ void SanitizeBiasQuantizationScale(armnn::TensorInfo& biasInfo, std::transform(biasScales.begin(), biasScales.end(), biasScales.begin(), UpdateBiasScaleValue); biasInfo.SetQuantizationScales(biasScales); - biasInfo.SetQuantizationDim(weightInfo.GetQuantizationDim()); + // bias is expected to be a 1d tensor, set qdim=0 + biasInfo.SetQuantizationDim(0); ALOGV("Bias quantization params have been updated for per-axis quantization"); } @@ -494,7 +510,7 @@ void SanitizeBiasQuantizationScale(armnn::TensorInfo& biasInfo, // 4D Tensor Permutations const armnn::PermutationVector IdentityPermutation4D({ 0U, 1U, 2U, 3U }); const armnn::PermutationVector IdentityPermutation3D({ 0U, 1U, 2U }); -const armnn::PermutationVector SwapDim1And2({ 0U, 2U, 1U, 3U }); +const armnn::PermutationVector SwapDim2And3({ 0U, 1U, 3U, 2U }); // 3D Permutation Vectors const armnn::PermutationVector RotateTensorLeft({ 1U, 2U, 0U }); @@ -506,9 +522,10 @@ armnn::IConnectableLayer& AddTransposeLayer(armnn::INetwork& network, OSlot& inp { // Add swizzle layer armnn::IConnectableLayer* const layer = network.AddTransposeLayer(mappings); - - ARMNN_ASSERT(layer != nullptr); - + if (!layer) + { + throw armnn::RuntimeException("TransposeLayer is null"); + } // Connect input to swizzle layer input.Connect(layer->GetInputSlot(0)); @@ -570,7 +587,8 @@ bool RequiresReshape(armnn::TensorShape & inputShape) void SwizzleInputs(armnn::INetwork& network, std::vector<LayerInputHandle>& inputs, std::vector<armnn::TensorShape>& inputShapes, - const armnn::PermutationVector& mapping) + const armnn::PermutationVector& mapping, + std::vector<armnn::BackendId>& setBackends) { if (!mapping.IsEqual(IdentityPermutation4D)) { @@ -579,6 +597,7 @@ void SwizzleInputs(armnn::INetwork& network, { // add swizzle layer armnn::IConnectableLayer& swizzleLayer = AddTransposeLayer(network, inputs[i], mapping); + swizzleLayer.SetBackendId(setBackends[i]); auto& outputSlot = swizzleLayer.GetOutputSlot(0); auto& outputInfo = outputSlot.GetTensorInfo(); // replace inputs with the swizzled ones @@ -596,6 +615,7 @@ bool TransposeInputTensors(ConversionData& data, // If we have a IdentityPermutation4D or IdentityPermutation3D then we are not permuting if (!mapping.IsEqual(IdentityPermutation4D) && !mapping.IsEqual(IdentityPermutation3D)) { + std::vector<armnn::BackendId> setBackendsVec; armnn::TensorInfo outputTransposeInfo; size_t nInputs = inputs.size(); for (size_t i=0; i<nInputs; ++i) @@ -606,20 +626,23 @@ bool TransposeInputTensors(ConversionData& data, outputTransposeInfo = armnnUtils::TransposeTensorShape(inputs[i].GetTensorInfo(), mapping); bool isSupported = false; + armnn::BackendId setBackend; FORWARD_LAYER_SUPPORT_FUNC(__func__, IsTransposeSupported, data.m_Backends, isSupported, + setBackend, inputs[i].GetTensorInfo(), outputTransposeInfo, transposeDesc); + setBackendsVec.push_back(setBackend); if (!isSupported) { return false; } } - SwizzleInputs(*data.m_Network, inputs, inputShapes, mapping); + SwizzleInputs(*data.m_Network, inputs, inputShapes, mapping, setBackendsVec); } return true; } @@ -630,15 +653,19 @@ bool CreateConcatPermutationParameters(const unsigned int numberOfDimensions, std::pair<armnn::PermutationVector, armnn::PermutationVector> & permutationPair) { bool needPermute = false; - ARMNN_ASSERT(numberOfDimensions >= 3); + + if (numberOfDimensions < 3) + { + return Fail("%s: Invalid numberOfDimensions: %i < 3", __func__, numberOfDimensions); + } // ArmNN uses Compute Library subtensors to perform concatenation // This only works when concatenating along dimension 0, 1 or 3 for a 4-D tensor, // or along dimension 0 or 2 for a 3-D tensor. if (numberOfDimensions == 4 && concatDimension == 2) { - concatDimension = 1; - permutationPair = std::make_pair(SwapDim1And2, SwapDim1And2); + concatDimension = 3; + permutationPair = std::make_pair(SwapDim2And3, SwapDim2And3); needPermute = true; } else if (numberOfDimensions == 3 && concatDimension == 1) @@ -696,13 +723,18 @@ const HalOperand* GetInputOperand(const HalOperation& operation, { if (failOnIndexOutOfBounds) { - Fail("%s: invalid input index: %i out of %i", __func__, inputIndex, operation.inputs.size()); + Fail("%s: Invalid input index: %i out of %i", __func__, inputIndex, operation.inputs.size()); } return nullptr; } // Model should have been validated beforehand - ARMNN_ASSERT(operation.inputs[inputIndex] < getMainModel(model).operands.size()); + if (operation.inputs[inputIndex] >= getMainModel(model).operands.size()) + { + Fail("%s: invalid model index: %i >= %i", __func__, inputIndex, getMainModel(model).operands.size()); + return nullptr; + } + return &getMainModel(model).operands[operation.inputs[inputIndex]]; } @@ -721,8 +753,11 @@ const HalOperand* GetOutputOperand(const HalOperation& operation, } // Model should have been validated beforehand - ARMNN_ASSERT(operation.outputs[outputIndex] < getMainModel(model).operands.size()); - + if (operation.inputs[outputIndex] >= getMainModel(model).operands.size()) + { + Fail("%s: invalid model index: %i >= %i", __func__, outputIndex, getMainModel(model).operands.size()); + return nullptr; + } return &getMainModel(model).operands[operation.outputs[outputIndex]]; } @@ -843,11 +878,9 @@ ConstTensorPin ConvertOperandToConstTensorPin(const HalOperand& operand, } armnn::TensorInfo tensorInfo = GetTensorInfoForOperand(operand); - // Android datalayout might be different than armnn datalayout, e.g. the kernel for the depthwise convolution. - if (tensorInfo.HasPerAxisQuantization()) - { - tensorInfo.SetQuantizationDim(dimensionMappings[tensorInfo.GetQuantizationDim().value()]); - } + + // Make sure isConstant flag is set. + tensorInfo.SetConstant(); if (overrideTensorShape != nullptr) { @@ -1166,7 +1199,8 @@ template<typename HalPolicy, LayerInputHandle ConvertToLayerInputHandle(const HalOperation& operation, uint32_t inputIndex, const HalModel& model, - ConversionData& data) + ConversionData& data, + const armnn::PermutationVector& dimensionMappings = g_DontPermute) { using HalOperand = typename HalPolicy::Operand; using HalOperandType = typename HalPolicy::OperandType; @@ -1205,6 +1239,7 @@ LayerInputHandle ConvertToLayerInputHandle(const HalOperation& operation, IsInputSupported, data.m_Backends, isInputSupported, + armnn::BackendId(), operandTensorInfo); if (!isInputSupported) @@ -1229,14 +1264,18 @@ LayerInputHandle ConvertToLayerInputHandle(const HalOperation& operation, case HalOperandLifeTime::CONSTANT_REFERENCE: { // The tensor has an already known constant value, and can be converted into an ArmNN Constant layer. - ConstTensorPin tensorPin = ConvertOperandToConstTensorPin<HalPolicy>(*operand, model, data); + ConstTensorPin tensorPin = + ConvertOperandToConstTensorPin<HalPolicy>(*operand, model, data, dimensionMappings); + if (tensorPin.IsValid()) { bool isSupported = false; + armnn::BackendId setBackend; FORWARD_LAYER_SUPPORT_FUNC(__func__, IsConstantSupported, data.m_Backends, isSupported, + setBackend, tensorPin.GetConstTensor().GetInfo()); if (!isSupported) { @@ -1245,17 +1284,18 @@ LayerInputHandle ConvertToLayerInputHandle(const HalOperation& operation, armnn::IConnectableLayer* constantLayer = data.m_Network->AddConstantLayer(tensorPin.GetConstTensor()); + constantLayer->SetBackendId(setBackend); armnn::IOutputSlot& outputSlot = constantLayer->GetOutputSlot(0); - outputSlot.SetTensorInfo(tensorPin.GetConstTensor().GetInfo()); + armnn::TensorInfo constantTensorInfo = tensorPin.GetConstTensor().GetInfo(); + outputSlot.SetTensorInfo(constantTensorInfo); - return LayerInputHandle(true, &outputSlot, operandTensorInfo); + return LayerInputHandle(true, &outputSlot, constantTensorInfo); } else { Fail("%s: invalid operand tensor", __func__); return LayerInputHandle(); } - break; } default: { @@ -1279,7 +1319,8 @@ template<typename HalPolicy> LayerInputHandle ConvertToLayerInputHandle(const ::android::hardware::neuralnetworks::V1_3::Operation& operation, uint32_t inputIndex, const::android::hardware::neuralnetworks::V1_3::Model& model, - ConversionData& data) + ConversionData& data, + const armnn::PermutationVector& dimensionMappings = g_DontPermute) { using HalOperand = typename HalPolicy::Operand; using HalOperandType = typename HalPolicy::OperandType; @@ -1332,6 +1373,7 @@ LayerInputHandle ConvertToLayerInputHandle(const ::android::hardware::neuralnetw IsInputSupported, data.m_Backends, isInputSupported, + armnn::BackendId(), operandTensorInfo); if (!isInputSupported) @@ -1356,14 +1398,18 @@ LayerInputHandle ConvertToLayerInputHandle(const ::android::hardware::neuralnetw case HalOperandLifeTime::CONSTANT_REFERENCE: { // The tensor has an already known constant value, and can be converted into an ArmNN Constant layer. - ConstTensorPin tensorPin = ConvertOperandToConstTensorPin<HalPolicy>(*operand, model, data); + ConstTensorPin tensorPin = + ConvertOperandToConstTensorPin<HalPolicy>(*operand, model, data, dimensionMappings); + if (tensorPin.IsValid()) { bool isSupported = false; + armnn::BackendId setBackend; FORWARD_LAYER_SUPPORT_FUNC(__func__, IsConstantSupported, data.m_Backends, isSupported, + setBackend, tensorPin.GetConstTensor().GetInfo()); if (!isSupported) { @@ -1372,10 +1418,12 @@ LayerInputHandle ConvertToLayerInputHandle(const ::android::hardware::neuralnetw armnn::IConnectableLayer* constantLayer = data.m_Network->AddConstantLayer(tensorPin.GetConstTensor()); + constantLayer->SetBackendId(setBackend); armnn::IOutputSlot& outputSlot = constantLayer->GetOutputSlot(0); - outputSlot.SetTensorInfo(tensorPin.GetConstTensor().GetInfo()); + armnn::TensorInfo constantTensorInfo = tensorPin.GetConstTensor().GetInfo(); + outputSlot.SetTensorInfo(constantTensorInfo); - return LayerInputHandle(true, &outputSlot, operandTensorInfo); + return LayerInputHandle(true, &outputSlot, constantTensorInfo); } else { @@ -1439,7 +1487,7 @@ bool SetupAndTrackLayerOutputSlot(const HalOperation& operation, // Type one dynamic tensors require the previous layer's output shape for inference for (unsigned int inputSlotIndex = 0; inputSlotIndex < layer.GetNumInputSlots(); ++inputSlotIndex) { - if(!layer.GetInputSlot(inputSlotIndex).GetConnection()) + if (!layer.GetInputSlot(inputSlotIndex).GetConnection()) { return false; } @@ -1569,13 +1617,14 @@ bool ConvertToActivation(const HalOperation& operation, const armnn::TensorInfo& outInfo = GetTensorInfoForOperand(*outputOperand); bool isSupported = false; - + armnn::BackendId setBackend; auto validateFunc = [&](const armnn::TensorInfo& outInfo, bool& isSupported) { FORWARD_LAYER_SUPPORT_FUNC(__func__, IsActivationSupported, data.m_Backends, isSupported, + setBackend, input.GetTensorInfo(), outInfo, activationDesc); @@ -1596,7 +1645,11 @@ bool ConvertToActivation(const HalOperation& operation, } armnn::IConnectableLayer* layer = data.m_Network->AddActivationLayer(activationDesc); - ARMNN_ASSERT(layer != nullptr); + layer->SetBackendId(setBackend); + if (!layer) + { + return Fail("%s: Could not add the ActivationLayer", __func__); + } input.Connect(layer->GetInputSlot(0)); return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data, nullptr, validateFunc); @@ -1782,13 +1835,14 @@ bool ConvertPooling2d(const HalOperation& operation, } bool isSupported = false; - + armnn::BackendId setBackend; auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) { FORWARD_LAYER_SUPPORT_FUNC(__func__, IsPooling2dSupported, data.m_Backends, isSupported, + setBackend, inputInfo, outputInfo, desc); @@ -1810,6 +1864,7 @@ bool ConvertPooling2d(const HalOperation& operation, } armnn::IConnectableLayer* pooling2dLayer = data.m_Network->AddPooling2dLayer(desc); + pooling2dLayer->SetBackendId(setBackend); if (!pooling2dLayer) { return Fail("%s: AddPooling2dLayer failed", __func__); @@ -1829,79 +1884,6 @@ bool ConvertPooling2d(const HalOperation& operation, template<typename HalPolicy, typename HalOperation = typename HalPolicy::Operation, typename HalModel = typename HalPolicy::Model> -bool ConvertAdd(const HalOperation& operation, const HalModel& model, ConversionData& data) -{ - using HalOperand = typename HalPolicy::Operand; - - LayerInputHandle input0 = ConvertToLayerInputHandle<HalPolicy>(operation, 0, model, data); - LayerInputHandle input1 = ConvertToLayerInputHandle<HalPolicy>(operation, 1, model, data); - - if (!input0.IsValid() || !input1.IsValid()) - { - return Fail("%s: Operation has invalid inputs", __func__); - } - - // The FuseActivation parameter is always the input index 2 - // and it should be optional - ActivationFn activationFunction; - if (!GetOptionalInputActivation<HalPolicy>(operation, 2, activationFunction, model, data)) - { - return Fail("%s: Operation has invalid inputs", __func__); - } - - const HalOperand* outputOperand = GetOutputOperand<HalPolicy>(operation, 0, model); - if (!outputOperand) - { - return false; - } - - const armnn::TensorInfo& inputInfo0 = input0.GetTensorInfo(); - const armnn::TensorInfo& inputInfo1 = input1.GetTensorInfo(); - - const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*outputOperand); - - bool isSupported = false; - auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) - { - FORWARD_LAYER_SUPPORT_FUNC(__func__, - IsAdditionSupported, - data.m_Backends, - isSupported, - inputInfo0, - inputInfo1, - outputInfo); - }; - - if(!IsDynamicTensor(outputInfo)) - { - validateFunc(outputInfo, isSupported); - } - else - { - isSupported = AreDynamicTensorsSupported(); - } - - if (!isSupported) - { - return false; - } - - armnn::IConnectableLayer* const startLayer = data.m_Network->AddAdditionLayer(); - - bool isReshapeSupported = BroadcastTensor(input0, input1, startLayer, data); - if (!isReshapeSupported) - { - return false; - } - - return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *startLayer, model, - data, nullptr, validateFunc, activationFunction); - -} - -template<typename HalPolicy, - typename HalOperation = typename HalPolicy::Operation, - typename HalModel = typename HalPolicy::Model> bool ConvertArgMinMax(const HalOperation& operation, const HalModel& model, ConversionData& data, @@ -1951,13 +1933,14 @@ bool ConvertArgMinMax(const HalOperation& operation, descriptor.m_Axis = axis; bool isSupported = false; - + armnn::BackendId setBackend; auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) { FORWARD_LAYER_SUPPORT_FUNC(__func__, IsArgMinMaxSupported, data.m_Backends, isSupported, + setBackend, inputInfo0, outputInfo, descriptor); @@ -1978,8 +1961,11 @@ bool ConvertArgMinMax(const HalOperation& operation, } armnn::IConnectableLayer* layer = data.m_Network->AddArgMinMaxLayer(descriptor); - assert(layer != nullptr); - + layer->SetBackendId(setBackend); + if (!layer) + { + return Fail("%s: Could not add the ArgMinMaxLayer", __func__); + } input0.Connect(layer->GetInputSlot(0)); return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data, nullptr, validateFunc); @@ -2082,10 +2068,12 @@ bool ConvertConcatenation(const HalOperation& operation, const HalModel& model, reshapeDescriptor.m_TargetShape = reshapeInfo.GetShape(); bool isSupported = false; + armnn::BackendId setBackendReshape; FORWARD_LAYER_SUPPORT_FUNC(__func__, IsReshapeSupported, data.m_Backends, isSupported, + setBackendReshape, operandInputHandle.GetTensorInfo(), reshapeInfo, reshapeDescriptor); @@ -2095,6 +2083,7 @@ bool ConvertConcatenation(const HalOperation& operation, const HalModel& model, return false; } armnn::IConnectableLayer& newReshape = AddReshapeLayer(*data.m_Network, operandInputHandle, reshapeInfo); + newReshape.SetBackendId(setBackendReshape); // Point to the reshape operation rather then the input operation operandShape = reshapeInfo.GetShape(); @@ -2110,7 +2099,11 @@ bool ConvertConcatenation(const HalOperation& operation, const HalModel& model, } } - ARMNN_ASSERT(inputShapes.size() == inputHandles.size()); + if (inputShapes.size() != inputHandles.size()) + { + return Fail("%s: invalid model input shapes size doesn't match input handles size: %i != %i", __func__, + inputShapes.size(), inputHandles.size()); + } if (inputsHaveBeenReshaped) { @@ -2197,9 +2190,16 @@ bool ConvertConcatenation(const HalOperation& operation, const HalModel& model, [](const LayerInputHandle& h)->const armnn::TensorInfo*{ return &h.GetTensorInfo(); }); bool isSupported = false; + armnn::BackendId setBackendConcat; auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported){ - FORWARD_LAYER_SUPPORT_FUNC(__func__, IsConcatSupported, data.m_Backends, isSupported, inputTensorInfos, - outputInfo, concatDescriptor); + FORWARD_LAYER_SUPPORT_FUNC(__func__, + IsConcatSupported, + data.m_Backends, + isSupported, + setBackendConcat, + inputTensorInfos, + outputInfo, + concatDescriptor); }; if (!isDynamicTensor) @@ -2217,15 +2217,24 @@ bool ConvertConcatenation(const HalOperation& operation, const HalModel& model, } armnn::IConnectableLayer* layer = data.m_Network->AddConcatLayer(concatDescriptor); - assert(layer != nullptr); + layer->SetBackendId(setBackendConcat); + if (!layer) + { + return Fail("%s: Could not add the ConcatLayer", __func__); + } layer->GetOutputSlot(0).SetTensorInfo(outputInfo); // Connect inputs to the layer const int numInputSlots = layer->GetNumInputSlots(); - assert(static_cast<std::size_t>(numInputSlots) == inputHandles.size()); + + if (static_cast<std::size_t>(numInputSlots) != inputHandles.size()) + { + return Fail("%s: invalid model input slots size doesn't match input handles size: %i != %i", __func__, + static_cast<std::size_t>(numInputSlots), inputHandles.size()); + } for (int i = 0; i < numInputSlots; ++i) { // connect the input directly to the merge (concat) layer - inputHandles[static_cast<unsigned int>(i)].Connect(layer->GetInputSlot(i)); + inputHandles[static_cast<unsigned int>(i)].Connect(layer->GetInputSlot(static_cast<unsigned int>(i))); } // Transpose the output shape @@ -2236,10 +2245,12 @@ bool ConvertConcatenation(const HalOperation& operation, const HalModel& model, armnn::TensorInfo outputTransposeInfo = armnnUtils::TransposeTensorShape(inputTransposeInfo, permutationPair.second); isSupported = false; + armnn::BackendId setBackendTranspose; FORWARD_LAYER_SUPPORT_FUNC(__func__, IsTransposeSupported, data.m_Backends, isSupported, + setBackendTranspose, inputTransposeInfo, outputTransposeInfo, transposeDesc); @@ -2250,6 +2261,7 @@ bool ConvertConcatenation(const HalOperation& operation, const HalModel& model, // Add permutation layer and connect the output to it, the permutation becomes the output layer armnn::IConnectableLayer& deswizzleLayer = AddTransposeLayer(*data.m_Network, layer->GetOutputSlot(0), permutationPair.second); + deswizzleLayer.SetBackendId(setBackendTranspose); layer = &deswizzleLayer; return true; @@ -2265,7 +2277,10 @@ bool ConvertConcatenation(const HalOperation& operation, const HalModel& model, if (isDynamicTensor) { // Infer the output shapes of concat if outputs are type 1 dynamic - ARMNN_ASSERT(layer->GetOutputSlot(0).IsTensorInfoSet()); + if (!layer->GetOutputSlot(0).IsTensorInfoSet()) + { + return Fail("%s: TensorInfo is not set", __func__); + } if (!ValidateConcatOutputShape(inputShapes, layer->GetOutputSlot(0).GetTensorInfo().GetShape(), concatDim)) @@ -2292,11 +2307,13 @@ bool ConvertConcatenation(const HalOperation& operation, const HalModel& model, armnn::TensorInfo concatInfo = layer->GetOutputSlot(0).GetTensorInfo(); isSupported = false; + armnn::BackendId setBackendReshape2; auto validateReshapeFunc = [&](const armnn::TensorInfo& afterConcatInfo, bool& isSupported){ FORWARD_LAYER_SUPPORT_FUNC(__func__, IsReshapeSupported, data.m_Backends, isSupported, + setBackendReshape2, concatInfo, afterConcatInfo, reshapeDescriptor); @@ -2316,6 +2333,7 @@ bool ConvertConcatenation(const HalOperation& operation, const HalModel& model, return false; } layer = &AddReshapeLayer(*data.m_Network, layer->GetOutputSlot(0), afterConcatInfo); + layer->SetBackendId(setBackendReshape2); return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, @@ -2351,18 +2369,21 @@ bool ConvertConv2d(const HalOperation& operation, const HalModel& model, Convers const armnn::TensorInfo& inputInfo = input.GetTensorInfo(); const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output); - // ArmNN does not currently support non-fixed weights or bias - const ConstTensorPin weightsPin = ConvertOperationInputToConstTensorPin<HalPolicy>(operation, 1, model, data); - const ConstTensorPin biasPin = ConvertOperationInputToConstTensorPin<HalPolicy>(operation, 2, model, data); + LayerInputHandle weightsInput = ConvertToLayerInputHandle<HalPolicy>(operation, 1, model, data); + if (!weightsInput.IsValid()) + { + return Fail("%s: Operation has invalid inputs", __func__); + } - if (!weightsPin.IsValid() || !biasPin.IsValid()) + LayerInputHandle biasInput = ConvertToLayerInputHandle<HalPolicy>(operation, 2, model, data); // 1D + if (!biasInput.IsValid()) { return Fail("%s: Operation has invalid inputs", __func__); } - armnn::ConstTensor weights = weightsPin.GetConstTensor(); - armnn::ConstTensor bias = biasPin.GetConstTensor(); - SanitizeBiasQuantizationScale(bias.GetInfo(), weights.GetInfo(), inputInfo); + biasInput.SanitizeQuantizationScale(weightsInput, input); + armnn::TensorInfo weightsInfo = weightsInput.GetTensorInfo(); + armnn::TensorInfo biasInfo = biasInput.GetTensorInfo(); armnn::Convolution2dDescriptor desc; desc.m_DataLayout = armnn::DataLayout::NHWC; @@ -2392,8 +2413,8 @@ bool ConvertConv2d(const HalOperation& operation, const HalModel& model, Convers return Fail("%s: Operation has invalid inputs", __func__); } - const uint32_t kernelX = weights.GetShape()[2]; - const uint32_t kernelY = weights.GetShape()[1]; + const uint32_t kernelX = weightsInfo.GetShape()[2]; + const uint32_t kernelY = weightsInfo.GetShape()[1]; const uint32_t inputX = inputInfo.GetShape()[2]; const uint32_t inputY = inputInfo.GetShape()[1]; @@ -2406,19 +2427,21 @@ bool ConvertConv2d(const HalOperation& operation, const HalModel& model, Convers } desc.m_BiasEnabled = true; - armnn::Optional<armnn::TensorInfo> biases(bias.GetInfo()); + armnn::Optional<armnn::TensorInfo> biases(biasInfo); bool isSupported = false; + armnn::BackendId setBackend; auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) { FORWARD_LAYER_SUPPORT_FUNC(__func__, IsConvolution2dSupported, data.m_Backends, isSupported, + setBackend, inputInfo, outputInfo, desc, - weights.GetInfo(), + weightsInfo, biases); }; @@ -2436,8 +2459,8 @@ bool ConvertConv2d(const HalOperation& operation, const HalModel& model, Convers return false; } - armnn::IConnectableLayer* startLayer = - data.m_Network->AddConvolution2dLayer(desc, weights, armnn::Optional<armnn::ConstTensor>(bias)); + armnn::IConnectableLayer* startLayer = data.m_Network->AddConvolution2dLayer(desc); + startLayer->SetBackendId(setBackend); if (!startLayer) { @@ -2446,6 +2469,10 @@ bool ConvertConv2d(const HalOperation& operation, const HalModel& model, Convers input.Connect(startLayer->GetInputSlot(0)); + // Connect weights and bias inputs + weightsInput.Connect(startLayer->GetInputSlot(1)); + biasInput.Connect(startLayer->GetInputSlot(2)); + return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *startLayer, model, data, nullptr, validateFunc, activation); } @@ -2484,7 +2511,7 @@ bool ConvertDepthToSpace(const HalOperation& operation, const HalModel& model, C GetInputScalar<HalPolicy>(operation, 1, HalOperandType::INT32, descriptor.m_BlockSize, model, data); if (descriptor.m_BlockSize <= 1) { - return Fail("%s: Block size must be at least 1 in all dimensions"); + return Fail("%s: Block size must be at least 1 in all dimensions", __func__); } descriptor.m_DataLayout = armnn::DataLayout::NHWC; @@ -2494,12 +2521,14 @@ bool ConvertDepthToSpace(const HalOperation& operation, const HalModel& model, C } bool isSupported = false; + armnn::BackendId setBackend; auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) { FORWARD_LAYER_SUPPORT_FUNC(__func__, IsDepthToSpaceSupported, data.m_Backends, isSupported, + setBackend, inputInfo, outputInfo, descriptor); @@ -2520,7 +2549,11 @@ bool ConvertDepthToSpace(const HalOperation& operation, const HalModel& model, C } armnn::IConnectableLayer* const layer = data.m_Network->AddDepthToSpaceLayer(descriptor); - assert(layer != nullptr); + layer->SetBackendId(setBackend); + if (!layer) + { + return Fail("%s: Could not add the DepthToSpaceLayer", __func__); + } input.Connect(layer->GetInputSlot(0)); return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data, nullptr, validateFunc); @@ -2554,10 +2587,9 @@ bool ConvertDepthwiseConv2d(const HalOperation& operation, const HalModel& model // ArmNN does not currently support non-fixed weights or bias // Find the shape of the weights tensor. In AndroidNN this will be [ 1, H, W, I * M ] const HalOperand* weightsOperand = GetInputOperand<HalPolicy>(operation, 1, model); - - if (weightsOperand == nullptr) + if (!weightsOperand) { - return Fail("%s: Operand is invalid", __func__); + return Fail("%s: Could not read weights", __func__); } // Basic sanity check on the weights shape. // ANEURALNETWORKS_DEPTHWISE_CONV_2D specifies a 4-D tensor, of shape @@ -2570,34 +2602,27 @@ bool ConvertDepthwiseConv2d(const HalOperation& operation, const HalModel& model armnn::DepthwiseConvolution2dDescriptor desc; desc.m_DataLayout = armnn::DataLayout::NHWC; - // Reinterpret weight data as [ H, W, I, M ] - armnn::TensorShape weightsShape({ weightsOperand->dimensions[1], - weightsOperand->dimensions[2], - inputInfo.GetShape()[3], - weightsOperand->dimensions[3] / inputInfo.GetShape()[3] }); - - // Swizzle weight data [ H, W, I, M ] -> [ M, I, H, W ] - const armnn::PermutationVector HWIMToMIHW = { 2U, 3U, 1U, 0U }; - - const ConstTensorPin weightsPin = - ConvertOperationInputToConstTensorPin<HalPolicy>(operation, - 1, - model, - data, - HWIMToMIHW, - &weightsShape); + LayerInputHandle weightsInput = ConvertToLayerInputHandle<HalPolicy>(operation, 1, model, data); + if (!weightsInput.IsValid()) + { + return Fail("%s: Operation has invalid inputs", __func__); + } - // Bias is a 1D tensor - const ConstTensorPin biasPin = ConvertOperationInputToConstTensorPin<HalPolicy>(operation, 2, model, data); + const HalOperand* biasOperand = GetInputOperand<HalPolicy>(operation, 2, model); + if (!biasOperand) + { + return Fail("%s: Could not read bias", __func__); + } - if (!weightsPin.IsValid() || !biasPin.IsValid()) + LayerInputHandle biasInput = ConvertToLayerInputHandle<HalPolicy>(operation, 2, model, data); // 1D + if (!biasInput.IsValid()) { return Fail("%s: Operation has invalid inputs", __func__); } - armnn::ConstTensor weights = weightsPin.GetConstTensor(); - armnn::ConstTensor bias = biasPin.GetConstTensor(); - SanitizeBiasQuantizationScale(bias.GetInfo(), weights.GetInfo(), inputInfo); + biasInput.SanitizeQuantizationScale(weightsInput, input); + armnn::TensorInfo weightsInfo = weightsInput.GetTensorInfo(); + armnn::TensorInfo biasInfo = biasInput.GetTensorInfo(); ActivationFn activation; @@ -2625,8 +2650,8 @@ bool ConvertDepthwiseConv2d(const HalOperation& operation, const HalModel& model return Fail("%s: Operation has invalid inputs", __func__); } - const uint32_t kernelX = weights.GetShape()[3]; - const uint32_t kernelY = weights.GetShape()[2]; + const uint32_t kernelX = weightsInfo.GetShape()[2]; + const uint32_t kernelY = weightsInfo.GetShape()[1]; const uint32_t inputX = inputInfo.GetShape()[2]; const uint32_t inputY = inputInfo.GetShape()[1]; @@ -2639,19 +2664,21 @@ bool ConvertDepthwiseConv2d(const HalOperation& operation, const HalModel& model } desc.m_BiasEnabled = true; - armnn::Optional<armnn::TensorInfo> biases(bias.GetInfo()); + armnn::Optional<armnn::TensorInfo> biases(biasInfo); bool isSupported = false; + armnn::BackendId setBackend; auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) { FORWARD_LAYER_SUPPORT_FUNC(__func__, IsDepthwiseConvolutionSupported, data.m_Backends, isSupported, + setBackend, inputInfo, outputInfo, desc, - weights.GetInfo(), + weightsInfo, biases); }; @@ -2670,8 +2697,8 @@ bool ConvertDepthwiseConv2d(const HalOperation& operation, const HalModel& model return false; } - armnn::IConnectableLayer* startLayer = - data.m_Network->AddDepthwiseConvolution2dLayer(desc, weights, armnn::Optional<armnn::ConstTensor>(bias)); + armnn::IConnectableLayer* startLayer = data.m_Network->AddDepthwiseConvolution2dLayer(desc); + startLayer->SetBackendId(setBackend); if (!startLayer) { return Fail("%s: AddDepthwiseConvolution2dLayer failed", __func__); @@ -2679,6 +2706,10 @@ bool ConvertDepthwiseConv2d(const HalOperation& operation, const HalModel& model input.Connect(startLayer->GetInputSlot(0)); + // Connect weights and bias inputs + weightsInput.Connect(startLayer->GetInputSlot(1)); + biasInput.Connect(startLayer->GetInputSlot(2)); + return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *startLayer, model, data, nullptr, validateFunc, activation); } @@ -2712,12 +2743,14 @@ bool ConvertDequantize(const HalOperation& operation, const HalModel& model, Con const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*outputOperand); bool isSupported = false; + armnn::BackendId setBackend; auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) { FORWARD_LAYER_SUPPORT_FUNC(__func__, IsDequantizeSupported, data.m_Backends, isSupported, + setBackend, inputInfo, outputInfo); }; @@ -2737,7 +2770,11 @@ bool ConvertDequantize(const HalOperation& operation, const HalModel& model, Con } armnn::IConnectableLayer* const layer = data.m_Network->AddDequantizeLayer(); - assert(layer != nullptr); + layer->SetBackendId(setBackend); + if (!layer) + { + return Fail("%s: Could not add the DequantizeLayer", __func__); + } input.Connect(layer->GetInputSlot(0)); return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data, nullptr, validateFunc); @@ -2746,10 +2783,16 @@ bool ConvertDequantize(const HalOperation& operation, const HalModel& model, Con template<typename HalPolicy, typename HalOperation = typename HalPolicy::Operation, typename HalModel = typename HalPolicy::Model> -bool ConvertDiv(const HalOperation& operation, const HalModel& model, ConversionData& data) +bool ConvertElementwiseBinary(const HalOperation& operation, + const HalModel& model, + ConversionData& data, + armnn::BinaryOperation binaryOperation) { using HalOperand = typename HalPolicy::Operand; + ALOGV("HalPolicy::ConvertElementwiseBinary()"); + ALOGV("binaryOperation = %s", GetBinaryOperationAsCString(binaryOperation)); + LayerInputHandle input0 = ConvertToLayerInputHandle<HalPolicy>(operation, 0, model, data); LayerInputHandle input1 = ConvertToLayerInputHandle<HalPolicy>(operation, 1, model, data); @@ -2758,35 +2801,38 @@ bool ConvertDiv(const HalOperation& operation, const HalModel& model, Conversion return Fail("%s: Operation has invalid inputs", __func__); } - // The FuseActivation parameter is always the input index 2 - // and it should be optional + // The FuseActivation parameter is always the input index 2, and it should be optional ActivationFn activationFunction; if (!GetOptionalInputActivation<HalPolicy>(operation, 2, activationFunction, model, data)) { - return Fail("%s: Operation has invalid inputs", __func__); + return Fail("%s: Operation has invalid optional input: activation function", __func__); } const HalOperand* output = GetOutputOperand<HalPolicy>(operation, 0, model); if (!output) { - return Fail("%s: Could not read output 0", __func__); + return Fail("%s: Could not read output", __func__); } const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output); + armnn::ElementwiseBinaryDescriptor descriptor(binaryOperation); + bool isSupported = false; auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) { FORWARD_LAYER_SUPPORT_FUNC(__func__, - IsDivisionSupported, + IsElementwiseBinarySupported, data.m_Backends, isSupported, + armnn::BackendId(), input0.GetTensorInfo(), input1.GetTensorInfo(), - outputInfo); + outputInfo, + binaryOperation); }; - if(!IsDynamicTensor(outputInfo)) + if (!IsDynamicTensor(outputInfo)) { validateFunc(outputInfo, isSupported); } @@ -2800,19 +2846,22 @@ bool ConvertDiv(const HalOperation& operation, const HalModel& model, Conversion return false; } - armnn::IConnectableLayer* const startLayer = data.m_Network->AddDivisionLayer(); - - bool isReshapeSupported = BroadcastTensor(input0, input1, startLayer, data); + armnn::IConnectableLayer* layer = data.m_Network->AddElementwiseBinaryLayer(descriptor); + if (!layer) + { + return Fail("%s: Could not add the ElementwiseBinaryLayer", __func__); + } + bool isReshapeSupported = BroadcastTensor(input0, input1, layer, data); if (!isReshapeSupported) { return false; } - return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *startLayer, model, - data, nullptr, validateFunc, activationFunction); - + return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data, nullptr, validateFunc, + activationFunction); } + template<typename HalPolicy, typename HalOperation = typename HalPolicy::Operation, typename HalModel = typename HalPolicy::Model> @@ -2835,12 +2884,14 @@ bool ConvertFloor(const HalOperation& operation, const HalModel& model, Conversi const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*outputOperand); bool isSupported = false; + armnn::BackendId setBackend; auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) { FORWARD_LAYER_SUPPORT_FUNC(__func__, IsFloorSupported, data.m_Backends, isSupported, + setBackend, input.GetTensorInfo(), outputInfo); }; @@ -2860,7 +2911,11 @@ bool ConvertFloor(const HalOperation& operation, const HalModel& model, Conversi } armnn::IConnectableLayer* layer = data.m_Network->AddFloorLayer(); - assert(layer != nullptr); + layer->SetBackendId(setBackend); + if (!layer) + { + return Fail("%s: Could not add the FloorLayer", __func__); + } input.Connect(layer->GetInputSlot(0)); return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data, nullptr, validateFunc); @@ -2945,7 +3000,11 @@ DequantizeResult DequantizeIfRequired(size_t operand_index, } const HalOperand* operand = GetInputOperand<HalPolicy>(operationIt, 0, model); - ARMNN_ASSERT(operand); + + if (!operand) + { + return { nullptr, 0, armnn::TensorInfo(), DequantizeStatus::INVALID_OPERAND }; + } if (!IsQSymm8(*operand)) { @@ -2969,8 +3028,12 @@ DequantizeResult DequantizeIfRequired(size_t operand_index, for (size_t i = 0; i < dequantizedBufferLength; ++i) { float* dstPtr = dequantizedBuffer.get(); - ARMNN_ASSERT(dstPtr); - *dstPtr++ = quantizedBuffer[i] * quantizationScale; + + if (!dstPtr) + { + return { nullptr, 0, armnn::TensorInfo(), DequantizeStatus::INVALID_OPERAND }; + } + *dstPtr = quantizedBuffer[i] * quantizationScale; } // Construct tensor info for dequantized ConstTensor @@ -3049,26 +3112,12 @@ bool ConvertFullyConnected(const HalOperation& operation, const HalModel& model, return Fail("%s: Could not read weights", __func__); } - const armnn::TensorInfo& weightsInfo = GetTensorInfoForOperand(*weightsOperand); - bool constantWeights = IsOperandConstant<HalPolicy>(*weightsOperand); - - armnn::Optional<armnn::ConstTensor> optionalWeights = armnn::EmptyOptional(); - if (!constantWeights) - { - weightsInput = ConvertToLayerInputHandle<HalPolicy>(operation, 1, model, data); - if (!weightsInput.IsValid()) - { - return Fail("%s: Operation has invalid inputs", __func__); - } - } - else + // If weights are constant a separate constant layer will be created to store data. + // Otherwise handle non const weights as inputs. + weightsInput = ConvertToLayerInputHandle<HalPolicy>(operation, 1, model, data); + if (!weightsInput.IsValid()) { - ConstTensorPin weightsPin = DequantizeAndMakeConstTensorPin<HalPolicy>(operation, model, data, 1); - if (!weightsPin.IsValid()) - { - return Fail("%s: Operation has invalid weights", __func__); - } - optionalWeights = armnn::Optional<armnn::ConstTensor>(weightsPin.GetConstTensor()); + return Fail("%s: Operation has invalid inputs", __func__); } LayerInputHandle biasInput = LayerInputHandle(); @@ -3077,33 +3126,16 @@ bool ConvertFullyConnected(const HalOperation& operation, const HalModel& model, { return Fail("%s: Could not read bias", __func__); } - armnn::TensorInfo biasInfo = GetTensorInfoForOperand(*biasOperand); - bool constantBias = IsOperandConstant<HalPolicy>(*biasOperand); - - armnn::Optional<armnn::ConstTensor> optionalBias = armnn::EmptyOptional(); - if (!constantBias) - { - biasInput = ConvertToLayerInputHandle<HalPolicy>(operation, 2, model, data); - if (!biasInput.IsValid()) - { - return Fail("%s: Operation has invalid inputs", __func__); - } - } - else - { - ConstTensorPin biasPin = ConvertOperationInputToConstTensorPin<HalPolicy>(operation, 2, model, data); // 1D - if (!biasPin.IsValid()) - { - return Fail("%s: Operation has invalid bias", __func__); - } - optionalBias = armnn::Optional<armnn::ConstTensor>(biasPin.GetConstTensor()); - } - if ((constantWeights && !constantBias) || (!constantWeights && constantBias)) + // If bias are constant a separate constant layer will be created to store data. + // Otherwise handle non const bias as inputs. + biasInput = ConvertToLayerInputHandle<HalPolicy>(operation, 2, model, data); // 1D + if (!biasInput.IsValid()) { - return Fail("%s: Non-compatible weights and bias", __func__); + return Fail("%s: Operation has invalid inputs", __func__); } + armnn::TensorInfo weightsInfo = weightsInput.GetTensorInfo(); armnn::TensorInfo reshapedInfo = inputInfo; try { @@ -3114,7 +3146,8 @@ bool ConvertFullyConnected(const HalOperation& operation, const HalModel& model, return Fail("%s: %s", __func__, e.what()); } - // ensuring that the bias value is within 1% of the weights input (small float differences can exist) + // Ensuring that the bias value is within 1% of the weights input (small float differences can exist) + armnn::TensorInfo biasInfo = biasInput.GetTensorInfo(); SanitizeBiasQuantizationScale(biasInfo, weightsInfo, reshapedInfo); ActivationFn activationFunction; @@ -3126,9 +3159,10 @@ bool ConvertFullyConnected(const HalOperation& operation, const HalModel& model, armnn::FullyConnectedDescriptor desc; desc.m_TransposeWeightMatrix = true; desc.m_BiasEnabled = true; - desc.m_ConstantWeights = constantWeights; + desc.m_ConstantWeights = IsOperandConstant<HalPolicy>(*weightsOperand); bool isSupported = false; + armnn::BackendId setBackend; auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) { if (!VerifyFullyConnectedShapes(reshapedInfo.GetShape(), @@ -3145,6 +3179,7 @@ bool ConvertFullyConnected(const HalOperation& operation, const HalModel& model, IsFullyConnectedSupported, data.m_Backends, isSupported, + setBackend, reshapedInfo, outputInfo, weightsInfo, @@ -3166,10 +3201,9 @@ bool ConvertFullyConnected(const HalOperation& operation, const HalModel& model, return false; } - armnn::IConnectableLayer* startLayer = - data.m_Network->AddFullyConnectedLayer(desc, - optionalWeights, - optionalBias); + // Add FullyConnected layer. Weights and bias will be connected as constant layers or non const inputs. + armnn::IConnectableLayer* startLayer = data.m_Network->AddFullyConnectedLayer(desc); + startLayer->SetBackendId(setBackend); if (inputInfo.GetNumDimensions() > 2U) { @@ -3177,7 +3211,10 @@ bool ConvertFullyConnected(const HalOperation& operation, const HalModel& model, reshapeDescriptor.m_TargetShape = reshapedInfo.GetShape(); armnn::IConnectableLayer* reshapeLayer = data.m_Network->AddReshapeLayer(reshapeDescriptor); - assert(reshapeLayer != nullptr); + if (!reshapeLayer) + { + return Fail("%s: could not add the reshapeLayer", __func__); + } input.Connect(reshapeLayer->GetInputSlot(0)); reshapeLayer->GetOutputSlot(0).SetTensorInfo(reshapedInfo); reshapeLayer->GetOutputSlot(0).Connect(startLayer->GetInputSlot(0)); @@ -3187,12 +3224,9 @@ bool ConvertFullyConnected(const HalOperation& operation, const HalModel& model, input.Connect(startLayer->GetInputSlot(0)); } - // connect weights input - if (!desc.m_ConstantWeights) - { - weightsInput.Connect(startLayer->GetInputSlot(1)); - biasInput.Connect(startLayer->GetInputSlot(2)); - } + // Connect weights and bias inputs + weightsInput.Connect(startLayer->GetInputSlot(1)); + biasInput.Connect(startLayer->GetInputSlot(2)); return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *startLayer, model, data, nullptr, validateFunc, activationFunction); @@ -3234,12 +3268,14 @@ bool ConvertL2Normalization(const HalOperation& operation, const HalModel& model desc.m_DataLayout = armnn::DataLayout::NHWC; bool isSupported = false; + armnn::BackendId setBackend; auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) { FORWARD_LAYER_SUPPORT_FUNC(__func__, IsL2NormalizationSupported, data.m_Backends, isSupported, + setBackend, inputInfo, outputInfo, desc); @@ -3260,7 +3296,11 @@ bool ConvertL2Normalization(const HalOperation& operation, const HalModel& model } armnn::IConnectableLayer* layer = data.m_Network->AddL2NormalizationLayer(desc); - assert(layer != nullptr); + layer->SetBackendId(setBackend); + if (!layer) + { + return Fail("%s: Could not add the L2NormalizationLayer", __func__); + } input.Connect(layer->GetInputSlot(0)); return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data, nullptr, validateFunc); @@ -3320,12 +3360,14 @@ bool ConvertLocalResponseNormalization(const HalOperation& operation, descriptor.m_NormSize = 1 + (2 * descriptor.m_NormSize); bool isSupported = false; + armnn::BackendId setBackend; auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) { FORWARD_LAYER_SUPPORT_FUNC(__func__, IsNormalizationSupported, data.m_Backends, isSupported, + setBackend, inputInfo, outputInfo, descriptor); @@ -3345,9 +3387,12 @@ bool ConvertLocalResponseNormalization(const HalOperation& operation, return false; } - armnn::IConnectableLayer* layer = data.m_Network->AddNormalizationLayer(descriptor); - assert(layer != nullptr); + layer->SetBackendId(setBackend); + if (!layer) + { + return Fail("%s: Could not add the NormalizationLayer", __func__); + } input.Connect(layer->GetInputSlot(0)); return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data, nullptr, validateFunc); @@ -3418,12 +3463,14 @@ bool ConvertMean(const HalOperation& operation, const HalModel& model, Conversio descriptor.m_KeepDims = keepDims > 0; bool isSupported = false; + armnn::BackendId setBackend; auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) { FORWARD_LAYER_SUPPORT_FUNC(__func__, IsMeanSupported, data.m_Backends, isSupported, + setBackend, inputInfo, outputInfo, descriptor); @@ -3444,80 +3491,14 @@ bool ConvertMean(const HalOperation& operation, const HalModel& model, Conversio } armnn::IConnectableLayer* const layer = data.m_Network->AddMeanLayer(descriptor); - assert(layer != nullptr); - input.Connect(layer->GetInputSlot(0)); - - return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data, nullptr, validateFunc); -} - -template<typename HalPolicy, - typename HalOperation = typename HalPolicy::Operation, - typename HalModel = typename HalPolicy::Model> -bool ConvertMul(const HalOperation& operation, const HalModel& model, ConversionData& data) -{ - using HalOperand = typename HalPolicy::Operand; - - LayerInputHandle input0 = ConvertToLayerInputHandle<HalPolicy>(operation, 0, model, data); - LayerInputHandle input1 = ConvertToLayerInputHandle<HalPolicy>(operation, 1, model, data); - - if (!input0.IsValid() || !input1.IsValid()) - { - return Fail("%s: Operation has invalid inputs", __func__); - } - - // The FuseActivation parameter is always the input index 2 - // and it should be optional - ActivationFn activationFunction; - if (!GetOptionalInputActivation<HalPolicy>(operation, 2, activationFunction, model, data)) - { - return Fail("%s: Operation has invalid inputs", __func__); - } - - const HalOperand* outputOperand = GetOutputOperand<HalPolicy>(operation, 0, model); - - if (outputOperand == nullptr) + layer->SetBackendId(setBackend); + if (!layer) { - return false; - } - - const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*outputOperand); - - bool isSupported = false; - auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) - { - FORWARD_LAYER_SUPPORT_FUNC(__func__, - IsMultiplicationSupported, - data.m_Backends, - isSupported, - input0.GetTensorInfo(), - input1.GetTensorInfo(), - outputInfo); - }; - - if(!IsDynamicTensor(outputInfo)) - { - validateFunc(outputInfo, isSupported); - } - else - { - isSupported = AreDynamicTensorsSupported(); - } - - if (!isSupported) - { - return false; - } - - armnn::IConnectableLayer* const startLayer = data.m_Network->AddMultiplicationLayer(); - - bool isReshapeSupported = BroadcastTensor(input0, input1, startLayer, data); - if (!isReshapeSupported) - { - return false; + return Fail("%s: Could not add the MeanLayer", __func__); } + input.Connect(layer->GetInputSlot(0)); - return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *startLayer, model, - data, nullptr, validateFunc, activationFunction); + return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data, nullptr, validateFunc); } template<typename HalPolicy, @@ -3561,12 +3542,14 @@ bool ConvertPad(HalOperation& operation, const HalModel& model, ConversionData& const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output); bool isSupported = false; + armnn::BackendId setBackend; auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) { FORWARD_LAYER_SUPPORT_FUNC(__func__, IsPadSupported, data.m_Backends, isSupported, + setBackend, inputInfo, outputInfo, descriptor); @@ -3587,7 +3570,11 @@ bool ConvertPad(HalOperation& operation, const HalModel& model, ConversionData& } armnn::IConnectableLayer* const layer = data.m_Network->AddPadLayer(descriptor); - assert(layer != nullptr); + layer->SetBackendId(setBackend); + if (!layer) + { + return Fail("%s: Could not add the PadLayer", __func__); + } input.Connect(layer->GetInputSlot(0)); return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data, nullptr, validateFunc); @@ -3646,12 +3633,14 @@ bool ConvertReshape(const HalOperation& operation, const HalModel& model, Conver const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*outputOperand); bool isSupported = false; + armnn::BackendId setBackend; auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) { FORWARD_LAYER_SUPPORT_FUNC(__func__, IsReshapeSupported, data.m_Backends, isSupported, + setBackend, input.GetTensorInfo(), outputInfo, reshapeDescriptor); @@ -3672,78 +3661,14 @@ bool ConvertReshape(const HalOperation& operation, const HalModel& model, Conver } armnn::IConnectableLayer* layer = data.m_Network->AddReshapeLayer(reshapeDescriptor); - assert(layer != nullptr); - input.Connect(layer->GetInputSlot(0)); - - return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data, nullptr, validateFunc); -} - -template<typename HalPolicy, - typename HalOperation = typename HalPolicy::Operation, - typename HalModel = typename HalPolicy::Model> -bool ConvertSub(const HalOperation& operation, const HalModel& model, ConversionData& data) -{ - using HalOperand = typename HalPolicy::Operand; - - LayerInputHandle input0 = ConvertToLayerInputHandle<HalPolicy>(operation, 0, model, data); - LayerInputHandle input1 = ConvertToLayerInputHandle<HalPolicy>(operation, 1, model, data); - - if (!input0.IsValid() || !input1.IsValid()) + layer->SetBackendId(setBackend); + if (!layer) { - return Fail("%s: Operation has invalid inputs", __func__); + return Fail("%s: Could not add the ReshapeLayer", __func__); } + input.Connect(layer->GetInputSlot(0)); - // The FuseActivation parameter is always the input index 2 - // and it should be optional - ActivationFn activationFunction; - if (!GetOptionalInputActivation<HalPolicy>(operation, 2, activationFunction, model, data)) - { - return Fail("%s: Operation has invalid inputs", __func__); - } - - const HalOperand* output = GetOutputOperand<HalPolicy>(operation, 0, model); - if (!output) - { - return Fail("%s: Could not read output 0", __func__); - } - - const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output); - - bool isSupported = false; - auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) - { - FORWARD_LAYER_SUPPORT_FUNC(__func__, - IsSubtractionSupported, - data.m_Backends, - isSupported, - input0.GetTensorInfo(), - input1.GetTensorInfo(), - outputInfo); - }; - - if(IsDynamicTensor(outputInfo)) - { - isSupported = AreDynamicTensorsSupported(); - } - else - { - validateFunc(outputInfo, isSupported); - } - - if (!isSupported) - { - return false; - } - - armnn::IConnectableLayer* const startLayer = data.m_Network->AddSubtractionLayer(); - - bool isReshapeSupported = BroadcastTensor(input0, input1, startLayer, data); - if (!isReshapeSupported) - { - return false; - } - return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *startLayer, model, - data, nullptr, validateFunc, activationFunction); + return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data, nullptr, validateFunc); } template<typename HalPolicy, @@ -3781,13 +3706,13 @@ bool ConvertSqueeze(const HalOperation& operation, const HalModel& model, Conver // if the operand index is out of bounds. const HalOperand* axisOperand = GetInputOperand<HalPolicy>(operation, 1, model, false); - const uint32_t dimensionSequence[] = { 0, 1, 2, 3 }; - std::vector<int32_t> axis; if (!axisOperand) { - axis.assign(dimensionSequence, - dimensionSequence + rank); + for (unsigned int i = 0; i < rank; ++i) + { + axis.push_back(static_cast<unsigned int>(i)); + } } else if (!GetTensorInt32Values<HalPolicy>(*axisOperand, axis, model, data)) { @@ -3814,10 +3739,12 @@ bool ConvertSqueeze(const HalOperation& operation, const HalModel& model, Conver reshapeDesc.m_TargetShape = outputInfo.GetShape(); bool isSupported = false; + armnn::BackendId setBackend; FORWARD_LAYER_SUPPORT_FUNC(__func__, IsReshapeSupported, data.m_Backends, isSupported, + setBackend, inputInfo, outputInfo, reshapeDesc); @@ -3828,7 +3755,11 @@ bool ConvertSqueeze(const HalOperation& operation, const HalModel& model, Conver } armnn::IConnectableLayer* const layer = data.m_Network->AddReshapeLayer(reshapeDesc); - assert(layer != nullptr); + layer->SetBackendId(setBackend); + if (!layer) + { + return Fail("%s: Could not add the ReshapeLayer", __func__); + } input.Connect(layer->GetInputSlot(0)); return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data); @@ -3914,12 +3845,14 @@ bool ConvertStridedSlice(const HalOperation& operation, const HalModel& model, C } bool isSupported = false; + armnn::BackendId setBackend; auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) { FORWARD_LAYER_SUPPORT_FUNC(__func__, IsStridedSliceSupported, data.m_Backends, isSupported, + setBackend, inputInfo, outputInfo, descriptor); @@ -3963,7 +3896,11 @@ bool ConvertStridedSlice(const HalOperation& operation, const HalModel& model, C } armnn::IConnectableLayer* const layer = data.m_Network->AddStridedSliceLayer(descriptor); - assert(layer != nullptr); + layer->SetBackendId(setBackend); + if (!layer) + { + return Fail("%s: Could not add the StridedSliceLayer", __func__); + } input.Connect(layer->GetInputSlot(0)); return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data, nullptr, validateFunc); @@ -4021,12 +3958,14 @@ bool ConvertTranspose(const HalOperation& operation, const HalModel& model, Conv const armnn::TensorInfo& outputInfo = GetTensorInfoForOperand(*output); bool isSupported = false; + armnn::BackendId setBackend; auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) { FORWARD_LAYER_SUPPORT_FUNC(__func__, IsTransposeSupported, data.m_Backends, isSupported, + setBackend, inputInfo, outputInfo, transposeDesc); @@ -4047,7 +3986,11 @@ bool ConvertTranspose(const HalOperation& operation, const HalModel& model, Conv } armnn::IConnectableLayer* const layer = data.m_Network->AddTransposeLayer(transposeDesc); - assert(layer != nullptr); + layer->SetBackendId(setBackend); + if (!layer) + { + return Fail("%s: Could not add the TransposeLayer", __func__); + } input.Connect(layer->GetInputSlot(0)); return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data, nullptr, validateFunc); @@ -4115,12 +4058,14 @@ bool ConvertBatchToSpaceNd(const HalOperation& operation, batchToSpaceNdDesc.m_Crops = {{0, 0}, {0, 0}}; bool isSupported = false; + armnn::BackendId setBackend; auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) { FORWARD_LAYER_SUPPORT_FUNC(__func__, IsBatchToSpaceNdSupported, data.m_Backends, isSupported, + setBackend, inputInfo, outputInfo, batchToSpaceNdDesc); @@ -4142,7 +4087,11 @@ bool ConvertBatchToSpaceNd(const HalOperation& operation, } armnn::IConnectableLayer* const layer = data.m_Network->AddBatchToSpaceNdLayer(batchToSpaceNdDesc); - assert(layer != nullptr); + layer->SetBackendId(setBackend); + if (!layer) + { + return Fail("%s: Could not add the BatchToSpaceNdLayer", __func__); + } input.Connect(layer->GetInputSlot(0)); return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data, nullptr, validateFunc); @@ -4217,7 +4166,8 @@ bool ConvertSpaceToBatchNd(const HalOperation& operation, const HalModel& model, return Fail("%s: Operation has invalid paddings operand, invalid padding values.", __func__); } - paddingList.emplace_back((unsigned int) paddingBeforeInput, (unsigned int) paddingAfterInput); + paddingList.emplace_back(static_cast<unsigned int>(paddingBeforeInput), + static_cast<unsigned int>(paddingAfterInput)); } armnn::SpaceToBatchNdDescriptor descriptor; @@ -4231,12 +4181,14 @@ bool ConvertSpaceToBatchNd(const HalOperation& operation, const HalModel& model, } bool isSupported = false; + armnn::BackendId setBackend; auto validateFunc = [&](const armnn::TensorInfo& outputInfo, bool& isSupported) { FORWARD_LAYER_SUPPORT_FUNC(__func__, IsSpaceToBatchNdSupported, data.m_Backends, isSupported, + setBackend, inputInfo, outputInfo, descriptor); @@ -4257,7 +4209,11 @@ bool ConvertSpaceToBatchNd(const HalOperation& operation, const HalModel& model, } armnn::IConnectableLayer* const layer = data.m_Network->AddSpaceToBatchNdLayer(descriptor); - assert(layer != nullptr); + layer->SetBackendId(setBackend); + if (!layer) + { + return Fail("%s: Could not add the BatchToSpaceLayer", __func__); + } input.Connect(layer->GetInputSlot(0)); return SetupAndTrackLayerOutputSlot<HalPolicy>(operation, 0, *layer, model, data, nullptr, validateFunc); |