blob: 2c3abfd70dd9d2e8d0c9f1e476e241af94414d1a [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
Sadik Armagan045f6be2020-09-10 13:37:32 +0100106IBackendInternal::IBackendSpecificModelContextPtr NeonBackend::CreateBackendSpecificModelContext(
107 const ModelOptions& modelOptions) const
108{
109 return IBackendSpecificModelContextPtr{new NeonBackendModelContext{modelOptions}};
110}
111
David Beck111b5d92018-11-12 14:59:37 +0000112IBackendInternal::ILayerSupportSharedPtr NeonBackend::GetLayerSupport() const
113{
Sadik Armagan045f6be2020-09-10 13:37:32 +0100114 static ILayerSupportSharedPtr layerSupport
115 {
116 new NeonLayerSupport(IBackendInternal::IBackendSpecificModelContextPtr{})
117 };
118 return layerSupport;
119}
120
121IBackendInternal::ILayerSupportSharedPtr NeonBackend::GetLayerSupport(const ModelOptions& modelOptions) const
122{
123 static ILayerSupportSharedPtr layerSupport
124 {
125 new NeonLayerSupport(CreateBackendSpecificModelContext(modelOptions))
126 };
David Beck111b5d92018-11-12 14:59:37 +0000127 return layerSupport;
128}
129
Matteo Martincighc3ba50e2019-05-22 14:28:16 +0100130OptimizationViews NeonBackend::OptimizeSubgraphView(const SubgraphView& subgraph) const
Matteo Martincighadddddb2019-01-24 14:06:23 +0000131{
Matteo Martincighc3ba50e2019-05-22 14:28:16 +0100132 OptimizationViews optimizationViews;
Matteo Martincighadddddb2019-01-24 14:06:23 +0000133
Mike Kelly07810fc2020-11-12 10:58:48 +0000134 auto it = subgraph.end();
Mike Kelly1ac690a2020-11-17 11:41:38 +0000135 std::map<LayerGuid, Layer*> untouched;
Mike Kelly07810fc2020-11-12 10:58:48 +0000136
137 while (it != subgraph.begin())
138 {
139 --it;
140 Layer& base = **it;
Mike Kelly1ac690a2020-11-17 11:41:38 +0000141 untouched.insert({base.GetGuid(), &base});
142 }
143
144 it = subgraph.end();
145 while (it != subgraph.begin())
146 {
147 --it;
148 Layer& base = **it;
Mike Kelly07810fc2020-11-12 10:58:48 +0000149
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100150 // Fuse activation into previous layer if supported by backend
Mike Kelly07810fc2020-11-12 10:58:48 +0000151 if ((base.GetType() == LayerType::DepthwiseConvolution2d || base.GetType() == LayerType::Convolution2d
152 || base.GetType() == LayerType::BatchNormalization || base.GetType() == LayerType::FullyConnected
153 || base.GetType() == LayerType::Addition || base.GetType() == LayerType::Multiplication
Matthew Sloyanae123062021-05-07 14:18:01 +0000154 || base.GetType() == LayerType::Subtraction || base.GetType() == LayerType::Division)
Mike Kelly07810fc2020-11-12 10:58:48 +0000155 && (base.GetAdditionalInformation<ActivationDescriptor>() == nullptr))
156 {
157 for (auto output = base.BeginOutputSlots(); output != base.EndOutputSlots(); ++output)
158 {
159 if (output->GetNumConnections() == 1)
160 {
161 for (auto&& childInput : output->GetConnections())
162 {
Teresa Charlind672f5d2021-01-18 18:07:57 +0000163 if ((childInput->GetOwningLayer().GetType() == LayerType::Activation) &&
164 (checkDataTypeInputandOutput(childInput->GetOwningLayer())))
Mike Kelly07810fc2020-11-12 10:58:48 +0000165 {
166 Layer& child = childInput->GetOwningLayer();
167
168 auto* activationLayer = PolymorphicDowncast<ActivationLayer*>(&child);
169
170 const std::string name = std::string("fused-") + child.GetName() + std::string("-into-") +
171 base.GetName();
172
173 // Get params from activation layer
174 ActivationDescriptor activationDesc = activationLayer->GetParameters();
175
176 if (base.GetType() == LayerType::Convolution2d)
177 {
178 Convolution2dLayer* baseLayer = PolymorphicDowncast<Convolution2dLayer*>(&base);
179
180 Optional<TensorInfo> biases;
181
182 if (baseLayer->GetParameters().m_BiasEnabled)
183 {
Mike Kelly1ac690a2020-11-17 11:41:38 +0000184 biases = baseLayer->m_Bias->GetTensorInfo();
Mike Kelly07810fc2020-11-12 10:58:48 +0000185 }
186
187 arm_compute::Status status = NeonConvolution2dWorkloadValidate(
188 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
189 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
190 baseLayer->GetParameters(),
191 baseLayer->m_Weight->GetTensorInfo(),
192 biases,
193 false,
194 &activationDesc);
195
196 if (status)
197 {
198 FuseLayerWithWeightsAndBiases<Convolution2dLayer>(optimizationViews,
199 baseLayer,
200 activationLayer,
201 activationDesc,
202 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000203 untouched.erase(baseLayer->GetGuid());
204 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000205 }
206 }
207 else if (base.GetType() == LayerType::DepthwiseConvolution2d)
208 {
209 DepthwiseConvolution2dLayer* baseLayer =
210 PolymorphicDowncast<DepthwiseConvolution2dLayer*>(&base);
211
212 Optional<TensorInfo> biases;
213
214 if (baseLayer->GetParameters().m_BiasEnabled)
215 {
Mike Kelly1ac690a2020-11-17 11:41:38 +0000216 biases = baseLayer->m_Bias->GetTensorInfo();
Mike Kelly07810fc2020-11-12 10:58:48 +0000217 }
218
219 arm_compute::Status status = NeonDepthwiseConvolutionWorkloadValidate(
220 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
221 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
222 baseLayer->GetParameters(),
223 baseLayer->m_Weight->GetTensorInfo(),
224 biases,
225 &activationDesc);
226
227 if (status)
228 {
229 FuseLayerWithWeightsAndBiases<DepthwiseConvolution2dLayer>(optimizationViews,
230 baseLayer,
231 activationLayer,
232 activationDesc,
233 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000234 untouched.erase(baseLayer->GetGuid());
235 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000236 }
237 }
238 else if (base.GetType() == LayerType::FullyConnected)
239 {
240 FullyConnectedLayer* baseLayer = PolymorphicDowncast<FullyConnectedLayer*>(&base);
241
242 arm_compute::Status status = NeonFullyConnectedWorkloadValidate(
243 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
244 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
245 baseLayer->m_Weight->GetTensorInfo(),
246 baseLayer->m_Bias->GetTensorInfo(),
247 baseLayer->GetParameters(),
248 &activationDesc);
249
250 if (status)
251 {
252 FuseLayerWithWeightsAndBiases<FullyConnectedLayer>(optimizationViews,
253 baseLayer,
254 activationLayer,
255 activationDesc,
256 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000257 untouched.erase(baseLayer->GetGuid());
258 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000259 }
260 }
261 else if (base.GetType() == LayerType::BatchNormalization)
262 {
263 BatchNormalizationLayer* baseLayer =
264 PolymorphicDowncast<BatchNormalizationLayer*>(&base);
265
266 arm_compute::Status status = NeonBatchNormalizationValidate(
267 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
268 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
269 baseLayer->m_Mean->GetTensorInfo(),
270 baseLayer->m_Variance->GetTensorInfo(),
271 baseLayer->m_Beta->GetTensorInfo(),
272 baseLayer->m_Gamma->GetTensorInfo(),
273 baseLayer->GetParameters(),
274 &activationDesc);
275
276 if (status)
277 {
278 BatchNormalizationLayer* replacementLayer =
279 FuseLayerWithParameters<BatchNormalizationLayer>(
280 optimizationViews,
281 baseLayer,
282 activationLayer,
283 activationDesc,
284 name);
285
286 replacementLayer->m_Beta = std::move(baseLayer->m_Beta);
287 replacementLayer->m_Gamma = std::move(baseLayer->m_Gamma);
288 replacementLayer->m_Mean = std::move(baseLayer->m_Mean);
289 replacementLayer->m_Variance = std::move(baseLayer->m_Variance);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000290 untouched.erase(baseLayer->GetGuid());
291 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000292 }
293 }
294 else if (base.GetType() == LayerType::Addition)
295 {
296 AdditionLayer* baseLayer = PolymorphicDowncast<AdditionLayer*>(&base);
297
298 arm_compute::Status status = NeonAdditionWorkloadValidate(
299 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
300 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
301 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
302 &activationDesc);
303
304 if (status)
305 {
306 FuseLayerWithoutParameters<AdditionLayer>(optimizationViews,
307 baseLayer,
308 activationLayer,
309 activationDesc,
310 name);
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::Division)
316 {
317 DivisionLayer* baseLayer = PolymorphicDowncast<DivisionLayer*>(&base);
318
319 arm_compute::Status status = NeonDivisionWorkloadValidate(
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 {
327 FuseLayerWithoutParameters<DivisionLayer>(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::Multiplication)
337 {
338 MultiplicationLayer* baseLayer = PolymorphicDowncast<MultiplicationLayer*>(&base);
339
340 arm_compute::Status status = NeonMultiplicationWorkloadValidate(
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 {
348 FuseLayerWithoutParameters<MultiplicationLayer>(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::Subtraction)
358 {
359 SubtractionLayer* baseLayer = PolymorphicDowncast<SubtractionLayer*>(&base);
360
361 arm_compute::Status status = NeonSubtractionWorkloadValidate(
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 {
369 FuseLayerWithoutParameters<SubtractionLayer>(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 }
379 }
380 }
381 }
382 }
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100383
384 // Separate reduce layer with multiple axes into multiple reduce layers with 1 axis.
385 if (base.GetType() == LayerType::Reduce)
386 {
387 ReduceLayer* baseLayer = PolymorphicDowncast<ReduceLayer*>(&base);
388 ReduceDescriptor reduceDescriptor = baseLayer->GetParameters();
389
390 if (!reduceDescriptor.m_vAxis.empty() && reduceDescriptor.m_vAxis.size() > 1)
391 {
392 // Add new layers to the graph and connect them.
393 std::vector<Layer*> layers = ChainReduceLayers<ReduceLayer>(optimizationViews,
394 baseLayer,
395 reduceDescriptor);
396
397 // Replace existing baselayer with new subgraph.
398 ReplaceLayers<ReduceLayer>(optimizationViews, baseLayer, layers);
399 untouched.erase(baseLayer->GetGuid());
400 }
401 }
Mike Kelly07810fc2020-11-12 10:58:48 +0000402 }
403
404 if (optimizationViews.GetSubstitutions().empty())
405 {
406 optimizationViews.AddUntouchedSubgraph(SubgraphView(subgraph));
407 }
Mike Kelly1ac690a2020-11-17 11:41:38 +0000408 else
409 {
410 ReportUntouchedLayers(optimizationViews, untouched);
411 }
Matteo Martincighc3ba50e2019-05-22 14:28:16 +0100412
413 return optimizationViews;
Matteo Martincighadddddb2019-01-24 14:06:23 +0000414}
415
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +0100416std::vector<ITensorHandleFactory::FactoryId> NeonBackend::GetHandleFactoryPreferences() const
417{
Narumol Prangnawarat265e53e2020-10-30 16:06:55 +0000418 return std::vector<ITensorHandleFactory::FactoryId>() = { NeonTensorHandleFactory::GetIdStatic() };
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +0100419}
420
421void NeonBackend::RegisterTensorHandleFactories(class TensorHandleFactoryRegistry& registry)
422{
423 auto memoryManager = std::make_shared<NeonMemoryManager>(std::make_unique<arm_compute::Allocator>(),
424 BaseMemoryManager::MemoryAffinity::Offset);
425
426 registry.RegisterMemoryManager(memoryManager);
Jan Eilerse9f0f0f2019-08-16 10:28:37 +0100427 registry.RegisterFactory(std::make_unique<NeonTensorHandleFactory>(memoryManager));
Narumol Prangnawarat4e3e8182019-08-14 12:25:50 +0100428}
429
Matthew Bentham42bad952018-12-17 09:23:36 +0000430} // namespace armnn