From 2cddc72f7aa1eab43c69250e608d662909383ba7 Mon Sep 17 00:00:00 2001 From: Keith Davis Date: Thu, 7 Apr 2022 11:32:00 +0100 Subject: IVGCVSW-6124 ConstTensorsAsInput: Conv2d - FrontEnd * Update Front-end and Tools. * Updated Serializer, Deserializer and unit tests to reflect this. * Updated TfLiteDelegate, TfLiteParser and OnnxParser. * Updated Ref. * Fixed resulting Neon / CL tests * Unified optimizers for conv2d ops * Optimizer Fix - Fp32ToBf16 * Partial implementation for ACL backends to fix VTS failures !android-nn-driver:7477 Signed-off-by: Keith Davis Change-Id: I5fb18877f7ee32643e15a9818945356274bb401b --- src/backends/backendsCommon/WorkloadData.cpp | 15 +- src/backends/backendsCommon/WorkloadFactory.cpp | 12 +- .../backendsCommon/test/DynamicBackendTests.hpp | 2 +- .../test/FullyConnectedEndToEndTestImpl.hpp | 39 +- .../test/LayerReleaseConstantDataTest.cpp | 99 ++-- .../backendsCommon/test/OptimizationViewsTests.cpp | 45 +- .../test/OptimizeSubgraphViewTests.cpp | 505 ++++++++++++++++----- .../backendsCommon/test/OptimizedNetworkTests.cpp | 3 + .../backendsCommon/test/WorkloadDataValidation.cpp | 93 +++- .../test/layerTests/Conv2dTestImpl.cpp | 114 ++++- 10 files changed, 703 insertions(+), 224 deletions(-) (limited to 'src/backends/backendsCommon') diff --git a/src/backends/backendsCommon/WorkloadData.cpp b/src/backends/backendsCommon/WorkloadData.cpp index 289f780fba..37fda3e210 100644 --- a/src/backends/backendsCommon/WorkloadData.cpp +++ b/src/backends/backendsCommon/WorkloadData.cpp @@ -1246,7 +1246,13 @@ void Convolution2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) co { const std::string descriptorName{"Convolution2dQueueDescriptor"}; - ValidateNumInputs(workloadInfo, descriptorName, 1); + uint32_t numInputs = 2; + if (m_Parameters.m_BiasEnabled) + { + numInputs = 3; + } + + ValidateNumInputs(workloadInfo, descriptorName, numInputs); ValidateNumOutputs(workloadInfo, descriptorName, 1); const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; @@ -1255,9 +1261,8 @@ void Convolution2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) co ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input"); ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output"); - ValidatePointer(m_Weight, descriptorName, "weight"); + const TensorInfo& weightTensorInfo = workloadInfo.m_InputTensorInfos[1]; - const TensorInfo& weightTensorInfo = m_Weight->GetTensorInfo(); ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 4, "weight"); ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName); @@ -1265,9 +1270,7 @@ void Convolution2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) co Optional optionalBiasTensorInfo; if (m_Parameters.m_BiasEnabled) { - ValidatePointer(m_Bias, descriptorName, "bias"); - - optionalBiasTensorInfo = MakeOptional(m_Bias->GetTensorInfo()); + optionalBiasTensorInfo = MakeOptional(workloadInfo.m_InputTensorInfos[2]); const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value(); ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias"); diff --git a/src/backends/backendsCommon/WorkloadFactory.cpp b/src/backends/backendsCommon/WorkloadFactory.cpp index f624ee6021..3660e6e721 100644 --- a/src/backends/backendsCommon/WorkloadFactory.cpp +++ b/src/backends/backendsCommon/WorkloadFactory.cpp @@ -246,7 +246,10 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, const TensorInfo input = OverrideDataType(layer.GetInputSlot(0).GetConnection()->GetTensorInfo(), dataType); const TensorInfo output = OverrideDataType(layer.GetOutputSlot(0).GetTensorInfo(), dataType); - ARMNN_ASSERT(cLayer->m_Weight.get() != nullptr); + ARMNN_ASSERT_MSG(layer.GetInputSlot(1).GetConnection(), + "Convolution2dLayer: Weights should be connected as a Constant Layer."); + const TensorInfo weights = OverrideDataType(layer.GetInputSlot(1).GetConnection()->GetTensorInfo(), + dataType); const Convolution2dDescriptor& descriptor = cLayer->GetParameters(); @@ -254,14 +257,17 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId, Optional biases; if (descriptor.m_BiasEnabled) { - biases = OverrideDataType(cLayer->m_Bias->GetTensorInfo(), GetBiasTypeFromWeightsType(dataType)); + ARMNN_ASSERT_MSG(layer.GetInputSlot(2).GetConnection(), + "Convolution2dLayer: Bias should be connected as a Constant Layer."); + biases = OverrideDataType(layer.GetInputSlot(2).GetConnection()->GetTensorInfo(), + GetBiasTypeFromWeightsType(dataType)); } result = layerSupportObject.IsConvolution2dSupported( input, output, descriptor, - OverrideDataType(cLayer->m_Weight->GetTensorInfo(), dataType), + weights, biases, reason); break; diff --git a/src/backends/backendsCommon/test/DynamicBackendTests.hpp b/src/backends/backendsCommon/test/DynamicBackendTests.hpp index f53bd83100..0d98804954 100644 --- a/src/backends/backendsCommon/test/DynamicBackendTests.hpp +++ b/src/backends/backendsCommon/test/DynamicBackendTests.hpp @@ -1465,7 +1465,7 @@ void CreateReferenceDynamicBackendTestImpl() Convolution2dQueueDescriptor convolution2dQueueDescriptor; WorkloadInfo workloadInfo { - { inputInfo }, + { inputInfo, weightInfo }, { outputInfo } }; convolution2dQueueDescriptor.m_Inputs.push_back(nullptr); diff --git a/src/backends/backendsCommon/test/FullyConnectedEndToEndTestImpl.hpp b/src/backends/backendsCommon/test/FullyConnectedEndToEndTestImpl.hpp index 1076aa6669..0d2d2cb2de 100644 --- a/src/backends/backendsCommon/test/FullyConnectedEndToEndTestImpl.hpp +++ b/src/backends/backendsCommon/test/FullyConnectedEndToEndTestImpl.hpp @@ -110,8 +110,11 @@ armnn::INetworkPtr CreateFullyConnectedNetworkNoConnectedWeightsExplicit(const a { armnn::INetworkPtr network(armnn::INetwork::Create()); + + ConstTensor biases; + armnn::IConnectableLayer* inputLayer = network->AddInputLayer(0, "Input"); - armnn::IConnectableLayer* biasLayer = network->AddInputLayer(2, "Bias_Input"); + armnn::IConnectableLayer* biasLayer = network->AddConstantLayer(biases, "Bias_Input"); armnn::IConnectableLayer* fullyConnectedLayer = network->AddFullyConnectedLayer(descriptor, "Fully_Connected"); armnn::IConnectableLayer* outputLayer = network->AddOutputLayer(0, "Output"); @@ -402,16 +405,7 @@ void FullyConnectedErrorChecking(const std::vector& backends, IRuntime::CreationOptions options; IRuntimePtr runtime(IRuntime::Create(options)); - try - { - Optimize(*network, backends, runtime->GetDeviceSpec()); - FAIL("LayerValidationException should have been thrown"); - } - catch (const LayerValidationException& exc) - { - CHECK(strcmp(exc.what(), "Fully_Connected layer weights not set: Input slot(s) 1 not connected " - "to an output slot on FullyConnected layer \"Fully_Connected\"") == 0); - } + CHECK_THROWS_AS(Optimize(*network, backends, runtime->GetDeviceSpec()), LayerValidationException); } else if (!connectedBias) { @@ -429,16 +423,7 @@ void FullyConnectedErrorChecking(const std::vector& backends, IRuntime::CreationOptions options; IRuntimePtr runtime(IRuntime::Create(options)); - try - { - Optimize(*network, backends, runtime->GetDeviceSpec()); - FAIL("LayerValidationException should have been thrown"); - } - catch (const LayerValidationException& exc) - { - CHECK(strcmp(exc.what(), "Fully_Connected layer bias not set: Input slot(s) 2 not connected " - "to an output slot on FullyConnected layer \"Fully_Connected\"") == 0); - } + CHECK_THROWS_AS(Optimize(*network, backends, runtime->GetDeviceSpec()), LayerValidationException); } } else if(!connectedWeights && !connectedBias) @@ -452,17 +437,7 @@ void FullyConnectedErrorChecking(const std::vector& backends, IRuntime::CreationOptions options; IRuntimePtr runtime(IRuntime::Create(options)); - try - { - Optimize(*network, backends, runtime->GetDeviceSpec()); - FAIL("LayerValidationException should have been thrown"); - } - catch (const LayerValidationException& exc) - { - CHECK(strcmp(exc.what(), "Fully_Connected layer weights and bias not set: Input slot(s) 1 & 2 not " - "connected to an output slot on FullyConnected layer \"Fully_Connected\"") == 0); - } - + CHECK_THROWS_AS(Optimize(*network, backends, runtime->GetDeviceSpec()), LayerValidationException); } else if(!tensorInfoSet) { diff --git a/src/backends/backendsCommon/test/LayerReleaseConstantDataTest.cpp b/src/backends/backendsCommon/test/LayerReleaseConstantDataTest.cpp index 56f15a51e5..5ceb8ae4b4 100644 --- a/src/backends/backendsCommon/test/LayerReleaseConstantDataTest.cpp +++ b/src/backends/backendsCommon/test/LayerReleaseConstantDataTest.cpp @@ -70,49 +70,68 @@ TEST_CASE("ReleaseBatchNormalizationLayerConstantDataTest") } +TEST_CASE("ReleaseConvolution2dLayerConstantDataTest") +{ + Graph graph; + + // create the layer we're testing + Convolution2dDescriptor layerDesc; + layerDesc.m_PadLeft = 3; + layerDesc.m_PadRight = 3; + layerDesc.m_PadTop = 1; + layerDesc.m_PadBottom = 1; + layerDesc.m_StrideX = 2; + layerDesc.m_StrideY = 4; + layerDesc.m_BiasEnabled = true; + + Convolution2dLayer* const layer = graph.AddLayer(layerDesc, "layer"); - TEST_CASE("ReleaseConvolution2dLayerConstantDataTest") - { - Graph graph; + layer->m_Weight = std::make_unique(TensorInfo({ 2, 3, 5, 3 }, + armnn::DataType::Float32)); + layer->m_Bias = std::make_unique + (TensorInfo({ 2 }, GetBiasDataType(armnn::DataType::Float32))); - // create the layer we're testing - Convolution2dDescriptor layerDesc; - layerDesc.m_PadLeft = 3; - layerDesc.m_PadRight = 3; - layerDesc.m_PadTop = 1; - layerDesc.m_PadBottom = 1; - layerDesc.m_StrideX = 2; - layerDesc.m_StrideY = 4; - layerDesc.m_BiasEnabled = true; + layer->m_Weight->Allocate(); + layer->m_Bias->Allocate(); - Convolution2dLayer* const layer = graph.AddLayer(layerDesc, "layer"); + ConstantLayer* weightsLayer = graph.AddLayer("Weights"); + ConstantLayer* biasLayer = graph.AddLayer("Bias"); - layer->m_Weight = std::make_unique(TensorInfo({2, 3, 5, 3}, - armnn::DataType::Float32)); - layer->m_Bias = std::make_unique - (TensorInfo({2}, GetBiasDataType(armnn::DataType::Float32))); + weightsLayer->m_LayerOutput = std::make_shared(TensorInfo({ 2, 3, 5, 3 }, + armnn::DataType::Float32)); - layer->m_Weight->Allocate(); - layer->m_Bias->Allocate(); + biasLayer->m_LayerOutput = std::make_shared( + TensorInfo({2}, GetBiasDataType(armnn::DataType::Float32))); - // create extra layers - Layer* const input = graph.AddLayer(0, "input"); - Layer* const output = graph.AddLayer(0, "output"); + TensorInfo weightsInfo = weightsLayer->m_LayerOutput->GetTensorInfo(); + weightsInfo.SetConstant(); + TensorInfo biasInfo = biasLayer->m_LayerOutput->GetTensorInfo(); + biasInfo.SetConstant(); - // connect up - Connect(input, layer, TensorInfo({2, 3, 8, 16}, armnn::DataType::Float32)); - Connect(layer, output, TensorInfo({2, 2, 2, 10}, armnn::DataType::Float32)); - // check the constants that they are not NULL - CHECK(layer->m_Weight != nullptr); - CHECK(layer->m_Bias != nullptr); + weightsLayer->GetOutputSlot(0).SetTensorInfo(weightsInfo); + biasLayer->GetOutputSlot(0).SetTensorInfo(biasInfo); - // free up the constants.. - layer->ReleaseConstantData(); + // create extra layers + Layer* const input = graph.AddLayer(0, "input"); + Layer* const output = graph.AddLayer(0, "output"); - // check the constants that they are NULL now - CHECK(layer->m_Weight == nullptr); - CHECK(layer->m_Bias == nullptr); + // connect up + Connect(input, layer, TensorInfo({ 2, 3, 8, 16 }, armnn::DataType::Float32)); + weightsLayer->GetOutputSlot().Connect(layer->GetInputSlot(1)); + biasLayer->GetOutputSlot().Connect(layer->GetInputSlot(2)); + Connect(layer, output, TensorInfo({ 2, 2, 2, 10 }, armnn::DataType::Float32)); + + // check the constants that they are not NULL + CHECK(layer->m_Weight != nullptr); + CHECK(layer->m_Bias != nullptr); + + // free up the constants.. + layer->ReleaseConstantData(); + + // check the constants that they are NULL now + CHECK(layer->m_Weight == nullptr); + CHECK(layer->m_Bias == nullptr); } TEST_CASE("ReleaseDepthwiseConvolution2dLayerConstantDataTest") @@ -131,8 +150,10 @@ TEST_CASE("ReleaseDepthwiseConvolution2dLayerConstantDataTest") DepthwiseConvolution2dLayer* const layer = graph.AddLayer(layerDesc, "layer"); - layer->m_Weight = std::make_unique(TensorInfo({3, 3, 5, 3}, DataType::Float32)); - layer->m_Bias = std::make_unique(TensorInfo({9}, DataType::Float32)); + layer->m_Weight = std::make_unique( + TensorInfo({3, 3, 5, 3}, DataType::Float32)); + layer->m_Bias = std::make_unique( + TensorInfo({9}, DataType::Float32)); layer->m_Weight->Allocate(); layer->m_Bias->Allocate(); @@ -170,10 +191,10 @@ TEST_CASE("ReleaseFullyConnectedLayerConstantDataTest") float inputsQScale = 1.0f; float outputQScale = 2.0f; - layer->m_Weight = std::make_unique(TensorInfo({7, 20}, - DataType::QAsymmU8, inputsQScale, 0)); - layer->m_Bias = std::make_unique(TensorInfo({7}, - GetBiasDataType(DataType::QAsymmU8), inputsQScale)); + layer->m_Weight = std::make_unique( + TensorInfo({7, 20}, DataType::QAsymmU8, inputsQScale, 0)); + layer->m_Bias = std::make_unique( + TensorInfo({7}, GetBiasDataType(DataType::QAsymmU8), inputsQScale)); layer->m_Weight->Allocate(); layer->m_Bias->Allocate(); diff --git a/src/backends/backendsCommon/test/OptimizationViewsTests.cpp b/src/backends/backendsCommon/test/OptimizationViewsTests.cpp index 1219ac5a33..9b86784dce 100644 --- a/src/backends/backendsCommon/test/OptimizationViewsTests.cpp +++ b/src/backends/backendsCommon/test/OptimizationViewsTests.cpp @@ -61,31 +61,35 @@ TEST_CASE("OptimizedViewsSubgraphLayerCount") Layer* const inputLayer = baseGraph.AddLayer(0, "input"); Convolution2dDescriptor convDescriptor; - PreCompiledDescriptor substitutionLayerDescriptor(1, 1); + PreCompiledDescriptor substitutionLayerDescriptor(2, 1); Layer* const convLayer1 = baseGraph.AddLayer(convDescriptor, "conv1"); Layer* const convLayer2 = baseGraph.AddLayer(convDescriptor, "conv2"); + Layer* const weightsLayer1 = baseGraph.AddLayer("weights1"); + Layer* const weightsLayer2 = baseGraph.AddLayer("weights2"); Layer* const substitutableCompiledLayer = baseGraph.AddLayer(substitutionLayerDescriptor, "pre-compiled"); Layer* const outputLayer = baseGraph.AddLayer(0, "output"); inputLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0)); + weightsLayer1->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(1)); convLayer1->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(0)); + weightsLayer2->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(1)); convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); // Subgraph for a failed layer SubgraphViewSelector::SubgraphViewPtr failedSubgraph = - CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}), + CreateSubgraphViewFrom(CreateInputsFrom(convLayer1), CreateOutputsFrom({convLayer1}), {convLayer1}); // Subgraph for an untouched layer SubgraphViewSelector::SubgraphViewPtr untouchedSubgraph = - CreateSubgraphViewFrom(CreateInputsFrom({convLayer2}), + CreateSubgraphViewFrom(CreateInputsFrom(convLayer2), CreateOutputsFrom({convLayer2}), {convLayer2}); // Subgraph for a substitutable layer SubgraphViewSelector::SubgraphViewPtr substitutableSubgraph = - CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}), + CreateSubgraphViewFrom(CreateInputsFrom(convLayer1), CreateOutputsFrom({convLayer2}), {substitutableCompiledLayer}); // Create a Graph containing a layer to substitute in @@ -95,7 +99,7 @@ TEST_CASE("OptimizedViewsSubgraphLayerCount") // Subgraph for a substitution layer SubgraphViewSelector::SubgraphViewPtr substitutionSubgraph = - CreateSubgraphViewFrom(CreateInputsFrom({substitutionpreCompiledLayer}), + CreateSubgraphViewFrom(CreateInputsFrom(substitutionpreCompiledLayer), CreateOutputsFrom({substitutionpreCompiledLayer}), {substitutionpreCompiledLayer}); @@ -106,14 +110,14 @@ TEST_CASE("OptimizedViewsSubgraphLayerCount") view.AddUntouchedSubgraph(SubgraphView(*untouchedSubgraph)); SubgraphViewSelector::SubgraphViewPtr baseSubgraph = - CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}), + CreateSubgraphViewFrom(CreateInputsFrom(convLayer1), CreateOutputsFrom({convLayer2}), {substitutionpreCompiledLayer}); view.AddSubstitution({*baseSubgraph, *substitutionSubgraph}); // Construct original subgraph to compare against SubgraphViewSelector::SubgraphViewPtr originalSubgraph = - CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}), + CreateSubgraphViewFrom(CreateInputsFrom(convLayer1), CreateOutputsFrom({convLayer2}), {convLayer1, convLayer2, substitutionpreCompiledLayer}); @@ -147,11 +151,11 @@ TEST_CASE("OptimizedViewsSubgraphLayerCountUsingGetINetwork") convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); // Subgraph for a failed layer - SubgraphViewSelector::SubgraphViewPtr failedSubgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}), + SubgraphViewSelector::SubgraphViewPtr failedSubgraph = CreateSubgraphViewFrom(CreateInputsFrom(convLayer1), CreateOutputsFrom({convLayer1}), {convLayer1}); // Subgraph for an untouched layer - SubgraphViewSelector::SubgraphViewPtr untouchedSubgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer2}), + SubgraphViewSelector::SubgraphViewPtr untouchedSubgraph = CreateSubgraphViewFrom(CreateInputsFrom(convLayer2), CreateOutputsFrom({convLayer2}), {convLayer2}); @@ -162,21 +166,21 @@ TEST_CASE("OptimizedViewsSubgraphLayerCountUsingGetINetwork") // Subgraph for a substitution layer SubgraphViewSelector::SubgraphViewPtr substitutionSubgraph = - CreateSubgraphViewFrom(CreateInputsFrom({substitutionpreCompiledLayer}), + CreateSubgraphViewFrom(CreateInputsFrom(substitutionpreCompiledLayer), CreateOutputsFrom({substitutionpreCompiledLayer}), {substitutionpreCompiledLayer}); view.AddFailedSubgraph(SubgraphView(*failedSubgraph)); view.AddUntouchedSubgraph(SubgraphView(*untouchedSubgraph)); - SubgraphViewSelector::SubgraphViewPtr baseSubgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}), + SubgraphViewSelector::SubgraphViewPtr baseSubgraph = CreateSubgraphViewFrom(CreateInputsFrom(convLayer1), CreateOutputsFrom({convLayer2}), {substitutionpreCompiledLayer}); view.AddSubstitution({*baseSubgraph, *substitutionSubgraph}); // Construct original subgraph to compare against SubgraphViewSelector::SubgraphViewPtr originalSubgraph = - CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}), + CreateSubgraphViewFrom(CreateInputsFrom(convLayer1), CreateOutputsFrom({convLayer2}), {convLayer1, convLayer2, substitutionpreCompiledLayer}); @@ -192,26 +196,31 @@ TEST_CASE("OptimizedViewsSubgraphLayerCountFailValidate") Layer* const inputLayer = baseGraph.AddLayer(0, "input"); Convolution2dDescriptor convDescriptor; - PreCompiledDescriptor substitutionLayerDescriptor(1, 1); + PreCompiledDescriptor substitutionLayerDescriptor(2, 1); Layer* const convLayer1 = baseGraph.AddLayer(convDescriptor, "conv1"); Layer* const convLayer2 = baseGraph.AddLayer(convDescriptor, "conv2"); + Layer* const weightsLayer1 = baseGraph.AddLayer("weights1"); + Layer* const weightsLayer2 = baseGraph.AddLayer("weights2"); Layer* const substitutableCompiledLayer = baseGraph.AddLayer(substitutionLayerDescriptor, "pre-compiled"); Layer* const outputLayer = baseGraph.AddLayer(0, "output"); + inputLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0)); + weightsLayer1->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(1)); convLayer1->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(0)); + weightsLayer2->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(1)); convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); // Subgraph for an untouched layer SubgraphViewSelector::SubgraphViewPtr untouchedSubgraph = - CreateSubgraphViewFrom(CreateInputsFrom({convLayer2}), + CreateSubgraphViewFrom(CreateInputsFrom(convLayer2), CreateOutputsFrom({convLayer2}), {convLayer2}); // Subgraph for a substitutable layer SubgraphViewSelector::SubgraphViewPtr substitutableSubgraph = - CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}), + CreateSubgraphViewFrom(CreateInputsFrom(convLayer1), CreateOutputsFrom({convLayer2}), {substitutableCompiledLayer}); // Create a Graph containing a layer to substitute in @@ -221,7 +230,7 @@ TEST_CASE("OptimizedViewsSubgraphLayerCountFailValidate") // Subgraph for a substitution layer SubgraphViewSelector::SubgraphViewPtr substitutionSubgraph = - CreateSubgraphViewFrom(CreateInputsFrom({substitutionpreCompiledLayer}), + CreateSubgraphViewFrom(CreateInputsFrom(substitutionpreCompiledLayer), CreateOutputsFrom({substitutionpreCompiledLayer}), {substitutionpreCompiledLayer}); @@ -231,14 +240,14 @@ TEST_CASE("OptimizedViewsSubgraphLayerCountFailValidate") view.AddUntouchedSubgraph(SubgraphView(*untouchedSubgraph)); SubgraphViewSelector::SubgraphViewPtr baseSubgraph = - CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}), + CreateSubgraphViewFrom(CreateInputsFrom(convLayer1), CreateOutputsFrom({convLayer2}), {substitutionpreCompiledLayer}); view.AddSubstitution({*baseSubgraph, *substitutionSubgraph}); // Construct original subgraph to compare against SubgraphViewSelector::SubgraphViewPtr originalSubgraph = - CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}), + CreateSubgraphViewFrom(CreateInputsFrom(convLayer1), CreateOutputsFrom({convLayer2}), {convLayer1, convLayer2, substitutionpreCompiledLayer}); diff --git a/src/backends/backendsCommon/test/OptimizeSubgraphViewTests.cpp b/src/backends/backendsCommon/test/OptimizeSubgraphViewTests.cpp index ad59704e2a..45fcf19f90 100644 --- a/src/backends/backendsCommon/test/OptimizeSubgraphViewTests.cpp +++ b/src/backends/backendsCommon/test/OptimizeSubgraphViewTests.cpp @@ -106,6 +106,21 @@ Convolution2dLayer* AddConvolutionLayer(Graph& graph, return convLayer; } +// Convenience function to add a constant layer to a graph +ConstantLayer* AddConstantLayer(Graph& graph, + LayerNameToLayerMap& layersInGraph, + const std::string& layerName, + const ConstTensor& constTensor, + const TensorInfo& outputInfo) +{ + ConstantLayer* const constantLayer = graph.AddLayer(layerName.c_str()); + CHECK(constantLayer); + constantLayer->m_LayerOutput = std::make_shared(constTensor); + constantLayer->GetOutputSlot(0).SetTensorInfo(outputInfo); + layersInGraph.insert(std::make_pair(constantLayer->GetName(), constantLayer)); + return constantLayer; +} + // Convenience function to add a pooling layer to a graph Pooling2dLayer* AddPoolingLayer(Graph& graph, LayerNameToLayerMap& layersInGraph, @@ -246,7 +261,7 @@ SubgraphView::SubgraphViewPtr BuildFullyUnsupportedSubgraph1(Graph& graph, Layer poolingLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); // Create the subgraph view for the whole network - return CreateSubgraphViewFrom(CreateInputsFrom({poolingLayer}), + return CreateSubgraphViewFrom(CreateInputsFrom(poolingLayer), CreateOutputsFrom({poolingLayer}), {poolingLayer}); } @@ -287,7 +302,7 @@ SubgraphView::SubgraphViewPtr BuildFullyUnsupportedSubgraph2(Graph& graph, Layer pooling3Layer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); // Create the subgraph view for the whole network - return CreateSubgraphViewFrom(CreateInputsFrom({pooling1Layer}), + return CreateSubgraphViewFrom(CreateInputsFrom(pooling1Layer), CreateOutputsFrom({pooling3Layer}), {pooling1Layer, pooling2Layer, @@ -299,8 +314,11 @@ SubgraphView::SubgraphViewPtr BuildFullyOptimizableSubgraph1(Graph& graph, Layer { const TensorInfo inputInfo ({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0); const TensorInfo outputInfo({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0); - const TensorInfo weightInfo({ 16, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0); - const TensorInfo biasInfo ({ 1, 1, 1, 16 }, DataType::Signed32, 0.9f, 0); + TensorInfo weightInfo({ 16, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0); + TensorInfo biasInfo ({ 1, 1, 1, 16 }, DataType::Signed32, 0.9f, 0); + + weightInfo.SetConstant(true); + biasInfo.SetConstant(true); Convolution2dDescriptor convolutionDescriptor; convolutionDescriptor.m_StrideX = 1; @@ -308,20 +326,34 @@ SubgraphView::SubgraphViewPtr BuildFullyOptimizableSubgraph1(Graph& graph, Layer convolutionDescriptor.m_BiasEnabled = true; convolutionDescriptor.m_DataLayout = DataLayout::NHWC; + std::vector weightsVector(64); + ConstTensor constWeightsTensor(weightInfo, weightsVector); + + std::vector biasVector(16); + ConstTensor constBiasTensor(biasInfo, biasVector); + // Construct the graph Layer* const inputLayer = AddInputLayer(graph, "input layer", inputInfo); Convolution2dLayer* const convLayer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor, "conv layer", weightInfo, biasInfo, outputInfo); + + ConstantLayer* const weightsLayer = + AddConstantLayer(graph, layersInGraph, "Weights Layer", constWeightsTensor, outputInfo); + ConstantLayer* const biasLayer = AddConstantLayer(graph, layersInGraph, "Bias Layer", constBiasTensor, outputInfo); + Layer* const outputLayer = AddOutputLayer(graph, "output layer"); // Connect the network inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0)); + weightsLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(1)); + biasLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(2)); convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + std::vector ignoreSlots = {1, 2}; // Create the subgraph view for the whole network - return CreateSubgraphViewFrom(CreateInputsFrom({convLayer}), + return CreateSubgraphViewFrom(CreateInputsFrom(convLayer, ignoreSlots), CreateOutputsFrom({convLayer}), - {convLayer}); + {convLayer, weightsLayer, biasLayer}); } // Creates a subgraph with five convolutions layers, all supported by the mock backend @@ -329,8 +361,18 @@ SubgraphView::SubgraphViewPtr BuildFullyOptimizableSubgraph2(Graph& graph, Layer { const TensorInfo inputInfo ({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0); const TensorInfo outputInfo({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0); - const TensorInfo weightInfo({ 16, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0); - const TensorInfo biasInfo ({ 1, 1, 1, 16 }, DataType::Signed32, 0.9f, 0); + TensorInfo weightInfo({ 16, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0); + TensorInfo biasInfo ({ 1, 1, 1, 16 }, DataType::Signed32, 0.9f, 0); + + weightInfo.SetConstant(true); + biasInfo.SetConstant(true); + + std::vector weightsVector(64); + ConstTensor constWeightsTensor(weightInfo, weightsVector); + + std::vector biasVector(16); + ConstTensor constBiasTensor(biasInfo, biasVector); + Convolution2dDescriptor convolutionDescriptor; convolutionDescriptor.m_StrideX = 1; @@ -342,32 +384,84 @@ SubgraphView::SubgraphViewPtr BuildFullyOptimizableSubgraph2(Graph& graph, Layer Layer* const inputLayer = AddInputLayer(graph, "input layer", inputInfo); Convolution2dLayer* const conv1Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor, "conv1 layer", weightInfo, biasInfo, outputInfo); + ConstantLayer* const weightsLayer1 = + AddConstantLayer(graph, layersInGraph, "Weights Layer 1", constWeightsTensor, outputInfo); + ConstantLayer* const biasLayer1 = + AddConstantLayer(graph, layersInGraph, "Bias Layer 1", constBiasTensor, outputInfo); + Convolution2dLayer* const conv2Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor, "conv2 layer", weightInfo, biasInfo, outputInfo); + ConstantLayer* const weightsLayer2 = + AddConstantLayer(graph, layersInGraph, "Weights Layer 2", constWeightsTensor, outputInfo); + ConstantLayer* const biasLayer2 = + AddConstantLayer(graph, layersInGraph, "Bias Layer 2", constBiasTensor, outputInfo); + + Convolution2dLayer* const conv3Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor, "conv3 layer", weightInfo, biasInfo, outputInfo); + ConstantLayer* const weightsLayer3 = + AddConstantLayer(graph, layersInGraph, "Weights Layer 3", constWeightsTensor, outputInfo); + ConstantLayer* const biasLayer3 = + AddConstantLayer(graph, layersInGraph, "Bias Layer 3", constBiasTensor, outputInfo); + Convolution2dLayer* const conv4Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor, "conv4 layer", weightInfo, biasInfo, outputInfo); + ConstantLayer* const weightsLayer4 = + AddConstantLayer(graph, layersInGraph, "Weights Layer 4", constWeightsTensor, outputInfo); + ConstantLayer* const biasLayer4 = + AddConstantLayer(graph, layersInGraph, "Bias Layer 4", constBiasTensor, outputInfo); + Convolution2dLayer* const conv5Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor, "conv5 layer", weightInfo, biasInfo, outputInfo); + ConstantLayer* const weightsLayer5 = + AddConstantLayer(graph, layersInGraph, "Weights Layer 5", constWeightsTensor, outputInfo); + ConstantLayer* const biasLayer5 = + AddConstantLayer(graph, layersInGraph, "Bias Layer 5", constBiasTensor, outputInfo); + + Layer* const outputLayer = AddOutputLayer(graph, "output layer"); // Connect the network inputLayer->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(0)); + weightsLayer1->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(1)); + biasLayer1->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(2)); + conv1Layer->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(0)); + weightsLayer2->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(1)); + biasLayer2->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(2)); + conv2Layer->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(0)); + weightsLayer3->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(1)); + biasLayer3->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(2)); + conv3Layer->GetOutputSlot(0).Connect(conv4Layer->GetInputSlot(0)); + weightsLayer4->GetOutputSlot(0).Connect(conv4Layer->GetInputSlot(1)); + biasLayer4->GetOutputSlot(0).Connect(conv4Layer->GetInputSlot(2)); + conv4Layer->GetOutputSlot(0).Connect(conv5Layer->GetInputSlot(0)); - conv5Layer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + weightsLayer5->GetOutputSlot(0).Connect(conv5Layer->GetInputSlot(1)); + biasLayer5->GetOutputSlot(0).Connect(conv5Layer->GetInputSlot(2)); + conv5Layer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + std::vector ignoreSlots = {1, 2}; // Create the subgraph view for the whole network - return CreateSubgraphViewFrom(CreateInputsFrom({conv1Layer}), - CreateOutputsFrom({conv5Layer}), - {conv1Layer, - conv2Layer, - conv3Layer, - conv4Layer, - conv5Layer}); + return CreateSubgraphViewFrom(CreateInputsFrom(conv1Layer, ignoreSlots), + CreateOutputsFrom({ conv5Layer }), + { weightsLayer1, + biasLayer1, + conv1Layer, + weightsLayer2, + biasLayer2, + conv2Layer, + weightsLayer3, + biasLayer3, + conv3Layer, + weightsLayer4, + biasLayer4, + conv4Layer, + weightsLayer5, + biasLayer5, + conv5Layer }); } // Creates a subgraph with both supported and unsupported layers @@ -376,8 +470,17 @@ SubgraphView::SubgraphViewPtr BuildPartiallySupportedSubgraph(Graph& graph, Laye { const TensorInfo inputInfo ({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0); const TensorInfo outputInfo({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0); - const TensorInfo weightInfo({ 16, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0); - const TensorInfo biasInfo ({ 1, 1, 1, 16 }, DataType::Signed32, 0.9f, 0); + TensorInfo weightInfo({ 16, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0); + TensorInfo biasInfo ({ 1, 1, 1, 16 }, DataType::Signed32, 0.9f, 0); + + weightInfo.SetConstant(true); + biasInfo.SetConstant(true); + + std::vector weightsVector(64); + ConstTensor constWeightsTensor(weightInfo, weightsVector); + + std::vector biasVector(16); + ConstTensor constBiasTensor(biasInfo, biasVector); Convolution2dDescriptor convolutionDescriptor; convolutionDescriptor.m_StrideX = 1; @@ -400,12 +503,25 @@ SubgraphView::SubgraphViewPtr BuildPartiallySupportedSubgraph(Graph& graph, Laye // Construct the graph Layer* const inputLayer = AddInputLayer(graph, "input layer", inputInfo); + ConstantLayer* const weightsLayer1 = + AddConstantLayer(graph, layersInGraph, "Weights Layer 1", constWeightsTensor, outputInfo); + + ConstantLayer* const biasLayer1 = + AddConstantLayer(graph, layersInGraph, "Bias Layer 1", constBiasTensor, outputInfo); + Convolution2dLayer* const conv1Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor, "conv1 layer", weightInfo, biasInfo, outputInfo); Pooling2dLayer* const pooling1Layer = AddPoolingLayer(graph, layersInGraph, poolingDescriptor, "pooling1 layer", outputInfo); Pooling2dLayer* const pooling2Layer = AddPoolingLayer(graph, layersInGraph, poolingDescriptor, "pooling2 layer", outputInfo); + + ConstantLayer* const weightsLayer2 = + AddConstantLayer(graph, layersInGraph, "Weights Layer 2", constWeightsTensor, outputInfo); + + ConstantLayer* const biasLayer2 = + AddConstantLayer(graph, layersInGraph, "Bias Layer 2", constBiasTensor, outputInfo); + Convolution2dLayer* const conv2Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor, "conv2 layer", weightInfo, biasInfo, outputInfo); Pooling2dLayer* const pooling3Layer = AddPoolingLayer(graph, layersInGraph, poolingDescriptor, @@ -414,18 +530,27 @@ SubgraphView::SubgraphViewPtr BuildPartiallySupportedSubgraph(Graph& graph, Laye // Connect the network inputLayer->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(0)); + weightsLayer1->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(1)); + biasLayer1->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(2)); conv1Layer->GetOutputSlot(0).Connect(pooling1Layer->GetInputSlot(0)); pooling1Layer->GetOutputSlot(0).Connect(pooling2Layer->GetInputSlot(0)); pooling2Layer->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(0)); + weightsLayer2->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(1)); + biasLayer2->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(2)); conv2Layer->GetOutputSlot(0).Connect(pooling3Layer->GetInputSlot(0)); pooling3Layer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + std::vector ignoreSlots = {1, 2}; // Create the subgraph view for the whole network - return CreateSubgraphViewFrom(CreateInputsFrom({conv1Layer}), + return CreateSubgraphViewFrom(CreateInputsFrom(conv1Layer, ignoreSlots), CreateOutputsFrom({pooling3Layer}), - {conv1Layer, + {weightsLayer1, + biasLayer1, + conv1Layer, pooling1Layer, pooling2Layer, + weightsLayer2, + biasLayer2, conv2Layer, pooling3Layer}); } @@ -435,9 +560,17 @@ SubgraphView::SubgraphViewPtr BuildFullyUnoptimizableSubgraph1(Graph& graph, Lay { const TensorInfo inputInfo ({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0); const TensorInfo outputInfo({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0); - const TensorInfo weightInfo({ 16, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0); - const TensorInfo biasInfo ({ 1, 1, 1, 16 }, DataType::Signed32, 0.9f, 0); + TensorInfo weightInfo({ 16, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0); + TensorInfo biasInfo ({ 1, 1, 1, 16 }, DataType::Signed32, 0.9f, 0); + weightInfo.SetConstant(true); + biasInfo.SetConstant(true); + + std::vector weightsVector(64); + ConstTensor constWeightsTensor(weightInfo, weightsVector); + + std::vector biasVector(16); + ConstTensor constBiasTensor(biasInfo, biasVector); Convolution2dDescriptor convolutionDescriptor; convolutionDescriptor.m_StrideX = 1; convolutionDescriptor.m_StrideY = 1; @@ -446,6 +579,13 @@ SubgraphView::SubgraphViewPtr BuildFullyUnoptimizableSubgraph1(Graph& graph, Lay // Construct the graph Layer* const inputLayer = AddInputLayer(graph, "input layer", inputInfo); + + ConstantLayer* const weightsLayer = + AddConstantLayer(graph, layersInGraph, "Weights Layer unoptimizable", constWeightsTensor, outputInfo); + + ConstantLayer* const biasLayer = + AddConstantLayer(graph, layersInGraph, "Bias Layer unoptimizable", constBiasTensor, outputInfo); + Convolution2dLayer* const convLayer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor, "conv layer unoptimizable", weightInfo, biasInfo, outputInfo); @@ -453,12 +593,15 @@ SubgraphView::SubgraphViewPtr BuildFullyUnoptimizableSubgraph1(Graph& graph, Lay // Connect the network inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0)); + weightsLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(1)); + biasLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(2)); convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + std::vector ignoreSlots = {1, 2}; // Create the subgraph view for the whole network - return CreateSubgraphViewFrom(CreateInputsFrom({convLayer}), + return CreateSubgraphViewFrom(CreateInputsFrom(convLayer, ignoreSlots), CreateOutputsFrom({convLayer}), - {convLayer}); + {convLayer, weightsLayer, biasLayer}); } // Creates a subgraph with some unoptimizable layers ("unoptimizable" is added to the layer's name) @@ -466,8 +609,17 @@ SubgraphView::SubgraphViewPtr BuildPartiallyOptimizableSubgraph1(Graph& graph, L { const TensorInfo inputInfo ({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0); const TensorInfo outputInfo({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0); - const TensorInfo weightInfo({ 16, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0); - const TensorInfo biasInfo ({ 1, 1, 1, 16 }, DataType::Signed32, 0.9f, 0); + TensorInfo weightInfo({ 16, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0); + TensorInfo biasInfo ({ 1, 1, 1, 16 }, DataType::Signed32, 0.9f, 0); + + weightInfo.SetConstant(true); + biasInfo.SetConstant(true); + + std::vector weightsVector(64); + ConstTensor constWeightsTensor(weightInfo, weightsVector); + + std::vector biasVector(16); + ConstTensor constBiasTensor(biasInfo, biasVector); Convolution2dDescriptor convolutionDescriptor; convolutionDescriptor.m_StrideX = 1; @@ -477,36 +629,93 @@ SubgraphView::SubgraphViewPtr BuildPartiallyOptimizableSubgraph1(Graph& graph, L // Construct the graph Layer* const inputLayer = AddInputLayer(graph, "input layer", inputInfo); - Convolution2dLayer* const conv1Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor, - "conv1 layer", weightInfo, biasInfo, outputInfo); - Convolution2dLayer* const conv2Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor, - "conv2 layer unoptimizable", weightInfo, biasInfo, - outputInfo); - Convolution2dLayer* const conv3Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor, - "conv3 layer", weightInfo, biasInfo, outputInfo); - Convolution2dLayer* const conv4Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor, - "conv4 layer unoptimizable", weightInfo, biasInfo, - outputInfo); - Convolution2dLayer* const conv5Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor, - "conv5 layer", weightInfo, biasInfo, outputInfo); - Layer* const outputLayer = AddOutputLayer(graph, "output layer"); + + ConstantLayer* const weightsLayer1 = + AddConstantLayer(graph, layersInGraph, "Weights Layer 1", constWeightsTensor, outputInfo); + ConstantLayer* const biasLayer1 = + AddConstantLayer(graph, layersInGraph, "Bias Layer 1", constBiasTensor, outputInfo); + ConstantLayer* const weightsLayer2 = + AddConstantLayer(graph, layersInGraph, "Weights Layer 2 unoptimizable", constWeightsTensor, outputInfo); + ConstantLayer* const biasLayer2 = + AddConstantLayer(graph, layersInGraph, "Bias Layer 2 unoptimizable", constBiasTensor, outputInfo); + ConstantLayer* const weightsLayer3 = + AddConstantLayer(graph, layersInGraph, "Weights Layer 3", constWeightsTensor, outputInfo); + ConstantLayer* const biasLayer3 = + AddConstantLayer(graph, layersInGraph, "Bias Layer 3", constBiasTensor, outputInfo); + ConstantLayer* const weightsLayer4 = + AddConstantLayer(graph, layersInGraph, "Weights Layer 4 unoptimizable", constWeightsTensor, outputInfo); + ConstantLayer* const biasLayer4 = + AddConstantLayer(graph, layersInGraph, "Bias Layer 4 unoptimizable", constBiasTensor, outputInfo); + ConstantLayer* const weightsLayer5 = + AddConstantLayer(graph, layersInGraph, "Weights Layer 5", constWeightsTensor, outputInfo); + ConstantLayer* const biasLayer5 = + AddConstantLayer(graph, layersInGraph, "Bias Layer 5", constBiasTensor, outputInfo); + + Convolution2dLayer* const conv1Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor, + "conv1 layer", weightInfo, biasInfo, outputInfo); + Convolution2dLayer* const conv2Layer = AddConvolutionLayer(graph, + layersInGraph, + convolutionDescriptor, + "conv2 layer unoptimizable", + weightInfo, + biasInfo, + outputInfo); + Convolution2dLayer* const conv3Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor, + "conv3 layer", weightInfo, biasInfo, outputInfo); + Convolution2dLayer* const conv4Layer = AddConvolutionLayer(graph, + layersInGraph, + convolutionDescriptor, + "conv4 layer unoptimizable", + weightInfo, + biasInfo, + outputInfo); + Convolution2dLayer* const conv5Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor, + "conv5 layer", weightInfo, biasInfo, outputInfo); + + Layer* const outputLayer = AddOutputLayer(graph, "output layer"); // Connect the network inputLayer->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(0)); + weightsLayer1->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(1)); + biasLayer1->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(2)); + conv1Layer->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(0)); + weightsLayer2->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(1)); + biasLayer2->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(2)); + conv2Layer->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(0)); + weightsLayer3->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(1)); + biasLayer3->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(2)); + conv3Layer->GetOutputSlot(0).Connect(conv4Layer->GetInputSlot(0)); + weightsLayer4->GetOutputSlot(0).Connect(conv4Layer->GetInputSlot(1)); + biasLayer4->GetOutputSlot(0).Connect(conv4Layer->GetInputSlot(2)); + conv4Layer->GetOutputSlot(0).Connect(conv5Layer->GetInputSlot(0)); + weightsLayer5->GetOutputSlot(0).Connect(conv5Layer->GetInputSlot(1)); + biasLayer5->GetOutputSlot(0).Connect(conv5Layer->GetInputSlot(2)); + conv5Layer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + std::vector ignoreSlots = {1, 2}; // Create the subgraph view for the whole network - return CreateSubgraphViewFrom(CreateInputsFrom({conv1Layer}), + return CreateSubgraphViewFrom(CreateInputsFrom(conv1Layer, ignoreSlots), CreateOutputsFrom({conv5Layer}), - {conv1Layer, - conv2Layer, - conv3Layer, - conv4Layer, - conv5Layer}); + {weightsLayer1, + biasLayer1, + conv1Layer, + weightsLayer2, + biasLayer2, + conv2Layer, + weightsLayer3, + biasLayer3, + conv3Layer, + weightsLayer4, + biasLayer4, + conv4Layer, + weightsLayer5, + biasLayer5, + conv5Layer}); } // Creates a subgraph with some input unoptimizable layers ("unoptimizable" is added to the layer's name), @@ -515,8 +724,17 @@ SubgraphView::SubgraphViewPtr BuildPartiallyOptimizableSubgraph2(Graph& graph, L { const TensorInfo inputInfo ({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0); const TensorInfo outputInfo({ 1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0); - const TensorInfo weightInfo({ 16, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0); - const TensorInfo biasInfo ({ 1, 1, 1, 16 }, DataType::Signed32, 0.9f, 0); + TensorInfo weightInfo({ 16, 1, 1, 16 }, DataType::QAsymmU8, 0.9f, 0); + TensorInfo biasInfo ({ 1, 1, 1, 16 }, DataType::Signed32, 0.9f, 0); + + weightInfo.SetConstant(true); + biasInfo.SetConstant(true); + + std::vector weightsVector(64); + ConstTensor constWeightsTensor(weightInfo, weightsVector); + + std::vector biasVector(16); + ConstTensor constBiasTensor(biasInfo, biasVector); Convolution2dDescriptor convolutionDescriptor; convolutionDescriptor.m_StrideX = 1; @@ -527,6 +745,20 @@ SubgraphView::SubgraphViewPtr BuildPartiallyOptimizableSubgraph2(Graph& graph, L // Construct the graph Layer* const input1Layer = AddInputLayer(graph, "input1 layer", inputInfo, 0); Layer* const input2Layer = AddInputLayer(graph, "input2 layer", inputInfo, 1); + + ConstantLayer* const weightsLayer1 = + AddConstantLayer(graph, layersInGraph, "Weights Layer 1", constWeightsTensor, outputInfo); + ConstantLayer* const biasLayer1 = + AddConstantLayer(graph, layersInGraph, "Bias Layer 1", constBiasTensor, outputInfo); + ConstantLayer* const weightsLayer2 = + AddConstantLayer(graph, layersInGraph, "Weights Layer 2 unoptimizable", constWeightsTensor, outputInfo); + ConstantLayer* const biasLayer2 = + AddConstantLayer(graph, layersInGraph, "Bias Layer 2 unoptimizable", constBiasTensor, outputInfo); + ConstantLayer* const weightsLayer3 = + AddConstantLayer(graph, layersInGraph, "Weights Layer 3", constWeightsTensor, outputInfo); + ConstantLayer* const biasLayer3 = + AddConstantLayer(graph, layersInGraph, "Bias Layer 3", constBiasTensor, outputInfo); + Convolution2dLayer* const conv1Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor, "conv1 layer", weightInfo, biasInfo, outputInfo); Convolution2dLayer* const conv2Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor, @@ -539,20 +771,35 @@ SubgraphView::SubgraphViewPtr BuildPartiallyOptimizableSubgraph2(Graph& graph, L // Connect the network input1Layer->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(0)); - input2Layer->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(0)); + weightsLayer1->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(1)); + biasLayer1->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(2)); conv1Layer->GetOutputSlot(0).Connect(addLayer->GetInputSlot(0)); + + input2Layer->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(0)); + weightsLayer2->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(1)); + biasLayer2->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(2)); conv2Layer->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(0)); + weightsLayer3->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(1)); + biasLayer3->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(2)); conv3Layer->GetOutputSlot(0).Connect(addLayer->GetInputSlot(1)); + addLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); // Create the subgraph view for the whole network + std::vector ignoreSlots = {1, 2}; return CreateSubgraphViewFrom(CreateInputsFrom({conv1Layer, - conv2Layer}), + conv2Layer}, ignoreSlots), CreateOutputsFrom({addLayer}), - {conv1Layer, - conv2Layer, - conv3Layer, - addLayer}); + { weightsLayer1, + biasLayer1, + weightsLayer2, + biasLayer2, + weightsLayer3, + biasLayer3, + conv1Layer, + conv2Layer, + conv3Layer, + addLayer }); } // The input subgraph contains only a single unsupported layer (only convolutions are unsupported by the mock backend) @@ -713,9 +960,11 @@ void FullyOptimizableSubgraphTestImpl1() CHECK(subgraphInputSlots.size() == 1); CHECK(subgraphOutputSlots.size() == 1); - CHECK(subgraphLayers.size() == 1); + CHECK(subgraphLayers.size() == 3); CHECK(Contains(layersInGraph, "conv layer")); + CHECK(Contains(layersInGraph, "Weights Layer")); + CHECK(Contains(layersInGraph, "Bias Layer")); // Create a mock backend object MockBackendInitialiser initialiser; // Register the Mock Backend @@ -776,15 +1025,25 @@ void FullyOptimizableSubgraphTestImpl2() const SubgraphView::IOutputSlots& subgraphOutputSlots = subgraphPtr->GetIOutputSlots(); const SubgraphView::IConnectableLayers& subgraphLayers = subgraphPtr->GetIConnectableLayers(); - CHECK(subgraphPtr->GetIInputSlots().size() == 1); - CHECK(subgraphPtr->GetIOutputSlots().size() == 1); - CHECK(subgraphPtr->GetIConnectableLayers().size() == 5); + CHECK(subgraphInputSlots.size() == 1); + CHECK(subgraphOutputSlots.size() == 1); + CHECK(subgraphPtr->GetIConnectableLayers().size() == 15); CHECK(Contains(layersInGraph, "conv1 layer")); CHECK(Contains(layersInGraph, "conv2 layer")); CHECK(Contains(layersInGraph, "conv3 layer")); CHECK(Contains(layersInGraph, "conv4 layer")); CHECK(Contains(layersInGraph, "conv5 layer")); + CHECK(Contains(layersInGraph, "Weights Layer 1")); + CHECK(Contains(layersInGraph, "Weights Layer 2")); + CHECK(Contains(layersInGraph, "Weights Layer 3")); + CHECK(Contains(layersInGraph, "Weights Layer 4")); + CHECK(Contains(layersInGraph, "Weights Layer 5")); + CHECK(Contains(layersInGraph, "Bias Layer 1")); + CHECK(Contains(layersInGraph, "Bias Layer 2")); + CHECK(Contains(layersInGraph, "Bias Layer 3")); + CHECK(Contains(layersInGraph, "Bias Layer 4")); + CHECK(Contains(layersInGraph, "Bias Layer 5")); // Create a mock backend object MockBackendInitialiser initialiser; // Register the Mock Backend @@ -811,20 +1070,31 @@ void FullyOptimizableSubgraphTestImpl2() const OptimizationViews::Substitutions& substitutions = optimizationViews.GetSubstitutions(); CHECK(substitutions.size() == 1); - std::list expectedSubstitutableLayers{ layersInGraph.at("conv1 layer"), + std::list expectedSubstitutableLayers{ + layersInGraph.at("Weights Layer 1"), + layersInGraph.at("Weights Layer 2"), + layersInGraph.at("Weights Layer 3"), + layersInGraph.at("Weights Layer 4"), + layersInGraph.at("Weights Layer 5"), + layersInGraph.at("Bias Layer 1"), + layersInGraph.at("Bias Layer 2"), + layersInGraph.at("Bias Layer 3"), + layersInGraph.at("Bias Layer 4"), + layersInGraph.at("Bias Layer 5"), + layersInGraph.at("conv1 layer"), layersInGraph.at("conv2 layer"), layersInGraph.at("conv3 layer"), layersInGraph.at("conv4 layer"), - layersInGraph.at("conv5 layer") }; + layersInGraph.at("conv5 layer")}; const OptimizationViews::SubstitutionPair& substitution = substitutions.at(0); - CheckSubstitution(substitution, - { subgraphInputSlots.size(), subgraphOutputSlots.size(), subgraphLayers.size() }, - { subgraphInputSlots.size(), subgraphOutputSlots.size(), 1 }, - subgraphInputSlots, - subgraphOutputSlots, - expectedSubstitutableLayers); + CheckSubstitution( + substitution, + {subgraphInputSlots.size(), subgraphOutputSlots.size(), + subgraphLayers.size()}, + {subgraphInputSlots.size(), subgraphOutputSlots.size(), 1}, + subgraphInputSlots, subgraphOutputSlots, expectedSubstitutableLayers); const SubgraphView::IConnectableLayers& substitutableSubgraphLayers = substitution.m_SubstitutableSubgraph.GetIConnectableLayers(); @@ -865,11 +1135,15 @@ void PartiallySupportedSubgraphTestImpl() CHECK(subgraphInputSlots.size() == 1); CHECK(subgraphOutputSlots.size() == 1); - CHECK(subgraphLayers.size() == 5); + CHECK(subgraphLayers.size() == 9); + CHECK(Contains(layersInGraph, "Weights Layer 1")); + CHECK(Contains(layersInGraph, "Bias Layer 1")); CHECK(Contains(layersInGraph, "conv1 layer")); CHECK(Contains(layersInGraph, "pooling1 layer")); CHECK(Contains(layersInGraph, "pooling2 layer")); + CHECK(Contains(layersInGraph, "Weights Layer 2")); + CHECK(Contains(layersInGraph, "Bias Layer 2")); CHECK(Contains(layersInGraph, "conv2 layer")); CHECK(Contains(layersInGraph, "pooling3 layer")); @@ -903,16 +1177,16 @@ void PartiallySupportedSubgraphTestImpl() s2.m_SubstitutableSubgraph.GetIConnectableLayers().front()->GetName()) < 0; }); - std::vector expectedSubstitutableSubgraphSizes{ { 1, 1, 1 }, - { 1, 1, 1 } }; + std::vector expectedSubstitutableSubgraphSizes{ { 1, 1, 3 }, + { 1, 1, 3 } }; std::vector expectedReplacementSubgraphSizes{ { 1, 1, 1 }, { 1, 1, 1 } }; std::vector expectedSubstitutableInputSlots { ConvertSlotsToISlots( - ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetInputSlots())), + {ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetInputSlot(0))}), ConvertSlotsToISlots( - ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer")->GetInputSlots())) + {ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer")->GetInputSlot(0))}) }; std::vector expectedSubstitutableOutputSlots @@ -924,8 +1198,8 @@ void PartiallySupportedSubgraphTestImpl() }; std::vector expectedSubstitutableLayers { - { layersInGraph.at("conv1 layer") }, - { layersInGraph.at("conv2 layer") } + { layersInGraph.at("Weights Layer 1"), layersInGraph.at("Bias Layer 1"), layersInGraph.at("conv1 layer") }, + { layersInGraph.at("Weights Layer 2"), layersInGraph.at("Bias Layer 2"), layersInGraph.at("conv2 layer") } }; for (size_t substitutionIndex = 0; substitutionIndex < substitutions.size(); substitutionIndex++) @@ -1005,7 +1279,7 @@ void FullyUnoptimizableSubgraphTestImpl1() CHECK(subgraphInputSlots.size() == 1); CHECK(subgraphOutputSlots.size() == 1); - CHECK(subgraphLayers.size() == 1); + CHECK(subgraphLayers.size() == 3); CHECK(Contains(layersInGraph, "conv layer unoptimizable")); @@ -1047,9 +1321,9 @@ void FullyUnoptimizableSubgraphTestImpl1() CHECK(untouchedSubgraphs.size() == 1); CheckUntouchedSubgraph(untouchedSubgraphs.at(0), - { subgraphInputSlots.size(), subgraphOutputSlots.size(), subgraphLayers.size() }, - subgraphInputSlots, - subgraphOutputSlots, + {subgraphInputSlots.size(), + subgraphOutputSlots.size(), subgraphLayers.size()}, + subgraphInputSlots, subgraphOutputSlots, subgraphLayers); } @@ -1069,7 +1343,7 @@ void PartiallyOptimizableSubgraphTestImpl1() CHECK(subgraphInputSlots.size() == 1); CHECK(subgraphOutputSlots.size() == 1); - CHECK(subgraphLayers.size() == 5); + CHECK(subgraphLayers.size() == 15); CHECK(Contains(layersInGraph, "conv1 layer")); CHECK(Contains(layersInGraph, "conv2 layer unoptimizable")); @@ -1107,20 +1381,20 @@ void PartiallyOptimizableSubgraphTestImpl1() { return strcmp(s1.m_SubstitutableSubgraph.GetIConnectableLayers().front()->GetName(), s2.m_SubstitutableSubgraph.GetIConnectableLayers().front()->GetName()) < 0; }); - std::vector expectedSubstitutableSubgraphSizes{ { 1, 1, 1 }, - { 1, 1, 1 }, - { 1, 1, 1 } }; + std::vector expectedSubstitutableSubgraphSizes{ { 1, 1, 3 }, + { 1, 1, 3 }, + { 1, 1, 3 } }; std::vector expectedReplacementSubgraphSizes{ { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 } }; std::vector expectedSubstitutableInputSlots { ConvertSlotsToISlots( - ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetInputSlots())), + {ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetInputSlot(0))}), ConvertSlotsToISlots( - ConvertReferenceTypeToPointerType(layersInGraph.at("conv3 layer")->GetInputSlots())), + {ConvertReferenceTypeToPointerType(layersInGraph.at("conv3 layer")->GetInputSlot(0))}), ConvertSlotsToISlots( - ConvertReferenceTypeToPointerType(layersInGraph.at("conv5 layer")->GetInputSlots())) + {ConvertReferenceTypeToPointerType(layersInGraph.at("conv5 layer")->GetInputSlot(0))}) }; std::vector expectedSubstitutableOutputSlots { @@ -1133,9 +1407,9 @@ void PartiallyOptimizableSubgraphTestImpl1() }; std::vector expectedSubstitutableLayers { - { layersInGraph.at("conv1 layer") }, - { layersInGraph.at("conv3 layer") }, - { layersInGraph.at("conv5 layer") } + { layersInGraph.at("Weights Layer 1"), layersInGraph.at("Bias Layer 1"), layersInGraph.at("conv1 layer") }, + { layersInGraph.at("Weights Layer 3"), layersInGraph.at("Bias Layer 3"), layersInGraph.at("conv3 layer") }, + { layersInGraph.at("Weights Layer 5"), layersInGraph.at("Bias Layer 5"), layersInGraph.at("conv5 layer") } }; for (size_t substitutionIndex = 0; substitutionIndex < substitutions.size(); substitutionIndex++) @@ -1166,27 +1440,33 @@ void PartiallyOptimizableSubgraphTestImpl1() s2.GetIConnectableLayers().front()->GetName()) < 0; }); - std::vector expectedUntouchedSubgraphSizes{ { 1, 1, 1 }, - { 1, 1, 1 } }; - std::vector expectedUntouchedInputSlots - { - ConvertSlotsToISlots( - ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer unoptimizable")->GetInputSlots())), - ConvertSlotsToISlots( - ConvertReferenceTypeToPointerType(layersInGraph.at("conv4 layer unoptimizable")->GetInputSlots())) - }; + std::vector expectedUntouchedSubgraphSizes{ { 1, 1, 3 }, + { 1, 1, 3 } }; + std::vector expectedUntouchedInputSlots{ + ConvertSlotsToISlots({ConvertReferenceTypeToPointerType( + layersInGraph.at("conv2 layer unoptimizable")->GetInputSlot(0))}), + ConvertSlotsToISlots({ConvertReferenceTypeToPointerType( + layersInGraph.at("conv4 layer unoptimizable")->GetInputSlot(0))})}; + std::vector expectedUntouchedOutputSlots - { + { ConvertSlotsToISlots( - ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer unoptimizable")->GetOutputSlots())), + ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer unoptimizable")->GetOutputSlots())), ConvertSlotsToISlots( - ConvertReferenceTypeToPointerType(layersInGraph.at("conv4 layer unoptimizable")->GetOutputSlots())) - }; + ConvertReferenceTypeToPointerType(layersInGraph.at("conv4 layer unoptimizable")->GetOutputSlots())) + }; + std::vector expectedUntouchedLayers - { - { layersInGraph.at("conv2 layer unoptimizable") }, - { layersInGraph.at("conv4 layer unoptimizable") } - }; + { + { layersInGraph.at("Weights Layer 2 unoptimizable"), + layersInGraph.at("Bias Layer 2 unoptimizable"), + layersInGraph.at("conv2 layer unoptimizable") }, + { layersInGraph.at("Weights Layer 4 unoptimizable"), + layersInGraph.at("Bias Layer 4 unoptimizable"), + layersInGraph.at("conv4 layer unoptimizable") } + }; for (size_t untouchedIndex = 0; untouchedIndex < untouchedSubgraphs.size(); untouchedIndex++) { @@ -1215,7 +1495,7 @@ void PartiallyOptimizableSubgraphTestImpl2() CHECK(subgraphInputSlots.size() == 2); CHECK(subgraphOutputSlots.size() == 1); - CHECK(subgraphLayers.size() == 4); + CHECK(subgraphLayers.size() == 10); CHECK(Contains(layersInGraph, "conv1 layer")); CHECK(Contains(layersInGraph, "conv2 layer unoptimizable")); @@ -1247,7 +1527,7 @@ void PartiallyOptimizableSubgraphTestImpl2() const OptimizationViews::Substitutions& substitutions = optimizationViews.GetSubstitutions(); CHECK(substitutions.size() == 1); - ExpectedSubgraphSize expectedSubstitutableSubgraphSizes{ 2, 1, 3 }; + ExpectedSubgraphSize expectedSubstitutableSubgraphSizes{ 2, 1, 7 }; ExpectedSubgraphSize expectedReplacementSubgraphSizes{ 2, 1, 1 }; SubgraphView::IInputSlots expectedSubstitutableInputSlots @@ -1266,6 +1546,10 @@ void PartiallyOptimizableSubgraphTestImpl2() SubgraphView::IConnectableLayers expectedSubstitutableLayers { + layersInGraph.at("Weights Layer 1"), + layersInGraph.at("Weights Layer 3"), + layersInGraph.at("Bias Layer 1"), + layersInGraph.at("Bias Layer 3"), layersInGraph.at("conv1 layer"), layersInGraph.at("conv3 layer"), layersInGraph.at("add layer") @@ -1291,12 +1575,12 @@ void PartiallyOptimizableSubgraphTestImpl2() const OptimizationViews::Subgraphs& untouchedSubgraphs = optimizationViews.GetUntouchedSubgraphs(); CHECK(untouchedSubgraphs.size() == 1); - std::vector expectedUntouchedSubgraphSizes{ { 1, 1, 1 } }; + std::vector expectedUntouchedSubgraphSizes{ { 1, 1, 3 } }; std::vector expectedUntouchedInputSlots { - ConvertSlotsToISlots( - ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer unoptimizable")->GetInputSlots())) - }; + ConvertSlotsToISlots({ConvertReferenceTypeToPointerType( + layersInGraph.at("conv2 layer unoptimizable")->GetInputSlot(0))})}; std::vector expectedUntouchedOutputSlots { ConvertSlotsToISlots( @@ -1304,7 +1588,8 @@ void PartiallyOptimizableSubgraphTestImpl2() }; std::vector expectedUntouchedLayers { - { layersInGraph.at("conv2 layer unoptimizable") } + { layersInGraph.at("conv2 layer unoptimizable"), layersInGraph.at("Weights Layer 2 unoptimizable"), + layersInGraph.at("Bias Layer 2 unoptimizable") } }; for (size_t untouchedIndex = 0; untouchedIndex < untouchedSubgraphs.size(); untouchedIndex++) diff --git a/src/backends/backendsCommon/test/OptimizedNetworkTests.cpp b/src/backends/backendsCommon/test/OptimizedNetworkTests.cpp index cc7974130d..8e3b275649 100644 --- a/src/backends/backendsCommon/test/OptimizedNetworkTests.cpp +++ b/src/backends/backendsCommon/test/OptimizedNetworkTests.cpp @@ -401,11 +401,14 @@ TEST_CASE("OptimizeNetworkCopy") armnn::INetworkPtr network = armnn::INetwork::Create(); armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0); + + ARMNN_NO_DEPRECATE_WARN_BEGIN armnn::IConnectableLayer* const convLayer = network->AddConvolution2dLayer(descriptor, weights, armnn::Optional(biases), layerName.c_str()); + ARMNN_NO_DEPRECATE_WARN_END armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0); inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0)); diff --git a/src/backends/backendsCommon/test/WorkloadDataValidation.cpp b/src/backends/backendsCommon/test/WorkloadDataValidation.cpp index c715d28ebe..fed21eb911 100644 --- a/src/backends/backendsCommon/test/WorkloadDataValidation.cpp +++ b/src/backends/backendsCommon/test/WorkloadDataValidation.cpp @@ -642,7 +642,7 @@ TEST_CASE("LstmQueueDescriptor_Validate") CHECK_NOTHROW(data.Validate(info)); } -TEST_CASE("BiasPerAxisQuantization_Validate") +TEST_CASE("BiasPerAxisQuantization_ValidateCorrectValues") { constexpr unsigned int nInput = 1u; constexpr unsigned int cInput = 3u; @@ -675,6 +675,7 @@ TEST_CASE("BiasPerAxisQuantization_Validate") WorkloadInfo workloadInfo; AddInputToWorkload(queueDescriptor, workloadInfo, inputInfo, nullptr); + AddInputToWorkload(queueDescriptor, workloadInfo, weightInfo, nullptr); AddOutputToWorkload(queueDescriptor, workloadInfo, outputInfo, nullptr); ScopedTensorHandle weightTensor(weightInfo); @@ -687,17 +688,102 @@ TEST_CASE("BiasPerAxisQuantization_Validate") ScopedTensorHandle biasHandle1(biasInfo1); queueDescriptor.m_Bias = &biasHandle1; + AddInputToWorkload(queueDescriptor, workloadInfo, biasInfo1, nullptr); + CHECK_NOTHROW(queueDescriptor.Validate(workloadInfo)); +} - // Test 2: wrong per-axis quantization values +TEST_CASE("BiasPerAxisQuantization_ValidateIncorrectValues") +{ + constexpr unsigned int nInput = 1u; + constexpr unsigned int cInput = 3u; + constexpr unsigned int hInput = 3u; + constexpr unsigned int wInput = 3u; + + constexpr unsigned int nOutput = nInput; + constexpr unsigned int cOutput = cInput; + constexpr unsigned int hOutput = 1u; + constexpr unsigned int wOutput = 1u; + + const TensorShape inputShape { nInput, cInput, hInput, wInput }; + const TensorShape outputShape{ nOutput, cOutput, hOutput, wOutput }; + const TensorShape weightShape{ cOutput, cInput, hInput, wInput }; + const TensorShape biasShape { cOutput }; + + constexpr DataType inputType = DataType::QAsymmU8; + constexpr DataType weightType = DataType::QSymmS8; + constexpr DataType biasType = DataType::Signed32; + + constexpr float perTensorScale = 1.5f; + const TensorInfo inputInfo (inputShape, inputType, perTensorScale); + const TensorInfo outputInfo(outputShape, inputType, perTensorScale); + + const std::vector weightPerAxisScales = { 2.50f, 3.50f }; + const TensorInfo weightInfo(weightShape, weightType, weightPerAxisScales, 0); + + Convolution2dQueueDescriptor queueDescriptor; + queueDescriptor.m_Parameters.m_BiasEnabled = true; + + WorkloadInfo workloadInfo; + AddInputToWorkload(queueDescriptor, workloadInfo, inputInfo, nullptr); + AddInputToWorkload(queueDescriptor, workloadInfo, weightInfo, nullptr); + AddOutputToWorkload(queueDescriptor, workloadInfo, outputInfo, nullptr); + + ScopedTensorHandle weightTensor(weightInfo); + queueDescriptor.m_Weight = &weightTensor; + + // Test 2: wrong per-axis quantization values const std::vector biasPerAxisScales2 = { 4.00f, 5.00f }; const TensorInfo biasInfo2(biasShape, biasType, biasPerAxisScales2, 0); ScopedTensorHandle biasHandle2(biasInfo2); queueDescriptor.m_Bias = &biasHandle2; + AddInputToWorkload(queueDescriptor, workloadInfo, biasInfo2, nullptr); + CHECK_NOTHROW(queueDescriptor.Validate(workloadInfo)); +} + +TEST_CASE("BiasPerAxisQuantization_ValidateInvalidArgumentException") +{ + constexpr unsigned int nInput = 1u; + constexpr unsigned int cInput = 3u; + constexpr unsigned int hInput = 3u; + constexpr unsigned int wInput = 3u; + + constexpr unsigned int nOutput = nInput; + constexpr unsigned int cOutput = cInput; + constexpr unsigned int hOutput = 1u; + constexpr unsigned int wOutput = 1u; + + const TensorShape inputShape { nInput, cInput, hInput, wInput }; + const TensorShape outputShape{ nOutput, cOutput, hOutput, wOutput }; + const TensorShape weightShape{ cOutput, cInput, hInput, wInput }; + const TensorShape biasShape { cOutput }; + + constexpr DataType inputType = DataType::QAsymmU8; + constexpr DataType weightType = DataType::QSymmS8; + constexpr DataType biasType = DataType::Signed32; + + constexpr float perTensorScale = 1.5f; + const TensorInfo inputInfo (inputShape, inputType, perTensorScale); + const TensorInfo outputInfo(outputShape, inputType, perTensorScale); + + const std::vector weightPerAxisScales = { 2.50f, 3.50f }; + const TensorInfo weightInfo(weightShape, weightType, weightPerAxisScales, 0); + + Convolution2dQueueDescriptor queueDescriptor; + queueDescriptor.m_Parameters.m_BiasEnabled = true; + + WorkloadInfo workloadInfo; + AddInputToWorkload(queueDescriptor, workloadInfo, inputInfo, nullptr); + AddInputToWorkload(queueDescriptor, workloadInfo, weightInfo, nullptr); + AddOutputToWorkload(queueDescriptor, workloadInfo, outputInfo, nullptr); + + ScopedTensorHandle weightTensor(weightInfo); + queueDescriptor.m_Weight = &weightTensor; + // Test 3: mismatched number of quantization scales const std::vector biasPerAxisScales3 = { 3.75f, 5.25f, 5.25f }; const TensorInfo biasInfo3(biasShape, biasType, biasPerAxisScales3, 0); @@ -705,7 +791,10 @@ TEST_CASE("BiasPerAxisQuantization_Validate") ScopedTensorHandle biasHandle3(biasInfo3); queueDescriptor.m_Bias = &biasHandle3; + AddInputToWorkload(queueDescriptor, workloadInfo, biasInfo3, nullptr); + CHECK_THROWS_AS(queueDescriptor.Validate(workloadInfo), InvalidArgumentException); } + } diff --git a/src/backends/backendsCommon/test/layerTests/Conv2dTestImpl.cpp b/src/backends/backendsCommon/test/layerTests/Conv2dTestImpl.cpp index 74c65e271c..1e0adc169a 100644 --- a/src/backends/backendsCommon/test/layerTests/Conv2dTestImpl.cpp +++ b/src/backends/backendsCommon/test/layerTests/Conv2dTestImpl.cpp @@ -309,6 +309,7 @@ LayerTestResult SimpleConvolution2dTestImpl( std::unique_ptr inputHandle = tensorHandleFactory.CreateTensorHandle(inputTensorInfo); std::unique_ptr outputHandle = tensorHandleFactory.CreateTensorHandle(outputTensorInfo); + std::unique_ptr weightsHandle = tensorHandleFactory.CreateTensorHandle(kernelDesc); armnn::Convolution2dQueueDescriptor data; armnn::WorkloadInfo info; @@ -329,8 +330,15 @@ LayerTestResult SimpleConvolution2dTestImpl( } AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get()); + AddInputToWorkload(data, info, kernelDesc, weightsHandle.get()); AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get()); + std::unique_ptr biasHandle = nullptr; + if (biasEnabled) + { + biasHandle = tensorHandleFactory.CreateTensorHandle(biasDesc); + AddInputToWorkload(data, info, biasDesc, biasHandle.get()); + } data.m_Weight = &weightsTensor; data.m_Bias = &biasTensor; // Still set this whether or not bias is enabled - can be a source of bugs. data.m_Parameters.m_StrideX = strideX; @@ -349,8 +357,16 @@ LayerTestResult SimpleConvolution2dTestImpl( info); inputHandle->Allocate(); outputHandle->Allocate(); + weightsHandle->Allocate(); + + if (biasEnabled) + { + biasHandle->Allocate(); + CopyDataToITensorHandle(biasHandle.get(), bias.data()); + } CopyDataToITensorHandle(inputHandle.get(), inputData.data()); + CopyDataToITensorHandle(weightsHandle.get(), kernel.data()); ExecuteWorkload(*workload, memoryManager); @@ -423,6 +439,8 @@ LayerTestResult SimpleConvolution2dNhwcTestImpl( std::unique_ptr inputHandle = tensorHandleFactory.CreateTensorHandle(inputTensorInfo); std::unique_ptr outputHandle = tensorHandleFactory.CreateTensorHandle(outputTensorInfo); + std::unique_ptr weightsHandle = tensorHandleFactory.CreateTensorHandle(kernelDesc); + std::unique_ptr biasHandle = nullptr; armnn::ScopedTensorHandle weightsTensor(kernelDesc); AllocateAndCopyDataToITensorHandle(&weightsTensor, kernel.data()); @@ -444,15 +462,30 @@ LayerTestResult SimpleConvolution2dNhwcTestImpl( armnn::WorkloadInfo info; AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get()); + AddInputToWorkload(data, info, kernelDesc, weightsHandle.get()); AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get()); + if (biasEnabled) + { + biasHandle = tensorHandleFactory.CreateTensorHandle(biasDesc); + AddInputToWorkload(data, info, biasDesc, biasHandle.get()); + } + std::unique_ptr workload = workloadFactory.CreateWorkload(armnn::LayerType::Convolution2d, data, info); inputHandle->Allocate(); outputHandle->Allocate(); + weightsHandle->Allocate(); + + if (biasEnabled) + { + biasHandle->Allocate(); + CopyDataToITensorHandle(biasHandle.get(), bias.data()); + } CopyDataToITensorHandle(inputHandle.get(), inputData.data()); + CopyDataToITensorHandle(weightsHandle.get(), kernel.data()); ExecuteWorkload(*workload, memoryManager); @@ -552,35 +585,52 @@ LayerTestResult Convolution1dTestImpl( std::unique_ptr inputHandle = tensorHandleFactory.CreateTensorHandle(inputInfo); std::unique_ptr outputHandle = tensorHandleFactory.CreateTensorHandle(outputInfo); + std::unique_ptr weightsHandle = tensorHandleFactory.CreateTensorHandle(kernelInfo); + std::unique_ptr biasHandle = nullptr; armnn::Convolution2dQueueDescriptor data; armnn::WorkloadInfo info; - armnn::ScopedTensorHandle weightsTensor(kernelInfo); - armnn::ScopedTensorHandle biasTensor(biasInfo); + armnn::ScopedTensorHandle weightsTensor(kernelInfo); + armnn::ScopedTensorHandle biasTensor(biasInfo); AllocateAndCopyDataToITensorHandle(&weightsTensor, kernelData.data()); AllocateAndCopyDataToITensorHandle(&biasTensor, biasData.data()); AddInputToWorkload(data, info, inputInfo, inputHandle.get()); + AddInputToWorkload(data, info, kernelInfo, weightsHandle.get()); AddOutputToWorkload(data, info, outputInfo, outputHandle.get()); - data.m_Weight = &weightsTensor; - data.m_Bias = &biasTensor; - data.m_Parameters.m_StrideX = 1; - data.m_Parameters.m_StrideY = stride; - data.m_Parameters.m_PadLeft = 0; - data.m_Parameters.m_PadRight = 0; - data.m_Parameters.m_PadTop = padSize; - data.m_Parameters.m_PadBottom = padSize; - data.m_Parameters.m_BiasEnabled = biasEnabled; + data.m_Weight = &weightsTensor; + data.m_Bias = &biasTensor; + data.m_Parameters.m_StrideX = 1; + data.m_Parameters.m_StrideY = stride; + data.m_Parameters.m_PadLeft = 0; + data.m_Parameters.m_PadRight = 0; + data.m_Parameters.m_PadTop = padSize; + data.m_Parameters.m_PadBottom = padSize; + data.m_Parameters.m_BiasEnabled = biasEnabled; + + if (biasEnabled) + { + biasHandle = tensorHandleFactory.CreateTensorHandle(biasInfo); + AddInputToWorkload(data, info, biasInfo, biasHandle.get()); + } std::unique_ptr workload = workloadFactory.CreateWorkload(armnn::LayerType::Convolution2d, data, info); inputHandle->Allocate(); outputHandle->Allocate(); + weightsHandle->Allocate(); + + if (biasEnabled) + { + biasHandle->Allocate(); + CopyDataToITensorHandle(biasHandle.get(), biasData.data()); + } CopyDataToITensorHandle(inputHandle.get(), inputData.data()); + CopyDataToITensorHandle(weightsHandle.get(), kernelData.data()); ExecuteWorkload(*workload, memoryManager); @@ -1364,18 +1414,30 @@ LayerTestResult CompareConvolution2dTestImpl( std::vector expectedOutput(outputTensorInfo.GetNumElements()); std::unique_ptr inputHandle = tensorHandleFactory.CreateTensorHandle(inputTensorInfo); + std::unique_ptr biasHandle = tensorHandleFactory.CreateTensorHandle(biasDesc); + std::unique_ptr weightsHandle = tensorHandleFactory.CreateTensorHandle(kernelDesc); std::unique_ptr outputHandle = tensorHandleFactory.CreateTensorHandle(outputTensorInfo); armnn::Convolution2dQueueDescriptor data; armnn::WorkloadInfo info; + armnn::ScopedTensorHandle weightsTensor(kernelDesc); armnn::ScopedTensorHandle biasTensor(biasDesc); + AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get()); + AddInputToWorkload(data, info, kernelDesc, weightsHandle.get()); + AddInputToWorkload(data, info, biasDesc, biasHandle.get()); + AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get()); + + // AllocateAndCopyDataToITensorHandle() is required twice for the weights AND biases: + // See comment in DepthwiseConvolution2dAsymmetricTestImpl() for reasons. + // 1) ScopedTensorHandle (weightsTensor) required for QueueDescriptor (data.m_Weight). + // 2) ITensorHandle (converts to Backend TensorHandle) required in RefWorkload for GetTensorInfo() method. + AllocateAndCopyDataToITensorHandle(weightsHandle.get(), kernel.data()); AllocateAndCopyDataToITensorHandle(&weightsTensor, kernel.data()); + AllocateAndCopyDataToITensorHandle(biasHandle.get(), bias.data()); AllocateAndCopyDataToITensorHandle(&biasTensor, bias.data()); - AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get()); - AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get()); data.m_Weight = &weightsTensor; data.m_Bias = &biasTensor; data.m_Parameters.m_StrideX = strideX; @@ -1387,11 +1449,15 @@ LayerTestResult CompareConvolution2dTestImpl( data.m_Parameters.m_BiasEnabled = true; std::unique_ptr outputHandleRef = refTensorHandleFactory.CreateTensorHandle(outputTensorInfo); + std::unique_ptr weightsHandleRef = refTensorHandleFactory.CreateTensorHandle(kernelDesc); + std::unique_ptr biasHandleRef = refTensorHandleFactory.CreateTensorHandle(biasDesc); std::unique_ptr inputHandleRef = refTensorHandleFactory.CreateTensorHandle(inputTensorInfo); armnn::Convolution2dQueueDescriptor refData = data; armnn::WorkloadInfo refInfo = info; SetWorkloadInput(refData, refInfo, 0, inputTensorInfo, inputHandleRef.get()); + SetWorkloadInput(refData, refInfo, 1, kernelDesc, weightsHandleRef.get()); + SetWorkloadInput(refData, refInfo, 2, biasDesc, biasHandleRef.get()); SetWorkloadOutput(refData, refInfo, 0, outputTensorInfo, outputHandleRef.get()); std::unique_ptr workload @@ -1401,12 +1467,16 @@ LayerTestResult CompareConvolution2dTestImpl( outputHandleRef->Allocate(); inputHandleRef->Allocate(); + weightsHandleRef->Allocate(); + biasHandleRef->Allocate(); inputHandle->Allocate(); outputHandle->Allocate(); CopyDataToITensorHandle(inputHandle.get(), input.data()); CopyDataToITensorHandle(inputHandleRef.get(), input.data()); + CopyDataToITensorHandle(weightsHandleRef.get(), kernel.data()); + CopyDataToITensorHandle(biasHandleRef.get(), bias.data()); ExecuteWorkload(*workload, memoryManager); @@ -3622,6 +3692,8 @@ LayerTestResult Convolution2dPerAxisQuantTest( std::unique_ptr inputHandle = tensorHandleFactory.CreateTensorHandle(inputInfo); std::unique_ptr outputHandle = tensorHandleFactory.CreateTensorHandle(outputInfo); + std::unique_ptr weightsHandle = tensorHandleFactory.CreateTensorHandle(kernelInfo); + std::unique_ptr biasHandle = nullptr; WorkloadInfo workloadInfo; ScopedTensorHandle weightTensor(kernelInfo); @@ -3636,6 +3708,14 @@ LayerTestResult Convolution2dPerAxisQuantTest( queueDescriptor.m_Bias = &biasTensor; AddInputToWorkload(queueDescriptor, workloadInfo, inputInfo, inputHandle.get()); + AddInputToWorkload(queueDescriptor, workloadInfo, kernelInfo, weightsHandle.get()); + + if (descriptor.m_BiasEnabled) + { + biasHandle = tensorHandleFactory.CreateTensorHandle(biasInfo); + AddInputToWorkload(queueDescriptor, workloadInfo, biasInfo, biasHandle.get()); + } + AddOutputToWorkload(queueDescriptor, workloadInfo, outputInfo, outputHandle.get()); std::unique_ptr workload= workloadFactory.CreateWorkload(armnn::LayerType::Convolution2d, @@ -3643,8 +3723,16 @@ LayerTestResult Convolution2dPerAxisQuantTest( workloadInfo); inputHandle->Allocate(); outputHandle->Allocate(); + weightsHandle->Allocate(); + if (descriptor.m_BiasEnabled) + { + biasHandle->Allocate(); + CopyDataToITensorHandle(biasHandle.get(), biasData.data()); + } CopyDataToITensorHandle(inputHandle.get(), inputData.data()); + CopyDataToITensorHandle(weightsHandle.get(), kernelData.data()); + ExecuteWorkload(*workload, memoryManager); -- cgit v1.2.1