ONE - On-device Neural Engine
Loading...
Searching...
No Matches
ConvolutionCommon.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17#include "ConvolutionCommon.h"
18
19#include "Utils.h"
20
21namespace luci_interpreter
22{
23
24namespace
25{
26
27bool isSupportedQuantized(const circle::Tensor *input, const circle::Tensor *weights)
28{
29 return Tensor::element_type(input) == DataType::U8 and Tensor::scales(weights).size() == 1;
30}
31
32bool isSupportedQuantizedPerChannel(const circle::Tensor *input, const circle::Tensor *weights)
33{
34 return (Tensor::element_type(input) == DataType::U8 or
35 Tensor::element_type(input) == DataType::S8) and
36 Tensor::scales(weights).size() > 1;
37}
38
39} // namespace
40
41int32_t computeConvPadding(const circle::Tensor *input, const circle::Tensor *filter,
42 circle::Padding padding_type, int32_t stride, int32_t dilation, int axis)
43{
44 const int32_t input_dim = Tensor::dim(input, axis);
45 const int32_t filter_dim = Tensor::dim(filter, axis);
46 const int32_t output_dim =
47 kernels::computeOutputSize(luci_padding(padding_type), input_dim, filter_dim, stride, dilation);
48
49 const auto padding = kernels::computePadding(stride, dilation, input_dim, filter_dim, output_dim);
50
51 return padding;
52}
53
55 const circle::Tensor *filter,
56 const circle::Tensor *output,
57 const circle::Conv2DOptions *options)
58{
60
61 if (isSupportedQuantized(input, filter))
62 {
63#ifndef DIS_QUANT
64 const auto input_scale = static_cast<double>(Tensor::scale(input));
65 const auto filter_scale = static_cast<double>(Tensor::scale(filter));
66 const auto output_scale = static_cast<double>(Tensor::scale(output));
67
68 const double real_multiplier = input_scale * filter_scale / output_scale;
69 int32_t output_multiplier{};
70 int output_shift{};
71 kernels::quantizeMultiplier(real_multiplier, &output_multiplier, &output_shift);
72
73 params.output_multiplier = output_multiplier;
74 params.output_shift = output_shift;
75
76 int32_t activation_min{};
77 int32_t activation_max{};
78 kernels::calculateActivationRangeQuantized(luci_actfunc(options->fused_activation_function()),
79 output, &activation_min, &activation_max);
80
81 // The kernel expects input and filter zero points to be negated.
82 params.input_offset = -Tensor::zero_point(input); // Note the '-'.
83 params.weights_offset = -Tensor::zero_point(filter); // Note the '-'.
84 params.output_offset = Tensor::zero_point(output);
85 params.quantized_activation_min = activation_min;
86 params.quantized_activation_max = activation_max;
87#endif // DIS_QUANT
88 }
89 else if (isSupportedQuantizedPerChannel(input, filter))
90 {
91#ifndef DIS_QUANT
92 int32_t activation_min{};
93 int32_t activation_max{};
94 kernels::calculateActivationRangeQuantized(luci_actfunc(options->fused_activation_function()),
95 output, &activation_min, &activation_max);
96
97 const std::vector<double> effective_output_scale = kernels::getQuantizedConvolutionMultiplers(
98 Tensor::scale(input), Tensor::scales(filter), Tensor::scale(output));
99
100 size_t n = effective_output_scale.size();
101 params.per_channel_output_shift.resize(n);
102 params.per_channel_output_multiplier.resize(n);
103 for (size_t i = 0; i < n; ++i)
104 {
105 kernels::quantizeMultiplier(effective_output_scale[i],
106 &params.per_channel_output_multiplier[i],
107 &params.per_channel_output_shift[i]);
108
109 // The kernel expects input and filter zero points to be negated.
110 params.input_offset = -Tensor::zero_point(input); // Note the '-'.
111 params.weights_offset = -Tensor::zero_point(filter); // Note the '-'.
112 params.output_offset = Tensor::zero_point(output);
113 params.quantized_activation_min = activation_min;
114 params.quantized_activation_max = activation_max;
115 }
116#endif // DIS_QUANT
117 }
118 else if (Tensor::element_type(input) == DataType::FLOAT32 and
119 Tensor::element_type(filter) == DataType::FLOAT32)
120 {
121#ifndef DIS_FLOAT
122 float activation_min{};
123 float activation_max{};
124 kernels::calculateActivationRange(luci_actfunc(options->fused_activation_function()),
125 &activation_min, &activation_max);
126
127 params.float_activation_min = activation_min;
128 params.float_activation_max = activation_max;
129#endif // DIS_FLOAT
130 }
131 else
132 {
133 assert(false && "Not supported type");
134 }
135
136 const auto padding = options->padding();
137 const auto stride_height = options->stride_h();
138 const auto stride_width = options->stride_w();
139 const auto dilation_height_factor = options->dilation_h_factor();
140 const auto dilation_width_factor = options->dilation_h_factor();
141
142 params.padding_values.height =
143 computeConvPadding(input, filter, padding, stride_height, dilation_height_factor, 1);
144 params.padding_values.width =
145 computeConvPadding(input, filter, padding, stride_width, dilation_width_factor, 2);
146 params.stride_height = stride_height;
147 params.stride_width = stride_width;
148 params.dilation_height_factor = dilation_height_factor;
149 params.dilation_width_factor = dilation_width_factor;
150
151 return params;
152}
153
154} // namespace luci_interpreter
int32_t computePadding(int32_t stride, int32_t dilation_rate, int32_t in_size, int32_t filter_size, int32_t out_size)
Definition Utils.h:41
void calculateActivationRange(Activation activation, T *activation_min, T *activation_max)
Definition Utils.cpp:52
void calculateActivationRangeQuantized(Activation activation, const Tensor *output, int32_t *activation_min, int32_t *activation_max)
Definition Utils.cpp:119
void quantizeMultiplier(double double_multiplier, int32_t *quantized_multiplier, int *shift)
Definition Utils.cpp:157
int32_t computeOutputSize(Padding padding, int32_t image_size, int32_t filter_size, int32_t stride, int32_t dilation_rate=1)
Definition Utils.h:59
std::vector< double > getQuantizedConvolutionMultiplers(float input_scale, const std::vector< float > &filter_scale, float output_scale)
Definition Utils.h:147
luci_interpreter_pal::ConvParams createConv2DParams(const circle::Tensor *input, const circle::Tensor *filter, const circle::Tensor *output, const circle::Conv2DOptions *options)
int32_t computeConvPadding(const circle::Tensor *input, const circle::Tensor *filter, circle::Padding padding_type, int32_t stride, int32_t dilation, int axis)
Padding luci_padding(const circle::Padding padding)
FusedActFunc luci_actfunc(const circle::ActivationFunctionType type)
This file contains utility macro.
const loco::Dimension & dim(uint32_t axis) const
Definition Tensor.h:44