1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5
6 #include "ClConvolution2dWorkload.hpp"
7
8 #include "ClWorkloadUtils.hpp"
9
10 #include <cl/ClLayerSupport.hpp>
11 #include <cl/ClTensorHandle.hpp>
12 #include <cl/ClLayerSupport.hpp>
13 #include <aclCommon/ArmComputeUtils.hpp>
14 #include <aclCommon/ArmComputeTensorUtils.hpp>
15 #include <backendsCommon/CpuTensorHandle.hpp>
16
17 #include <arm_compute/runtime/CL/functions/CLConvolutionLayer.h>
18
19 namespace armnn
20 {
21 using namespace armcomputetensorutils;
22
ClConvolution2dWorkloadValidate(const TensorInfo & input,const TensorInfo & output,const Convolution2dDescriptor & descriptor,const TensorInfo & weights,const Optional<TensorInfo> & biases,bool isFastMathEnabled,const ActivationDescriptor * activationDescriptor)23 arm_compute::Status ClConvolution2dWorkloadValidate(const TensorInfo& input,
24 const TensorInfo& output,
25 const Convolution2dDescriptor& descriptor,
26 const TensorInfo& weights,
27 const Optional<TensorInfo>& biases,
28 bool isFastMathEnabled,
29 const ActivationDescriptor* activationDescriptor)
30 {
31 const arm_compute::TensorInfo aclInputInfo = BuildArmComputeTensorInfo(input, descriptor.m_DataLayout);
32 const arm_compute::TensorInfo aclOutputInfo = BuildArmComputeTensorInfo(output, descriptor.m_DataLayout);
33 const arm_compute::TensorInfo aclWeightsInfo = BuildArmComputeTensorInfo(weights, descriptor.m_DataLayout);
34
35 const arm_compute::Size2D aclDilationInfo = BuildArmComputeSize2D(descriptor.m_DilationX,
36 descriptor.m_DilationY);
37
38 arm_compute::TensorInfo aclBiasesInfo;
39 arm_compute::TensorInfo *optionalAclBiasesInfo = nullptr;
40
41 if (descriptor.m_BiasEnabled)
42 {
43 ARMNN_ASSERT(biases.has_value());
44
45 aclBiasesInfo = BuildArmComputeTensorInfo(biases.value(), descriptor.m_DataLayout);
46 optionalAclBiasesInfo = &aclBiasesInfo;
47 }
48
49 arm_compute::PadStrideInfo layerInfo = BuildArmComputePadStrideInfo(descriptor);
50
51 const arm_compute::ActivationLayerInfo activationInfo = ConvertActivationDescriptorToAclActivationLayerInfo(
52 activationDescriptor);
53
54 return arm_compute::CLConvolutionLayer::validate(&aclInputInfo,
55 &aclWeightsInfo,
56 optionalAclBiasesInfo,
57 &aclOutputInfo,
58 layerInfo,
59 arm_compute::WeightsInfo(),
60 aclDilationInfo,
61 activationInfo,
62 isFastMathEnabled);
63 }
64
ClConvolution2dWorkload(const Convolution2dQueueDescriptor & descriptor,const WorkloadInfo & info,std::shared_ptr<arm_compute::MemoryManagerOnDemand> & memoryManager,const bool isFastMathEnabled)65 ClConvolution2dWorkload::ClConvolution2dWorkload(const Convolution2dQueueDescriptor& descriptor,
66 const WorkloadInfo& info,
67 std::shared_ptr<arm_compute::MemoryManagerOnDemand>& memoryManager,
68 const bool isFastMathEnabled)
69 : BaseWorkload<Convolution2dQueueDescriptor>(descriptor, info)
70 , m_ConvolutionLayer(memoryManager)
71 {
72 // todo: check tensor shapes match.
73 const TensorInfo& weightInfo = m_Data.m_Weight->GetTensorInfo();
74
75 m_KernelTensor = std::make_unique<arm_compute::CLTensor>();
76 BuildArmComputeTensor(*m_KernelTensor, weightInfo, m_Data.m_Parameters.m_DataLayout);
77
78 const arm_compute::Size2D aclDilationInfo = BuildArmComputeSize2D(m_Data.m_Parameters.m_DilationX,
79 m_Data.m_Parameters.m_DilationY);
80
81 if (m_Data.m_Parameters.m_BiasEnabled)
82 {
83 m_BiasTensor = std::make_unique<arm_compute::CLTensor>();
84 BuildArmComputeTensor(*m_BiasTensor, m_Data.m_Bias->GetTensorInfo(), m_Data.m_Parameters.m_DataLayout);
85 }
86
87 m_Data.ValidateInputsOutputs("ClConvolution2dWorkload", 1, 1);
88
89 arm_compute::ICLTensor& input = static_cast<IClTensorHandle*>(m_Data.m_Inputs[0])->GetTensor();
90 arm_compute::ICLTensor& output = static_cast<IClTensorHandle*>(m_Data.m_Outputs[0])->GetTensor();
91
92 arm_compute::DataLayout aclDataLayout = ConvertDataLayout(m_Data.m_Parameters.m_DataLayout);
93 input.info()->set_data_layout(aclDataLayout);
94 output.info()->set_data_layout(aclDataLayout);
95
96 arm_compute::PadStrideInfo padStrideInfo = BuildArmComputePadStrideInfo(m_Data.m_Parameters);
97
98 const arm_compute::ActivationLayerInfo activationInfo = ConvertAdditionalInfoToAclActivationLayerInfo(descriptor);
99
100 m_ConvolutionLayer.configure(&input,
101 m_KernelTensor.get(),
102 m_BiasTensor.get(),
103 &output,
104 padStrideInfo,
105 arm_compute::WeightsInfo(),
106 aclDilationInfo,
107 activationInfo,
108 isFastMathEnabled);
109
110 m_ConvolutionMethod =
111 m_ConvolutionLayer.get_convolution_method(input.info(),
112 m_KernelTensor->info(),
113 output.info(),
114 padStrideInfo,
115 arm_compute::WeightsInfo(),
116 activationInfo,
117 arm_compute::CLScheduler::get().target(),
118 aclDilationInfo,
119 isFastMathEnabled);
120
121 InitializeArmComputeClTensorData(*m_KernelTensor, m_Data.m_Weight);
122
123 if (m_BiasTensor)
124 {
125 InitializeArmComputeClTensorData(*m_BiasTensor, m_Data.m_Bias);
126 }
127
128 // Force Compute Library to perform the necessary copying and reshaping, after which
129 // delete all the input tensors that will no longer be needed
130 m_ConvolutionLayer.prepare();
131 FreeUnusedTensors();
132 }
133
Execute() const134 void ClConvolution2dWorkload::Execute() const
135 {
136 ARMNN_SCOPED_PROFILING_EVENT_CL("ClConvolution2dWorkload_Execute");
137 RunClFunction(m_ConvolutionLayer, CHECK_LOCATION());
138 }
139
GetConvolutionMethod() const140 arm_compute::ConvolutionMethod ClConvolution2dWorkload::GetConvolutionMethod() const
141 {
142 return m_ConvolutionMethod;
143 }
144
FreeUnusedTensors()145 void ClConvolution2dWorkload::FreeUnusedTensors()
146 {
147 FreeTensorIfUnused(m_KernelTensor);
148 FreeTensorIfUnused(m_BiasTensor);
149 }
150
151 } //namespace armnn
152