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