blob: a1299fb458ec594befd00291c09e7dec590cd75a [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"
32#include "workloads/NeonSubtractionWorkload.hpp"
33
David Beck263e3492018-11-09 14:46:40 +000034#include <Optimizer.hpp>
arovir01a0944792018-10-11 15:00:58 +010035
Mike Kelly07810fc2020-11-12 10:58:48 +000036#include <arm_compute/core/Types.h>
Aron Virginas-Tar56055192018-11-12 18:10:43 +000037#include <arm_compute/runtime/Allocator.h>
38
arovir014424b0a2018-10-04 10:46:04 +010039namespace armnn
40{
41
David Beck3cc9a622018-10-12 10:38:31 +010042const BackendId& NeonBackend::GetIdStatic()
arovir014424b0a2018-10-04 10:46:04 +010043{
David Beck3e9e1152018-10-17 14:17:50 +010044 static const BackendId s_Id{NeonBackendId()};
arovir014424b0a2018-10-04 10:46:04 +010045 return s_Id;
46}
47
Aron Virginas-Tar56055192018-11-12 18:10:43 +000048IBackendInternal::IMemoryManagerUniquePtr NeonBackend::CreateMemoryManager() const
arovir014424b0a2018-10-04 10:46:04 +010049{
Aron Virginas-Tar56055192018-11-12 18:10:43 +000050 return std::make_unique<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
Sadik Armagan13a9fa62019-04-26 16:04:34 +010051 BaseMemoryManager::MemoryAffinity::Offset);
Aron Virginas-Tar56055192018-11-12 18:10:43 +000052}
53
54IBackendInternal::IWorkloadFactoryPtr NeonBackend::CreateWorkloadFactory(
55 const IBackendInternal::IMemoryManagerSharedPtr& memoryManager) const
56{
57 return std::make_unique<NeonWorkloadFactory>(
Jan Eilers3c9e0452020-04-10 13:00:44 +010058 PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager));
arovir014424b0a2018-10-04 10:46:04 +010059}
60
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +010061IBackendInternal::IWorkloadFactoryPtr NeonBackend::CreateWorkloadFactory(
Sadik Armagan04a72972020-09-14 15:44:18 +010062 const IBackendInternal::IMemoryManagerSharedPtr& memoryManager, const ModelOptions& modelOptions) const
63{
64 return std::make_unique<NeonWorkloadFactory>(
65 PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager), CreateBackendSpecificModelContext(modelOptions));
66}
67
68IBackendInternal::IWorkloadFactoryPtr NeonBackend::CreateWorkloadFactory(
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +010069 class TensorHandleFactoryRegistry& tensorHandleFactoryRegistry) const
70{
71 auto memoryManager = std::make_shared<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
72 BaseMemoryManager::MemoryAffinity::Offset);
73
74 tensorHandleFactoryRegistry.RegisterMemoryManager(memoryManager);
Narumol Prangnawarat549cb7a2020-07-10 17:50:53 +010075 tensorHandleFactoryRegistry.RegisterFactory(std::make_unique<NeonTensorHandleFactory>(memoryManager));
76
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +010077 return std::make_unique<NeonWorkloadFactory>(
Jan Eilers3c9e0452020-04-10 13:00:44 +010078 PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager));
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +010079}
80
Sadik Armagan04a72972020-09-14 15:44:18 +010081IBackendInternal::IWorkloadFactoryPtr NeonBackend::CreateWorkloadFactory(
82 TensorHandleFactoryRegistry& tensorHandleFactoryRegistry, const ModelOptions& modelOptions) const
83{
84 auto memoryManager = std::make_shared<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
85 BaseMemoryManager::MemoryAffinity::Offset);
86
87 tensorHandleFactoryRegistry.RegisterMemoryManager(memoryManager);
88 tensorHandleFactoryRegistry.RegisterFactory(std::make_unique<NeonTensorHandleFactory>(memoryManager));
89
90 return std::make_unique<NeonWorkloadFactory>(
91 PolymorphicPointerDowncast<NeonMemoryManager>(memoryManager), CreateBackendSpecificModelContext(modelOptions));
92}
93
David Beck263e3492018-11-09 14:46:40 +000094IBackendInternal::IBackendContextPtr NeonBackend::CreateBackendContext(const IRuntime::CreationOptions&) const
95{
96 return IBackendContextPtr{};
97}
98
Colm Donelane49755b2020-01-29 15:22:43 +000099IBackendInternal::IBackendProfilingContextPtr NeonBackend::CreateBackendProfilingContext(
Colm Donelan1aff3932020-02-05 17:48:59 +0000100 const IRuntime::CreationOptions&, IBackendProfilingPtr&)
Colm Donelane49755b2020-01-29 15:22:43 +0000101{
102 return IBackendProfilingContextPtr{};
103}
104
David Beck263e3492018-11-09 14:46:40 +0000105IBackendInternal::Optimizations NeonBackend::GetOptimizations() const
106{
107 return Optimizations{};
108}
109
Sadik Armagan045f6be2020-09-10 13:37:32 +0100110IBackendInternal::IBackendSpecificModelContextPtr NeonBackend::CreateBackendSpecificModelContext(
111 const ModelOptions& modelOptions) const
112{
113 return IBackendSpecificModelContextPtr{new NeonBackendModelContext{modelOptions}};
114}
115
David Beck111b5d92018-11-12 14:59:37 +0000116IBackendInternal::ILayerSupportSharedPtr NeonBackend::GetLayerSupport() const
117{
Sadik Armagan045f6be2020-09-10 13:37:32 +0100118 static ILayerSupportSharedPtr layerSupport
119 {
120 new NeonLayerSupport(IBackendInternal::IBackendSpecificModelContextPtr{})
121 };
122 return layerSupport;
123}
124
125IBackendInternal::ILayerSupportSharedPtr NeonBackend::GetLayerSupport(const ModelOptions& modelOptions) const
126{
127 static ILayerSupportSharedPtr layerSupport
128 {
129 new NeonLayerSupport(CreateBackendSpecificModelContext(modelOptions))
130 };
David Beck111b5d92018-11-12 14:59:37 +0000131 return layerSupport;
132}
133
Sadik Armaganaede8ca2021-03-31 16:12:13 +0100134bool NeonBackend::HasCapability(BackendCapability capabilityClass) const
135{
136 auto search = cpuAccCapabilities.find(capabilityClass);
137 if (search != cpuAccCapabilities.end())
138 {
139 return true;
140 }
141 return false;
142}
143
Matteo Martincighc3ba50e2019-05-22 14:28:16 +0100144OptimizationViews NeonBackend::OptimizeSubgraphView(const SubgraphView& subgraph) const
Matteo Martincighadddddb2019-01-24 14:06:23 +0000145{
Matteo Martincighc3ba50e2019-05-22 14:28:16 +0100146 OptimizationViews optimizationViews;
Matteo Martincighadddddb2019-01-24 14:06:23 +0000147
Mike Kelly07810fc2020-11-12 10:58:48 +0000148 auto it = subgraph.end();
Mike Kelly1ac690a2020-11-17 11:41:38 +0000149 std::map<LayerGuid, Layer*> untouched;
Mike Kelly07810fc2020-11-12 10:58:48 +0000150
151 while (it != subgraph.begin())
152 {
153 --it;
154 Layer& base = **it;
Mike Kelly1ac690a2020-11-17 11:41:38 +0000155 untouched.insert({base.GetGuid(), &base});
156 }
157
158 it = subgraph.end();
159 while (it != subgraph.begin())
160 {
161 --it;
162 Layer& base = **it;
Mike Kelly07810fc2020-11-12 10:58:48 +0000163
164 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
167 || base.GetType() == LayerType::Subtraction || base.GetType() == LayerType::Division)
168 && (base.GetAdditionalInformation<ActivationDescriptor>() == nullptr))
169 {
170 for (auto output = base.BeginOutputSlots(); output != base.EndOutputSlots(); ++output)
171 {
172 if (output->GetNumConnections() == 1)
173 {
174 for (auto&& childInput : output->GetConnections())
175 {
Teresa Charlind672f5d2021-01-18 18:07:57 +0000176 if ((childInput->GetOwningLayer().GetType() == LayerType::Activation) &&
177 (checkDataTypeInputandOutput(childInput->GetOwningLayer())))
Mike Kelly07810fc2020-11-12 10:58:48 +0000178 {
179 Layer& child = childInput->GetOwningLayer();
180
181 auto* activationLayer = PolymorphicDowncast<ActivationLayer*>(&child);
182
183 const std::string name = std::string("fused-") + child.GetName() + std::string("-into-") +
184 base.GetName();
185
186 // Get params from activation layer
187 ActivationDescriptor activationDesc = activationLayer->GetParameters();
188
189 if (base.GetType() == LayerType::Convolution2d)
190 {
191 Convolution2dLayer* baseLayer = PolymorphicDowncast<Convolution2dLayer*>(&base);
192
193 Optional<TensorInfo> biases;
194
195 if (baseLayer->GetParameters().m_BiasEnabled)
196 {
Mike Kelly1ac690a2020-11-17 11:41:38 +0000197 biases = baseLayer->m_Bias->GetTensorInfo();
Mike Kelly07810fc2020-11-12 10:58:48 +0000198 }
199
200 arm_compute::Status status = NeonConvolution2dWorkloadValidate(
201 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
202 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
203 baseLayer->GetParameters(),
204 baseLayer->m_Weight->GetTensorInfo(),
205 biases,
206 false,
207 &activationDesc);
208
209 if (status)
210 {
211 FuseLayerWithWeightsAndBiases<Convolution2dLayer>(optimizationViews,
212 baseLayer,
213 activationLayer,
214 activationDesc,
215 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000216 untouched.erase(baseLayer->GetGuid());
217 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000218 }
219 }
220 else if (base.GetType() == LayerType::DepthwiseConvolution2d)
221 {
222 DepthwiseConvolution2dLayer* baseLayer =
223 PolymorphicDowncast<DepthwiseConvolution2dLayer*>(&base);
224
225 Optional<TensorInfo> biases;
226
227 if (baseLayer->GetParameters().m_BiasEnabled)
228 {
Mike Kelly1ac690a2020-11-17 11:41:38 +0000229 biases = baseLayer->m_Bias->GetTensorInfo();
Mike Kelly07810fc2020-11-12 10:58:48 +0000230 }
231
232 arm_compute::Status status = NeonDepthwiseConvolutionWorkloadValidate(
233 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
234 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
235 baseLayer->GetParameters(),
236 baseLayer->m_Weight->GetTensorInfo(),
237 biases,
238 &activationDesc);
239
240 if (status)
241 {
242 FuseLayerWithWeightsAndBiases<DepthwiseConvolution2dLayer>(optimizationViews,
243 baseLayer,
244 activationLayer,
245 activationDesc,
246 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000247 untouched.erase(baseLayer->GetGuid());
248 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000249 }
250 }
251 else if (base.GetType() == LayerType::FullyConnected)
252 {
253 FullyConnectedLayer* baseLayer = PolymorphicDowncast<FullyConnectedLayer*>(&base);
254
255 arm_compute::Status status = NeonFullyConnectedWorkloadValidate(
256 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
257 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
258 baseLayer->m_Weight->GetTensorInfo(),
259 baseLayer->m_Bias->GetTensorInfo(),
260 baseLayer->GetParameters(),
261 &activationDesc);
262
263 if (status)
264 {
265 FuseLayerWithWeightsAndBiases<FullyConnectedLayer>(optimizationViews,
266 baseLayer,
267 activationLayer,
268 activationDesc,
269 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000270 untouched.erase(baseLayer->GetGuid());
271 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000272 }
273 }
274 else if (base.GetType() == LayerType::BatchNormalization)
275 {
276 BatchNormalizationLayer* baseLayer =
277 PolymorphicDowncast<BatchNormalizationLayer*>(&base);
278
279 arm_compute::Status status = NeonBatchNormalizationValidate(
280 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
281 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
282 baseLayer->m_Mean->GetTensorInfo(),
283 baseLayer->m_Variance->GetTensorInfo(),
284 baseLayer->m_Beta->GetTensorInfo(),
285 baseLayer->m_Gamma->GetTensorInfo(),
286 baseLayer->GetParameters(),
287 &activationDesc);
288
289 if (status)
290 {
291 BatchNormalizationLayer* replacementLayer =
292 FuseLayerWithParameters<BatchNormalizationLayer>(
293 optimizationViews,
294 baseLayer,
295 activationLayer,
296 activationDesc,
297 name);
298
299 replacementLayer->m_Beta = std::move(baseLayer->m_Beta);
300 replacementLayer->m_Gamma = std::move(baseLayer->m_Gamma);
301 replacementLayer->m_Mean = std::move(baseLayer->m_Mean);
302 replacementLayer->m_Variance = std::move(baseLayer->m_Variance);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000303 untouched.erase(baseLayer->GetGuid());
304 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000305 }
306 }
307 else if (base.GetType() == LayerType::Addition)
308 {
309 AdditionLayer* baseLayer = PolymorphicDowncast<AdditionLayer*>(&base);
310
311 arm_compute::Status status = NeonAdditionWorkloadValidate(
312 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
313 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
314 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
315 &activationDesc);
316
317 if (status)
318 {
319 FuseLayerWithoutParameters<AdditionLayer>(optimizationViews,
320 baseLayer,
321 activationLayer,
322 activationDesc,
323 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000324 untouched.erase(baseLayer->GetGuid());
325 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000326 }
327 }
328 else if (base.GetType() == LayerType::Division)
329 {
330 DivisionLayer* baseLayer = PolymorphicDowncast<DivisionLayer*>(&base);
331
332 arm_compute::Status status = NeonDivisionWorkloadValidate(
333 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
334 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
335 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
336 &activationDesc);
337
338 if (status)
339 {
340 FuseLayerWithoutParameters<DivisionLayer>(optimizationViews,
341 baseLayer,
342 activationLayer,
343 activationDesc,
344 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000345 untouched.erase(baseLayer->GetGuid());
346 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000347 }
348 }
349 else if (base.GetType() == LayerType::Multiplication)
350 {
351 MultiplicationLayer* baseLayer = PolymorphicDowncast<MultiplicationLayer*>(&base);
352
353 arm_compute::Status status = NeonMultiplicationWorkloadValidate(
354 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
355 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
356 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
357 &activationDesc);
358
359 if (status)
360 {
361 FuseLayerWithoutParameters<MultiplicationLayer>(optimizationViews,
362 baseLayer,
363 activationLayer,
364 activationDesc,
365 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000366 untouched.erase(baseLayer->GetGuid());
367 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000368 }
369 }
370 else if (base.GetType() == LayerType::Subtraction)
371 {
372 SubtractionLayer* baseLayer = PolymorphicDowncast<SubtractionLayer*>(&base);
373
374 arm_compute::Status status = NeonSubtractionWorkloadValidate(
375 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
376 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
377 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
378 &activationDesc);
379
380 if (status)
381 {
382 FuseLayerWithoutParameters<SubtractionLayer>(optimizationViews,
383 baseLayer,
384 activationLayer,
385 activationDesc,
386 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000387 untouched.erase(baseLayer->GetGuid());
388 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000389 }
390 }
391 }
392 }
393 }
394 }
395 }
396 }
397
398 if (optimizationViews.GetSubstitutions().empty())
399 {
400 optimizationViews.AddUntouchedSubgraph(SubgraphView(subgraph));
401 }
Mike Kelly1ac690a2020-11-17 11:41:38 +0000402 else
403 {
404 ReportUntouchedLayers(optimizationViews, untouched);
405 }
Matteo Martincighc3ba50e2019-05-22 14:28:16 +0100406
407 return optimizationViews;
Matteo Martincighadddddb2019-01-24 14:06:23 +0000408}
409
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +0100410std::vector<ITensorHandleFactory::FactoryId> NeonBackend::GetHandleFactoryPreferences() const
411{
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000412 return std::vector<ITensorHandleFactory::FactoryId>() = { NeonTensorHandleFactory::GetIdStatic() };
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +0100413}
414
415void NeonBackend::RegisterTensorHandleFactories(class TensorHandleFactoryRegistry& registry)
416{
417 auto memoryManager = std::make_shared<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
418 BaseMemoryManager::MemoryAffinity::Offset);
419
420 registry.RegisterMemoryManager(memoryManager);
Jan Eilerse9f0f0f2019-08-16 10:28:37 +0100421 registry.RegisterFactory(std::make_unique<NeonTensorHandleFactory>(memoryManager));
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +0100422}
423
Matthew Bentham42bad952018-12-17 09:23:36 +0000424} // namespace armnn