18 #include <fmt/format.h>
20 #include <unordered_map>
28 : m_LayersInOrder(other.m_LayersInOrder)
29 , m_AllowExpandedDims(other.m_AllowExpandedDims)
30 , m_ShapeInferenceMethod(other.m_ShapeInferenceMethod)
31 , m_Profiler(other.m_Profiler)
33 std::unordered_map<const Layer*, Layer*> otherToClonedMap;
35 for (
auto&& otherLayer : other.m_Layers)
38 otherToClonedMap.emplace(otherLayer, layer);
42 for (
auto&& otherLayer : other.m_Layers)
44 Layer*
const thisLayer = otherToClonedMap[otherLayer];
47 for (
auto&& otherOutputSlot : otherLayer->GetOutputSlots())
49 for (
auto&& otherInputSlot : otherOutputSlot.GetConnections())
51 const Layer& otherTgtLayer = otherInputSlot->GetOwningLayer();
52 Layer*
const thisTgtLayer = otherToClonedMap[&otherTgtLayer];
56 if (otherInputSlot->IsTensorInfoOverridden())
60 outputSlot->Connect(inputSlot);
62 outputSlot->SetTensorInfo(otherOutputSlot.GetTensorInfo());
80 auto numInputSlots = it->GetNumInputSlots();
81 auto numOutputSlots = it->GetNumOutputSlots();
87 guid += std::to_string(it->GetGuid());
90 <<
":" << it->GetBackendId().Get()
92 <<
" has " << numInputSlots <<
" input slots"
93 <<
" and " << numOutputSlots <<
" output slots.";
95 for (
auto i : it->GetInputSlots())
97 std::ostringstream message;
98 auto inputTensorShape = i.GetConnectedOutputSlot()->GetTensorInfo().GetShape();
99 unsigned int numDims = inputTensorShape.GetNumDimensions();
101 message <<
"The input slot has shape [ ";
102 for (
unsigned int dim=0; dim < numDims; dim++)
104 message << inputTensorShape[dim] <<
",";
109 message <<
" Scale: " << i.GetConnectedOutputSlot()->GetTensorInfo().GetQuantizationScale();
110 message <<
" Offset: " << i.GetConnectedOutputSlot()->GetTensorInfo().GetQuantizationOffset();
111 message <<
" The input slot is connected to: ";
112 message << i.GetConnectedOutputSlot()->GetOwningIConnectableLayer().GetGuid();
117 for (
unsigned int i = 0; i < it->GetNumOutputSlots(); i++)
120 std::ostringstream message;
121 auto outputTensorShape = layer->
GetOutputSlots()[i].GetTensorInfo().GetShape();
122 unsigned int numDims = outputTensorShape.GetNumDimensions();
124 message <<
"The output slot has shape [ ";
125 for (
unsigned int dim=0; dim < numDims; dim++)
127 message << outputTensorShape[dim] <<
",";
132 message <<
" Scale: " << layer->
GetOutputSlots()[i].GetTensorInfo().GetQuantizationScale();
133 message <<
" Offset: " << layer->
GetOutputSlots()[i].GetTensorInfo().GetQuantizationOffset();
134 message <<
" The output slot is connected to: ";
135 message << layer->
GetOutputSlots()[i].GetConnection(0)->GetOwningIConnectableLayer().GetGuid();
149 DotGraph graph(stream,
"Optimized");
168 for (
auto&& layer : m_Layers)
175 layer->SerializeLayerParameters(extractParams);
179 for (
auto&& layer : m_Layers)
183 for (
unsigned int i=0;i<layer->GetNumInputSlots(); i++)
187 DotEdge edge(stream, fromId, toId);
192 std::stringstream ss;
213 std::unordered_set<const ITensorHandle*> preallocatedTensors;
214 std::unordered_map<const ITensorHandle*, unsigned int> handleReferenceCounts;
218 auto TraceSubTensorHandleAncestry = [](
ITensorHandle*
const subTensorHandle)
221 while (ancestor && ancestor->
GetParent())
231 return tensorHandle && preallocatedTensors.find(tensorHandle) != preallocatedTensors.end();
236 for (
auto&& layer : m_Layers)
240 for (
auto&& slot = layer->BeginOutputSlots(); slot != layer->EndOutputSlots(); ++slot)
242 ITensorHandle *tensorHandle = TraceSubTensorHandleAncestry(slot->GetOutputHandler().GetData());
244 if (tensorHandle && !IsPreallocated(tensorHandle))
247 preallocatedTensors.insert(tensorHandle);
254 for (
auto&& layer : m_Layers)
258 for (
auto&& slot = layer->BeginOutputSlots(); slot != layer->EndOutputSlots(); ++slot)
260 ITensorHandle *tensorHandle = TraceSubTensorHandleAncestry(slot->GetOutputHandler().GetData());
262 if (tensorHandle && !IsPreallocated(tensorHandle))
264 unsigned int numConnections = slot->GetNumConnections();
265 if (handleReferenceCounts.find(tensorHandle) == handleReferenceCounts.end())
267 handleReferenceCounts[tensorHandle] = numConnections;
269 if (handleReferenceCounts[tensorHandle] == 0u)
277 handleReferenceCounts[tensorHandle] += numConnections;
284 for (
auto&& slot = layer->BeginInputSlots(); slot != layer->EndInputSlots(); ++slot)
287 slot->GetConnectedOutputSlot()->GetOutputHandler().GetData());
289 if (tensorHandle && !IsPreallocated(tensorHandle))
291 --handleReferenceCounts[tensorHandle];
293 if (handleReferenceCounts[tensorHandle] == 0u)
297 handleReferenceCounts.erase(tensorHandle);
308 if (!m_LayersInOrder)
311 for (
auto&& it : m_Layers)
316 auto compareLayerPriority = [](
const LayerList::value_type& layerA,
const LayerList::value_type& layerB)
318 return layerA->GetPriority() < layerB->GetPriority();
321 m_Layers.sort(compareLayerPriority);
323 m_LayersInOrder =
true;
334 auto MayNeedCompatibilityLayer = [](
const Layer& layer)
343 auto IsCompatibilityStrategy = [](
EdgeStrategy strategy)
349 ForEachLayer([
this, &backends, ®istry, MayNeedCompatibilityLayer, IsCompatibilityStrategy](
Layer* srcLayer)
353 if (!MayNeedCompatibilityLayer(*srcLayer))
359 const std::vector<OutputSlot>& srcOutputSlots = srcLayer->
GetOutputSlots();
360 for (
unsigned int srcOutputIndex = 0; srcOutputIndex < srcOutputSlots.size(); srcOutputIndex++)
363 const std::vector<InputSlot*> srcConnections = srcOutputSlot.
GetConnections();
364 const std::vector<EdgeStrategy> srcEdgeStrategies = srcOutputSlot.
GetEdgeStrategies();
365 for (
unsigned int srcConnectionIndex = 0; srcConnectionIndex < srcConnections.size(); srcConnectionIndex++)
367 InputSlot* dstInputSlot = srcConnections[srcConnectionIndex];
370 EdgeStrategy strategy = srcEdgeStrategies[srcConnectionIndex];
372 "Undefined memory strategy found while adding copy layers for compatibility");
375 if (MayNeedCompatibilityLayer(dstLayer) &&
376 IsCompatibilityStrategy(strategy))
381 const std::string compLayerName = fmt::format(
"[ {} ({}) -> {} ({}) ]",
386 Layer* compLayer =
nullptr;
389 compLayer = InsertNewLayer<MemCopyLayer>(*dstInputSlot, compLayerName.c_str());
394 compLayer = InsertNewLayer<MemImportLayer>(*dstInputSlot, compLayerName.c_str());
400 auto backendIt = backends.find(dstLayer.
GetBackendId());
401 if (backendIt != backends.end() &&
403 backendIt->second->SupportsTensorAllocatorAPI())
405 auto backend = backendIt->second.get();
406 auto tensorHandleFactoryIds = backend->GetHandleFactoryPreferences();
409 for (
auto preference : tensorHandleFactoryIds)
411 auto factory = registry.
GetFactory(preference);
415 auto srcFactory = registry.
GetFactory(srcPref);
419 bool canExportImport =
420 (factory->GetImportFlags() & srcFactory->GetExportFlags()) != 0;
422 if (factory->SupportsMapUnmap() || canExportImport)
446 const std::vector<InputSlot*>& newSourceConnections = srcOutputSlot.
GetConnections();
447 auto newSrcConnectionIndex = std::distance(newSourceConnections.begin(),
448 std::find(newSourceConnections.begin(),
449 newSourceConnections.end(),
453 srcOutputSlot.
SetEdgeStrategy(armnn::numeric_cast<unsigned int>(newSrcConnectionIndex),
477 if (std::find(std::begin(m_Layers),
479 iConnectableLayer) == std::end(m_Layers))
481 auto layer = PolymorphicDowncast<Layer*>(iConnectableLayer);
482 layer->Reparent(*
this, m_Layers.end());
483 m_LayersInOrder =
false;
487 ReplaceSubgraphConnections(subgraph, substituteSubgraph);
488 EraseSubgraphLayers(subgraph);
495 "New sub-graph used for substitution must not be empty");
498 std::for_each(substituteSubgraphLayers.begin(), substituteSubgraphLayers.end(), [&](
IConnectableLayer* layer)
501 layer = PolymorphicDowncast<Layer*>(layer);
502 ARMNN_ASSERT_MSG(std::find(m_Layers.begin(), m_Layers.end(), layer) != m_Layers.end(),
503 "Substitute layer is not a member of graph");
509 unsigned int subgraphNumInputSlots = armnn::numeric_cast<unsigned int>(subgraphInputSlots.size());
510 unsigned int subgraphNumOutputSlots = armnn::numeric_cast<unsigned int>(subgraphOutputSlots.size());
515 ARMNN_ASSERT(subgraphNumInputSlots == substituteSubgraphInputSlots.size());
516 ARMNN_ASSERT(subgraphNumOutputSlots == substituteSubgraphOutputSlots.size());
521 for (
unsigned int inputSlotIdx = 0; inputSlotIdx < subgraphNumInputSlots; ++inputSlotIdx)
523 IInputSlot* subgraphInputSlot = subgraphInputSlots.at(inputSlotIdx);
532 InputSlot* inputSlot = PolymorphicDowncast<InputSlot*>(subgraphInputSlot);
536 connectedOutputSlot->
Disconnect(*subgraphInputSlot);
538 IInputSlot* substituteInputSlot = substituteSubgraphInputSlots.at(inputSlotIdx);
540 connectedOutputSlot->
Connect(*substituteInputSlot);
545 InputSlot* newInputSlot = PolymorphicDowncast<InputSlot*>(substituteInputSlot);
552 for(
unsigned int outputSlotIdx = 0; outputSlotIdx < subgraphNumOutputSlots; ++outputSlotIdx)
554 auto subgraphOutputSlot =
555 PolymorphicDowncast<OutputSlot*>(subgraphOutputSlots.at(outputSlotIdx));
558 auto substituteOutputSlot =
559 PolymorphicDowncast<OutputSlot*>(substituteSubgraphOutputSlots.at(outputSlotIdx));
562 subgraphOutputSlot->MoveAllConnections(*substituteOutputSlot);
566 void Graph::EraseSubgraphLayers(SubgraphView &subgraph)
569 for (
auto iConnectableLayer : subgraph.GetIConnectableLayers())
571 auto layer = PolymorphicDowncast<Layer*>(iConnectableLayer);
587 for (
auto&& output: layer->GetOutputSlots())
589 if (!output.IsTensorInfoSet())
591 std::ostringstream message;
592 message <<
"Output slot TensorInfo not set on "
608 for (
auto&& input : layer->GetInputSlots())
610 const IOutputSlot* source = input.GetConnectedOutputSlot();
615 ConstructErrorMessageForUnconnectedInputs(layer, input.GetSlotIndex());
620 std::ostringstream message;
621 message <<
"Output slot TensorInfo not set on "
624 << std::quoted(layer->GetName());
631 layer->ValidateTensorShapesFromInputs();
643 void Graph::ConstructErrorMessageForUnconnectedInputs(
Layer*
const layer,
644 unsigned int slotIndex)
646 std::ostringstream message;
647 bool noWeightsAndBias =
false;
654 message << std::endl;
660 if (biasSource == NULL)
662 message <<
"Weights and bias layers not set." << std::endl;
663 noWeightsAndBias =
true;
668 if (!noWeightsAndBias)
672 message <<
"Weights layer not set." << std::endl;
676 message <<
"Bias layer not set." << std::endl;
681 std::string slotString = noWeightsAndBias ?
"1 & 2" : std::to_string(slotIndex);
682 message <<
"Input slot(s) "
686 <<
" not connected to an output slot. " << std::endl
688 << std::quoted(layer->
GetName());
689 throw LayerValidationException(message.str());
699 m_LayersInOrder =
false;