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), _activation(ir::Activation::NONE),
35 _conv_kernel(new nnfw::cker::Conv()), _prepare(false)
40 ConvolutionLayer::~ConvolutionLayer() = default;
42 void ConvolutionLayer::convFloat32()
44 float output_activation_min = 0, output_activation_max = 0;
45 CalculateActivationRange(_activation, &output_activation_min, &output_activation_max);
47 nnfw::cker::ConvParams op_params;
48 op_params.padding_type = getPaddingType(_paddingType);
49 op_params.padding_values.width = _paddingLeft;
50 op_params.padding_values.height = _paddingTop;
51 op_params.stride_width = _strideWidth;
52 op_params.stride_height = _strideHeight;
53 op_params.dilation_width_factor = 1;
54 op_params.dilation_height_factor = 1;
55 op_params.float_activation_min = output_activation_min;
56 op_params.float_activation_max = output_activation_max;
58 nnfw::cker::Conv &kernel = *_conv_kernel;
59 kernel(op_params, getTensorShape(_input), reinterpret_cast<const float *>(_input->buffer()),
60 getTensorShape(_kernel), reinterpret_cast<const float *>(_kernel->buffer()),
61 getTensorShape(_bias), reinterpret_cast<const float *>(_bias->buffer()),
62 getTensorShape(_output), reinterpret_cast<float *>(_output->buffer()));
65 void ConvolutionLayer::convQuant8()
67 int32_t output_activation_min = 0;
68 int32_t output_activation_max = 0;
69 CalculateActivationRangeUint8(_activation, _output, &output_activation_min,
70 &output_activation_max);
72 double real_multiplier = 0.0;
73 int32_t output_multiplier = 0;
74 int32_t output_shift = 0;
75 GetQuantizedConvolutionMultiplier(_input, _kernel, _bias, _output, &real_multiplier);
76 QuantizeMultiplier(real_multiplier, &output_multiplier, &output_shift);
78 nnfw::cker::ConvParams op_params;
79 op_params.stride_width = _strideWidth;
80 op_params.stride_height = _strideHeight;
81 op_params.dilation_width_factor = 1;
82 op_params.dilation_height_factor = 1;
83 op_params.padding_type = getPaddingType(_paddingType);
84 op_params.padding_values.width = _paddingLeft;
85 op_params.padding_values.height = _paddingTop;
86 op_params.input_offset = -_input->data_offset();
87 op_params.weights_offset = -_kernel->data_offset();
88 op_params.output_offset = _output->data_offset();
89 op_params.output_multiplier = output_multiplier;
90 op_params.output_shift = output_shift;
91 op_params.quantized_activation_min = output_activation_min;
92 op_params.quantized_activation_max = output_activation_max;
93 op_params.is_replaced_weights = true;
95 nnfw::cker::Conv &kernel = *_conv_kernel;
96 kernel(op_params, getTensorShape(_input), reinterpret_cast<const uint8_t *>(_input->buffer()),
97 getTensorShape(_kernel), reinterpret_cast<const uint8_t *>(_kernel->buffer()),
98 getTensorShape(_bias), reinterpret_cast<const int32_t *>(_bias->buffer()),
99 getTensorShape(_output), reinterpret_cast<uint8_t *>(_output->buffer()));
102 void ConvolutionLayer::configure(const IPortableTensor *input, const IPortableTensor *kernel,
103 const IPortableTensor *bias, const ir::PaddingType paddingType,
104 const uint32_t paddingLeft, const uint32_t paddingRight,
105 const uint32_t paddingTop, const uint32_t paddingBottom,
106 const uint32_t strideWidth, const uint32_t strideHeight,
107 const ir::Activation activation, IPortableTensor *output)
112 _paddingType = paddingType;
113 _paddingLeft = paddingLeft;
114 _paddingRight = paddingRight;
115 _paddingTop = paddingTop;
116 _paddingBottom = paddingBottom;
117 _strideWidth = strideWidth;
118 _strideHeight = strideHeight;
119 _activation = activation;
123 void ConvolutionLayer::run()
127 if (_input->is_dynamic() || _kernel->is_dynamic())
129 const auto ifm_shape = _input->getShape().asFeature(_input->layout());
130 const auto ofm_shape = _output->getShape().asFeature(_input->layout());
131 // Kernel format is [depth_out, kernel_height, kernel_width, depth_in].
132 const auto ker_shape = _kernel->getShape();
133 const auto ker_height = ker_shape.dim(1);
134 const auto ker_width = ker_shape.dim(2);
137 stride.vertical = _strideWidth;
138 stride.horizontal = _strideWidth;
140 ir::Padding param_padding;
141 param_padding.type = _paddingType;
142 param_padding.param.left = _paddingLeft;
143 param_padding.param.right = _paddingRight;
144 param_padding.param.top = _paddingTop;
145 param_padding.param.bottom = _paddingBottom;
148 ir::calculatePadding(param_padding, ifm_shape, ofm_shape, stride, ker_width, ker_height);
150 _paddingLeft = padding.left;
151 _paddingRight = padding.right;
152 _paddingTop = padding.top;
153 _paddingBottom = padding.bottom;
155 if (_input->data_type() == OperandType::FLOAT32)
159 else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
165 throw std::runtime_error{"Conv: unsupported data type"};
169 void ConvolutionLayer::prepare()
174 nnfw::cker::Conv &kernel = *_conv_kernel;
175 if (_input->data_type() == OperandType::FLOAT32 && _kernel->is_constant())
177 bool is_transposed = false;
178 kernel.prepare(getTensorShape(_kernel), reinterpret_cast<const float *>(_kernel->buffer()),
179 getPaddingType(_paddingType), is_transposed);
181 // Decrease reference of _kernel(weights) only when _kernel is constant
184 auto kernel_tensor = dynamic_cast<const Tensor *>(_kernel);
186 // TODO Remove const_cast
187 const_cast<Tensor *>(kernel_tensor)->decrease_ref();
190 else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM && _kernel->is_constant() &&
191 !_input->is_dynamic() && !_output->is_dynamic())
193 kernel.prepareQuant(getTensorShape(_input), getTensorShape(_kernel), getTensorShape(_output),
194 _strideWidth, _strideHeight);
199 #undef ANDROID_NN_CONV_PARAMETERS
203 } // namespace backend