2 * Copyright (c) 2019 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 "DepthwiseConvolutionLayer.h"
19 #include <cker/operation/DepthwiseConv.h>
30 void DepthwiseConvolutionLayer::convFloat32()
32 float output_activation_min = 0, output_activation_max = 0;
33 CalculateActivationRange(_activation, &output_activation_min, &output_activation_max);
35 nnfw::cker::DepthwiseConvParams op_params;
36 op_params.stride_width = _strideWidth;
37 op_params.stride_height = _strideHeight;
38 op_params.dilation_width_factor = _dilationWidth;
39 op_params.dilation_height_factor = _dilationHeight;
40 op_params.padding_values.width = _paddingLeft;
41 op_params.padding_values.height = _paddingTop;
42 op_params.depth_multiplier = _multiplier;
43 op_params.float_activation_min = output_activation_min;
44 op_params.float_activation_max = output_activation_max;
46 nnfw::cker::DepthwiseConv<float, float>(
47 op_params, getShape(_input), getBuffer<float>(_input), getShape(_kernel),
48 getBuffer<float>(_kernel), getShape(_bias), getBuffer<float>(_bias), getShape(_output),
49 getBuffer<float>(_output), _external_context->ruy_context());
52 void DepthwiseConvolutionLayer::convQ8uPerTensor()
54 int32_t output_activation_min = 0;
55 int32_t output_activation_max = 0;
56 CalculateActivationRangeQuantized(_activation, _output, &output_activation_min,
57 &output_activation_max);
59 double real_multiplier = 0.0;
60 int32_t output_multiplier = 0;
61 int32_t output_shift = 0;
62 GetQuantizedConvolutionMultiplier(_input, _kernel, _bias, _output, &real_multiplier);
63 QuantizeMultiplier(real_multiplier, &output_multiplier, &output_shift);
65 nnfw::cker::DepthwiseConvParams op_params;
66 op_params.stride_width = _strideWidth;
67 op_params.stride_height = _strideHeight;
68 op_params.dilation_width_factor = _dilationWidth;
69 op_params.dilation_height_factor = _dilationHeight;
70 op_params.padding_values.width = _paddingLeft;
71 op_params.padding_values.height = _paddingTop;
72 op_params.depth_multiplier = _multiplier;
73 op_params.input_offset = -_input->data_zero_point();
74 op_params.weights_offset = -_kernel->data_zero_point();
75 op_params.output_offset = _output->data_zero_point();
76 op_params.output_multiplier = output_multiplier;
77 op_params.output_shift = output_shift;
78 op_params.quantized_activation_min = output_activation_min;
79 op_params.quantized_activation_max = output_activation_max;
81 nnfw::cker::DepthwiseConv<uint8_t, int32_t>(
82 op_params, getShape(_input), getBuffer<uint8_t>(_input), getShape(_kernel),
83 getBuffer<uint8_t>(_kernel), getShape(_bias), getBuffer<int32_t>(_bias), getShape(_output),
84 getBuffer<uint8_t>(_output), _external_context->ruy_context());
87 void DepthwiseConvolutionLayer::convQ8uPerChannel()
89 nnfw::cker::DepthwiseConvParams op_params;
90 op_params.padding_values.width = _paddingLeft;
91 op_params.padding_values.height = _paddingTop;
92 op_params.stride_width = _strideWidth;
93 op_params.stride_height = _strideHeight;
94 op_params.dilation_width_factor = _dilationWidth;
95 op_params.dilation_height_factor = _dilationHeight;
96 op_params.depth_multiplier = _multiplier;
97 op_params.input_offset = -_input->data_zero_point();
98 op_params.output_offset = _output->data_zero_point();
99 int32_t output_activation_min = 0;
100 int32_t output_activation_max = 0;
101 CalculateActivationRangeQuantized(_activation, _output, &output_activation_min,
102 &output_activation_max);
103 op_params.quantized_activation_min = output_activation_min;
104 op_params.quantized_activation_max = output_activation_max;
105 // NOTE: The following fields of ConvParams are not used:
106 // padding_type, weights_offset, output_{multiplier,shift}, float_activation_{min,max}
108 nnfw::cker::reference_integer_ops::DepthwiseConvPerChannel(
109 op_params, _per_channel_output_multiplier.data(), _per_channel_output_shift.data(),
110 getShape(_input), getBuffer<uint8_t>(_input), getShape(_kernel), getBuffer<uint8_t>(_kernel),
111 _kernel->data_zero_points().data(), getShape(_bias), getBuffer<int32_t>(_bias),
112 getShape(_output), getBuffer<uint8_t>(_output));
115 void DepthwiseConvolutionLayer::convQ8i()
123 int32_t output_activation_min = 0;
124 int32_t output_activation_max = 0;
125 CalculateActivationRangeQuantized(_activation, _output, &output_activation_min,
126 &output_activation_max);
128 nnfw::cker::DepthwiseConvParams op_params;
129 op_params.padding_type = nnfw::cker::PaddingType::kSame;
130 op_params.padding_values.width = _paddingLeft;
131 op_params.padding_values.height = _paddingTop;
132 op_params.depth_multiplier = _multiplier;
133 op_params.stride_width = _strideWidth;
134 op_params.stride_height = _strideHeight;
135 op_params.dilation_width_factor = _dilationWidth;
136 op_params.dilation_height_factor = _dilationHeight;
137 op_params.input_offset = -_input->data_zero_point();
138 op_params.weights_offset = 0;
139 op_params.output_offset = _output->data_zero_point();
140 op_params.quantized_activation_min = output_activation_min;
141 op_params.quantized_activation_max = output_activation_max;
143 nnfw::cker::optimized_integer_ops::DepthwiseConvPerChannel(
144 op_params, _per_channel_output_multiplier.data(), _per_channel_output_shift.data(),
145 getShape(_input), getBuffer<int8_t>(_input), getShape(_kernel), getBuffer<int8_t>(_kernel),
146 getShape(_bias), getBuffer<int32_t>(_bias), getShape(_output), getBuffer<int8_t>(_output),
147 _external_context->ruy_context());
150 void DepthwiseConvolutionLayer::prepareQ8i()
152 GetQuantizedConvolutionMultipliersAndShifts(
153 _input->data_scale(), _output->data_scale(), _kernel->data_scales().data(),
154 _kernel->data_scales().size(), getShape(_kernel).Dims(3), _per_channel_output_multiplier,
155 _per_channel_output_shift);
158 void DepthwiseConvolutionLayer::prepareQ8uPerChannel()
160 GetQuantizedConvolutionMultipliersAndShifts(
161 _input->data_scale(), _output->data_scale(), _kernel->data_scales().data(),
162 _kernel->data_scales().size(), getShape(_kernel).Dims(3), _per_channel_output_multiplier,
163 _per_channel_output_shift);
166 void DepthwiseConvolutionLayer::configure(
167 const IPortableTensor *input, const IPortableTensor *kernel, const IPortableTensor *bias,
168 const uint32_t paddingLeft, const uint32_t paddingRight, const uint32_t paddingTop,
169 const uint32_t paddingBottom, const uint32_t strideWidth, const uint32_t strideHeight,
170 const uint32_t multiplier, const uint32_t dilationWidth, const uint32_t dilationHeight,
171 const ir::Activation activation, IPortableTensor *output,
172 const std::shared_ptr<ExternalContext> &external_context)
177 _paddingLeft = paddingLeft;
178 _paddingRight = paddingRight;
179 _paddingTop = paddingTop;
180 _paddingBottom = paddingBottom;
181 _strideWidth = strideWidth;
182 _strideHeight = strideHeight;
183 _multiplier = multiplier;
184 _dilationWidth = dilationWidth;
185 _dilationHeight = dilationHeight;
186 _activation = activation;
188 _external_context = external_context;
190 if (_input->data_type() == OperandType::QUANT_INT8_ASYMM)
192 if (_kernel->is_constant() && !_input->is_dynamic() && !_output->is_dynamic())
198 else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM && _kernel->is_constant() &&
199 !_input->is_dynamic() && !_output->is_dynamic())
201 const bool per_channel_quantized = _kernel->data_scales().size() > 1;
202 if (per_channel_quantized)
204 prepareQ8uPerChannel();
210 void DepthwiseConvolutionLayer::run()
212 if (_input->data_type() == OperandType::FLOAT32)
216 else if (_input->data_type() == OperandType::QUANT_UINT8_ASYMM)
218 const bool per_channel_quantized = _kernel->data_scales().size() > 1;
219 if (per_channel_quantized)
224 else if (_input->data_type() == OperandType::QUANT_INT8_ASYMM)
230 throw std::runtime_error{"DepthwiseConv: unsupported data type"};
236 } // namespace backend