ArmNN
 21.02
Graph.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "Graph.hpp"
7 #include "SubgraphView.hpp"
8 #include "LayersFwd.hpp"
9 
11 
12 #include <armnn/BackendId.hpp>
13 #include <armnn/Logging.hpp>
14 #include <armnn/TypesUtils.hpp>
15 #include <armnn/Utils.hpp>
16 #include <armnn/utility/Assert.hpp>
18 
19 #include <fmt/format.h>
20 
21 #include <unordered_map>
22 #include <DotSerializer.hpp>
23 #include <sstream>
24 
25 namespace armnn
26 {
27 
28 Graph::Graph(const Graph& other)
29 : m_LayersInOrder(other.m_LayersInOrder)
30 {
31  std::unordered_map<const Layer*, Layer*> otherToClonedMap;
32 
33  for (auto&& otherLayer : other.m_Layers)
34  {
35  Layer* const layer = otherLayer->Clone(*this);
36  otherToClonedMap.emplace(otherLayer, layer);
37  }
38 
39  // Copies slot connections.
40  for (auto&& otherLayer : other.m_Layers)
41  {
42  Layer* const thisLayer = otherToClonedMap[otherLayer];
43 
44  auto outputSlot = thisLayer->BeginOutputSlots();
45  for (auto&& otherOutputSlot : otherLayer->GetOutputSlots())
46  {
47  for (auto&& otherInputSlot : otherOutputSlot.GetConnections())
48  {
49  const Layer& otherTgtLayer = otherInputSlot->GetOwningLayer();
50  Layer* const thisTgtLayer = otherToClonedMap[&otherTgtLayer];
51 
52  InputSlot& inputSlot = thisTgtLayer->GetInputSlot(otherInputSlot->GetSlotIndex());
53  outputSlot->Connect(inputSlot);
54  }
55  outputSlot->SetTensorInfo(otherOutputSlot.GetTensorInfo());
56  ++outputSlot;
57  }
58  }
59 }
60 
62 {
63  if (m_Layers.empty())
64  {
65  ARMNN_LOG(info) << "\n Graph is empty.\n";
66  return Status::Success;
67  }
68  ARMNN_LOG(info) << "\n";
69  ARMNN_LOG(info) << "Walking Pattern: \n";
70 
71  for (auto&& it : TopologicalSort())
72  {
73  auto numInputSlots = it->GetNumInputSlots();
74  auto numOutputSlots = it->GetNumOutputSlots();
75 
76  ARMNN_LOG(info) << it->GetName() << ":" << GetLayerTypeAsCString(it->GetType())
77  << ":" << it->GetBackendId().Get()
78  << " has " << numInputSlots << " input slots"
79  << " and " << numOutputSlots << " output slots.";
80 
81  for (auto i : it->GetInputSlots())
82  {
83  std::ostringstream message;
84  auto inputTensorShape = i.GetConnectedOutputSlot()->GetTensorInfo().GetShape();
85  unsigned int numDims = inputTensorShape.GetNumDimensions();
86 
87  message << "The input slot has shape [ ";
88  for (unsigned int dim=0; dim < numDims; dim++)
89  {
90  message << inputTensorShape[dim] << ",";
91  }
92  message << " ]";
93  ARMNN_LOG(info) << message.str();
94  }
95 
96  for (unsigned int i = 0; i < it->GetNumOutputSlots(); i++)
97  {
98  const armnn::Layer *layer = it;
99  std::ostringstream message;
100  auto outputTensorShape = layer->GetOutputSlots()[i].GetTensorInfo().GetShape();
101  unsigned int numDims = outputTensorShape.GetNumDimensions();
102 
103  message << "The output slot has shape [ ";
104  for (unsigned int dim=0; dim < numDims; dim++)
105  {
106  message << outputTensorShape[dim] << ",";
107  }
108  message << " ]";
109  ARMNN_LOG(info) << message.str();
110  }
111  ARMNN_LOG(info) << "\n";
112  }
113  ARMNN_LOG(info) << "\n\n";
114 
115  return Status::Success;
116 }
117 
118 Status Graph::SerializeToDot(std::ostream& stream)
119 {
120  {
121  DotGraph graph(stream, "Optimized");
122 
123  {
124  // Default node attributes:
125  DotDefaults nodes(stream, "node");
126  nodes.GetAttributeSet()
127  .AddAttribute("shape", "record");
128  }
129 
130  {
131  // Default edge attributes:
132  DotDefaults edges(stream, "edge");
133  edges.GetAttributeSet()
134  .AddAttribute("fontsize", 8)
135  .AddAttribute("fontcolor", "blue")
136  .AddAttribute("fontname", "arial-bold");
137  }
138 
139  // First declares the nodes.
140  for (auto&& layer : m_Layers)
141  {
142  DotNode node(stream, layer->GetGuid(), GetLayerTypeAsCString(layer->GetType()));
143  // Extracts the layer parameters.
144  ParameterStringifyFunction extractParams = [&node](const std::string & name, const std::string & value){
145  node.GetContents().AddContent(name + " : " + value);
146  };
147  layer->SerializeLayerParameters(extractParams);
148  }
149 
150  // Second declares the edges.
151  for (auto&& layer : m_Layers)
152  {
153  LayerGuid toId = layer->GetGuid();
154 
155  for (unsigned int i=0;i<layer->GetNumInputSlots(); i++)
156  {
157  OutputSlot* outputSlot = static_cast<OutputSlot*>(layer->GetInputSlot(i).GetConnection());
158  LayerGuid fromId = outputSlot->GetOwningLayer().GetGuid();
159  DotEdge edge(stream, fromId, toId);
160 
161  // Now print the tensor shape on the edge.
162  {
163  // Constructs the label attribute with HTML markup.
164  std::stringstream ss;
165  ss << "< " << outputSlot->GetTensorInfo().GetShape() << " >";
166  edge.GetAttributeSet().AddAttribute("label", ss);
167  }
168  }
169  }
170  }
171 
172  if (stream.bad())
173  {
174  return Status::Failure;
175  }
176  return Status::Success;
177 }
178 
180 {
181  // Layers must be sorted in topological order
182  ARMNN_ASSERT(m_LayersInOrder);
183 
184  std::unordered_set<const ITensorHandle*> preallocatedTensors;
185  std::unordered_map<const ITensorHandle*, unsigned int> handleReferenceCounts;
186 
187  // Finds the first TensorHandle ancestor of a SubTensorHandle. If the ITensorHandle provided
188  // is a TensorHandle, the function just returns it
189  auto TraceSubTensorHandleAncestry = [](ITensorHandle* const subTensorHandle)
190  {
191  ITensorHandle* ancestor = subTensorHandle;
192  while (ancestor && ancestor->GetParent())
193  {
194  ancestor = ancestor->GetParent();
195  }
196  return ancestor;
197  };
198 
199  // Checks whether a TensorHandle has been pre-allocated
200  auto IsPreallocated = [&](ITensorHandle* const tensorHandle)
201  {
202  return tensorHandle && preallocatedTensors.find(tensorHandle) != preallocatedTensors.end();
203  };
204 
205  // Constant tensor handles need to last from the beginning of execution till the end,
206  // therefore we pre-allocate them upfront
207  for (auto&& layer : m_Layers)
208  {
209  if (layer->GetType() == LayerType::Constant)
210  {
211  for (auto&& slot = layer->BeginOutputSlots(); slot != layer->EndOutputSlots(); ++slot)
212  {
213  ITensorHandle *tensorHandle = TraceSubTensorHandleAncestry(slot->GetOutputHandler().GetData());
214 
215  if (tensorHandle && !IsPreallocated(tensorHandle))
216  {
217  tensorHandle->Allocate();
218  preallocatedTensors.insert(tensorHandle);
219  }
220  }
221  }
222  }
223 
224  // Iterate over the network in topological order
225  for (auto&& layer : m_Layers)
226  {
227  // Count the amount of times each output slot references a certain buffer (ITensorHandle).
228  // The first time we encounter a new tensor handle, we start managing its lifetime.
229  for (auto&& slot = layer->BeginOutputSlots(); slot != layer->EndOutputSlots(); ++slot)
230  {
231  ITensorHandle *tensorHandle = TraceSubTensorHandleAncestry(slot->GetOutputHandler().GetData());
232 
233  if (tensorHandle && !IsPreallocated(tensorHandle))
234  {
235  unsigned int numConnections = slot->GetNumConnections();
236  if (handleReferenceCounts.find(tensorHandle) == handleReferenceCounts.end())
237  {
238  handleReferenceCounts[tensorHandle] = numConnections;
239  tensorHandle->Manage();
240  if (handleReferenceCounts[tensorHandle] == 0u)
241  {
242  // if nobody consumes this tensor we call Allocate()
243  tensorHandle->Allocate();
244  }
245  }
246  else
247  {
248  handleReferenceCounts[tensorHandle] += numConnections;
249  }
250  }
251  }
252 
253  // Loop through the input slots in the same layer and decrement the reference counter associated
254  // to each tensor handle we encounter. Once it reaches zero, we end the lifetime of the tensor handle
255  for (auto&& slot = layer->BeginInputSlots(); slot != layer->EndInputSlots(); ++slot)
256  {
257  ITensorHandle *tensorHandle = TraceSubTensorHandleAncestry(
258  slot->GetConnectedOutputSlot()->GetOutputHandler().GetData());
259 
260  if (tensorHandle && !IsPreallocated(tensorHandle))
261  {
262  --handleReferenceCounts[tensorHandle];
263 
264  if (handleReferenceCounts[tensorHandle] == 0u)
265  {
266  // Stop managing lifetime of tensor handle
267  tensorHandle->Allocate();
268  handleReferenceCounts.erase(tensorHandle);
269  }
270  }
271  }
272  }
273 
274  return Status::Success;
275 }
276 
278 {
279  if (!m_LayersInOrder)
280  {
281  // Resets layer order.
282  for (auto&& it : m_Layers)
283  {
284  it->ResetPriority();
285  }
286 
287  auto compareLayerPriority = [](const LayerList::value_type& layerA, const LayerList::value_type& layerB)
288  {
289  return layerA->GetPriority() < layerB->GetPriority();
290  };
291 
292  m_Layers.sort(compareLayerPriority);
293 
294  m_LayersInOrder = true;
295  }
296 
297  return *this;
298 }
299 
300 void Graph::AddCompatibilityLayers(std::map<BackendId, std::unique_ptr<IBackendInternal>>& backends,
301  TensorHandleFactoryRegistry& registry)
302 {
303  // Returns true if the given layer could potentially need an intermediate copy/import layer (depending on its
304  // connections to other layers).
305  auto MayNeedCompatibilityLayer = [](const Layer& layer)
306  {
307  // All layers should have been associated with a valid compute device at this point.
308  ARMNN_ASSERT(layer.GetBackendId() != Compute::Undefined);
309  // Does not need another compatibility layer if a copy or import layer is already present.
310  return layer.GetType() != LayerType::MemCopy &&
311  layer.GetType() != LayerType::MemImport;
312  };
313 
314  auto IsCompatibilityStrategy = [](EdgeStrategy strategy)
315  {
316  return strategy == EdgeStrategy::CopyToTarget ||
317  strategy == EdgeStrategy::ExportToTarget;
318  };
319 
320  ForEachLayer([this, &backends, &registry, MayNeedCompatibilityLayer, IsCompatibilityStrategy](Layer* srcLayer)
321  {
322  ARMNN_ASSERT(srcLayer);
323 
324  if (!MayNeedCompatibilityLayer(*srcLayer))
325  {
326  // The current layer does not need copy layers, move to the next one
327  return;
328  }
329 
330  const std::vector<OutputSlot>& srcOutputSlots = srcLayer->GetOutputSlots();
331  for (unsigned int srcOutputIndex = 0; srcOutputIndex < srcOutputSlots.size(); srcOutputIndex++)
332  {
333  OutputSlot& srcOutputSlot = srcLayer->GetOutputSlot(srcOutputIndex);
334  const std::vector<InputSlot*> srcConnections = srcOutputSlot.GetConnections();
335  const std::vector<EdgeStrategy> srcEdgeStrategies = srcOutputSlot.GetEdgeStrategies();
336  for (unsigned int srcConnectionIndex = 0; srcConnectionIndex < srcConnections.size(); srcConnectionIndex++)
337  {
338  InputSlot* dstInputSlot = srcConnections[srcConnectionIndex];
339  ARMNN_ASSERT(dstInputSlot);
340 
341  EdgeStrategy strategy = srcEdgeStrategies[srcConnectionIndex];
343  "Undefined memory strategy found while adding copy layers for compatibility");
344 
345  const Layer& dstLayer = dstInputSlot->GetOwningLayer();
346  if (MayNeedCompatibilityLayer(dstLayer) &&
347  IsCompatibilityStrategy(strategy))
348  {
349  // A copy layer is needed in between the source and destination layers.
350  // Record the operation rather than attempting to modify the graph as we go.
351  // (invalidating iterators)
352  const std::string compLayerName = fmt::format("[ {} ({}) -> {} ({}) ]",
353  srcLayer->GetName(),
354  srcOutputIndex,
355  dstLayer.GetName(),
356  dstInputSlot->GetSlotIndex());
357  Layer* compLayer = nullptr;
358  if (strategy == EdgeStrategy::CopyToTarget)
359  {
360  compLayer = InsertNewLayer<MemCopyLayer>(*dstInputSlot, compLayerName.c_str());
361  }
362  else
363  {
364  ARMNN_ASSERT_MSG(strategy == EdgeStrategy::ExportToTarget, "Invalid edge strategy found.");
365  compLayer = InsertNewLayer<MemImportLayer>(*dstInputSlot, compLayerName.c_str());
366  }
367 
368  compLayer->SetBackendId(dstLayer.GetBackendId());
369 
370  OutputSlot& compOutputSlot = compLayer->GetOutputSlot(0);
371  auto backendIt = backends.find(dstLayer.GetBackendId());
372  if (backendIt != backends.end() &&
373  backendIt->second &&
374  backendIt->second->SupportsTensorAllocatorAPI())
375  {
376  auto backend = backendIt->second.get();
377  auto tensorHandleFactoryIds = backend->GetHandleFactoryPreferences();
378  bool found = false;
379 
380  for (auto preference : tensorHandleFactoryIds)
381  {
382  auto factory = registry.GetFactory(preference);
383  if (factory)
384  {
385  auto srcPref = srcOutputSlot.GetTensorHandleFactoryId();
386  auto srcFactory = registry.GetFactory(srcPref);
387 
388  if (srcFactory)
389  {
390  bool canExportImport =
391  (factory->GetImportFlags() & srcFactory->GetExportFlags()) != 0;
392 
393  if (factory->SupportsMapUnmap() || canExportImport)
394  {
395  compOutputSlot.SetTensorHandleFactory(preference);
396  found = true;
397  break;
398  }
399  }
400  }
401  }
402 
403  if (!found)
404  {
406  }
407  }
408  else
409  {
411  }
412 
413  // The output strategy of a compatibility layer is always DirectCompatibility.
415 
416  // Recalculate the connection index on the previous layer as we have just inserted into it.
417  const std::vector<InputSlot*>& newSourceConnections = srcOutputSlot.GetConnections();
418  auto newSrcConnectionIndex = std::distance(newSourceConnections.begin(),
419  std::find(newSourceConnections.begin(),
420  newSourceConnections.end(),
421  &compLayer->GetInputSlot(0)));
422 
423  // The input strategy of a compatibility layer is always DirectCompatibilty.
424  srcOutputSlot.SetEdgeStrategy(armnn::numeric_cast<unsigned int>(newSrcConnectionIndex),
426  }
427  }
428  }
429  });
430 }
431 
433 {
434  ARMNN_ASSERT(substituteLayer != nullptr);
435 
436  ReplaceSubgraphConnections(subgraph, substituteLayer);
437  EraseSubgraphLayers(subgraph);
438 }
439 
440 void Graph::SubstituteSubgraph(SubgraphView& subgraph, const SubgraphView& substituteSubgraph)
441 {
442  // Look through each layer in the new subgraph and add any that are not already a member of this graph
443  substituteSubgraph.ForEachLayer([this](Layer* layer)
444  {
445  if (std::find(std::begin(m_Layers), std::end(m_Layers), layer) == std::end(m_Layers))
446  {
447  layer->Reparent(*this, m_Layers.end());
448  m_LayersInOrder = false;
449  }
450  });
451 
452  ReplaceSubgraphConnections(subgraph, substituteSubgraph);
453  EraseSubgraphLayers(subgraph);
454  TopologicalSort();
455 }
456 
457 void Graph::ReplaceSubgraphConnections(const SubgraphView& subgraph, IConnectableLayer* substituteLayer)
458 {
459  ARMNN_ASSERT(substituteLayer != nullptr);
460 
461  // Create a new sub-graph with only the given layer, using
462  // the given sub-graph as a reference of which parent graph to use
463  SubgraphView substituteSubgraph(substituteLayer);
464  ReplaceSubgraphConnections(subgraph, substituteSubgraph);
465 }
466 
467 void Graph::ReplaceSubgraphConnections(const SubgraphView& subgraph, const SubgraphView& substituteSubgraph)
468 {
469  ARMNN_ASSERT_MSG(!substituteSubgraph.GetLayers().empty(), "New sub-graph used for substitution must not be empty");
470 
471  const SubgraphView::Layers& substituteSubgraphLayers = substituteSubgraph.GetLayers();
472  std::for_each(substituteSubgraphLayers.begin(), substituteSubgraphLayers.end(), [&](Layer* layer)
473  {
474  IgnoreUnused(layer);
475  ARMNN_ASSERT_MSG(std::find(m_Layers.begin(), m_Layers.end(), layer) != m_Layers.end(),
476  "Substitute layer is not a member of graph");
477  });
478 
479  const SubgraphView::InputSlots& subgraphInputSlots = subgraph.GetInputSlots();
480  const SubgraphView::OutputSlots& subgraphOutputSlots = subgraph.GetOutputSlots();
481 
482  unsigned int subgraphNumInputSlots = armnn::numeric_cast<unsigned int>(subgraphInputSlots.size());
483  unsigned int subgraphNumOutputSlots = armnn::numeric_cast<unsigned int>(subgraphOutputSlots.size());
484 
485  const SubgraphView::InputSlots& substituteSubgraphInputSlots = substituteSubgraph.GetInputSlots();
486  const SubgraphView::OutputSlots& substituteSubgraphOutputSlots = substituteSubgraph.GetOutputSlots();
487 
488  ARMNN_ASSERT(subgraphNumInputSlots == substituteSubgraphInputSlots.size());
489  ARMNN_ASSERT(subgraphNumOutputSlots == substituteSubgraphOutputSlots.size());
490 
491  // Disconnect the sub-graph and replace it with the substitute sub-graph
492 
493  // Step 1: process input slots
494  for (unsigned int inputSlotIdx = 0; inputSlotIdx < subgraphNumInputSlots; ++inputSlotIdx)
495  {
496  InputSlot* subgraphInputSlot = subgraphInputSlots.at(inputSlotIdx);
497  ARMNN_ASSERT(subgraphInputSlot);
498 
499  IOutputSlot* connectedOutputSlot = subgraphInputSlot->GetConnection();
500  ARMNN_ASSERT(connectedOutputSlot);
501  connectedOutputSlot->Disconnect(*subgraphInputSlot);
502 
503  IInputSlot* substituteInputSlot = substituteSubgraphInputSlots.at(inputSlotIdx);
504  ARMNN_ASSERT(substituteInputSlot);
505  connectedOutputSlot->Connect(*substituteInputSlot);
506  }
507 
508  // Step 2: process output slots
509  for(unsigned int outputSlotIdx = 0; outputSlotIdx < subgraphNumOutputSlots; ++outputSlotIdx)
510  {
511  OutputSlot* subgraphOutputSlot = subgraphOutputSlots.at(outputSlotIdx);
512  ARMNN_ASSERT(subgraphOutputSlot);
513 
514  OutputSlot* substituteOutputSlot = substituteSubgraphOutputSlots.at(outputSlotIdx);
515  ARMNN_ASSERT(substituteOutputSlot);
516  subgraphOutputSlot->MoveAllConnections(*substituteOutputSlot);
517  }
518 }
519 
520 void Graph::EraseSubgraphLayers(SubgraphView &subgraph)
521 {
522  for (auto layer : subgraph.GetLayers())
523  {
524  EraseLayer(layer);
525  }
526  subgraph.Clear();
527 }
528 
530 {
531  for (auto&& layer : TopologicalSort())
532  {
533  for (auto&& input : layer->GetInputSlots())
534  {
535  const IOutputSlot* source = input.GetConnectedOutputSlot();
536  if (source == NULL)
537  {
538  std::ostringstream message;
539  message << "Input not connected on "
540  << GetLayerTypeAsCString(layer->GetType())
541  << " layer \""
542  << layer->GetName()
543  << "\"";
544  throw LayerValidationException(message.str());
545  }
546 
547  if (!source->IsTensorInfoSet())
548  {
549  throw LayerValidationException("All inputs must have the TensorInfo set at this point.");
550  }
551 
552  if (layer->m_ShapeInferenceMethod == ShapeInferenceMethod::ValidateOnly)
553  {
554  layer->ValidateTensorShapesFromInputs();
555  }
556  }
557  }
558 }
559 
560 } // namespace armnn
Graph(bool shapeInferenceMethod=false)
Definition: Graph.hpp:95
const std::vector< InputSlot * > & GetConnections() const
Definition: Layer.hpp:125
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
Definition: INetwork.hpp:62
NodeContent & AddContent(const std::string &content)
void SetEdgeStrategy(unsigned int connectionIndex, EdgeStrategy strategy)
Definition: Layer.cpp:181
No strategy has been defined. Used internally to verify integrity of optimizations.
const TensorShape & GetShape() const
Definition: Tensor.hpp:187
Status SerializeToDot(std::ostream &stream)
Definition: Graph.cpp:118
const std::vector< EdgeStrategy > & GetEdgeStrategies() const
Definition: Layer.hpp:126
virtual void Reparent(Graph &dest, std::list< Layer *>::const_iterator iterator)=0
Layer & GetOwningLayer() const
Definition: Layer.hpp:115
Source backends tensor data can be exported to destination backend tensor without copy...
void EraseLayer(Iterator pos)
Deletes the layer at the specified position.
Definition: Graph.hpp:449
std::vector< OutputSlot * > OutputSlots
DotAttributeSet & GetAttributeSet()
virtual void Allocate()=0
Indicate to the memory manager that this resource is no longer active.
virtual Layer * Clone(Graph &graph) const =0
Creates a dynamically-allocated copy of this layer.
#define ARMNN_LOG(severity)
Definition: Logging.hpp:202
virtual void Manage()=0
Indicate to the memory manager that this resource is active.
Copyright (c) 2021 ARM Limited and Contributors.
void IgnoreUnused(Ts &&...)
const IOutputSlot * GetConnection() const override
Definition: Layer.hpp:199
Destination backend can work directly with tensors on source backend.
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.
Definition: Layer.hpp:316
void ForEachLayer(Func func) const
Definition: Graph.hpp:39
#define ARMNN_ASSERT_MSG(COND, MSG)
Definition: Assert.hpp:15
DotAttributeSet & AddAttribute(const std::string &name, const std::stringstream &value)
NodeContent & GetContents()
An output connection slot for a layer.
Definition: INetwork.hpp:38
unsigned int GetSlotIndex() const
Definition: Layer.hpp:53
virtual void Disconnect(IInputSlot &slot)=0
virtual ITensorHandle * GetParent() const =0
Get the parent tensor if this is a subtensor.
Validate all output shapes.
Status
enumeration
Definition: Types.hpp:26
#define ARMNN_ASSERT(COND)
Definition: Assert.hpp:14
Layer & GetOwningLayer() const
Definition: Layer.hpp:52
const BackendId & GetBackendId() const
Definition: Layer.hpp:269
const std::vector< OutputSlot > & GetOutputSlots() const
Definition: Layer.hpp:238
std::vector< InputSlot * > InputSlots
void SubstituteSubgraph(SubgraphView &subgraph, IConnectableLayer *substituteLayer)
Substitutes the given sub-graph with either a new layer or a new sub-graph.
Definition: Graph.cpp:432
void SetTensorHandleFactory(const ITensorHandleFactory::FactoryId &id)
Definition: Layer.cpp:171
const InputSlots & GetInputSlots() const
std::vector< OutputSlot >::iterator BeginOutputSlots()
Definition: Layer.hpp:245
const OutputSlots & GetOutputSlots() const
void InferTensorInfos()
Definition: Graph.cpp:529
ITensorHandleFactory * GetFactory(ITensorHandleFactory::FactoryId id) const
Find a TensorHandleFactory by Id Returns nullptr if not found.
virtual bool IsTensorInfoSet() const =0
const Layers & GetLayers() const
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
Definition: NumericCast.hpp:35
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
Definition: Layer.hpp:318
DotAttributeSet & GetAttributeSet()
const char * GetName() const override
Returns the name of the layer.
Definition: Layer.hpp:311
ITensorHandleFactory::FactoryId GetTensorHandleFactoryId() const
Definition: Layer.cpp:176
Graph & TopologicalSort()
Sorts layers in topological order and return this.
Definition: Graph.hpp:177
virtual int Connect(IInputSlot &destination)=0
void ForEachLayer(Func func) const
std::list< Layer * > Layers
std::function< void(const std::string &name, const std::string &value)> ParameterStringifyFunction
Status AllocateDynamicBuffers()
Allocates memory for all tensors under output tensor handers of each layer.
Definition: Graph.cpp:179
const TensorInfo & GetTensorInfo() const override
Definition: Layer.cpp:63
const char * GetLayerTypeAsCString(LayerType type)
void AddCompatibilityLayers(std::map< BackendId, std::unique_ptr< class IBackendInternal >> &backends, TensorHandleFactoryRegistry &registry)
Modifies the graph in-place, removing edges connecting layers using different compute devices...
Definition: Graph.cpp:300
Status Print() const
Definition: Graph.cpp:61
static const FactoryId LegacyFactoryId
void MoveAllConnections(OutputSlot &destination)
Moves all connections to another OutputSlot.
Definition: Layer.cpp:116
An input connection slot for a layer.
Definition: INetwork.hpp:25
LayerGuid GetGuid() const final
Returns the unique id of the layer.
Definition: Layer.hpp:322