5 #include <boost/test/unit_test.hpp> 19 using namespace armnn;
26 for(
auto&& layer : subgraphLayers)
28 auto posInGraph = std::find(graph.
begin(), graph.
end(), layer);
29 if(posInGraph != graph.
end())
44 for (
auto&& layer : layers)
46 for (
auto&& it = layer->BeginInputSlots(); it != layer->EndInputSlots(); ++it)
48 result.push_back(&(*it));
60 for (
auto && layer : layers)
62 for (
auto&& it = layer->BeginOutputSlots(); it != layer->EndOutputSlots(); ++it)
64 result.push_back(&(*it));
78 return std::make_unique<SubgraphView>(std::move(inputs), std::move(outputs), std::move(layers));
81 template <
typename T,
typename Iterator>
82 std::vector<T> ToSortedArray(Iterator begin, Iterator end)
84 std::vector<T> result(begin, end);
85 std::sort(result.begin(), result.end());
90 void CompareVectors(
const std::vector<T>& result,
const std::vector<T>& expected)
92 BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end());
99 BOOST_TEST((result.get() !=
nullptr));
100 BOOST_TEST((expected.get() !=
nullptr));
102 if (result.get() !=
nullptr && expected.get() !=
nullptr)
107 BOOST_TEST(result->GetInputSlots().size() == expected->GetInputSlots().size());
108 BOOST_TEST(result->GetOutputSlots().size() == expected->GetOutputSlots().size());
109 BOOST_TEST(result->GetLayers().size() == expected->GetLayers().size());
111 auto resultLayers = ToSortedArray<Layer *>(result->GetLayers().begin(),
112 result->GetLayers().end());
113 auto expectedLayers = ToSortedArray<Layer *>(expected->GetLayers().begin(),
114 expected->GetLayers().end());
115 CompareVectors(resultLayers, expectedLayers);
117 auto resultInputs = ToSortedArray<InputSlot *>(result->GetInputSlots().begin(),
118 result->GetInputSlots().end());
119 auto expectedInputs = ToSortedArray<InputSlot *>(expected->GetInputSlots().begin(),
120 expected->GetInputSlots().end());
121 CompareVectors(resultInputs, expectedInputs);
123 auto resultOutputs = ToSortedArray<OutputSlot *>(result->GetOutputSlots().begin(),
124 result->GetOutputSlots().end());
125 auto expectedOutputs = ToSortedArray<OutputSlot *>(expected->GetOutputSlots().begin(),
126 expected->GetOutputSlots().end());
127 CompareVectors(resultOutputs, expectedOutputs);
150 convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
188 convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
200 Graph substituteGraph;
239 convLayer2->GetOutputSlot(0).Connect(concatLayer->
GetInputSlot(1));
288 convLayer2->GetOutputSlot(0).Connect(concatLayer->
GetInputSlot(1));
339 convLayer2->GetOutputSlot(0).Connect(concatLayer->
GetInputSlot(1));
407 BOOST_CHECK(!AreAnySubgraphLayersPresentInGraph(subgraphLayers, graph));
421 BOOST_TEST(subgraph.
GetLayers().empty());
439 BOOST_TEST(subgraph.GetInputSlots().empty());
440 BOOST_TEST(subgraph.GetOutputSlots().empty());
441 BOOST_TEST(subgraph.GetLayers().size() == graph.
GetNumLayers());
454 BOOST_TEST(subgraphs.empty());
470 bool isOutput = l.
GetNameStr().compare(
"output") == 0;
474 BOOST_TEST(subgraphs.size() == 1);
475 if (subgraphs.size() == 1)
482 CompareSubgraphViews(subgraphs[0], expected);
509 BOOST_TEST(subgraphs.size() == 1);
510 if (subgraphs.size() == 1)
516 CompareSubgraphViews(subgraphs[0], expected);
545 BOOST_TEST(subgraphs.size() == 2);
546 if (subgraphs.size() == 2)
548 BOOST_TEST((subgraphs[0] !=
nullptr));
549 BOOST_TEST((subgraphs[1] !=
nullptr));
550 if (subgraphs[0].
get() !=
nullptr && subgraphs[1].
get() !=
nullptr)
552 if (std::find(subgraphs[0]->GetLayers().begin(), subgraphs[0]->GetLayers().end(), i0) !=
553 subgraphs[0]->GetLayers().end())
555 CompareSubgraphViews(subgraphs[0], expected1);
556 CompareSubgraphViews(subgraphs[1], expected2);
560 CompareSubgraphViews(subgraphs[0], expected2);
561 CompareSubgraphViews(subgraphs[1], expected1);
618 bool toSelect = std::string(l.
GetName())[0] ==
'm';
625 { m0, m1, m2, m3, m4 });
627 auto smallerSubgraph =
629 std::vector<OutputSlot*>{},
632 BOOST_TEST(subgraphs.size() == 2);
633 if (subgraphs.size() == 2)
636 BOOST_TEST((subgraphs[0] !=
nullptr));
637 BOOST_TEST((subgraphs[1] !=
nullptr));
639 if (subgraphs[0].
get() !=
nullptr && subgraphs[1].
get() !=
nullptr)
642 std::sort(subgraphs.begin(), subgraphs.end(),
645 return (lhs->GetLayers().size() < rhs->GetLayers().size());
649 BOOST_TEST(subgraphs[0]->GetLayers().size() == 2);
650 BOOST_TEST(subgraphs[1]->GetLayers().size() == 5);
652 CompareSubgraphViews(subgraphs[0], smallerSubgraph);
653 CompareSubgraphViews(subgraphs[1], largerSubgraph);
707 BOOST_TEST(subgraphs.size() == 2);
708 if (subgraphs.size() == 2)
711 BOOST_TEST((subgraphs[0] !=
nullptr));
712 BOOST_TEST((subgraphs[1] !=
nullptr));
714 if (subgraphs[0].
get() !=
nullptr && subgraphs[1].
get() !=
nullptr)
717 std::sort(subgraphs.begin(), subgraphs.end(),
720 return (lhs->GetLayers().size() < rhs->GetLayers().size());
724 BOOST_TEST(subgraphs[0]->GetLayers().size() == 1);
725 BOOST_TEST(subgraphs[1]->GetLayers().size() == 2);
727 CompareSubgraphViews(subgraphs[0], smallerSubgraph);
728 CompareSubgraphViews(subgraphs[1], largerSubgraph);
768 BOOST_CHECK(subgraphs.size() == 1);
769 if(subgraphs.size() == 1)
775 CompareSubgraphViews(subgraphs[0], expected);
823 BOOST_CHECK(subgraphs.size() == 1);
824 if (subgraphs.size() == 1)
828 {layerM1, layerM2, layerM3});
830 CompareSubgraphViews(subgraphs[0], expected);
863 layerM1->GetOutputSlot(0).Connect(layerM2->GetInputSlot(0));
864 layerM1->GetOutputSlot(1).Connect(layerM3->GetInputSlot(0));
865 layerM2->GetOutputSlot(0).Connect(layerX2->GetInputSlot(0));
866 layerM3->GetOutputSlot(0).Connect(layerX3->GetInputSlot(0));
879 BOOST_CHECK(subgraphs.size() == 1);
880 if(subgraphs.size() == 1)
884 {layerM1, layerM2, layerM3});
886 CompareSubgraphViews(subgraphs[0], expected);
943 BOOST_CHECK(subgraphs.size() == 1);
944 if (subgraphs.size() == 1)
948 {m1, m2, m3, m4, m5});
950 CompareSubgraphViews(subgraphs[0], expected);
989 return std::string(l.
GetName())[0] ==
'm';
993 auto expectedSubgraph0 =
1004 BOOST_TEST(subgraphs.size() == 2);
1005 if (subgraphs.size() == 2)
1008 BOOST_TEST((subgraphs[0] !=
nullptr));
1009 BOOST_TEST((subgraphs[1] !=
nullptr));
1011 if (subgraphs[0].
get() !=
nullptr && subgraphs[1].
get() !=
nullptr)
1013 if (subgraphs[0]->GetInputSlots().size() == 1)
1015 CompareSubgraphViews(subgraphs[0], expectedSubgraph0);
1016 CompareSubgraphViews(subgraphs[1], expectedSubgraph1);
1020 CompareSubgraphViews(subgraphs[0], expectedSubgraph1);
1021 CompareSubgraphViews(subgraphs[1], expectedSubgraph0);
1083 bool toSelect = std::string(l.
GetName())[0] ==
'm';
1090 { m0, m1, m2, m3, m4 });
1093 std::vector<OutputSlot*>{}, { m5, m6 });
1095 auto smallerSubgraph =
1098 BOOST_TEST(subgraphs.size() == 3);
1099 if (subgraphs.size() == 3)
1102 BOOST_TEST((subgraphs[0] !=
nullptr));
1103 BOOST_TEST((subgraphs[1] !=
nullptr));
1104 BOOST_TEST((subgraphs[2] !=
nullptr));
1106 if (subgraphs[0].
get() !=
nullptr && subgraphs[1].
get() !=
nullptr && subgraphs[2].
get() !=
nullptr)
1109 std::sort(subgraphs.begin(), subgraphs.end(),
1112 return (lhs->GetLayers().size() < rhs->GetLayers().size());
1116 CompareSubgraphViews(subgraphs[0], smallerSubgraph);
1117 CompareSubgraphViews(subgraphs[1], mediumSubgraph);
1118 CompareSubgraphViews(subgraphs[2], largerSubgraph);
1128 constexpr
bool debug =
false;
1130 std::mt19937 randomGenerator;
1133 auto GetRandom = [&randomGenerator](
auto maxExclusive) {
1137 std::uniform_real_distribution<float> uniform(0.0f, 1.0f);
1138 return static_cast<decltype(maxExclusive)
>(uniform(randomGenerator) *
static_cast<float>(maxExclusive));
1141 auto GetRandomFlag = [&randomGenerator](
float trueProb) {
1142 std::uniform_real_distribution<float> uniform(0.0f, 1.0f);
1143 return uniform(randomGenerator) < trueProb;
1146 constexpr uint32_t numTests = 100;
1147 for (uint32_t testIdx = 0; testIdx < numTests; ++testIdx)
1149 randomGenerator.seed(testIdx);
1157 uint32_t numInputs = 1 + GetRandom(4u);
1158 uint32_t numConstants = 1 + GetRandom(4u);
1159 uint32_t numOutputs = 1 + GetRandom(4u);
1160 uint32_t numConcats = 0 + GetRandom(500u);
1161 uint32_t numSplits = 0 + GetRandom(500u);
1162 float supportedProb = 0.7f;
1164 for (uint32_t i = 0; i < numInputs; ++i)
1166 std::string name =
"input" + std::to_string(i) + (GetRandomFlag(supportedProb) ?
"S" :
"N");
1169 for (uint32_t i = 0; i < numConstants; ++i)
1171 std::string name =
"constant" + std::to_string(i) + (GetRandomFlag(supportedProb) ?
"S" :
"N");
1174 for (uint32_t i = 0; i < numOutputs; ++i)
1176 std::string name =
"output" + std::to_string(i) + (GetRandomFlag(supportedProb) ?
"S" :
"N");
1179 for (uint32_t i = 0; i < numConcats; ++i)
1181 std::string name =
"concat" + std::to_string(i) + (GetRandomFlag(supportedProb) ?
"S" :
"N");
1182 uint32_t numInputs = 1 + GetRandom(3u);
1186 for (uint32_t i = 0; i < numSplits; ++i)
1188 std::string name =
"split" + std::to_string(i) + (GetRandomFlag(supportedProb) ?
"S" :
"N");
1189 uint32_t numOutputs = 1 + GetRandom(3u);
1199 uint32_t maxLayerDepth = 5 + GetRandom(2000u);
1200 std::map<Layer*, uint32_t> layerDepths;
1201 std::map<uint32_t, std::vector<Layer*>> layersAtDepth;
1202 for (
Layer* layer : graph)
1214 depth = 1 + GetRandom(maxLayerDepth);
1216 layerDepths[layer] = depth;
1217 layersAtDepth[depth].push_back(layer);
1222 for (
Layer* layer : graph)
1224 for (uint32_t inputSlotIdx = 0; inputSlotIdx < layer->GetNumInputSlots(); ++inputSlotIdx)
1226 InputSlot& inputSlot = layer->GetInputSlot(inputSlotIdx);
1227 uint32_t maxLayerDepthToConnectTo = layerDepths[layer];
1231 uint32_t layerDepth = GetRandom(maxLayerDepthToConnectTo);
1232 const std::vector<Layer*>& layersToChooseFrom = layersAtDepth[layerDepth];
1233 if (layersToChooseFrom.size() == 0)
1237 Layer* layerToConnectWith = layersToChooseFrom[GetRandom(layersToChooseFrom.size())];
1251 std::ofstream f(
"INPUT_" + std::to_string(testIdx) +
".dot");
1256 auto startTime = std::chrono::high_resolution_clock::now();
1260 [](
const Layer& l) {
return std::string(l.
GetName()).back() ==
'S'; });
1262 auto endTime = std::chrono::high_resolution_clock::now();
1263 auto duration = std::chrono::duration_cast<std::chrono::microseconds>(endTime - startTime);
1266 std::cout <<
"Test " << testIdx <<
": " << duration.count() <<
" microseconds" << std::endl;
1271 std::map<Layer*, SubgraphView*> layerToSubgraph;
1272 for (
Layer* layer : graph)
1275 for (std::unique_ptr<SubgraphView>& subgraph : subgraphs)
1277 std::string name = std::to_string(i++);
1278 if (std::find(subgraph->begin(), subgraph->end(), layer) != subgraph->end())
1280 layerToSubgraph[layer] = subgraph.get();
1290 for (
Layer* layer : graph)
1292 std::string name =
"NotAssigned";
1293 auto subgraphIt = layerToSubgraph.find(layer);
1294 if (subgraphIt != layerToSubgraph.end())
1296 auto subgraphIdx = std::distance(subgraphs.begin(),
1297 std::find_if(subgraphs.begin(), subgraphs.end(),
1298 [&](
auto& s) {
return s.get() == subgraphIt->second; }));
1299 name = std::to_string(subgraphIdx);
1304 std::ofstream f(
"GRAPH_" + std::to_string(testIdx) +
".dot");
1305 graph.SerializeToDot(f);
1311 for (std::unique_ptr<SubgraphView>& subgraph : subgraphs)
1313 for (
InputSlot* inputSlot : subgraph->GetInputSlots())
1315 std::queue<Layer*> toProcess;
1316 toProcess.push(&inputSlot->GetConnectedOutputSlot()->GetOwningLayer());
1317 while (toProcess.size() > 0)
1319 Layer* l = toProcess.front();
1322 BOOST_CHECK(layerToSubgraph[l] != subgraph.get());
1326 toProcess.push(&is.GetConnectedOutputSlot()->GetOwningLayer());
1366 [](
const Layer & l){
1371 BOOST_TEST(subgraphs.size() == 1);
1372 if(subgraphs.size() == 1)
1374 BOOST_TEST((subgraphs[0] !=
nullptr));
1376 if (subgraphs[0].
get() !=
nullptr)
1378 unsigned int numInputSlots =
armnn::numeric_cast<
unsigned int>(subgraphs[0]->GetInputSlots().size());
1379 unsigned int numOutputSlots =
armnn::numeric_cast<
unsigned int>(subgraphs[0]->GetOutputSlots().size());
1381 BOOST_TEST((numInputSlots == 1));
1382 BOOST_TEST((numOutputSlots == 1));
1431 convLayer2->GetOutputSlot(0).Connect(pConcatLayer->
GetInputSlot(1));
1439 [](
const Layer & l){
1444 BOOST_TEST(subgraphs.size() == 2);
1445 if(subgraphs.size() == 2)
1447 BOOST_TEST((subgraphs[0] !=
nullptr));
1448 BOOST_TEST((subgraphs[1] !=
nullptr));
1450 if (subgraphs[0].
get() !=
nullptr && subgraphs[1].
get() !=
nullptr)
1453 std::sort(subgraphs.begin(), subgraphs.end(),
1456 return (lhs->GetInputSlots().size() < rhs->GetInputSlots().size());
1460 unsigned int numInputSlots1 =
armnn::numeric_cast<
unsigned int>(subgraphs[0]->GetInputSlots().size());
1461 unsigned int numOutputSlots1 =
armnn::numeric_cast<
unsigned int>(subgraphs[0]->GetOutputSlots().size());
1463 unsigned int numInputSlots2 =
armnn::numeric_cast<
unsigned int>(subgraphs[1]->GetInputSlots().size());
1464 unsigned int numOutputSlots2 =
armnn::numeric_cast<
unsigned int>(subgraphs[1]->GetOutputSlots().size());
1545 bool toSelect = (l.
GetNameStr().find(
'm') != std::string::npos);
1558 BOOST_TEST(subgraphs.size() == 2);
1559 if (subgraphs.size() == 2)
1562 BOOST_TEST((subgraphs[0] !=
nullptr));
1563 BOOST_TEST((subgraphs[1] !=
nullptr));
1565 if (subgraphs[0].
get() !=
nullptr && subgraphs[1].
get() !=
nullptr)
1568 std::sort(subgraphs.begin(), subgraphs.end(),
1571 return (lhs->GetLayers().size() < rhs->GetLayers().size());
1576 BOOST_TEST(subgraphs[0]->GetLayers().size() == 1);
1577 BOOST_TEST(subgraphs[1]->GetLayers().size() == 2);
1579 CompareSubgraphViews(subgraphs[0], outputSubgraph);
1580 CompareSubgraphViews(subgraphs[1], inputSubgraph);
1599 {output, input, activation});
1604 view->ForEachLayer([&idx, &expectedSorted](
const Layer* l)
1606 BOOST_TEST((expectedSorted[idx] == l->
GetType()));
A layer that the constant data can be bound to.
BOOST_AUTO_TEST_SUITE(TensorflowLiteParser)
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.
Status SerializeToDot(std::ostream &stream)
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
This layer represents an activation operation with the specified activation function.
Copyright (c) 2021 ARM Limited and Contributors.
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.
int LayerBindingId
Type of identifiers for bindable layers (inputs, outputs).
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).
An output connection slot for a layer.
SubgraphView::InputSlots CreateInputsFrom(const std::vector< Layer *> &layers)
An OriginsDescriptor for the ConcatLayer.
This layer represents a merge operation.
const std::string & GetNameStr() const
LayerType GetType() const override
Returns the armnn::LayerType of this layer.
std::vector< SubgraphViewPtr > Subgraphs
GPU Execution: OpenCL: ArmCompute.
BOOST_AUTO_TEST_CASE(CheckConvolution2dLayer)
An ActivationDescriptor for the ActivationLayer.
const BackendId & GetBackendId() const
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.
const InputSlots & GetInputSlots() const
std::unique_ptr< SubgraphView > SubgraphViewPtr
BOOST_AUTO_TEST_SUITE_END()
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.
const OutputSlots & GetOutputSlots() const
CPU Execution: NEON: ArmCompute.
Iterator end()
Returns iterator pointing to the end of the list. Lowercase for range-based for loops.
const Layers & GetLayers() const
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.
const char * GetName() const override
Returns the name of the layer.
This layer represents a convolution 2d operation.
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...
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...