blob: b5719db007fa7e5498b35b1f8e856eeb7d8bbcaa [file] [log] [blame]
arovir014424b0a2018-10-04 10:46:04 +01001//
Mike Kelly3ec30772023-03-08 13:47:17 +00002// Copyright © 2017-2023 Arm Ltd and Contributors. All rights reserved.
arovir014424b0a2018-10-04 10:46:04 +01003// 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
Francis Murtaghe8d7ccb2021-10-14 17:30:24 +010025#include <neon/workloads/NeonAdditionWorkload.hpp>
26#include <neon/workloads/NeonBatchNormalizationWorkload.hpp>
27#include <neon/workloads/NeonConvolution2dWorkload.hpp>
28#include <neon/workloads/NeonDepthwiseConvolutionWorkload.hpp>
29#include <neon/workloads/NeonDivisionWorkload.hpp>
30#include <neon/workloads/NeonFullyConnectedWorkload.hpp>
31#include <neon/workloads/NeonMultiplicationWorkload.hpp>
32#include <neon/workloads/NeonReduceWorkload.hpp>
33#include <neon/workloads/NeonSubtractionWorkload.hpp>
34#include <backendsCommon/DefaultAllocator.hpp>
Mike Kelly07810fc2020-11-12 10:58:48 +000035
David Beck263e3492018-11-09 14:46:40 +000036#include <Optimizer.hpp>
arovir01a0944792018-10-11 15:00:58 +010037
Mike Kelly07810fc2020-11-12 10:58:48 +000038#include <arm_compute/core/Types.h>
Aron Virginas-Tar56055192018-11-12 18:10:43 +000039#include <arm_compute/runtime/Allocator.h>
40
arovir014424b0a2018-10-04 10:46:04 +010041namespace armnn
42{
43
David Beck3cc9a622018-10-12 10:38:31 +010044const BackendId& NeonBackend::GetIdStatic()
arovir014424b0a2018-10-04 10:46:04 +010045{
David Beck3e9e1152018-10-17 14:17:50 +010046 static const BackendId s_Id{NeonBackendId()};
arovir014424b0a2018-10-04 10:46:04 +010047 return s_Id;
48}
49
Aron Virginas-Tar56055192018-11-12 18:10:43 +000050IBackendInternal::IMemoryManagerUniquePtr NeonBackend::CreateMemoryManager() const
arovir014424b0a2018-10-04 10:46:04 +010051{
Aron Virginas-Tar56055192018-11-12 18:10:43 +000052 return std::make_unique<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
Sadik Armagan13a9fa62019-04-26 16:04:34 +010053 BaseMemoryManager::MemoryAffinity::Offset);
Aron Virginas-Tar56055192018-11-12 18:10:43 +000054}
55
56IBackendInternal::IWorkloadFactoryPtr NeonBackend::CreateWorkloadFactory(
57 const IBackendInternal::IMemoryManagerSharedPtr& memoryManager) const
58{
59 return std::make_unique<NeonWorkloadFactory>(
Jan Eilers3c9e0452020-04-10 13:00:44 +010060 PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager));
arovir014424b0a2018-10-04 10:46:04 +010061}
62
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +010063IBackendInternal::IWorkloadFactoryPtr NeonBackend::CreateWorkloadFactory(
Sadik Armagan04a72972020-09-14 15:44:18 +010064 const IBackendInternal::IMemoryManagerSharedPtr& memoryManager, const ModelOptions& modelOptions) const
65{
66 return std::make_unique<NeonWorkloadFactory>(
67 PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager), CreateBackendSpecificModelContext(modelOptions));
68}
69
70IBackendInternal::IWorkloadFactoryPtr NeonBackend::CreateWorkloadFactory(
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +010071 class TensorHandleFactoryRegistry& tensorHandleFactoryRegistry) const
72{
73 auto memoryManager = std::make_shared<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
74 BaseMemoryManager::MemoryAffinity::Offset);
75
76 tensorHandleFactoryRegistry.RegisterMemoryManager(memoryManager);
Narumol Prangnawarat77400452022-01-13 17:43:41 +000077
78 auto factory = std::make_unique<NeonTensorHandleFactory>(memoryManager);
79 // Register copy and import factory pair
80 tensorHandleFactoryRegistry.RegisterCopyAndImportFactoryPair(factory->GetId(), factory->GetId());
81 // Register the factory
82 tensorHandleFactoryRegistry.RegisterFactory(std::move(factory));
83
Narumol Prangnawarat549cb7a2020-07-10 17:50:53 +010084
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +010085 return std::make_unique<NeonWorkloadFactory>(
Jan Eilers3c9e0452020-04-10 13:00:44 +010086 PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager));
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +010087}
88
Sadik Armagan04a72972020-09-14 15:44:18 +010089IBackendInternal::IWorkloadFactoryPtr NeonBackend::CreateWorkloadFactory(
90 TensorHandleFactoryRegistry& tensorHandleFactoryRegistry, const ModelOptions& modelOptions) const
91{
92 auto memoryManager = std::make_shared<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
93 BaseMemoryManager::MemoryAffinity::Offset);
94
95 tensorHandleFactoryRegistry.RegisterMemoryManager(memoryManager);
Narumol Prangnawarat77400452022-01-13 17:43:41 +000096
97 auto factory = std::make_unique<NeonTensorHandleFactory>(memoryManager);
98 // Register copy and import factory pair
99 tensorHandleFactoryRegistry.RegisterCopyAndImportFactoryPair(factory->GetId(), factory->GetId());
100 // Register the factory
101 tensorHandleFactoryRegistry.RegisterFactory(std::move(factory));
Sadik Armagan04a72972020-09-14 15:44:18 +0100102
103 return std::make_unique<NeonWorkloadFactory>(
104 PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager), CreateBackendSpecificModelContext(modelOptions));
105}
106
David Beck263e3492018-11-09 14:46:40 +0000107IBackendInternal::IBackendContextPtr NeonBackend::CreateBackendContext(const IRuntime::CreationOptions&) const
108{
109 return IBackendContextPtr{};
110}
111
Colm Donelane49755b2020-01-29 15:22:43 +0000112IBackendInternal::IBackendProfilingContextPtr NeonBackend::CreateBackendProfilingContext(
Colm Donelan1aff3932020-02-05 17:48:59 +0000113 const IRuntime::CreationOptions&, IBackendProfilingPtr&)
Colm Donelane49755b2020-01-29 15:22:43 +0000114{
115 return IBackendProfilingContextPtr{};
116}
117
Sadik Armagan045f6be2020-09-10 13:37:32 +0100118IBackendInternal::IBackendSpecificModelContextPtr NeonBackend::CreateBackendSpecificModelContext(
119 const ModelOptions& modelOptions) const
120{
121 return IBackendSpecificModelContextPtr{new NeonBackendModelContext{modelOptions}};
122}
123
David Beck111b5d92018-11-12 14:59:37 +0000124IBackendInternal::ILayerSupportSharedPtr NeonBackend::GetLayerSupport() const
125{
Sadik Armagan045f6be2020-09-10 13:37:32 +0100126 static ILayerSupportSharedPtr layerSupport
127 {
128 new NeonLayerSupport(IBackendInternal::IBackendSpecificModelContextPtr{})
129 };
130 return layerSupport;
131}
132
133IBackendInternal::ILayerSupportSharedPtr NeonBackend::GetLayerSupport(const ModelOptions& modelOptions) const
134{
135 static ILayerSupportSharedPtr layerSupport
136 {
137 new NeonLayerSupport(CreateBackendSpecificModelContext(modelOptions))
138 };
David Beck111b5d92018-11-12 14:59:37 +0000139 return layerSupport;
140}
141
Mike Kelly80512b02022-05-16 23:10:42 +0100142OptimizationViews NeonBackend::OptimizeSubgraphView(const SubgraphView& subgraph,
143 const ModelOptions& modelOptions) const
Matteo Martincighadddddb2019-01-24 14:06:23 +0000144{
Mike Kelly80512b02022-05-16 23:10:42 +0100145 OptimizationViews optimizationViews(modelOptions);
Matteo Martincighadddddb2019-01-24 14:06:23 +0000146
Francis Murtagh0f3e9a02023-07-28 14:29:46 +0100147 auto it = subgraph.end();
Mike Kelly1ac690a2020-11-17 11:41:38 +0000148 std::map<LayerGuid, Layer*> untouched;
Mike Kelly07810fc2020-11-12 10:58:48 +0000149
Francis Murtagh0f3e9a02023-07-28 14:29:46 +0100150 while (it != subgraph.begin())
Mike Kelly07810fc2020-11-12 10:58:48 +0000151 {
152 --it;
Francis Murtagh56ccf682021-12-13 18:48:12 +0000153 Layer& base = *(PolymorphicDowncast<Layer*>(*it));
Mike Kelly1ac690a2020-11-17 11:41:38 +0000154 untouched.insert({base.GetGuid(), &base});
155 }
156
Francis Murtagh0f3e9a02023-07-28 14:29:46 +0100157 it = subgraph.end();
158 while (it != subgraph.begin())
Mike Kelly1ac690a2020-11-17 11:41:38 +0000159 {
160 --it;
Francis Murtagh56ccf682021-12-13 18:48:12 +0000161 Layer& base = *(PolymorphicDowncast<Layer*>(*it));
Mike Kelly07810fc2020-11-12 10:58:48 +0000162
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100163 // Fuse activation into previous layer if supported by backend
Mike Kelly07810fc2020-11-12 10:58:48 +0000164 if ((base.GetType() == LayerType::DepthwiseConvolution2d || base.GetType() == LayerType::Convolution2d
165 || base.GetType() == LayerType::BatchNormalization || base.GetType() == LayerType::FullyConnected
166 || base.GetType() == LayerType::Addition || base.GetType() == LayerType::Multiplication
Teresa Charlin0aa080d2023-09-19 16:46:54 +0100167 || base.GetType() == LayerType::Subtraction || base.GetType() == LayerType::Division
168 || base.GetType() == LayerType::ElementwiseBinary)
Mike Kelly07810fc2020-11-12 10:58:48 +0000169 && (base.GetAdditionalInformation<ActivationDescriptor>() == nullptr))
170 {
171 for (auto output = base.BeginOutputSlots(); output != base.EndOutputSlots(); ++output)
172 {
173 if (output->GetNumConnections() == 1)
174 {
175 for (auto&& childInput : output->GetConnections())
176 {
Teresa Charlind672f5d2021-01-18 18:07:57 +0000177 if ((childInput->GetOwningLayer().GetType() == LayerType::Activation) &&
178 (checkDataTypeInputandOutput(childInput->GetOwningLayer())))
Mike Kelly07810fc2020-11-12 10:58:48 +0000179 {
180 Layer& child = childInput->GetOwningLayer();
181
182 auto* activationLayer = PolymorphicDowncast<ActivationLayer*>(&child);
183
184 const std::string name = std::string("fused-") + child.GetName() + std::string("-into-") +
185 base.GetName();
186
187 // Get params from activation layer
188 ActivationDescriptor activationDesc = activationLayer->GetParameters();
189
190 if (base.GetType() == LayerType::Convolution2d)
191 {
192 Convolution2dLayer* baseLayer = PolymorphicDowncast<Convolution2dLayer*>(&base);
193
194 Optional<TensorInfo> biases;
195
196 if (baseLayer->GetParameters().m_BiasEnabled)
197 {
Keith Davisb4dd5cc2022-04-07 11:32:00 +0100198 biases = baseLayer->GetInputSlot(2).GetConnectedOutputSlot()->GetTensorInfo();
Mike Kelly07810fc2020-11-12 10:58:48 +0000199 }
200
201 arm_compute::Status status = NeonConvolution2dWorkloadValidate(
202 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
203 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
204 baseLayer->GetParameters(),
Keith Davisb4dd5cc2022-04-07 11:32:00 +0100205 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
Mike Kelly07810fc2020-11-12 10:58:48 +0000206 biases,
207 false,
208 &activationDesc);
209
210 if (status)
211 {
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000212 FuseConvolution2dLayer<Convolution2dLayer>(optimizationViews,
213 baseLayer,
214 activationLayer,
215 activationDesc,
216 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000217 untouched.erase(baseLayer->GetGuid());
218 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000219 }
220 }
221 else if (base.GetType() == LayerType::DepthwiseConvolution2d)
222 {
223 DepthwiseConvolution2dLayer* baseLayer =
224 PolymorphicDowncast<DepthwiseConvolution2dLayer*>(&base);
225
226 Optional<TensorInfo> biases;
227
228 if (baseLayer->GetParameters().m_BiasEnabled)
229 {
Cathal Corbett06902652022-04-14 17:55:11 +0100230 biases = baseLayer->GetInputSlot(2).GetConnectedOutputSlot()->GetTensorInfo();
Mike Kelly07810fc2020-11-12 10:58:48 +0000231 }
232
233 arm_compute::Status status = NeonDepthwiseConvolutionWorkloadValidate(
234 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
235 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
236 baseLayer->GetParameters(),
Cathal Corbett06902652022-04-14 17:55:11 +0100237 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
Mike Kelly07810fc2020-11-12 10:58:48 +0000238 biases,
239 &activationDesc);
240
241 if (status)
242 {
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000243 FuseDepthwiseConvolution2dLayer<DepthwiseConvolution2dLayer>(optimizationViews,
244 baseLayer,
245 activationLayer,
246 activationDesc,
247 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000248 untouched.erase(baseLayer->GetGuid());
249 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000250 }
251 }
252 else if (base.GetType() == LayerType::FullyConnected)
253 {
254 FullyConnectedLayer* baseLayer = PolymorphicDowncast<FullyConnectedLayer*>(&base);
Cathal Corbett4452baf2022-05-13 09:55:59 +0100255 FullyConnectedDescriptor descriptor = baseLayer->GetParameters();
Matthew Bentham67d63902022-02-08 15:03:07 +0000256
Cathal Corbett4452baf2022-05-13 09:55:59 +0100257 // As bias is optional only try to get TensorInfo from input if bias is enabled.
258 Optional<TensorInfo> biases;
259 if (descriptor.m_BiasEnabled)
Matthew Bentham67d63902022-02-08 15:03:07 +0000260 {
Cathal Corbett4452baf2022-05-13 09:55:59 +0100261 biases = baseLayer->GetInputSlot(2).GetConnectedOutputSlot()->GetTensorInfo();
Matthew Bentham67d63902022-02-08 15:03:07 +0000262 }
Mike Kelly07810fc2020-11-12 10:58:48 +0000263
264 arm_compute::Status status = NeonFullyConnectedWorkloadValidate(
265 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
266 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
Cathal Corbett4452baf2022-05-13 09:55:59 +0100267 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
Matthew Bentham67d63902022-02-08 15:03:07 +0000268 biases,
Mike Kelly07810fc2020-11-12 10:58:48 +0000269 baseLayer->GetParameters(),
270 &activationDesc);
271
272 if (status)
273 {
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000274 FuseFullyConnectedLayer<FullyConnectedLayer>(optimizationViews,
275 baseLayer,
276 activationLayer,
277 activationDesc,
278 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000279 untouched.erase(baseLayer->GetGuid());
280 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000281 }
282 }
283 else if (base.GetType() == LayerType::BatchNormalization)
284 {
285 BatchNormalizationLayer* baseLayer =
286 PolymorphicDowncast<BatchNormalizationLayer*>(&base);
287
288 arm_compute::Status status = NeonBatchNormalizationValidate(
289 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
290 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
291 baseLayer->m_Mean->GetTensorInfo(),
292 baseLayer->m_Variance->GetTensorInfo(),
293 baseLayer->m_Beta->GetTensorInfo(),
294 baseLayer->m_Gamma->GetTensorInfo(),
295 baseLayer->GetParameters(),
296 &activationDesc);
297
298 if (status)
299 {
300 BatchNormalizationLayer* replacementLayer =
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000301 FuseBatchNormalizationLayer<BatchNormalizationLayer>(optimizationViews,
302 baseLayer,
303 activationLayer,
304 activationDesc,
305 name);
Mike Kelly07810fc2020-11-12 10:58:48 +0000306
307 replacementLayer->m_Beta = std::move(baseLayer->m_Beta);
308 replacementLayer->m_Gamma = std::move(baseLayer->m_Gamma);
309 replacementLayer->m_Mean = std::move(baseLayer->m_Mean);
310 replacementLayer->m_Variance = std::move(baseLayer->m_Variance);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000311 untouched.erase(baseLayer->GetGuid());
312 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000313 }
314 }
315 else if (base.GetType() == LayerType::Addition)
316 {
317 AdditionLayer* baseLayer = PolymorphicDowncast<AdditionLayer*>(&base);
318
319 arm_compute::Status status = NeonAdditionWorkloadValidate(
320 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
321 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
322 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
323 &activationDesc);
324
325 if (status)
326 {
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000327 FuseAdditionLayer<AdditionLayer>(optimizationViews,
328 baseLayer,
329 activationLayer,
330 activationDesc,
331 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000332 untouched.erase(baseLayer->GetGuid());
333 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000334 }
335 }
336 else if (base.GetType() == LayerType::Division)
337 {
338 DivisionLayer* baseLayer = PolymorphicDowncast<DivisionLayer*>(&base);
339
340 arm_compute::Status status = NeonDivisionWorkloadValidate(
341 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
342 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
343 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
344 &activationDesc);
345
346 if (status)
347 {
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000348 FuseDivisionLayer<DivisionLayer>(optimizationViews,
349 baseLayer,
350 activationLayer,
351 activationDesc,
352 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000353 untouched.erase(baseLayer->GetGuid());
354 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000355 }
356 }
357 else if (base.GetType() == LayerType::Multiplication)
358 {
359 MultiplicationLayer* baseLayer = PolymorphicDowncast<MultiplicationLayer*>(&base);
360
361 arm_compute::Status status = NeonMultiplicationWorkloadValidate(
362 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
363 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
364 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
365 &activationDesc);
366
367 if (status)
368 {
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000369 FuseMultiplicationLayer<MultiplicationLayer>(optimizationViews,
370 baseLayer,
371 activationLayer,
372 activationDesc,
373 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000374 untouched.erase(baseLayer->GetGuid());
375 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000376 }
377 }
378 else if (base.GetType() == LayerType::Subtraction)
379 {
380 SubtractionLayer* baseLayer = PolymorphicDowncast<SubtractionLayer*>(&base);
381
382 arm_compute::Status status = NeonSubtractionWorkloadValidate(
383 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
384 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
385 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
386 &activationDesc);
387
388 if (status)
389 {
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000390 FuseSubtractionLayer<SubtractionLayer>(optimizationViews,
391 baseLayer,
392 activationLayer,
393 activationDesc,
394 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000395 untouched.erase(baseLayer->GetGuid());
396 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000397 }
398 }
Mike Kelly3ec30772023-03-08 13:47:17 +0000399 else if (base.GetType() == LayerType::ElementwiseBinary)
400 {
401 ElementwiseBinaryLayer* baseLayer = PolymorphicDowncast<ElementwiseBinaryLayer*>(&base);
402
403 if (baseLayer->GetParameters().m_Operation == BinaryOperation::Add)
404 {
405 arm_compute::Status status = NeonAdditionWorkloadValidate(
406 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
407 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
408 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
409 &activationDesc);
410
411 if (status)
412 {
413 FuseElementwiseBinaryLayer<ElementwiseBinaryLayer>(optimizationViews,
414 baseLayer,
415 activationLayer,
416 activationDesc,
417 BinaryOperation::Add,
418 name);
419 untouched.erase(baseLayer->GetGuid());
420 untouched.erase(activationLayer->GetGuid());
421 }
422 }
423 else if (baseLayer->GetParameters().m_Operation == BinaryOperation::Div)
424 {
425 arm_compute::Status status = NeonDivisionWorkloadValidate(
426 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
427 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
428 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
429 &activationDesc);
430
431 if (status)
432 {
433 FuseElementwiseBinaryLayer<ElementwiseBinaryLayer>(optimizationViews,
434 baseLayer,
435 activationLayer,
436 activationDesc,
437 BinaryOperation::Div,
438 name);
439 untouched.erase(baseLayer->GetGuid());
440 untouched.erase(activationLayer->GetGuid());
441 }
442 }
443 else if (baseLayer->GetParameters().m_Operation == BinaryOperation::Mul)
444 {
445 arm_compute::Status status = NeonMultiplicationWorkloadValidate(
446 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
447 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
448 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
449 &activationDesc);
450
451 if (status)
452 {
453 FuseElementwiseBinaryLayer<ElementwiseBinaryLayer>(optimizationViews,
454 baseLayer,
455 activationLayer,
456 activationDesc,
457 BinaryOperation::Mul,
458 name);
459 untouched.erase(baseLayer->GetGuid());
460 untouched.erase(activationLayer->GetGuid());
461 }
462 }
463 else if (baseLayer->GetParameters().m_Operation == BinaryOperation::Sub)
464 {
465 arm_compute::Status status = NeonSubtractionWorkloadValidate(
466 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
467 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
468 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
469 &activationDesc);
470
471 if (status)
472 {
473 FuseElementwiseBinaryLayer<ElementwiseBinaryLayer>(optimizationViews,
474 baseLayer,
475 activationLayer,
476 activationDesc,
477 BinaryOperation::Sub,
478 name);
479 untouched.erase(baseLayer->GetGuid());
480 untouched.erase(activationLayer->GetGuid());
481 }
482 }
483 // No fusion available for other BinaryOperations
484 }
Mike Kelly07810fc2020-11-12 10:58:48 +0000485 }
486 }
487 }
488 }
489 }
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100490
491 // Separate reduce layer with multiple axes into multiple reduce layers with 1 axis.
492 if (base.GetType() == LayerType::Reduce)
493 {
494 ReduceLayer* baseLayer = PolymorphicDowncast<ReduceLayer*>(&base);
495 ReduceDescriptor reduceDescriptor = baseLayer->GetParameters();
496
497 if (!reduceDescriptor.m_vAxis.empty() && reduceDescriptor.m_vAxis.size() > 1)
498 {
499 // Add new layers to the graph and connect them.
Francis Murtagh56ccf682021-12-13 18:48:12 +0000500 std::vector<IConnectableLayer*> layers = ChainReduceLayers<ReduceLayer>(optimizationViews,
501 baseLayer,
502 reduceDescriptor);
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100503
504 // Replace existing baselayer with new subgraph.
505 ReplaceLayers<ReduceLayer>(optimizationViews, baseLayer, layers);
506 untouched.erase(baseLayer->GetGuid());
507 }
508 }
Mike Kelly4cc341c2023-07-07 15:43:06 +0100509
510 // Remove Reshape where possible
511 if (base.GetType() == LayerType::Reshape)
512 {
513 ReshapeLayer* baseLayer = PolymorphicDowncast<ReshapeLayer*>(&base);
Mike Kelly4cc341c2023-07-07 15:43:06 +0100514
Mike Kellybe06f102023-07-17 17:49:55 +0100515 // Cannot remove a Reshape if it's connected to any layer that has an NCHW layout
516 if (ConnectedToLayerWithNCHW(baseLayer))
Mike Kelly4cc341c2023-07-07 15:43:06 +0100517 {
518 continue;
519 }
Mike Kellya638f102023-07-24 17:42:47 +0100520 // Cannot remove a Reshape if it's connected to a SplitterLayer
521 if (ConnectedToLayerType(baseLayer, LayerType::Splitter))
Mike Kelly4cc341c2023-07-07 15:43:06 +0100522 {
523 continue;
524 }
525 RemoveReshapeLayer(baseLayer, untouched, optimizationViews);
526 }
Mike Kelly07810fc2020-11-12 10:58:48 +0000527 }
528
Mike Kelly4cc341c2023-07-07 15:43:06 +0100529 if (optimizationViews.GetSubstitutions().empty() && optimizationViews.GetDeletedSubgraphs().empty())
Mike Kelly07810fc2020-11-12 10:58:48 +0000530 {
531 optimizationViews.AddUntouchedSubgraph(SubgraphView(subgraph));
532 }
Mike Kelly1ac690a2020-11-17 11:41:38 +0000533 else
534 {
535 ReportUntouchedLayers(optimizationViews, untouched);
536 }
Matteo Martincighc3ba50e2019-05-22 14:28:16 +0100537
538 return optimizationViews;
Matteo Martincighadddddb2019-01-24 14:06:23 +0000539}
540
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +0100541std::vector<ITensorHandleFactory::FactoryId> NeonBackend::GetHandleFactoryPreferences() const
542{
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000543 return std::vector<ITensorHandleFactory::FactoryId>() = { NeonTensorHandleFactory::GetIdStatic() };
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +0100544}
545
546void NeonBackend::RegisterTensorHandleFactories(class TensorHandleFactoryRegistry& registry)
547{
548 auto memoryManager = std::make_shared<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
549 BaseMemoryManager::MemoryAffinity::Offset);
550
551 registry.RegisterMemoryManager(memoryManager);
Narumol Prangnawarat77400452022-01-13 17:43:41 +0000552
553 auto factory = std::make_unique<NeonTensorHandleFactory>(memoryManager);
554 // Register copy and import factory pair
555 registry.RegisterCopyAndImportFactoryPair(factory->GetId(), factory->GetId());
556 // Register the factory
557 registry.RegisterFactory(std::move(factory));
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +0100558}
559
Francis Murtaghe8d7ccb2021-10-14 17:30:24 +0100560std::unique_ptr<ICustomAllocator> NeonBackend::GetDefaultAllocator() const
561{
562 return std::make_unique<DefaultAllocator>();
563}
564
565
Matthew Bentham42bad952018-12-17 09:23:36 +0000566} // namespace armnn