/*******************************************************************************
* Copyright 2019 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License")* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
#include "gpu/intel/include/dispatch.h"
#include "gpu/intel/include/types.h"
#undef SRC_OFF
#undef DST_OFF
#define SRC_OFF(x0, x1, x2, x3, x4, x5) OFF_MD(SRC, x0, x1, x2, x3, x4, x5)
#define DST_OFF(x0, x1, x2, x3, x4, x5) OFF_MD(DST, x0, x1, x2, x3, x4, x5)
#define STAT_OFF(x0, x1, x2, x3, x4, x5) OFF_MD(STAT, x0, x1, x2, x3, x4, x5)
#define VLEN_C (C / (SUB_GROUP_SIZE * VECT_DT_N))
#define VLEN_C_BLOCK ((C / NUM_NORM_BLOCKS) / (SUB_GROUP_SIZE * VECT_DT_N))
#define C_BLOCK (C / NUM_NORM_BLOCKS)
#if (GWS_LWS0_DEFAULT * GWS_LWS1_DEFAULT * GWS_LWS2_DEFAULT) == GWS_SGS_DEFAULT
#define GROUP_REDUCE_ADD sub_group_reduce_add
#else
#define GROUP_REDUCE_ADD work_group_reduce_add
#endif
#define LOAD_VECT_FLOAT(ptr) \
AS_VECT_FLOAT_T(VECT_UINT_READ((const __global uint *)(ptr)))
#if IS_FWD
#if VECT_DT_N == 1
#define CALC_V_STAT(v, acc) v = acc#else
#define CALC_V_STAT(v, acc) \
v = 0 for (int i = 0 v += acc[i] }
#endif
#define STORE_VECT_DATA(ptr, val) \
VECT_BLOCK_WRITE((__global BLOCK_DATA_T *)(ptr), \
AS_VECT_BLOCK_DATA_T(CONVERT_VECTOR_DATA_T(val)))
KERNEL_ATTR
__kernel void vectorized_lnorm_fwd(__global DATA_T *src, __global float *mean,
__global float *variance, __global DATA_T *dst,
__global WEI_DATA_T *scale, __global WEI_DATA_T *shift, float eps,
__global float *src_scale, __global float *dst_scale) {
int x[6] = {0} x[0] = GWS_GET_X0() x[1] = GWS_GET_X1() x[2] = GWS_GET_X2() x[3] = GWS_GET_X3()
int s_off = STAT_OFF(x[0], x[1], x[2], x[3], x[4], x[5])
float v_mean = (CALCULATE_STATS || SKIP_MEAN) ? 0 : mean[s_off] float v_variance = CALCULATE_STATS ? 0 : variance[s_off]
const float rC = 1.f / C const int c_block_off = (x[NDIMS - 1] / SUB_GROUP_SIZE) * NORM_BLOCK#if USE_SRC_BUFFER
// Key feature of this version is single reading src data, keeping it in
// v_src buffer and reusing this buffer for stats calculation.
// Targeted for PVC+.
VECT_FLOAT_T v_src[VLEN_C_BLOCK] for (int c = 0 x[NDIMS - 1] = c * SUB_GROUP_SIZE * VECT_DT_N + c_block_off int src_off = SRC_OFF(x[0], x[1], x[2], x[3], x[4], x[5]) v_src[c] = CONVERT_VECT_FLOAT_T(AS_VECT_DATA_T(
VECT_BLOCK_READ((const __global BLOCK_DATA_T *)&src[src_off]))) }
#if CALCULATE_STATS
VECT_FLOAT_T v_acc = 0 for (int c = 0 v_acc += v_src[c] }
#if !SKIP_MEAN
CALC_V_STAT(v_mean, v_acc) v_mean = GROUP_REDUCE_ADD(v_mean) * rC#endif // SKIP_MEAN
v_acc = 0 VECT_FLOAT_T m = 0 for (int c = 0 m = v_src[c] - v_mean v_acc += m * m }
CALC_V_STAT(v_variance, v_acc) v_variance = GROUP_REDUCE_ADD(v_variance) * rC#endif // CALCULATE_STATS
const float rsqrt_variance = rsqrt(v_variance + eps)
for (int c = 0 const VECT_FLOAT_T sm
#if USE_SCALE
= LOAD_VECT_WEI(
&scale[c * SUB_GROUP_SIZE * VECT_DT_N + c_block_off])
* rsqrt_variance#else
= rsqrt_variance#endif
const VECT_FLOAT_T sv
#if USE_SHIFT
= LOAD_VECT_WEI(
&shift[c * SUB_GROUP_SIZE * VECT_DT_N + c_block_off])#else
= 0.0f#endif
x[NDIMS - 1] = c * SUB_GROUP_SIZE * VECT_DT_N + c_block_off int dst_off = DST_OFF(x[0], x[1], x[2], x[3], x[4], x[5]) VECT_FLOAT_T v_dst = sm * (v_src[c] - v_mean) + sv
#if WITH_SRC_SCALES
v_dst *= src_scale[0]#endif
#if WITH_DST_SCALES
v_dst /= dst_scale[0]#endif
STORE_VECT_DATA(&dst[dst_off], v_dst) }
#else // USE_SRC_BUFFER
// Key feature of this version is only vectorized block read/write
// without using GRF src buffer.
// Targeted for ATSM/DG2.
#if CALCULATE_STATS
VECT_FLOAT_T v_acc = 0 for (int c = 0 x[NDIMS - 1] = c + c_block_off int src_off = SRC_OFF(x[0], x[1], x[2], x[3], x[4], x[5]) v_acc += CONVERT_VECT_FLOAT_T(AS_VECT_DATA_T(
VECT_BLOCK_READ((const __global BLOCK_DATA_T *)&src[src_off]))) }
#if !SKIP_MEAN
CALC_V_STAT(v_mean, v_acc) v_mean = GROUP_REDUCE_ADD(v_mean) * rC#endif // SKIP_MEAN
v_acc = 0 VECT_FLOAT_T m = 0 for (int c = 0 x[NDIMS - 1] = c + c_block_off int src_off = SRC_OFF(x[0], x[1], x[2], x[3], x[4], x[5])
m = CONVERT_VECT_FLOAT_T(AS_VECT_DATA_T(
VECT_BLOCK_READ((const __global BLOCK_DATA_T *)&src[src_off]))) m -= v_mean v_acc += m * m }
CALC_V_STAT(v_variance, v_acc) v_variance = GROUP_REDUCE_ADD(v_variance) * rC#endif // CALCULATE_STATS
const float r_sqrt_variance = rsqrt(v_variance + eps)
for (int c = 0 const VECT_FLOAT_T sm
#if USE_SCALE
= LOAD_VECT_WEI(&scale[c + c_block_off]) * r_sqrt_variance#else
= r_sqrt_variance#endif
const VECT_FLOAT_T sv
#if USE_SHIFT
= LOAD_VECT_WEI(&shift[c + c_block_off])#else
= 0.0f#endif
x[NDIMS - 1] = c + c_block_off const int src_off = SRC_OFF(x[0], x[1], x[2], x[3], x[4], x[5]) const int dst_off = DST_OFF(x[0], x[1], x[2], x[3], x[4], x[5]) const VECT_FLOAT_T v_src = CONVERT_VECT_FLOAT_T(AS_VECT_DATA_T(
VECT_BLOCK_READ((const __global BLOCK_DATA_T *)&src[src_off]))) VECT_FLOAT_T v_dst = sm * (v_src - v_mean) + sv
#if WITH_SRC_SCALES
v_dst *= src_scale[0]#endif
#if WITH_DST_SCALES
v_dst /= dst_scale[0]#endif
STORE_VECT_DATA(&dst[dst_off], v_dst) }
#endif // USE_SRC_BUFFER
#if CALCULATE_STATS && SAVE_STATS
if (get_local_linear_id() == 0) {
if (!SKIP_MEAN) mean[s_off] = v_mean variance[s_off] = v_variance }
#endif
}
#endif // IS_FWD
#if IS_BWD
#define STORE_FLOAT_SGx1(ptr, val) \
intel_sub_group_block_write((__global uint *)(ptr), as_uint(val))
#define STORE_FLOAT_SGx2(ptr, val) \
intel_sub_group_block_write2((__global uint *)(ptr), as_uint2(val))
#define STORE_FLOAT_SGx4(ptr, val) \
intel_sub_group_block_write4((__global uint *)(ptr), as_uint4(val))
#define STORE_FLOAT_SGx8(ptr, val) \
intel_sub_group_block_write8((__global uint *)(ptr), as_uint8(val))
#define STORE_VECT_FLOAT(ptr, val) CONCAT2(STORE_FLOAT_SGx, VECT_DT_N)(ptr, val)
#if USE_SCALE || USE_SHIFT
NAMED_KERNEL_ATTR(SCALESHIFT)
__kernel void vectorized_lnorm_bwd_scaleshift(__global DATA_T *src,
__global float *mean, __global float *variance,
__global DATA_T *diff_dst, __global float *diff_scale,
__global float *diff_shift, float eps) {
const int c = GWS_GET_C() * VECT_DT_N const int n_chunk_idx = GWS_GET_N() const int n_start = n_chunk_idx * N_CHUNK_SIZE const int n_end = min(n_start + N_CHUNK_SIZE, N)
// diff_scale and diff_shift use the same tensor in scratchpad
const int shift_off = N_CHUNKS * C diff_shift += shift_off
VECT_FLOAT_T diff_gamma_vect = 0 VECT_FLOAT_T diff_beta_vect = 0
for (int n_off = n_start const float mean_vect = SKIP_MEAN ? 0 : mean[n_off] const float variance_vect = variance[n_off] const float inv_sqrt_variance = rsqrt(variance_vect + eps)#if NDIMS == 2
const int src_off = SRC_OFF(n_off, c, 0, 0, 0, 0) const int dst_off = DST_OFF(n_off, c, 0, 0, 0, 0)#else
const int src_off = SRC_OFF(0, n_off, c, 0, 0, 0) const int dst_off = DST_OFF(0, n_off, c, 0, 0, 0)#endif
const VECT_FLOAT_T src_vect
= CONVERT_VECT_FLOAT_T(AS_VECT_DATA_T(VECT_BLOCK_READ(
(const __global BLOCK_DATA_T *)(&src[src_off])))) const VECT_FLOAT_T diff_dst_vect
= CONVERT_VECT_FLOAT_T(AS_VECT_DATA_T(VECT_BLOCK_READ(
(const __global BLOCK_DATA_T *)(&diff_dst[dst_off]))))
diff_gamma_vect
+= (src_vect - mean_vect) * diff_dst_vect * inv_sqrt_variance diff_beta_vect += diff_dst_vect }
const int result_offset = n_chunk_idx * C + c if (USE_SCALE)
STORE_VECT_FLOAT(&diff_scale[result_offset], diff_gamma_vect) if (USE_SHIFT) STORE_VECT_FLOAT(&diff_shift[result_offset], diff_beta_vect)}
NAMED_KERNEL_ATTR(SCALESHIFT_FINALIZE)
__kernel void vectorized_lnorm_bwd_scaleshift_final(
__global float *tmp_reduce_mem, __global WEI_DATA_T *diff_scale,
__global WEI_DATA_T *diff_shift) {
const int c = GWS_GET_C_finalize() const int n_chunk = div_up(N_CHUNKS, FINALIZE_N_CHUNKS) const int n = GWS_GET_N_finalize() * n_chunk const int lid = get_local_id(0)
// diff_scale and diff_shift use the same tensor in scratchpad
const int diff_shift_off = N_CHUNKS * C __global float *tmp_diff_scale = tmp_reduce_mem __global float *tmp_diff_shift = tmp_reduce_mem + diff_shift_off
float diff_gamma = 0 float diff_beta = 0
for (int n_idx = n const int result_off = n_idx * C + c diff_gamma += tmp_diff_scale[result_off] diff_beta += tmp_diff_shift[result_off] }
diff_gamma = work_group_reduce_add(diff_gamma) diff_beta = work_group_reduce_add(diff_beta)
if (diff_scale && lid == 0) diff_scale[c] = CONVERT_WEI_DATA_T(diff_gamma) if (diff_shift && lid == 0) diff_shift[c] = CONVERT_WEI_DATA_T(diff_beta)}
#endif // USE_SCALE || USE_SHIFT
KERNEL_ATTR
__kernel void vectorized_lnorm_bwd(__global DATA_T *src, __global float *mean,
__global float *variance, __global DATA_T *diff_dst,
__global WEI_DATA_T *scale, __global DATA_T *diff_src, float eps) {
int x[6] = {0} x[0] = GWS_GET_X0() x[1] = GWS_GET_X1() x[2] = GWS_GET_X2() x[3] = GWS_GET_X3()
const int s_off = STAT_OFF(x[0], x[1], x[2], x[3], x[4], x[5]) const float mean_val = SKIP_MEAN ? 0 : mean[s_off] const float inv_sqrt_variance = rsqrt(variance[s_off] + eps)
float dd_gamma = 0, dd_gamma_x = 0 VECT_FLOAT_T dd_gamma_vect = 0 VECT_FLOAT_T dd_gamma_x_vect = 0 if (CALCULATE_STATS) {
for (int c = 0 VECT_FLOAT_T gamma = 1.0f if (scale) { gamma = LOAD_VECT_WEI(&scale[c]) x[NDIMS - 1] = c const int src_off = SRC_OFF(x[0], x[1], x[2], x[3], x[4], x[5]) const int dst_off = DST_OFF(x[0], x[1], x[2], x[3], x[4], x[5])
const VECT_FLOAT_T src_vect
= CONVERT_VECT_FLOAT_T(AS_VECT_DATA_T(VECT_BLOCK_READ(
(const __global BLOCK_DATA_T *)&src[src_off]))) const VECT_FLOAT_T dst_vect
= CONVERT_VECT_FLOAT_T(AS_VECT_DATA_T(VECT_BLOCK_READ((
const __global BLOCK_DATA_T *)&diff_dst[dst_off])))
dd_gamma_vect += dst_vect * gamma dd_gamma_x_vect += dst_vect * gamma * (src_vect - mean_val) }
#if VECT_DT_N == 1
dd_gamma = dd_gamma_vect dd_gamma_x = dd_gamma_x_vect#else
for (int i = 0 dd_gamma += dd_gamma_vect[i] dd_gamma_x += dd_gamma_x_vect[i] }
#endif
dd_gamma = sub_group_reduce_add(dd_gamma) dd_gamma_x = sub_group_reduce_add(dd_gamma_x) dd_gamma_x *= inv_sqrt_variance }
for (int c = 0 VECT_FLOAT_T gamma = 1.0f if (scale) { gamma = LOAD_VECT_WEI(&scale[c]) x[NDIMS - 1] = c const int src_off = SRC_OFF(x[0], x[1], x[2], x[3], x[4], x[5]) const int dst_off = DST_OFF(x[0], x[1], x[2], x[3], x[4], x[5])
const VECT_FLOAT_T src_vect = CONVERT_VECT_FLOAT_T(AS_VECT_DATA_T(
VECT_BLOCK_READ((const __global BLOCK_DATA_T *)&src[src_off]))) VECT_FLOAT_T v_diff_src_vect
= CONVERT_VECT_FLOAT_T(AS_VECT_DATA_T(VECT_BLOCK_READ(
(const __global BLOCK_DATA_T *)&diff_dst[dst_off]))) v_diff_src_vect *= gamma if (CALCULATE_STATS) {
v_diff_src_vect -= dd_gamma / C
+ (src_vect - mean_val) * dd_gamma_x * inv_sqrt_variance
/ C }
v_diff_src_vect *= inv_sqrt_variance VECT_BLOCK_WRITE((__global BLOCK_DATA_T *)&diff_src[src_off],
AS_VECT_BLOCK_DATA_T(CONVERT_VECTOR_DATA_T(v_diff_src_vect))) }
}
#endif // IS_BWD