ArmNN
 21.05
SubgraphViewSelector Class Referencefinal

Algorithm that splits a Graph into Subgraphs based on a filtering of layers (e.g. More...

#include <SubgraphViewSelector.hpp>

Public Types

using SubgraphViewPtr = std::unique_ptr< SubgraphView >
 
using Subgraphs = std::vector< SubgraphViewPtr >
 
using LayerSelectorFunction = std::function< bool(const Layer &)>
 

Static Public Member Functions

static Subgraphs SelectSubgraphs (Graph &graph, const LayerSelectorFunction &selector)
 Selects subgraphs from a graph based on the selector function and the algorithm. More...
 
static Subgraphs SelectSubgraphs (SubgraphView &subgraph, const LayerSelectorFunction &selector)
 

Detailed Description

Algorithm that splits a Graph into Subgraphs based on a filtering of layers (e.g.

which layers are appropriate for a certain backend). The resulting subgraphs are guaranteed to be form a DAG (i.e. there are no dependency loops).

The algorithm aims to produce as few subgraphs as possible.

Definition at line 21 of file SubgraphViewSelector.hpp.

Member Typedef Documentation

◆ LayerSelectorFunction

using LayerSelectorFunction = std::function<bool(const Layer&)>

Definition at line 26 of file SubgraphViewSelector.hpp.

◆ Subgraphs

using Subgraphs = std::vector<SubgraphViewPtr>

Definition at line 25 of file SubgraphViewSelector.hpp.

◆ SubgraphViewPtr

using SubgraphViewPtr = std::unique_ptr<SubgraphView>

Definition at line 24 of file SubgraphViewSelector.hpp.

Member Function Documentation

◆ SelectSubgraphs() [1/2]

SubgraphViewSelector::Subgraphs SelectSubgraphs ( Graph graph,
const LayerSelectorFunction selector 
)
static

Selects subgraphs from a graph based on the selector function and the algorithm.

Since the Subgraphs object returns modifiable pointers to the input and output slots of the graph: 1) the graph/sub-graph cannot be const 2) the caller needs to make sure that the Subgraphs lifetime is shorter than the parent graph's

Definition at line 255 of file SubgraphViewSelector.cpp.

Referenced by armnn::ApplyBackendOptimizations(), BOOST_AUTO_TEST_CASE(), and MockBackend::OptimizeSubgraphView().

256 {
257  SubgraphView subgraph(graph);
258  return SubgraphViewSelector::SelectSubgraphs(subgraph, selector);
259 }
static Subgraphs SelectSubgraphs(Graph &graph, const LayerSelectorFunction &selector)
Selects subgraphs from a graph based on the selector function and the algorithm.

◆ SelectSubgraphs() [2/2]

SubgraphViewSelector::Subgraphs SelectSubgraphs ( SubgraphView subgraph,
const LayerSelectorFunction selector 
)
static

Definition at line 385 of file SubgraphViewSelector.cpp.

References armnn::AssignSplitId(), OutputSlot::CalculateIndexOnOwner(), armnn::ForEachLayerOutput(), Layer::GetGuid(), InputSlot::GetOwningLayer(), OutputSlot::GetOwningLayer(), InputSlot::GetSlotIndex(), armnn::info, and armnn::IsReadyForSplitAssignment().

