18 #include <boost/cast.hpp> 19 #include <boost/test/unit_test.hpp> 28 auto firstPos = std::find(order.begin(), order.end(), first);
29 auto secondPos = std::find(firstPos, order.end(), second);
31 return (secondPos != order.end());
91 std::vector<armnn::Layer*> order;
123 BOOST_TEST(
CheckOrder(graph, layerA, layerB));
124 BOOST_TEST(
CheckOrder(graph, layerA, layerC));
125 BOOST_TEST(
CheckOrder(graph, layerB, layerD));
126 BOOST_TEST(
CheckOrder(graph, layerC, layerD));
142 BOOST_TEST(
CheckOrder(graph, layerA, layerB));
143 BOOST_TEST(
CheckOrder(graph, layerA, layerC));
144 BOOST_TEST(
CheckOrder(graph, layerB, layerD));
145 BOOST_TEST(
CheckOrder(graph, layerC, layerE));
146 BOOST_TEST(
CheckOrder(graph, layerE, layerD));
164 BOOST_TEST(
CheckOrder(graph, layerA, layerB));
165 BOOST_TEST(
CheckOrder(graph, layerA, layerF));
166 BOOST_TEST(
CheckOrder(graph, layerF, layerC));
167 BOOST_TEST(
CheckOrder(graph, layerB, layerD));
168 BOOST_TEST(
CheckOrder(graph, layerC, layerE));
169 BOOST_TEST(
CheckOrder(graph, layerE, layerD));
177 std::vector<armnn::Layer*> order;
209 BOOST_TEST(
CheckOrder(graph, layerA, layerB));
210 BOOST_TEST(
CheckOrder(graph, layerA, layerC));
211 BOOST_TEST(
CheckOrder(graph, layerB, layerD));
212 BOOST_TEST(
CheckOrder(graph, layerC, layerD));
228 BOOST_TEST(
CheckOrder(graph, layerA, layerB));
229 BOOST_TEST(
CheckOrder(graph, layerA, layerC));
230 BOOST_TEST(
CheckOrder(graph, layerB, layerD));
231 BOOST_TEST(
CheckOrder(graph, layerC, layerE));
232 BOOST_TEST(
CheckOrder(graph, layerE, layerD));
251 BOOST_TEST(
CheckOrder(graph, layerA, layerF));
252 BOOST_TEST(
CheckOrder(graph, layerF, layerB));
253 BOOST_TEST(
CheckOrder(graph, layerF, layerC));
254 BOOST_TEST(
CheckOrder(graph, layerB, layerD));
255 BOOST_TEST(
CheckOrder(graph, layerC, layerE));
256 BOOST_TEST(
CheckOrder(graph, layerE, layerD));
261 using Edge = std::pair<const armnn::Layer*, const armnn::Layer*>;
264 static std::vector<Edge> GetEdgeList(
const armnn::Graph& graph)
266 std::vector<Edge> edges;
268 for (
auto&& srcLayer: graph)
270 const unsigned int numOutputSlots = srcLayer->GetNumOutputSlots();
271 for (
unsigned int s = 0; s < numOutputSlots; ++s)
275 for (
unsigned int c = 0; c < numConnections; ++c)
277 auto inputSlot = boost::polymorphic_downcast<const armnn::InputSlot*>(outputSlot.
GetConnection(c));
278 edges.emplace_back(srcLayer, &inputSlot->GetOwningLayer());
288 std::vector<Edge> origEdges = GetEdgeList(origGraph);
289 std::vector<Edge> newEdges = GetEdgeList(graph);
293 std::vector<Edge> sortedNewEdges = newEdges;
294 std::sort(sortedNewEdges.begin(), sortedNewEdges.end());
296 auto last = std::unique(sortedNewEdges.begin(), sortedNewEdges.end());
297 BOOST_CHECK_MESSAGE(last == sortedNewEdges.end(),
"New graph contains duplicate edges!");
301 while (!newEdges.empty())
303 const Edge edge = std::move(newEdges.back());
307 int originalEdge = -1;
308 for (
unsigned int i = 0; i < origEdges.size(); i++)
310 const Edge& origEdge = origEdges[i];
311 if (origEdge.first->GetNameStr() == edge.first->GetNameStr() &&
312 origEdge.second->GetNameStr() == edge.second->GetNameStr())
314 originalEdge = boost::numeric_cast<
int>(i);
318 if (originalEdge != -1)
323 BOOST_TEST(srcLayer);
324 BOOST_TEST(dstLayer);
327 if (srcLayer && dstLayer)
333 origEdges.erase(origEdges.begin() + originalEdge);
342 if (srcLayer ==
nullptr || dstLayer ==
nullptr)
344 BOOST_ERROR(
"At least one of the two ends of a new edge (" << edge.first <<
", " << edge.second <<
") " 345 "introduced after adding copy layers to a graph " 346 "correspond to a layer not known to the graph");
354 if (srcLayerInOrigGraph == dstLayerInOrigGraph)
356 BOOST_ERROR(
"A new edge (" 357 << edge.first->GetName()
359 << edge.second->GetName()
360 <<
") introduced after adding copy " 361 "layers to a graph is invalid. One of the ends should be present in the original " 362 "graph and the other should not, but " 363 << (srcLayerInOrigGraph ?
"both are" :
"none are"));
367 const armnn::Layer* copyLayer = srcLayerInOrigGraph ? dstLayer : srcLayer;
368 const armnn::Layer* nonCopyLayer = srcLayerInOrigGraph ? srcLayer : dstLayer;
371 std::vector<Edge> adjEdges;
372 auto it = newEdges.begin();
373 while (it != newEdges.end())
376 if (copyLayer == (srcLayerInOrigGraph ? newEdge.first : newEdge.second))
378 adjEdges.push_back(newEdge);
381 it = newEdges.erase(it);
389 if (adjEdges.empty())
391 BOOST_ERROR(
"An edge connecting a layer and a copy layer exists, (" << edge.first <<
", " <<
392 edge.second <<
"), but no other edges connecting the copy layer '" << copyLayer->
GetName()
393 <<
"' to other layers could be found");
398 for (
const Edge& adjEdge : adjEdges)
401 const armnn::Layer* adjLayer = srcLayerInOrigGraph ? adjEdge.second : adjEdge.first;
405 BOOST_ERROR(
"An edge (" << adjEdge.first <<
", " << adjEdge.second <<
") is adjacent to an edge " 406 "connecting a layer and a copy layer, (" << edge.first <<
", " << edge.second <<
"), " 407 "but the non-copy layer in the former does not correspond to a layer");
416 const armnn::Layer* origEdgeSrc = srcLayerInOrigGraph ? nonCopyLayer : adjLayer;
417 const armnn::Layer* origEdgeDst = srcLayerInOrigGraph ? adjLayer : nonCopyLayer;
419 auto origEdgeIter = origEdges.begin();
420 for (; origEdgeIter != origEdges.end(); origEdgeIter++)
422 if (origEdgeIter->first->GetNameStr() == origEdgeSrc->
GetNameStr() &&
423 origEdgeIter->second->GetNameStr() == origEdgeDst->
GetNameStr())
429 if (origEdgeIter != origEdges.end())
431 origEdges.erase(origEdgeIter);
435 BOOST_ERROR(
"An edge (" << adjEdge.first <<
", " << adjEdge.second <<
") is adjacent to an " 436 "edge connecting a layer and a copy layer, (" << edge.first <<
", " << edge.second <<
437 "), but there is no edge connecting the layers in the original graph");
444 BOOST_TEST(origEdges.empty(),
"Not all of the edges in the original graph correspond to paths in the new graph");
447 struct CopyLayersFixture
453 void InitialiseTestGraph()
455 using namespace armnn;
458 Layer*
const inputLayer = AddLayer<InputLayer>(0,
"input");
462 Layer*
const convLayer1 = AddLayer<Convolution2dLayer>(convolutionDefaults,
"conv1");
467 Layer*
const convLayer2 = AddLayer<Convolution2dLayer>(convolutionDefaults,
"conv2");
473 Layer*
const concatLayer = AddLayer<ConcatLayer>(concatDefaults,
"concat");
480 Layer*
const actLayer = AddLayer<ActivationLayer>(activationDefaults,
"act");
486 Layer*
const softmaxLayer = AddLayer<SoftmaxLayer>(softmaxDefaults,
"softmax");
491 Layer*
const outputLayer = AddLayer<OutputLayer>(0,
"output");
509 std::map<armnn::BackendId, std::unique_ptr<armnn::IBackendInternal>> m_Backends;
514 template <
typename LayerType,
typename... Args>
519 for (
auto slot = layer->BeginOutputSlots(); slot != layer->EndOutputSlots(); ++slot)
521 slot->SetTensorInfo(m_TensorDesc);
530 InitialiseTestGraph();
532 m_Graph.AddCompatibilityLayers(m_Backends, m_FactoryRegistry);
534 TestGraphAfterAddingCopyLayers(m_Graph, origGraph);
539 InitialiseTestGraph();
540 m_Graph.AddCompatibilityLayers(m_Backends, m_FactoryRegistry);
543 const std::vector<Edge> edges = GetEdgeList(m_Graph);
544 for (
int i = 0; i < 4; ++i)
546 m_Graph.AddCompatibilityLayers(m_Backends, m_FactoryRegistry);
547 const std::vector<Edge> otherEdges = GetEdgeList(m_Graph);
548 BOOST_TEST((edges == otherEdges));
581 std::vector<Edge> edges = GetEdgeList(graph);
583 std::sort(edges.begin(), edges.end());
584 auto last = std::unique(edges.begin(), edges.end());
585 BOOST_CHECK_MESSAGE(last == edges.end(),
"Found duplicated edges after AddCompatibilityLayers()");
const char * GetName() const override
Graph & TopologicalSort()
Sorts layers in topological order and return this.
void SetEdgeStrategy(unsigned int connectionIndex, EdgeStrategy strategy)
No strategy has been defined. Used internally to verify integrity of optimizations.
An ActivationDescriptor for the ActivationLayer.
virtual const IInputSlot * GetConnection(unsigned int index) const =0
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
Source backends tensor data can be exported to destination backend tensor without copy...
int Connect(InputSlot &destination)
const BackendId & GetBackendId() const
const std::string & GetNameStr() const
Iterator begin()
Returns iterator pointing to the beginning of the list. Lowercase for range-based for loops...
A ViewsDescriptor for the SplitterLayer. Descriptor to configure the splitting process. Number of Views must be equal to the number of outputs, and their order must match - e.g. first view corresponds to the first output, second view to the second output, etc.
bool GraphHasNamedLayer(const armnn::Graph &graph, const std::string &name)
void AddCompatibilityLayers(std::map< BackendId, std::unique_ptr< class IBackendInternal >> &backends, TensorHandleFactoryRegistry ®istry)
void SetBackendId(const BackendId &id)
This layer represents an activation operation with the specified activation function.
This layer represents a split operation.
bool CheckOrder(const armnn::Graph &graph, const armnn::Layer *first, const armnn::Layer *second)
Checks that first comes before second in the order.
void SetTensorInfo(const TensorInfo &tensorInfo) override
BOOST_CHECK(profilingService.GetCurrentState()==ProfilingState::WaitingForAck)
A layer user-provided data can be bound to (e.g. inputs, outputs).
GPU Execution: OpenCL: ArmCompute.
BOOST_AUTO_TEST_CASE(ClassGraph)
BOOST_FIXTURE_TEST_CASE(AddCopyLayers, CopyLayersFixture)
virtual unsigned int GetNumConnections() const =0
CPU Execution: Reference C++ kernels.
BOOST_AUTO_TEST_SUITE_END()
A SoftmaxDescriptor for the SoftmaxLayer.
An output connection slot for a layer. The output slot may be connected to 1 or more input slots of s...
CPU Execution: NEON: ArmCompute.
This layer represents an addition operation.
armnn::Layer * GetFirstLayerWithName(armnn::Graph &graph, const std::string &name)
BOOST_AUTO_TEST_SUITE(TensorflowLiteParser)
A Convolution2dDescriptor for the Convolution2dLayer.
LayerT * InsertNewLayer(InputSlot &insertBefore, Args &&... args)
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
An OriginsDescriptor for the ConcatLayer. Descriptor to configure the concatenation process...
const InputSlot & GetInputSlot(unsigned int index) const override