diff options
Diffstat (limited to 'src/armnn/test')
-rw-r--r-- | src/armnn/test/CreateWorkload.hpp | 128 | ||||
-rw-r--r-- | src/armnn/test/SubGraphTests.cpp | 407 |
2 files changed, 535 insertions, 0 deletions
diff --git a/src/armnn/test/CreateWorkload.hpp b/src/armnn/test/CreateWorkload.hpp index f52f6055ca..acc5cbdb1a 100644 --- a/src/armnn/test/CreateWorkload.hpp +++ b/src/armnn/test/CreateWorkload.hpp @@ -14,6 +14,8 @@ #include <Graph.hpp> #include <DataLayoutIndexed.hpp> +#include <Network.hpp> +#include <TypeUtils.hpp> #include <utility> @@ -1093,4 +1095,130 @@ std::unique_ptr<MergerWorkload> CreateMergerWorkloadTest(armnn::IWorkloadFactory return std::move(workloadMerger); } +template <typename PreCompiledWorkload, armnn::DataType dataType> +std::pair<armnn::IOptimizedNetworkPtr, std::unique_ptr<PreCompiledWorkload>> CreatePreCompiledWorkloadTest( + armnn::IWorkloadFactory& factory, + armnn::Graph& graph, + bool biasEnabled = false) +{ + // To create a PreCompiled layer, create a network and Optimize it. + armnn::Network net; + + // Add an input layer + armnn::IConnectableLayer* const inputLayer = net.AddInputLayer(0, "input layer"); + BOOST_TEST(inputLayer); + + // ArmNN weights tensor shape is OIHW (out channels, in channels, height, width) for NCHW + // ArmNN weights tensor shape is OHWI (out channels, height, width, in channels) for NHWC + // this test is using NHWC, so the weights shape is OHWI + TensorInfo weightsTensorInfo(TensorShape({16, 1, 1, 16}), dataType, 0.9f, 0); + unsigned int weightsLength = weightsTensorInfo.GetNumElements(); + + using WeightType = armnn::ResolveType<dataType>; + std::vector<WeightType> convWeightsData(weightsLength); + for (unsigned int i = 0; i < weightsLength; ++i) + { + convWeightsData[i] = static_cast<WeightType>(i); + } + + armnn::ConstTensor weights(weightsTensorInfo, convWeightsData); + + // Add a layer that can be used in the PreCompiled layer + armnn::Convolution2dDescriptor convDesc2d; + convDesc2d.m_StrideX = 1; + convDesc2d.m_StrideY = 1; + convDesc2d.m_BiasEnabled = biasEnabled; + convDesc2d.m_DataLayout = armnn::DataLayout::NHWC; + + armnn::IConnectableLayer* convLayer = nullptr; + const std::string convLayerName("conv layer"); + + if (biasEnabled) + { + constexpr armnn::DataType biasDataType = ( dataType == armnn::DataType::QuantisedAsymm8) ? + armnn::DataType::Signed32 : armnn::DataType::Float32; + + TensorInfo biasTensorInfo(TensorShape({1, 1, 1, 16}), biasDataType, 0.9f * 0.9f, 0); + unsigned int biasLength = biasTensorInfo.GetNumElements(); + + using BiasType = armnn::ResolveType<biasDataType>; + std::vector<BiasType> biasData(biasLength); + std::fill(biasData.begin(), biasData.end(), static_cast<BiasType>(0)); + + armnn::ConstTensor biases(biasTensorInfo, biasData); + + // Create convolution layer with biases + convLayer = net.AddConvolution2dLayer(convDesc2d, weights, biases, convLayerName.c_str()); + } + else + { + // Create convolution layer without biases + convLayer = net.AddConvolution2dLayer(convDesc2d, weights, convLayerName.c_str()); + } + + BOOST_TEST(convLayer); + + // Add an output layer + armnn::IConnectableLayer* const outputLayer = net.AddOutputLayer(0, "output layer"); + BOOST_TEST(outputLayer); + + // set the tensors in the network (NHWC format) + TensorInfo inputTensorInfo(TensorShape({ 1, 16, 16, 16 }), dataType); + if (dataType == armnn::DataType::QuantisedAsymm8) + { + inputTensorInfo.SetQuantizationOffset(0); + inputTensorInfo.SetQuantizationScale(0.9f); + } + + TensorInfo outputTensorInfo(TensorShape({1, 16, 16, 16}), dataType); + if (dataType == armnn::DataType::QuantisedAsymm8) + { + outputTensorInfo.SetQuantizationOffset(0); + outputTensorInfo.SetQuantizationScale(0.9f); + } + + // Connect the layers + inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0)); + inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo); + + convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + convLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); + + // Optimize the network for the backend supported by the factory + std::vector<armnn::BackendId> backends = {factory.GetBackendId()}; + armnn::IRuntime::CreationOptions options; + armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options)); + armnn::OptimizerOptions optimizerOptions; + armnn::IOptimizedNetworkPtr optimizedNet = armnn::Optimize(net, backends, runtime->GetDeviceSpec(), + optimizerOptions); + BOOST_CHECK(optimizedNet != nullptr); + + // Find the PreCompiled layer in the optimised graph + armnn::Graph& optimisedGraph = static_cast<armnn::OptimizedNetwork*>(optimizedNet.get())->GetGraph(); + Layer* preCompiledLayer = nullptr; + for (auto& layer : optimisedGraph) + { + if (layer->GetType() == LayerType::PreCompiled) + { + preCompiledLayer = layer; + } + } + BOOST_TEST(preCompiledLayer); + + // Create the TensorHandles. + CreateTensorHandles(optimisedGraph, factory); + + // Make the workload and check it. + auto workload = MakeAndCheckWorkload<PreCompiledWorkload>(*preCompiledLayer, optimisedGraph, factory); + + PreCompiledQueueDescriptor queueDescriptor = workload->GetData(); + BOOST_TEST(queueDescriptor.m_Inputs.size() == 1); + BOOST_TEST(queueDescriptor.m_Outputs.size() == 1); + + // Returns the workload so we can do extra, backend-specific tests. + // NOTE: We need to return the optimised network as well, otherwise it gets + // out of scope and the tensor handles get destructed + return std::make_pair(std::move(optimizedNet), std::move(workload)); +} + } diff --git a/src/armnn/test/SubGraphTests.cpp b/src/armnn/test/SubGraphTests.cpp index e516ac0fa6..9e49197ea6 100644 --- a/src/armnn/test/SubGraphTests.cpp +++ b/src/armnn/test/SubGraphTests.cpp @@ -17,6 +17,20 @@ using namespace armnn; namespace { +bool AreAnySubGraphLayersPresentInGraph(const SubGraph::Layers &subGraphLayers, const Graph &graph) +{ + for(auto&& layer : subGraphLayers) + { + auto posInGraph = std::find(graph.begin(), graph.end(), layer); + if(posInGraph != graph.end()) + { + return true; + } + } + + return false; +} + // // this helper only works if all layers where the inputs connect to are not selected // @@ -112,6 +126,235 @@ void CompareSubGraphs(SubGraphSelector::SubGraphPtr & result, } // namespace <anonymous> +BOOST_AUTO_TEST_SUITE(SubGraphSubstitution) + +BOOST_AUTO_TEST_CASE(SingleInputSingleOutput) +{ + // Construct graph + Graph graph; + + Layer* const inputLayer = graph.AddLayer<InputLayer>(0, "input"); + + Convolution2dDescriptor convDescriptor; + Layer* const convLayer1 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1"); + Layer* const convLayer2 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2"); + + Layer* const outputLayer = graph.AddLayer<OutputLayer>(0, "output"); + + inputLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0)); + convLayer1->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(0)); + convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + + // Construct sub-graph + SubGraphSelector::SubGraphPtr subGraph = + CreateSubGraphFrom(CreateInputsFrom({convLayer1}), CreateOutputsFrom({convLayer2}), {}); + + // Save sub-graph connections for comparison after substitution + IOutputSlot* subGraphInputConn = subGraph->GetInputSlot(0)->GetConnection(); + IInputSlot* subGraphOutputConn = subGraph->GetOutputSlot(0)->GetConnection(0); + + // Construct dummy pre-compiled layer + PreCompiledDescriptor preCompiledDescriptor(1, 1); + Layer* const preCompiledLayer = graph.AddLayer<PreCompiledLayer>(preCompiledDescriptor, "pre-compiled"); + + // Substitute sub-graph with pre-compiled layer + graph.SubstituteSubGraph(std::move(subGraph), preCompiledLayer); + + // Check that connections are correct after substitution + BOOST_CHECK_EQUAL(preCompiledLayer->GetInputSlot(0).GetConnection(), subGraphInputConn); + BOOST_CHECK_EQUAL(preCompiledLayer->GetOutputSlot(0).GetConnection(0), subGraphOutputConn); +} + +BOOST_AUTO_TEST_CASE(MultiInputSingleOutput) +{ + // Construct graph + Graph graph; + + Layer* const inputLayer = graph.AddLayer<InputLayer>(0, "input"); + + ViewsDescriptor splitterDescriptor(2); + Layer* const splitterLayer = graph.AddLayer<SplitterLayer>(splitterDescriptor, "splitter"); + + Convolution2dDescriptor convDescriptor; + Layer* const convLayer1 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1"); + Layer* const convLayer2 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2"); + + OriginsDescriptor mergerDescriptor(2); + Layer* const mergerLayer = graph.AddLayer<MergerLayer>(mergerDescriptor, "merger"); + + Layer* const outputLayer = graph.AddLayer<OutputLayer>(0, "output"); + + inputLayer->GetOutputSlot(0).Connect(splitterLayer->GetInputSlot(0)); + splitterLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0)); + splitterLayer->GetOutputSlot(1).Connect(convLayer2->GetInputSlot(0)); + convLayer1->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(0)); + convLayer2->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(1)); + mergerLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + + // Construct sub-graph + SubGraphSelector::SubGraphPtr subGraph = + CreateSubGraphFrom(CreateInputsFrom({convLayer1, convLayer2}), CreateOutputsFrom({mergerLayer}), {}); + + // Save sub-graph connections for comparison after substitution + IOutputSlot* subGraphInputConn1 = subGraph->GetInputSlot(0)->GetConnection(); + IOutputSlot* subGraphInputConn2 = subGraph->GetInputSlot(1)->GetConnection(); + + IInputSlot* subGraphOutputConn = subGraph->GetOutputSlot(0)->GetConnection(0); + + // Construct dummy pre-compiled layer + PreCompiledDescriptor preCompiledDescriptor(2, 1); + Layer* const preCompiledLayer = graph.AddLayer<PreCompiledLayer>(preCompiledDescriptor, "pre-compiled"); + + // Substitute sub-graph with pre-compiled layer + graph.SubstituteSubGraph(std::move(subGraph), preCompiledLayer); + + // Check that connections are correct after substitution + BOOST_CHECK_EQUAL(preCompiledLayer->GetInputSlot(0).GetConnection(), subGraphInputConn1); + BOOST_CHECK_EQUAL(preCompiledLayer->GetInputSlot(1).GetConnection(), subGraphInputConn2); + + BOOST_CHECK_EQUAL(preCompiledLayer->GetOutputSlot(0).GetConnection(0), subGraphOutputConn); +} + +BOOST_AUTO_TEST_CASE(SingleInputMultiOutput) +{ + // Construct graph + Graph graph; + + Layer* const inputLayer = graph.AddLayer<InputLayer>(0, "input"); + + Convolution2dDescriptor convDescriptor; + Layer* const convLayer1 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1"); + Layer* const convLayer2 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2"); + OriginsDescriptor mergerDescriptor(2); + Layer* const mergerLayer = graph.AddLayer<MergerLayer>(mergerDescriptor, "merger"); + Layer* const outputLayer = graph.AddLayer<OutputLayer>(0, "output"); + + ViewsDescriptor splitterDescriptor(2); + Layer* const splitterLayer = graph.AddLayer<SplitterLayer>(splitterDescriptor, "splitter"); + + inputLayer->GetOutputSlot(0).Connect(splitterLayer->GetInputSlot(0)); + splitterLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0)); + splitterLayer->GetOutputSlot(1).Connect(convLayer2->GetInputSlot(0)); + convLayer1->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(0)); + convLayer2->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(1)); + mergerLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + + // Construct sub-graph + SubGraphSelector::SubGraphPtr subGraph = + CreateSubGraphFrom(CreateInputsFrom({splitterLayer}), CreateOutputsFrom({convLayer1, convLayer2}), {}); + + // Save sub-graph connections for comparison after substitution + IOutputSlot* subGraphInputConn1 = subGraph->GetInputSlot(0)->GetConnection(); + + IInputSlot* subGraphOutputConn1 = subGraph->GetOutputSlot(0)->GetConnection(0); + IInputSlot* subGraphOutputConn2 = subGraph->GetOutputSlot(1)->GetConnection(0); + + // Construct dummy pre-compiled layer + PreCompiledDescriptor preCompiledDescriptor(1, 2); + Layer* const preCompiledLayer = graph.AddLayer<PreCompiledLayer>(preCompiledDescriptor, "pre-compiled"); + + // Substitute sub-graph with pre-compiled layer + graph.SubstituteSubGraph(std::move(subGraph), preCompiledLayer); + + // Check that connections are correct after substitution + BOOST_CHECK_EQUAL(preCompiledLayer->GetInputSlot(0).GetConnection(), subGraphInputConn1); + + BOOST_CHECK_EQUAL(preCompiledLayer->GetOutputSlot(0).GetConnection(0), subGraphOutputConn1); + BOOST_CHECK_EQUAL(preCompiledLayer->GetOutputSlot(1).GetConnection(0), subGraphOutputConn2); +} + +BOOST_AUTO_TEST_CASE(MultiInputMultiOutput) +{ + // Construct graph + Graph graph; + + Layer* const inputLayer = graph.AddLayer<InputLayer>(0, "input"); + + ViewsDescriptor splitterDescriptor(2); + Layer* const splitterLayer = graph.AddLayer<SplitterLayer>(splitterDescriptor, "splitter"); + + Convolution2dDescriptor convDescriptor; + Layer* const convLayer1 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1"); + Layer* const convLayer2 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2"); + + OriginsDescriptor mergerDescriptor(2); + Layer* const mergerLayer = graph.AddLayer<MergerLayer>(mergerDescriptor, "merger"); + + Layer* const outputLayer = graph.AddLayer<OutputLayer>(0, "output"); + + inputLayer->GetOutputSlot(0).Connect(splitterLayer->GetInputSlot(0)); + splitterLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0)); + splitterLayer->GetOutputSlot(1).Connect(convLayer2->GetInputSlot(0)); + convLayer1->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(0)); + convLayer2->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(1)); + mergerLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + + // Construct sub-graph + SubGraphSelector::SubGraphPtr subGraph = CreateSubGraphFrom(CreateInputsFrom({convLayer1, convLayer2}), + CreateOutputsFrom({convLayer1, convLayer2}), + {}); + + // Save sub-graph connections for comparison after substitution + IOutputSlot* subGraphInputConn1 = subGraph->GetInputSlot(0)->GetConnection(); + IOutputSlot* subGraphInputConn2 = subGraph->GetInputSlot(1)->GetConnection(); + + IInputSlot* subGraphOutputConn1 = subGraph->GetOutputSlot(0)->GetConnection(0); + IInputSlot* subGraphOutputConn2 = subGraph->GetOutputSlot(1)->GetConnection(0); + + // Construct dummy pre-compiled layer + PreCompiledDescriptor preCompiledDescriptor(2, 2); + Layer* const preCompiledLayer = graph.AddLayer<PreCompiledLayer>(preCompiledDescriptor, "pre-compiled"); + + // Substitute sub-graph with pre-compiled layer + graph.SubstituteSubGraph(std::move(subGraph), preCompiledLayer); + + // Check that connections are correct after substitution + BOOST_CHECK_EQUAL(preCompiledLayer->GetInputSlot(0).GetConnection(), subGraphInputConn1); + BOOST_CHECK_EQUAL(preCompiledLayer->GetInputSlot(1).GetConnection(), subGraphInputConn2); + + BOOST_CHECK_EQUAL(preCompiledLayer->GetOutputSlot(0).GetConnection(0), subGraphOutputConn1); + BOOST_CHECK_EQUAL(preCompiledLayer->GetOutputSlot(1).GetConnection(0), subGraphOutputConn2); +} + +BOOST_AUTO_TEST_CASE(EraseReplacedLayers) +{ + // Construct graph + Graph graph; + + graph.AddLayer<InputLayer>(0, "input"); + + ViewsDescriptor splitterDescriptor(2); + Layer* const splitterLayer = graph.AddLayer<SplitterLayer>(splitterDescriptor, "splitter"); + + Convolution2dDescriptor convDescriptor; + Layer* const convLayer1 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1"); + Layer* const convLayer2 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2"); + + OriginsDescriptor mergerDescriptor(2); + Layer* const mergerLayer = graph.AddLayer<MergerLayer>(mergerDescriptor, "merger"); + + graph.AddLayer<OutputLayer>(0, "output"); + + // Construct sub-graph + SubGraphSelector::SubGraphPtr subGraph = + CreateSubGraphFrom({}, {}, {splitterLayer, convLayer1, convLayer2, mergerLayer}); + + // Construct dummy pre-compiled layer + PreCompiledDescriptor preCompiledDescriptor(0, 0); + Layer* const preCompiledLayer = graph.AddLayer<PreCompiledLayer>(preCompiledDescriptor, "pre-compiled"); + + // Save sub-graph layers for later verification + const SubGraph::Layers subGraphLayers = subGraph->GetLayers(); + + // Substitute sub-graph with pre-compiled layer + graph.SubstituteSubGraph(std::move(subGraph), preCompiledLayer); + + // Check that the layers belonging to the sub-graph have been erased from the graph after substitution + BOOST_CHECK(!AreAnySubGraphLayersPresentInGraph(subGraphLayers, graph)); +} + +BOOST_AUTO_TEST_SUITE_END() + BOOST_AUTO_TEST_SUITE(SubGraphSelection) BOOST_AUTO_TEST_CASE(NoSubGraphsForNoMatch) @@ -585,3 +828,167 @@ BOOST_AUTO_TEST_CASE(MultiInputMultiOutput) } BOOST_AUTO_TEST_SUITE_END() + +BOOST_AUTO_TEST_SUITE(IntegrationTests) + +BOOST_AUTO_TEST_CASE(SingleSubGraph) +{ + // This test case represents the scenario when we have one subgraph + // in which two layers have GpuAcc backend assigned + + //Construct graph + Graph graph; + + Layer* const inputLayer = graph.AddLayer<InputLayer>(0, "input"); + + Convolution2dDescriptor convDescriptor; + Layer* const convLayer1 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1"); + convLayer1->SetBackendId(Compute::GpuAcc); + + Layer* const convLayer2 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2"); + convLayer2->SetBackendId(Compute::GpuAcc); + + Layer* const outputLayer = graph.AddLayer<OutputLayer>(0, "output"); + + inputLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0)); + convLayer1->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(0)); + convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + + // GpuAcc sub graph selector + SubGraphSelector::SubGraphs subGraphs = + SubGraphSelector::SelectSubGraphs( + graph, + // select the GpuAcc layers only + [](const Layer & l){ + bool toSelect = (l.GetBackendId() == Compute::GpuAcc); + return toSelect; + }); + + BOOST_TEST(subGraphs.size() == 1); + if(subGraphs.size() == 1) + { + BOOST_TEST((subGraphs[0] != nullptr)); + + if (subGraphs[0].get() != nullptr) + { + unsigned int numInputSlots = boost::numeric_cast<unsigned int>(subGraphs[0]->GetInputSlots().size()); + unsigned int numOutputSlots = boost::numeric_cast<unsigned int>(subGraphs[0]->GetOutputSlots().size()); + + BOOST_TEST((numInputSlots == 1)); + BOOST_TEST((numOutputSlots == 1)); + + // Save sub-graph connections for comparison after substitution + IOutputSlot* subGraphInputConn1 = subGraphs[0]->GetInputSlot(0)->GetConnection(); + IInputSlot* subGraphOutputConn1 = subGraphs[0]->GetOutputSlot(0)->GetConnection(0); + + // Construct dummy pre-compiled layer + PreCompiledDescriptor preCompiledDescriptor(numInputSlots, numOutputSlots); + Layer* const preCompiledLayer = graph.AddLayer<PreCompiledLayer>(preCompiledDescriptor, "pre-compiled"); + + // Substitute sub-graph with pre-compiled layer + graph.SubstituteSubGraph((std::move(subGraphs[0])), preCompiledLayer); + + // Check that connections are correct after substitution + BOOST_CHECK_EQUAL(preCompiledLayer->GetInputSlot(0).GetConnection(), subGraphInputConn1); + + BOOST_CHECK_EQUAL(preCompiledLayer->GetOutputSlot(0).GetConnection(0), subGraphOutputConn1); + } + } +} + +BOOST_AUTO_TEST_CASE(MultipleSubGraphs) +{ + // This test case represents the scenario when we have two subgraphs + // in which two layers have CpuAcc backend assigned + + //Construct graph + Graph graph; + + Layer* const inputLayer = graph.AddLayer<InputLayer>(0, "input"); + + ViewsDescriptor splitterDescriptor(2); + Layer* const splitterLayer = graph.AddLayer<SplitterLayer>(splitterDescriptor, "splitter"); + splitterLayer->SetBackendId(Compute::CpuAcc); + + Convolution2dDescriptor convDescriptor; + Layer* const convLayer1 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1"); + Layer* const convLayer2 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2"); + + OriginsDescriptor mergerDescriptor(2); + Layer* const mergerLayer = graph.AddLayer<MergerLayer>(mergerDescriptor, "merger"); + mergerLayer->SetBackendId(Compute::CpuAcc); + + Layer* const outputLayer = graph.AddLayer<OutputLayer>(0, "output"); + + inputLayer->GetOutputSlot(0).Connect(splitterLayer->GetInputSlot(0)); + splitterLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0)); + splitterLayer->GetOutputSlot(1).Connect(convLayer2->GetInputSlot(0)); + convLayer1->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(0)); + convLayer2->GetOutputSlot(0).Connect(mergerLayer->GetInputSlot(1)); + mergerLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); + + // CpuAcc sub graph selector + SubGraphSelector::SubGraphs subGraphs = + SubGraphSelector::SelectSubGraphs( + graph, + // select the CpuAcc layers only + [](const Layer & l){ + bool toSelect = (l.GetBackendId() == Compute::CpuAcc); + return toSelect; + }); + + BOOST_TEST(subGraphs.size() == 2); + if(subGraphs.size() == 2) + { + BOOST_TEST((subGraphs[0] != nullptr)); + BOOST_TEST((subGraphs[1] != nullptr)); + + if (subGraphs[0].get() != nullptr && subGraphs[1].get() != nullptr) + { + //Sort subGraphs by their inputSlot size. + std::sort(subGraphs.begin(), subGraphs.end(), + [](SubGraphSelector::SubGraphPtr & lhs, SubGraphSelector::SubGraphPtr & rhs) + { + return (lhs->GetInputSlots().size() < rhs->GetInputSlots().size()); + } + ); + + unsigned int numInputSlots1 = boost::numeric_cast<unsigned int>(subGraphs[0]->GetInputSlots().size()); + unsigned int numOutputSlots1 = boost::numeric_cast<unsigned int>(subGraphs[0]->GetOutputSlots().size()); + + unsigned int numInputSlots2 = boost::numeric_cast<unsigned int>(subGraphs[1]->GetInputSlots().size()); + unsigned int numOutputSlots2 = boost::numeric_cast<unsigned int>(subGraphs[1]->GetOutputSlots().size()); + + // Save sub-graph connections for comparison after substitution + IOutputSlot* subGraph1InputConn = subGraphs[0]->GetInputSlot(0)->GetConnection(); + IInputSlot* subGraph1OutputConn1 = subGraphs[0]->GetOutputSlot(0)->GetConnection(0); + IInputSlot* subGraph1OutputConn2 = subGraphs[0]->GetOutputSlot(1)->GetConnection(0); + + // Save sub-graph connections for comparison after substitution + IOutputSlot* subGraph2InputConn1 = subGraphs[1]->GetInputSlot(0)->GetConnection(); + IOutputSlot* subGraph2InputConn2 = subGraphs[1]->GetInputSlot(1)->GetConnection(); + IInputSlot* subGraph2OutputConn = subGraphs[1]->GetOutputSlot(0)->GetConnection(0); + + PreCompiledDescriptor preCompiledDescriptor1(numInputSlots1, numOutputSlots1); + Layer* const preCompiledLayer1 = graph.AddLayer<PreCompiledLayer>(preCompiledDescriptor1, "pre-compiled1"); + + PreCompiledDescriptor preCompiledDescriptor2(numInputSlots2, numOutputSlots2); + Layer* const preCompiledLayer2 = graph.AddLayer<PreCompiledLayer>(preCompiledDescriptor2, "pre-compiled2"); + + // Substitute sub-graph with pre-compiled layer + graph.SubstituteSubGraph((std::move(subGraphs[0])), preCompiledLayer1); + graph.SubstituteSubGraph((std::move(subGraphs[1])), preCompiledLayer2); + + // Check that connections are correct after substitution + BOOST_CHECK_EQUAL(preCompiledLayer1->GetInputSlot(0).GetConnection(), subGraph1InputConn); + BOOST_CHECK_EQUAL(preCompiledLayer1->GetOutputSlot(0).GetConnection(0), subGraph1OutputConn1); + BOOST_CHECK_EQUAL(preCompiledLayer1->GetOutputSlot(1).GetConnection(0), subGraph1OutputConn2); + + BOOST_CHECK_EQUAL(preCompiledLayer2->GetInputSlot(0).GetConnection(), subGraph2InputConn1); + BOOST_CHECK_EQUAL(preCompiledLayer2->GetInputSlot(1).GetConnection(), subGraph2InputConn2); + BOOST_CHECK_EQUAL(preCompiledLayer2->GetOutputSlot(0).GetConnection(0), subGraph2OutputConn); + } + } +} + +BOOST_AUTO_TEST_SUITE_END() |