17 #include <boost/polymorphic_cast.hpp> 18 #include <boost/assert.hpp> 19 #include <boost/format.hpp> 21 #include <unordered_map> 29 : m_LayersInOrder(other.m_LayersInOrder)
31 std::unordered_map<const Layer*, Layer*> otherToClonedMap;
33 for (
auto&& otherLayer : other.m_Layers)
36 otherToClonedMap.emplace(otherLayer, layer);
40 for (
auto&& otherLayer : other.m_Layers)
42 Layer*
const thisLayer = otherToClonedMap[otherLayer];
45 for (
auto&& otherOutputSlot : otherLayer->GetOutputSlots())
47 for (
auto&& otherInputSlot : otherOutputSlot.GetConnections())
49 const Layer& otherTgtLayer = otherInputSlot->GetOwningLayer();
50 Layer*
const thisTgtLayer = otherToClonedMap[&otherTgtLayer];
53 outputSlot->Connect(inputSlot);
55 outputSlot->SetTensorInfo(otherOutputSlot.GetTensorInfo());
74 <<
":" << it->GetBackendId().Get();
103 for (
auto&& layer : m_Layers)
110 layer->SerializeLayerParameters(extractParams);
114 for (
auto&& layer : m_Layers)
118 for (
unsigned int i=0;i<layer->GetNumInputSlots(); i++)
122 DotEdge edge(stream, fromId, toId);
127 std::stringstream ss;
145 BOOST_ASSERT(m_LayersInOrder);
147 std::unordered_set<const ITensorHandle*> preallocatedTensors;
148 std::unordered_map<const ITensorHandle*, unsigned int> handleReferenceCounts;
152 auto TraceSubTensorHandleAncestry = [](
ITensorHandle*
const subTensorHandle)
155 while (ancestor && ancestor->
GetParent())
165 return tensorHandle && preallocatedTensors.find(tensorHandle) != preallocatedTensors.end();
170 for (
auto&& layer : m_Layers)
174 for (
auto&& slot = layer->BeginOutputSlots(); slot != layer->EndOutputSlots(); ++slot)
176 ITensorHandle *tensorHandle = TraceSubTensorHandleAncestry(slot->GetOutputHandler().GetData());
178 if (tensorHandle && !IsPreallocated(tensorHandle))
181 preallocatedTensors.insert(tensorHandle);
188 for (
auto&& layer : m_Layers)
192 for (
auto&& slot = layer->BeginOutputSlots(); slot != layer->EndOutputSlots(); ++slot)
194 ITensorHandle *tensorHandle = TraceSubTensorHandleAncestry(slot->GetOutputHandler().GetData());
196 if (tensorHandle && !IsPreallocated(tensorHandle))
198 unsigned int numConnections = slot->GetNumConnections();
199 if (handleReferenceCounts.find(tensorHandle) == handleReferenceCounts.end())
201 handleReferenceCounts[tensorHandle] = numConnections;
203 if (handleReferenceCounts[tensorHandle] == 0u)
211 handleReferenceCounts[tensorHandle] += numConnections;
218 for (
auto&& slot = layer->BeginInputSlots(); slot != layer->EndInputSlots(); ++slot)
221 slot->GetConnectedOutputSlot()->GetOutputHandler().GetData());
223 if (tensorHandle && !IsPreallocated(tensorHandle))
225 --handleReferenceCounts[tensorHandle];
227 if (handleReferenceCounts[tensorHandle] == 0u)
231 handleReferenceCounts.erase(tensorHandle);
242 if (!m_LayersInOrder)
245 for (
auto&& it : m_Layers)
250 auto compareLayerPriority = [](
const LayerList::value_type& layerA,
const LayerList::value_type& layerB)
252 return layerA->GetPriority() < layerB->GetPriority();
255 m_Layers.sort(compareLayerPriority);
257 m_LayersInOrder =
true;
268 auto MayNeedCompatibilityLayer = [](
const Layer& layer)
277 auto IsCompatibilityStrategy = [](
EdgeStrategy strategy)
283 ForEachLayer([
this, &backends, ®istry, MayNeedCompatibilityLayer, IsCompatibilityStrategy](
Layer* srcLayer)
285 BOOST_ASSERT(srcLayer);
287 if (!MayNeedCompatibilityLayer(*srcLayer))
293 const std::vector<OutputSlot>& srcOutputSlots = srcLayer->
GetOutputSlots();
294 for (
unsigned int srcOutputIndex = 0; srcOutputIndex < srcOutputSlots.size(); srcOutputIndex++)
297 const std::vector<InputSlot*> srcConnections = srcOutputSlot.
GetConnections();
298 const std::vector<EdgeStrategy> srcEdgeStrategies = srcOutputSlot.
GetEdgeStrategies();
299 for (
unsigned int srcConnectionIndex = 0; srcConnectionIndex < srcConnections.size(); srcConnectionIndex++)
301 InputSlot* dstInputSlot = srcConnections[srcConnectionIndex];
302 BOOST_ASSERT(dstInputSlot);
304 EdgeStrategy strategy = srcEdgeStrategies[srcConnectionIndex];
306 "Undefined memory strategy found while adding copy layers for compatibility");
309 if (MayNeedCompatibilityLayer(dstLayer) &&
310 IsCompatibilityStrategy(strategy))
315 const std::string compLayerName = boost::str(boost::format(
"[ %1% (%2%) -> %3% (%4%) ]")
321 Layer* compLayer =
nullptr;
324 compLayer = InsertNewLayer<MemCopyLayer>(*dstInputSlot, compLayerName.c_str());
329 compLayer = InsertNewLayer<MemImportLayer>(*dstInputSlot, compLayerName.c_str());
334 OutputSlot& compOutputSlot = compLayer->GetOutputSlot(0);
335 auto backendIt = backends.find(dstLayer.
GetBackendId());
336 if (backendIt != backends.end() &&
338 backendIt->second->SupportsTensorAllocatorAPI())
340 auto backend = backendIt->second.get();
341 auto tensorHandleFactoryIds = backend->GetHandleFactoryPreferences();
344 for (
auto preference : tensorHandleFactoryIds)
346 auto factory = registry.
GetFactory(preference);
350 auto srcFactory = registry.
GetFactory(srcPref);
354 bool canExportImport =
355 (factory->GetImportFlags() & srcFactory->GetExportFlags()) != 0;
357 if (factory->SupportsMapUnmap() || canExportImport)
381 const std::vector<InputSlot*>& newSourceConnections = srcOutputSlot.
GetConnections();
382 long newSrcConnectionIndex = std::distance(newSourceConnections.begin(),
383 std::find(newSourceConnections.begin(),
384 newSourceConnections.end(),
385 &compLayer->GetInputSlot(0)));
388 srcOutputSlot.
SetEdgeStrategy(boost::numeric_cast<unsigned int>(newSrcConnectionIndex),
398 BOOST_ASSERT(substituteLayer !=
nullptr);
400 ReplaceSubgraphConnections(subgraph, substituteLayer);
401 EraseSubgraphLayers(subgraph);
409 if (std::find(std::begin(m_Layers), std::end(m_Layers), layer) == std::end(m_Layers))
411 layer->
Reparent(*
this, m_Layers.end());
412 m_LayersInOrder =
false;
416 ReplaceSubgraphConnections(subgraph, substituteSubgraph);
417 EraseSubgraphLayers(subgraph);
423 BOOST_ASSERT(substituteLayer !=
nullptr);
428 ReplaceSubgraphConnections(subgraph, substituteSubgraph);
433 BOOST_ASSERT_MSG(!substituteSubgraph.
GetLayers().empty(),
"New sub-graph used for substitution must not be empty");
436 std::for_each(substituteSubgraphLayers.begin(), substituteSubgraphLayers.end(), [&](
Layer* layer)
439 BOOST_ASSERT_MSG(std::find(m_Layers.begin(), m_Layers.end(), layer) != m_Layers.end(),
440 "Substitute layer is not a member of graph");
446 unsigned int subgraphNumInputSlots =
boost::numeric_cast<
unsigned int>(subgraphInputSlots.size());
447 unsigned int subgraphNumOutputSlots =
boost::numeric_cast<
unsigned int>(subgraphOutputSlots.size());
452 BOOST_ASSERT(subgraphNumInputSlots == substituteSubgraphInputSlots.size());
453 BOOST_ASSERT(subgraphNumOutputSlots == substituteSubgraphOutputSlots.size());
458 for (
unsigned int inputSlotIdx = 0; inputSlotIdx < subgraphNumInputSlots; ++inputSlotIdx)
460 InputSlot* subgraphInputSlot = subgraphInputSlots.at(inputSlotIdx);
461 BOOST_ASSERT(subgraphInputSlot);
464 BOOST_ASSERT(connectedOutputSlot);
465 connectedOutputSlot->
Disconnect(*subgraphInputSlot);
467 IInputSlot* substituteInputSlot = substituteSubgraphInputSlots.at(inputSlotIdx);
468 BOOST_ASSERT(substituteInputSlot);
469 connectedOutputSlot->
Connect(*substituteInputSlot);
473 for(
unsigned int outputSlotIdx = 0; outputSlotIdx < subgraphNumOutputSlots; ++outputSlotIdx)
475 OutputSlot* subgraphOutputSlot = subgraphOutputSlots.at(outputSlotIdx);
476 BOOST_ASSERT(subgraphOutputSlot);
478 OutputSlot* substituteOutputSlot = substituteSubgraphOutputSlots.at(outputSlotIdx);
479 BOOST_ASSERT(substituteOutputSlot);
497 for (
auto&& input : layer->GetInputSlots())
499 const IOutputSlot* source = input.GetConnectedOutputSlot();
502 std::ostringstream message;
503 message <<
"Input not connected on " 516 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
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.
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.