blob: 17876753fb0b6233dddc3fdc07a662dd05a6541c [file] [log] [blame]
arovir014424b0a2018-10-04 10:46:04 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "NeonBackend.hpp"
David Beck3e9e1152018-10-17 14:17:50 +01007#include "NeonBackendId.hpp"
Sadik Armagan045f6be2020-09-10 13:37:32 +01008#include "NeonBackendModelContext.hpp"
arovir01a0944792018-10-11 15:00:58 +01009#include "NeonWorkloadFactory.hpp"
David Beck111b5d92018-11-12 14:59:37 +000010#include "NeonLayerSupport.hpp"
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +010011#include "NeonTensorHandleFactory.hpp"
arovir01a0944792018-10-11 15:00:58 +010012
Matteo Martincighc601aa62019-10-29 15:03:22 +000013#include <armnn/BackendRegistry.hpp>
Mike Kelly07810fc2020-11-12 10:58:48 +000014#include <armnn/Descriptors.hpp>
Matteo Martincighc601aa62019-10-29 15:03:22 +000015
Mike Kelly07810fc2020-11-12 10:58:48 +000016#include <aclCommon/ArmComputeSubgraphUtils.hpp>
17#include <aclCommon/ArmComputeUtils.hpp>
Aron Virginas-Tar56055192018-11-12 18:10:43 +000018#include <aclCommon/BaseMemoryManager.hpp>
19
Matteo Martincighe5b8eb92019-11-28 15:45:42 +000020#include <armnn/backends/IBackendContext.hpp>
21#include <armnn/backends/IMemoryManager.hpp>
Aron Virginas-Tar56055192018-11-12 18:10:43 +000022
Jan Eilers3c9e0452020-04-10 13:00:44 +010023#include <armnn/utility/PolymorphicDowncast.hpp>
24
Mike Kelly07810fc2020-11-12 10:58:48 +000025#include "workloads/NeonAdditionWorkload.hpp"
26#include "workloads/NeonBatchNormalizationWorkload.hpp"
27#include "workloads/NeonConvolution2dWorkload.hpp"
28#include "workloads/NeonDepthwiseConvolutionWorkload.hpp"
29#include "workloads/NeonDivisionWorkload.hpp"
30#include "workloads/NeonFullyConnectedWorkload.hpp"
31#include "workloads/NeonMultiplicationWorkload.hpp"
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +010032#include "workloads/NeonReduceWorkload.hpp"
Mike Kelly07810fc2020-11-12 10:58:48 +000033#include "workloads/NeonSubtractionWorkload.hpp"
34
David Beck263e3492018-11-09 14:46:40 +000035#include <Optimizer.hpp>
arovir01a0944792018-10-11 15:00:58 +010036
Mike Kelly07810fc2020-11-12 10:58:48 +000037#include <arm_compute/core/Types.h>
Aron Virginas-Tar56055192018-11-12 18:10:43 +000038#include <arm_compute/runtime/Allocator.h>
39
arovir014424b0a2018-10-04 10:46:04 +010040namespace armnn
41{
42
David Beck3cc9a622018-10-12 10:38:31 +010043const BackendId& NeonBackend::GetIdStatic()
arovir014424b0a2018-10-04 10:46:04 +010044{
David Beck3e9e1152018-10-17 14:17:50 +010045 static const BackendId s_Id{NeonBackendId()};
arovir014424b0a2018-10-04 10:46:04 +010046 return s_Id;
47}
48
Aron Virginas-Tar56055192018-11-12 18:10:43 +000049IBackendInternal::IMemoryManagerUniquePtr NeonBackend::CreateMemoryManager() const
arovir014424b0a2018-10-04 10:46:04 +010050{
Aron Virginas-Tar56055192018-11-12 18:10:43 +000051 return std::make_unique<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
Sadik Armagan13a9fa62019-04-26 16:04:34 +010052 BaseMemoryManager::MemoryAffinity::Offset);
Aron Virginas-Tar56055192018-11-12 18:10:43 +000053}
54
55IBackendInternal::IWorkloadFactoryPtr NeonBackend::CreateWorkloadFactory(
56 const IBackendInternal::IMemoryManagerSharedPtr& memoryManager) const
57{
58 return std::make_unique<NeonWorkloadFactory>(
Jan Eilers3c9e0452020-04-10 13:00:44 +010059 PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager));
arovir014424b0a2018-10-04 10:46:04 +010060}
61
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +010062IBackendInternal::IWorkloadFactoryPtr NeonBackend::CreateWorkloadFactory(
Sadik Armagan04a72972020-09-14 15:44:18 +010063 const IBackendInternal::IMemoryManagerSharedPtr& memoryManager, const ModelOptions& modelOptions) const
64{
65 return std::make_unique<NeonWorkloadFactory>(
66 PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager), CreateBackendSpecificModelContext(modelOptions));
67}
68
69IBackendInternal::IWorkloadFactoryPtr NeonBackend::CreateWorkloadFactory(
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +010070 class TensorHandleFactoryRegistry& tensorHandleFactoryRegistry) const
71{
72 auto memoryManager = std::make_shared<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
73 BaseMemoryManager::MemoryAffinity::Offset);
74
75 tensorHandleFactoryRegistry.RegisterMemoryManager(memoryManager);
Narumol Prangnawarat549cb7a2020-07-10 17:50:53 +010076 tensorHandleFactoryRegistry.RegisterFactory(std::make_unique<NeonTensorHandleFactory>(memoryManager));
77
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +010078 return std::make_unique<NeonWorkloadFactory>(
Jan Eilers3c9e0452020-04-10 13:00:44 +010079 PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager));
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +010080}
81
Sadik Armagan04a72972020-09-14 15:44:18 +010082IBackendInternal::IWorkloadFactoryPtr NeonBackend::CreateWorkloadFactory(
83 TensorHandleFactoryRegistry& tensorHandleFactoryRegistry, const ModelOptions& modelOptions) const
84{
85 auto memoryManager = std::make_shared<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
86 BaseMemoryManager::MemoryAffinity::Offset);
87
88 tensorHandleFactoryRegistry.RegisterMemoryManager(memoryManager);
89 tensorHandleFactoryRegistry.RegisterFactory(std::make_unique<NeonTensorHandleFactory>(memoryManager));
90
91 return std::make_unique<NeonWorkloadFactory>(
92 PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager), CreateBackendSpecificModelContext(modelOptions));
93}
94
David Beck263e3492018-11-09 14:46:40 +000095IBackendInternal::IBackendContextPtr NeonBackend::CreateBackendContext(const IRuntime::CreationOptions&) const
96{
97 return IBackendContextPtr{};
98}
99
Colm Donelane49755b2020-01-29 15:22:43 +0000100IBackendInternal::IBackendProfilingContextPtr NeonBackend::CreateBackendProfilingContext(
Colm Donelan1aff3932020-02-05 17:48:59 +0000101 const IRuntime::CreationOptions&, IBackendProfilingPtr&)
Colm Donelane49755b2020-01-29 15:22:43 +0000102{
103 return IBackendProfilingContextPtr{};
104}
105
David Beck263e3492018-11-09 14:46:40 +0000106IBackendInternal::Optimizations NeonBackend::GetOptimizations() const
107{
108 return Optimizations{};
109}
110
Sadik Armagan045f6be2020-09-10 13:37:32 +0100111IBackendInternal::IBackendSpecificModelContextPtr NeonBackend::CreateBackendSpecificModelContext(
112 const ModelOptions& modelOptions) const
113{
114 return IBackendSpecificModelContextPtr{new NeonBackendModelContext{modelOptions}};
115}
116
David Beck111b5d92018-11-12 14:59:37 +0000117IBackendInternal::ILayerSupportSharedPtr NeonBackend::GetLayerSupport() const
118{
Sadik Armagan045f6be2020-09-10 13:37:32 +0100119 static ILayerSupportSharedPtr layerSupport
120 {
121 new NeonLayerSupport(IBackendInternal::IBackendSpecificModelContextPtr{})
122 };
123 return layerSupport;
124}
125
126IBackendInternal::ILayerSupportSharedPtr NeonBackend::GetLayerSupport(const ModelOptions& modelOptions) const
127{
128 static ILayerSupportSharedPtr layerSupport
129 {
130 new NeonLayerSupport(CreateBackendSpecificModelContext(modelOptions))
131 };
David Beck111b5d92018-11-12 14:59:37 +0000132 return layerSupport;
133}
134
Matteo Martincighc3ba50e2019-05-22 14:28:16 +0100135OptimizationViews NeonBackend::OptimizeSubgraphView(const SubgraphView& subgraph) const
Matteo Martincighadddddb2019-01-24 14:06:23 +0000136{
Matteo Martincighc3ba50e2019-05-22 14:28:16 +0100137 OptimizationViews optimizationViews;
Matteo Martincighadddddb2019-01-24 14:06:23 +0000138
Mike Kelly07810fc2020-11-12 10:58:48 +0000139 auto it = subgraph.end();
Mike Kelly1ac690a2020-11-17 11:41:38 +0000140 std::map<LayerGuid, Layer*> untouched;
Mike Kelly07810fc2020-11-12 10:58:48 +0000141
142 while (it != subgraph.begin())
143 {
144 --it;
145 Layer& base = **it;
Mike Kelly1ac690a2020-11-17 11:41:38 +0000146 untouched.insert({base.GetGuid(), &base});
147 }
148
149 it = subgraph.end();
150 while (it != subgraph.begin())
151 {
152 --it;
153 Layer& base = **it;
Mike Kelly07810fc2020-11-12 10:58:48 +0000154
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100155 // Fuse activation into previous layer if supported by backend
Mike Kelly07810fc2020-11-12 10:58:48 +0000156 if ((base.GetType() == LayerType::DepthwiseConvolution2d || base.GetType() == LayerType::Convolution2d
157 || base.GetType() == LayerType::BatchNormalization || base.GetType() == LayerType::FullyConnected
158 || base.GetType() == LayerType::Addition || base.GetType() == LayerType::Multiplication
Matthew Sloyanae123062021-05-07 14:18:01 +0000159 || base.GetType() == LayerType::Subtraction || base.GetType() == LayerType::Division)
Mike Kelly07810fc2020-11-12 10:58:48 +0000160 && (base.GetAdditionalInformation<ActivationDescriptor>() == nullptr))
161 {
162 for (auto output = base.BeginOutputSlots(); output != base.EndOutputSlots(); ++output)
163 {
164 if (output->GetNumConnections() == 1)
165 {
166 for (auto&& childInput : output->GetConnections())
167 {
Teresa Charlind672f5d2021-01-18 18:07:57 +0000168 if ((childInput->GetOwningLayer().GetType() == LayerType::Activation) &&
169 (checkDataTypeInputandOutput(childInput->GetOwningLayer())))
Mike Kelly07810fc2020-11-12 10:58:48 +0000170 {
171 Layer& child = childInput->GetOwningLayer();
172
173 auto* activationLayer = PolymorphicDowncast<ActivationLayer*>(&child);
174
175 const std::string name = std::string("fused-") + child.GetName() + std::string("-into-") +
176 base.GetName();
177
178 // Get params from activation layer
179 ActivationDescriptor activationDesc = activationLayer->GetParameters();
180
181 if (base.GetType() == LayerType::Convolution2d)
182 {
183 Convolution2dLayer* baseLayer = PolymorphicDowncast<Convolution2dLayer*>(&base);
184
185 Optional<TensorInfo> biases;
186
187 if (baseLayer->GetParameters().m_BiasEnabled)
188 {
Mike Kelly1ac690a2020-11-17 11:41:38 +0000189 biases = baseLayer->m_Bias->GetTensorInfo();
Mike Kelly07810fc2020-11-12 10:58:48 +0000190 }
191
192 arm_compute::Status status = NeonConvolution2dWorkloadValidate(
193 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
194 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
195 baseLayer->GetParameters(),
196 baseLayer->m_Weight->GetTensorInfo(),
197 biases,
198 false,
199 &activationDesc);
200
201 if (status)
202 {
203 FuseLayerWithWeightsAndBiases<Convolution2dLayer>(optimizationViews,
204 baseLayer,
205 activationLayer,
206 activationDesc,
207 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000208 untouched.erase(baseLayer->GetGuid());
209 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000210 }
211 }
212 else if (base.GetType() == LayerType::DepthwiseConvolution2d)
213 {
214 DepthwiseConvolution2dLayer* baseLayer =
215 PolymorphicDowncast<DepthwiseConvolution2dLayer*>(&base);
216
217 Optional<TensorInfo> biases;
218
219 if (baseLayer->GetParameters().m_BiasEnabled)
220 {
Mike Kelly1ac690a2020-11-17 11:41:38 +0000221 biases = baseLayer->m_Bias->GetTensorInfo();
Mike Kelly07810fc2020-11-12 10:58:48 +0000222 }
223
224 arm_compute::Status status = NeonDepthwiseConvolutionWorkloadValidate(
225 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
226 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
227 baseLayer->GetParameters(),
228 baseLayer->m_Weight->GetTensorInfo(),
229 biases,
230 &activationDesc);
231
232 if (status)
233 {
234 FuseLayerWithWeightsAndBiases<DepthwiseConvolution2dLayer>(optimizationViews,
235 baseLayer,
236 activationLayer,
237 activationDesc,
238 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000239 untouched.erase(baseLayer->GetGuid());
240 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000241 }
242 }
243 else if (base.GetType() == LayerType::FullyConnected)
244 {
245 FullyConnectedLayer* baseLayer = PolymorphicDowncast<FullyConnectedLayer*>(&base);
246
247 arm_compute::Status status = NeonFullyConnectedWorkloadValidate(
248 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
249 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
250 baseLayer->m_Weight->GetTensorInfo(),
251 baseLayer->m_Bias->GetTensorInfo(),
252 baseLayer->GetParameters(),
253 &activationDesc);
254
255 if (status)
256 {
257 FuseLayerWithWeightsAndBiases<FullyConnectedLayer>(optimizationViews,
258 baseLayer,
259 activationLayer,
260 activationDesc,
261 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000262 untouched.erase(baseLayer->GetGuid());
263 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000264 }
265 }
266 else if (base.GetType() == LayerType::BatchNormalization)
267 {
268 BatchNormalizationLayer* baseLayer =
269 PolymorphicDowncast<BatchNormalizationLayer*>(&base);
270
271 arm_compute::Status status = NeonBatchNormalizationValidate(
272 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
273 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
274 baseLayer->m_Mean->GetTensorInfo(),
275 baseLayer->m_Variance->GetTensorInfo(),
276 baseLayer->m_Beta->GetTensorInfo(),
277 baseLayer->m_Gamma->GetTensorInfo(),
278 baseLayer->GetParameters(),
279 &activationDesc);
280
281 if (status)
282 {
283 BatchNormalizationLayer* replacementLayer =
284 FuseLayerWithParameters<BatchNormalizationLayer>(
285 optimizationViews,
286 baseLayer,
287 activationLayer,
288 activationDesc,
289 name);
290
291 replacementLayer->m_Beta = std::move(baseLayer->m_Beta);
292 replacementLayer->m_Gamma = std::move(baseLayer->m_Gamma);
293 replacementLayer->m_Mean = std::move(baseLayer->m_Mean);
294 replacementLayer->m_Variance = std::move(baseLayer->m_Variance);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000295 untouched.erase(baseLayer->GetGuid());
296 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000297 }
298 }
299 else if (base.GetType() == LayerType::Addition)
300 {
301 AdditionLayer* baseLayer = PolymorphicDowncast<AdditionLayer*>(&base);
302
303 arm_compute::Status status = NeonAdditionWorkloadValidate(
304 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
305 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
306 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
307 &activationDesc);
308
309 if (status)
310 {
311 FuseLayerWithoutParameters<AdditionLayer>(optimizationViews,
312 baseLayer,
313 activationLayer,
314 activationDesc,
315 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000316 untouched.erase(baseLayer->GetGuid());
317 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000318 }
319 }
320 else if (base.GetType() == LayerType::Division)
321 {
322 DivisionLayer* baseLayer = PolymorphicDowncast<DivisionLayer*>(&base);
323
324 arm_compute::Status status = NeonDivisionWorkloadValidate(
325 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
326 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
327 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
328 &activationDesc);
329
330 if (status)
331 {
332 FuseLayerWithoutParameters<DivisionLayer>(optimizationViews,
333 baseLayer,
334 activationLayer,
335 activationDesc,
336 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000337 untouched.erase(baseLayer->GetGuid());
338 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000339 }
340 }
341 else if (base.GetType() == LayerType::Multiplication)
342 {
343 MultiplicationLayer* baseLayer = PolymorphicDowncast<MultiplicationLayer*>(&base);
344
345 arm_compute::Status status = NeonMultiplicationWorkloadValidate(
346 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
347 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
348 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
349 &activationDesc);
350
351 if (status)
352 {
353 FuseLayerWithoutParameters<MultiplicationLayer>(optimizationViews,
354 baseLayer,
355 activationLayer,
356 activationDesc,
357 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000358 untouched.erase(baseLayer->GetGuid());
359 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000360 }
361 }
362 else if (base.GetType() == LayerType::Subtraction)
363 {
364 SubtractionLayer* baseLayer = PolymorphicDowncast<SubtractionLayer*>(&base);
365
366 arm_compute::Status status = NeonSubtractionWorkloadValidate(
367 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
368 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
369 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
370 &activationDesc);
371
372 if (status)
373 {
374 FuseLayerWithoutParameters<SubtractionLayer>(optimizationViews,
375 baseLayer,
376 activationLayer,
377 activationDesc,
378 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000379 untouched.erase(baseLayer->GetGuid());
380 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000381 }
382 }
383 }
384 }
385 }
386 }
387 }
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100388
389 // Separate reduce layer with multiple axes into multiple reduce layers with 1 axis.
390 if (base.GetType() == LayerType::Reduce)
391 {
392 ReduceLayer* baseLayer = PolymorphicDowncast<ReduceLayer*>(&base);
393 ReduceDescriptor reduceDescriptor = baseLayer->GetParameters();
394
395 if (!reduceDescriptor.m_vAxis.empty() && reduceDescriptor.m_vAxis.size() > 1)
396 {
397 // Add new layers to the graph and connect them.
398 std::vector<Layer*> layers = ChainReduceLayers<ReduceLayer>(optimizationViews,
399 baseLayer,
400 reduceDescriptor);
401
402 // Replace existing baselayer with new subgraph.
403 ReplaceLayers<ReduceLayer>(optimizationViews, baseLayer, layers);
404 untouched.erase(baseLayer->GetGuid());
405 }
406 }
Mike Kelly07810fc2020-11-12 10:58:48 +0000407 }
408
409 if (optimizationViews.GetSubstitutions().empty())
410 {
411 optimizationViews.AddUntouchedSubgraph(SubgraphView(subgraph));
412 }
Mike Kelly1ac690a2020-11-17 11:41:38 +0000413 else
414 {
415 ReportUntouchedLayers(optimizationViews, untouched);
416 }
Matteo Martincighc3ba50e2019-05-22 14:28:16 +0100417
418 return optimizationViews;
Matteo Martincighadddddb2019-01-24 14:06:23 +0000419}
420
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +0100421std::vector<ITensorHandleFactory::FactoryId> NeonBackend::GetHandleFactoryPreferences() const
422{
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000423 return std::vector<ITensorHandleFactory::FactoryId>() = { NeonTensorHandleFactory::GetIdStatic() };
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +0100424}
425
426void NeonBackend::RegisterTensorHandleFactories(class TensorHandleFactoryRegistry& registry)
427{
428 auto memoryManager = std::make_shared<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
429 BaseMemoryManager::MemoryAffinity::Offset);
430
431 registry.RegisterMemoryManager(memoryManager);
Jan Eilerse9f0f0f2019-08-16 10:28:37 +0100432 registry.RegisterFactory(std::make_unique<NeonTensorHandleFactory>(memoryManager));
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +0100433}
434
Matthew Bentham42bad952018-12-17 09:23:36 +0000435} // namespace armnn