2 * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "ConvolutionLayer.h"
19 #include "../Tensor.h"
20 #include "ir/Padding.h"
21 #include <cker/operation/Conv.h>
31 ConvolutionLayer::ConvolutionLayer()
32 : _input(nullptr), _kernel(nullptr), _bias(nullptr), _output(nullptr),
33 _paddingType(ir::PaddingType::EXPLICIT), _paddingLeft(0), _paddingTop(0), _paddingRight(0),
34 _paddingBottom(0), _strideWidth(0), _strideHeight(0), _dilationWidthFactor(1),
35 _dilationHeightFactor(1), _activation(ir::Activation::NONE),
36 _conv_kernel(new nnfw::cker::Conv()), _prepare(false)
41 ConvolutionLayer::~ConvolutionLayer() = default;
43 void ConvolutionLayer::convFloat32()
45 float output_activation_min = 0, output_activation_max = 0;
46 CalculateActivationRange(_activation, &output_activation_min, &output_activation_max);
48 nnfw::cker::ConvParams op_params;
49 op_params.padding_type = getPaddingType(_paddingType);
50 op_params.padding_values.width = _paddingLeft;
51 op_params.padding_values.height = _paddingTop;
52 op_params.stride_width = _strideWidth;
53 op_params.stride_height = _strideHeight;
54 op_params.dilation_width_factor = _dilationWidthFactor;
55 op_params.dilation_height_factor = _dilationHeightFactor;
56 op_params.float_activation_min = output_activation_min;
57 op_params.float_activation_max = output_activation_max;
59 nnfw::cker::Conv &kernel = *_conv_kernel;
60 kernel(op_params, getTensorShape(_input), reinterpret_cast<const float *>(_input->buffer()),
61 getTensorShape(_kernel), reinterpret_cast<const float *>(_kernel->buffer()),
62 getTensorShape(_bias), reinterpret_cast<const float *>(_bias->buffer()),
63 getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()));
66 void ConvolutionLayer::convQuant8()
68 int32_t output_activation_min = 0;
69 int32_t output_activation_max = 0;
70 CalculateActivationRangeUint8(_activation, _output, &output_activation_min,
71 &output_activation_max);
73 double real_multiplier = 0.0;
74 int32_t output_multiplier = 0;
75 int32_t output_shift = 0;
76 GetQuantizedConvolutionMultiplier(_input, _kernel, _bias, _output, &real_multiplier);
77 QuantizeMultiplier(real_multiplier, &output_multiplier, &output_shift);
79 nnfw::cker::ConvParams op_params;
80 op_params.stride_width = _strideWidth;
81 op_params.stride_height = _strideHeight;
82 op_params.dilation_width_factor = _dilationWidthFactor;
83 op_params.dilation_height_factor = _dilationHeightFactor;
84 op_params.padding_type = getPaddingType(_paddingType);
85 op_params.padding_values.width = _paddingLeft;
86 op_params.padding_values.height = _paddingTop;
87 op_params.input_offset = -_input->data_offset();
88 op_params.weights_offset = -_kernel->data_offset();
89 op_params.output_offset = _output->data_offset();
90 op_params.output_multiplier = output_multiplier;
91 op_params.output_shift = output_shift;
92 op_params.quantized_activation_min = output_activation_min;
93 op_params.quantized_activation_max = output_activation_max;
94 op_params.is_replaced_weights = true;
96 nnfw::cker::Conv &kernel = *_conv_kernel;
97 kernel(op_params, getTensorShape(_input), reinterpret_cast<const uint8_t *>(_input->buffer()),
98 getTensorShape(_kernel), reinterpret_cast<const uint8_t *>(_kernel->buffer()),
99 getTensorShape(_bias), reinterpret_cast<const int32_t *>(_bias->buffer()),
100 getTensorShape(_output), reinterpret_cast<uint8_t *>(_output->buffer()));
103 void ConvolutionLayer::configure(const IPortableTensor *input, const IPortableTensor *kernel,
104 const IPortableTensor *bias, const ir::PaddingType paddingType,
105 const uint32_t paddingLeft, const uint32_t paddingRight,
106 const uint32_t paddingTop, const uint32_t paddingBottom,
107 const uint32_t strideWidth, const uint32_t strideHeight,
108 const uint32_t dilationWidthFactor,
109 const uint32_t dilationHeightFactor,
110 const ir::Activation activation, IPortableTensor *output)
115 _paddingType = paddingType;
116 _paddingLeft = paddingLeft;
117 _paddingRight = paddingRight;
118 _paddingTop = paddingTop;
119 _paddingBottom = paddingBottom;
120 _strideWidth = strideWidth;
121 _strideHeight = strideHeight;
122 _dilationWidthFactor = dilationWidthFactor;
123 _dilationHeightFactor = dilationHeightFactor;
124 _activation = activation;
128 void ConvolutionLayer::run()
132 if (_input->is_dynamic() || _kernel->is_dynamic())
134 const auto ifm_shape = _input->getShape().asFeature(_input->layout());
135 const auto ofm_shape = _output->getShape().asFeature(_input->layout());
136 // Kernel format is [depth_out, kernel_height, kernel_width, depth_in].
137 const auto ker_shape = _kernel->getShape();
138 const auto ker_height = ker_shape.dim(1);
139 const auto ker_width = ker_shape.dim(2);
142 stride.vertical = _strideWidth;
143 stride.horizontal = _strideWidth;
145 ir::Padding param_padding;
146 param_padding.type = _paddingType;
147 param_padding.param.left = _paddingLeft;
148 param_padding.param.right = _paddingRight;
149 param_padding.param.top = _paddingTop;
150 param_padding.param.bottom = _paddingBottom;
153 ir::calculatePadding(param_padding, ifm_shape, ofm_shape, stride, ker_width, ker_height,
154 _dilationWidthFactor, _dilationHeightFactor);
156 _paddingLeft = padding.left;
157 _paddingRight = padding.right;
158 _paddingTop = padding.top;
159 _paddingBottom = padding.bottom;
161 if (_input->data_type() == OperandType::FLOAT32)
165 else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
171 throw std::runtime_error{"Conv: unsupported data type"};
175 void ConvolutionLayer::prepare()
180 nnfw::cker::Conv &kernel = *_conv_kernel;
181 if (_input->data_type() == OperandType::FLOAT32 && _kernel->is_constant())
183 bool is_transposed = false;
184 kernel.prepare(getTensorShape(_kernel), reinterpret_cast<const float *>(_kernel->buffer()),
185 getPaddingType(_paddingType), is_transposed, _dilationWidthFactor,
186 _dilationHeightFactor);
188 // Decrease reference of _kernel(weights) only when _kernel is constant
191 auto kernel_tensor = dynamic_cast<const Tensor *>(_kernel);
193 // TODO Remove const_cast
194 const_cast<Tensor *>(kernel_tensor)->decrease_ref();
197 else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM && _kernel->is_constant() &&
198 !_input->is_dynamic() && !_output->is_dynamic())
200 kernel.prepareQuant(getTensorShape(_input), getTensorShape(_kernel), getTensorShape(_output),
201 _strideWidth, _strideHeight);
206 #undef ANDROID_NN_CONV_PARAMETERS
210 } // namespace backend