14 #include <doctest/doctest.h> 23 using namespace armnn;
30 for(
auto&& layer : subgraphLayers)
32 auto posInGraph = std::find(graph.
begin(), graph.
end(), layer);
33 if(posInGraph != graph.
end())
46 std::vector<int> ignoreSlots = {})
49 for (
auto&& layer : layers)
51 for (
auto&& it = layer->BeginInputSlots(); it != layer->EndInputSlots(); ++it)
53 if (std::find(ignoreSlots.begin(), ignoreSlots.end(), it->GetSlotIndex()) != ignoreSlots.end())
59 result.push_back(&(*it));
68 std::vector<int> ignoreSlots = {})
71 for (
auto&& layer: layers)
73 for (
unsigned int i = 0; i < layer->GetNumInputSlots(); ++i)
75 if (std::find(ignoreSlots.begin(), ignoreSlots.end(), i) != ignoreSlots.end())
81 result.push_back(&(layer->GetInputSlot(i)));
94 for (
auto && layer : layers)
96 for (
auto&& it = layer->BeginOutputSlots(); it != layer->EndOutputSlots(); ++it)
98 result.push_back(&(*it));
108 for (
auto&& layer: layers)
110 for (
unsigned int i = 0; i < layer->GetNumOutputSlots(); ++i)
112 result.push_back(&(layer->GetOutputSlot(i)));
126 return std::make_unique<SubgraphView>(std::move(inputs), std::move(outputs), std::move(layers));
133 return std::make_unique<SubgraphView>(std::move(layers), std::move(inputs), std::move(outputs));
136 template <
typename T,
typename Iterator>
137 std::vector<T> ToSortedArray(Iterator begin, Iterator end)
139 std::vector<T> result(begin, end);
140 std::sort(result.begin(), result.end());
144 template <
typename T>
145 void CompareVectors(
const std::vector<T>& result,
const std::vector<T>& expected)
147 CHECK(std::equal(result.begin(), result.end(), expected.begin(), expected.end()));
154 CHECK((result.get() !=
nullptr));
155 CHECK((expected.get() !=
nullptr));
157 if (result.get() !=
nullptr && expected.get() !=
nullptr)
159 CHECK(result->GetIInputSlots().size() == expected->GetIInputSlots().size());
160 CHECK(result->GetIOutputSlots().size() == expected->GetIOutputSlots().size());
161 CHECK(result->GetIConnectableLayers().size() == expected->GetIConnectableLayers().size());
163 auto resultLayers = ToSortedArray<IConnectableLayer*>(result->GetIConnectableLayers().begin(),
164 result->GetIConnectableLayers().end());
165 auto expectedLayers = ToSortedArray<IConnectableLayer*>(expected->GetIConnectableLayers().begin(),
166 expected->GetIConnectableLayers().end());
167 CompareVectors(resultLayers, expectedLayers);
169 auto resultInputs = ToSortedArray<IInputSlot *>(result->GetIInputSlots().begin(),
170 result->GetIInputSlots().end());
171 auto expectedInputs = ToSortedArray<IInputSlot *>(expected->GetIInputSlots().begin(),
172 expected->GetIInputSlots().end());
173 CompareVectors(resultInputs, expectedInputs);
175 auto resultOutputs = ToSortedArray<IOutputSlot *>(result->GetIOutputSlots().begin(),
176 result->GetIOutputSlots().end());
177 auto expectedOutputs = ToSortedArray<IOutputSlot *>(expected->GetIOutputSlots().begin(),
178 expected->GetIOutputSlots().end());
179 CompareVectors(resultOutputs, expectedOutputs);
189 TEST_CASE(
"SubgraphViewIterators")
198 if (std::find(subgraph.cbeginIConnectable(), subgraph.cendIConnectable(), layer)
199 != subgraph.cendIConnectable())
207 if (std::find(subgraph.beginIConnectable(), subgraph.endIConnectable(), layer)
208 != subgraph.endIConnectable())
217 for (
auto& iConnectableLayer : subgraphLayers)
219 if (std::string(iConnectableLayer->GetName()) ==
"input")
231 for (
auto& layerOld : subgraphLayersOld)
233 if (std::string(layerOld->GetName()) ==
"input")
241 TEST_CASE(
"SubgraphViewSlots")
256 convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
260 CreateIInputsFrom({convLayer1}, {1, 2}),
261 CreateIOutputsFrom({convLayer2}));
264 CHECK(subgraph->GetIInputSlots().size() == 1);
265 CHECK(subgraph->GetIOutputSlots().size() == 1);
268 CHECK(subgraph->GetInputSlots().size() == 1);
269 CHECK(subgraph->GetOutputSlots().size() == 1);
272 CHECK(subgraph->GetOutputSlot(0) == subgraph->GetIOutputSlot(0));
273 CHECK(subgraph->GetInputSlot(0) == subgraph->GetIInputSlot(0));
278 TEST_CASE(
"SubgraphViewConstructors")
293 convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
298 CreateIInputsFrom({convLayer1}),
299 CreateIOutputsFrom({convLayer2}));
303 CHECK(subgraph->GetIConnectableLayers() == subgraph2.GetIConnectableLayers());
304 CHECK(subgraph->GetIInputSlots() == subgraph2.GetIInputSlots());
305 CHECK(subgraph->GetIOutputSlots() == subgraph2.GetIOutputSlots());
308 CHECK(subgraph->GetLayers() == subgraph2.GetLayers());
309 CHECK(subgraph->GetInputSlots() == subgraph2.GetInputSlots());
310 CHECK(subgraph->GetOutputSlots() == subgraph2.GetOutputSlots());
315 CHECK(subgraph->GetIConnectableLayers() == subgraph3.GetIConnectableLayers());
316 CHECK(subgraph->GetIInputSlots() == subgraph3.GetIInputSlots());
317 CHECK(subgraph->GetIOutputSlots() == subgraph3.GetIOutputSlots());
320 CHECK(subgraph->GetLayers() == subgraph3.GetLayers());
321 CHECK(subgraph->GetInputSlots() == subgraph3.GetInputSlots());
322 CHECK(subgraph->GetOutputSlots() == subgraph3.GetOutputSlots());
326 subgraph.get()->Clear();
327 CHECK(subgraph->GetIConnectableLayers().size() == 0);
328 CHECK(subgraph->GetIInputSlots().size() == 0);
329 CHECK(subgraph->GetIOutputSlots().size() == 0);
336 TEST_CASE(
"SingleInputSingleOutput")
351 weightsLayer1->GetOutputSlot(0).Connect(convLayer1->
GetInputSlot(1));
353 weightsLayer2->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(1));
354 convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
359 CreateIInputsFrom({convLayer1}, {1}),
360 CreateIOutputsFrom({convLayer2}));
381 TEST_CASE(
"SingleInputSingleOutputAddPrecompiledLayerSubstituteSubgraph1")
396 convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
413 IConnectableLayer* preCompiledLayer = network->AddPrecompiledLayer(preCompiledDescriptor,
414 std::move(compiledBlobPtr),
425 TEST_CASE(
"SingleInputSingleOutputAddPrecompiledLayerSubstituteSubgraph2")
440 convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
457 IConnectableLayer* preCompiledLayer = network->AddPrecompiledLayer(preCompiledDescriptor,
458 std::move(compiledBlobPtr),
470 TEST_CASE(
"SingleInputSingleOutputSubstituteGraph")
485 convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
498 Graph substituteGraph;
514 TEST_CASE(
"MultiInputSingleOutput")
537 convLayer2->GetOutputSlot(0).Connect(concatLayer->
GetInputSlot(1));
565 TEST_CASE(
"SingleInputMultiOutput")
586 convLayer2->GetOutputSlot(0).Connect(concatLayer->
GetInputSlot(1));
615 TEST_CASE(
"MultiInputMultiOutput")
638 convLayer2->GetOutputSlot(0).Connect(concatLayer->
GetInputSlot(1));
669 TEST_CASE(
"EraseReplacedIConnectableLayers")
707 CHECK(!AreAnySubgraphLayersPresentInGraph(subgraphLayers, graph));
714 TEST_CASE(
"SubgraphForEmptyGraph")
724 TEST_CASE(
"SubgraphForEntireGraph")
739 CHECK(subgraph.GetIInputSlots().empty());
740 CHECK(subgraph.GetIOutputSlots().empty());
741 CHECK(subgraph.GetIConnectableLayers().size() == graph.
GetNumLayers());
744 TEST_CASE(
"NoSubgraphsForNoMatch")
754 CHECK(subgraphs.empty());
757 TEST_CASE(
"OneSubgraphsSelectedASingleMatch")
770 bool isOutput = l.
GetNameStr().compare(
"output") == 0;
774 CHECK(subgraphs.size() == 1);
775 if (subgraphs.size() == 1)
782 CompareSubgraphViews(subgraphs[0], expected);
786 TEST_CASE(
"MultipleLayersSelectedInTheMiddle")
809 CHECK(subgraphs.size() == 1);
810 if (subgraphs.size() == 1)
816 CompareSubgraphViews(subgraphs[0], expected);
820 TEST_CASE(
"DisjointGraphs")
845 CHECK(subgraphs.size() == 2);
846 if (subgraphs.size() == 2)
848 CHECK((subgraphs[0] !=
nullptr));
849 CHECK((subgraphs[1] !=
nullptr));
850 if (subgraphs[0].
get() !=
nullptr && subgraphs[1].
get() !=
nullptr)
852 if (std::find(subgraphs[0]->GetIConnectableLayers().begin(),
853 subgraphs[0]->GetIConnectableLayers().end(), i0) !=
854 subgraphs[0]->GetIConnectableLayers().end())
856 CompareSubgraphViews(subgraphs[0], expected1);
857 CompareSubgraphViews(subgraphs[1], expected2);
861 CompareSubgraphViews(subgraphs[0], expected2);
862 CompareSubgraphViews(subgraphs[1], expected1);
868 TEST_CASE(
"IslandInTheMiddle")
919 bool toSelect = std::string(l.
GetName())[0] ==
'm';
926 { m0, m1, m2, m3, m4 });
928 auto smallerSubgraph =
930 std::vector<OutputSlot*>{},
933 CHECK(subgraphs.size() == 2);
934 if (subgraphs.size() == 2)
937 CHECK((subgraphs[0] !=
nullptr));
938 CHECK((subgraphs[1] !=
nullptr));
940 if (subgraphs[0].
get() !=
nullptr && subgraphs[1].
get() !=
nullptr)
943 std::sort(subgraphs.begin(), subgraphs.end(),
946 return (lhs->GetIConnectableLayers().size() < rhs->GetIConnectableLayers().size());
950 CHECK(subgraphs[0]->GetIConnectableLayers().size() == 2);
951 CHECK(subgraphs[1]->GetIConnectableLayers().size() == 5);
953 CompareSubgraphViews(subgraphs[0], smallerSubgraph);
954 CompareSubgraphViews(subgraphs[1], largerSubgraph);
959 TEST_CASE(
"MultipleSimpleSubgraphs")
1015 CHECK(subgraphs.size() == 2);
1016 if (subgraphs.size() == 2)
1019 CHECK((subgraphs[0] !=
nullptr));
1020 CHECK((subgraphs[1] !=
nullptr));
1022 if (subgraphs[0].
get() !=
nullptr && subgraphs[1].
get() !=
nullptr)
1025 std::sort(subgraphs.begin(), subgraphs.end(),
1028 return (lhs->GetIConnectableLayers().size() < rhs->GetIConnectableLayers().size());
1032 CHECK(subgraphs[0]->GetIConnectableLayers().size() == 1);
1033 CHECK(subgraphs[1]->GetIConnectableLayers().size() == 2);
1035 CompareSubgraphViews(subgraphs[0], smallerSubgraph);
1036 CompareSubgraphViews(subgraphs[1], largerSubgraph);
1041 TEST_CASE(
"SimpleLinearTest")
1076 CHECK(subgraphs.size() == 1);
1077 if(subgraphs.size() == 1)
1081 {layerM1, layerM2});
1083 CompareSubgraphViews(subgraphs[0], expected);
1087 TEST_CASE(
"MultiInputSingleOutput")
1131 CHECK(subgraphs.size() == 1);
1132 if (subgraphs.size() == 1)
1136 {layerM1, layerM2, layerM3});
1138 CompareSubgraphViews(subgraphs[0], expected);
1142 TEST_CASE(
"SingleInputMultiOutput")
1171 layerM1->GetOutputSlot(0).Connect(layerM2->GetInputSlot(0));
1172 layerM1->GetOutputSlot(1).Connect(layerM3->GetInputSlot(0));
1173 layerM2->GetOutputSlot(0).Connect(layerX2->GetInputSlot(0));
1174 layerM3->GetOutputSlot(0).Connect(layerX3->GetInputSlot(0));
1187 CHECK(subgraphs.size() == 1);
1188 if(subgraphs.size() == 1)
1192 {layerM1, layerM2, layerM3});
1194 CompareSubgraphViews(subgraphs[0], expected);
1198 TEST_CASE(
"MultiInputMultiOutput")
1251 CHECK(subgraphs.size() == 1);
1252 if (subgraphs.size() == 1)
1256 {m1, m2, m3, m4, m5});
1258 CompareSubgraphViews(subgraphs[0], expected);
1262 TEST_CASE(
"ValidMerge")
1296 [](
const Layer& l) {
1297 return std::string(l.
GetName())[0] ==
'm';
1301 auto expectedSubgraph0 =
1312 CHECK(subgraphs.size() == 2);
1313 if (subgraphs.size() == 2)
1316 CHECK((subgraphs[0] !=
nullptr));
1317 CHECK((subgraphs[1] !=
nullptr));
1319 if (subgraphs[0].
get() !=
nullptr && subgraphs[1].
get() !=
nullptr)
1321 if (subgraphs[0]->GetIInputSlots().size() == 1)
1323 CompareSubgraphViews(subgraphs[0], expectedSubgraph0);
1324 CompareSubgraphViews(subgraphs[1], expectedSubgraph1);
1328 CompareSubgraphViews(subgraphs[0], expectedSubgraph1);
1329 CompareSubgraphViews(subgraphs[1], expectedSubgraph0);
1335 TEST_CASE(
"PropagatedDependencies")
1391 bool toSelect = std::string(l.
GetName())[0] ==
'm';
1398 { m0, m1, m2, m3, m4 });
1401 std::vector<OutputSlot*>{}, { m5, m6 });
1403 auto smallerSubgraph =
1406 CHECK(subgraphs.size() == 3);
1407 if (subgraphs.size() == 3)
1410 CHECK((subgraphs[0] !=
nullptr));
1411 CHECK((subgraphs[1] !=
nullptr));
1412 CHECK((subgraphs[2] !=
nullptr));
1414 if (subgraphs[0].
get() !=
nullptr && subgraphs[1].
get() !=
nullptr && subgraphs[2].
get() !=
nullptr)
1417 std::sort(subgraphs.begin(), subgraphs.end(),
1420 return (lhs->GetIConnectableLayers().size() < rhs->GetIConnectableLayers().size());
1424 CompareSubgraphViews(subgraphs[0], smallerSubgraph);
1425 CompareSubgraphViews(subgraphs[1], mediumSubgraph);
1426 CompareSubgraphViews(subgraphs[2], largerSubgraph);
1436 constexpr
bool debug =
false;
1438 std::mt19937 randomGenerator;
1441 auto GetRandom = [&randomGenerator](
auto maxExclusive) {
1445 std::uniform_real_distribution<float> uniform(0.0f, 1.0f);
1446 return static_cast<decltype(maxExclusive)
>(uniform(randomGenerator) *
static_cast<float>(maxExclusive));
1449 auto GetRandomFlag = [&randomGenerator](
float trueProb) {
1450 std::uniform_real_distribution<float> uniform(0.0f, 1.0f);
1451 return uniform(randomGenerator) < trueProb;
1454 constexpr uint32_t numTests = 100;
1455 for (uint32_t testIdx = 0; testIdx < numTests; ++testIdx)
1457 randomGenerator.seed(testIdx);
1465 uint32_t numInputs = 1 + GetRandom(4u);
1466 uint32_t numConstants = 1 + GetRandom(4u);
1467 uint32_t numOutputs = 1 + GetRandom(4u);
1468 uint32_t numConcats = 0 + GetRandom(500u);
1469 uint32_t numSplits = 0 + GetRandom(500u);
1470 float supportedProb = 0.7f;
1472 for (uint32_t i = 0; i < numInputs; ++i)
1474 std::string name =
"input" + std::to_string(i) + (GetRandomFlag(supportedProb) ?
"S" :
"N");
1477 for (uint32_t i = 0; i < numConstants; ++i)
1479 std::string name =
"constant" + std::to_string(i) + (GetRandomFlag(supportedProb) ?
"S" :
"N");
1482 for (uint32_t i = 0; i < numOutputs; ++i)
1484 std::string name =
"output" + std::to_string(i) + (GetRandomFlag(supportedProb) ?
"S" :
"N");
1487 for (uint32_t i = 0; i < numConcats; ++i)
1489 std::string name =
"concat" + std::to_string(i) + (GetRandomFlag(supportedProb) ?
"S" :
"N");
1490 numInputs = 1 + GetRandom(3u);
1494 for (uint32_t i = 0; i < numSplits; ++i)
1496 std::string name =
"split" + std::to_string(i) + (GetRandomFlag(supportedProb) ?
"S" :
"N");
1497 numOutputs = 1 + GetRandom(3u);
1507 uint32_t maxLayerDepth = 5 + GetRandom(2000u);
1508 std::map<Layer*, uint32_t> layerDepths;
1509 std::map<uint32_t, std::vector<Layer*>> layersAtDepth;
1510 for (
Layer* layer : graph)
1522 depth = 1 + GetRandom(maxLayerDepth);
1524 layerDepths[layer] = depth;
1525 layersAtDepth[depth].push_back(layer);
1530 for (
Layer* layer : graph)
1532 for (uint32_t inputSlotIdx = 0; inputSlotIdx < layer->GetNumInputSlots(); ++inputSlotIdx)
1534 InputSlot& inputSlot = layer->GetInputSlot(inputSlotIdx);
1535 uint32_t maxLayerDepthToConnectTo = layerDepths[layer];
1540 uint32_t layerDepth = GetRandom(maxLayerDepthToConnectTo);
1541 const std::vector<Layer*>& layersToChooseFrom = layersAtDepth[layerDepth];
1542 if (layersToChooseFrom.size() == 0)
1546 Layer* layerToConnectWith = layersToChooseFrom[GetRandom(layersToChooseFrom.size())];
1560 std::ofstream f(
"INPUT_" + std::to_string(testIdx) +
".dot");
1565 auto startTime = std::chrono::high_resolution_clock::now();
1569 [](
const Layer& l) {
return std::string(l.
GetName()).back() ==
'S'; });
1571 auto endTime = std::chrono::high_resolution_clock::now();
1572 auto duration = std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime);
1575 std::cout <<
"Test " << testIdx <<
": " << duration.count() <<
" microseconds" << std::endl;
1580 std::map<Layer*, SubgraphView*> layerToSubgraph;
1581 for (
Layer* layer : graph)
1584 for (std::unique_ptr<SubgraphView>& subgraph : subgraphs)
1586 std::string name = std::to_string(i++);
1587 if (std::find(subgraph->cbeginIConnectable(), subgraph->cendIConnectable(), layer)
1588 != subgraph->cendIConnectable())
1590 layerToSubgraph[layer] = subgraph.get();
1600 for (
Layer* layer : graph)
1602 std::string name =
"NotAssigned";
1603 auto subgraphIt = layerToSubgraph.find(layer);
1604 if (subgraphIt != layerToSubgraph.end())
1606 auto subgraphIdx = std::distance(subgraphs.begin(),
1607 std::find_if(subgraphs.begin(), subgraphs.end(),
1608 [&](
auto& s) {
return s.get() == subgraphIt->second; }));
1609 name = std::to_string(subgraphIdx);
1614 std::ofstream f(
"GRAPH_" + std::to_string(testIdx) +
".dot");
1615 graph.SerializeToDot(f);
1621 for (std::unique_ptr<SubgraphView>& subgraph : subgraphs)
1623 for (
IInputSlot* inSlot : subgraph->GetIInputSlots())
1625 std::queue<Layer*> toProcess;
1626 toProcess.push(&PolymorphicDowncast<InputSlot*>(inSlot)->GetConnectedOutputSlot()->GetOwningLayer());
1627 while (toProcess.size() > 0)
1629 Layer* l = toProcess.front();
1632 CHECK(layerToSubgraph[l] != subgraph.get());
1636 toProcess.push(&is.GetConnectedOutputSlot()->GetOwningLayer());
1648 TEST_CASE(
"SingleSubgraph")
1683 [](
const Layer & l){
1688 CHECK(subgraphs.size() == 1);
1689 if(subgraphs.size() == 1)
1691 CHECK((subgraphs[0] !=
nullptr));
1693 if (subgraphs[0].
get() !=
nullptr)
1695 unsigned int numInputSlots =
armnn::numeric_cast<
unsigned int>(subgraphs[0]->GetIInputSlots().size());
1696 unsigned int numOutputSlots =
armnn::numeric_cast<
unsigned int>(subgraphs[0]->GetIOutputSlots().size());
1698 CHECK((numInputSlots == 1));
1699 CHECK((numOutputSlots == 1));
1720 TEST_CASE(
"MultipleSubgraphs")
1750 weights1->GetOutputSlot(0).Connect(convLayer1->
GetInputSlot(1));
1752 weights2->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(1));
1753 convLayer2->GetOutputSlot(0).Connect(pConcatLayer->
GetInputSlot(1));
1761 [](
const Layer & l){
1766 CHECK(subgraphs.size() == 2);
1767 if(subgraphs.size() == 2)
1769 CHECK((subgraphs[0] !=
nullptr));
1770 CHECK((subgraphs[1] !=
nullptr));
1772 if (subgraphs[0].
get() !=
nullptr && subgraphs[1].
get() !=
nullptr)
1775 std::sort(subgraphs.begin(), subgraphs.end(),
1778 return (lhs->GetIInputSlots().size() < rhs->GetIInputSlots().size());
1782 unsigned int numInputSlots1 =
armnn::numeric_cast<
unsigned int>(subgraphs[0]->GetIInputSlots().size());
1783 unsigned int numOutputSlots1 =
armnn::numeric_cast<
unsigned int>(subgraphs[0]->GetIOutputSlots().size());
1785 unsigned int numInputSlots2 =
armnn::numeric_cast<
unsigned int>(subgraphs[1]->GetIInputSlots().size());
1786 unsigned int numOutputSlots2 =
armnn::numeric_cast<
unsigned int>(subgraphs[1]->GetIOutputSlots().size());
1820 TEST_CASE(
"SubgraphCycles")
1867 bool toSelect = (l.
GetNameStr().find(
'm') != std::string::npos);
1880 CHECK(subgraphs.size() == 2);
1881 if (subgraphs.size() == 2)
1884 CHECK((subgraphs[0] !=
nullptr));
1885 CHECK((subgraphs[1] !=
nullptr));
1887 if (subgraphs[0].
get() !=
nullptr && subgraphs[1].
get() !=
nullptr)
1890 std::sort(subgraphs.begin(), subgraphs.end(),
1893 return (lhs->GetIConnectableLayers().size() < rhs->GetIConnectableLayers().size());
1898 CHECK(subgraphs[0]->GetIConnectableLayers().size() == 1);
1899 CHECK(subgraphs[1]->GetIConnectableLayers().size() == 2);
1901 CompareSubgraphViews(subgraphs[0], outputSubgraph);
1902 CompareSubgraphViews(subgraphs[1], inputSubgraph);
1907 TEST_CASE(
"SubgraphOrder")
1921 {output, input, activation});
1926 view->ForEachLayer([&idx, &expectedSorted](
const Layer* l)
1928 CHECK((expectedSorted[idx] == l->
GetType()));
1934 TEST_CASE(
"SubgraphViewWorkingCopy")
1955 workingCopy.ForEachIConnectableLayer([&idx, &expectedSorted](
const IConnectableLayer* l)
1957 CHECK((expectedSorted[idx] == l->
GetType()));
1963 bool ReplaceConstantMultiplicationWithDepthwise(
SubgraphView& subgraph,
1977 std::swap(patternSubgraphInput, patternSubgraphConstant);
1998 ARMNN_ASSERT_MSG(M == 1,
"Constant multiplication only support 1x1x1xC, so M should always be 1 here");
2001 const void* weightData = PolymorphicPointerDowncast<const ConstantLayer>(constantLayer)
2002 ->m_LayerOutput->GetConstTensor<
void>();
2006 const auto depthwiseLayer = replacementGraph->AddDepthwiseConvolution2dLayer(
2007 desc,
"Replacement for Constant-Multiplication");
2012 layers.push_back(layer);
2013 layers.push_back(const_cast<IConnectableLayer*>(constantLayer));
2016 {patternSubgraphInput, patternSubgraphConstant},
2037 return ReplaceConstantMultiplicationWithDepthwise(subgraph, layer);
2040 throw Exception(
"Found unknown MultiplicationSupportedMode value");
2050 const ReplacementFunc replacementFuncs[] = {
2051 &ReplaceTestMultiplication,
2056 auto madeChange =
false;
2057 for (
const ReplacementFunc f : replacementFuncs)
2059 madeChange = f(subgraph, layer);
2070 TEST_CASE(
"SubgraphViewWorkingCopyReplacementFunc")
2078 std::vector<uint8_t> constData(constInfo.GetNumElements(), 0);
2079 std::iota(constData.begin(), constData.end(), 0);
2086 constant->m_LayerOutput = std::make_shared<ScopedTensorHandle>(constTensor);
2093 mul->GetOutputSlot(0).SetTensorInfo(outputInfo);
2097 mul->GetOutputSlot(0).Connect(output->GetInputSlot(0));
2107 CHECK(workingCopy.GetIConnectableLayers().size() == 4);
2110 workingCopy.ForEachIConnectableLayer([&idx, &expectedSorted](
const IConnectableLayer* l)
2112 CHECK((expectedSorted[idx] == l->
GetType()));
2118 ReplaceUnsupportedLayers(workingCopy);
2121 CHECK(workingCopy.GetIConnectableLayers().size() == 3);
2124 workingCopy.ForEachIConnectableLayer([&idx, &expectedSortedReplaced](
const IConnectableLayer* l)
2126 CHECK((expectedSortedReplaced[idx] == l->
GetType()));
2132 TEST_CASE(
"SubgraphViewWorkingCopySubstituteSubgraph")
2153 auto workingCopy = view->GetWorkingCopy();
2154 CHECK_THROWS_AS(workingCopy.GetWorkingCopy(),
Exception);
2157 TEST_CASE(
"SubgraphViewWorkingCopyOptimizationViews")
2165 std::vector<uint8_t> constData(constInfo.GetNumElements(), 0);
2166 std::iota(constData.begin(), constData.end(), 0);
2173 constant->m_LayerOutput = std::make_shared<ScopedTensorHandle>(constTensor);
2180 mul->GetOutputSlot(0).SetTensorInfo(outputInfo);
2184 mul->GetOutputSlot(0).Connect(output->GetInputSlot(0));
2196 workingCopy.ForEachIConnectableLayer([&idx, &expectedSorted](
const IConnectableLayer* l)
2198 CHECK((expectedSorted[idx] == l->
GetType()));
2204 ReplaceUnsupportedLayers(workingCopy);
2209 workingCopy.ForEachIConnectableLayer([&idx, &expectedSortedReplaced](
const IConnectableLayer* l)
2211 CHECK((expectedSortedReplaced[idx] == l->
GetType()));
2231 CHECK(optimizationViews.
Validate(*view));
2234 TEST_CASE(
"SubgraphViewWorkingCopyReplaceSlots")
2241 std::vector<uint8_t> constData(constInfo.GetNumElements(), 0);
2242 std::iota(constData.begin(), constData.end(), 0);
2249 constant->m_LayerOutput = std::make_shared<ScopedTensorHandle>(constTensor);
2256 mul->GetOutputSlot(0).SetTensorInfo(outputInfo);
2260 mul->GetOutputSlot(0).Connect(output->GetInputSlot(0));
2263 CreateIInputsFrom({mul}),
2264 CreateIOutputsFrom({mul}));
2274 CHECK((expectedSorted[idx] == l->
GetType()));
2280 ReplaceUnsupportedLayers(workingCopy);
2288 CHECK((expectedSortedReplaced[idx] == l->
GetType()));
TEST_SUITE("TestConstTensorLayerVisitor")
A layer that the constant data can be bound to.
Iterator begin()
Returns iterator pointing to the beginning of the list. Lowercase for range-based for loops...
This layer represents a split operation.
A ViewsDescriptor for the SplitterLayer.
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
const IOutputSlots & GetIOutputSlots() const
const TensorShape & GetShape() const
CPU Execution: Reference C++ kernels.
Status SerializeToDot(std::ostream &stream)
void swap(OriginsDescriptor &first, OriginsDescriptor &second)
const IConnectableLayers & GetIConnectableLayers() const
const IInputSlots & GetIInputSlots() const
#define ARMNN_NO_DEPRECATE_WARN_BEGIN
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
A Convolution2dDescriptor for the Convolution2dLayer.
int Connect(InputSlot &destination)
std::vector< OutputSlot * > OutputSlots
void AddSubstitution(SubstitutionPair &&substitution)
This layer represents an activation operation with the specified activation function.
Copyright (c) 2021 ARM Limited and Contributors.
void IgnoreUnused(Ts &&...)
void SetBackendId(const BackendId &id)
const std::vector< InputSlot > & GetInputSlots() const
virtual const IInputSlot * GetConnection(unsigned int index) const =0
unsigned int GetNumOutputSlots() const override
Returns the number of connectable output slots.
void SubstituteSubgraph(SubgraphView &, IConnectableLayer *)
These methods should be called on a working copy subgraph created from GetWorkingCopy.
int LayerBindingId
Type of identifiers for bindable layers (inputs, outputs).
virtual void SetTensorInfo(const TensorInfo &tensorInfo)=0
void SetShape(const TensorShape &newShape)
std::unique_ptr< void, CompiledBlobDeleter > CompiledBlobPtr
The SubgraphView class represents a subgraph of a Graph.
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
A layer user-provided data can be bound to (e.g. inputs, outputs).
std::list< IConnectableLayer * > IConnectableLayers
#define ARMNN_NO_DEPRECATE_WARN_END
#define ARMNN_ASSERT_MSG(COND, MSG)
An output connection slot for a layer.
An OriginsDescriptor for the ConcatLayer.
std::vector< IOutputSlot * > IOutputSlots
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
This layer represents a merge operation.
void ForEachIConnectableLayer(Func func) const
const std::string & GetNameStr() const
LayerType GetType() const override
Returns the armnn::LayerType of this layer.
std::vector< SubgraphViewPtr > Subgraphs
virtual const IConnectableLayer & GetOwningIConnectableLayer() const =0
INetworkPtr & GetINetwork()
std::vector< IInputSlot * > IInputSlots
GPU Execution: OpenCL: ArmCompute.
bool Validate(const SubgraphView &originalSubgraph) const
An ActivationDescriptor for the ActivationLayer.
const BackendId & GetBackendId() const
virtual LayerType GetType() const =0
Returns the armnn::LayerType of this layer.
std::vector< InputSlot * > InputSlots
This layer represents an addition operation.
void SubstituteSubgraph(SubgraphView &subgraph, IConnectableLayer *substituteLayer)
Substitutes the given sub-graph with either a new layer or a new sub-graph.
std::unique_ptr< SubgraphView > SubgraphViewPtr
EmptyOptional is used to initialize the Optional class in case we want to have default value for an O...
SubgraphView::SubgraphViewPtr CreateSubgraphViewFrom(SubgraphView::InputSlots &&inputs, SubgraphView::OutputSlots &&outputs, SubgraphView::Layers &&layers)
SubgraphView::OutputSlots CreateOutputsFrom(const std::vector< Layer *> &layers)
static Subgraphs SelectSubgraphs(Graph &graph, const LayerSelectorFunction &selector)
Selects subgraphs from a graph based on the selector function and the algorithm.
Base class for all ArmNN exceptions so that users can filter to just those.
CPU Execution: NEON: ArmCompute.
Iterator end()
Returns iterator pointing to the end of the list. Lowercase for range-based for loops.
void SetTensorInfo(const TensorInfo &tensorInfo) override
virtual const IInputSlot & GetInputSlot(unsigned int index) const =0
Get a const input slot handle by slot index.
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
virtual const TensorInfo & GetTensorInfo() const =0
virtual const IOutputSlot & GetOutputSlot(unsigned int index) const =0
Get the const output slot handle by slot index.
const char * GetName() const override
Returns the name of the layer.
This layer represents a convolution 2d operation.
std::unique_ptr< INetwork, void(*)(INetwork *network)> INetworkPtr
virtual int Connect(IInputSlot &destination)=0
void ForEachLayer(Func func) const
A PreCompiledDescriptor for the PreCompiledLayer.
std::list< Layer * > Layers
size_t GetNumLayers() const
LayerT * InsertNewLayer(InputSlot &insertBefore, Args &&... args)
Inserts a new layer between the output slot currently connected to insertBefore and insertBefore itse...
This layer represents a multiplication operation.
SubgraphView GetWorkingCopy()
This method returns a copy of the original SubgraphView provided by OptimizeSubgraphView with a separ...
static INetworkPtr Create(NetworkOptions networkOptions={})
SubgraphView::InputSlots CreateInputsFrom(Layer *layer, std::vector< unsigned int > ignoreSlots)
A DepthwiseConvolution2dDescriptor for the DepthwiseConvolution2dLayer.
const InputSlot * GetConnection(unsigned int index) const override
LayerType
When adding a new layer, adapt also the LastLayer enum value in the enum class LayerType below...