blob: 554e2e26a5187dc500412077f6b2824e1ec20429 [file] [log] [blame]
telsoa014fcda012018-03-09 14:13:49 +00001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
David Beckecb56cd2018-09-05 12:52:57 +01003// SPDX-License-Identifier: MIT
telsoa014fcda012018-03-09 14:13:49 +00004//
Matteo Martincigh49124022019-01-11 13:25:59 +00005
telsoa014fcda012018-03-09 14:13:49 +00006#include "Network.hpp"
7#include "Graph.hpp"
8#include "Layer.hpp"
telsoa01c577f2c2018-08-31 09:22:23 +01009#include "DeviceSpec.hpp"
telsoa014fcda012018-03-09 14:13:49 +000010#include "Optimizer.hpp"
Derek Lambertiff05cc52019-04-26 13:05:17 +010011#include "SubgraphViewSelector.hpp"
Matteo Martincigh49124022019-01-11 13:25:59 +000012#include "BackendSettings.hpp"
David Beckac42efd2018-09-26 17:41:13 +010013#include "optimizations/All.hpp"
telsoa014fcda012018-03-09 14:13:49 +000014
Aron Virginas-Tarc9cc8042018-11-01 16:15:57 +000015#include <backendsCommon/CpuTensorHandle.hpp>
16#include <backendsCommon/WorkloadFactory.hpp>
Matteo Martincighe5b8eb92019-11-28 15:45:42 +000017#include <armnn/backends/IBackendInternal.hpp>
Derek Lamberti84da38b2019-06-13 11:40:08 +010018#include <backendsCommon/TensorHandleFactoryRegistry.hpp>
David Beckac42efd2018-09-26 17:41:13 +010019
20#include <armnn/Exceptions.hpp>
telsoa014fcda012018-03-09 14:13:49 +000021#include <armnn/Utils.hpp>
telsoa01c577f2c2018-08-31 09:22:23 +010022#include <armnn/TypesUtils.hpp>
Matteo Martincighc601aa62019-10-29 15:03:22 +000023#include <armnn/BackendRegistry.hpp>
telsoa014fcda012018-03-09 14:13:49 +000024
Jan Eilers99d9d4a2019-11-06 10:02:16 +000025#include <ProfilingService.hpp>
26
telsoa014fcda012018-03-09 14:13:49 +000027#include <fcntl.h>
28#include <algorithm>
29#include <fstream>
30#include <memory>
telsoa01c577f2c2018-08-31 09:22:23 +010031#include <vector>
32#include <algorithm>
telsoa014fcda012018-03-09 14:13:49 +000033
34#include <boost/assert.hpp>
35#include <boost/format.hpp>
telsoa014fcda012018-03-09 14:13:49 +000036#include <boost/numeric/conversion/converter_policies.hpp>
37#include <boost/cast.hpp>
38
39namespace armnn
40{
41
42armnn::INetwork* INetwork::CreateRaw()
43{
44 return new Network();
45}
46
47armnn::INetworkPtr INetwork::Create()
48{
49 return INetworkPtr(CreateRaw(), &INetwork::Destroy);
50}
51
52void INetwork::Destroy(INetwork* network)
53{
54 delete boost::polymorphic_downcast<Network*>(network);
55}
56
telsoa014fcda012018-03-09 14:13:49 +000057void IOptimizedNetwork::Destroy(IOptimizedNetwork* network)
58{
59 delete boost::polymorphic_downcast<OptimizedNetwork*>(network);
60}
61
62Status OptimizedNetwork::PrintGraph()
63{
64 m_Graph->Print();
65 return Status::Success;
66}
67
surmeh01bceff2f2018-03-29 16:29:27 +010068Status OptimizedNetwork::SerializeToDot(std::ostream& stream) const
69{
70 return m_Graph->SerializeToDot(stream);
71}
72
Matteo Martincigh49124022019-01-11 13:25:59 +000073void ReportError(const std::string& errorMessage,
74 Optional<std::vector<std::string>&> errorMessages)
75{
76 std::stringstream fullErrorMessage;
77 fullErrorMessage << "ERROR: " << errorMessage;
Derek Lamberti08446972019-11-26 16:38:31 +000078 ARMNN_LOG(warning) << fullErrorMessage.str();
Matteo Martincigh49124022019-01-11 13:25:59 +000079 if (errorMessages)
80 {
81 errorMessages.value().push_back(fullErrorMessage.str());
82 }
83}
84
85void ReportWarning(const std::string& warningMessage,
86 Optional<std::vector<std::string>&> warningMessages)
87{
88 std::stringstream fullWarningMessage;
89 fullWarningMessage << "WARNING: " << warningMessage;
Derek Lamberti08446972019-11-26 16:38:31 +000090 ARMNN_LOG(warning) << fullWarningMessage.str();
Matteo Martincigh49124022019-01-11 13:25:59 +000091 if (warningMessages)
92 {
93 warningMessages.value().push_back(fullWarningMessage.str());
94 }
95}
96
jimfly016b0b53d2018-10-08 14:43:01 +010097bool CheckScaleSetOnQuantizedType(Layer* layer, Optional<std::vector<std::string>&> errMessages)
98{
99 bool noErrors = true;
100 unsigned int numOutputs = layer->GetNumOutputSlots();
101 for (unsigned int i = 0; i < numOutputs; i++) {
David Monahanb8554702019-04-25 16:03:38 +0100102 OutputSlot& outputSlot = layer->GetOutputSlot(i);
103 TensorInfo info = outputSlot.GetTensorInfo();
Derek Lambertif90c56d2020-01-10 17:14:08 +0000104 if (DataType::QAsymmU8 == info.GetDataType()) {
jimfly016b0b53d2018-10-08 14:43:01 +0100105 if (0.f == info.GetQuantizationScale()) {
106 noErrors = false;
107 std::stringstream ss;
Matteo Martincigh49124022019-01-11 13:25:59 +0000108 ss << "output " << i << " of layer " << GetLayerTypeAsCString(layer->GetType())
jimfly016b0b53d2018-10-08 14:43:01 +0100109 << " (" << layer->GetNameStr() << ") is of type"
110 << " Quantized 8 bit but its scale parameter has not been set";
Matteo Martincigh49124022019-01-11 13:25:59 +0000111 ReportError(ss.str(), errMessages);
jimfly016b0b53d2018-10-08 14:43:01 +0100112 }
David Monahanb8554702019-04-25 16:03:38 +0100113 // Softmax under QuantisedAsymm8 must always be scale (1.0f/256.0f) and offset 0
114 if ((info.GetQuantizationScale() != (1.0f / 256.0f) ||
115 info.GetQuantizationOffset() != 0) &&
116 layer->GetType() == armnn::LayerType::Softmax)
117 {
118 std::stringstream ss;
119 ss << "Quantization parameters for Softmax layer (Scale: " <<
120 info.GetQuantizationScale() << " and Offset: " << info.GetQuantizationOffset() <<
121 ") are incorrect and have been updated to Scale: 0.00390625 and Offset: 0";
Derek Lamberti08446972019-11-26 16:38:31 +0000122 ARMNN_LOG(warning) << ss.str();
David Monahanb8554702019-04-25 16:03:38 +0100123 info.SetQuantizationScale((1.0f /256.0f));
124 info.SetQuantizationOffset(0);
125 outputSlot.SetTensorInfo(info);
126 }
jimfly016b0b53d2018-10-08 14:43:01 +0100127 }
128 }
129 return noErrors;
130}
131
Matteo Martincigh49124022019-01-11 13:25:59 +0000132OptimizationResult AssignBackends(OptimizedNetwork* optNetObjPtr,
133 BackendSettings& backendSettings,
134 Graph::Iterator& firstLayer,
135 Graph::Iterator& lastLayer,
136 Optional<std::vector<std::string>&> errMessages)
telsoa014fcda012018-03-09 14:13:49 +0000137{
Matteo Martincigh49124022019-01-11 13:25:59 +0000138 OptimizationResult result;
telsoa014fcda012018-03-09 14:13:49 +0000139
Matteo Martincigh49124022019-01-11 13:25:59 +0000140 // Helper lambda to compose meaningful error message before returning with error
141 auto ReturnWithError = [&](const Layer* layer)
telsoa01c577f2c2018-08-31 09:22:23 +0100142 {
jimfly016b0b53d2018-10-08 14:43:01 +0100143 std::stringstream failureMsg;
Matteo Martincigh49124022019-01-11 13:25:59 +0000144 failureMsg << "Layer of type " << GetLayerTypeAsCString(layer->GetType())
145 << " is not supported on any preferred backend " << backendSettings.m_PreferredBackends;
146 ReportError(failureMsg.str(), errMessages);
147
148 result.m_Error = true;
149 return result;
telsoa01c577f2c2018-08-31 09:22:23 +0100150 };
151
Matteo Martincigh49124022019-01-11 13:25:59 +0000152 auto availablePreferredBackends = backendSettings.GetAvailablePreferredBackends();
153 if (availablePreferredBackends.empty())
telsoa01c577f2c2018-08-31 09:22:23 +0100154 {
Matteo Martincigh49124022019-01-11 13:25:59 +0000155 std::stringstream failureMsg;
156 failureMsg << "No preferred backends are available";
157 ReportError(failureMsg.str(), errMessages);
158
159 result.m_Error = true;
160 return result;
161 }
162
163 for (auto it = firstLayer; it != lastLayer; ++it)
164 {
165 auto layer = *it;
Aron Virginas-Tar87972be2019-11-13 15:16:28 +0000166
167 DataType dataTypeIn = layer->GetNumInputSlots() == 0 ? DataType::Float32 :
168 layer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo().GetDataType();
169 DataType dataTypeOut = layer->GetNumOutputSlots() == 0 ? DataType::Float32 :
170 layer->GetOutputSlot(0).GetTensorInfo().GetDataType();
171
telsoa01c577f2c2018-08-31 09:22:23 +0100172 std::string reasonIfUnsupported;
173 bool found = false;
jimfly016b0b53d2018-10-08 14:43:01 +0100174 if (!CheckScaleSetOnQuantizedType(layer, errMessages))
175 {
176 // don't bomb immediately, find all the quantized outputs
177 // which haven't had a scale set and report them all back.
Matteo Martincigh49124022019-01-11 13:25:59 +0000178 result.m_Error = true;
jimfly016b0b53d2018-10-08 14:43:01 +0100179 }
Matteo Martincigh49124022019-01-11 13:25:59 +0000180
David Beckf0b48452018-10-19 15:20:56 +0100181 for (const auto& backend : availablePreferredBackends)
telsoa01c577f2c2018-08-31 09:22:23 +0100182 {
183 // need to set the compute device on the layer
184 // before we can check if it is supported
David Beck33f0ae02018-10-18 15:13:56 +0100185 layer->SetBackendId(backend);
Aron Virginas-Tar87972be2019-11-13 15:16:28 +0000186 if (!IWorkloadFactory::IsLayerSupported(*layer, EmptyOptional(), reasonIfUnsupported))
telsoa01c577f2c2018-08-31 09:22:23 +0100187 {
Aron Virginas-Tar87972be2019-11-13 15:16:28 +0000188 if (dataTypeIn == DataType::Float16 || dataTypeOut == DataType::Float16)
telsoa01c577f2c2018-08-31 09:22:23 +0100189 {
190 if (IWorkloadFactory::IsLayerSupported(*layer, DataType::Float32, reasonIfUnsupported)
191 && layer->GetType() != LayerType::ConvertFp32ToFp16
192 && layer->GetType() != LayerType::ConvertFp16ToFp32)
193 {
194 // Insert FP16 -> FP32 conversion layer before current layer
Aron Virginas-Tar87972be2019-11-13 15:16:28 +0000195 std::vector<ConvertFp16ToFp32Layer*> convertFp16ToFp32Layers;
196 if (dataTypeIn == DataType::Float16)
197 {
198 convertFp16ToFp32Layers =
199 InsertConvertFp16ToFp32LayersBefore(optNetObjPtr->GetGraph(), *layer);
200 }
telsoa01c577f2c2018-08-31 09:22:23 +0100201
202 // Insert FP32 -> FP16 conversion layer after current layer
Aron Virginas-Tar87972be2019-11-13 15:16:28 +0000203 std::vector<ConvertFp32ToFp16Layer*> convertFp32ToFp16Layers;
204 if (dataTypeOut == DataType::Float16)
205 {
206 convertFp32ToFp16Layers =
207 InsertConvertFp32ToFp16LayersAfter(optNetObjPtr->GetGraph(), *layer);
208 }
telsoa01c577f2c2018-08-31 09:22:23 +0100209
210 // Assign a supported backend to the newly introduced conversion layers
David Beckf0b48452018-10-19 15:20:56 +0100211 auto AssignFirstSupportedBackend = [&](Layer* layer, BackendId preferredBackend)
telsoa01c577f2c2018-08-31 09:22:23 +0100212 {
213 bool supportedBackendFound = false;
214 std::string reasonIfUnsupported;
215
216 // Try preferred backend first
David Beck33f0ae02018-10-18 15:13:56 +0100217 layer->SetBackendId(preferredBackend);
David Beck29c75de2018-10-23 13:35:58 +0100218 if (IWorkloadFactory::IsLayerSupported(*layer,
219 EmptyOptional(),
220 reasonIfUnsupported))
telsoa01c577f2c2018-08-31 09:22:23 +0100221 {
222 supportedBackendFound = true;
223 }
224 else
225 {
David Beckf0b48452018-10-19 15:20:56 +0100226 for (const auto& backend : availablePreferredBackends)
telsoa01c577f2c2018-08-31 09:22:23 +0100227 {
228 // Skip preferred backend (we already determined that it is not supported)
229 if (backend == preferredBackend)
230 {
231 continue;
232 }
233
David Beck33f0ae02018-10-18 15:13:56 +0100234 layer->SetBackendId(backend);
David Beck29c75de2018-10-23 13:35:58 +0100235 if (IWorkloadFactory::IsLayerSupported(*layer,
236 EmptyOptional(),
237 reasonIfUnsupported))
telsoa01c577f2c2018-08-31 09:22:23 +0100238 {
239 supportedBackendFound = true;
240 break;
241 }
242 }
243 }
244
245 return supportedBackendFound;
246 };
247
248 for (ConvertFp16ToFp32Layer* convertLayer : convertFp16ToFp32Layers)
249 {
250 if (!AssignFirstSupportedBackend(convertLayer, backend))
251 {
252 return ReturnWithError(convertLayer);
253 }
254 }
255
256 for (ConvertFp32ToFp16Layer* convertLayer : convertFp32ToFp16Layers)
257 {
258 if (!AssignFirstSupportedBackend(convertLayer, backend))
259 {
260 return ReturnWithError(convertLayer);
261 }
262 }
263
264 found = true;
265 break;
266 }
267 }
jimfly016b0b53d2018-10-08 14:43:01 +0100268 std::stringstream warningMsg;
Matteo Martincigh49124022019-01-11 13:25:59 +0000269 warningMsg << "Layer of type " << GetLayerTypeAsCString(layer->GetType())
David Beck33f0ae02018-10-18 15:13:56 +0100270 << " is not supported on requested backend " << layer->GetBackendId().Get()
Aron Virginas-Tar87972be2019-11-13 15:16:28 +0000271 << " for input data type " << GetDataTypeName(dataTypeIn)
272 << " and output data type " << GetDataTypeName(dataTypeOut)
jimfly016b0b53d2018-10-08 14:43:01 +0100273 << " (reason: " << reasonIfUnsupported
274 << "), falling back to the next backend.";
Matteo Martincigh49124022019-01-11 13:25:59 +0000275 ReportWarning(warningMsg.str(), errMessages);
telsoa01c577f2c2018-08-31 09:22:23 +0100276 }
277 else
278 {
279 found = true;
Matteo Martincigh49124022019-01-11 13:25:59 +0000280 backendSettings.m_SelectedBackends.insert(backend);
telsoa01c577f2c2018-08-31 09:22:23 +0100281 break;
282 }
283 }
284
285 // If the layer is unsupported by any devices, log and return a null network.
Matteo Martincigh49124022019-01-11 13:25:59 +0000286 if (!found)
287 {
telsoa01c577f2c2018-08-31 09:22:23 +0100288 // NOTE: if the layer is not an operation queue type AND we have not got CpuRef as a
289 // fallback we should set the compute device on the layer to CpuRef (these are not
290 // available as accelerated operations, or are only available under certain
291 // conditions, currently they comprise MemCopy, Constant, Permute)
292 armnn::LayerType layerType = layer->GetType();
Matteo Martincigh49124022019-01-11 13:25:59 +0000293 if (!backendSettings.IsCpuRefUsed() && (layerType == armnn::LayerType::MemCopy ||
294 layerType == armnn::LayerType::Constant ||
295 layerType == armnn::LayerType::Permute))
telsoa01c577f2c2018-08-31 09:22:23 +0100296 {
Matteo Martincigh49124022019-01-11 13:25:59 +0000297 BackendId cpuBackendId(armnn::Compute::CpuRef);
298 layer->SetBackendId(cpuBackendId);
299 backendSettings.m_SelectedBackends.insert(cpuBackendId);
telsoa01c577f2c2018-08-31 09:22:23 +0100300 }
301 else
302 {
303 return ReturnWithError(layer);
304 }
305 }
306 }
Matteo Martincigh49124022019-01-11 13:25:59 +0000307
308 return result;
309}
310
Matteo Martincighadddddb2019-01-24 14:06:23 +0000311OptimizationResult AssignBackends(OptimizedNetwork* optNetObjPtr,
312 BackendSettings& backendSettings,
Derek Lambertiff05cc52019-04-26 13:05:17 +0100313 SubgraphView& subgraph,
Matteo Martincighadddddb2019-01-24 14:06:23 +0000314 Optional<std::vector<std::string>&> errMessages)
Matteo Martincigh49124022019-01-11 13:25:59 +0000315{
Derek Lambertiff05cc52019-04-26 13:05:17 +0100316 Graph::Iterator firstLayer = subgraph.begin();
317 Graph::Iterator lastLayer = subgraph.end();
Matteo Martincighadddddb2019-01-24 14:06:23 +0000318 return AssignBackends(optNetObjPtr,
319 backendSettings,
320 firstLayer,
321 lastLayer,
322 errMessages);
323}
324
Derek Lamberti84da38b2019-06-13 11:40:08 +0100325BackendsMap CreateSupportedBackends(TensorHandleFactoryRegistry& handleFactoryRegistry,
326 BackendSettings& backendSettings)
327{
328 BackendsMap backends;
329 auto const& backendRegistry = BackendRegistryInstance();
330 for (auto&& selectedBackend : backendSettings.m_SupportedBackends)
331 {
332 auto backendFactory = backendRegistry.GetFactory(selectedBackend);
333 auto backendObjPtr = backendFactory();
334 BOOST_ASSERT(backendObjPtr);
335
336 backendObjPtr->RegisterTensorHandleFactories(handleFactoryRegistry);
337
338 backends[backendObjPtr->GetId()] = std::move(backendObjPtr);
339 }
340
341 return backends;
342}
343
Matteo Martincighadddddb2019-01-24 14:06:23 +0000344OptimizationResult ApplyBackendOptimizations(OptimizedNetwork* optNetObjPtr,
345 BackendSettings& backendSettings,
Derek Lamberti84da38b2019-06-13 11:40:08 +0100346 BackendsMap& backends,
Matteo Martincighadddddb2019-01-24 14:06:23 +0000347 Optional<std::vector<std::string>&> errMessages)
348{
349 BOOST_ASSERT(optNetObjPtr);
Matteo Martincigh49124022019-01-11 13:25:59 +0000350
351 OptimizationResult result;
352
Matteo Martincighadddddb2019-01-24 14:06:23 +0000353 // Get the optimized graph
354 Graph& optGraph = optNetObjPtr->GetGraph();
Matteo Martincigh49124022019-01-11 13:25:59 +0000355
Matteo Martincighadddddb2019-01-24 14:06:23 +0000356 // Run backend specific optimizations
Matteo Martincighadddddb2019-01-24 14:06:23 +0000357 for (auto&& selectedBackend : backendSettings.m_SelectedBackends)
Matteo Martincigh49124022019-01-11 13:25:59 +0000358 {
Derek Lamberti84da38b2019-06-13 11:40:08 +0100359 auto backendObjPtr = backends.find(selectedBackend)->second.get();
Matteo Martincighadddddb2019-01-24 14:06:23 +0000360 BOOST_ASSERT(backendObjPtr);
361
362 // Select sub-graphs based on backend
Derek Lambertiff05cc52019-04-26 13:05:17 +0100363 SubgraphViewSelector::Subgraphs subgraphs =
Rob Hughes65c32262019-07-23 15:33:39 +0100364 SubgraphViewSelector::SelectSubgraphs(optGraph,
Matteo Martincigh602af092019-05-01 10:31:27 +0100365 // Select layers assigned to the requested backend
366 [&backendObjPtr](const Layer& layer)
367 {
368 return layer.GetType() != LayerType::Input &&
369 layer.GetType() != LayerType::Output &&
370 layer.GetBackendId() == backendObjPtr->GetId();
371 });
Derek Lambertiff05cc52019-04-26 13:05:17 +0100372 if (subgraphs.empty())
Matteo Martincigh49124022019-01-11 13:25:59 +0000373 {
Matteo Martincighadddddb2019-01-24 14:06:23 +0000374 // No sub-graphs found, try with next selected backend
375 continue;
Matteo Martincigh49124022019-01-11 13:25:59 +0000376 }
Matteo Martincighadddddb2019-01-24 14:06:23 +0000377
378 // Try to optimize each sub-graph
Derek Lambertiff05cc52019-04-26 13:05:17 +0100379 for (auto& subgraph : subgraphs)
Matteo Martincigh49124022019-01-11 13:25:59 +0000380 {
Matteo Martincighadddddb2019-01-24 14:06:23 +0000381 // Try to optimize the current sub-graph
Matteo Martincigh84924332019-05-09 12:46:16 +0100382 OptimizationViews optimizationViews = backendObjPtr->OptimizeSubgraphView(*subgraph);
383 BOOST_ASSERT(optimizationViews.Validate(*subgraph));
Matteo Martincighadddddb2019-01-24 14:06:23 +0000384
385 // Optimization attempted, check the resulting optimized sub-graph
Matteo Martincigh84924332019-05-09 12:46:16 +0100386 for (auto& substitution : optimizationViews.GetSubstitutions())
Matteo Martincighadddddb2019-01-24 14:06:23 +0000387 {
388 // Sub-graph optimized, substitute the sub-graph with the new optimized one in the main optimized graph
Matteo Martincigh84924332019-05-09 12:46:16 +0100389 SubgraphView& replacementSubgraph = substitution.m_ReplacementSubgraph;
390 SubgraphView& substitutableSubgraph = substitution.m_SubstitutableSubgraph;
391 optGraph.SubstituteSubgraph(substitutableSubgraph, replacementSubgraph);
Matteo Martincighadddddb2019-01-24 14:06:23 +0000392
393 // Assign the current backend to the optimized sub-graph
Matteo Martincigh84924332019-05-09 12:46:16 +0100394 std::for_each(replacementSubgraph.begin(), replacementSubgraph.end(), [&selectedBackend](Layer* l)
Derek Lambertic2fe5fb2019-05-08 10:23:08 +0100395 {
396 BOOST_ASSERT(l);
397 l->SetBackendId(selectedBackend);
398 });
Matteo Martincighadddddb2019-01-24 14:06:23 +0000399 }
Derek Lambertic2fe5fb2019-05-08 10:23:08 +0100400
Matteo Martincigh84924332019-05-09 12:46:16 +0100401 if (!optimizationViews.GetFailedSubgraphs().empty())
Matteo Martincighadddddb2019-01-24 14:06:23 +0000402 {
Matteo Martincighadddddb2019-01-24 14:06:23 +0000403 std::stringstream warningMsg;
Derek Lambertic2fe5fb2019-05-08 10:23:08 +0100404 warningMsg << "Some sub-graph(s) failed to optimized on " << backendObjPtr->GetId() << " backend.";
Matteo Martincighadddddb2019-01-24 14:06:23 +0000405 ReportWarning(warningMsg.str(), errMessages);
406
407 // Failed to optimize the given sub-graph, re-assign the sub-graph layers to other available backends
Derek Lambertic2fe5fb2019-05-08 10:23:08 +0100408 BackendSettings settingsCopy(backendSettings);
Matteo Martincighadddddb2019-01-24 14:06:23 +0000409 if (!backendObjPtr->GetId().IsCpuRef())
410 {
411 // Add the current backend to the list of backends to ignore
Derek Lambertic2fe5fb2019-05-08 10:23:08 +0100412 settingsCopy.m_IgnoredBackends.insert(backendObjPtr->GetId());
Matteo Martincighadddddb2019-01-24 14:06:23 +0000413 }
Derek Lambertic2fe5fb2019-05-08 10:23:08 +0100414
415 int count=0;
Matteo Martincigh84924332019-05-09 12:46:16 +0100416 for (auto& failedSubgraph : optimizationViews.GetFailedSubgraphs())
Matteo Martincighadddddb2019-01-24 14:06:23 +0000417 {
Derek Lambertic2fe5fb2019-05-08 10:23:08 +0100418 // An error occurred: the optimization was attempted but not performed, try different backends
419 std::stringstream subgraphMsg;
420 subgraphMsg << "Re-assigning backends to " << failedSubgraph.GetLayers().size()
421 << " layers inside sub-graph " << count++;
Matteo Martincigh328d92b2019-07-04 17:52:55 +0100422 ReportWarning(subgraphMsg.str(), errMessages);
Derek Lambertic2fe5fb2019-05-08 10:23:08 +0100423
424 OptimizationResult reassignmentResult = AssignBackends(optNetObjPtr,
425 settingsCopy,
426 *subgraph,
427 errMessages);
428 if (reassignmentResult.m_Error)
429 {
430 // Failed to re-assign one of the remaining backends to each layer of the sub-graph
431 result.m_Error = true;
432 return result;
433 }
Matteo Martincighadddddb2019-01-24 14:06:23 +0000434 }
Matteo Martincigh49124022019-01-11 13:25:59 +0000435 }
436 }
437 }
438
439 return result;
440}
441
Derek Lamberti84da38b2019-06-13 11:40:08 +0100442bool RequiresCopy(ITensorHandleFactory::FactoryId src,
443 ITensorHandleFactory::FactoryId dst,
444 TensorHandleFactoryRegistry& registry)
445{
446 if (src != dst)
447 {
448 ITensorHandleFactory* srcFactory = registry.GetFactory(src);
449 ITensorHandleFactory* dstFactory = registry.GetFactory(dst);
450
Matteo Martincigha6539ed2019-08-27 13:43:32 +0100451 if (srcFactory && dstFactory &&
452 (srcFactory->GetExportFlags() & dstFactory->GetImportFlags()) != 0)
Derek Lamberti84da38b2019-06-13 11:40:08 +0100453 {
454 return false;
455 }
456 return true;
457 }
458 return false;
459}
460
461// Find the handle factory for the input layer which results in fewest required copies.
462ITensorHandleFactory::FactoryId CalculateSlotOptionForInput(BackendsMap& backends,
463 OutputSlot& slot,
464 TensorHandleFactoryRegistry& registry)
465{
466 Layer& layer = slot.GetOwningLayer();
467 BOOST_ASSERT(layer.GetType() == LayerType::Input);
468
469 // Explicitly select the tensorhandle factory for InputLayer because the rules for it are slightly different. It
470 // doesn't matter which backend it is assigned to because they all use the same implementation, which
471 // requires Map/Unmap support. This means that, so long as the handle type supports map/unmap semantics, we can
472 // select a factory with maximum compatibility with the layers connected to the InputLayer.
473
474 // First ensure the from backends can support the TensorHandeAPI
475 auto frmBackend = backends.find(layer.GetBackendId());
476 if (frmBackend == backends.end() ||
477 !frmBackend->second->SupportsTensorAllocatorAPI())
478 {
479 return ITensorHandleFactory::LegacyFactoryId;
480 }
481
482 // Go through all connections to the output slot and determine the TensorHandleFactory which results in the
483 // fewest copies.
484 std::map<ITensorHandleFactory::FactoryId, int> factoryScores;
485 int topScore = 0;
486 ITensorHandleFactory::FactoryId topChoice = ITensorHandleFactory::LegacyFactoryId;
487
488 for (auto&& connection : slot.GetConnections())
489 {
490 const Layer& connectedLayer = connection->GetOwningLayer();
491
492 auto toBackend = backends.find(connectedLayer.GetBackendId());
493 BOOST_ASSERT_MSG(toBackend != backends.end(), "Backend id not found for the connected layer");
494
495 if (!toBackend->second.get()->SupportsTensorAllocatorAPI())
496 {
497 // The destination backend does not support the tensor allocator API, move to the next one
498 continue;
499 }
500
501 auto dstPrefs = toBackend->second.get()->GetHandleFactoryPreferences();
502 for (auto&& dst : dstPrefs)
503 {
Derek Lambertif674aa02019-08-01 15:56:25 +0100504 // Input layers use the mem copy workload or import, so the selected factory must
505 // support either the map/unmap API or Import API
Derek Lamberti84da38b2019-06-13 11:40:08 +0100506 ITensorHandleFactory* factory = registry.GetFactory(dst);
Derek Lambertif674aa02019-08-01 15:56:25 +0100507 if (!factory->SupportsMapUnmap() &&
508 !CheckFlag(factory->GetImportFlags(), MemorySource::Malloc)) // Just support cpu mem imports for now
Derek Lamberti84da38b2019-06-13 11:40:08 +0100509 {
Derek Lambertif674aa02019-08-01 15:56:25 +0100510 // The current tensor handle factory does not support the map/unmap or import
511 // strategy, move to the next one
Derek Lamberti84da38b2019-06-13 11:40:08 +0100512 continue;
513 }
514
515 auto it = factoryScores.find(dst);
516 if (it == factoryScores.end())
517 {
518 // Add new score to the table
519 factoryScores[dst] = 0;
520 if (topChoice == ITensorHandleFactory::LegacyFactoryId)
521 {
522 topChoice = dst;
523 }
524 }
525 else
526 {
527 // Increase the score
528 factoryScores[dst]++;
529
530 // Track the best option
531 if (factoryScores[dst] > topScore)
532 {
533 topScore = factoryScores[dst];
534 topChoice = dst;
535 }
536 }
537 }
538 }
539
540 return topChoice;
541}
542
543// Find the handle factory for the output layer which results in fewest required copies.
544ITensorHandleFactory::FactoryId CalculateSlotOptionForOutput(BackendsMap& backends,
545 OutputSlot& slot,
546 TensorHandleFactoryRegistry& registry)
547{
Derek Lamberti94a88d22019-12-10 21:12:59 +0000548 boost::ignore_unused(backends, slot, registry);
549 return ITensorHandleFactory::DeferredFactoryId;
Derek Lamberti84da38b2019-06-13 11:40:08 +0100550}
551
552// For all handle factories supported on the source backend, we wish to find the one which requires the fewest copies
553// when considering all connections.
554ITensorHandleFactory::FactoryId CalculateSlotOption(BackendsMap& backends,
555 OutputSlot& outputSlot,
556 TensorHandleFactoryRegistry& registry)
557{
558 // First ensure the from backends can support the TensorHandeAPI
559 Layer& layer = outputSlot.GetOwningLayer();
560 auto frmBackend = backends.find(layer.GetBackendId());
561 if (frmBackend == backends.end() ||
562 !frmBackend->second->SupportsTensorAllocatorAPI())
563 {
564 return ITensorHandleFactory::LegacyFactoryId;
565 }
566
567 // Connections to Output Layers requires support for map/unmap on the TensorHandle.
568 bool requiresMapUnmap = false;
569 for (auto&& connection : outputSlot.GetConnections())
570 {
571 const Layer& connectedLayer = connection->GetOwningLayer();
572 if (connectedLayer.GetType() == LayerType::Output)
573 {
574 requiresMapUnmap = true;
575 }
576 }
577
578 IBackendInternal* srcBackend = frmBackend->second.get();
579 auto srcPrefs = srcBackend->GetHandleFactoryPreferences();
580
581 // Initialize the scores
582 std::map<ITensorHandleFactory::FactoryId, int> factoryScores;
583 for (auto&& pref : srcPrefs)
584 {
585 if (requiresMapUnmap) // Only consider factories that support map/unmap if required
586 {
587 ITensorHandleFactory* factory = registry.GetFactory(pref);
588 if (!factory->SupportsMapUnmap())
589 {
590 // The current tensor handle factory does not support the map/unmap strategy, move to the next one
591 continue;
592 }
593 }
594
595 auto it = factoryScores.find(pref);
596 if (it == factoryScores.end())
597 {
598 // Add new score to the table
599 factoryScores[pref] = 0;
600 }
601 }
602
603 // Score each handle factory based on how many times it requires copies on the slot connections
604 for (auto&& connection : outputSlot.GetConnections())
605 {
606 const Layer& connectedLayer = connection->GetOwningLayer();
607
608 auto toBackend = backends.find(connectedLayer.GetBackendId());
609 BOOST_ASSERT_MSG(toBackend != backends.end(), "Backend id not found for the connected layer");
610
611 auto dstPrefs = toBackend->second.get()->GetHandleFactoryPreferences();
612 for (auto&& src : srcPrefs)
613 {
614 if (factoryScores.find(src) == factoryScores.end()) // Don't consider excluded factories
615 {
616 continue;
617 }
618
619 for (auto&& dst : dstPrefs)
620 {
621 if (RequiresCopy(src, dst, registry))
622 {
623 // Copy avoided, increase the score
624 factoryScores[src]++;
625 break;
626 }
627 }
628 }
629 }
630
631 // Find the lowest score
632 int minScore = std::numeric_limits<int>::max();
633 for (auto it : factoryScores)
634 {
635 minScore = std::min(minScore, it.second);
636 }
637
638 // Collect factories matching the best(lowest) score
639 std::vector<ITensorHandleFactory::FactoryId> optimalFactories;
640 for (auto it : factoryScores)
641 {
642 if (it.second == minScore)
643 {
644 optimalFactories.push_back(it.first);
645 }
646 }
647
648 // For all compatible Factories matching the best score, find the preferred one for the current layer.
649 for (auto&& srcPref : srcPrefs)
650 {
651 for (auto&& comp : optimalFactories)
652 {
653 if (comp == srcPref)
654 {
655 return comp;
656 }
657 }
658 }
659
660 return ITensorHandleFactory::LegacyFactoryId;
661}
662
Derek Lambertif674aa02019-08-01 15:56:25 +0100663EdgeStrategy CalculateEdgeStrategy(BackendsMap& backends,
664 ITensorHandleFactory::FactoryId srcFactoryId,
665 const Layer& layer,
666 const Layer& connectedLayer,
667 TensorHandleFactoryRegistry& registry)
Derek Lamberti84da38b2019-06-13 11:40:08 +0100668{
669 auto toBackend = backends.find(connectedLayer.GetBackendId());
670 BOOST_ASSERT_MSG(toBackend != backends.end(), "Backend id not found for the connected layer");
671
672 auto dstPrefs = toBackend->second.get()->GetHandleFactoryPreferences();
673
674 // Legacy API check for backward compatibility
675 if (srcFactoryId == ITensorHandleFactory::LegacyFactoryId || dstPrefs.empty())
676 {
677 if (layer.GetBackendId() != connectedLayer.GetBackendId())
678 {
Derek Lambertif674aa02019-08-01 15:56:25 +0100679 return EdgeStrategy::CopyToTarget;
Derek Lamberti84da38b2019-06-13 11:40:08 +0100680 }
681 else
682 {
Derek Lambertif674aa02019-08-01 15:56:25 +0100683 return EdgeStrategy::DirectCompatibility;
Derek Lamberti84da38b2019-06-13 11:40:08 +0100684 }
685 }
686
687 // TensorHandleFactory API present, so perform more sophisticated strategies.
Derek Lambertif674aa02019-08-01 15:56:25 +0100688 // Dst Output layers don't require copy because they use import or map/unmap
Derek Lamberti84da38b2019-06-13 11:40:08 +0100689 if (connectedLayer.GetType() == LayerType::Output)
690 {
Derek Lambertif674aa02019-08-01 15:56:25 +0100691 return EdgeStrategy::DirectCompatibility;
Derek Lamberti84da38b2019-06-13 11:40:08 +0100692 }
693
694 // Search for direct match in prefs
695 for (auto&& pref : dstPrefs)
696 {
697 if (pref == srcFactoryId)
698 {
Derek Lambertif674aa02019-08-01 15:56:25 +0100699 return EdgeStrategy::DirectCompatibility;
Derek Lamberti84da38b2019-06-13 11:40:08 +0100700 }
701 }
702
703 // Search for export/import options
704 ITensorHandleFactory* srcFactory = registry.GetFactory(srcFactoryId);
Derek Lambertif674aa02019-08-01 15:56:25 +0100705 if (srcFactory->GetExportFlags() != 0)
Derek Lamberti84da38b2019-06-13 11:40:08 +0100706 {
707 for (auto&& pref : dstPrefs)
708 {
709 ITensorHandleFactory* dstFactory = registry.GetFactory(pref);
James Conroyffab16f2019-11-07 14:37:09 +0000710
James Conroy47e863d2019-11-18 17:07:43 +0000711 // Handles cases when a destPref is not listed in TensorHandleFactoryRegistry
James Conroyffab16f2019-11-07 14:37:09 +0000712 if (!dstFactory) {
James Conroy47e863d2019-11-18 17:07:43 +0000713 continue;
James Conroyffab16f2019-11-07 14:37:09 +0000714 }
715
Derek Lambertif674aa02019-08-01 15:56:25 +0100716 if ((dstFactory->GetImportFlags() & srcFactory->GetExportFlags()) != 0)
Derek Lamberti84da38b2019-06-13 11:40:08 +0100717 {
Derek Lambertif674aa02019-08-01 15:56:25 +0100718 return EdgeStrategy::ExportToTarget;
Derek Lamberti84da38b2019-06-13 11:40:08 +0100719 }
720 }
721 }
722
723 // Search for copy options via map/unmap
724 if (srcFactory->SupportsMapUnmap())
725 {
726 for (auto&& pref : dstPrefs)
727 {
728 ITensorHandleFactory* dstFactory = registry.GetFactory(pref);
James Conroy47e863d2019-11-18 17:07:43 +0000729 if (dstFactory && dstFactory->SupportsMapUnmap())
Derek Lamberti84da38b2019-06-13 11:40:08 +0100730 {
Derek Lambertif674aa02019-08-01 15:56:25 +0100731 return EdgeStrategy::CopyToTarget;
Derek Lamberti84da38b2019-06-13 11:40:08 +0100732 }
733 }
734 }
735
Derek Lambertif674aa02019-08-01 15:56:25 +0100736 return EdgeStrategy::Undefined;
Derek Lamberti84da38b2019-06-13 11:40:08 +0100737}
738
739// Select the TensorHandleFactories and the corresponding memory strategy
740OptimizationResult SelectTensorHandleStrategy(Graph& optGraph,
741 BackendsMap& backends,
742 TensorHandleFactoryRegistry& registry,
743 Optional<std::vector<std::string>&> errMessages)
744{
745 OptimizationResult result;
746
747 optGraph.ForEachLayer([&backends, &registry, &result, &errMessages](Layer* layer)
748 {
749 BOOST_ASSERT(layer);
750
751 // Lets make sure the backend is in our list of supported backends. Something went wrong during backend
752 // assignment if this check fails
753 BOOST_ASSERT(backends.find(layer->GetBackendId()) != backends.end());
754
755 // Check each output separately
756 for (unsigned int slotIdx = 0; slotIdx < layer->GetNumOutputSlots(); slotIdx++)
757 {
758 OutputSlot& outputSlot = layer->GetOutputSlot(slotIdx);
759
760 ITensorHandleFactory::FactoryId slotOption = ITensorHandleFactory::LegacyFactoryId;
761
762 // Calculate the factory to use which results in the fewest copies being made.
763 switch(layer->GetType())
764 {
765 case LayerType::Input:
766 slotOption = CalculateSlotOptionForInput(backends, outputSlot, registry);
767 break;
768 case LayerType::Output:
769 slotOption = CalculateSlotOptionForOutput(backends, outputSlot, registry);
770 break;
771 default:
772 slotOption = CalculateSlotOption(backends, outputSlot, registry);
773 break;
774 }
775 outputSlot.SetTensorHandleFactory(slotOption);
776
Derek Lambertif674aa02019-08-01 15:56:25 +0100777 // Now determine the "best" edge strategy for each connection given the slotOption.
Derek Lamberti84da38b2019-06-13 11:40:08 +0100778 unsigned int connectionIdx = 0;
779 for (auto&& connection : outputSlot.GetConnections())
780 {
781 const Layer& connectedLayer = connection->GetOwningLayer();
782
Derek Lambertif674aa02019-08-01 15:56:25 +0100783 EdgeStrategy strategy = CalculateEdgeStrategy(backends, slotOption, *layer, connectedLayer, registry);
Derek Lamberti84da38b2019-06-13 11:40:08 +0100784
Derek Lambertif674aa02019-08-01 15:56:25 +0100785 if (strategy == EdgeStrategy::Undefined)
Derek Lamberti84da38b2019-06-13 11:40:08 +0100786 {
787 result.m_Error = true;
788 if (errMessages)
789 {
790 errMessages.value().emplace_back("Could not find valid strategy required for compatibility"
791 " between backends.");
792 }
793 return;
794 }
795
Derek Lambertif674aa02019-08-01 15:56:25 +0100796 outputSlot.SetEdgeStrategy(connectionIdx, strategy);
Derek Lamberti84da38b2019-06-13 11:40:08 +0100797
798 connectionIdx++;
799 }
800 }
801 });
802
803 return result;
804}
805
Matteo Martincigh49124022019-01-11 13:25:59 +0000806IOptimizedNetworkPtr Optimize(const INetwork& inNetwork,
807 const std::vector<BackendId>& backendPreferences,
808 const IDeviceSpec& deviceSpec,
809 const OptimizerOptions& options,
Rob Hughes23214432019-11-05 11:27:36 +0000810 Optional<std::vector<std::string>&> messages)
Matteo Martincigh49124022019-01-11 13:25:59 +0000811{
812 if (backendPreferences.empty())
813 {
814 throw armnn::InvalidArgumentException("Invoked Optimize with no backends specified");
815 }
816
817 const Network& network = *boost::polymorphic_downcast<const Network*>(&inNetwork);
818 std::unique_ptr<Graph> graph = std::make_unique<Graph>(network.GetGraph());
819
820 auto optNet = IOptimizedNetworkPtr(new OptimizedNetwork(std::move(graph)), &IOptimizedNetwork::Destroy);
821
822 OptimizedNetwork* optNetObjPtr = boost::polymorphic_downcast<OptimizedNetwork*>(optNet.get());
823
Matteo Martincighadddddb2019-01-24 14:06:23 +0000824 // Get the optimized graph
825 Graph& optGraph = optNetObjPtr->GetGraph();
826
Matteo Martincigh49124022019-01-11 13:25:59 +0000827 // Perform optimisation passes
828 using namespace optimizations;
Matteo Martincighadddddb2019-01-24 14:06:23 +0000829 Optimizer::Pass(optGraph, MakeOptimizations(SquashEqualPermuteSiblings(),
830 SquashEqualReshapeSiblings(),
831 OptimizeInversePermutes(),
832 MovePermuteUp(),
833 PermuteAsReshape(),
Nina Drozd861985f2019-04-18 14:48:51 +0100834 OptimizeConsecutiveReshapes(),
Rob Hughes3a7d3a72019-09-24 16:59:56 +0100835 FoldPadIntoConvolution2d(),
836 PermuteAndBatchToSpaceAsDepthToSpace()));
Matteo Martincigh49124022019-01-11 13:25:59 +0000837
Matteo Martincighadddddb2019-01-24 14:06:23 +0000838 // Infer the tensor infos for all output slots. Throws an exception on failure
839 optGraph.InferTensorInfos();
Matteo Martincigh49124022019-01-11 13:25:59 +0000840
841 // If Fp32 to Fp16 optimization is set convert Fp32 network to Fp16
842 if (options.m_ReduceFp32ToFp16)
843 {
Matteo Martincighadddddb2019-01-24 14:06:23 +0000844 Optimizer::Pass(optGraph, MakeOptimizations(Fp32NetworkToFp16Converter()));
Derek Lambertidd6804b2019-11-27 09:29:57 +0000845 Optimizer::Pass(optGraph, MakeOptimizations(ConvertConstantsFloatToHalf()));
Matteo Martincigh49124022019-01-11 13:25:59 +0000846 }
847
848 // Initialize backend settings
849 BackendSettings backendSettings(backendPreferences, deviceSpec);
850 if (backendSettings.GetAvailablePreferredBackends().empty())
851 {
852 std::stringstream failureMsg;
853 failureMsg << "None of the preferred backends " << backendPreferences
854 << " are supported. Current platform provides " << backendSettings.m_SupportedBackends;
Rob Hughes23214432019-11-05 11:27:36 +0000855 ReportError(failureMsg.str(), messages);
Matteo Martincigh49124022019-01-11 13:25:59 +0000856 return IOptimizedNetworkPtr(nullptr, &IOptimizedNetwork::Destroy);
857 }
858
Derek Lamberti84da38b2019-06-13 11:40:08 +0100859 // Create a map to temporarily hold initialized backend objects
860 TensorHandleFactoryRegistry tensorHandleFactoryRegistry;
861 BackendsMap backends = CreateSupportedBackends(tensorHandleFactoryRegistry, backendSettings);
862
Matteo Martincigh49124022019-01-11 13:25:59 +0000863 // Assign an available backend to each layer
Matteo Martincighadddddb2019-01-24 14:06:23 +0000864 Graph::Iterator firstLayer = optGraph.begin();
865 Graph::Iterator lastLayer = optGraph.end();
Derek Lamberti84da38b2019-06-13 11:40:08 +0100866 OptimizationResult assignBackendsResult = AssignBackends(optNetObjPtr,
867 backendSettings,
868 firstLayer,
869 lastLayer,
Rob Hughes23214432019-11-05 11:27:36 +0000870 messages);
Derek Lamberti84da38b2019-06-13 11:40:08 +0100871 if (assignBackendsResult.m_Error)
Matteo Martincigh49124022019-01-11 13:25:59 +0000872 {
873 // Failed to assign a backend to each layer
jimfly016b0b53d2018-10-08 14:43:01 +0100874 return IOptimizedNetworkPtr(nullptr, &IOptimizedNetwork::Destroy);
875 }
telsoa01c577f2c2018-08-31 09:22:23 +0100876
Matteo Martincighadddddb2019-01-24 14:06:23 +0000877 Optimizer::Pass(optGraph, MakeOptimizations(OptimizeInverseConversionsFp16(),
878 OptimizeInverseConversionsFp32()));
telsoa01c577f2c2018-08-31 09:22:23 +0100879
Matteo Martincighadddddb2019-01-24 14:06:23 +0000880 // Apply the backend-specific optimizations
881 OptimizationResult backendOptimizationResult = ApplyBackendOptimizations(optNetObjPtr,
882 backendSettings,
Derek Lamberti84da38b2019-06-13 11:40:08 +0100883 backends,
Rob Hughes23214432019-11-05 11:27:36 +0000884 messages);
Matteo Martincighadddddb2019-01-24 14:06:23 +0000885 if (backendOptimizationResult.m_Error)
Matteo Martincigh49124022019-01-11 13:25:59 +0000886 {
Matteo Martincighadddddb2019-01-24 14:06:23 +0000887 // Failed to apply the backend-specific optimizations
888 return IOptimizedNetworkPtr(nullptr, &IOptimizedNetwork::Destroy);
Matteo Martincigh49124022019-01-11 13:25:59 +0000889 }
890
Matteo Martincighadddddb2019-01-24 14:06:23 +0000891 // If the debug flag is set, then insert a DebugLayer after each layer
892 // Doing this after applying the backend optimizations as they might have changed some layers
893 if (options.m_Debug)
894 {
895 Optimizer::Pass(optGraph, MakeOptimizations(InsertDebugLayer()));
896 }
897
Derek Lamberti84da38b2019-06-13 11:40:08 +0100898 // Calculate the compatibility strategies for tensor handles
899 OptimizationResult strategyResult = SelectTensorHandleStrategy(optGraph,
900 backends,
901 tensorHandleFactoryRegistry,
Rob Hughes23214432019-11-05 11:27:36 +0000902 messages);
Derek Lamberti84da38b2019-06-13 11:40:08 +0100903 if (strategyResult.m_Error)
904 {
905 // Failed to apply the backend-specific optimizations
906 return IOptimizedNetworkPtr(nullptr, &IOptimizedNetwork::Destroy);
907 }
908
909 // Based on the tensor handle strategy determined above, insert copy layers where required.
Derek Lambertif674aa02019-08-01 15:56:25 +0100910 optGraph.AddCompatibilityLayers(backends, tensorHandleFactoryRegistry);
telsoa01c577f2c2018-08-31 09:22:23 +0100911
912 // Convert constants
Matteo Martincighadddddb2019-01-24 14:06:23 +0000913 Optimizer::Pass(optGraph, MakeOptimizations(ConvertConstantsFloatToHalf()));
914 Optimizer::Pass(optGraph, MakeOptimizations(ConvertConstantsHalfToFloat()));
telsoa01c577f2c2018-08-31 09:22:23 +0100915
Derek Lamberti84da38b2019-06-13 11:40:08 +0100916 // Run backend specific optimizations (deprecated)
Matteo Martincigh49124022019-01-11 13:25:59 +0000917 for (auto&& chosenBackend : backendSettings.m_SelectedBackends)
David Beck263e3492018-11-09 14:46:40 +0000918 {
919 auto factoryFun = BackendRegistryInstance().GetFactory(chosenBackend);
920 auto backendPtr = factoryFun();
921 BOOST_ASSERT(backendPtr.get() != nullptr);
922
Matteo Martincighed735042019-05-22 09:42:43 +0100923 ARMNN_NO_DEPRECATE_WARN_BEGIN
David Beck263e3492018-11-09 14:46:40 +0000924 auto backendSpecificOptimizations = backendPtr->GetOptimizations();
Matteo Martincighed735042019-05-22 09:42:43 +0100925 ARMNN_NO_DEPRECATE_WARN_END
926
David Beck263e3492018-11-09 14:46:40 +0000927 if (!backendSpecificOptimizations.empty())
928 {
929 Optimizer::Pass(optNetObjPtr->GetGraph(), backendSpecificOptimizations);
930 }
931 }
932
telsoa01c577f2c2018-08-31 09:22:23 +0100933 return optNet;
telsoa014fcda012018-03-09 14:13:49 +0000934}
935
936Network::Network()
Jan Eilers99d9d4a2019-11-06 10:02:16 +0000937: m_Graph(std::make_unique<Graph>()),
938 m_Guid(profiling::ProfilingService::Instance().NextGuid())
telsoa014fcda012018-03-09 14:13:49 +0000939{
940}
941
942Network::~Network()
943{
944}
945
Jan Eilers99d9d4a2019-11-06 10:02:16 +0000946Status Network::PrintGraph()
947{
948 m_Graph->Print();
949 return Status::Success;
950}
951
telsoa014fcda012018-03-09 14:13:49 +0000952IConnectableLayer* Network::AddInputLayer(LayerBindingId id, const char* name)
953{
954 return m_Graph->AddLayer<InputLayer>(id, name);
955}
956
Éanna Ó Catháin4e1e1362018-11-12 11:36:34 +0000957IConnectableLayer* Network::AddBatchToSpaceNdLayer(const BatchToSpaceNdDescriptor& batchToSpaceNdDescriptor,
958 const char* name)
959{
960 return m_Graph->AddLayer<BatchToSpaceNdLayer>(batchToSpaceNdDescriptor, name);
961}
962
Aron Virginas-Tar77bfb5e2019-10-16 17:45:38 +0100963IConnectableLayer* Network::AddComparisonLayer(const ComparisonDescriptor& comparisonDescriptor,
964 const char* name)
965{
966 return m_Graph->AddLayer<ComparisonLayer>(comparisonDescriptor, name);
967}
968
telsoa014fcda012018-03-09 14:13:49 +0000969IConnectableLayer* Network::AddFullyConnectedLayerImpl(const FullyConnectedDescriptor& fullyConnectedDescriptor,
telsoa01c577f2c2018-08-31 09:22:23 +0100970 const ConstTensor& weights,
Aron Virginas-Tarad402702019-02-22 17:03:44 +0000971 const Optional<ConstTensor>& biases,
telsoa01c577f2c2018-08-31 09:22:23 +0100972 const char* name)
telsoa014fcda012018-03-09 14:13:49 +0000973{
Aron Virginas-Tarad402702019-02-22 17:03:44 +0000974 if (fullyConnectedDescriptor.m_BiasEnabled && !biases.has_value())
telsoa014fcda012018-03-09 14:13:49 +0000975 {
Aron Virginas-Tarad402702019-02-22 17:03:44 +0000976 throw InvalidArgumentException("AddFullyConnectedLayer: biases cannot be empty");
telsoa014fcda012018-03-09 14:13:49 +0000977 }
978
979 const auto layer = m_Graph->AddLayer<FullyConnectedLayer>(fullyConnectedDescriptor, name);
980
981 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(weights);
982
983 if (fullyConnectedDescriptor.m_BiasEnabled)
984 {
Aron Virginas-Tarad402702019-02-22 17:03:44 +0000985 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(biases.value());
telsoa014fcda012018-03-09 14:13:49 +0000986 }
987
988 return layer;
989}
990
991IConnectableLayer* Network::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor,
telsoa01c577f2c2018-08-31 09:22:23 +0100992 const ConstTensor& weights,
Aron Virginas-Tarad402702019-02-22 17:03:44 +0000993 const Optional<ConstTensor>& biases,
telsoa01c577f2c2018-08-31 09:22:23 +0100994 const char* name)
telsoa014fcda012018-03-09 14:13:49 +0000995{
Aron Virginas-Tarad402702019-02-22 17:03:44 +0000996 return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, weights, biases, name);
telsoa014fcda012018-03-09 14:13:49 +0000997}
998
Aron Virginas-Tarad402702019-02-22 17:03:44 +0000999IConnectableLayer* Network::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor,
1000 const ConstTensor& weights,
1001 const char* name)
1002{
Matteo Martincighfc598e12019-05-14 10:36:13 +01001003 Optional<ConstTensor> biases;
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001004 return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, weights, biases, name);
1005}
1006
telsoa014fcda012018-03-09 14:13:49 +00001007IConnectableLayer* Network::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor,
telsoa01c577f2c2018-08-31 09:22:23 +01001008 const ConstTensor& weights,
1009 const ConstTensor& biases,
1010 const char* name)
telsoa014fcda012018-03-09 14:13:49 +00001011{
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001012 Optional<ConstTensor> optionalBiases(biases);
1013 return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, weights, optionalBiases, name);
telsoa014fcda012018-03-09 14:13:49 +00001014}
1015
Jim Flynne242f2d2019-05-22 14:24:13 +01001016IConnectableLayer* Network::AddConcatLayer(const ConcatDescriptor& concatDescriptor,
Jim Flynn906f9462019-05-10 13:55:21 +01001017 const char* name)
1018{
Jim Flynne242f2d2019-05-22 14:24:13 +01001019 return m_Graph->AddLayer<ConcatLayer>(concatDescriptor, name);
Jim Flynn906f9462019-05-10 13:55:21 +01001020}
1021
telsoa014fcda012018-03-09 14:13:49 +00001022IConnectableLayer* Network::AddConvolution2dLayerImpl(const Convolution2dDescriptor& convolution2dDescriptor,
telsoa01c577f2c2018-08-31 09:22:23 +01001023 const ConstTensor& weights,
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001024 const Optional<ConstTensor>& biases,
telsoa01c577f2c2018-08-31 09:22:23 +01001025 const char* name)
telsoa014fcda012018-03-09 14:13:49 +00001026{
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001027 if (convolution2dDescriptor.m_BiasEnabled && !biases.has_value())
telsoa014fcda012018-03-09 14:13:49 +00001028 {
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001029 throw InvalidArgumentException("AddConvolution2dLayer: biases cannot be empty");
telsoa014fcda012018-03-09 14:13:49 +00001030 }
1031
1032 const auto layer = m_Graph->AddLayer<Convolution2dLayer>(convolution2dDescriptor, name);
1033
1034 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(weights);
1035
1036 if (convolution2dDescriptor.m_BiasEnabled)
1037 {
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001038 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(biases.value());
telsoa014fcda012018-03-09 14:13:49 +00001039 }
1040
1041 return layer;
1042}
1043
1044IConnectableLayer* Network::AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor,
telsoa01c577f2c2018-08-31 09:22:23 +01001045 const ConstTensor& weights,
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001046 const Optional<ConstTensor>& biases,
telsoa01c577f2c2018-08-31 09:22:23 +01001047 const char* name)
telsoa014fcda012018-03-09 14:13:49 +00001048{
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001049 return AddConvolution2dLayerImpl(convolution2dDescriptor, weights, biases, name);
telsoa014fcda012018-03-09 14:13:49 +00001050}
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001051
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001052IConnectableLayer* Network::AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor,
1053 const ConstTensor& weights,
1054 const char* name)
1055{
Matteo Martincighfc598e12019-05-14 10:36:13 +01001056 Optional<ConstTensor> biases;
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001057 return AddConvolution2dLayerImpl(convolution2dDescriptor, weights, biases, name);
1058}
1059
telsoa014fcda012018-03-09 14:13:49 +00001060IConnectableLayer* Network::AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor,
telsoa01c577f2c2018-08-31 09:22:23 +01001061 const ConstTensor& weights,
1062 const ConstTensor& biases,
1063 const char* name)
telsoa014fcda012018-03-09 14:13:49 +00001064{
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001065 Optional<ConstTensor> optionalBiases(biases);
1066 return AddConvolution2dLayerImpl(convolution2dDescriptor, weights, optionalBiases, name);
telsoa014fcda012018-03-09 14:13:49 +00001067}
1068
1069IConnectableLayer* Network::AddDepthwiseConvolution2dLayerImpl(
1070 const DepthwiseConvolution2dDescriptor& convolution2dDescriptor,
1071 const ConstTensor& weights,
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001072 const Optional<ConstTensor>& biases,
telsoa014fcda012018-03-09 14:13:49 +00001073 const char* name)
1074{
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001075 if (convolution2dDescriptor.m_BiasEnabled && !biases.has_value())
telsoa014fcda012018-03-09 14:13:49 +00001076 {
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001077 throw InvalidArgumentException("AddDepthwiseConvolution2dLayer: biases cannot be empty");
telsoa014fcda012018-03-09 14:13:49 +00001078 }
1079
Matteo Martincigh3d6898c2019-01-15 16:11:44 +00001080 const auto layer = m_Graph->AddLayer<DepthwiseConvolution2dLayer>(convolution2dDescriptor, name);
telsoa014fcda012018-03-09 14:13:49 +00001081
1082 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(weights);
1083
1084 if (convolution2dDescriptor.m_BiasEnabled)
1085 {
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001086 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(biases.value());
telsoa014fcda012018-03-09 14:13:49 +00001087 }
1088
1089 return layer;
1090}
1091
Aron Virginas-Tardd6247f2019-09-19 14:31:17 +01001092IConnectableLayer* Network::AddDepthToSpaceLayer(const DepthToSpaceDescriptor& depthToSpaceDescriptor,
1093 const char* name)
1094{
1095 return m_Graph->AddLayer<DepthToSpaceLayer>(depthToSpaceDescriptor, name);
1096}
1097
telsoa014fcda012018-03-09 14:13:49 +00001098IConnectableLayer* Network::AddDepthwiseConvolution2dLayer(
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001099 const DepthwiseConvolution2dDescriptor& convolution2dDescriptor,
1100 const ConstTensor& weights,
1101 const Optional<ConstTensor>& biases,
1102 const char* name)
1103{
1104 return AddDepthwiseConvolution2dLayerImpl(convolution2dDescriptor, weights, biases, name);
1105}
1106
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001107IConnectableLayer* Network::AddDepthwiseConvolution2dLayer(
telsoa014fcda012018-03-09 14:13:49 +00001108 const DepthwiseConvolution2dDescriptor& convolution2dDescriptor,
1109 const ConstTensor& weights,
1110 const char* name)
1111{
Matteo Martincighfc598e12019-05-14 10:36:13 +01001112 Optional<ConstTensor> biases;
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001113 return AddDepthwiseConvolution2dLayerImpl(convolution2dDescriptor, weights, biases, name);
telsoa014fcda012018-03-09 14:13:49 +00001114}
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001115
telsoa014fcda012018-03-09 14:13:49 +00001116IConnectableLayer* Network::AddDepthwiseConvolution2dLayer(
1117 const DepthwiseConvolution2dDescriptor& convolution2dDescriptor,
1118 const ConstTensor& weights,
1119 const ConstTensor& biases,
1120 const char* name)
1121{
Aron Virginas-Tarad402702019-02-22 17:03:44 +00001122 Optional<ConstTensor> optionalBiases(biases);
1123 return AddDepthwiseConvolution2dLayerImpl(convolution2dDescriptor, weights, optionalBiases, name);
telsoa014fcda012018-03-09 14:13:49 +00001124}
1125
Narumol Prangnawarat94dd5d82019-01-23 18:06:26 +00001126IConnectableLayer* Network::AddDetectionPostProcessLayer(const armnn::DetectionPostProcessDescriptor& descriptor,
Narumol Prangnawarat6d302bf2019-02-04 11:46:26 +00001127 const ConstTensor& anchors, const char* name)
Narumol Prangnawarat94dd5d82019-01-23 18:06:26 +00001128{
Narumol Prangnawarat6d302bf2019-02-04 11:46:26 +00001129 const auto layer = m_Graph->AddLayer<DetectionPostProcessLayer>(descriptor, name);
1130
1131 layer->m_Anchors = std::make_unique<ScopedCpuTensorHandle>(anchors);
1132
1133 return layer;
Narumol Prangnawarat94dd5d82019-01-23 18:06:26 +00001134}
1135
telsoa014fcda012018-03-09 14:13:49 +00001136IConnectableLayer* Network::AddPermuteLayer(const PermuteDescriptor& permuteDescriptor,
1137 const char* name)
1138{
1139 return m_Graph->AddLayer<PermuteLayer>(permuteDescriptor, name);
1140}
1141
1142IConnectableLayer* Network::AddPooling2dLayer(const Pooling2dDescriptor& pooling2dDescriptor,
1143 const char* name)
1144{
1145 return m_Graph->AddLayer<Pooling2dLayer>(pooling2dDescriptor, name);
1146}
1147
1148IConnectableLayer* Network::AddActivationLayer(const ActivationDescriptor& activationDescriptor,
1149 const char* name)
1150{
1151 return m_Graph->AddLayer<ActivationLayer>(activationDescriptor, name);
1152}
1153
Nikhil Rajee391d52019-09-05 17:50:44 +01001154IConnectableLayer* Network::AddArgMinMaxLayer(const ArgMinMaxDescriptor& argMinMaxDescriptor,
1155 const char* name)
1156{
1157 return m_Graph->AddLayer<ArgMinMaxLayer>(argMinMaxDescriptor, name);
1158}
1159
telsoa01c577f2c2018-08-31 09:22:23 +01001160IConnectableLayer* Network::AddNormalizationLayer(const NormalizationDescriptor&
1161normalizationDescriptor,
telsoa014fcda012018-03-09 14:13:49 +00001162 const char* name)
1163{
1164 return m_Graph->AddLayer<NormalizationLayer>(normalizationDescriptor, name);
1165}
1166
Aron Virginas-Tar636ab402019-09-16 14:27:45 +01001167IConnectableLayer* Network::AddSliceLayer(const SliceDescriptor& sliceDescriptor, const char* name)
1168{
1169 return m_Graph->AddLayer<SliceLayer>(sliceDescriptor, name);
1170}
1171
telsoa014fcda012018-03-09 14:13:49 +00001172IConnectableLayer* Network::AddSoftmaxLayer(const SoftmaxDescriptor& softmaxDescriptor,
1173 const char* name)
1174{
1175 return m_Graph->AddLayer<SoftmaxLayer>(softmaxDescriptor, name);
1176}
1177
1178IConnectableLayer* Network::AddSplitterLayer(const ViewsDescriptor& splitterDescriptor,
1179 const char* name)
1180{
1181 return m_Graph->AddLayer<SplitterLayer>(splitterDescriptor, name);
1182}
1183
Nattapat Chaimanowong5a4304a2018-11-28 10:44:37 +00001184IConnectableLayer* Network::AddMaximumLayer(const char* name)
1185{
1186 return m_Graph->AddLayer<MaximumLayer>(name);
1187}
1188
Éanna Ó Catháin20e58802018-12-04 10:29:06 +00001189IConnectableLayer* Network::AddMinimumLayer(const char* name)
1190{
1191 return m_Graph->AddLayer<MinimumLayer>(name);
1192}
1193
Jim Flynne242f2d2019-05-22 14:24:13 +01001194IConnectableLayer* Network::AddMergerLayer(const MergerDescriptor& mergerDescriptor,
Jim Flynn906f9462019-05-10 13:55:21 +01001195 const char* name)
telsoa014fcda012018-03-09 14:13:49 +00001196{
Jim Flynne242f2d2019-05-22 14:24:13 +01001197 return AddConcatLayer(mergerDescriptor, name);
telsoa014fcda012018-03-09 14:13:49 +00001198}
1199
Kevin May868eb142019-09-04 17:29:31 +01001200IConnectableLayer* Network::AddAbsLayer(const char * name)
1201{
1202 return m_Graph->AddLayer<AbsLayer>(name);
1203}
1204
telsoa014fcda012018-03-09 14:13:49 +00001205IConnectableLayer* Network::AddAdditionLayer(const char* name)
1206{
1207 return m_Graph->AddLayer<AdditionLayer>(name);
1208}
1209
1210IConnectableLayer* Network::AddMultiplicationLayer(const char* name)
1211{
1212 return m_Graph->AddLayer<MultiplicationLayer>(name);
1213}
1214
1215IConnectableLayer* Network::AddOutputLayer(LayerBindingId id, const char* name)
1216{
1217 return m_Graph->AddLayer<OutputLayer>(id, name);
1218}
1219
1220IConnectableLayer* Network::AddBatchNormalizationLayer(const BatchNormalizationDescriptor& desc,
1221 const ConstTensor& mean,
1222 const ConstTensor& variance,
1223 const ConstTensor& beta,
1224 const ConstTensor& gamma,
1225 const char* name)
1226{
1227 const auto layer = m_Graph->AddLayer<BatchNormalizationLayer>(desc, name);
1228
1229 layer->m_Mean = std::make_unique<ScopedCpuTensorHandle>(mean);
1230 layer->m_Variance = std::make_unique<ScopedCpuTensorHandle>(variance);
1231 layer->m_Beta = std::make_unique<ScopedCpuTensorHandle>(beta);
1232 layer->m_Gamma = std::make_unique<ScopedCpuTensorHandle>(gamma);
1233
1234 return layer;
1235}
1236
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01001237IConnectableLayer* Network::AddResizeBilinearLayer(const ResizeBilinearDescriptor& descriptor,
1238 const char* name)
telsoa014fcda012018-03-09 14:13:49 +00001239{
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01001240 ResizeDescriptor resizeDescriptor;
1241 resizeDescriptor.m_Method = ResizeMethod::Bilinear;
1242 resizeDescriptor.m_DataLayout = descriptor.m_DataLayout;
1243 resizeDescriptor.m_TargetWidth = descriptor.m_TargetWidth;
1244 resizeDescriptor.m_TargetHeight = descriptor.m_TargetHeight;
1245
1246 return m_Graph->AddLayer<ResizeLayer>(resizeDescriptor, name);
telsoa014fcda012018-03-09 14:13:49 +00001247}
1248
Teresa Charlina9075df2019-06-27 15:41:57 +01001249IConnectableLayer* Network::AddResizeLayer(const ResizeDescriptor&
1250resizeDescriptor, const char* name)
1251{
Aron Virginas-Tar169d2f12019-07-01 19:01:44 +01001252 return m_Graph->AddLayer<ResizeLayer>(resizeDescriptor, name);
Teresa Charlina9075df2019-06-27 15:41:57 +01001253}
1254
Kevin Mayce5045a2019-10-02 14:07:47 +01001255IConnectableLayer* Network::AddInstanceNormalizationLayer(const InstanceNormalizationDescriptor& desc,
1256 const char* name)
1257{
1258 return m_Graph->AddLayer<InstanceNormalizationLayer>(desc, name);
1259}
1260
Matteo Martincighbcd3c852018-09-28 14:14:12 +01001261IConnectableLayer* Network::AddL2NormalizationLayer(const L2NormalizationDescriptor& desc,
1262 const char* name)
telsoa014fcda012018-03-09 14:13:49 +00001263{
Matteo Martincighbcd3c852018-09-28 14:14:12 +01001264 return m_Graph->AddLayer<L2NormalizationLayer>(desc, name);
telsoa014fcda012018-03-09 14:13:49 +00001265}
1266
Aron Virginas-Tarf982dea2019-10-11 14:07:53 +01001267IConnectableLayer* Network::AddLogSoftmaxLayer(const LogSoftmaxDescriptor& desc,
1268 const char* name)
1269{
1270 return m_Graph->AddLayer<LogSoftmaxLayer>(desc, name);
1271}
1272
telsoa014fcda012018-03-09 14:13:49 +00001273IConnectableLayer* Network::AddConstantLayer(const ConstTensor& input, const char* name)
1274{
telsoa01c577f2c2018-08-31 09:22:23 +01001275 auto layer = m_Graph->AddLayer<ConstantLayer>(name);
1276
1277 layer->m_LayerOutput = std::make_unique<ScopedCpuTensorHandle>(input);
1278
1279 return layer;
telsoa014fcda012018-03-09 14:13:49 +00001280}
1281
telsoa01c577f2c2018-08-31 09:22:23 +01001282IConnectableLayer* Network::AddReshapeLayer(const ReshapeDescriptor& reshapeDescriptor,
1283 const char* name)
telsoa014fcda012018-03-09 14:13:49 +00001284{
1285 return m_Graph->AddLayer<ReshapeLayer>(reshapeDescriptor, name);
1286}
1287
Nattapat Chaimanowong207ef9a2018-11-02 10:57:25 +00001288IConnectableLayer* Network::AddSpaceToBatchNdLayer(const SpaceToBatchNdDescriptor& spaceToBatchNdDescriptor,
1289 const char* name)
1290{
1291 return m_Graph->AddLayer<SpaceToBatchNdLayer>(spaceToBatchNdDescriptor, name);
1292}
1293
Aron Virginas-Tar972af152019-06-11 14:14:03 +01001294IConnectableLayer* Network::AddSpaceToDepthLayer(const SpaceToDepthDescriptor& spaceToDepthDescriptor,
1295 const char* name)
1296{
1297 return m_Graph->AddLayer<SpaceToDepthLayer>(spaceToDepthDescriptor, name);
1298}
1299
telsoa014fcda012018-03-09 14:13:49 +00001300IConnectableLayer* Network::AddFloorLayer(const char* name)
1301{
1302 return m_Graph->AddLayer<FloorLayer>(name);
1303}
1304
telsoa01c577f2c2018-08-31 09:22:23 +01001305IConnectableLayer* Network::AddLstmLayer(const LstmDescriptor& descriptor,
1306 const LstmInputParams& params,
1307 const char* name)
1308{
1309 const auto layer = m_Graph->AddLayer<LstmLayer>(descriptor, name);
1310
1311 //Lstm Basic Parameters
1312 layer->m_BasicParameters.m_InputToForgetWeights =
1313 std::make_unique<ScopedCpuTensorHandle>(*(params.m_InputToForgetWeights));
1314 layer->m_BasicParameters.m_InputToCellWeights =
1315 std::make_unique<ScopedCpuTensorHandle>(*(params.m_InputToCellWeights));
1316 layer->m_BasicParameters.m_InputToOutputWeights =
1317 std::make_unique<ScopedCpuTensorHandle>(*(params.m_InputToOutputWeights));
1318 layer->m_BasicParameters.m_RecurrentToForgetWeights =
1319 std::make_unique<ScopedCpuTensorHandle>(*(params.m_RecurrentToForgetWeights));
1320 layer->m_BasicParameters.m_RecurrentToCellWeights =
1321 std::make_unique<ScopedCpuTensorHandle>(*(params.m_RecurrentToCellWeights));
1322 layer->m_BasicParameters.m_RecurrentToOutputWeights =
1323 std::make_unique<ScopedCpuTensorHandle>(*(params.m_RecurrentToOutputWeights));
1324 layer->m_BasicParameters.m_ForgetGateBias =
1325 std::make_unique<ScopedCpuTensorHandle>(*(params.m_ForgetGateBias));
1326 layer->m_BasicParameters.m_CellBias =
1327 std::make_unique<ScopedCpuTensorHandle>(*(params.m_CellBias));
1328 layer->m_BasicParameters.m_OutputGateBias =
1329 std::make_unique<ScopedCpuTensorHandle>(*(params.m_OutputGateBias));
1330
1331 //Lstm Cifg parameters
1332 if(!descriptor.m_CifgEnabled)
1333 {
1334 if(params.m_InputToInputWeights == nullptr)
1335 {
1336 throw InvalidArgumentException("AddLstmLayer: Input To Input Weights cannot be NULL");
1337 }
1338 if(params.m_RecurrentToInputWeights == nullptr)
1339 {
1340 throw InvalidArgumentException(
1341 "AddLstmLayer: Recurrent To Input Weights cannot be NULL");
1342 }
1343 if(params.m_InputGateBias == nullptr)
1344 {
1345 throw InvalidArgumentException("AddLstmLayer: Input Gate Bias cannot be NULL");
1346 }
1347 layer->m_CifgParameters.m_InputToInputWeights =
1348 std::make_unique<ScopedCpuTensorHandle>(*(params.m_InputToInputWeights));
1349 layer->m_CifgParameters.m_RecurrentToInputWeights =
1350 std::make_unique<ScopedCpuTensorHandle>(*(params.m_RecurrentToInputWeights));
1351 // In the VTS tests, cell-to-input weights may be null, even if the other CIFG params are not.
1352 if(params.m_CellToInputWeights != nullptr)
1353 {
1354 layer->m_CifgParameters.m_CellToInputWeights =
1355 std::make_unique<ScopedCpuTensorHandle>(*(params.m_CellToInputWeights));
1356 }
1357 layer->m_CifgParameters.m_InputGateBias =
1358 std::make_unique<ScopedCpuTensorHandle>(*(params.m_InputGateBias));
1359 }
1360
1361 //Lstm projection parameters
1362 if(descriptor.m_ProjectionEnabled)
1363 {
1364 if(params.m_ProjectionWeights == nullptr)
1365 {
1366 throw InvalidArgumentException("AddLstmLayer: Projection Weights cannot be NULL");
1367 }
1368 layer->m_ProjectionParameters.m_ProjectionWeights =
1369 std::make_unique<ScopedCpuTensorHandle>(*(params.m_ProjectionWeights));
1370 if(params.m_ProjectionBias != nullptr)
1371 {
1372 layer->m_ProjectionParameters.m_ProjectionBias =
1373 std::make_unique<ScopedCpuTensorHandle>(*(params.m_ProjectionBias));
1374 }
1375 }
1376
1377 //Lstm Peephole params
1378 if(descriptor.m_PeepholeEnabled)
1379 {
1380 if(params.m_CellToForgetWeights == nullptr)
1381 {
1382 throw InvalidArgumentException("AddLstmLayer: Cell To Forget Weights cannot be NULL");
1383 }
1384 if(params.m_CellToOutputWeights == nullptr)
1385 {
1386 throw InvalidArgumentException("AddLstmLayer: Cell To Output Weights cannot be NULL");
1387 }
1388 layer->m_PeepholeParameters.m_CellToForgetWeights =
1389 std::make_unique<ScopedCpuTensorHandle>(*(params.m_CellToForgetWeights));
1390 layer->m_PeepholeParameters.m_CellToOutputWeights =
1391 std::make_unique<ScopedCpuTensorHandle>(*(params.m_CellToOutputWeights));
1392 }
Jan Eilersf8c62972019-07-17 11:07:49 +01001393
1394 //Lstm Layer Normalization params
1395 if(descriptor.m_LayerNormEnabled)
1396 {
1397 if(!descriptor.m_CifgEnabled)
1398 {
1399 if(params.m_InputLayerNormWeights == nullptr)
1400 {
1401 throw InvalidArgumentException("AddLstmLayer: Input layer normalization weights cannot be NULL");
1402 }
1403 layer->m_LayerNormParameters.m_InputLayerNormWeights =
1404 std::make_unique<ScopedCpuTensorHandle>(*(params.m_InputLayerNormWeights));
1405 }
1406
1407 if(params.m_ForgetLayerNormWeights == nullptr)
1408 {
1409 throw InvalidArgumentException("AddLstmLayer: Forget layer normalization weights cannot be NULL");
1410 }
1411 if(params.m_CellLayerNormWeights == nullptr)
1412 {
1413 throw InvalidArgumentException("AddLstmLayer: Cell layer normalization weights cannot be NULL");
1414 }
1415 if(params.m_OutputLayerNormWeights == nullptr)
1416 {
1417 throw InvalidArgumentException("AddLstmLayer: Output layer normalization weights cannot be NULL");
1418 }
1419 layer->m_LayerNormParameters.m_ForgetLayerNormWeights =
1420 std::make_unique<ScopedCpuTensorHandle>(*(params.m_ForgetLayerNormWeights));
1421 layer->m_LayerNormParameters.m_CellLayerNormWeights =
1422 std::make_unique<ScopedCpuTensorHandle>(*(params.m_CellLayerNormWeights));
1423 layer->m_LayerNormParameters.m_OutputLayerNormWeights =
1424 std::make_unique<ScopedCpuTensorHandle>(*(params.m_OutputLayerNormWeights));
1425 }
telsoa01c577f2c2018-08-31 09:22:23 +01001426 return layer;
1427}
1428
Francis Murtaghe7a86a42018-08-29 12:42:10 +01001429IConnectableLayer* Network::AddDivisionLayer(const char* name)
1430{
1431 return m_Graph->AddLayer<DivisionLayer>(name);
1432}
1433
David Beck19526222018-09-12 16:00:08 +01001434IConnectableLayer* Network::AddSubtractionLayer(const char* name)
1435{
1436 return m_Graph->AddLayer<SubtractionLayer>(name);
1437}
1438
narpra0132b90462018-09-13 11:07:48 +01001439IConnectableLayer* Network::AddMeanLayer(const MeanDescriptor& meanDescriptor, const char* name)
1440{
1441 return m_Graph->AddLayer<MeanLayer>(meanDescriptor,name);
1442}
1443
Mohamed Nour Abouelseoud5662c202018-09-24 13:30:09 +01001444IConnectableLayer* Network::AddPadLayer(const PadDescriptor& padDescriptor, const char* name)
1445{
1446 return m_Graph->AddLayer<PadLayer>(padDescriptor,name);
1447}
1448
Derek Lambertia9cca6a2019-03-25 15:41:58 +00001449IConnectableLayer *Network::AddQuantizeLayer(const char *name)
1450{
1451 return m_Graph->AddLayer<QuantizeLayer>(name);
1452}
1453
Nattapat Chaimanowonge4294fd2019-03-28 09:56:53 +00001454IConnectableLayer* Network::AddDequantizeLayer(const char* name)
1455{
1456 return m_Graph->AddLayer<DequantizeLayer>(name);
1457}
1458
Conor Kennedy430b5d82018-11-14 15:28:28 +00001459IConnectableLayer* Network::AddStridedSliceLayer(const StridedSliceDescriptor& stridedSliceDescriptor,
1460 const char* name)
1461{
1462 return m_Graph->AddLayer<StridedSliceLayer>(stridedSliceDescriptor, name);
1463}
1464
Matteo Martincigh59a950c2018-12-13 12:48:25 +00001465IConnectableLayer* Network::AddGreaterLayer(const char* name)
1466{
Aron Virginas-Tar77bfb5e2019-10-16 17:45:38 +01001467 return AddComparisonLayer(ComparisonDescriptor(ComparisonOperation::Greater), name);
Matteo Martincigh59a950c2018-12-13 12:48:25 +00001468}
1469
FrancisMurtagh20995952018-12-17 12:11:36 +00001470IConnectableLayer* Network::AddEqualLayer(const char* name)
1471{
Aron Virginas-Tar77bfb5e2019-10-16 17:45:38 +01001472 return AddComparisonLayer(ComparisonDescriptor(ComparisonOperation::Equal), name);
FrancisMurtagh20995952018-12-17 12:11:36 +00001473}
1474
Mohamed Nour Abouelseouda1d3c6a2018-12-27 12:39:16 +00001475IConnectableLayer* Network::AddRsqrtLayer(const char * name)
1476{
1477 return m_Graph->AddLayer<RsqrtLayer>(name);
1478}
1479
narpra01b89b05f2019-01-16 09:53:09 +00001480IConnectableLayer* Network::AddGatherLayer(const char* name)
1481{
1482 return m_Graph->AddLayer<GatherLayer>(name);
1483}
1484
Nattapat Chaimanowong1f886302019-04-05 13:37:19 +01001485IConnectableLayer* Network::AddMergeLayer(const char* name)
1486{
1487 return m_Graph->AddLayer<MergeLayer>(name);
1488}
1489
Sadik Armaganeff363d2019-04-05 15:25:46 +01001490IConnectableLayer* Network::AddSwitchLayer(const char* name)
1491{
1492 return m_Graph->AddLayer<SwitchLayer>(name);
1493}
1494
Matteo Martincigh0e406ee2019-06-12 15:42:18 +01001495IConnectableLayer* Network::AddPreluLayer(const char* name)
1496{
1497 return m_Graph->AddLayer<PreluLayer>(name);
1498}
1499
Aron Virginas-Tar639fb042019-06-20 14:28:19 +01001500IConnectableLayer* Network::AddTransposeConvolution2dLayer(const TransposeConvolution2dDescriptor& descriptor,
1501 const ConstTensor& weights,
1502 const Optional<ConstTensor>& biases,
1503 const char* name)
1504{
1505 if (descriptor.m_BiasEnabled && !biases.has_value())
1506 {
1507 throw InvalidArgumentException("AddTransposeConvolution2dLayer: Biases cannot be empty");
1508 }
1509
1510 const auto layer = m_Graph->AddLayer<TransposeConvolution2dLayer>(descriptor, name);
1511
1512 layer->m_Weight = std::make_unique<ScopedCpuTensorHandle>(weights);
1513
1514 if (descriptor.m_BiasEnabled)
1515 {
1516 layer->m_Bias = std::make_unique<ScopedCpuTensorHandle>(biases.value());
1517 }
1518
1519 return layer;
1520}
1521
Matthew Jackson2b8c1da2019-07-04 14:59:16 +01001522IConnectableLayer* Network::AddStackLayer(const StackDescriptor& stackDescriptor,
1523 const char* name)
1524{
1525 return m_Graph->AddLayer<StackLayer>(stackDescriptor, name);
1526}
1527
Derek Lamberti013c3902019-10-21 10:46:16 +01001528
1529IConnectableLayer* Network::AddStandInLayer(const StandInDescriptor& desc,
1530 const char* name)
1531{
1532 return m_Graph->AddLayer<StandInLayer>(desc, name);
1533}
1534
James Conroyee18dc82019-07-17 11:27:46 +01001535IConnectableLayer* Network::AddQuantizedLstmLayer(const QuantizedLstmInputParams& params,
1536 const char* name)
1537{
1538 const auto layer = m_Graph->AddLayer<QuantizedLstmLayer>(name);
1539
1540 // InputToX weights
1541 layer->m_QuantizedLstmParameters.m_InputToInputWeights =
Francis Murtaghbb590b42019-08-14 09:51:36 +01001542 std::make_unique<ScopedCpuTensorHandle>(params.GetInputToInputWeights());
James Conroyee18dc82019-07-17 11:27:46 +01001543 layer->m_QuantizedLstmParameters.m_InputToForgetWeights =
Francis Murtaghbb590b42019-08-14 09:51:36 +01001544 std::make_unique<ScopedCpuTensorHandle>(params.GetInputToForgetWeights());
James Conroyee18dc82019-07-17 11:27:46 +01001545 layer->m_QuantizedLstmParameters.m_InputToCellWeights =
Francis Murtaghbb590b42019-08-14 09:51:36 +01001546 std::make_unique<ScopedCpuTensorHandle>(params.GetInputToCellWeights());
James Conroyee18dc82019-07-17 11:27:46 +01001547 layer->m_QuantizedLstmParameters.m_InputToOutputWeights =
Francis Murtaghbb590b42019-08-14 09:51:36 +01001548 std::make_unique<ScopedCpuTensorHandle>(params.GetInputToOutputWeights());
James Conroyee18dc82019-07-17 11:27:46 +01001549
1550 // RecurrentToX weights
1551 layer->m_QuantizedLstmParameters.m_RecurrentToInputWeights =
Francis Murtaghbb590b42019-08-14 09:51:36 +01001552 std::make_unique<ScopedCpuTensorHandle>(params.GetRecurrentToInputWeights());
James Conroyee18dc82019-07-17 11:27:46 +01001553 layer->m_QuantizedLstmParameters.m_RecurrentToForgetWeights =
Francis Murtaghbb590b42019-08-14 09:51:36 +01001554 std::make_unique<ScopedCpuTensorHandle>(params.GetRecurrentToForgetWeights());
James Conroyee18dc82019-07-17 11:27:46 +01001555 layer->m_QuantizedLstmParameters.m_RecurrentToCellWeights =
Francis Murtaghbb590b42019-08-14 09:51:36 +01001556 std::make_unique<ScopedCpuTensorHandle>(params.GetRecurrentToCellWeights());
James Conroyee18dc82019-07-17 11:27:46 +01001557 layer->m_QuantizedLstmParameters.m_RecurrentToOutputWeights =
Francis Murtaghbb590b42019-08-14 09:51:36 +01001558 std::make_unique<ScopedCpuTensorHandle>(params.GetRecurrentToOutputWeights());
James Conroyee18dc82019-07-17 11:27:46 +01001559
1560 // Bias
1561 layer->m_QuantizedLstmParameters.m_InputGateBias =
Francis Murtaghbb590b42019-08-14 09:51:36 +01001562 std::make_unique<ScopedCpuTensorHandle>(params.GetInputGateBias());
James Conroyee18dc82019-07-17 11:27:46 +01001563 layer->m_QuantizedLstmParameters.m_ForgetGateBias =
Francis Murtaghbb590b42019-08-14 09:51:36 +01001564 std::make_unique<ScopedCpuTensorHandle>(params.GetForgetGateBias());
James Conroyee18dc82019-07-17 11:27:46 +01001565 layer->m_QuantizedLstmParameters.m_CellBias =
Francis Murtaghbb590b42019-08-14 09:51:36 +01001566 std::make_unique<ScopedCpuTensorHandle>(params.GetCellBias());
James Conroyee18dc82019-07-17 11:27:46 +01001567 layer->m_QuantizedLstmParameters.m_OutputGateBias =
Francis Murtaghbb590b42019-08-14 09:51:36 +01001568 std::make_unique<ScopedCpuTensorHandle>(params.GetOutputGateBias());
James Conroyee18dc82019-07-17 11:27:46 +01001569
1570 return layer;
1571}
1572
Mike Kelly8c1701a2019-02-11 17:01:27 +00001573void Network::Accept(ILayerVisitor& visitor) const
1574{
1575 for (auto layer : GetGraph())
1576 {
1577 layer->Accept(visitor);
1578 };
1579}
1580
telsoa014fcda012018-03-09 14:13:49 +00001581OptimizedNetwork::OptimizedNetwork(std::unique_ptr<Graph> graph)
Jan Eilers99d9d4a2019-11-06 10:02:16 +00001582 : m_Graph(std::move(graph)),
1583 m_Guid(profiling::ProfilingService::Instance().NextGuid())
telsoa014fcda012018-03-09 14:13:49 +00001584{
1585}
1586
1587OptimizedNetwork::~OptimizedNetwork()
1588{
1589}
1590
1591} // namespace armnn