blob: 8da3e472491a94312175733dfca5ff35573ff5e7 [file] [log] [blame]
telsoa014fcda012018-03-09 14:13:49 +00001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
David Beckecb56cd2018-09-05 12:52:57 +01003// SPDX-License-Identifier: MIT
telsoa014fcda012018-03-09 14:13:49 +00004//
5
David Beck711fa312018-09-24 10:46:38 +01006#include <backends/CpuTensorHandle.hpp>
7#include <backends/aclCommon/ArmComputeTensorUtils.hpp>
David Beck0dbe0ee2018-09-24 15:59:27 +01008#include <backends/neon/NeonLayerSupport.hpp>
telsoa014fcda012018-03-09 14:13:49 +00009
10#include "NeonConvolution2dBaseWorkload.hpp"
11
David Beck711fa312018-09-24 10:46:38 +010012#include <armnn/Types.hpp>
arovir01616e7752018-10-01 17:08:59 +010013#include <armnnUtils/Half.hpp>
telsoa01c577f2c2018-08-31 09:22:23 +010014
telsoa014fcda012018-03-09 14:13:49 +000015namespace armnn
16{
17
surmeh013537c2c2018-05-18 16:31:43 +010018using namespace armcomputetensorutils;
19
20arm_compute::Status NeonConvolution2dWorkloadValidate(const TensorInfo& input,
21 const TensorInfo& output,
22 const Convolution2dDescriptor& descriptor,
23 const TensorInfo& weights,
David Beck5eec11d2018-10-04 15:43:17 +010024 const Optional<TensorInfo>& biases)
surmeh013537c2c2018-05-18 16:31:43 +010025{
Francis Murtagh351d13d2018-09-24 15:01:18 +010026 const arm_compute::TensorInfo aclInputInfo = BuildArmComputeTensorInfo(input, descriptor.m_DataLayout);
27 const arm_compute::TensorInfo aclOutputInfo = BuildArmComputeTensorInfo(output, descriptor.m_DataLayout);
28 const arm_compute::TensorInfo aclWeightsInfo = BuildArmComputeTensorInfo(weights, descriptor.m_DataLayout);
arovir01a6824102018-08-28 17:40:45 +010029
surmeh013537c2c2018-05-18 16:31:43 +010030 arm_compute::TensorInfo aclBiasesInfo;
31 arm_compute::TensorInfo *optionalAclBiasesInfo = nullptr;
32
33 if (descriptor.m_BiasEnabled)
34 {
David Beck5eec11d2018-10-04 15:43:17 +010035 BOOST_ASSERT(biases.has_value());
arovir01a6824102018-08-28 17:40:45 +010036
David Beck5eec11d2018-10-04 15:43:17 +010037 aclBiasesInfo = BuildArmComputeTensorInfo(biases.value(), descriptor.m_DataLayout);
surmeh013537c2c2018-05-18 16:31:43 +010038 optionalAclBiasesInfo = &aclBiasesInfo;
39 }
40
41 arm_compute::PadStrideInfo layerInfo = BuildArmComputePadStrideInfo(descriptor);
42
43 return arm_compute::NEConvolutionLayer::validate(&aclInputInfo,
44 &aclWeightsInfo,
45 optionalAclBiasesInfo,
46 &aclOutputInfo,
47 layerInfo);
48}
49
telsoa01c577f2c2018-08-31 09:22:23 +010050template<armnn::DataType... dataTypes>
51NeonConvolution2dBaseWorkload<dataTypes...>::NeonConvolution2dBaseWorkload(
52 const Convolution2dQueueDescriptor& descriptor, const WorkloadInfo& info,
53 std::shared_ptr<arm_compute::MemoryManagerOnDemand>& memoryManager)
54 : TypedWorkload<Convolution2dQueueDescriptor, dataTypes...>(descriptor, info)
telsoa014fcda012018-03-09 14:13:49 +000055{
56 using arm_compute::NEDirectConvolutionLayer;
telsoa014fcda012018-03-09 14:13:49 +000057
58 ValidateData();
59
telsoa01c577f2c2018-08-31 09:22:23 +010060 // todo: check tensor shapes match.
telsoa014fcda012018-03-09 14:13:49 +000061
62 arm_compute::ITensor& input = boost::polymorphic_downcast<INeonTensorHandle*>(m_Data.m_Inputs[0])->GetTensor();
63 arm_compute::ITensor& output = boost::polymorphic_downcast<INeonTensorHandle*>(m_Data.m_Outputs[0])->GetTensor();
64
Francis Murtaghd59116e2018-10-04 16:03:07 +010065 arm_compute::DataLayout aclDataLayout = ConvertDataLayout(m_Data.m_Parameters.m_DataLayout);
66 input.info()->set_data_layout(aclDataLayout);
67 output.info()->set_data_layout(aclDataLayout);
68
telsoa01c577f2c2018-08-31 09:22:23 +010069 m_KernelTensor = std::make_unique<arm_compute::Tensor>();
Francis Murtaghd59116e2018-10-04 16:03:07 +010070 BuildArmComputeTensor(*m_KernelTensor, m_Data.m_Weight->GetTensorInfo(), m_Data.m_Parameters.m_DataLayout);
telsoa014fcda012018-03-09 14:13:49 +000071
telsoa014fcda012018-03-09 14:13:49 +000072 if (m_Data.m_Parameters.m_BiasEnabled)
73 {
telsoa01c577f2c2018-08-31 09:22:23 +010074 m_BiasTensor = std::make_unique<arm_compute::Tensor>();
Francis Murtaghd59116e2018-10-04 16:03:07 +010075 BuildArmComputeTensor(*m_BiasTensor, m_Data.m_Bias->GetTensorInfo(), m_Data.m_Parameters.m_DataLayout);
telsoa014fcda012018-03-09 14:13:49 +000076 }
77
78 arm_compute::PadStrideInfo padStrideInfo(m_Data.m_Parameters.m_StrideX,
79 m_Data.m_Parameters.m_StrideY,
80 m_Data.m_Parameters.m_PadLeft,
81 m_Data.m_Parameters.m_PadRight,
82 m_Data.m_Parameters.m_PadTop,
83 m_Data.m_Parameters.m_PadBottom,
84 arm_compute::DimensionRoundingType::FLOOR);
85
86 const bool preferDirectConvolution =
87 IsNeonDirectConvolutionPreferred(m_Data.m_Weight->GetTensorInfo(),
88 m_Data.m_Parameters);
89
90 if (preferDirectConvolution)
91 {
surmeh013537c2c2018-05-18 16:31:43 +010092 auto directConvolutionLayer = std::make_unique<arm_compute::NEDirectConvolutionLayer>(memoryManager);
telsoa014fcda012018-03-09 14:13:49 +000093 directConvolutionLayer->configure(&input,
telsoa01c577f2c2018-08-31 09:22:23 +010094 m_KernelTensor.get(),
95 m_BiasTensor.get(),
telsoa014fcda012018-03-09 14:13:49 +000096 &output,
97 padStrideInfo);
98 m_ConvolutionLayer.reset(directConvolutionLayer.release());
99 }
100 else
101 {
surmeh013537c2c2018-05-18 16:31:43 +0100102 auto convolutionLayer = std::make_unique<arm_compute::NEConvolutionLayer>(memoryManager);
telsoa014fcda012018-03-09 14:13:49 +0000103 convolutionLayer->configure(&input,
telsoa01c577f2c2018-08-31 09:22:23 +0100104 m_KernelTensor.get(),
105 m_BiasTensor.get(),
telsoa014fcda012018-03-09 14:13:49 +0000106 &output,
107 padStrideInfo);
108 m_ConvolutionLayer.reset(convolutionLayer.release());
109 }
110 BOOST_ASSERT(m_ConvolutionLayer);
111
telsoa01c577f2c2018-08-31 09:22:23 +0100112 armnn::DataType dataType = m_Data.m_Weight->GetTensorInfo().GetDataType();
telsoa014fcda012018-03-09 14:13:49 +0000113
telsoa01c577f2c2018-08-31 09:22:23 +0100114 switch (dataType)
115 {
116 case DataType::Float16:
117 {
118 InitialiseArmComputeTensorData(*m_KernelTensor, m_Data.m_Weight->template GetConstTensor<Half>());
119 break;
120 }
121 case DataType::Float32:
122 {
123 InitialiseArmComputeTensorData(*m_KernelTensor, m_Data.m_Weight->template GetConstTensor<float>());
124 break;
125 }
126 case DataType::QuantisedAsymm8:
127 {
128 InitialiseArmComputeTensorData(*m_KernelTensor, m_Data.m_Weight->template GetConstTensor<uint8_t>());
129 break;
130 }
131 default:
132 {
133 BOOST_ASSERT_MSG(false, "Unknown DataType.");
134 }
135 }
telsoa014fcda012018-03-09 14:13:49 +0000136}
137
telsoa01c577f2c2018-08-31 09:22:23 +0100138template<armnn::DataType... dataTypes>
139void NeonConvolution2dBaseWorkload<dataTypes...>::FreeUnusedTensors()
140{
141 FreeTensorIfUnused(m_KernelTensor);
142 FreeTensorIfUnused(m_BiasTensor);
143}
144
145// Generates known implementations for linker.
146template class NeonConvolution2dBaseWorkload<armnn::DataType::Float16, armnn::DataType::Float32>;
147template class NeonConvolution2dBaseWorkload<armnn::DataType::QuantisedAsymm8>;
telsoa014fcda012018-03-09 14:13:49 +0000148
149} //namespace armnn
150