blob: 89555a0cb6dd915c17c67b71aaa83070a7d81547 [file] [log] [blame]
Giorgio Arena93a690e2017-08-01 16:09:33 +01001/*
2 * Copyright (c) 2017 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
25#include "helpers.h"
26
Giorgio Arena9fe41442017-08-23 16:36:24 +010027#if defined(CONV_STRIDE_X)
28
Giorgio Arena93a690e2017-08-01 16:09:33 +010029#if CONV_STRIDE_X == 1
30#define convolution1x3 convolution1x3_stride_1
31#elif CONV_STRIDE_X == 2
32#define convolution1x3 convolution1x3_stride_2
33#elif CONV_STRIDE_X == 3
34#define convolution1x3 convolution1x3_stride_3
35#else /* CONV_STRIDE_X */
36#error "Stride not supported"
37#endif /* CONV_STRIDE_X */
38
39/** Compute a 1D horizontal convolution of size 3 and stride 1 for floating point type.
40 *
41 * @param[in] left_pixel Pointer to the left pixel.
42 * @param[in] left_coeff Weight of the left pixel
43 * @param[in] middle_coeff Weight of the middle pixel
44 * @param[in] right_coeff Weight of the right pixel
45 *
46 * @return a float2 containing 2 convoluted values.
47 */
48inline float2 convolution1x3_stride_1(__global const uchar *left_pixel,
49 const float left_coeff,
50 const float middle_coeff,
51 const float right_coeff)
52{
53 float4 temp = vload4(0, (__global float *)left_pixel);
54
55 float2 left = CONVERT(temp.s01, float2);
56 float2 middle = CONVERT(temp.s12, float2);
57 float2 right = CONVERT(temp.s23, float2);
58
59 return left * (float2)left_coeff + middle * (float2)middle_coeff + right * (float2)right_coeff;
60}
61
62/** Compute a 1D horizontal convolution of size 3 and stride 2 for floating point type.
63 *
64 * @param[in] left_pixel Pointer to the left pixel.
65 * @param[in] left_coeff Weight of the left pixel
66 * @param[in] middle_coeff Weight of the middle pixel
67 * @param[in] right_coeff Weight of the right pixel
68 *
69 * @return a float2 containing 2 convoluted values.
70 */
71inline float2 convolution1x3_stride_2(__global const uchar *left_pixel,
72 const float left_coeff,
73 const float middle_coeff,
74 const float right_coeff)
75{
76 float4 temp0 = vload4(0, (__global float *)left_pixel);
77 float temp1 = *((__global float *)(left_pixel + 4 * sizeof(float)));
78
79 float2 left = CONVERT(temp0.s02, float2);
80 float2 middle = CONVERT(temp0.s13, float2);
81 float2 right = CONVERT((float2)(temp0.s2, temp1), float2);
82
83 return left * (float2)left_coeff + middle * (float2)middle_coeff + right * (float2)right_coeff;
84}
85
86/** Compute a 1D horizontal convolution of size 3 and stride 3 for floating point type.
87 *
88 * @param[in] left_pixel Pointer to the left pixel.
89 * @param[in] left_coeff Weight of the left pixel
90 * @param[in] middle_coeff Weight of the middle pixel
91 * @param[in] right_coeff Weight of the right pixel
92 *
93 * @return a float2 containing 2 convoluted values.
94 */
95inline float2 convolution1x3_stride_3(__global const uchar *left_pixel,
96 const float left_coeff,
97 const float middle_coeff,
98 const float right_coeff)
99{
100 float4 temp0 = vload4(0, (__global float *)left_pixel);
101 float2 temp1 = vload2(0, (__global float *)(left_pixel + 4 * sizeof(float)));
102
103 float2 left = CONVERT(temp0.s03, float2);
104 float2 middle = CONVERT((float2)(temp0.s1, temp1.s0), float2);
105 float2 right = CONVERT((float2)(temp0.s2, temp1.s1), float2);
106
107 return left * (float2)left_coeff + middle * (float2)middle_coeff + right * (float2)right_coeff;
108}
109
110/** Apply a 3x3 convolution matrix to a single channel F32 input image and return the result.
111 *
112 * Convolution matrix layout:
113 *
114 * [ mat0, mat1, mat2 ]\n
115 * [ mat3, mat4, mat5 ]\n
116 * [ mat6, mat7, mat8 ]\n
117 *
118 * @param[in] src A pointer to source Image structure
119 * @param[in] mat0 Coefficient from the convolution matrix
120 * @param[in] mat1 Coefficient from the convolution matrix
121 * @param[in] mat2 Coefficient from the convolution matrix
122 * @param[in] mat3 Coefficient from the convolution matrix
123 * @param[in] mat4 Coefficient from the convolution matrix
124 * @param[in] mat5 Coefficient from the convolution matrix
125 * @param[in] mat6 Coefficient from the convolution matrix
126 * @param[in] mat0 Coefficient from the convolution matrix
127 * @param[in] mat7 Coefficient from the convolution matrix
128 * @param[in] mat8 Coefficient from the convolution matrix
129 *
130 * @return a float2 containing 2 convoluted values.
131 */
132inline float2 convolution3x3(
133 Image *src,
134 const float mat0, const float mat1, const float mat2,
135 const float mat3, const float mat4, const float mat5,
136 const float mat6, const float mat7, const float mat8)
137{
138 float2 pixels;
139
140 pixels = convolution1x3(offset(src, 0, 0), mat0, mat1, mat2);
141 pixels += convolution1x3(offset(src, 0, 1), mat3, mat4, mat5);
142 pixels += convolution1x3(offset(src, 0, 2), mat6, mat7, mat8);
143
144 return pixels;
145}
146
147/** This function computes the horizontal integral of the image.
Anthony Barbierf202e502017-11-23 18:02:04 +0000148 *
149 * @param[in] src_ptr Pointer to the source image. Supported data types: U8
150 * @param[in] src_stride_x Stride of the source image in X dimension (in bytes)
151 * @param[in] src_step_x src_stride_x * number of elements along X processed per workitem(in bytes)
152 * @param[in] src_stride_y Stride of the source image in Y dimension (in bytes)
153 * @param[in] src_step_y src_stride_y * number of elements along Y processed per workitem(in bytes)
154 * @param[in] src_offset_first_element_in_bytes The offset of the first element in the source image
155 * @param[in] src_stride_z Stride of the source tensor in Z dimension (in bytes)
156 * @param[in] src_step_z src_stride_z * number of elements along Y processed per workitem(in bytes)
157 * @param[in] dst_ptr Pointer to the destination tensor. Supported data types: F16/F32
158 * @param[in] dst_stride_x Stride of the destination tensor in X dimension (in bytes)
159 * @param[in] dst_step_x dst_stride_x * number of elements along X processed per workitem(in bytes)
160 * @param[in] dst_stride_y Stride of the destination tensor in Y dimension (in bytes)
161 * @param[in] dst_step_y dst_stride_y * number of elements along Y processed per workitem(in bytes)
162 * @param[in] dst_stride_z Stride of the destination tensor in Z dimension (in bytes)
163 * @param[in] dst_step_z dst_stride_z * number of elements along Y processed per workitem(in bytes)
164 * @param[in] dst_offset_first_element_in_bytes The offset of the first element in the destination tensor
165 * @param[in] weights_ptr Pointer to the weights tensor. Supported data types: F16/F32
166 * @param[in] weights_stride_x Stride of the weights tensor in X dimension (in bytes)
167 * @param[in] weights_step_x weights_stride_x * number of elements along X processed per workitem(in bytes)
168 * @param[in] weights_stride_y Stride of the weights tensor in Y dimension (in bytes)
169 * @param[in] weights_step_y weights_stride_y * number of elements along Y processed per workitem(in bytes)
170 * @param[in] weights_stride_z Stride of the weights tensor in Z dimension (in bytes)
171 * @param[in] weights_step_z weights_stride_z * number of elements along Y processed per workitem(in bytes)
172 * @param[in] weights_offset_first_element_in_bytes The offset of the first element in the biases vector
173 * @param[in] biases_ptr (Optional) Pointer to the biases vector. Supported data types: F16/F32
174 * @param[in] biases_stride_x (Optional) Stride of the biases vector in X dimension (in bytes)
175 * @param[in] biases_step_x (Optional) biases_stride_x * number of elements along X processed per workitem(in bytes)
176 * @param[in] biases_offset_first_element_in_bytes (Optional) The offset of the first element in the biases vector
177 */
Giorgio Arena93a690e2017-08-01 16:09:33 +0100178
Georgios Pinitas81a26ad2017-10-23 20:29:30 +0100179__kernel void depthwise_convolution_3x3(
180 TENSOR3D_DECLARATION(src),
181 TENSOR3D_DECLARATION(dst),
182 TENSOR3D_DECLARATION(weights)
183#if defined(HAS_BIAS)
184 ,
185 VECTOR_DECLARATION(biases)
186#endif //defined(HAS_BIAS)
187)
Giorgio Arena93a690e2017-08-01 16:09:33 +0100188{
189 Image src = CONVERT_TENSOR3D_TO_IMAGE_STRUCT(src);
190 Image dst = CONVERT_TENSOR3D_TO_IMAGE_STRUCT(dst);
191 Tensor3D weights = CONVERT_TO_TENSOR3D_STRUCT(weights);
Georgios Pinitas81a26ad2017-10-23 20:29:30 +0100192#if defined(HAS_BIAS)
193 Vector biases = CONVERT_TO_VECTOR_STRUCT_NO_STEP(biases);
194#endif //defined(HAS_BIAS)
Giorgio Arena93a690e2017-08-01 16:09:33 +0100195
196 uchar3 offset = (uchar3)(0, 1, 2) * (uchar3)weights_stride_y;
197 float3 weights_values0 = vload3(0, (__global float *)(weights.ptr + offset.s0));
198 float3 weights_values1 = vload3(0, (__global float *)(weights.ptr + offset.s1));
199 float3 weights_values2 = vload3(0, (__global float *)(weights.ptr + offset.s2));
200
201 float2 pixels = convolution3x3(&src, weights_values0.s0, weights_values0.s1, weights_values0.s2,
202 weights_values1.s0, weights_values1.s1, weights_values1.s2,
203 weights_values2.s0, weights_values2.s1, weights_values2.s2);
Georgios Pinitas81a26ad2017-10-23 20:29:30 +0100204#if defined(HAS_BIAS)
205 pixels += (float2)(*((__global float *)(biases.ptr + get_global_id(2) * biases_stride_x)));
206#endif //defined(HAS_BIAS)
Giorgio Arena93a690e2017-08-01 16:09:33 +0100207
208 vstore2(pixels, 0, (__global float *)dst.ptr);
Giorgio Arena9fe41442017-08-23 16:36:24 +0100209}
210
211#endif //defined(CONV_STRIDE_X)
212
213#if defined(SRC_WIDTH) && defined(DATA_TYPE)
214/** This kernel reshapes each of the tensor's low three dimensions to single rows.
215 *
216 * @note Datatype and source width should be given as a preprocessor argument using -DDATA_TYPE=type and -DSRC_WIDTH=width. e.g. -DSRC_WIDTH=128
217 *
Georgios Pinitas81a26ad2017-10-23 20:29:30 +0100218 * @param[in] src_ptr Pointer to the source tensor. Supported data types: F16/F32
219 * @param[in] src_stride_x Stride of the source tensor in X dimension (in bytes)
220 * @param[in] src_step_x src_stride_x * number of elements along X processed per workitem(in bytes)
221 * @param[in] src_stride_y Stride of the source tensor in Y dimension (in bytes)
222 * @param[in] src_step_y src_stride_y * number of elements along Y processed per workitem(in bytes)
223 * @param[in] src_stride_z Stride of the source tensor in Z dimension (in bytes)
224 * @param[in] src_step_z src_stride_z * number of elements along Y processed per workitem(in bytes)
225 * @param[in] src_offset_first_element_in_bytes The offset of the first element in the source tensor
226 * @param[out] dst_ptr Pointer to the destination tensor. Same as @p src_ptr
227 * @param[in] dst_stride_x Stride of the destination tensor in X dimension (in bytes)
228 * @param[in] dst_step_x dst_stride_x * number of elements along X processed per workitem(in bytes)
229 * @param[in] dst_stride_y Stride of the destination tensor in Y dimension (in bytes)
230 * @param[in] dst_step_y dst_stride_y * number of elements along Y processed per workitem(in bytes)
231 * @param[in] dst_offset_first_element_in_bytes The offset of the first element in the destination tensor
232 * @param[in] biases_ptr (Optional) Pointer to the biases vector. Supported data types: F16/F32
233 * @param[in] biases_stride_x (Optional) Stride of the biases vector in X dimension (in bytes)
234 * @param[in] biases_step_x (Optional) biases_stride_x * number of elements along X processed per workitem(in bytes)
235 * @param[in] biases_offset_first_element_in_bytes (Optional) The offset of the first element in the biases vector
Giorgio Arena9fe41442017-08-23 16:36:24 +0100236 */
Georgios Pinitas81a26ad2017-10-23 20:29:30 +0100237__kernel void depthwise_weights_reshape(
238 TENSOR3D_DECLARATION(src),
239 IMAGE_DECLARATION(dst)
240#ifdef HAS_BIAS
241 ,
242 VECTOR_DECLARATION(biases)
243#endif /* HAS_BIAS */
244)
Giorgio Arena9fe41442017-08-23 16:36:24 +0100245{
246 Tensor3D src = CONVERT_TO_TENSOR3D_STRUCT(src);
Georgios Pinitas81a26ad2017-10-23 20:29:30 +0100247#ifdef HAS_BIAS
248 Vector biases = CONVERT_TO_VECTOR_STRUCT_NO_STEP(biases);
249#endif /* HAS_BIAS */
Giorgio Arena9fe41442017-08-23 16:36:24 +0100250
251 __global DATA_TYPE *input_ptr = (__global DATA_TYPE *)src.ptr;
252 __global uchar *output_ptr = dst_ptr + dst_offset_first_element_in_bytes + get_global_id(1) * SRC_WIDTH * dst_stride_x + get_global_id(2) * dst_stride_y;
253
254 for(int i = 0; i < SRC_WIDTH; ++i, ++input_ptr)
255 {
256 *((__global DATA_TYPE *)(output_ptr + i * dst_stride_x)) = *input_ptr;
257 }
Georgios Pinitas81a26ad2017-10-23 20:29:30 +0100258
259#if defined(HAS_BIAS)
260 if(get_global_id(1) == 0)
261 {
262 *((__global DATA_TYPE *)(output_ptr + SRC_WIDTH * get_global_size(1) * dst_stride_x)) = *((__global float *)(biases.ptr + get_global_id(2) * biases_stride_x));
263 }
264#endif // defined(HAS_BIAS)
Giorgio Arena9fe41442017-08-23 16:36:24 +0100265}
266#endif //defined(SRC_WIDTH) && defined(DATA_TYPE)
267
Jaroslaw Rzepeckia1ed41f2017-10-13 11:13:58 +0100268#if defined(STRIDE_X) && defined(STRIDE_Y) && defined(PAD_LEFT) && defined(PAD_TOP) && defined(PAD_RIGHT) && defined(PAD_BOTTOM) && defined(KERNEL_WIDTH) && defined(KERNEL_HEIGHT) && defined(SRC_WIDTH) && defined(SRC_HEIGHT) && defined(DATA_TYPE)
Giorgio Arena9fe41442017-08-23 16:36:24 +0100269/** This kernel performs a reshaping of the input tensor to a tensor used to perform depthwise convolution using vector to matrix multiplication.
270 *
271 * @note The data type must be passed at compile time using -DDATA_TYPE: e.g. -DDATA_TYPE=float
Jaroslaw Rzepeckia1ed41f2017-10-13 11:13:58 +0100272 * @note The convolution information must be passed at compile time using -DSTRIDE_X, -DSTRIDE_Y, -DPAD_LEFT, -DPAD_TOP, -DPAD_RIGHT, -DPAD_BOTTOM, -DKERNEL_WIDHT, -DKERNEL_HEIGHT, -DSRC_WIDTH, -DSRC_HEIGHT
Giorgio Arena9fe41442017-08-23 16:36:24 +0100273 *
274 * @param[in] src_ptr Pointer to the source tensor. Supported data types: QS8/QS16/F16/F32
275 * @param[in] src_stride_x Stride of the source tensor in X dimension (in bytes)
276 * @param[in] src_step_x src_stride_x * number of elements along X processed per workitem(in bytes)
277 * @param[in] src_stride_y Stride of the source tensor in Y dimension (in bytes)
278 * @param[in] src_step_y src_stride_y * number of elements along Y processed per workitem(in bytes)
279 * @param[in] src_stride_z Stride of the source tensor in Z dimension (in bytes)
280 * @param[in] src_step_z src_stride_z * number of elements along Z processed per workitem(in bytes)
281 * @param[in] src_offset_first_element_in_bytes The offset of the first element in the source tensor
282 * @param[out] dst_ptr Pointer to the destination tensor. Supported data types: same as @p src_ptr
283 * @param[in] dst_stride_x Stride of the destination tensor in X dimension (in bytes)
284 * @param[in] dst_step_x dst_stride_x * number of elements along X processed per workitem(in bytes)
285 * @param[in] dst_stride_y Stride of the destination tensor in Y dimension (in bytes)
286 * @param[in] dst_step_y dst_stride_y * number of elements along Y processed per workitem(in bytes)
287 * @param[in] dst_stride_z Stride of the destination tensor in Z dimension (in bytes)
288 * @param[in] dst_step_z dst_stride_z * number of elements along Z processed per workitem(in bytes)
289 * @param[in] dst_offset_first_element_in_bytes The offset of the first element in the destination tensor
290 */
291
292__kernel void depthwise_im2col(TENSOR3D_DECLARATION(src), TENSOR3D_DECLARATION(dst))
293{
294 Tensor3D dst = CONVERT_TO_TENSOR3D_STRUCT(dst);
295
296 const int src_pixel_linear = get_global_id(1) * STRIDE_X;
Jaroslaw Rzepeckia1ed41f2017-10-13 11:13:58 +0100297 const int full_length = SRC_WIDTH + PAD_LEFT + PAD_RIGHT;
Giorgio Arena9fe41442017-08-23 16:36:24 +0100298 const int max_initial_x = STRIDE_X * (((full_length - KERNEL_WIDTH) / STRIDE_X) + 1);
299
Jaroslaw Rzepeckia1ed41f2017-10-13 11:13:58 +0100300 const int src_x = -PAD_LEFT + src_pixel_linear % max_initial_x;
301 const int src_y = -PAD_TOP + src_pixel_linear / max_initial_x * STRIDE_Y;
Giorgio Arena9fe41442017-08-23 16:36:24 +0100302 const int src_z = get_global_id(2);
303
304 __global uchar *input_ptr = src_ptr + src_offset_first_element_in_bytes + src_z * src_stride_z;
305 __global DATA_TYPE *output_ptr = ((__global DATA_TYPE *)(dst.ptr));
306
307 for(int y = src_y; y < src_y + KERNEL_HEIGHT; ++y)
308 {
309 for(int x = src_x; x < src_x + KERNEL_WIDTH; ++x, ++output_ptr)
310 {
311 if(x < 0 || x >= SRC_WIDTH || y < 0 || y >= SRC_HEIGHT)
312 {
313 *output_ptr = 0;
314 }
315 else
316 {
317 *output_ptr = *((__global DATA_TYPE *)(input_ptr + x * src_stride_x + y * src_stride_y));
318 }
319 }
320 }
Georgios Pinitas81a26ad2017-10-23 20:29:30 +0100321#if defined(HAS_BIAS)
322 *output_ptr = (DATA_TYPE)(1);
323#endif // defined(HAS_BIAS)
Giorgio Arena9fe41442017-08-23 16:36:24 +0100324}
325
Jaroslaw Rzepeckia1ed41f2017-10-13 11:13:58 +0100326#endif //defined(STRIDE_X) && defined(STRIDE_Y) && defined(PAD_LEFT) && defined(PAD_TOP) && defined(PAD_RIGHT) && defined(PAD_BOTTOM) && defined(KERNEL_WIDTH) && defined(KERNEL_HEIGHT) && defined(SRC_WIDTH) && defined(DATA_TYPE)
Giorgio Arena9fe41442017-08-23 16:36:24 +0100327
328#if defined(CONV_WIDTH) && defined(CONV_HEIGHT) && defined(DATA_TYPE)
329
330/** This kernel performs a reshaping of the output of the depthwise generic convolution.
331 *
332 * @note The data type must be passed at compile time using -DDATA_TYPE: e.g. -DDATA_TYPE=float
333 * @note The convolution information must be passed at compile time using -DCONV_WIDTH, -DCONV_HEIGHT, e.g -DCONV_WIDTH=32, -DCONV_HEIGHT=42
334 *
335 * @param[in] src_ptr Pointer to the source tensor. Supported data types: QS8/QS16/F16/F32
336 * @param[in] src_stride_x Stride of the source tensor in X dimension (in bytes)
337 * @param[in] src_step_x src_stride_x * number of elements along X processed per workitem(in bytes)
338 * @param[in] src_offset_first_element_in_bytes The offset of the first element in the source tensor
339 * @param[out] dst_ptr Pointer to the destination tensor. Supported data types: same as @p src_ptr
340 * @param[in] dst_stride_x Stride of the destination tensor in X dimension (in bytes)
341 * @param[in] dst_step_x dst_stride_x * number of elements along X processed per workitem(in bytes)
342 * @param[in] dst_stride_y Stride of the destination tensor in Y dimension (in bytes)
343 * @param[in] dst_step_y dst_stride_y * number of elements along Y processed per workitem(in bytes)
344 * @param[in] dst_stride_z Stride of the destination tensor in Z dimension (in bytes)
345 * @param[in] dst_step_z dst_stride_z * number of elements along Z processed per workitem(in bytes)
346 * @param[in] dst_offset_first_element_in_bytes The offset of the first element in the destination tensor
347 */
348__kernel void depthwise_vector_to_tensor(
349 VECTOR_DECLARATION(src),
350 TENSOR3D_DECLARATION(dst))
351{
352 Vector src = CONVERT_TO_VECTOR_STRUCT(src);
353
354 const int patch_size = CONV_WIDTH * CONV_HEIGHT;
355 const int id0 = get_global_id(0);
356 const int z = id0 / patch_size;
357 const int index2D = id0 - z * patch_size;
358
359 __global uchar *out_ptr = dst_ptr + dst_offset_first_element_in_bytes + index2D % CONV_WIDTH * dst_stride_x + index2D / CONV_WIDTH * dst_stride_y + z * dst_stride_z;
360 *((__global DATA_TYPE *)out_ptr) = *((__global DATA_TYPE *)src.ptr);
361}
362
363#endif //defined(CONV_WIDTH) && defined(CONV_HEIGHT) && defined(DATA_TYPE)