1*c217d954SCole Faust /*
2*c217d954SCole Faust * Copyright (c) 2021 Arm Limited.
3*c217d954SCole Faust *
4*c217d954SCole Faust * SPDX-License-Identifier: MIT
5*c217d954SCole Faust *
6*c217d954SCole Faust * Permission is hereby granted, free of charge, to any person obtaining a copy
7*c217d954SCole Faust * of this software and associated documentation files (the "Software"), to
8*c217d954SCole Faust * deal in the Software without restriction, including without limitation the
9*c217d954SCole Faust * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10*c217d954SCole Faust * sell copies of the Software, and to permit persons to whom the Software is
11*c217d954SCole Faust * furnished to do so, subject to the following conditions:
12*c217d954SCole Faust *
13*c217d954SCole Faust * The above copyright notice and this permission notice shall be included in all
14*c217d954SCole Faust * copies or substantial portions of the Software.
15*c217d954SCole Faust *
16*c217d954SCole Faust * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*c217d954SCole Faust * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*c217d954SCole Faust * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19*c217d954SCole Faust * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20*c217d954SCole Faust * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21*c217d954SCole Faust * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22*c217d954SCole Faust * SOFTWARE.
23*c217d954SCole Faust */
24*c217d954SCole Faust #include "src/cpu/operators/CpuDirectConv2d.h"
25*c217d954SCole Faust
26*c217d954SCole Faust #include "arm_compute/core/PixelValue.h"
27*c217d954SCole Faust #include "arm_compute/core/Utils.h"
28*c217d954SCole Faust #include "arm_compute/core/Validate.h"
29*c217d954SCole Faust #include "arm_compute/runtime/NEON/NEScheduler.h"
30*c217d954SCole Faust #include "src/common/utils/Log.h"
31*c217d954SCole Faust
32*c217d954SCole Faust namespace arm_compute
33*c217d954SCole Faust {
34*c217d954SCole Faust namespace cpu
35*c217d954SCole Faust {
36*c217d954SCole Faust CpuDirectConv2d::~CpuDirectConv2d() = default;
37*c217d954SCole Faust
CpuDirectConv2d(std::shared_ptr<IMemoryManager> memory_manager)38*c217d954SCole Faust CpuDirectConv2d::CpuDirectConv2d(std::shared_ptr<IMemoryManager> memory_manager)
39*c217d954SCole Faust : _memory_group(std::move(memory_manager)), _output_stage_kernel(), _conv_kernel(), _input_border_handler(), _activationlayer_function(), _accumulator(), _has_bias(false),
40*c217d954SCole Faust _is_activationlayer_enabled(false), _dim_split(Window::DimZ), _is_padding_required()
41*c217d954SCole Faust {
42*c217d954SCole Faust }
43*c217d954SCole Faust
configure(ITensorInfo * src,ITensorInfo * weights,const ITensorInfo * bias,ITensorInfo * dst,const PadStrideInfo & conv_info,const ActivationLayerInfo & act_info)44*c217d954SCole Faust void CpuDirectConv2d::configure(ITensorInfo *src, ITensorInfo *weights, const ITensorInfo *bias, ITensorInfo *dst, const PadStrideInfo &conv_info, const ActivationLayerInfo &act_info)
45*c217d954SCole Faust {
46*c217d954SCole Faust ARM_COMPUTE_ERROR_ON(src->data_layout() == DataLayout::UNKNOWN);
47*c217d954SCole Faust ARM_COMPUTE_LOG_PARAMS(src, weights, bias, dst, conv_info, act_info);
48*c217d954SCole Faust
49*c217d954SCole Faust _output_stage_kernel = std::make_unique<kernels::CpuDirectConv2dOutputStageKernel>();
50*c217d954SCole Faust _conv_kernel = std::make_unique<kernels::CpuDirectConv2dKernel>();
51*c217d954SCole Faust _input_border_handler = std::make_unique<NEFillBorderKernel>();
52*c217d954SCole Faust
53*c217d954SCole Faust // Free accumulator
54*c217d954SCole Faust if(_accumulator.buffer() != nullptr)
55*c217d954SCole Faust {
56*c217d954SCole Faust _accumulator.allocator()->free();
57*c217d954SCole Faust }
58*c217d954SCole Faust
59*c217d954SCole Faust _dim_split = src->data_layout() == DataLayout::NCHW ? Window::DimZ : Window::DimY;
60*c217d954SCole Faust
61*c217d954SCole Faust // Check if bias should be added in the convolution result
62*c217d954SCole Faust _has_bias = (bias != nullptr);
63*c217d954SCole Faust
64*c217d954SCole Faust _conv_kernel->configure(src, weights, dst, conv_info);
65*c217d954SCole Faust if(_has_bias)
66*c217d954SCole Faust {
67*c217d954SCole Faust _output_stage_kernel->configure(dst, bias);
68*c217d954SCole Faust }
69*c217d954SCole Faust _is_padding_required = !_conv_kernel->border_size().empty();
70*c217d954SCole Faust
71*c217d954SCole Faust if(_is_padding_required)
72*c217d954SCole Faust {
73*c217d954SCole Faust // Add zero padding XY
74*c217d954SCole Faust _input_border_handler->configure(src, _conv_kernel->border_size(), BorderMode::CONSTANT, PixelValue(static_cast<float>(0.f)));
75*c217d954SCole Faust }
76*c217d954SCole Faust
77*c217d954SCole Faust //Configure Activation Layer
78*c217d954SCole Faust _is_activationlayer_enabled = act_info.enabled();
79*c217d954SCole Faust if(_is_activationlayer_enabled)
80*c217d954SCole Faust {
81*c217d954SCole Faust _activationlayer_function = std::make_unique<CpuActivation>();
82*c217d954SCole Faust _activationlayer_function->configure(dst, dst, act_info);
83*c217d954SCole Faust }
84*c217d954SCole Faust }
85*c217d954SCole Faust
validate(const ITensorInfo * src,const ITensorInfo * weights,const ITensorInfo * bias,const ITensorInfo * dst,const PadStrideInfo & conv_info,const ActivationLayerInfo & act_info)86*c217d954SCole Faust Status CpuDirectConv2d::validate(const ITensorInfo *src, const ITensorInfo *weights, const ITensorInfo *bias, const ITensorInfo *dst, const PadStrideInfo &conv_info,
87*c217d954SCole Faust const ActivationLayerInfo &act_info)
88*c217d954SCole Faust {
89*c217d954SCole Faust ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(src, weights, dst);
90*c217d954SCole Faust
91*c217d954SCole Faust // output might not be initialized since it can be an intermediate tensor of another layer
92*c217d954SCole Faust DataType data_type = src->data_type();
93*c217d954SCole Faust TensorInfo accumulator(dst->clone()->set_is_resizable(true).reset_padding().set_data_type(data_type));
94*c217d954SCole Faust
95*c217d954SCole Faust // Validate Convolution kernel
96*c217d954SCole Faust ARM_COMPUTE_RETURN_ON_ERROR(kernels::CpuDirectConv2dKernel::validate(src, weights, &accumulator, conv_info));
97*c217d954SCole Faust
98*c217d954SCole Faust if(bias != nullptr)
99*c217d954SCole Faust {
100*c217d954SCole Faust ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(weights, bias);
101*c217d954SCole Faust ARM_COMPUTE_RETURN_ERROR_ON_MSG(bias->dimension(0) != weights->dimension(3),
102*c217d954SCole Faust "Biases size and number of input feature maps should match");
103*c217d954SCole Faust ARM_COMPUTE_RETURN_ERROR_ON_MSG(bias->num_dimensions() > 1, "Biases should be one dimensional");
104*c217d954SCole Faust }
105*c217d954SCole Faust
106*c217d954SCole Faust // Validate bias kernel
107*c217d954SCole Faust ARM_COMPUTE_RETURN_ON_ERROR(kernels::CpuDirectConv2dOutputStageKernel::validate(&accumulator, bias, dst));
108*c217d954SCole Faust
109*c217d954SCole Faust if(act_info.enabled())
110*c217d954SCole Faust {
111*c217d954SCole Faust ARM_COMPUTE_RETURN_ON_ERROR(CpuActivation::validate(dst, nullptr, act_info));
112*c217d954SCole Faust }
113*c217d954SCole Faust
114*c217d954SCole Faust return Status{};
115*c217d954SCole Faust }
116*c217d954SCole Faust
run(ITensorPack & tensors)117*c217d954SCole Faust void CpuDirectConv2d::run(ITensorPack &tensors)
118*c217d954SCole Faust {
119*c217d954SCole Faust MemoryGroupResourceScope scope_mg(_memory_group);
120*c217d954SCole Faust
121*c217d954SCole Faust auto src = tensors.get_tensor(TensorType::ACL_SRC_0);
122*c217d954SCole Faust auto bias = tensors.get_const_tensor(TensorType::ACL_SRC_2);
123*c217d954SCole Faust auto dst = tensors.get_tensor(TensorType::ACL_DST);
124*c217d954SCole Faust
125*c217d954SCole Faust if(_is_padding_required)
126*c217d954SCole Faust {
127*c217d954SCole Faust ITensorPack pack;
128*c217d954SCole Faust pack.add_tensor(TensorType::ACL_SRC_DST, src);
129*c217d954SCole Faust NEScheduler::get().schedule_op(_input_border_handler.get(), Window::DimZ, _input_border_handler->window(), pack);
130*c217d954SCole Faust }
131*c217d954SCole Faust NEScheduler::get().schedule_op(_conv_kernel.get(), _dim_split, _conv_kernel->window(), tensors);
132*c217d954SCole Faust if(_has_bias)
133*c217d954SCole Faust {
134*c217d954SCole Faust ITensorPack pack;
135*c217d954SCole Faust pack.add_tensor(TensorType::ACL_SRC_0, dst);
136*c217d954SCole Faust pack.add_tensor(TensorType::ACL_SRC_1, bias);
137*c217d954SCole Faust pack.add_tensor(TensorType::ACL_DST, dst);
138*c217d954SCole Faust NEScheduler::get().schedule_op(_output_stage_kernel.get(), Window::DimY, _output_stage_kernel->window(), pack);
139*c217d954SCole Faust }
140*c217d954SCole Faust
141*c217d954SCole Faust if(_is_activationlayer_enabled)
142*c217d954SCole Faust {
143*c217d954SCole Faust ITensorPack pack;
144*c217d954SCole Faust pack.add_tensor(TensorType::ACL_SRC, dst);
145*c217d954SCole Faust pack.add_tensor(TensorType::ACL_DST, dst);
146*c217d954SCole Faust _activationlayer_function->run(pack);
147*c217d954SCole Faust }
148*c217d954SCole Faust }
149*c217d954SCole Faust } // namespace cpu
150*c217d954SCole Faust } // namespace arm_compute
151