xref: /aosp_15_r20/external/ComputeLibrary/src/core/CL/cl_kernels/common/mean_stddev_normalization.cl (revision c217d954acce2dbc11938adb493fc0abd69584f3)
1/*
2 * Copyright (c) 2019-2022 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.h"
25
26#if defined(VEC_SIZE) && defined(DATA_TYPE) && defined(EPSILON) && defined(WIDTH)
27/** This function normalizes the input 2D tensor across the first dimension with respect to mean and standard deviation of the same dimension.
28 *
29 * @attention Vector size should be given as a preprocessor argument using -DVEC_SIZE=size. e.g. -DVEC_SIZE=16
30 * @attention Data type should be passed using the -DDATA_TYPE compile flag, e.g. -DDATA_TYPE=float
31 * @attention Width of the input tensor should be passed using the -DWIDTH compile flag, e.g. -DWIDTH=16
32 * @attention Normalization epsilon parameter should be given as a preprocessor argument with -DEPSILON=value. e.g. -DEPSILON=0.001f
33 *
34 * @param[in]  input_ptr                            Pointer to the first source tensor. Supported data types: F16/F32
35 * @param[in]  input_stride_x                       Stride of the first source tensor in X dimension (in bytes)
36 * @param[in]  input_step_x                         input_stride_x * number of elements along X processed per workitem(in bytes)
37 * @param[in]  input_stride_y                       Stride of the first source tensor in Y dimension (in bytes)
38 * @param[in]  input_step_y                         input_stride_y * number of elements along Y processed per workitem(in bytes)
39 * @param[in]  input_offset_first_element_in_bytes  The offset of the first element in the first source tensor
40 * @param[out] output_ptr                           (Optional) Pointer to the destination tensor. Supported data types: same as @p input_ptr
41 * @param[in]  output_stride_x                      (Optional) Stride of the destination tensor in X dimension (in bytes)
42 * @param[in]  output_step_x                        (Optional) output_stride_x * number of elements along X processed per workitem(in bytes)
43 * @param[in]  output_stride_y                      (Optional) Stride of the destination tensor in Y dimension (in bytes)
44 * @param[in]  output_step_y                        (Optional) output_stride_y * number of elements along Y processed per workitem(in bytes)
45 * @param[in]  output_offset_first_element_in_bytes (Optional) The offset of the first element in the destination tensor
46 */
47__kernel void mean_stddev_normalization(
48    IMAGE_DECLARATION(input)
49#ifndef IN_PLACE
50    ,
51    IMAGE_DECLARATION(output)
52#endif /* IN_PLACE */
53)
54{
55    // Get pixels pointer
56    Image in = CONVERT_TO_IMAGE_STRUCT(input);
57#ifdef IN_PLACE
58    Image out = in;
59#else  /* IN_PLACE */
60    Image out = CONVERT_TO_IMAGE_STRUCT(output);
61#endif /* IN_PLACE */
62
63    VEC_DATA_TYPE(DATA_TYPE, VEC_SIZE)
64    sum = 0.f;
65#ifdef MEANSTDNORM_HALF
66    VEC_DATA_TYPE(float, VEC_SIZE)
67#else  /* MEANSTDNORM_HALF */
68    VEC_DATA_TYPE(DATA_TYPE, VEC_SIZE)
69#endif /* MEANSTDNORM_HALF */
70    sum_sq = 0.f;
71    // Calculate partial sum
72    int i = 0;
73    for(; i <= (WIDTH - VEC_SIZE); i += VEC_SIZE)
74    {
75        // Load data
76        VEC_DATA_TYPE(DATA_TYPE, VEC_SIZE)
77        data = VLOAD(VEC_SIZE)(0, (__global DATA_TYPE *)offset(&in, i, 0));
78
79        sum += data;
80#ifdef MEANSTDNORM_HALF
81        VEC_DATA_TYPE(float, VEC_SIZE)
82        dsq = CONVERT(data * data, VEC_DATA_TYPE(float, VEC_SIZE));
83        sum_sq += dsq;
84#else  /* MEANSTDNORM_HALF */
85        sum_sq += data * data;
86#endif /* MEANSTDNORM_HALF */
87    }
88    // Perform reduction
89    sum    = SUM_REDUCE(sum, VEC_SIZE);
90    sum_sq = SUM_REDUCE(sum_sq, VEC_SIZE);
91
92#if VEC_SIZE > 1
93#define sum sum.s0
94#define sum_sq sum_sq.s0
95#endif // VEC_SIZE > 1
96
97    // Left-overs loop
98    for(; i < WIDTH; ++i)
99    {
100        DATA_TYPE data = *((__global DATA_TYPE *)offset(&in, i, 0));
101
102        sum += data;
103        sum_sq += data * data;
104    }
105
106    DATA_TYPE mean       = sum / WIDTH;
107    DATA_TYPE var        = (sum_sq / WIDTH) - (mean * mean);
108    DATA_TYPE stddev_inv = 1.f / sqrt(var + EPSILON);
109
110    i = 0;
111    for(; i <= (WIDTH - VEC_SIZE); i += VEC_SIZE)
112    {
113        VEC_DATA_TYPE(DATA_TYPE, VEC_SIZE)
114        data = VLOAD(VEC_SIZE)(0, (__global DATA_TYPE *)offset(&in, i, 0));
115
116        VEC_DATA_TYPE(DATA_TYPE, VEC_SIZE)
117        res = (data - mean) * stddev_inv;
118        VSTORE(VEC_SIZE)
119        (res, 0, (__global DATA_TYPE *)offset(&out, i, 0));
120    }
121    for(; i < WIDTH; ++i)
122    {
123        DATA_TYPE data = *((__global DATA_TYPE *)offset(&in, i, 0));
124
125        *((__global DATA_TYPE *)offset(&out, i, 0)) = (data - mean) * stddev_inv;
126    }
127}
128#endif /* defined(VEC_SIZE) && defined(DATA_TYPE) && defined(EPSILON) && defined(WIDTH) */
129