/*******************************************************************************
* 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"
#include "gpu/intel/include/types_interop.h"
#ifdef USE_GENERAL_KERNEL
#if ONE_REDUCTION_PER_SUBGROUP == 1
__attribute__((reqd_work_group_size(SUBGROUP_SIZE, 1, 1)))
__attribute__((intel_reqd_sub_group_size(SUBGROUP_SIZE)))
#endif
__kernel void
reusable_softmax_fwd_generic(__global SRC_DATA_T *src, __global DST_DATA_T *dst,
__global float *src_scale, __global float *dst_scale,
dim_t softmax_axis_size, dim_t softmax_axis_stride,
dim_t softmax_axis_chunk_size, dispatch_gws_rt_params_t gws_params) {
dst = GWS_GET_BUFFER_POS(DST, gws_params, dst)
FLT_ACC_DATA_T max_ = TO_FLT_ACC_DATA_T(DATA_MIN) FLT_ACC_DATA_T denom_ = TO_FLT_ACC_DATA_T(DATA_ZERO)
const size_t begin
= GWS_GET_OFF_NAMED(SRC, DEFAULT_DISPATCHER_SUFFIX, gws_params)
#if MANY_REDUCTIONS_PER_WORKGROUP == 1
const size_t end = begin + softmax_axis_stride * softmax_axis_size#else
const size_t axis_begin = GWS_GET_OFF_NAMED(
ORIGINAL, DEFAULT_DISPATCHER_SUFFIX, gws_params) const size_t end = min(axis_begin + softmax_axis_stride * softmax_axis_size,
begin + softmax_axis_stride * softmax_axis_chunk_size)#endif
for (off_t c = begin max_ = max(max_, TO_FLT_ACC_DATA_T(src[c])) }
if (USE_WORKGROUP_REDUCTION) { max_ = work_group_reduce_max(max_) if (USE_SUBGROUP_REDUCTION) { max_ = sub_group_reduce_max(max_) max_ = isfinite(max_) ? max_ : -FLT_MAX
for (off_t c = begin denom_ += exp(TO_FLT_ACC_DATA_T(src[c]) - max_) }
if (USE_WORKGROUP_REDUCTION) { denom_ = work_group_reduce_add(denom_) if (USE_SUBGROUP_REDUCTION) { denom_ = sub_group_reduce_add(denom_)
if (LOGSOFTMAX) {
denom_ = log(denom_) } else if (SOFTMAX_INF_AS_ZERO && denom_ == 0.f) {
denom_ = 1.0f } else {
denom_ = 1.0f / denom_ }
for (off_t c = begin FLT_ACC_DATA_T unscaled = LOGSOFTMAX
? TO_FLT_ACC_DATA_T(src[c]) - max_ - denom_
: exp(TO_FLT_ACC_DATA_T(src[c]) - max_) * denom_
float scale = 1.0f if (src_scale) { scale = *src_scale if (dst_scale) { scale /= *dst_scale
dst[c - begin] = TO_DST(unscaled * scale) }
}
#endif
#define VECT_SIZE 8
#define STORE_FLOAT8(prefix, ptr, val) \
WRITE_BLOCK8(prefix, (__global BLOCK_T(ALIAS(prefix)) *)(ptr), \
DATA_TO_BLOCK8(prefix, FLOAT_TO_DATA8(prefix, val)))
#define STORE_DOUBLE8(prefix, ptr, val) \
WRITE_BLOCK8(prefix, (__global BLOCK_T(ALIAS(prefix)) *)(ptr), \
DATA_TO_BLOCK8(prefix, DOUBLE_TO_DATA8(prefix, val)))
#if DST_DT_F64
#define UP_CASE_DATA DOUBLE
#define COMMON_DATA_T double
#define COMMON_DATA_MAX DBL_MAX
#define COMMON_DATA_ZERO 0.0
#else
#define UP_CASE_DATA FLOAT
#define COMMON_DATA_T float
#define COMMON_DATA_MAX FLT_MAX
#define COMMON_DATA_ZERO 0.0f
#endif
#define COMMON_DATA_TO_X(x, y) CONCAT2(DATA_TO_, UP_CASE_DATA)(x, y)
#define COMMON_STORE_DATA8(x, y, z) CONCAT3(STORE_, UP_CASE_DATA, 8)(x, y, z)
#ifdef USE_VECTORIZED_KERNEL
__attribute__((reqd_work_group_size(SUBGROUP_SIZE, 1, 1)))
__attribute__((intel_reqd_sub_group_size(SUBGROUP_SIZE))) __kernel void
reusable_softmax_fwd_generic(__global DATA_T *src, __global DST_DATA_T *dst,
__global float *src_scale, __global float *dst_scale,
dim_t softmax_axis_size, dim_t softmax_axis_stride,
dim_t softmax_axis_chunk_size, dispatch_gws_rt_params_t gws_params) {
float scale = 1.0f if (src_scale) { scale = *src_scale if (dst_scale) { scale /= *dst_scale
const off_t linear_thread_id = get_global_id(0) const off_t data_off
= (linear_thread_id / SUBGROUP_SIZE) * softmax_axis_size global DATA_T *src_backup = src src += data_off
VECT_FLOAT_T dk float max_ = -INFINITY float denom_ = 0.0f const bool has_tail = softmax_axis_size % (SUBGROUP_SIZE * VECT_SIZE) int last_buf = div_up(softmax_axis_size, (SUBGROUP_SIZE * VECT_SIZE)) if (has_tail) last_buf--
const off_t idx_end = has_tail
? softmax_axis_size - (SUBGROUP_SIZE * VECT_SIZE + 1)
: softmax_axis_size
for (off_t idx = 0 dk = CONVERT_VECT_FLOAT_T(AS_VECT_DATA_T(
VECT_BLOCK_READ((const __global BLOCK_DATA_T *)&src[idx]))) for (off_t i = 0 max_ = max(dk[i], max_) }
}
if (has_tail) {
const off_t idx_beg = last_buf * SUBGROUP_SIZE * VECT_SIZE
+ get_sub_group_local_id() const off_t idx_end = idx_beg + SUBGROUP_SIZE * VECT_SIZE for (off_t idx = idx_beg float d = (idx < softmax_axis_size ? COMMON_DATA_TO_X(SRC, src[idx])
: -COMMON_DATA_MAX) max_ = max(d, max_) }
}
max_ = sub_group_reduce_max(max_) max_ = isfinite(max_) ? max_ : -FLT_MAX
for (off_t idx = 0 dk = CONVERT_VECT_FLOAT_T(AS_VECT_DATA_T(
VECT_BLOCK_READ((const __global BLOCK_DATA_T *)&src[idx]))) dk = exp(dk - max_) for (off_t i = 0 denom_ += dk[i] }
if (has_tail) {
const off_t idx_beg = last_buf * SUBGROUP_SIZE * VECT_SIZE
+ get_sub_group_local_id() const off_t idx_end = idx_beg + SUBGROUP_SIZE * VECT_SIZE for (off_t idx = idx_beg if (idx < softmax_axis_size)
denom_ += exp(COMMON_DATA_TO_X(SRC, src[idx]) - max_) }
}
denom_ = sub_group_reduce_add(denom_)
if (LOGSOFTMAX) {
denom_ = log(denom_) } else if (SOFTMAX_INF_AS_ZERO && denom_ == 0.f) {
denom_ = 1.0f } else {
denom_ = 1.0f / denom_ }
dst += data_off
for (off_t idx = 0 dk = CONVERT_VECT_FLOAT_T(AS_VECT_DATA_T(
VECT_BLOCK_READ((const __global BLOCK_DATA_T *)&src[idx]))) dk = LOGSOFTMAX ? dk - max_ - denom_ : exp(dk - max_) * denom_ COMMON_STORE_DATA8(DST, &dst[idx], scale * dk) }
if (has_tail) {
const off_t idx_beg = last_buf * SUBGROUP_SIZE * VECT_SIZE
+ get_sub_group_local_id() const off_t idx_end = idx_beg + SUBGROUP_SIZE * VECT_SIZE for (off_t idx = idx_beg if (idx < softmax_axis_size) {
float dk = COMMON_DATA_TO_X(SRC, src[idx]) dk = LOGSOFTMAX ? dk - max_ - denom_ : exp(dk - max_) * denom_ dst[idx] = TO_DST(scale * dk) }
}
}
}
#endif
#ifdef USE_SMALL_KERNEL
__attribute__((reqd_work_group_size(SUBGROUP_SIZE, 1, 1)))
__attribute__((intel_reqd_sub_group_size(SUBGROUP_SIZE))) __kernel void
reusable_softmax_fwd_generic(__global DATA_T *src, __global DST_DATA_T *dst,
__global float *src_scale, __global float *dst_scale,
dim_t softmax_axis_size, dim_t softmax_axis_stride,
dim_t softmax_axis_chunk_size, dispatch_gws_rt_params_t gws_params) {
float scale = 1.0f if (src_scale) { scale = *src_scale if (dst_scale) { scale /= *dst_scale const off_t data_off
= (get_global_id(0) / SUBGROUP_SIZE) * softmax_axis_size float d float max_ = -INFINITY float denom_ = 0.0f src += data_off
const off_t off = get_sub_group_local_id()
d = (off < softmax_axis_size ? COMMON_DATA_TO_X(SRC, src[off]) : -INFINITY) max_ = sub_group_reduce_max(d) max_ = isfinite(max_) ? max_ : -FLT_MAX
if (off < softmax_axis_size) denom_ += exp(d - max_)
denom_ = sub_group_reduce_add(denom_) if (LOGSOFTMAX) {
denom_ = log(denom_) } else if (SOFTMAX_INF_AS_ZERO && denom_ == 0.f) {
denom_ = 1.0f } else {
denom_ = 1.0f / denom_ }
dst += data_off
if (off < softmax_axis_size) {
float from_src = d float thing = LOGSOFTMAX ? from_src - max_ - denom_
: exp(from_src - max_) * denom_ dst[off] = TO_DST(scale * thing) }
}
#endif