blob: f1e52c199897d2004d620c553f04621e2ff9c6d3 [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 "ClBackend.hpp"
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +01007#include "ClBackendContext.hpp"
David Beck3e9e1152018-10-17 14:17:50 +01008#include "ClBackendId.hpp"
Sadik Armagan045f6be2020-09-10 13:37:32 +01009#include "ClBackendModelContext.hpp"
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +010010#include "ClImportTensorHandleFactory.hpp"
David Beck111b5d92018-11-12 14:59:37 +000011#include "ClLayerSupport.hpp"
Jan Eilerse9f0f0f2019-08-16 10:28:37 +010012#include "ClTensorHandleFactory.hpp"
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +010013#include "ClWorkloadFactory.hpp"
arovir01a0944792018-10-11 15:00:58 +010014
Matteo Martincighc601aa62019-10-29 15:03:22 +000015#include <armnn/BackendRegistry.hpp>
Mike Kelly07810fc2020-11-12 10:58:48 +000016#include <armnn/Descriptors.hpp>
Matteo Martincighc601aa62019-10-29 15:03:22 +000017
Mike Kelly07810fc2020-11-12 10:58:48 +000018#include <aclCommon/ArmComputeSubgraphUtils.hpp>
19#include <aclCommon/ArmComputeUtils.hpp>
Aron Virginas-Tar56055192018-11-12 18:10:43 +000020#include <aclCommon/BaseMemoryManager.hpp>
21
Matteo Martincighe5b8eb92019-11-28 15:45:42 +000022#include <armnn/backends/IBackendContext.hpp>
23#include <armnn/backends/IMemoryManager.hpp>
Jan Eilers3c9e0452020-04-10 13:00:44 +010024#include <armnn/utility/PolymorphicDowncast.hpp>
25
Mike Kelly07810fc2020-11-12 10:58:48 +000026#include "workloads/ClAdditionWorkload.hpp"
27#include "workloads/ClBatchNormalizationFloatWorkload.hpp"
28#include "workloads/ClConvolution2dWorkload.hpp"
29#include "workloads/ClDepthwiseConvolutionWorkload.hpp"
Teresa Charline11e63d2021-04-21 12:56:45 +010030#include "workloads/ClDivisionWorkload.hpp"
Mike Kelly07810fc2020-11-12 10:58:48 +000031#include "workloads/ClFullyConnectedWorkload.hpp"
32#include "workloads/ClMultiplicationWorkload.hpp"
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +010033#include "workloads/ClReduceWorkload.hpp"
Mike Kelly07810fc2020-11-12 10:58:48 +000034#include "workloads/ClSubtractionWorkload.hpp"
35
David Beck263e3492018-11-09 14:46:40 +000036#include <Optimizer.hpp>
arovir014424b0a2018-10-04 10:46:04 +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/CL/CLBufferAllocator.h>
40
arovir014424b0a2018-10-04 10:46:04 +010041namespace armnn
42{
43
David Beck3cc9a622018-10-12 10:38:31 +010044const BackendId& ClBackend::GetIdStatic()
arovir014424b0a2018-10-04 10:46:04 +010045{
David Beck3e9e1152018-10-17 14:17:50 +010046 static const BackendId s_Id{ClBackendId()};
arovir014424b0a2018-10-04 10:46:04 +010047 return s_Id;
48}
49
Aron Virginas-Tar56055192018-11-12 18:10:43 +000050IBackendInternal::IMemoryManagerUniquePtr ClBackend::CreateMemoryManager() const
arovir014424b0a2018-10-04 10:46:04 +010051{
Aron Virginas-Tar56055192018-11-12 18:10:43 +000052 return std::make_unique<ClMemoryManager>(std::make_unique<arm_compute::CLBufferAllocator>());
53}
54
55IBackendInternal::IWorkloadFactoryPtr ClBackend::CreateWorkloadFactory(
56 const IBackendInternal::IMemoryManagerSharedPtr& memoryManager) const
57{
58 return std::make_unique<ClWorkloadFactory>(
Jan Eilers3c9e0452020-04-10 13:00:44 +010059 PolymorphicPointerDowncast<ClMemoryManager>(memoryManager));
arovir014424b0a2018-10-04 10:46:04 +010060}
61
Jan Eilerse9f0f0f2019-08-16 10:28:37 +010062IBackendInternal::IWorkloadFactoryPtr ClBackend::CreateWorkloadFactory(
Sadik Armagan04a72972020-09-14 15:44:18 +010063 const IBackendInternal::IMemoryManagerSharedPtr& memoryManager, const ModelOptions& modelOptions) const
64{
65 return std::make_unique<ClWorkloadFactory>(
66 PolymorphicPointerDowncast<ClMemoryManager>(memoryManager), CreateBackendSpecificModelContext(modelOptions));
67}
68
69IBackendInternal::IWorkloadFactoryPtr ClBackend::CreateWorkloadFactory(
Jan Eilerse9f0f0f2019-08-16 10:28:37 +010070 TensorHandleFactoryRegistry& registry) const
71{
72 auto memoryManager = std::make_shared<ClMemoryManager>(std::make_unique<arm_compute::CLBufferAllocator>());
73
74 registry.RegisterMemoryManager(memoryManager);
Narumol Prangnawarat549cb7a2020-07-10 17:50:53 +010075 registry.RegisterFactory(std::make_unique<ClTensorHandleFactory>(memoryManager));
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +010076 registry.RegisterFactory(std::make_unique<ClImportTensorHandleFactory>(
77 static_cast<MemorySourceFlags>(MemorySource::Malloc), static_cast<MemorySourceFlags>(MemorySource::Malloc)));
Jan Eilerse9f0f0f2019-08-16 10:28:37 +010078
79 return std::make_unique<ClWorkloadFactory>(
Jan Eilers3c9e0452020-04-10 13:00:44 +010080 PolymorphicPointerDowncast<ClMemoryManager>(memoryManager));
Jan Eilerse9f0f0f2019-08-16 10:28:37 +010081}
82
Sadik Armagan04a72972020-09-14 15:44:18 +010083IBackendInternal::IWorkloadFactoryPtr ClBackend::CreateWorkloadFactory(
84 TensorHandleFactoryRegistry& registry, const ModelOptions& modelOptions) const
85{
86 auto memoryManager = std::make_shared<ClMemoryManager>(std::make_unique<arm_compute::CLBufferAllocator>());
87
88 registry.RegisterMemoryManager(memoryManager);
89 registry.RegisterFactory(std::make_unique<ClTensorHandleFactory>(memoryManager));
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +010090 registry.RegisterFactory(std::make_unique<ClImportTensorHandleFactory>(
91 static_cast<MemorySourceFlags>(MemorySource::Malloc), static_cast<MemorySourceFlags>(MemorySource::Malloc)));
92
93 return std::make_unique<ClWorkloadFactory>(
94 PolymorphicPointerDowncast<ClMemoryManager>(memoryManager), CreateBackendSpecificModelContext(modelOptions));
95}
96
97IBackendInternal::IWorkloadFactoryPtr ClBackend::CreateWorkloadFactory(
98 TensorHandleFactoryRegistry& registry,
99 const ModelOptions& modelOptions,
100 MemorySourceFlags inputFlags,
101 MemorySourceFlags outputFlags) const
102{
103 auto memoryManager = std::make_shared<ClMemoryManager>(std::make_unique<arm_compute::CLBufferAllocator>());
104
105 registry.RegisterMemoryManager(memoryManager);
106 registry.RegisterFactory(std::make_unique<ClTensorHandleFactory>(memoryManager));
107 registry.RegisterFactory(std::make_unique<ClImportTensorHandleFactory>(inputFlags, outputFlags));
Sadik Armagan04a72972020-09-14 15:44:18 +0100108
109 return std::make_unique<ClWorkloadFactory>(
110 PolymorphicPointerDowncast<ClMemoryManager>(memoryManager), CreateBackendSpecificModelContext(modelOptions));
111}
112
Jan Eilerse9f0f0f2019-08-16 10:28:37 +0100113std::vector<ITensorHandleFactory::FactoryId> ClBackend::GetHandleFactoryPreferences() const
114{
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100115 return std::vector<ITensorHandleFactory::FactoryId> {ClTensorHandleFactory::GetIdStatic(),
116 ClImportTensorHandleFactory::GetIdStatic()};
Jan Eilerse9f0f0f2019-08-16 10:28:37 +0100117}
118
119void ClBackend::RegisterTensorHandleFactories(TensorHandleFactoryRegistry& registry)
120{
121 auto mgr = std::make_shared<ClMemoryManager>(std::make_unique<arm_compute::CLBufferAllocator>());
122
123 registry.RegisterMemoryManager(mgr);
124 registry.RegisterFactory(std::make_unique<ClTensorHandleFactory>(mgr));
Narumol Prangnawarate5f0b242021-05-07 17:52:36 +0100125 registry.RegisterFactory(std::make_unique<ClImportTensorHandleFactory>(
126 static_cast<MemorySourceFlags>(MemorySource::Malloc), static_cast<MemorySourceFlags>(MemorySource::Malloc)));
127}
128
129void ClBackend::RegisterTensorHandleFactories(TensorHandleFactoryRegistry& registry,
130 MemorySourceFlags inputFlags,
131 MemorySourceFlags outputFlags)
132{
133 auto mgr = std::make_shared<ClMemoryManager>(std::make_unique<arm_compute::CLBufferAllocator>());
134
135 registry.RegisterMemoryManager(mgr);
136 registry.RegisterFactory(std::make_unique<ClTensorHandleFactory>(mgr));
137 registry.RegisterFactory(std::make_unique<ClImportTensorHandleFactory>(inputFlags, outputFlags));
Jan Eilerse9f0f0f2019-08-16 10:28:37 +0100138}
139
Sadik Armagan045f6be2020-09-10 13:37:32 +0100140IBackendInternal::IBackendContextPtr ClBackend::CreateBackendContext(const IRuntime::CreationOptions& options) const
David Beck1b61be52018-11-08 09:19:14 +0000141{
142 return IBackendContextPtr{new ClBackendContext{options}};
143}
144
Colm Donelane49755b2020-01-29 15:22:43 +0000145IBackendInternal::IBackendProfilingContextPtr ClBackend::CreateBackendProfilingContext(
Colm Donelan1aff3932020-02-05 17:48:59 +0000146 const IRuntime::CreationOptions&, IBackendProfilingPtr&)
Colm Donelane49755b2020-01-29 15:22:43 +0000147{
148 return IBackendProfilingContextPtr{};
149}
150
David Beck263e3492018-11-09 14:46:40 +0000151IBackendInternal::Optimizations ClBackend::GetOptimizations() const
152{
153 return Optimizations{};
154}
David Beck1b61be52018-11-08 09:19:14 +0000155
Sadik Armagan045f6be2020-09-10 13:37:32 +0100156IBackendInternal::IBackendSpecificModelContextPtr ClBackend::CreateBackendSpecificModelContext(
157 const ModelOptions& modelOptions) const
158{
159 return IBackendSpecificModelContextPtr{new ClBackendModelContext{modelOptions}};
160}
161
David Beck111b5d92018-11-12 14:59:37 +0000162IBackendInternal::ILayerSupportSharedPtr ClBackend::GetLayerSupport() const
163{
Sadik Armagan045f6be2020-09-10 13:37:32 +0100164 static ILayerSupportSharedPtr layerSupport
165 {
166 new ClLayerSupport(IBackendInternal::IBackendSpecificModelContextPtr{})
167 };
168 return layerSupport;
169}
170
171IBackendInternal::ILayerSupportSharedPtr ClBackend::GetLayerSupport(const ModelOptions& modelOptions) const
172{
173 static ILayerSupportSharedPtr layerSupport
174 {
175 new ClLayerSupport(CreateBackendSpecificModelContext(modelOptions))
176 };
David Beck111b5d92018-11-12 14:59:37 +0000177 return layerSupport;
178}
179
Mike Kelly07810fc2020-11-12 10:58:48 +0000180OptimizationViews ClBackend::OptimizeSubgraphView(const SubgraphView& subgraph,
181 const ModelOptions& modelOptions) const
Matteo Martincighadddddb2019-01-24 14:06:23 +0000182{
Matteo Martincighc3ba50e2019-05-22 14:28:16 +0100183 OptimizationViews optimizationViews;
Matteo Martincighadddddb2019-01-24 14:06:23 +0000184
Mike Kelly07810fc2020-11-12 10:58:48 +0000185 auto it = subgraph.end();
186 bool isFastMathEnabled = false;
Mike Kelly1ac690a2020-11-17 11:41:38 +0000187 std::map<LayerGuid, Layer*> untouched;
Mike Kelly07810fc2020-11-12 10:58:48 +0000188
Mike Kelly1ac690a2020-11-17 11:41:38 +0000189 while (it != subgraph.begin())
190 {
191 --it;
192 Layer& base = **it;
193 untouched.insert({base.GetGuid(), &base});
194 }
195
196 it = subgraph.end();
Mike Kelly07810fc2020-11-12 10:58:48 +0000197#if defined(ARMCOMPUTECL_ENABLED)
198 IBackendInternal::IBackendSpecificModelContextPtr modelContextPtr = CreateBackendSpecificModelContext(modelOptions);
199
200 if (modelContextPtr)
201 {
202 auto clModelOptions = dynamic_cast<ClBackendModelContext*>(modelContextPtr.get());
203 if (clModelOptions)
204 {
205 isFastMathEnabled = clModelOptions->IsFastMathEnabled();
206 }
207 }
208#endif
Mike Kelly07810fc2020-11-12 10:58:48 +0000209 while (it != subgraph.begin())
210 {
211 --it;
212 Layer& base = **it;
213
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100214 // Fuse activation into previous layer if supported by backend
Mike Kelly07810fc2020-11-12 10:58:48 +0000215 if ((base.GetType() == LayerType::DepthwiseConvolution2d || base.GetType() == LayerType::Convolution2d
216 || base.GetType() == LayerType::BatchNormalization || base.GetType() == LayerType::FullyConnected
217 || base.GetType() == LayerType::Addition || base.GetType() == LayerType::Multiplication
Matthew Sloyanae123062021-05-07 14:18:01 +0000218 || base.GetType() == LayerType::Subtraction || base.GetType() == LayerType::Division)
Mike Kelly07810fc2020-11-12 10:58:48 +0000219 && (base.GetAdditionalInformation<ActivationDescriptor>() == nullptr))
220 {
221 for (auto output = base.BeginOutputSlots(); output != base.EndOutputSlots(); ++output)
222 {
223 if (output->GetNumConnections() == 1)
224 {
225 for (auto&& childInput : output->GetConnections())
226 {
Teresa Charlind672f5d2021-01-18 18:07:57 +0000227 if ((childInput->GetOwningLayer().GetType() == LayerType::Activation) &&
228 (checkDataTypeInputandOutput(childInput->GetOwningLayer())))
Mike Kelly07810fc2020-11-12 10:58:48 +0000229 {
230 Layer& child = childInput->GetOwningLayer();
231
232 auto* activationLayer = PolymorphicDowncast<ActivationLayer*>(&child);
233
234 const std::string name = std::string("fused-") + child.GetName() + std::string("-into-") +
235 base.GetName();
236
237 // Get params from activation layer
238 ActivationDescriptor activationDesc = activationLayer->GetParameters();
239
240 if (base.GetType() == LayerType::Convolution2d)
241 {
242 Convolution2dLayer* baseLayer = PolymorphicDowncast<Convolution2dLayer*>(&base);
243
244 Optional<TensorInfo> biases;
245
246 if (baseLayer->GetParameters().m_BiasEnabled)
247 {
Mike Kelly1ac690a2020-11-17 11:41:38 +0000248 biases = baseLayer->m_Bias->GetTensorInfo();
Mike Kelly07810fc2020-11-12 10:58:48 +0000249 }
250
251 arm_compute::Status status = ClConvolution2dWorkloadValidate(
252 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
253 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
254 baseLayer->GetParameters(),
255 baseLayer->m_Weight->GetTensorInfo(),
256 biases,
257 isFastMathEnabled,
258 &activationDesc);
259
260 if (status)
261 {
262 FuseLayerWithWeightsAndBiases<Convolution2dLayer>(optimizationViews,
263 baseLayer,
264 activationLayer,
265 activationDesc,
266 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000267 untouched.erase(baseLayer->GetGuid());
268 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000269 }
270 }
271 else if (base.GetType() == LayerType::DepthwiseConvolution2d)
272 {
273 DepthwiseConvolution2dLayer* baseLayer =
274 PolymorphicDowncast<DepthwiseConvolution2dLayer*>(&base);
275
276 Optional<TensorInfo> biases;
277
278 if (baseLayer->GetParameters().m_BiasEnabled)
279 {
Mike Kelly1ac690a2020-11-17 11:41:38 +0000280 biases = baseLayer->m_Bias->GetTensorInfo();
Mike Kelly07810fc2020-11-12 10:58:48 +0000281 }
282
283 arm_compute::Status status = ClDepthwiseConvolutionWorkloadValidate(
284 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
285 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
286 baseLayer->GetParameters(),
287 baseLayer->m_Weight->GetTensorInfo(),
288 biases,
289 &activationDesc);
290
291 if (status)
292 {
293 FuseLayerWithWeightsAndBiases<DepthwiseConvolution2dLayer>(optimizationViews,
294 baseLayer,
295 activationLayer,
296 activationDesc,
297 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000298 untouched.erase(baseLayer->GetGuid());
299 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000300 }
301 }
302 else if (base.GetType() == LayerType::FullyConnected)
303 {
304 FullyConnectedLayer* baseLayer = PolymorphicDowncast<FullyConnectedLayer*>(&base);
305
306 arm_compute::Status status = ClFullyConnectedWorkloadValidate(
307 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
308 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
309 baseLayer->m_Weight->GetTensorInfo(),
310 baseLayer->m_Bias->GetTensorInfo(),
311 baseLayer->GetParameters(),
312 &activationDesc);
313
314 if (status)
315 {
316 FuseLayerWithWeightsAndBiases<FullyConnectedLayer>(optimizationViews,
317 baseLayer,
318 activationLayer,
319 activationDesc,
320 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000321 untouched.erase(baseLayer->GetGuid());
322 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000323 }
324 }
325 else if (base.GetType() == LayerType::BatchNormalization)
326 {
327 BatchNormalizationLayer* baseLayer =
328 PolymorphicDowncast<BatchNormalizationLayer*>(&base);
329
330 arm_compute::Status status = ClBatchNormalizationValidate(
331 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
332 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
333 baseLayer->m_Mean->GetTensorInfo(),
334 baseLayer->m_Variance->GetTensorInfo(),
335 baseLayer->m_Beta->GetTensorInfo(),
336 baseLayer->m_Gamma->GetTensorInfo(),
337 baseLayer->GetParameters(),
338 &activationDesc);
339
340 if (status)
341 {
342 BatchNormalizationLayer* replacementLayer =
343 FuseLayerWithParameters<BatchNormalizationLayer>(optimizationViews,
344 baseLayer,
345 activationLayer,
346 activationDesc,
347 name);
348
349 replacementLayer->m_Beta = std::move(baseLayer->m_Beta);
350 replacementLayer->m_Gamma = std::move(baseLayer->m_Gamma);
351 replacementLayer->m_Mean = std::move(baseLayer->m_Mean);
352 replacementLayer->m_Variance = std::move(baseLayer->m_Variance);
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::Addition)
358 {
359 AdditionLayer* baseLayer = PolymorphicDowncast<AdditionLayer*>(&base);
360
361 arm_compute::Status status = ClAdditionValidate(
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<AdditionLayer>(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::Division)
379 {
380 DivisionLayer* baseLayer = PolymorphicDowncast<DivisionLayer*>(&base);
381
382 arm_compute::Status status = ClDivisionWorkloadValidate(
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 {
390 FuseLayerWithoutParameters<DivisionLayer>(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 }
399 else if (base.GetType() == LayerType::Multiplication)
400 {
401 MultiplicationLayer* baseLayer = PolymorphicDowncast<MultiplicationLayer*>(&base);
402
403 arm_compute::Status status = ClMultiplicationWorkloadValidate(
404 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
405 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
406 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
407 &activationDesc);
408
409 if (status)
410 {
411 FuseLayerWithoutParameters<MultiplicationLayer>(optimizationViews,
412 baseLayer,
413 activationLayer,
414 activationDesc,
415 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000416 untouched.erase(baseLayer->GetGuid());
417 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000418 }
419 }
420 else if (base.GetType() == LayerType::Subtraction)
421 {
422 SubtractionLayer* baseLayer = PolymorphicDowncast<SubtractionLayer*>(&base);
423
424 arm_compute::Status status = ClSubtractionValidate(
425 baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
426 baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
427 activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
428 &activationDesc);
429
430 if (status)
431 {
432 FuseLayerWithoutParameters<SubtractionLayer>(optimizationViews,
433 baseLayer,
434 activationLayer,
435 activationDesc,
436 name);
Mike Kelly1ac690a2020-11-17 11:41:38 +0000437 untouched.erase(baseLayer->GetGuid());
438 untouched.erase(activationLayer->GetGuid());
Mike Kelly07810fc2020-11-12 10:58:48 +0000439 }
440 }
441 }
442 }
443 }
444 }
445 }
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100446
447 // Separate reduce layer with multiple axes into multiple reduce layers with 1 axis.
448 if (base.GetType() == LayerType::Reduce)
449 {
450 ReduceLayer* baseLayer = PolymorphicDowncast<ReduceLayer*>(&base);
451 ReduceDescriptor reduceDescriptor = baseLayer->GetParameters();
452
453 if (!reduceDescriptor.m_vAxis.empty() && reduceDescriptor.m_vAxis.size() > 1)
454 {
455 // Add new layers to the graph and connect them.
456 std::vector<Layer*> layers = ChainReduceLayers<ReduceLayer>(optimizationViews,
457 baseLayer,
458 reduceDescriptor);
459
460 // Replace existing baselayer with new subgraph.
461 ReplaceLayers<ReduceLayer>(optimizationViews, baseLayer, layers);
462 untouched.erase(baseLayer->GetGuid());
463 }
464 }
Mike Kelly07810fc2020-11-12 10:58:48 +0000465 }
Mike Kelly1ac690a2020-11-17 11:41:38 +0000466
Mike Kelly07810fc2020-11-12 10:58:48 +0000467 if (optimizationViews.GetSubstitutions().empty())
468 {
469 optimizationViews.AddUntouchedSubgraph(SubgraphView(subgraph));
470 }
Mike Kelly1ac690a2020-11-17 11:41:38 +0000471 else
472 {
473 ReportUntouchedLayers(optimizationViews, untouched);
474 }
Matteo Martincighc3ba50e2019-05-22 14:28:16 +0100475
476 return optimizationViews;
Matteo Martincighadddddb2019-01-24 14:06:23 +0000477}
478
David Beck9efb57d2018-11-05 13:40:33 +0000479} // namespace armnn