ArmNN  NotReleased
Network.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "Network.hpp"
7 #include "Graph.hpp"
8 #include "Layer.hpp"
9 #include "DeviceSpec.hpp"
10 #include "Optimizer.hpp"
11 #include "SubgraphViewSelector.hpp"
12 #include "BackendSettings.hpp"
13 #include "optimizations/All.hpp"
14 
19 
20 #include <armnn/Exceptions.hpp>
21 #include <armnn/Utils.hpp>
22 #include <armnn/TypesUtils.hpp>
24 #include <armnn/Logging.hpp>
25 
26 #include <ProfilingService.hpp>
27 
28 #include <fcntl.h>
29 #include <algorithm>
30 #include <fstream>
31 #include <memory>
32 #include <vector>
33 #include <algorithm>
34 
35 #include <boost/assert.hpp>
36 #include <boost/format.hpp>
37 #include <boost/numeric/conversion/converter_policies.hpp>
38 #include <boost/cast.hpp>
39 
40 namespace armnn
41 {
42 
44 {
45  return new Network();
46 }
47 
49 {
51 }
52 
54 {
55  delete boost::polymorphic_downcast<Network*>(network);
56 }
57 
59 {
60  delete boost::polymorphic_downcast<OptimizedNetwork*>(network);
61 }
62 
64 {
65  m_Graph->Print();
66  return Status::Success;
67 }
68 
69 Status OptimizedNetwork::SerializeToDot(std::ostream& stream) const
70 {
71  return m_Graph->SerializeToDot(stream);
72 }
73 
74 void ReportError(const std::string& errorMessage,
75  Optional<std::vector<std::string>&> errorMessages)
76 {
77  std::stringstream fullErrorMessage;
78  fullErrorMessage << "ERROR: " << errorMessage;
79  ARMNN_LOG(warning) << fullErrorMessage.str();
80  if (errorMessages)
81  {
82  errorMessages.value().push_back(fullErrorMessage.str());
83  }
84 }
85 
86 void ReportWarning(const std::string& warningMessage,
87  Optional<std::vector<std::string>&> warningMessages)
88 {
89  std::stringstream fullWarningMessage;
90  fullWarningMessage << "WARNING: " << warningMessage;
91  ARMNN_LOG(warning) << fullWarningMessage.str();
92  if (warningMessages)
93  {
94  warningMessages.value().push_back(fullWarningMessage.str());
95  }
96 }
97 
98 bool CheckScaleSetOnQuantizedType(Layer* layer, Optional<std::vector<std::string>&> errMessages)
99 {
100  bool noErrors = true;
101  unsigned int numOutputs = layer->GetNumOutputSlots();
102  for (unsigned int i = 0; i < numOutputs; i++) {
103  OutputSlot& outputSlot = layer->GetOutputSlot(i);
104  TensorInfo info = outputSlot.GetTensorInfo();
105  if (DataType::QAsymmU8 == info.GetDataType()) {
106  if (0.f == info.GetQuantizationScale()) {
107  noErrors = false;
108  std::stringstream ss;
109  ss << "output " << i << " of layer " << GetLayerTypeAsCString(layer->GetType())
110  << " (" << layer->GetNameStr() << ") is of type"
111  << " Quantized 8 bit but its scale parameter has not been set";
112  ReportError(ss.str(), errMessages);
113  }
114  // Softmax under QuantisedAsymm8 must always be scale (1.0f/256.0f) and offset 0
115  if ((info.GetQuantizationScale() != (1.0f / 256.0f) ||
116  info.GetQuantizationOffset() != 0) &&
118  {
119  std::stringstream ss;
120  ss << "Quantization parameters for Softmax layer (Scale: " <<
121  info.GetQuantizationScale() << " and Offset: " << info.GetQuantizationOffset() <<
122  ") are incorrect and have been updated to Scale: 0.00390625 and Offset: 0";
123  ARMNN_LOG(warning) << ss.str();
124  info.SetQuantizationScale((1.0f /256.0f));
125  info.SetQuantizationOffset(0);
126  outputSlot.SetTensorInfo(info);
127  }
128  }
129  }
130  return noErrors;
131 }
132 
134  BackendSettings& backendSettings,
135  Graph::Iterator& firstLayer,
136  Graph::Iterator& lastLayer,
137  Optional<std::vector<std::string>&> errMessages)
138 {
139  OptimizationResult result;
140 
141  // Helper lambda to compose meaningful error message before returning with error
142  auto ReturnWithError = [&](const Layer* layer)
143  {
144  std::stringstream failureMsg;
145  failureMsg << "Layer of type " << GetLayerTypeAsCString(layer->GetType())
146  << " is not supported on any preferred backend " << backendSettings.m_PreferredBackends;
147  ReportError(failureMsg.str(), errMessages);
148 
149  result.m_Error = true;
150  return result;
151  };
152 
153  auto availablePreferredBackends = backendSettings.GetAvailablePreferredBackends();
154  if (availablePreferredBackends.empty())
155  {
156  std::stringstream failureMsg;
157  failureMsg << "No preferred backends are available";
158  ReportError(failureMsg.str(), errMessages);
159 
160  result.m_Error = true;
161  return result;
162  }
163 
164  for (auto it = firstLayer; it != lastLayer; ++it)
165  {
166  auto layer = *it;
167 
168  DataType dataTypeIn = layer->GetNumInputSlots() == 0 ? DataType::Float32 :
169  layer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo().GetDataType();
170  DataType dataTypeOut = layer->GetNumOutputSlots() == 0 ? DataType::Float32 :
171  layer->GetOutputSlot(0).GetTensorInfo().GetDataType();
172 
173  std::string reasonIfUnsupported;
174  bool found = false;
175  if (!CheckScaleSetOnQuantizedType(layer, errMessages))
176  {
177  // don't bomb immediately, find all the quantized outputs
178  // which haven't had a scale set and report them all back.
179  result.m_Error = true;
180  }
181 
182  for (const auto& backend : availablePreferredBackends)
183  {
184  // need to set the compute device on the layer
185  // before we can check if it is supported
186  layer->SetBackendId(backend);
187  if (!IWorkloadFactory::IsLayerSupported(*layer, EmptyOptional(), reasonIfUnsupported))
188  {
189  if (dataTypeIn == DataType::Float16 || dataTypeOut == DataType::Float16)
190  {
191  if (IWorkloadFactory::IsLayerSupported(*layer, DataType::Float32, reasonIfUnsupported)
192  && layer->GetType() != LayerType::ConvertFp32ToFp16
193  && layer->GetType() != LayerType::ConvertFp16ToFp32)
194  {
195  // Insert FP16 -> FP32 conversion layer before current layer
196  std::vector<ConvertFp16ToFp32Layer*> convertFp16ToFp32Layers;
197  if (dataTypeIn == DataType::Float16)
198  {
199  convertFp16ToFp32Layers =
200  InsertConvertFp16ToFp32LayersBefore(optNetObjPtr->GetGraph(), *layer);
201  }
202 
203  // Insert FP32 -> FP16 conversion layer after current layer
204  std::vector<ConvertFp32ToFp16Layer*> convertFp32ToFp16Layers;
205  if (dataTypeOut == DataType::Float16)
206  {
207  convertFp32ToFp16Layers =
208  InsertConvertFp32ToFp16LayersAfter(optNetObjPtr->GetGraph(), *layer);
209  }
210 
211  // Assign a supported backend to the newly introduced conversion layers
212  auto AssignFirstSupportedBackend = [&](Layer* layer, BackendId preferredBackend)
213  {
214  bool supportedBackendFound = false;
215  std::string reasonIfUnsupported;
216 
217  // Try preferred backend first
218  layer->SetBackendId(preferredBackend);
220  EmptyOptional(),
221  reasonIfUnsupported))
222  {
223  supportedBackendFound = true;
224  }
225  else
226  {
227  for (const auto& backend : availablePreferredBackends)
228  {
229  // Skip preferred backend (we already determined that it is not supported)
230  if (backend == preferredBackend)
231  {
232  continue;
233  }
234 
235  layer->SetBackendId(backend);
237  EmptyOptional(),
238  reasonIfUnsupported))
239  {
240  supportedBackendFound = true;
241  break;
242  }
243  }
244  }
245 
246  return supportedBackendFound;
247  };
248 
249  for (ConvertFp16ToFp32Layer* convertLayer : convertFp16ToFp32Layers)
250  {
251  if (!AssignFirstSupportedBackend(convertLayer, backend))
252  {
253  return ReturnWithError(convertLayer);
254  }
255  }
256 
257  for (ConvertFp32ToFp16Layer* convertLayer : convertFp32ToFp16Layers)
258  {
259  if (!AssignFirstSupportedBackend(convertLayer, backend))
260  {
261  return ReturnWithError(convertLayer);
262  }
263  }
264 
265  found = true;
266  break;
267  }
268  }
269  std::stringstream warningMsg;
270  warningMsg << "Layer of type " << GetLayerTypeAsCString(layer->GetType())
271  << " is not supported on requested backend " << layer->GetBackendId().Get()
272  << " for input data type " << GetDataTypeName(dataTypeIn)
273  << " and output data type " << GetDataTypeName(dataTypeOut)
274  << " (reason: " << reasonIfUnsupported
275  << "), falling back to the next backend.";
276  ReportWarning(warningMsg.str(), errMessages);
277  }
278  else
279  {
280  found = true;
281  backendSettings.m_SelectedBackends.insert(backend);
282  break;
283  }
284  }
285 
286  // If the layer is unsupported by any devices, log and return a null network.
287  if (!found)
288  {
289  // NOTE: if the layer is not an operation queue type AND we have not got CpuRef as a
290  // fallback we should set the compute device on the layer to CpuRef (these are not
291  // available as accelerated operations, or are only available under certain
292  // conditions, currently they comprise MemCopy, Constant, Permute)
293  armnn::LayerType layerType = layer->GetType();
294  if (!backendSettings.IsCpuRefUsed() && (layerType == armnn::LayerType::MemCopy ||
295  layerType == armnn::LayerType::Constant ||
296  layerType == armnn::LayerType::Permute))
297  {
298  BackendId cpuBackendId(armnn::Compute::CpuRef);
299  layer->SetBackendId(cpuBackendId);
300  backendSettings.m_SelectedBackends.insert(cpuBackendId);
301  }
302  else
303  {
304  return ReturnWithError(layer);
305  }
306  }
307  }
308 
309  return result;
310 }
311 
313  BackendSettings& backendSettings,
314  SubgraphView& subgraph,
315  Optional<std::vector<std::string>&> errMessages)
316 {
317  Graph::Iterator firstLayer = subgraph.begin();
318  Graph::Iterator lastLayer = subgraph.end();
319  return AssignBackends(optNetObjPtr,
320  backendSettings,
321  firstLayer,
322  lastLayer,
323  errMessages);
324 }
325 
327  BackendSettings& backendSettings)
328 {
329  BackendsMap backends;
330  auto const& backendRegistry = BackendRegistryInstance();
331  for (auto&& selectedBackend : backendSettings.m_SupportedBackends)
332  {
333  auto backendFactory = backendRegistry.GetFactory(selectedBackend);
334  auto backendObjPtr = backendFactory();
335  BOOST_ASSERT(backendObjPtr);
336 
337  backendObjPtr->RegisterTensorHandleFactories(handleFactoryRegistry);
338 
339  backends[backendObjPtr->GetId()] = std::move(backendObjPtr);
340  }
341 
342  return backends;
343 }
344 
346  BackendSettings& backendSettings,
347  BackendsMap& backends,
348  Optional<std::vector<std::string>&> errMessages)
349 {
350  BOOST_ASSERT(optNetObjPtr);
351 
352  OptimizationResult result;
353 
354  // Get the optimized graph
355  Graph& optGraph = optNetObjPtr->GetGraph();
356 
357  // Run backend specific optimizations
358  for (auto&& selectedBackend : backendSettings.m_SelectedBackends)
359  {
360  auto backendObjPtr = backends.find(selectedBackend)->second.get();
361  BOOST_ASSERT(backendObjPtr);
362 
363  // Select sub-graphs based on backend
366  // Select layers assigned to the requested backend
367  [&backendObjPtr](const Layer& layer)
368  {
369  return layer.GetType() != LayerType::Input &&
370  layer.GetType() != LayerType::Output &&
371  layer.GetBackendId() == backendObjPtr->GetId();
372  });
373  if (subgraphs.empty())
374  {
375  // No sub-graphs found, try with next selected backend
376  continue;
377  }
378 
379  // Try to optimize each sub-graph
380  for (auto& subgraph : subgraphs)
381  {
382  // Try to optimize the current sub-graph
383  OptimizationViews optimizationViews = backendObjPtr->OptimizeSubgraphView(*subgraph);
384  BOOST_ASSERT(optimizationViews.Validate(*subgraph));
385 
386  // Optimization attempted, check the resulting optimized sub-graph
387  for (auto& substitution : optimizationViews.GetSubstitutions())
388  {
389  // Sub-graph optimized, substitute the sub-graph with the new optimized one in the main optimized graph
390  SubgraphView& replacementSubgraph = substitution.m_ReplacementSubgraph;
391  SubgraphView& substitutableSubgraph = substitution.m_SubstitutableSubgraph;
392  optGraph.SubstituteSubgraph(substitutableSubgraph, replacementSubgraph);
393 
394  // Assign the current backend to the optimized sub-graph
395  std::for_each(replacementSubgraph.begin(), replacementSubgraph.end(), [&selectedBackend](Layer* l)
396  {
397  BOOST_ASSERT(l);
398  l->SetBackendId(selectedBackend);
399  });
400  }
401 
402  if (!optimizationViews.GetFailedSubgraphs().empty())
403  {
404  std::stringstream warningMsg;
405  warningMsg << "Some sub-graph(s) failed to optimized on " << backendObjPtr->GetId() << " backend.";
406  ReportWarning(warningMsg.str(), errMessages);
407 
408  // Failed to optimize the given sub-graph, re-assign the sub-graph layers to other available backends
409  BackendSettings settingsCopy(backendSettings);
410  if (!backendObjPtr->GetId().IsCpuRef())
411  {
412  // Add the current backend to the list of backends to ignore
413  settingsCopy.m_IgnoredBackends.insert(backendObjPtr->GetId());
414  }
415 
416  int count=0;
417  for (auto& failedSubgraph : optimizationViews.GetFailedSubgraphs())
418  {
419  // An error occurred: the optimization was attempted but not performed, try different backends
420  std::stringstream subgraphMsg;
421  subgraphMsg << "Re-assigning backends to " << failedSubgraph.GetLayers().size()
422  << " layers inside sub-graph " << count++;
423  ReportWarning(subgraphMsg.str(), errMessages);
424 
425  OptimizationResult reassignmentResult = AssignBackends(optNetObjPtr,
426  settingsCopy,
427  *subgraph,
428  errMessages);
429  if (reassignmentResult.m_Error)
430  {
431  // Failed to re-assign one of the remaining backends to each layer of the sub-graph
432  result.m_Error = true;
433  return result;
434  }
435  }
436  }
437  }
438  }
439 
440  return result;
441 }
442 
445  TensorHandleFactoryRegistry& registry)
446 {
447  if (src != dst)
448  {
449  ITensorHandleFactory* srcFactory = registry.GetFactory(src);
450  ITensorHandleFactory* dstFactory = registry.GetFactory(dst);
451 
452  if (srcFactory && dstFactory &&
453  (srcFactory->GetExportFlags() & dstFactory->GetImportFlags()) != 0)
454  {
455  return false;
456  }
457  return true;
458  }
459  return false;
460 }
461 
462 // Find the handle factory for the input layer which results in fewest required copies.
464  OutputSlot& slot,
465  TensorHandleFactoryRegistry& registry)
466 {
467  Layer& layer = slot.GetOwningLayer();
468  BOOST_ASSERT(layer.GetType() == LayerType::Input);
469 
470  // Explicitly select the tensorhandle factory for InputLayer because the rules for it are slightly different. It
471  // doesn't matter which backend it is assigned to because they all use the same implementation, which
472  // requires Map/Unmap support. This means that, so long as the handle type supports map/unmap semantics, we can
473  // select a factory with maximum compatibility with the layers connected to the InputLayer.
474 
475  // First ensure the from backends can support the TensorHandeAPI
476  auto frmBackend = backends.find(layer.GetBackendId());
477  if (frmBackend == backends.end() ||
478  !frmBackend->second->SupportsTensorAllocatorAPI())
479  {
481  }
482 
483  // Go through all connections to the output slot and determine the TensorHandleFactory which results in the
484  // fewest copies.
485  std::map<ITensorHandleFactory::FactoryId, int> factoryScores;
486  int topScore = 0;
488 
489  for (auto&& connection : slot.GetConnections())
490  {
491  const Layer& connectedLayer = connection->GetOwningLayer();
492 
493  auto toBackend = backends.find(connectedLayer.GetBackendId());
494  BOOST_ASSERT_MSG(toBackend != backends.end(), "Backend id not found for the connected layer");
495 
496  if (!toBackend->second.get()->SupportsTensorAllocatorAPI())
497  {
498  // The destination backend does not support the tensor allocator API, move to the next one
499  continue;
500  }
501 
502  auto dstPrefs = toBackend->second.get()->GetHandleFactoryPreferences();
503  for (auto&& dst : dstPrefs)
504  {
505  // Input layers use the mem copy workload or import, so the selected factory must
506  // support either the map/unmap API or Import API
507  ITensorHandleFactory* factory = registry.GetFactory(dst);
508  if (!factory->SupportsMapUnmap() &&
509  !CheckFlag(factory->GetImportFlags(), MemorySource::Malloc)) // Just support cpu mem imports for now
510  {
511  // The current tensor handle factory does not support the map/unmap or import
512  // strategy, move to the next one
513  continue;
514  }
515 
516  auto it = factoryScores.find(dst);
517  if (it == factoryScores.end())
518  {
519  // Add new score to the table
520  factoryScores[dst] = 0;
521  if (topChoice == ITensorHandleFactory::LegacyFactoryId)
522  {
523  topChoice = dst;
524  }
525  }
526  else
527  {
528  // Increase the score
529  factoryScores[dst]++;
530 
531  // Track the best option
532  if (factoryScores[dst] > topScore)
533  {
534  topScore = factoryScores[dst];
535  topChoice = dst;
536  }
537  }
538  }
539  }
540 
541  return topChoice;
542 }
543 
544 // Find the handle factory for the output layer which results in fewest required copies.
546  OutputSlot& slot,
547  TensorHandleFactoryRegistry& registry)
548 {
549  boost::ignore_unused(backends, slot, registry);
551 }
552 
553 // For all handle factories supported on the source backend, we wish to find the one which requires the fewest copies
554 // when considering all connections.
556  OutputSlot& outputSlot,
557  TensorHandleFactoryRegistry& registry)
558 {
559  // First ensure the from backends can support the TensorHandeAPI
560  Layer& layer = outputSlot.GetOwningLayer();
561  auto frmBackend = backends.find(layer.GetBackendId());
562  if (frmBackend == backends.end() ||
563  !frmBackend->second->SupportsTensorAllocatorAPI())
564  {
566  }
567 
568  // Connections to Output Layers requires support for map/unmap on the TensorHandle.
569  bool requiresMapUnmap = false;
570  for (auto&& connection : outputSlot.GetConnections())
571  {
572  const Layer& connectedLayer = connection->GetOwningLayer();
573  if (connectedLayer.GetType() == LayerType::Output)
574  {
575  requiresMapUnmap = true;
576  }
577  }
578 
579  IBackendInternal* srcBackend = frmBackend->second.get();
580  auto srcPrefs = srcBackend->GetHandleFactoryPreferences();
581 
582  // Initialize the scores
583  std::map<ITensorHandleFactory::FactoryId, int> factoryScores;
584  for (auto&& pref : srcPrefs)
585  {
586  if (requiresMapUnmap) // Only consider factories that support map/unmap if required
587  {
588  ITensorHandleFactory* factory = registry.GetFactory(pref);
589  if (!factory->SupportsMapUnmap())
590  {
591  // The current tensor handle factory does not support the map/unmap strategy, move to the next one
592  continue;
593  }
594  }
595 
596  auto it = factoryScores.find(pref);
597  if (it == factoryScores.end())
598  {
599  // Add new score to the table
600  factoryScores[pref] = 0;
601  }
602  }
603 
604  // Score each handle factory based on how many times it requires copies on the slot connections
605  for (auto&& connection : outputSlot.GetConnections())
606  {
607  const Layer& connectedLayer = connection->GetOwningLayer();
608 
609  auto toBackend = backends.find(connectedLayer.GetBackendId());
610  BOOST_ASSERT_MSG(toBackend != backends.end(), "Backend id not found for the connected layer");
611 
612  auto dstPrefs = toBackend->second.get()->GetHandleFactoryPreferences();
613  for (auto&& src : srcPrefs)
614  {
615  if (factoryScores.find(src) == factoryScores.end()) // Don't consider excluded factories
616  {
617  continue;
618  }
619 
620  for (auto&& dst : dstPrefs)
621  {
622  if (RequiresCopy(src, dst, registry))
623  {
624  // Copy avoided, increase the score
625  factoryScores[src]++;
626  break;
627  }
628  }
629  }
630  }
631 
632  // Find the lowest score
633  int minScore = std::numeric_limits<int>::max();
634  for (auto it : factoryScores)
635  {
636  minScore = std::min(minScore, it.second);
637  }
638 
639  // Collect factories matching the best(lowest) score
640  std::vector<ITensorHandleFactory::FactoryId> optimalFactories;
641  for (auto it : factoryScores)
642  {
643  if (it.second == minScore)
644  {
645  optimalFactories.push_back(it.first);
646  }
647  }
648 
649  // For all compatible Factories matching the best score, find the preferred one for the current layer.
650  for (auto&& srcPref : srcPrefs)
651  {
652  for (auto&& comp : optimalFactories)
653  {
654  if (comp == srcPref)
655  {
656  return comp;
657  }
658  }
659  }
660 
662 }
663 
665  ITensorHandleFactory::FactoryId srcFactoryId,
666  const Layer& layer,
667  const Layer& connectedLayer,
668  TensorHandleFactoryRegistry& registry)
669 {
670  auto toBackend = backends.find(connectedLayer.GetBackendId());
671  BOOST_ASSERT_MSG(toBackend != backends.end(), "Backend id not found for the connected layer");
672 
673  auto dstPrefs = toBackend->second.get()->GetHandleFactoryPreferences();
674 
675  // Legacy API check for backward compatibility
676  if (srcFactoryId == ITensorHandleFactory::LegacyFactoryId || dstPrefs.empty())
677  {
678  if (layer.GetBackendId() != connectedLayer.GetBackendId())
679  {
681  }
682  else
683  {
685  }
686  }
687 
688  // TensorHandleFactory API present, so perform more sophisticated strategies.
689  // Dst Output layers don't require copy because they use import or map/unmap
690  if (connectedLayer.GetType() == LayerType::Output)
691  {
693  }
694 
695  // Search for direct match in prefs
696  for (auto&& pref : dstPrefs)
697  {
698  if (pref == srcFactoryId)
699  {
701  }
702  }
703 
704  // Search for export/import options
705  ITensorHandleFactory* srcFactory = registry.GetFactory(srcFactoryId);
706  if (srcFactory->GetExportFlags() != 0)
707  {
708  for (auto&& pref : dstPrefs)
709  {
710  ITensorHandleFactory* dstFactory = registry.GetFactory(pref);
711 
712  // Handles cases when a destPref is not listed in TensorHandleFactoryRegistry
713  if (!dstFactory) {
714  continue;
715  }
716 
717  if ((dstFactory->GetImportFlags() & srcFactory->GetExportFlags()) != 0)
718  {
720  }
721  }
722  }
723 
724  // Search for copy options via map/unmap
725  if (srcFactory->SupportsMapUnmap())
726  {
727  for (auto&& pref : dstPrefs)
728  {
729  ITensorHandleFactory* dstFactory = registry.GetFactory(pref);
730  if (dstFactory && dstFactory->SupportsMapUnmap())
731  {
733  }
734  }
735  }
736 
738 }
739 
740 // Select the TensorHandleFactories and the corresponding memory strategy
742  BackendsMap& backends,
743  TensorHandleFactoryRegistry& registry,
744  Optional<std::vector<std::string>&> errMessages)
745 {
746  OptimizationResult result;
747 
748  optGraph.ForEachLayer([&backends, &registry, &result, &errMessages](Layer* layer)
749  {
750  BOOST_ASSERT(layer);
751 
752  // Lets make sure the backend is in our list of supported backends. Something went wrong during backend
753  // assignment if this check fails
754  BOOST_ASSERT(backends.find(layer->GetBackendId()) != backends.end());
755 
756  // Check each output separately
757  for (unsigned int slotIdx = 0; slotIdx < layer->GetNumOutputSlots(); slotIdx++)
758  {
759  OutputSlot& outputSlot = layer->GetOutputSlot(slotIdx);
760 
762 
763  // Calculate the factory to use which results in the fewest copies being made.
764  switch(layer->GetType())
765  {
766  case LayerType::Input:
767  slotOption = CalculateSlotOptionForInput(backends, outputSlot, registry);
768  break;
769  case LayerType::Output:
770  slotOption = CalculateSlotOptionForOutput(backends, outputSlot, registry);
771  break;
772  default:
773  slotOption = CalculateSlotOption(backends, outputSlot, registry);
774  break;
775  }
776  outputSlot.SetTensorHandleFactory(slotOption);
777 
778  // Now determine the "best" edge strategy for each connection given the slotOption.
779  unsigned int connectionIdx = 0;
780  for (auto&& connection : outputSlot.GetConnections())
781  {
782  const Layer& connectedLayer = connection->GetOwningLayer();
783 
784  EdgeStrategy strategy = CalculateEdgeStrategy(backends, slotOption, *layer, connectedLayer, registry);
785 
786  if (strategy == EdgeStrategy::Undefined)
787  {
788  result.m_Error = true;
789  if (errMessages)
790  {
791  errMessages.value().emplace_back("Could not find valid strategy required for compatibility"
792  " between backends.");
793  }
794  return;
795  }
796 
797  outputSlot.SetEdgeStrategy(connectionIdx, strategy);
798 
799  connectionIdx++;
800  }
801  }
802  });
803 
804  return result;
805 }
806 
808  const std::vector<BackendId>& backendPreferences,
809  const IDeviceSpec& deviceSpec,
810  const OptimizerOptions& options,
811  Optional<std::vector<std::string>&> messages)
812 {
813  if (backendPreferences.empty())
814  {
815  throw armnn::InvalidArgumentException("Invoked Optimize with no backends specified");
816  }
817 
818  const Network& network = *boost::polymorphic_downcast<const Network*>(&inNetwork);
819  std::unique_ptr<Graph> graph = std::make_unique<Graph>(network.GetGraph());
820 
821  auto optNet = IOptimizedNetworkPtr(new OptimizedNetwork(std::move(graph)), &IOptimizedNetwork::Destroy);
822 
823  OptimizedNetwork* optNetObjPtr = boost::polymorphic_downcast<OptimizedNetwork*>(optNet.get());
824 
825  // Get the optimized graph
826  Graph& optGraph = optNetObjPtr->GetGraph();
827 
828  // Perform optimisation passes
829  using namespace optimizations;
833  MovePermuteUp(),
838 
839  // Infer the tensor infos for all output slots. Throws an exception on failure
840  optGraph.InferTensorInfos();
841 
842  // If Fp32 to Fp16 optimization is set convert Fp32 network to Fp16
843  if (options.m_ReduceFp32ToFp16)
844  {
847  }
848 
849  // Initialize backend settings
850  BackendSettings backendSettings(backendPreferences, deviceSpec);
851  if (backendSettings.GetAvailablePreferredBackends().empty())
852  {
853  std::stringstream failureMsg;
854  failureMsg << "None of the preferred backends " << backendPreferences
855  << " are supported. Current platform provides " << backendSettings.m_SupportedBackends;
856  ReportError(failureMsg.str(), messages);
858  }
859 
860  // Create a map to temporarily hold initialized backend objects
861  TensorHandleFactoryRegistry tensorHandleFactoryRegistry;
862  BackendsMap backends = CreateSupportedBackends(tensorHandleFactoryRegistry, backendSettings);
863 
864  // Assign an available backend to each layer
865  Graph::Iterator firstLayer = optGraph.begin();
866  Graph::Iterator lastLayer = optGraph.end();
867  OptimizationResult assignBackendsResult = AssignBackends(optNetObjPtr,
868  backendSettings,
869  firstLayer,
870  lastLayer,
871  messages);
872  if (assignBackendsResult.m_Error)
873  {
874  // Failed to assign a backend to each layer
876  }
877 
880 
881  // Apply the backend-specific optimizations
882  OptimizationResult backendOptimizationResult = ApplyBackendOptimizations(optNetObjPtr,
883  backendSettings,
884  backends,
885  messages);
886  if (backendOptimizationResult.m_Error)
887  {
888  // Failed to apply the backend-specific optimizations
890  }
891 
892  // If the debug flag is set, then insert a DebugLayer after each layer
893  // Doing this after applying the backend optimizations as they might have changed some layers
894  if (options.m_Debug)
895  {
897  }
898 
899  // Calculate the compatibility strategies for tensor handles
900  OptimizationResult strategyResult = SelectTensorHandleStrategy(optGraph,
901  backends,
902  tensorHandleFactoryRegistry,
903  messages);
904  if (strategyResult.m_Error)
905  {
906  // Failed to apply the backend-specific optimizations
908  }
909 
910  // Based on the tensor handle strategy determined above, insert copy layers where required.
911  optGraph.AddCompatibilityLayers(backends, tensorHandleFactoryRegistry);
912 
913  // Convert constants
916 
917  // Run backend specific optimizations (deprecated)
918  for (auto&& chosenBackend : backendSettings.m_SelectedBackends)
919  {
920  auto factoryFun = BackendRegistryInstance().GetFactory(chosenBackend);
921  auto backendPtr = factoryFun();
922  BOOST_ASSERT(backendPtr.get() != nullptr);
923 
925  auto backendSpecificOptimizations = backendPtr->GetOptimizations();
927 
928  if (!backendSpecificOptimizations.empty())
929  {
930  Optimizer::Pass(optNetObjPtr->GetGraph(), backendSpecificOptimizations);
931  }
932  }
933 
934  return optNet;
935 }
936 
938 : m_Graph(std::make_unique<Graph>()),
939  m_Guid(profiling::ProfilingService::Instance().NextGuid())
940 {
941 }
942 
944 {
945 }
946 
948 {
949  m_Graph->Print();
950  return Status::Success;
951 }
952 
954 {
955  return m_Graph->AddLayer<InputLayer>(id, name);
956 }
957 
959  const char* name)
960 {
961  return m_Graph->AddLayer<BatchToSpaceNdLayer>(batchToSpaceNdDescriptor, name);
962 }
963 
965  const char* name)
966 {
967  return m_Graph->AddLayer<ComparisonLayer>(comparisonDescriptor, name);
968 }
969 
971  const char* name)
972 {
973  return m_Graph->AddLayer<ElementwiseUnaryLayer>(elementwiseUnaryDescriptor, name);
974 }
975 
976 IConnectableLayer* Network::AddFullyConnectedLayerImpl(const FullyConnectedDescriptor& fullyConnectedDescriptor,
977  const ConstTensor& weights,
978  const Optional<ConstTensor>& biases,
979  const char* name)
980 {
981  if (fullyConnectedDescriptor.m_BiasEnabled && !biases.has_value())
982  {
983  throw InvalidArgumentException("AddFullyConnectedLayer: biases cannot be empty");
984  }
985 
986  const auto layer = m_Graph->AddLayer<FullyConnectedLayer>(fullyConnectedDescriptor, name);
987 
988  layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(weights);
989 
990  if (fullyConnectedDescriptor.m_BiasEnabled)
991  {
992  layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(biases.value());
993  }
994 
995  return layer;
996 }
997 
999  const ConstTensor& weights,
1000  const Optional<ConstTensor>& biases,
1001  const char* name)
1002 {
1003  return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, weights, biases, name);
1004 }
1005 
1007  const ConstTensor& weights,
1008  const char* name)
1009 {
1010  Optional<ConstTensor> biases;
1011  return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, weights, biases, name);
1012 }
1013 
1015  const ConstTensor& weights,
1016  const ConstTensor& biases,
1017  const char* name)
1018 {
1019  Optional<ConstTensor> optionalBiases(biases);
1020  return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, weights, optionalBiases, name);
1021 }
1022 
1024  const char* name)
1025 {
1026  return m_Graph->AddLayer<ConcatLayer>(concatDescriptor, name);
1027 }
1028 
1029 IConnectableLayer* Network::AddConvolution2dLayerImpl(const Convolution2dDescriptor& convolution2dDescriptor,
1030  const ConstTensor& weights,
1031  const Optional<ConstTensor>& biases,
1032  const char* name)
1033 {
1034  if (convolution2dDescriptor.m_BiasEnabled && !biases.has_value())
1035  {
1036  throw InvalidArgumentException("AddConvolution2dLayer: biases cannot be empty");
1037  }
1038 
1039  const auto layer = m_Graph->AddLayer<Convolution2dLayer>(convolution2dDescriptor, name);
1040 
1041  layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(weights);
1042 
1043  if (convolution2dDescriptor.m_BiasEnabled)
1044  {
1045  layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(biases.value());
1046  }
1047 
1048  return layer;
1049 }
1050 
1052  const ConstTensor& weights,
1053  const Optional<ConstTensor>& biases,
1054  const char* name)
1055 {
1056  return AddConvolution2dLayerImpl(convolution2dDescriptor, weights, biases, name);
1057 }
1058 
1060  const ConstTensor& weights,
1061  const char* name)
1062 {
1063  Optional<ConstTensor> biases;
1064  return AddConvolution2dLayerImpl(convolution2dDescriptor, weights, biases, name);
1065 }
1066 
1068  const ConstTensor& weights,
1069  const ConstTensor& biases,
1070  const char* name)
1071 {
1072  Optional<ConstTensor> optionalBiases(biases);
1073  return AddConvolution2dLayerImpl(convolution2dDescriptor, weights, optionalBiases, name);
1074 }
1075 
1076 IConnectableLayer* Network::AddDepthwiseConvolution2dLayerImpl(
1077  const DepthwiseConvolution2dDescriptor& convolution2dDescriptor,
1078  const ConstTensor& weights,
1079  const Optional<ConstTensor>& biases,
1080  const char* name)
1081 {
1082  if (convolution2dDescriptor.m_BiasEnabled && !biases.has_value())
1083  {
1084  throw InvalidArgumentException("AddDepthwiseConvolution2dLayer: biases cannot be empty");
1085  }
1086 
1087  const auto layer = m_Graph->AddLayer<DepthwiseConvolution2dLayer>(convolution2dDescriptor, name);
1088 
1089  layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(weights);
1090 
1091  if (convolution2dDescriptor.m_BiasEnabled)
1092  {
1093  layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(biases.value());
1094  }
1095 
1096  return layer;
1097 }
1098 
1100  const char* name)
1101 {
1102  return m_Graph->AddLayer<DepthToSpaceLayer>(depthToSpaceDescriptor, name);
1103 }
1104 
1106  const DepthwiseConvolution2dDescriptor& convolution2dDescriptor,
1107  const ConstTensor& weights,
1108  const Optional<ConstTensor>& biases,
1109  const char* name)
1110 {
1111  return AddDepthwiseConvolution2dLayerImpl(convolution2dDescriptor, weights, biases, name);
1112 }
1113 
1115  const DepthwiseConvolution2dDescriptor& convolution2dDescriptor,
1116  const ConstTensor& weights,
1117  const char* name)
1118 {
1119  Optional<ConstTensor> biases;
1120  return AddDepthwiseConvolution2dLayerImpl(convolution2dDescriptor, weights, biases, name);
1121 }
1122 
1124  const DepthwiseConvolution2dDescriptor& convolution2dDescriptor,
1125  const ConstTensor& weights,
1126  const ConstTensor& biases,
1127  const char* name)
1128 {
1129  Optional<ConstTensor> optionalBiases(biases);
1130  return AddDepthwiseConvolution2dLayerImpl(convolution2dDescriptor, weights, optionalBiases, name);
1131 }
1132 
1134  const ConstTensor& anchors, const char* name)
1135 {
1136  const auto layer = m_Graph->AddLayer<DetectionPostProcessLayer>(descriptor, name);
1137 
1138  layer->m_Anchors = std::make_unique<ScopedCpuTensorHandle>(anchors);
1139 
1140  return layer;
1141 }
1142 
1144  const char* name)
1145 {
1146  return m_Graph->AddLayer<PermuteLayer>(permuteDescriptor, name);
1147 }
1148 
1150  const char* name)
1151 {
1152  return m_Graph->AddLayer<Pooling2dLayer>(pooling2dDescriptor, name);
1153 }
1154 
1156  const char* name)
1157 {
1158  return m_Graph->AddLayer<ActivationLayer>(activationDescriptor, name);
1159 }
1160 
1162  const char* name)
1163 {
1164  return m_Graph->AddLayer<ArgMinMaxLayer>(argMinMaxDescriptor, name);
1165 }
1166 
1168 normalizationDescriptor,
1169  const char* name)
1170 {
1171  return m_Graph->AddLayer<NormalizationLayer>(normalizationDescriptor, name);
1172 }
1173 
1174 IConnectableLayer* Network::AddSliceLayer(const SliceDescriptor& sliceDescriptor, const char* name)
1175 {
1176  return m_Graph->AddLayer<SliceLayer>(sliceDescriptor, name);
1177 }
1178 
1180  const char* name)
1181 {
1182  return m_Graph->AddLayer<SoftmaxLayer>(softmaxDescriptor, name);
1183 }
1184 
1186  const char* name)
1187 {
1188  return m_Graph->AddLayer<SplitterLayer>(splitterDescriptor, name);
1189 }
1190 
1192 {
1193  return m_Graph->AddLayer<MaximumLayer>(name);
1194 }
1195 
1197 {
1198  return m_Graph->AddLayer<MinimumLayer>(name);
1199 }
1200 
1202  const char* name)
1203 {
1204  return AddConcatLayer(mergerDescriptor, name);
1205 }
1206 
1208 {
1210 }
1211 
1213 {
1214  return m_Graph->AddLayer<AdditionLayer>(name);
1215 }
1216 
1218 {
1219  return m_Graph->AddLayer<MultiplicationLayer>(name);
1220 }
1221 
1223 {
1224  return m_Graph->AddLayer<OutputLayer>(id, name);
1225 }
1226 
1228  const ConstTensor& mean,
1229  const ConstTensor& variance,
1230  const ConstTensor& beta,
1231  const ConstTensor& gamma,
1232  const char* name)
1233 {
1234  const auto layer = m_Graph->AddLayer<BatchNormalizationLayer>(desc, name);
1235 
1236  layer->m_Mean = std::make_unique<ScopedCpuTensorHandle>(mean);
1237  layer->m_Variance = std::make_unique<ScopedCpuTensorHandle>(variance);
1238  layer->m_Beta = std::make_unique<ScopedCpuTensorHandle>(beta);
1239  layer->m_Gamma = std::make_unique<ScopedCpuTensorHandle>(gamma);
1240 
1241  return layer;
1242 }
1243 
1245  const char* name)
1246 {
1247  ResizeDescriptor resizeDescriptor;
1248  resizeDescriptor.m_Method = ResizeMethod::Bilinear;
1249  resizeDescriptor.m_DataLayout = descriptor.m_DataLayout;
1250  resizeDescriptor.m_TargetWidth = descriptor.m_TargetWidth;
1251  resizeDescriptor.m_TargetHeight = descriptor.m_TargetHeight;
1252 
1253  return m_Graph->AddLayer<ResizeLayer>(resizeDescriptor, name);
1254 }
1255 
1257 resizeDescriptor, const char* name)
1258 {
1259  return m_Graph->AddLayer<ResizeLayer>(resizeDescriptor, name);
1260 }
1261 
1263  const char* name)
1264 {
1265  return m_Graph->AddLayer<InstanceNormalizationLayer>(desc, name);
1266 }
1267 
1269  const char* name)
1270 {
1271  return m_Graph->AddLayer<L2NormalizationLayer>(desc, name);
1272 }
1273 
1275  const char* name)
1276 {
1277  return m_Graph->AddLayer<LogSoftmaxLayer>(desc, name);
1278 }
1279 
1281 {
1282  auto layer = m_Graph->AddLayer<ConstantLayer>(name);
1283 
1284  layer->m_LayerOutput = std::make_unique<ScopedCpuTensorHandle>(input);
1285 
1286  return layer;
1287 }
1288 
1290  const char* name)
1291 {
1292  return m_Graph->AddLayer<ReshapeLayer>(reshapeDescriptor, name);
1293 }
1294 
1296  const char* name)
1297 {
1298  return m_Graph->AddLayer<SpaceToBatchNdLayer>(spaceToBatchNdDescriptor, name);
1299 }
1300 
1302  const char* name)
1303 {
1304  return m_Graph->AddLayer<SpaceToDepthLayer>(spaceToDepthDescriptor, name);
1305 }
1306 
1308 {
1309  return m_Graph->AddLayer<FloorLayer>(name);
1310 }
1311 
1313  const LstmInputParams& params,
1314  const char* name)
1315 {
1316  const auto layer = m_Graph->AddLayer<LstmLayer>(descriptor, name);
1317 
1318  //Lstm Basic Parameters
1320  std::make_unique<ScopedCpuTensorHandle>(*(params.m_InputToForgetWeights));
1321  layer->m_BasicParameters.m_InputToCellWeights =
1322  std::make_unique<ScopedCpuTensorHandle>(*(params.m_InputToCellWeights));
1323  layer->m_BasicParameters.m_InputToOutputWeights =
1324  std::make_unique<ScopedCpuTensorHandle>(*(params.m_InputToOutputWeights));
1325  layer->m_BasicParameters.m_RecurrentToForgetWeights =
1326  std::make_unique<ScopedCpuTensorHandle>(*(params.m_RecurrentToForgetWeights));
1327  layer->m_BasicParameters.m_RecurrentToCellWeights =
1328  std::make_unique<ScopedCpuTensorHandle>(*(params.m_RecurrentToCellWeights));
1329  layer->m_BasicParameters.m_RecurrentToOutputWeights =
1330  std::make_unique<ScopedCpuTensorHandle>(*(params.m_RecurrentToOutputWeights));
1331  layer->m_BasicParameters.m_ForgetGateBias =
1332  std::make_unique<ScopedCpuTensorHandle>(*(params.m_ForgetGateBias));
1333  layer->m_BasicParameters.m_CellBias =
1334  std::make_unique<ScopedCpuTensorHandle>(*(params.m_CellBias));
1335  layer->m_BasicParameters.m_OutputGateBias =
1336  std::make_unique<ScopedCpuTensorHandle>(*(params.m_OutputGateBias));
1337 
1338  //Lstm Cifg parameters
1339  if(!descriptor.m_CifgEnabled)
1340  {
1341  if(params.m_InputToInputWeights == nullptr)
1342  {
1343  throw InvalidArgumentException("AddLstmLayer: Input To Input Weights cannot be NULL");
1344  }
1345  if(params.m_RecurrentToInputWeights == nullptr)
1346  {
1348  "AddLstmLayer: Recurrent To Input Weights cannot be NULL");
1349  }
1350  if(params.m_InputGateBias == nullptr)
1351  {
1352  throw InvalidArgumentException("AddLstmLayer: Input Gate Bias cannot be NULL");
1353  }
1354  layer->m_CifgParameters.m_InputToInputWeights =
1355  std::make_unique<ScopedCpuTensorHandle>(*(params.m_InputToInputWeights));
1356  layer->m_CifgParameters.m_RecurrentToInputWeights =
1357  std::make_unique<ScopedCpuTensorHandle>(*(params.m_RecurrentToInputWeights));
1358  // In the VTS tests, cell-to-input weights may be null, even if the other CIFG params are not.
1359  if(params.m_CellToInputWeights != nullptr)
1360  {
1361  layer->m_CifgParameters.m_CellToInputWeights =
1362  std::make_unique<ScopedCpuTensorHandle>(*(params.m_CellToInputWeights));
1363  }
1364  layer->m_CifgParameters.m_InputGateBias =
1365  std::make_unique<ScopedCpuTensorHandle>(*(params.m_InputGateBias));
1366  }
1367 
1368  //Lstm projection parameters
1369  if(descriptor.m_ProjectionEnabled)
1370  {
1371  if(params.m_ProjectionWeights == nullptr)
1372  {
1373  throw InvalidArgumentException("AddLstmLayer: Projection Weights cannot be NULL");
1374  }
1375  layer->m_ProjectionParameters.m_ProjectionWeights =
1376  std::make_unique<ScopedCpuTensorHandle>(*(params.m_ProjectionWeights));
1377  if(params.m_ProjectionBias != nullptr)
1378  {
1379  layer->m_ProjectionParameters.m_ProjectionBias =
1380  std::make_unique<ScopedCpuTensorHandle>(*(params.m_ProjectionBias));
1381  }
1382  }
1383 
1384  //Lstm Peephole params
1385  if(descriptor.m_PeepholeEnabled)
1386  {
1387  if(params.m_CellToForgetWeights == nullptr)
1388  {
1389  throw InvalidArgumentException("AddLstmLayer: Cell To Forget Weights cannot be NULL");
1390  }
1391  if(params.m_CellToOutputWeights == nullptr)
1392  {
1393  throw InvalidArgumentException("AddLstmLayer: Cell To Output Weights cannot be NULL");
1394  }
1395  layer->m_PeepholeParameters.m_CellToForgetWeights =
1396  std::make_unique<ScopedCpuTensorHandle>(*(params.m_CellToForgetWeights));
1397  layer->m_PeepholeParameters.m_CellToOutputWeights =
1398  std::make_unique<ScopedCpuTensorHandle>(*(params.m_CellToOutputWeights));
1399  }
1400 
1401  //Lstm Layer Normalization params
1402  if(descriptor.m_LayerNormEnabled)
1403  {
1404  if(!descriptor.m_CifgEnabled)
1405  {
1406  if(params.m_InputLayerNormWeights == nullptr)
1407  {
1408  throw InvalidArgumentException("AddLstmLayer: Input layer normalization weights cannot be NULL");
1409  }
1410  layer->m_LayerNormParameters.m_InputLayerNormWeights =
1411  std::make_unique<ScopedCpuTensorHandle>(*(params.m_InputLayerNormWeights));
1412  }
1413 
1414  if(params.m_ForgetLayerNormWeights == nullptr)
1415  {
1416  throw InvalidArgumentException("AddLstmLayer: Forget layer normalization weights cannot be NULL");
1417  }
1418  if(params.m_CellLayerNormWeights == nullptr)
1419  {
1420  throw InvalidArgumentException("AddLstmLayer: Cell layer normalization weights cannot be NULL");
1421  }
1422  if(params.m_OutputLayerNormWeights == nullptr)
1423  {
1424  throw InvalidArgumentException("AddLstmLayer: Output layer normalization weights cannot be NULL");
1425  }
1426  layer->m_LayerNormParameters.m_ForgetLayerNormWeights =
1427  std::make_unique<ScopedCpuTensorHandle>(*(params.m_ForgetLayerNormWeights));
1428  layer->m_LayerNormParameters.m_CellLayerNormWeights =
1429  std::make_unique<ScopedCpuTensorHandle>(*(params.m_CellLayerNormWeights));
1430  layer->m_LayerNormParameters.m_OutputLayerNormWeights =
1431  std::make_unique<ScopedCpuTensorHandle>(*(params.m_OutputLayerNormWeights));
1432  }
1433  return layer;
1434 }
1435 
1437 {
1438  return m_Graph->AddLayer<DivisionLayer>(name);
1439 }
1440 
1442 {
1443  return m_Graph->AddLayer<SubtractionLayer>(name);
1444 }
1445 
1446 IConnectableLayer* Network::AddMeanLayer(const MeanDescriptor& meanDescriptor, const char* name)
1447 {
1448  return m_Graph->AddLayer<MeanLayer>(meanDescriptor,name);
1449 }
1450 
1451 IConnectableLayer* Network::AddPadLayer(const PadDescriptor& padDescriptor, const char* name)
1452 {
1453  return m_Graph->AddLayer<PadLayer>(padDescriptor,name);
1454 }
1455 
1457 {
1458  return m_Graph->AddLayer<QuantizeLayer>(name);
1459 }
1460 
1462 {
1463  return m_Graph->AddLayer<DequantizeLayer>(name);
1464 }
1465 
1467  const char* name)
1468 {
1469  return m_Graph->AddLayer<StridedSliceLayer>(stridedSliceDescriptor, name);
1470 }
1471 
1473 {
1475 }
1476 
1478 {
1480 }
1481 
1483 {
1485 }
1486 
1488 {
1489  return m_Graph->AddLayer<GatherLayer>(name);
1490 }
1491 
1493 {
1494  return m_Graph->AddLayer<MergeLayer>(name);
1495 }
1496 
1498 {
1499  return m_Graph->AddLayer<SwitchLayer>(name);
1500 }
1501 
1503 {
1504  return m_Graph->AddLayer<PreluLayer>(name);
1505 }
1506 
1508  const ConstTensor& weights,
1509  const Optional<ConstTensor>& biases,
1510  const char* name)
1511 {
1512  if (descriptor.m_BiasEnabled && !biases.has_value())
1513  {
1514  throw InvalidArgumentException("AddTransposeConvolution2dLayer: Biases cannot be empty");
1515  }
1516 
1517  const auto layer = m_Graph->AddLayer<TransposeConvolution2dLayer>(descriptor, name);
1518 
1519  layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(weights);
1520 
1521  if (descriptor.m_BiasEnabled)
1522  {
1523  layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(biases.value());
1524  }
1525 
1526  return layer;
1527 }
1528 
1530  const char* name)
1531 {
1532  return m_Graph->AddLayer<StackLayer>(stackDescriptor, name);
1533 }
1534 
1535 
1537  const char* name)
1538 {
1539  return m_Graph->AddLayer<StandInLayer>(desc, name);
1540 }
1541 
1543  const char* name)
1544 {
1545  const auto layer = m_Graph->AddLayer<QuantizedLstmLayer>(name);
1546 
1547  // InputToX weights
1549  std::make_unique<ScopedCpuTensorHandle>(params.GetInputToInputWeights());
1550  layer->m_QuantizedLstmParameters.m_InputToForgetWeights =
1551  std::make_unique<ScopedCpuTensorHandle>(params.GetInputToForgetWeights());
1552  layer->m_QuantizedLstmParameters.m_InputToCellWeights =
1553  std::make_unique<ScopedCpuTensorHandle>(params.GetInputToCellWeights());
1554  layer->m_QuantizedLstmParameters.m_InputToOutputWeights =
1555  std::make_unique<ScopedCpuTensorHandle>(params.GetInputToOutputWeights());
1556 
1557  // RecurrentToX weights
1558  layer->m_QuantizedLstmParameters.m_RecurrentToInputWeights =
1559  std::make_unique<ScopedCpuTensorHandle>(params.GetRecurrentToInputWeights());
1560  layer->m_QuantizedLstmParameters.m_RecurrentToForgetWeights =
1561  std::make_unique<ScopedCpuTensorHandle>(params.GetRecurrentToForgetWeights());
1562  layer->m_QuantizedLstmParameters.m_RecurrentToCellWeights =
1563  std::make_unique<ScopedCpuTensorHandle>(params.GetRecurrentToCellWeights());
1564  layer->m_QuantizedLstmParameters.m_RecurrentToOutputWeights =
1565  std::make_unique<ScopedCpuTensorHandle>(params.GetRecurrentToOutputWeights());
1566 
1567  // Bias
1568  layer->m_QuantizedLstmParameters.m_InputGateBias =
1569  std::make_unique<ScopedCpuTensorHandle>(params.GetInputGateBias());
1570  layer->m_QuantizedLstmParameters.m_ForgetGateBias =
1571  std::make_unique<ScopedCpuTensorHandle>(params.GetForgetGateBias());
1572  layer->m_QuantizedLstmParameters.m_CellBias =
1573  std::make_unique<ScopedCpuTensorHandle>(params.GetCellBias());
1574  layer->m_QuantizedLstmParameters.m_OutputGateBias =
1575  std::make_unique<ScopedCpuTensorHandle>(params.GetOutputGateBias());
1576 
1577  return layer;
1578 }
1579 
1580 void Network::Accept(ILayerVisitor& visitor) const
1581 {
1582  for (auto layer : GetGraph())
1583  {
1584  layer->Accept(visitor);
1585  };
1586 }
1587 
1588 OptimizedNetwork::OptimizedNetwork(std::unique_ptr<Graph> graph)
1589  : m_Graph(std::move(graph)),
1590  m_Guid(profiling::ProfilingService::Instance().NextGuid())
1591 {
1592 }
1593 
1595 {
1596 }
1597 
1598 } // namespace armnn
const ConstTensor & GetInputToForgetWeights() const
This layer represents a subtraction operation.
BackendIdSet m_SupportedBackends
IConnectableLayer * AddReshapeLayer(const ReshapeDescriptor &reshapeDescriptor, const char *name=nullptr) override
Definition: Network.cpp:1289
OptimizeForConnection< Layer, ReshapeLayer, SquashEqualSiblingsImpl< ReshapeLayer > > SquashEqualReshapeSiblings
EdgeStrategy CalculateEdgeStrategy(BackendsMap &backends, ITensorHandleFactory::FactoryId srcFactoryId, const Layer &layer, const Layer &connectedLayer, TensorHandleFactoryRegistry &registry)
Definition: Network.cpp:664
This layer represents a pad operation.
Definition: PadLayer.hpp:14
std::unique_ptr< ScopedCpuTensorHandle > m_Weight
A unique pointer to store Weight values.
This layer dequantizes the input tensor.
Definition: MergeLayer.hpp:13
const ConstTensor * m_InputToOutputWeights
Definition: LstmParams.hpp:43
std::unique_ptr< ScopedCpuTensorHandle > m_Anchors
A unique pointer to store Anchor values.
unsigned int GetNumOutputSlots() const override
Definition: Layer.hpp:308
const ConstTensor & GetInputGateBias() const
This layer represents a DepthToSpace operation.
const ConstTensor * m_CellToForgetWeights
Definition: LstmParams.hpp:49
This layer represents a BatchToSpaceNd operation.
This layer represents a 2D transpose convolution operation.
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
FactoryFunction GetFactory(const BackendId &id) const
LayerType GetType() const
Definition: Layer.hpp:259
int32_t GetQuantizationOffset() const
Definition: Tensor.cpp:264
A BatchToSpaceNdDescriptor for the BatchToSpaceNdLayer.
Status
Definition: Types.hpp:26
IConnectableLayer * AddSplitterLayer(const ViewsDescriptor &splitterDescriptor, const char *name=nullptr) override
Definition: Network.cpp:1185
A NormalizationDescriptor for the NormalizationLayer.
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
Definition: Tensor.hpp:199
IConnectableLayer * AddMaximumLayer(const char *name=nullptr) override
Definition: Network.cpp:1191
IConnectableLayer * AddInputLayer(LayerBindingId id, const char *name=nullptr) override
Definition: Network.cpp:953
const ConstTensor * m_InputToForgetWeights
Definition: LstmParams.hpp:41
char const * GetLayerTypeAsCString(LayerType type)
BackendsMap CreateSupportedBackends(TensorHandleFactoryRegistry &handleFactoryRegistry, BackendSettings &backendSettings)
Definition: Network.cpp:326
This layer represents a batch normalization operation.
const Subgraphs & GetFailedSubgraphs() const
IOptimizedNetworkPtr Optimize(const INetwork &network, const std::vector< BackendId > &backendPreferences, const IDeviceSpec &deviceSpec, const OptimizerOptions &options=OptimizerOptions(), Optional< std::vector< std::string > &> messages=EmptyOptional())
Definition: Network.cpp:807
IConnectableLayer * AddL2NormalizationLayer(const L2NormalizationDescriptor &desc, const char *name=nullptr) override
Definition: Network.cpp:1268
virtual bool SupportsMapUnmap() const final
void SetEdgeStrategy(unsigned int connectionIndex, EdgeStrategy strategy)
Definition: Layer.cpp:177
BackendIdSet m_SelectedBackends
ConvertConstants< Float32ToFloat16, IsFloat16Layer > ConvertConstantsFloatToHalf
IConnectableLayer * AddMergeLayer(const char *name=nullptr) override
Definition: Network.cpp:1492
This layer represents a detection postprocess operator.
OptimizeForConnection< PermuteLayer, BatchToSpaceNdLayer, PermuteAndBatchToSpaceAsDepthToSpaceImpl > PermuteAndBatchToSpaceAsDepthToSpace
uint32_t m_TargetHeight
Target height value.
const ConstTensor & GetOutputGateBias() const
No strategy has been defined. Used internally to verify integrity of optimizations.
This layer represents a maximum operation.
void Accept(ILayerVisitor &visitor) const override
Definition: Network.cpp:1580
This layer represents a minimum operation.
This layer represents a depthwise convolution 2d operation.
This layer represents a convolution 2d operation.
const ConstTensor * m_RecurrentToOutputWeights
Definition: LstmParams.hpp:47
IConnectableLayer * AddGatherLayer(const char *name=nullptr) override
Definition: Network.cpp:1487
std::unique_ptr< ScopedCpuTensorHandle > m_Weight
A unique pointer to store Weight values.
This layer represents a softmax operation.
This layer represents a stack operation.
Definition: StackLayer.hpp:13
const ConstTensor & GetForgetGateBias() const
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
This layer converts data type Float 32 to Float 16.
A PadDescriptor for the PadLayer.
An ActivationDescriptor for the ActivationLayer.
Definition: Descriptors.hpp:20
IConnectableLayer * AddGreaterLayer(const char *name=nullptr) override
Definition: Network.cpp:1472
A BatchNormalizationDescriptor for the BatchNormalizationLayer.
static void Destroy(INetwork *network)
Definition: Network.cpp:53
ITensorHandleFactory::FactoryId CalculateSlotOption(BackendsMap &backends, OutputSlot &outputSlot, TensorHandleFactoryRegistry &registry)
Definition: Network.cpp:555
OptimizeForConnection< ConvertFp32ToFp16Layer, ConvertFp16ToFp32Layer, OptimizeInverseConversionsImpl > OptimizeInverseConversionsFp32
OptimizeForConnection< ReshapeLayer, ReshapeLayer, OptimizeConsecutiveReshapesImpl > OptimizeConsecutiveReshapes
This layer represents a log softmax operation.
const ConstTensor * m_OutputLayerNormWeights
Definition: LstmParams.hpp:60
Source backends tensor data can be exported to destination backend tensor without copy...
This layer represents a SpaceToDepth operation.
This layer represents a reshape operation.
static Subgraphs SelectSubgraphs(Graph &graph, const LayerSelectorFunction &selector)
static void Pass(Graph &graph, const Optimizations &optimizations)
Definition: Optimizer.cpp:16
uint32_t m_TargetWidth
Target width value.
This layer represents a ArgMinMax operation.
IConnectableLayer * AddAdditionLayer(const char *name=nullptr) override
Definition: Network.cpp:1212
const BackendId & GetBackendId() const
Definition: Layer.hpp:263
This layer represents a pooling 2d operation.
This layer represents a floor operation.
Definition: FloorLayer.hpp:13
const ConstTensor & GetRecurrentToInputWeights() const
const std::string & GetNameStr() const
Definition: Layer.hpp:216
This layer represents a merge operation.
Definition: ConcatLayer.hpp:13
const ConstTensor & GetCellBias() const
IConnectableLayer * AddEqualLayer(const char *name=nullptr) override
Definition: Network.cpp:1477
This layer represents a multiplication operation.
const ConstTensor & GetRecurrentToOutputWeights() const
const ConstTensor * m_InputLayerNormWeights
Definition: LstmParams.hpp:57
A L2NormalizationDescriptor for the L2NormalizationLayer.
static void Destroy(IOptimizedNetwork *network)
Definition: Network.cpp:58
static const FactoryId LegacyFactoryId
bool m_BiasEnabled
Enable/disable bias.
A ViewsDescriptor for the SplitterLayer. Descriptor to configure the splitting process. Number of Views must be equal to the number of outputs, and their order must match - e.g. first view corresponds to the first output, second view to the second output, etc.
IConnectableLayer * AddElementwiseUnaryLayer(const ElementwiseUnaryDescriptor &elementwiseUnaryDescriptor, const char *name=nullptr) override
Definition: Network.cpp:970
IConnectableLayer * AddDequantizeLayer(const char *name=nullptr) override
Definition: Network.cpp:1461
This layer represents a SpaceToBatchNd operation.
std::unique_ptr< ScopedCpuTensorHandle > m_Weight
A unique pointer to store Weight values.
OptimizeForType< Layer, ConvertFp32NetworkToFp16Impl > Fp32NetworkToFp16Converter
OptimizeForConnection< PadLayer, Convolution2dLayer, FoldPadIntoConvolution2dImpl > FoldPadIntoConvolution2d
IConnectableLayer * AddPooling2dLayer(const Pooling2dDescriptor &pooling2dDescriptor, const char *name=nullptr) override
Definition: Network.cpp:1149
IConnectableLayer * AddStandInLayer(const StandInDescriptor &descriptor, const char *name=nullptr) override
Definition: Network.cpp:1536
IConnectableLayer * AddLogSoftmaxLayer(const LogSoftmaxDescriptor &logSoftmaxDescriptor, const char *name=nullptr) override
Definition: Network.cpp:1274
const ConstTensor & GetInputToInputWeights() const
IConnectableLayer * AddDivisionLayer(const char *name=nullptr) override
Definition: Network.cpp:1436
std::vector< ConvertFp32ToFp16Layer * > InsertConvertFp32ToFp16LayersAfter(Graph &graph, Layer &layer)
A SpaceToDepthDescriptor for the SpaceToDepthLayer.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
#define ARMNN_LOG(severity)
Definition: Logging.hpp:163
This layer represents a fully connected operation.
OptimizationResult SelectTensorHandleStrategy(Graph &optGraph, BackendsMap &backends, TensorHandleFactoryRegistry &registry, Optional< std::vector< std::string > &> errMessages)
Definition: Network.cpp:741
A ReshapeDescriptor for the ReshapeLayer.
A TransposeConvolution2dDescriptor for the TransposeConvolution2dLayer.
IConnectableLayer * AddResizeLayer(const ResizeDescriptor &resizeDescriptor, const char *name=nullptr) override
Definition: Network.cpp:1256
std::vector< SubgraphViewPtr > Subgraphs
ITensorHandleFactory * GetFactory(ITensorHandleFactory::FactoryId id) const
bool CheckFlag(MemorySourceFlags flags, MemorySource source)
A ElementwiseUnaryDescriptor for the ElementwiseUnaryLayer.
Definition: Descriptors.hpp:82
const ConstTensor * m_CellBias
Definition: LstmParams.hpp:53
const ConstTensor * m_ForgetLayerNormWeights
Definition: LstmParams.hpp:58
IConnectableLayer * AddActivationLayer(const ActivationDescriptor &activationDescriptor, const char *name=nullptr) override
Definition: Network.cpp:1155
IConnectableLayer * AddLstmLayer(const LstmDescriptor &descriptor, const LstmInputParams &params, const char *name=nullptr) override
Definition: Network.cpp:1312
OptimizeForConnection< Layer, PermuteLayer, MovePermuteUpImpl > MovePermuteUp
const ConstTensor * m_OutputGateBias
Definition: LstmParams.hpp:54
void SetBackendId(const BackendId &id)
Definition: Layer.hpp:264
IConnectableLayer * AddMultiplicationLayer(const char *name=nullptr) override
Definition: Network.cpp:1217
This layer represents an activation operation with the specified activation function.
void ReportWarning(const std::string &warningMessage, Optional< std::vector< std::string > &> warningMessages)
Definition: Network.cpp:86
IConnectableLayer * AddMinimumLayer(const char *name=nullptr) override
Definition: Network.cpp:1196
IConnectableLayer * AddMergerLayer(const MergerDescriptor &mergerDescriptor, const char *name=nullptr) override
Definition: Network.cpp:1201
static const FactoryId DeferredFactoryId
ConvertConstants< Float16ToFloat32, IsFloat32Layer > ConvertConstantsHalfToFloat
#define ARMNN_NO_DEPRECATE_WARN_BEGIN
Definition: Deprecated.hpp:33
This layer represents a split operation.
Private implementation of INetwork.
Definition: Network.hpp:27
const ConstTensor * m_InputToCellWeights
Definition: LstmParams.hpp:42
std::unique_ptr< ScopedCpuTensorHandle > m_InputToInputWeights
A unique pointer to represent 2D weights tensor with dimensions [outputSize, inputSize] (QAsymm8)...
BackendRegistry & BackendRegistryInstance()
const ConstTensor & GetRecurrentToForgetWeights() const
std::map< BackendId, std::unique_ptr< class IBackendInternal > > BackendsMap
Definition: Network.hpp:292
virtual MemorySourceFlags GetExportFlags() const
OptimizeForConnection< Layer, PermuteLayer, SquashEqualSiblingsImpl< PermuteLayer > > SquashEqualPermuteSiblings
IConnectableLayer * AddSpaceToBatchNdLayer(const SpaceToBatchNdDescriptor &spaceToBatchNdDescriptor, const char *name=nullptr) override
Definition: Network.cpp:1295
std::unique_ptr< ScopedCpuTensorHandle > m_InputToForgetWeights
A unique pointer to represent 2D weights tensor with dimensions [input_size, num_units].
Definition: LstmLayer.hpp:57
ITensorHandleFactory::FactoryId CalculateSlotOptionForOutput(BackendsMap &backends, OutputSlot &slot, TensorHandleFactoryRegistry &registry)
Definition: Network.cpp:545
const ConstTensor * m_RecurrentToCellWeights
Definition: LstmParams.hpp:46
LstmBasicParameters m_BasicParameters
Definition: LstmLayer.hpp:81
IConnectableLayer * AddPreluLayer(const char *name=nullptr) override
Definition: Network.cpp:1502
const Substitutions & GetSubstitutions() const
const ConstTensor * m_ProjectionWeights
Definition: LstmParams.hpp:55
IConnectableLayer * AddComparisonLayer(const ComparisonDescriptor &comparisonDescriptor, const char *name=nullptr) override
Definition: Network.cpp:964
bool RequiresCopy(ITensorHandleFactory::FactoryId src, ITensorHandleFactory::FactoryId dst, TensorHandleFactoryRegistry &registry)
Definition: Network.cpp:443
void SetTensorInfo(const TensorInfo &tensorInfo) override
Definition: Layer.cpp:58
An LstmDescriptor for the LstmLayer.
OptimizedNetwork(std::unique_ptr< Graph > graph)
Definition: Network.cpp:1588
This layer represents a division operation.
IConnectableLayer * AddResizeBilinearLayer(const ResizeBilinearDescriptor &resizeDesc, const char *name=nullptr) override
Definition: Network.cpp:1244
IConnectableLayer * AddSliceLayer(const SliceDescriptor &sliceDescriptor, const char *name=nullptr) override
Definition: Network.cpp:1174
This layer represents a permutation operation.
IConnectableLayer * AddPermuteLayer(const PermuteDescriptor &permuteDescriptor, const char *name=nullptr) override
Definition: Network.cpp:1143
OptimizeForConnection< ConvertFp16ToFp32Layer, ConvertFp32ToFp16Layer, OptimizeInverseConversionsImpl > OptimizeInverseConversionsFp16
const ConstTensor * m_CellToInputWeights
Definition: LstmParams.hpp:48
void SetQuantizationScale(float scale)
Definition: Tensor.cpp:259
void ReportError(const std::string &errorMessage, Optional< std::vector< std::string > &> errorMessages)
Definition: Network.cpp:74
IConnectableLayer * AddRsqrtLayer(const char *name=nullptr) override
Definition: Network.cpp:1482
static INetworkPtr Create()
Definition: Network.cpp:48
An InstanceNormalizationDescriptor for InstanceNormalizationLayer.
IConnectableLayer * AddMeanLayer(const MeanDescriptor &meanDescriptor, const char *name=nullptr) override
Definition: Network.cpp:1446
const std::vector< InputSlot * > & GetConnections() const
Definition: Layer.hpp:125
Destination backend can work directly with tensors on source backend.
void ForEachLayer(Func func) const
Definition: Graph.hpp:39
Status PrintGraph() override
Definition: Network.cpp:63
A FullyConnectedDescriptor for the FullyConnectedLayer.
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: OutputLayer.hpp:13
IConnectableLayer * AddSoftmaxLayer(const SoftmaxDescriptor &softmaxDescriptor, const char *name=nullptr) override
Definition: Network.cpp:1179
std::unique_ptr< ScopedCpuTensorHandle > m_LayerOutput
IConnectableLayer * AddQuantizedLstmLayer(const QuantizedLstmInputParams &params, const char *name=nullptr) override
Definition: Network.cpp:1542
This layer represents a normalization operation.
ITensorHandleFactory::FactoryId CalculateSlotOptionForInput(BackendsMap &backends, OutputSlot &slot, TensorHandleFactoryRegistry &registry)
Definition: Network.cpp:463
IConnectableLayer * AddConvolution2dLayer(const Convolution2dDescriptor &convolution2dDescriptor, const ConstTensor &weights, const Optional< ConstTensor > &biases, const char *name=nullptr) override
Definition: Network.cpp:1051
const ConstTensor * m_RecurrentToForgetWeights
Definition: LstmParams.hpp:45
This layer represents a Gather operator.
Definition: GatherLayer.hpp:14
void SubstituteSubgraph(SubgraphView &subgraph, IConnectableLayer *substituteLayer)
Definition: Graph.cpp:396
IConnectableLayer * AddTransposeConvolution2dLayer(const TransposeConvolution2dDescriptor &descriptor, const ConstTensor &weights, const Optional< ConstTensor > &biases, const char *name=nullptr) override
Definition: Network.cpp:1507
std::unique_ptr< INetwork, void(*)(INetwork *network)> INetworkPtr
Definition: INetwork.hpp:85
A layer that the constant data can be bound to.
bool CheckScaleSetOnQuantizedType(Layer *layer, Optional< std::vector< std::string > &> errMessages)
Definition: Network.cpp:98
CPU Execution: Reference C++ kernels.
bool m_BiasEnabled
Enable/disable bias.
const ConstTensor * m_CellLayerNormWeights
Definition: LstmParams.hpp:59
const ConstTensor & GetInputToCellWeights() const
const ConstTensor & GetRecurrentToCellWeights() const
bool Validate(const SubgraphView &originalSubgraph) const
const Graph & GetGraph() const
Definition: Network.hpp:33
IConnectableLayer * AddStackLayer(const StackDescriptor &stackDescriptor, const char *name=nullptr) override
Definition: Network.cpp:1529
IConnectableLayer * AddAbsLayer(const char *name=nullptr) override
Definition: Network.cpp:1207
QuantizedLstmParameters m_QuantizedLstmParameters
const ConstTensor * m_RecurrentToInputWeights
Definition: LstmParams.hpp:44
Optimizer::Optimizations MakeOptimizations(Args &&... args)
Definition: Optimizer.hpp:43
This layer represents a LSTM operation.
Definition: LstmLayer.hpp:77
A StackDescriptor for the StackLayer.
OptimizationResult AssignBackends(OptimizedNetwork *optNetObjPtr, BackendSettings &backendSettings, Graph::Iterator &firstLayer, Graph::Iterator &lastLayer, Optional< std::vector< std::string > &> errMessages)
Definition: Network.cpp:133
A ResizeBilinearDescriptor for the ResizeBilinearLayer.
A SoftmaxDescriptor for the SoftmaxLayer.
IConnectableLayer * AddQuantizeLayer(const char *name=nullptr) override
Definition: Network.cpp:1456
uint32_t m_TargetWidth
Target width value.
const ConstTensor * m_ForgetGateBias
Definition: LstmParams.hpp:52
const ConstTensor * m_InputGateBias
Definition: LstmParams.hpp:51
LayerList::const_iterator Iterator
Definition: Graph.hpp:50
This layer represents a mean operation.
Definition: MeanLayer.hpp:14
Status PrintGraph() override
Definition: Network.cpp:947
OptimizationResult ApplyBackendOptimizations(OptimizedNetwork *optNetObjPtr, BackendSettings &backendSettings, BackendsMap &backends, Optional< std::vector< std::string > &> errMessages)
Definition: Network.cpp:345
bool m_BiasEnabled
Enable/disable bias.
DataType
Definition: Types.hpp:32
IConnectableLayer * AddPadLayer(const PadDescriptor &padDescriptor, const char *name=nullptr) override
Definition: Network.cpp:1451
IConnectableLayer * AddSwitchLayer(const char *name=nullptr) override
Definition: Network.cpp:1497
IConnectableLayer * AddDepthToSpaceLayer(const DepthToSpaceDescriptor &depthToSpaceDescriptor, const char *name=nullptr) override
Definition: Network.cpp:1099
std::vector< float > anchors({ 0.5f, 0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 1.0f, 1.0f, 0.5f, 0.5f, 1.0f, 1.0f, 0.5f, 10.5f, 1.0f, 1.0f, 0.5f, 10.5f, 1.0f, 1.0f, 0.5f, 100.5f, 1.0f, 1.0f })
This layer represents a elementwiseUnary operation.
static INetwork * CreateRaw()
Definition: Network.cpp:43
This layer represents an addition operation.
IConnectableLayer * AddDepthwiseConvolution2dLayer(const DepthwiseConvolution2dDescriptor &convolution2dDescriptor, const ConstTensor &weights, const Optional< ConstTensor > &biases, const char *name=nullptr) override
Definition: Network.cpp:1105
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
Definition: INetwork.hpp:61
static bool IsLayerSupported(const BackendId &backendId, const IConnectableLayer &layer, Optional< DataType > dataType, std::string &outReasonIfUnsupported)
const ConstTensor * m_InputToInputWeights
Definition: LstmParams.hpp:40
const ConstTensor * m_ProjectionBias
Definition: LstmParams.hpp:56
This layer represents a comparison operation.
std::unique_ptr< ScopedCpuTensorHandle > m_Mean
A unique pointer to store Mean values.
DataType GetDataType() const
Definition: Tensor.hpp:95
virtual std::vector< ITensorHandleFactory::FactoryId > GetHandleFactoryPreferences() const
(Optional) Returns a vector of supported TensorHandleFactory ids in preference order.
std::unique_ptr< IOptimizedNetwork, void(*)(IOptimizedNetwork *network)> IOptimizedNetworkPtr
Definition: INetwork.hpp:544
std::vector< ConvertFp16ToFp32Layer * > InsertConvertFp16ToFp32LayersBefore(Graph &graph, Layer &layer, bool expectCorrectInputType)
A Pooling2dDescriptor for the Pooling2dLayer.
Status SerializeToDot(std::ostream &stream) const override
Definition: Network.cpp:69
A StandInDescriptor for the StandIn layer.
IConnectableLayer * AddSubtractionLayer(const char *name=nullptr) override
Definition: Network.cpp:1441
A SliceDescriptor for the SliceLayer.
This layer represents a strided slice operation.
IConnectableLayer * AddFullyConnectedLayer(const FullyConnectedDescriptor &fullyConnectedDescriptor, const ConstTensor &weights, const Optional< ConstTensor > &biases, const char *name=nullptr) override
Definition: Network.cpp:998
const ConstTensor & GetInputToOutputWeights() const
bool m_BiasEnabled
Enable/disable bias.
BackendIdVector m_PreferredBackends
virtual MemorySourceFlags GetImportFlags() const
This layer calculates both true and false outputs for input.
Definition: SwitchLayer.hpp:13
const ConstTensor * m_CellToOutputWeights
Definition: LstmParams.hpp:50
void SetTensorHandleFactory(const ITensorHandleFactory::FactoryId &id)
Definition: Layer.cpp:167
A DepthwiseConvolution2dDescriptor for the DepthwiseConvolution2dLayer.
A PermuteDescriptor for the PermuteLayer.
void SetQuantizationOffset(int32_t offset)
Definition: Tensor.cpp:275
A Convolution2dDescriptor for the Convolution2dLayer.
IConnectableLayer * AddNormalizationLayer(const NormalizationDescriptor &normalizationDescriptor, const char *name=nullptr) override
Definition: Network.cpp:1167
IConnectableLayer * AddOutputLayer(LayerBindingId id, const char *name=nullptr) override
Definition: Network.cpp:1222
IConnectableLayer * AddArgMinMaxLayer(const ArgMinMaxDescriptor &desc, const char *name=nullptr) override
Definition: Network.cpp:1161
uint32_t m_TargetHeight
Target height value.
This layer represents an unknown operation in the input graph.
A MeanDescriptor for the MeanLayer.
armnn::Runtime::CreationOptions::ExternalProfilingOptions options
A SpaceToBatchNdDescriptor for the SpaceToBatchNdLayer.
OptimizeForType< Layer, AddDebugImpl > InsertDebugLayer
Definition: AddDebug.hpp:34
This layer represents an instance normalization operation.
IConnectableLayer * AddStridedSliceLayer(const StridedSliceDescriptor &stridedSliceDescriptor, const char *name=nullptr) override
Definition: Network.cpp:1466
const TensorInfo & GetTensorInfo() const override
Definition: Layer.cpp:63
An ArgMinMaxDescriptor for ArgMinMaxLayer.
Definition: Descriptors.hpp:43
OptimizeForConnection< PermuteLayer, PermuteLayer, OptimizeInversePermutesImpl > OptimizeInversePermutes
IConnectableLayer * AddConstantLayer(const ConstTensor &input, const char *name=nullptr) override
Definition: Network.cpp:1280
OptimizeForType< PermuteLayer, PermuteAsReshapeImpl > PermuteAsReshape
bool has_value() const noexcept
Definition: Optional.hpp:53
Layer & GetOwningLayer() const
Definition: Layer.hpp:115
IConnectableLayer * AddInstanceNormalizationLayer(const InstanceNormalizationDescriptor &desc, const char *name=nullptr) override
Definition: Network.cpp:1262
IConnectableLayer * AddFloorLayer(const char *name=nullptr) override
Definition: Network.cpp:1307
int LayerBindingId
Type of identifiers for bindable layers (inputs, outputs).
Definition: Types.hpp:168
constexpr const char * GetDataTypeName(DataType dataType)
Definition: TypesUtils.hpp:165
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Definition: Layer.hpp:312
A ResizeDescriptor for the ResizeLayer.
BackendIdVector GetAvailablePreferredBackends() const
IConnectableLayer * AddBatchNormalizationLayer(const BatchNormalizationDescriptor &desc, const ConstTensor &mean, const ConstTensor &variance, const ConstTensor &beta, const ConstTensor &gamma, const char *name=nullptr) override
Definition: Network.cpp:1227
This layer represents a L2 normalization operation.
A ComparisonDescriptor for the ComparisonLayer.
Definition: Descriptors.hpp:62
Device specific knowledge to be passed to the optimizer.
Definition: Types.hpp:158
This layer converts data type Float 16 to Float 32.
IConnectableLayer * AddSpaceToDepthLayer(const SpaceToDepthDescriptor &spaceToDepthDescriptor, const char *name=nullptr) override
Definition: Network.cpp:1301
float GetQuantizationScale() const
Definition: Tensor.cpp:247
This layer dequantizes the input tensor.
An OriginsDescriptor for the ConcatLayer. Descriptor to configure the concatenation process...
IConnectableLayer * AddDetectionPostProcessLayer(const DetectionPostProcessDescriptor &descriptor, const ConstTensor &anchors, const char *name=nullptr) override
Definition: Network.cpp:1133
IConnectableLayer * AddBatchToSpaceNdLayer(const BatchToSpaceNdDescriptor &batchToSpaceNdDescriptor, const char *name=nullptr) override
Definition: Network.cpp:958
This layer represents a QuantizedLstm operation.
#define ARMNN_NO_DEPRECATE_WARN_END
Definition: Deprecated.hpp:34
This layer represents a resize operation.
Definition: ResizeLayer.hpp:13
IConnectableLayer * AddConcatLayer(const ConcatDescriptor &concatDescriptor, const char *name=nullptr) override
Definition: Network.cpp:1023
A StridedSliceDescriptor for the StridedSliceLayer.
std::unique_ptr< ScopedCpuTensorHandle > m_Weight
A unique pointer to store weight values.