blob: 0500ee3411f4a52e390c9f1dd8fe663a149b4c7b [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
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 Prangnawarat549cb7a2020-07-10 17:50:53 +010077 tensorHandleFactoryRegistry.RegisterFactory(std::make_unique<NeonTensorHandleFactory>(memoryManager));
78
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +010079 return std::make_unique<NeonWorkloadFactory>(
Jan Eilers3c9e0452020-04-10 13:00:44 +010080 PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager));
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +010081}
82
Sadik Armagan04a72972020-09-14 15:44:18 +010083IBackendInternal::IWorkloadFactoryPtr NeonBackend::CreateWorkloadFactory(
84 TensorHandleFactoryRegistry& tensorHandleFactoryRegistry, const ModelOptions& modelOptions) const
85{
86 auto memoryManager = std::make_shared<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
87 BaseMemoryManager::MemoryAffinity::Offset);
88
89 tensorHandleFactoryRegistry.RegisterMemoryManager(memoryManager);
90 tensorHandleFactoryRegistry.RegisterFactory(std::make_unique<NeonTensorHandleFactory>(memoryManager));
91
92 return std::make_unique<NeonWorkloadFactory>(
93 PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager), CreateBackendSpecificModelContext(modelOptions));
94}
95
David Beck263e3492018-11-09 14:46:40 +000096IBackendInternal::IBackendContextPtr NeonBackend::CreateBackendContext(const IRuntime::CreationOptions&) const
97{
98 return IBackendContextPtr{};
99}
100
Colm Donelane49755b2020-01-29 15:22:43 +0000101IBackendInternal::IBackendProfilingContextPtr NeonBackend::CreateBackendProfilingContext(
Colm Donelan1aff3932020-02-05 17:48:59 +0000102 const IRuntime::CreationOptions&, IBackendProfilingPtr&)
Colm Donelane49755b2020-01-29 15:22:43 +0000103{
104 return IBackendProfilingContextPtr{};
105}
106
Sadik Armagan045f6be2020-09-10 13:37:32 +0100107IBackendInternal::IBackendSpecificModelContextPtr NeonBackend::CreateBackendSpecificModelContext(
108 const ModelOptions& modelOptions) const
109{
110 return IBackendSpecificModelContextPtr{new NeonBackendModelContext{modelOptions}};
111}
112
David Beck111b5d92018-11-12 14:59:37 +0000113IBackendInternal::ILayerSupportSharedPtr NeonBackend::GetLayerSupport() const
114{
Sadik Armagan045f6be2020-09-10 13:37:32 +0100115 static ILayerSupportSharedPtr layerSupport
116 {
117 new NeonLayerSupport(IBackendInternal::IBackendSpecificModelContextPtr{})
118 };
119 return layerSupport;
120}
121
122IBackendInternal::ILayerSupportSharedPtr NeonBackend::GetLayerSupport(const ModelOptions& modelOptions) const
123{
124 static ILayerSupportSharedPtr layerSupport
125 {
126 new NeonLayerSupport(CreateBackendSpecificModelContext(modelOptions))
127 };
David Beck111b5d92018-11-12 14:59:37 +0000128 return layerSupport;
129}
130
Matteo Martincighc3ba50e2019-05-22 14:28:16 +0100131OptimizationViews NeonBackend::OptimizeSubgraphView(const SubgraphView& subgraph) const
Matteo Martincighadddddb2019-01-24 14:06:23 +0000132{
Matteo Martincighc3ba50e2019-05-22 14:28:16 +0100133 OptimizationViews optimizationViews;
Matteo Martincighadddddb2019-01-24 14:06:23 +0000134
Mike Kelly07810fc2020-11-12 10:58:48 +0000135 auto it = subgraph.end();
Mike Kelly1ac690a2020-11-17 11:41:38 +0000136 std::map<LayerGuid, Layer*> untouched;
Mike Kelly07810fc2020-11-12 10:58:48 +0000137
138 while (it != subgraph.begin())
139 {
140 --it;
141 Layer& base = **it;
Mike Kelly1ac690a2020-11-17 11:41:38 +0000142 untouched.insert({base.GetGuid(), &base});
143 }
144
145 it = subgraph.end();
146 while (it != subgraph.begin())
147 {
148 --it;
149 Layer& base = **it;
Mike Kelly07810fc2020-11-12 10:58:48 +0000150
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100151 // Fuse activation into previous layer if supported by backend
Mike Kelly07810fc2020-11-12 10:58:48 +0000152 if ((base.GetType() == LayerType::DepthwiseConvolution2d || base.GetType() == LayerType::Convolution2d
153 || base.GetType() == LayerType::BatchNormalization || base.GetType() == LayerType::FullyConnected
154 || base.GetType() == LayerType::Addition || base.GetType() == LayerType::Multiplication
Matthew Sloyanae123062021-05-07 14:18:01 +0000155 || base.GetType() == LayerType::Subtraction || base.GetType() == LayerType::Division)
Mike Kelly07810fc2020-11-12 10:58:48 +0000156 && (base.GetAdditionalInformation<ActivationDescriptor>() == nullptr))
157 {
158 for (auto output = base.BeginOutputSlots(); output != base.EndOutputSlots(); ++output)
159 {
160 if (output->GetNumConnections() == 1)
161 {
162 for (auto&& childInput : output->GetConnections())
163 {
Teresa Charlind672f5d2021-01-18 18:07:57 +0000164 if ((childInput->GetOwningLayer().GetType() == LayerType::Activation) &&
165 (checkDataTypeInputandOutput(childInput->GetOwningLayer())))
Mike Kelly07810fc2020-11-12 10:58:48 +0000166 {
167 Layer& child = childInput->GetOwningLayer();
168
169 auto* activationLayer = PolymorphicDowncast<ActivationLayer*>(&child);
170
171 const std::string name = std::string("fused-") + child.GetName() + std::string("-into-") +
172 base.GetName();
173
174 // Get params from activation layer
175 ActivationDescriptor activationDesc = activationLayer->GetParameters();
176
177 if (base.GetType() == LayerType::Convolution2d)
178 {
179 Convolution2dLayer* baseLayer = PolymorphicDowncast<Convolution2dLayer*>(&base);
180
181 Optional<TensorInfo> biases;
182
183 if (baseLayer->GetParameters().m_BiasEnabled)
184 {
Mike Kelly1ac690a2020-11-17 11:41:38 +0000185 biases = baseLayer->m_Bias->GetTensorInfo();
Mike Kelly07810fc2020-11-12 10:58:48 +0000186 }
187
188 arm_compute::Status status = NeonConvolution2dWorkloadValidate(
189 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
190 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
191 baseLayer->GetParameters(),
192 baseLayer->m_Weight->GetTensorInfo(),
193 biases,
194 false,
195 &activationDesc);
196
197 if (status)
198 {
199 FuseLayerWithWeightsAndBiases<Convolution2dLayer>(optimizationViews,
200 baseLayer,
201 activationLayer,
202 activationDesc,
203 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000204 untouched.erase(baseLayer->GetGuid());
205 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000206 }
207 }
208 else if (base.GetType() == LayerType::DepthwiseConvolution2d)
209 {
210 DepthwiseConvolution2dLayer* baseLayer =
211 PolymorphicDowncast<DepthwiseConvolution2dLayer*>(&base);
212
213 Optional<TensorInfo> biases;
214
215 if (baseLayer->GetParameters().m_BiasEnabled)
216 {
Mike Kelly1ac690a2020-11-17 11:41:38 +0000217 biases = baseLayer->m_Bias->GetTensorInfo();
Mike Kelly07810fc2020-11-12 10:58:48 +0000218 }
219
220 arm_compute::Status status = NeonDepthwiseConvolutionWorkloadValidate(
221 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
222 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
223 baseLayer->GetParameters(),
224 baseLayer->m_Weight->GetTensorInfo(),
225 biases,
226 &activationDesc);
227
228 if (status)
229 {
230 FuseLayerWithWeightsAndBiases<DepthwiseConvolution2dLayer>(optimizationViews,
231 baseLayer,
232 activationLayer,
233 activationDesc,
234 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000235 untouched.erase(baseLayer->GetGuid());
236 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000237 }
238 }
239 else if (base.GetType() == LayerType::FullyConnected)
240 {
241 FullyConnectedLayer* baseLayer = PolymorphicDowncast<FullyConnectedLayer*>(&base);
242
243 arm_compute::Status status = NeonFullyConnectedWorkloadValidate(
244 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
245 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
246 baseLayer->m_Weight->GetTensorInfo(),
247 baseLayer->m_Bias->GetTensorInfo(),
248 baseLayer->GetParameters(),
249 &activationDesc);
250
251 if (status)
252 {
253 FuseLayerWithWeightsAndBiases<FullyConnectedLayer>(optimizationViews,
254 baseLayer,
255 activationLayer,
256 activationDesc,
257 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000258 untouched.erase(baseLayer->GetGuid());
259 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000260 }
261 }
262 else if (base.GetType() == LayerType::BatchNormalization)
263 {
264 BatchNormalizationLayer* baseLayer =
265 PolymorphicDowncast<BatchNormalizationLayer*>(&base);
266
267 arm_compute::Status status = NeonBatchNormalizationValidate(
268 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
269 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
270 baseLayer->m_Mean->GetTensorInfo(),
271 baseLayer->m_Variance->GetTensorInfo(),
272 baseLayer->m_Beta->GetTensorInfo(),
273 baseLayer->m_Gamma->GetTensorInfo(),
274 baseLayer->GetParameters(),
275 &activationDesc);
276
277 if (status)
278 {
279 BatchNormalizationLayer* replacementLayer =
280 FuseLayerWithParameters<BatchNormalizationLayer>(
281 optimizationViews,
282 baseLayer,
283 activationLayer,
284 activationDesc,
285 name);
286
287 replacementLayer->m_Beta = std::move(baseLayer->m_Beta);
288 replacementLayer->m_Gamma = std::move(baseLayer->m_Gamma);
289 replacementLayer->m_Mean = std::move(baseLayer->m_Mean);
290 replacementLayer->m_Variance = std::move(baseLayer->m_Variance);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000291 untouched.erase(baseLayer->GetGuid());
292 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000293 }
294 }
295 else if (base.GetType() == LayerType::Addition)
296 {
297 AdditionLayer* baseLayer = PolymorphicDowncast<AdditionLayer*>(&base);
298
299 arm_compute::Status status = NeonAdditionWorkloadValidate(
300 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
301 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
302 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
303 &activationDesc);
304
305 if (status)
306 {
307 FuseLayerWithoutParameters<AdditionLayer>(optimizationViews,
308 baseLayer,
309 activationLayer,
310 activationDesc,
311 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000312 untouched.erase(baseLayer->GetGuid());
313 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000314 }
315 }
316 else if (base.GetType() == LayerType::Division)
317 {
318 DivisionLayer* baseLayer = PolymorphicDowncast<DivisionLayer*>(&base);
319
320 arm_compute::Status status = NeonDivisionWorkloadValidate(
321 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
322 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
323 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
324 &activationDesc);
325
326 if (status)
327 {
328 FuseLayerWithoutParameters<DivisionLayer>(optimizationViews,
329 baseLayer,
330 activationLayer,
331 activationDesc,
332 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000333 untouched.erase(baseLayer->GetGuid());
334 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000335 }
336 }
337 else if (base.GetType() == LayerType::Multiplication)
338 {
339 MultiplicationLayer* baseLayer = PolymorphicDowncast<MultiplicationLayer*>(&base);
340
341 arm_compute::Status status = NeonMultiplicationWorkloadValidate(
342 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
343 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
344 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
345 &activationDesc);
346
347 if (status)
348 {
349 FuseLayerWithoutParameters<MultiplicationLayer>(optimizationViews,
350 baseLayer,
351 activationLayer,
352 activationDesc,
353 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000354 untouched.erase(baseLayer->GetGuid());
355 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000356 }
357 }
358 else if (base.GetType() == LayerType::Subtraction)
359 {
360 SubtractionLayer* baseLayer = PolymorphicDowncast<SubtractionLayer*>(&base);
361
362 arm_compute::Status status = NeonSubtractionWorkloadValidate(
363 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
364 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
365 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
366 &activationDesc);
367
368 if (status)
369 {
370 FuseLayerWithoutParameters<SubtractionLayer>(optimizationViews,
371 baseLayer,
372 activationLayer,
373 activationDesc,
374 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000375 untouched.erase(baseLayer->GetGuid());
376 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000377 }
378 }
379 }
380 }
381 }
382 }
383 }
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100384
385 // Separate reduce layer with multiple axes into multiple reduce layers with 1 axis.
386 if (base.GetType() == LayerType::Reduce)
387 {
388 ReduceLayer* baseLayer = PolymorphicDowncast<ReduceLayer*>(&base);
389 ReduceDescriptor reduceDescriptor = baseLayer->GetParameters();
390
391 if (!reduceDescriptor.m_vAxis.empty() && reduceDescriptor.m_vAxis.size() > 1)
392 {
393 // Add new layers to the graph and connect them.
394 std::vector<Layer*> layers = ChainReduceLayers<ReduceLayer>(optimizationViews,
395 baseLayer,
396 reduceDescriptor);
397
398 // Replace existing baselayer with new subgraph.
399 ReplaceLayers<ReduceLayer>(optimizationViews, baseLayer, layers);
400 untouched.erase(baseLayer->GetGuid());
401 }
402 }
Mike Kelly07810fc2020-11-12 10:58:48 +0000403 }
404
405 if (optimizationViews.GetSubstitutions().empty())
406 {
407 optimizationViews.AddUntouchedSubgraph(SubgraphView(subgraph));
408 }
Mike Kelly1ac690a2020-11-17 11:41:38 +0000409 else
410 {
411 ReportUntouchedLayers(optimizationViews, untouched);
412 }
Matteo Martincighc3ba50e2019-05-22 14:28:16 +0100413
414 return optimizationViews;
Matteo Martincighadddddb2019-01-24 14:06:23 +0000415}
416
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +0100417std::vector<ITensorHandleFactory::FactoryId> NeonBackend::GetHandleFactoryPreferences() const
418{
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000419 return std::vector<ITensorHandleFactory::FactoryId>() = { NeonTensorHandleFactory::GetIdStatic() };
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +0100420}
421
422void NeonBackend::RegisterTensorHandleFactories(class TensorHandleFactoryRegistry& registry)
423{
424 auto memoryManager = std::make_shared<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
425 BaseMemoryManager::MemoryAffinity::Offset);
426
427 registry.RegisterMemoryManager(memoryManager);
Jan Eilerse9f0f0f2019-08-16 10:28:37 +0100428 registry.RegisterFactory(std::make_unique<NeonTensorHandleFactory>(memoryManager));
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +0100429}
430
Francis Murtaghe8d7ccb2021-10-14 17:30:24 +0100431std::unique_ptr<ICustomAllocator> NeonBackend::GetDefaultAllocator() const
432{
433 return std::make_unique<DefaultAllocator>();
434}
435
436
Matthew Bentham42bad952018-12-17 09:23:36 +0000437} // namespace armnn