18 #include <boost/format.hpp> 20 #include <unordered_map> 28 : m_LayersInOrder(other.m_LayersInOrder)
30 std::unordered_map<const Layer*, Layer*> otherToClonedMap;
32 for (
auto&& otherLayer : other.m_Layers)
35 otherToClonedMap.emplace(otherLayer, layer);
39 for (
auto&& otherLayer : other.m_Layers)
41 Layer*
const thisLayer = otherToClonedMap[otherLayer];
44 for (
auto&& otherOutputSlot : otherLayer->GetOutputSlots())
46 for (
auto&& otherInputSlot : otherOutputSlot.GetConnections())
48 const Layer& otherTgtLayer = otherInputSlot->GetOwningLayer();
49 Layer*
const thisTgtLayer = otherToClonedMap[&otherTgtLayer];
52 outputSlot->Connect(inputSlot);
54 outputSlot->SetTensorInfo(otherOutputSlot.GetTensorInfo());
73 <<
":" << it->GetBackendId().Get();
102 for (
auto&& layer : m_Layers)
109 layer->SerializeLayerParameters(extractParams);
113 for (
auto&& layer : m_Layers)
117 for (
unsigned int i=0;i<layer->GetNumInputSlots(); i++)
121 DotEdge edge(stream, fromId, toId);
126 std::stringstream ss;
146 std::unordered_set<const ITensorHandle*> preallocatedTensors;
147 std::unordered_map<const ITensorHandle*, unsigned int> handleReferenceCounts;
151 auto TraceSubTensorHandleAncestry = [](
ITensorHandle*
const subTensorHandle)
154 while (ancestor && ancestor->
GetParent())
164 return tensorHandle && preallocatedTensors.find(tensorHandle) != preallocatedTensors.end();
169 for (
auto&& layer : m_Layers)
173 for (
auto&& slot = layer->BeginOutputSlots(); slot != layer->EndOutputSlots(); ++slot)
175 ITensorHandle *tensorHandle = TraceSubTensorHandleAncestry(slot->GetOutputHandler().GetData());
177 if (tensorHandle && !IsPreallocated(tensorHandle))
180 preallocatedTensors.insert(tensorHandle);
187 for (
auto&& layer : m_Layers)
191 for (
auto&& slot = layer->BeginOutputSlots(); slot != layer->EndOutputSlots(); ++slot)
193 ITensorHandle *tensorHandle = TraceSubTensorHandleAncestry(slot->GetOutputHandler().GetData());
195 if (tensorHandle && !IsPreallocated(tensorHandle))
197 unsigned int numConnections = slot->GetNumConnections();
198 if (handleReferenceCounts.find(tensorHandle) == handleReferenceCounts.end())
200 handleReferenceCounts[tensorHandle] = numConnections;
202 if (handleReferenceCounts[tensorHandle] == 0u)
210 handleReferenceCounts[tensorHandle] += numConnections;
217 for (
auto&& slot = layer->BeginInputSlots(); slot != layer->EndInputSlots(); ++slot)
220 slot->GetConnectedOutputSlot()->GetOutputHandler().GetData());
222 if (tensorHandle && !IsPreallocated(tensorHandle))
224 --handleReferenceCounts[tensorHandle];
226 if (handleReferenceCounts[tensorHandle] == 0u)
230 handleReferenceCounts.erase(tensorHandle);
241 if (!m_LayersInOrder)
244 for (
auto&& it : m_Layers)
249 auto compareLayerPriority = [](
const LayerList::value_type& layerA,
const LayerList::value_type& layerB)
251 return layerA->GetPriority() < layerB->GetPriority();
254 m_Layers.sort(compareLayerPriority);
256 m_LayersInOrder =
true;
267 auto MayNeedCompatibilityLayer = [](
const Layer& layer)
276 auto IsCompatibilityStrategy = [](
EdgeStrategy strategy)
282 ForEachLayer([
this, &backends, ®istry, MayNeedCompatibilityLayer, IsCompatibilityStrategy](
Layer* srcLayer)
286 if (!MayNeedCompatibilityLayer(*srcLayer))
292 const std::vector<OutputSlot>& srcOutputSlots = srcLayer->
GetOutputSlots();
293 for (
unsigned int srcOutputIndex = 0; srcOutputIndex < srcOutputSlots.size(); srcOutputIndex++)
296 const std::vector<InputSlot*> srcConnections = srcOutputSlot.
GetConnections();
297 const std::vector<EdgeStrategy> srcEdgeStrategies = srcOutputSlot.
GetEdgeStrategies();
298 for (
unsigned int srcConnectionIndex = 0; srcConnectionIndex < srcConnections.size(); srcConnectionIndex++)
300 InputSlot* dstInputSlot = srcConnections[srcConnectionIndex];
303 EdgeStrategy strategy = srcEdgeStrategies[srcConnectionIndex];
305 "Undefined memory strategy found while adding copy layers for compatibility");
308 if (MayNeedCompatibilityLayer(dstLayer) &&
309 IsCompatibilityStrategy(strategy))
314 const std::string compLayerName = boost::str(boost::format(
"[ %1% (%2%) -> %3% (%4%) ]")
320 Layer* compLayer =
nullptr;
323 compLayer = InsertNewLayer<MemCopyLayer>(*dstInputSlot, compLayerName.c_str());
328 compLayer = InsertNewLayer<MemImportLayer>(*dstInputSlot, compLayerName.c_str());
333 OutputSlot& compOutputSlot = compLayer->GetOutputSlot(0);
334 auto backendIt = backends.find(dstLayer.
GetBackendId());
335 if (backendIt != backends.end() &&
337 backendIt->second->SupportsTensorAllocatorAPI())
339 auto backend = backendIt->second.get();
340 auto tensorHandleFactoryIds = backend->GetHandleFactoryPreferences();
343 for (
auto preference : tensorHandleFactoryIds)
345 auto factory = registry.
GetFactory(preference);
349 auto srcFactory = registry.
GetFactory(srcPref);
353 bool canExportImport =
354 (factory->GetImportFlags() & srcFactory->GetExportFlags()) != 0;
356 if (factory->SupportsMapUnmap() || canExportImport)
380 const std::vector<InputSlot*>& newSourceConnections = srcOutputSlot.
GetConnections();
381 auto newSrcConnectionIndex = std::distance(newSourceConnections.begin(),
382 std::find(newSourceConnections.begin(),
383 newSourceConnections.end(),
384 &compLayer->GetInputSlot(0)));
387 srcOutputSlot.
SetEdgeStrategy(boost::numeric_cast<unsigned int>(newSrcConnectionIndex),
399 ReplaceSubgraphConnections(subgraph, substituteLayer);
400 EraseSubgraphLayers(subgraph);
408 if (std::find(std::begin(m_Layers), std::end(m_Layers), layer) == std::end(m_Layers))
410 layer->
Reparent(*
this, m_Layers.end());
411 m_LayersInOrder =
false;
415 ReplaceSubgraphConnections(subgraph, substituteSubgraph);
416 EraseSubgraphLayers(subgraph);
427 ReplaceSubgraphConnections(subgraph, substituteSubgraph);
435 std::for_each(substituteSubgraphLayers.begin(), substituteSubgraphLayers.end(), [&](
Layer* layer)
438 ARMNN_ASSERT_MSG(std::find(m_Layers.begin(), m_Layers.end(), layer) != m_Layers.end(),
439 "Substitute layer is not a member of graph");
445 unsigned int subgraphNumInputSlots =
boost::numeric_cast<
unsigned int>(subgraphInputSlots.size());
446 unsigned int subgraphNumOutputSlots =
boost::numeric_cast<
unsigned int>(subgraphOutputSlots.size());
451 ARMNN_ASSERT(subgraphNumInputSlots == substituteSubgraphInputSlots.size());
452 ARMNN_ASSERT(subgraphNumOutputSlots == substituteSubgraphOutputSlots.size());
457 for (
unsigned int inputSlotIdx = 0; inputSlotIdx < subgraphNumInputSlots; ++inputSlotIdx)
459 InputSlot* subgraphInputSlot = subgraphInputSlots.at(inputSlotIdx);
464 connectedOutputSlot->
Disconnect(*subgraphInputSlot);
466 IInputSlot* substituteInputSlot = substituteSubgraphInputSlots.at(inputSlotIdx);
468 connectedOutputSlot->
Connect(*substituteInputSlot);
472 for(
unsigned int outputSlotIdx = 0; outputSlotIdx < subgraphNumOutputSlots; ++outputSlotIdx)
474 OutputSlot* subgraphOutputSlot = subgraphOutputSlots.at(outputSlotIdx);
477 OutputSlot* substituteOutputSlot = substituteSubgraphOutputSlots.at(outputSlotIdx);
496 for (
auto&& input : layer->GetInputSlots())
498 const IOutputSlot* source = input.GetConnectedOutputSlot();
501 std::ostringstream message;
502 message <<
"Input not connected on " 515 layer->ValidateTensorShapesFromInputs();
const std::vector< InputSlot * > & GetConnections() const
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
NodeContent & AddContent(const std::string &content)
void SetEdgeStrategy(unsigned int connectionIndex, EdgeStrategy strategy)
No strategy has been defined. Used internally to verify integrity of optimizations.
const TensorShape & GetShape() const
Status SerializeToDot(std::ostream &stream)
const std::vector< EdgeStrategy > & GetEdgeStrategies() const
virtual void Reparent(Graph &dest, std::list< Layer *>::const_iterator iterator)=0
Layer & GetOwningLayer() const
Source backends tensor data can be exported to destination backend tensor without copy...
void EraseLayer(Iterator pos)
Deletes the layer at the specified position.
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)
virtual void Manage()=0
Indicate to the memory manager that this resource is active.
Copyright (c) 2020 ARM Limited.
void IgnoreUnused(Ts &&...)
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.
void ForEachLayer(Func func) const
#define ARMNN_ASSERT_MSG(COND, MSG)
char const * GetLayerTypeAsCString(LayerType type)
DotAttributeSet & AddAttribute(const std::string &name, const std::stringstream &value)
NodeContent & GetContents()
An output connection slot for a layer.
virtual void Disconnect(IInputSlot &slot)=0
virtual ITensorHandle * GetParent() const =0
Get the parent tensor if this is a subtensor.
#define ARMNN_ASSERT(COND)
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
const BackendId & GetBackendId() const
const std::vector< OutputSlot > & GetOutputSlots() const
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.
void SetTensorHandleFactory(const ITensorHandleFactory::FactoryId &id)
const InputSlots & GetInputSlots() const
std::vector< OutputSlot >::iterator BeginOutputSlots()
const OutputSlots & GetOutputSlots() const
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
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
DotAttributeSet & GetAttributeSet()
const char * GetName() const override
Returns the name of the layer.
ITensorHandleFactory::FactoryId GetTensorHandleFactoryId() const
Graph & TopologicalSort()
Sorts layers in topological order and return this.
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.
const TensorInfo & GetTensorInfo() const override
void AddCompatibilityLayers(std::map< BackendId, std::unique_ptr< class IBackendInternal >> &backends, TensorHandleFactoryRegistry ®istry)
Modifies the graph in-place, removing edges connecting layers using different compute devices...
static const FactoryId LegacyFactoryId
void MoveAllConnections(OutputSlot &destination)
Moves all connections to another OutputSlot.
LayerGuid GetGuid() const final
Returns the unique id of the layer.