arm_compute v18.02
[platform/upstream/armcl.git] / src / core / CL / cl_kernels / direct_convolution_1x1_3x3_5x5_quantized.cl
1 /*
2  * Copyright (c) 2017-2018 ARM Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 #include "helpers_asymm.h"
25
26 #undef CONVERT_SAT
27
28 #if defined(DATA_TYPE) && defined(STRIDE_X) && defined(WEIGHTS_DEPTH)
29
30 #if KERNEL_SIZE == 5
31
32 #if STRIDE_X == 1
33 #define CONVOLUTION1x5(acc, src_row_ptr, weights_row_ptr) CONVOLUTION1x5_STRIDE1(acc, src_row_ptr, weights_row_ptr)
34 #elif STRIDE_X == 2
35 #define CONVOLUTION1x5(acc, src_row_ptr, weights_row_ptr) CONVOLUTION1x5_STRIDE2(acc, src_row_ptr, weights_row_ptr)
36 #else /* STRIDE_X not equals 1 or 2 */
37 #error "STRIDE_X larger than 2 is not supported"
38 #endif /* STRIDE_X */
39
40 #define CONVOLUTION1x5_STRIDE1(acc, src_row_ptr, weights_row_ptr)                                                    \
41     ({                                                                                                               \
42         int4 weights_values0 = convert_int4(vload4(0, weights_row_ptr));                                             \
43         int  weights_value1  = convert_int(*(weights_row_ptr + 4));                                                  \
44         int8 src0            = convert_int8(vload8(0, src_row_ptr));                                                 \
45         int4 src1            = convert_int4(vload4(0, src_row_ptr + 8));                                             \
46         acc += (src0 + input_offset) * ((int8)weights_values0.s0 + weight_offset);                                   \
47         acc += ((int8)(src0.s1234, src0.s567, src1.s0) + input_offset) * ((int8)weights_values0.s1 + weight_offset); \
48         acc += ((int8)(src0.s234, src0.s567, src1.s01) + input_offset) * ((int8)weights_values0.s2 + weight_offset); \
49         acc += ((int8)(src0.s345, src0.s67, src1.s012) + input_offset) * ((int8)weights_values0.s3 + weight_offset); \
50         acc += ((int8)(src0.s45, src0.s67, src1.s0123) + input_offset) * ((int8)weights_value1 + weight_offset);     \
51     })
52
53 #define CONVOLUTION1x5_STRIDE2(acc, src_row_ptr, weights_row_ptr)                                                    \
54     ({                                                                                                               \
55         int4  weights_values0 = convert_int4(vload4(0, weights_row_ptr));                                            \
56         int   weights_value1  = convert_int(*(weights_row_ptr + 4));                                                 \
57         int16 src0            = convert_int16(vload16(0, src_row_ptr));                                              \
58         int4  src1            = convert_int4(vload4(0, src_row_ptr + 16));                                           \
59         acc += (src0.even + input_offset) * ((int8)weights_values0.s0 + weight_offset);                              \
60         acc += ((int8)(src0.s1357, src0.s9BDF) + input_offset) * ((int8)weights_values0.s1 + weight_offset);         \
61         acc += ((int8)(src0.s2468, src0.sACE, src1.s0) + input_offset) * ((int8)weights_values0.s2 + weight_offset); \
62         acc += ((int8)(src0.s3579, src0.sBDF, src1.s1) + input_offset) * ((int8)weights_values0.s3 + weight_offset); \
63         acc += ((int8)(src0.s468a, src0.sCE, src1.s02) + input_offset) * ((int8)weights_value1 + weight_offset);     \
64     })
65
66 #elif KERNEL_SIZE == 3
67
68 #if STRIDE_X == 1
69 #define CONVOLUTION1x3(acc, src_row_ptr, weights_row_ptr) CONVOLUTION1x3_STRIDE1(acc, src_row_ptr, weights_row_ptr)
70 #elif STRIDE_X == 2
71 #define CONVOLUTION1x3(acc, src_row_ptr, weights_row_ptr) CONVOLUTION1x3_STRIDE2(acc, src_row_ptr, weights_row_ptr)
72 #else /* STRIDE_X not equals 1 or 2 */
73 #error "STRIDE_X larger than 2 is not supported"
74 #endif /* STRIDE_X */
75
76 #define CONVOLUTION1x3_STRIDE1(acc, src_row_ptr, weights_row_ptr)                                                    \
77     ({                                                                                                               \
78         int3 weights_values0 = convert_int3(vload3(0, weights_row_ptr));                                             \
79         int8 src0            = convert_int8(vload8(0, src_row_ptr));                                                 \
80         int2 src1            = convert_int2(vload2(0, src_row_ptr + 8));                                             \
81         acc += (src0 + input_offset) * ((int8)weights_values0.s0 + weight_offset);                                   \
82         acc += ((int8)(src0.s1234, src0.s567, src1.s0) + input_offset) * ((int8)weights_values0.s1 + weight_offset); \
83         acc += ((int8)(src0.s234, src0.s567, src1.s01) + input_offset) * ((int8)weights_values0.s2 + weight_offset); \
84     })
85
86 #define CONVOLUTION1x3_STRIDE2(acc, src_row_ptr, weights_row_ptr)                                                 \
87     ({                                                                                                            \
88         int3  weights_values0 = convert_int3(vload3(0, weights_row_ptr));                                         \
89         int16 src0            = convert_int16(vload16(0, src_row_ptr));                                           \
90         int   src1            = convert_int(*(src_row_ptr + 16));                                                 \
91         acc += (src0.even + input_offset) * ((int8)weights_values0.s0 + weight_offset);                           \
92         acc += ((int8)(src0.s1357, src0.s9BDF) + input_offset) * ((int8)weights_values0.s1 + weight_offset);      \
93         acc += ((int8)(src0.s2468, src0.sACE, src1) + input_offset) * ((int8)weights_values0.s2 + weight_offset); \
94     })
95
96 #elif KERNEL_SIZE == 1
97
98 #if STRIDE_X == 3
99 #define INPUT_PIXEL extract_input_stride3
100 #elif STRIDE_X == 2
101 #define INPUT_PIXEL extract_input_stride2
102 #elif STRIDE_X == 1
103 #define INPUT_PIXEL extract_input_stride1
104
105 #else /* STRIDE_X not equals 1, 2 or 3 */
106 #error "Only support strides 1, 2 and 3"
107 #endif /* STRIDE_X */
108
109 /** Extracts a 1D horizontal vector from the input tensor with stride as 1.
110  *
111  * @param[in] input_pixel Pointer to the first pixel.
112  *
113  * @return extracted input pixels.
114  */
115 inline uchar8 extract_input_stride1(__global const uchar *input_pixel)
116 {
117     return vload8(0, input_pixel);
118 }
119
120 /** Extracts a 1D horizontal vector from the input tensor with stride as 2.
121  *
122  * @param[in] input_pixel Pointer to the first pixel.
123  *
124  * @return extracted input pixels.
125  */
126 inline uchar8 extract_input_stride2(__global const uchar *input_pixel)
127 {
128     uchar16 temp = vload16(0, input_pixel);
129     return temp.s02468ace;
130 }
131
132 /** Extracts a 1D horizontal vector from the input tensor with stride as 3 and 8-bit data size.
133  *
134  * @param[in] input_pixel Pointer to the first pixel.
135  *
136  * @return extracted input pixels.
137  */
138 inline uchar8 extract_input_stride3(__global const uchar *input_pixel)
139 {
140     uchar16 temp1 = vload16(0, input_pixel);
141     uchar16 temp2 = vload16(0, input_pixel + 12);
142     return (uchar8)(temp1.s0369, temp2.s0369);
143 }
144
145 #else /* KERNEL_SIZE not equals 1, 3 or 5 */
146 #error "Only kernel sizes 1, 3 and 5 are supported"
147 #endif /* KERNEL_SIZE */
148
149 /** This kernel performs a direct convolution to convolve the low three dimensions.
150  *
151  * @note The convolution stride x must be passed at compile time using -DSTRIDE_X e.g. -DSTRIDE_X=1
152  * @note The third dimensions of the weights tensors must be passed at compile time using -DWEIGHTS_DEPTH
153  * @note If biases are used then -DHAS_BIAS has to be passed at compile time
154  *
155  * @param[in]  src_ptr                               Pointer to the source tensor. Supported data types: QASYMM8
156  * @param[in]  src_stride_x                          Stride of the source tensor in X dimension (in bytes)
157  * @param[in]  src_step_x                            src_stride_x * number of elements along X processed per workitem(in bytes)
158  * @param[in]  src_stride_y                          Stride of the source tensor in Y dimension (in bytes)
159  * @param[in]  src_step_y                            src_stride_y * number of elements along Y processed per workitem(in bytes)
160  * @param[in]  src_stride_z                          Stride of the source tensor in Z dimension (in bytes)
161  * @param[in]  src_step_z                            src_stride_z * number of elements along Z processed per workitem(in bytes)
162  * @param[in]  src_offset_first_element_in_bytes     The offset of the first element in the source tensor
163  * @param[out] dst_ptr                               Pointer to the destination tensor. Supported data types: same as @p src_ptr
164  * @param[in]  dst_stride_x                          Stride of the destination tensor in X dimension (in bytes)
165  * @param[in]  dst_step_x                            dst_stride_x * number of elements along X processed per workitem(in bytes)
166  * @param[in]  dst_stride_y                          Stride of the destination tensor in Y dimension (in bytes)
167  * @param[in]  dst_step_y                            dst_stride_y * number of elements along Z processed per workitem(in bytes)
168  * @param[in]  dst_stride_z                          Stride of the destination tensor in Z dimension (in bytes)
169  * @param[in]  dst_step_z                            dst_stride_z * number of elements along Z processed per workitem(in bytes)
170  * @param[in]  dst_offset_first_element_in_bytes     The offset of the first element in the destination tensor
171  * @param[in]  weights_ptr                           Pointer to the weights tensor. Supported data types: same as @p weights_ptr
172  * @param[in]  weights_stride_x                      Stride of the weights tensor in X dimension (in bytes)
173  * @param[in]  weights_step_x                        weights_stride_x * number of elements along X processed per workitem(in bytes)
174  * @param[in]  weights_stride_y                      Stride of the weights tensor in Y dimension (in bytes)
175  * @param[in]  weights_step_y                        weights_stride_y * number of elements along y processed per workitem(in bytes)
176  * @param[in]  weights_stride_z                      Stride of the weights tensor in Z dimension (in bytes)
177  * @param[in]  weights_step_z                        weights_stride_z * number of elements along Z processed per workitem(in bytes)
178  * @param[in]  weights_offset_first_element_in_bytes The offset of the first element in the weights tensor
179  * @param[in]  biases_ptr                            Pointer to the biases tensor. Supported data types: S32
180  * @param[in]  biases_stride_x                       Stride of the biases tensor in X dimension (in bytes)
181  * @param[in]  biases_step_x                         biases_stride_x * number of elements along X processed per workitem(in bytes)
182  * @param[in]  biases_offset_first_element_in_bytes  The offset of the first element in the biases tensor
183  * @param[in]  weights_stride_w                      Stride of the weights tensor in the 4th dimension
184  * @param[in]  input_offset                          Input offset quantization parameter
185  * @param[in]  weight_offset                         Weights offset quantization parameter
186  * @param[in]  output_offset                         Output offset quantization parameter
187  * @param[in]  output_multiplier                     Output integer multiplier quantization parameter
188  * @param[in]  output_shift                          Output integer shift quantization parameter
189  */
190 __kernel void direct_convolution_1x1_3x3_5x5_quantized(
191     TENSOR3D_DECLARATION(src),
192     TENSOR3D_DECLARATION(dst),
193     TENSOR3D_DECLARATION(weights),
194 #ifdef HAS_BIAS
195     VECTOR_DECLARATION(biases),
196 #endif /* defined(HAS_BIAS) */
197     unsigned int weights_stride_w,
198     int          input_offset,
199     int          weight_offset,
200     int          output_offset,
201     int          output_multiplier,
202     int          output_shift)
203 {
204     Image    src     = CONVERT_TO_IMAGE_STRUCT(src);
205     Tensor3D weights = CONVERT_TO_TENSOR3D_STRUCT_NO_STEP(weights);
206     Tensor3D dst     = CONVERT_TO_TENSOR3D_STRUCT(dst);
207
208     int8 pixels0 = 0;
209
210     __global uchar *weights_addr = (__global uchar *)tensor3D_offset(&weights, 0, 0, 0);
211     __global uchar *src_addr     = (__global uchar *)offset(&src, 0, 0);
212
213     const int kernel_index = get_global_id(2);
214     weights_addr += kernel_index * weights_stride_w;
215
216     for(volatile int d = 0; d < WEIGHTS_DEPTH; ++d)
217     {
218 #if KERNEL_SIZE == 5
219         CONVOLUTION1x5(pixels0, (__global uchar *)src_addr, (__global uchar *)weights_addr);
220         CONVOLUTION1x5(pixels0, (__global uchar *)(src_addr + 1 * src_stride_y), (__global uchar *)(weights_addr + 1 * weights_stride_y));
221         CONVOLUTION1x5(pixels0, (__global uchar *)(src_addr + 2 * src_stride_y), (__global uchar *)(weights_addr + 2 * weights_stride_y));
222         CONVOLUTION1x5(pixels0, (__global uchar *)(src_addr + 3 * src_stride_y), (__global uchar *)(weights_addr + 3 * weights_stride_y));
223         CONVOLUTION1x5(pixels0, (__global uchar *)(src_addr + 4 * src_stride_y), (__global uchar *)(weights_addr + 4 * weights_stride_y));
224 #elif KERNEL_SIZE == 3
225         CONVOLUTION1x3(pixels0, (__global uchar *)(src_addr + 0 * src_stride_y), (__global uchar *)(weights_addr + 0 * weights_stride_y));
226         CONVOLUTION1x3(pixels0, (__global uchar *)(src_addr + 1 * src_stride_y), (__global uchar *)(weights_addr + 1 * weights_stride_y));
227         CONVOLUTION1x3(pixels0, (__global uchar *)(src_addr + 2 * src_stride_y), (__global uchar *)(weights_addr + 2 * weights_stride_y));
228 #elif KERNEL_SIZE == 1
229         int weight       = convert_int(*(__global uchar *)weights_addr);
230         int8 input_pixel = convert_int8(INPUT_PIXEL((__global uchar *)src_addr));
231         pixels0 += (input_pixel + input_offset) * ((int8)weight + weight_offset);
232 #endif /* (KERNEL_SIZE == 1) || (KERNEL_SIZE == 3) || (KERNEL_SIZE == 5) */
233
234         src_addr += src_stride_z;
235         weights_addr += weights_stride_z;
236     }
237
238 #ifdef HAS_BIAS
239     Vector        biases    = CONVERT_TO_VECTOR_STRUCT_NO_STEP(biases);
240     __global int *bias_addr = ((__global int *)(vector_offset(&biases, kernel_index)));
241     pixels0 += (int8)(*bias_addr);
242 #endif /* defined(HAS_BIAS) */
243
244     pixels0 = ASYMM_MULT_BY_QUANT_MULTIPLIER_LESS_THAN_ONE(pixels0, output_multiplier, output_shift, 8);
245     pixels0 = pixels0 + output_offset;
246
247     vstore8(convert_uchar8_sat(pixels0), 0, (__global uchar *)dst.ptr);
248 }
249 #endif // defined(DATA_TYPE) && defined(STRIDE_X) && defined(WEIGHTS_DEPTH)
250
251 /** This function computes the output stage of a depthwise convolution.
252  *
253  * @param[in] src_ptr                            Pointer to the source image. Supported data types: QASYMM8
254  * @param[in] src_stride_x                       Stride of the source image in X dimension (in bytes)
255  * @param[in] src_step_x                         src_stride_x * number of elements along X processed per workitem(in bytes)
256  * @param[in] src_stride_y                       Stride of the source image in Y dimension (in bytes)
257  * @param[in] src_step_y                         src_stride_y * number of elements along Y processed per workitem(in bytes)
258  * @param[in] src_offset_first_element_in_bytes  The offset of the first element in the source image
259  * @param[in] src_stride_z                       Stride of the source tensor in Z dimension (in bytes)
260  * @param[in] src_step_z                         src_stride_z * number of elements along Y processed per workitem(in bytes)
261  * @param[in] dst_ptr                            Pointer to the destination tensor. Supported data types: QASYMM8
262  * @param[in] dst_stride_x                       Stride of the destination tensor in X dimension (in bytes)
263  * @param[in] dst_step_x                         dst_stride_x * number of elements along X processed per workitem(in bytes)
264  * @param[in] dst_stride_y                       Stride of the destination tensor in Y dimension (in bytes)
265  * @param[in] dst_step_y                         dst_stride_y * number of elements along Y processed per workitem(in bytes)
266  * @param[in] dst_stride_z                       Stride of the destination tensor in Z dimension (in bytes)
267  * @param[in] dst_step_z                         dst_stride_z * number of elements along Y processed per workitem(in bytes)
268  * @param[in] dst_offset_first_element_in_bytes  The offset of the first element in the destination tensor
269  * @param[in] bias_ptr                           (Optional) Pointer to the biases vector. Supported data types: S32
270  * @param[in] bias_stride_x                      (Optional) Stride of the biases vector in X dimension (in bytes)
271  * @param[in] bias_step_x                        (Optional) bias_stride_x * number of elements along X processed per workitem(in bytes)
272  * @param[in] bias_offset_first_element_in_bytes (Optional) The offset of the first element in the biases vector
273  * @param[in] output_offset                      Quantized offset of zero point of the output tensor data range
274  * @param[in] output_multiplier                  Output scale multiplier
275  * @param[in] output_shift                       Output scale divisor exponent
276  */
277
278 __kernel void output_stage_quantized(
279     TENSOR3D_DECLARATION(src),
280     TENSOR3D_DECLARATION(dst),
281 #if defined(HAS_BIAS)
282     VECTOR_DECLARATION(bias),
283 #endif //defined(HAS_BIAS)
284     int output_offset,
285     int output_multiplier,
286     int output_shift)
287 {
288     Image src = CONVERT_TENSOR3D_TO_IMAGE_STRUCT(src);
289     Image dst = CONVERT_TENSOR3D_TO_IMAGE_STRUCT(dst);
290 #if defined(HAS_BIAS)
291     Vector bias = CONVERT_TO_VECTOR_STRUCT_NO_STEP(bias);
292 #endif //defined(HAS_BIAS)
293
294     // Load input
295     int16 vals = vload16(0, (__global int *)(src.ptr));
296
297 #if defined(HAS_BIAS)
298     // Load and add bias
299     int bias_value = *((__global int *)(vector_offset(&bias, get_global_id(2))));
300     vals += (int16)(bias_value);
301 #endif //defined(HAS_BIAS)
302
303     vals = ASYMM_MULT_BY_QUANT_MULTIPLIER_LESS_THAN_ONE(vals, output_multiplier, output_shift, 16);
304     vals = vals + output_offset;
305
306     // Store result in dst
307     vstore16(convert_uchar16_sat(vals), 0, (__global uchar *)dst.ptr);
308 }