386 {
387  LayerSelectionInfo::LayerInfoContainer layerInfos;
388 
389  LayerSelectionInfo::LayerInfoQueue processQueue;
390  for (auto& layer : subgraph)
391  {
392  auto emplaced = layerInfos.emplace(layer, LayerSelectionInfo{layer, selector});
393  LayerSelectionInfo& layerInfo = emplaced.first->second;
394 
395  // Start with Input type layers
396  if (layerInfo.IsInputLayer())
397  {
398  processQueue.push(&layerInfo);
399  }
400  }
401 
402  const SubgraphView::InputSlots& subgraphInputSlots = subgraph.GetInputSlots();
403  for (auto& inputSlot : subgraphInputSlots)
404  {
405  Layer& layer = inputSlot->GetOwningLayer();
406  auto emplaced = layerInfos.emplace(&layer, LayerSelectionInfo{&layer, selector});
407  LayerSelectionInfo& layerInfo = emplaced.first->second;
408 
409  processQueue.push(&layerInfo);
410  }
411 
412  while (!processQueue.empty())
413  {
414  LayerSelectionInfo& layerInfo = *processQueue.front();
415  processQueue.pop(); // remove front from queue
416 
417  // This layerInfo may have been added to the queue multiple times, so skip if we have already processed it
418  if (!layerInfo.m_IsProcessed)
419  {
420  // Only process this layerInfo if all inputs have been processed
421  if (!IsReadyForSplitAssignment(layerInfos, layerInfo))
422  {
423  // Put back of the process queue if we can't process it just yet
424  processQueue.push(&layerInfo);
425  continue; // Skip to next iteration
426  }
427 
428  // Now we do the processing
429  AssignSplitId(layerInfos, layerInfo);
430 
431  // Queue any child nodes for processing
432  ForEachLayerOutput(layerInfos, layerInfo, [&processQueue](LayerSelectionInfo& childInfo)
433  {
434  processQueue.push(&childInfo);
435  });
436 
437  // We don't need to process this node again
438  layerInfo.m_IsProcessed = true;
439  }
440  }
441 
442  // Collect all selected layers keyed by subgraph representative into a map
443  using SelectionInfoPtrs = std::vector<LayerSelectionInfo*>;
444  std::map<PartialSubgraph*, SelectionInfoPtrs> splitMap;
445  for (auto& info : layerInfos)
446  {
447  if (info.second.m_IsSelected)
448  {
449  auto it = splitMap.find(info.second.m_Subgraph->GetRepresentative());
450  if (it == splitMap.end())
451  {
452  splitMap.insert(
453  std::make_pair(info.second.m_Subgraph->GetRepresentative(), SelectionInfoPtrs{&info.second}));
454  }
455  else
456  {
457  it->second.push_back(&info.second);
458  }
459  }
460  }
461 
462  // Now each entry in splitMap represents a subgraph
463  Subgraphs result;
464  for (auto& splitGraph : splitMap)
465  {
468  SubgraphView::Layers layers;
469  for (auto&& infoPtr : splitGraph.second)
470  {
471  infoPtr->CollectNonSelectedInputs(layerInfos, inputs);
472  infoPtr->CollectNonSelectedOutputSlots(layerInfos, outputs);
473  layers.push_back(infoPtr->m_Layer);
474  }
475 
476  // Sort lists into deterministic order, not relying on pointer values which may be different on each execution.
477  // This makes debugging the optimised graph much easier as subsequent stages can also be deterministic.
478  std::sort(inputs.begin(), inputs.end(), [](const InputSlot* a, const InputSlot* b)
479  {
480  const LayerGuid guidA = a->GetOwningLayer().GetGuid();
481  const LayerGuid guidB = b->GetOwningLayer().GetGuid();
482  if (guidA < guidB)
483  {
484  return true;
485  }
486  else if (guidA == guidB)
487  {
488  return (a->GetSlotIndex() < b->GetSlotIndex());
489  }
490  return false;
491  });
492  std::sort(outputs.begin(), outputs.end(), [](const OutputSlot* a, const OutputSlot* b)
493  {
494  const LayerGuid guidA = a->GetOwningLayer().GetGuid();
495  const LayerGuid guidB = b->GetOwningLayer().GetGuid();
496  if (guidA < guidB)
497  {
498  return true;
499  }
500  else if (guidA == guidB)
501  {
502  return (a->CalculateIndexOnOwner() < b->CalculateIndexOnOwner());
503  }
504  return false;
505  });
506  layers.sort([](const Layer* a, const Layer* b) { return a->GetGuid() < b->GetGuid(); });
507 
508  // Create a new sub-graph with the new lists of input/output slots and layer
509  result.emplace_back(std::make_unique<SubgraphView>(std::move(inputs),
510  std::move(outputs),
511  std::move(layers)));
512  }
513 
514  return result;
515 }
void AssignSplitId(LayerSelectionInfo::LayerInfoContainer &layerInfos, LayerSelectionInfo &layerInfo)
std::vector< OutputSlot * > OutputSlots
bool IsReadyForSplitAssignment(LayerSelectionInfo::LayerInfoContainer &layerInfos, LayerSelectionInfo &layerInfo)
std::vector< SubgraphViewPtr > Subgraphs
std::vector< InputSlot * > InputSlots
profiling::ProfilingGuid LayerGuid
Define LayerGuid type.
Definition: Types.hpp:308
std::list< Layer * > Layers
void ForEachLayerOutput(LayerSelectionInfo::LayerInfoContainer &layerInfos, LayerSelectionInfo &layerInfo, Delegate function)

The documentation for this class was generated from the following files: