#ifndef GPU_INTEL_INCLUDE_ELTWISE_H
#define GPU_INTEL_INCLUDE_ELTWISE_H
#include "gpu/intel/include/dnnl_interop.h"
#include "gpu/intel/include/types.h"
#if DT_F16 == 1
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
#endif
#ifndef DATA_MAX
#if DT_F16 == 1
#define DATA_MAX HALF_MAX
#elif DT_S8 == 1
#define DATA_MAX CHAR_MAX
#elif DT_U8 == 1
#define DATA_MAX UCHAR_MAX
#else
#define DATA_MAX FLT_MAX
#endif
#endif
#if DT_F64 == 1
#define POST_OP_LITERAL(x) x
#else
#define POST_OP_LITERAL(x) x##f
#endif
POST_OP_DATA_T relu_fwd(POST_OP_DATA_T s, float alpha) {
return s > 0 ? s : s * alpha;
}
POST_OP_DATA_T relu_bwd(POST_OP_DATA_T dd, POST_OP_DATA_T s, float alpha) {
return s > 0 ? dd : dd * alpha;
}
POST_OP_DATA_T relu_bwd_use_dst(
POST_OP_DATA_T dd, POST_OP_DATA_T d, float alpha) {
return d > 0 ? dd : dd * alpha;
}
POST_OP_DATA_T linear_fwd(POST_OP_DATA_T s, float alpha, float beta) {
return alpha * s + beta;
}
POST_OP_DATA_T linear_bwd(POST_OP_DATA_T dd, float alpha) {
return dd * alpha;
}
POST_OP_DATA_T soft_relu_fwd(POST_OP_DATA_T s, float alpha) {
s = alpha * s;
POST_OP_DATA_T v = (s < log((POST_OP_DATA_T)DATA_MAX) ? log1p(exp(s)) : s);
return v / alpha;
}
POST_OP_DATA_T soft_relu_bwd(POST_OP_DATA_T dd, POST_OP_DATA_T s, float alpha) {
s = alpha * s;
return dd / (POST_OP_LITERAL(1.) + exp(-s));
}
POST_OP_DATA_T logistic_fwd(POST_OP_DATA_T s) {
return (POST_OP_LITERAL(1.)) / (POST_OP_LITERAL(1.) + exp(-s));
}
POST_OP_DATA_T logistic_bwd(POST_OP_DATA_T dd, POST_OP_DATA_T s) {
POST_OP_DATA_T v = logistic_fwd(s);
return dd * v * (POST_OP_LITERAL(1.) - v);
}
POST_OP_DATA_T logistic_bwd_use_dst(POST_OP_DATA_T dd, POST_OP_DATA_T d) {
return dd * d * (POST_OP_LITERAL(1.) - d);
}
POST_OP_DATA_T square_fwd(POST_OP_DATA_T s) {
return s * s;
}
POST_OP_DATA_T square_bwd(POST_OP_DATA_T dd, POST_OP_DATA_T s) {
return dd * 2 * s;
}
POST_OP_DATA_T sqrt_fwd(POST_OP_DATA_T s) {
return sqrt(s);
}
POST_OP_DATA_T sqrt_bwd(POST_OP_DATA_T dd, POST_OP_DATA_T s) {
return dd / (POST_OP_LITERAL(2.) * sqrt(s));
}
POST_OP_DATA_T sqrt_bwd_use_dst(POST_OP_DATA_T dd, POST_OP_DATA_T d) {
return dd / (POST_OP_LITERAL(2.) * d);
}
POST_OP_DATA_T abs_fwd(POST_OP_DATA_T s) {
return s > 0 ? s : -s;
}
POST_OP_DATA_T abs_bwd(POST_OP_DATA_T dd, POST_OP_DATA_T s) {
return s > 0 ? dd : s < 0 ? -dd : 0;
}
POST_OP_DATA_T tanh_fwd(POST_OP_DATA_T s) {
return tanh(s);
}
POST_OP_DATA_T tanh_bwd(POST_OP_DATA_T dd, POST_OP_DATA_T s) {
POST_OP_DATA_T e = tanh_fwd(s);
return dd * (POST_OP_LITERAL(1.) - e) * (POST_OP_LITERAL(1.) + e);
}
POST_OP_DATA_T tanh_bwd_use_dst(POST_OP_DATA_T dd, POST_OP_DATA_T d) {
return dd * (POST_OP_LITERAL(1.) - d) * (POST_OP_LITERAL(1.) + d);
}
POST_OP_DATA_T mish_fwd(POST_OP_DATA_T s) {
return s * tanh_fwd(soft_relu_fwd(s, POST_OP_LITERAL(1.)));
}
POST_OP_DATA_T mish_bwd(POST_OP_DATA_T dd, POST_OP_DATA_T s) {
const POST_OP_DATA_T tanh = tanh_fwd(soft_relu_fwd(s, POST_OP_LITERAL(1.)));
const POST_OP_DATA_T srelu_bwd
= soft_relu_bwd(POST_OP_LITERAL(1.), s, POST_OP_LITERAL(1.));
const POST_OP_DATA_T derivative = tanh
+ s * srelu_bwd
* (POST_OP_LITERAL(1.) - pow(tanh, POST_OP_LITERAL(2.)));
return dd * derivative;
}
POST_OP_DATA_T elu_fwd(POST_OP_DATA_T s, float alpha) {
return s > 0 ? s : alpha * expm1(s);
}
POST_OP_DATA_T elu_bwd(POST_OP_DATA_T dd, POST_OP_DATA_T s, float alpha) {
return dd * (s > 0 ? 1 : alpha * exp(s));
}
POST_OP_DATA_T elu_bwd_use_dst(
POST_OP_DATA_T dd, POST_OP_DATA_T d, float alpha) {
return dd * (d > 0 ? 1 : d + alpha);
}
POST_OP_DATA_T exp_fwd(POST_OP_DATA_T s) {
return exp(s);
}
POST_OP_DATA_T exp_bwd(POST_OP_DATA_T dd, POST_OP_DATA_T s) {
return dd * exp_fwd(s);
}
POST_OP_DATA_T exp_bwd_use_dst(POST_OP_DATA_T dd, POST_OP_DATA_T d) {
return dd * d;
}
POST_OP_DATA_T gelu_tanh_fwd(POST_OP_DATA_T s) {
const POST_OP_DATA_T sqrt_2_over_pi
= POST_OP_LITERAL(0.79788458347320556640625);
const POST_OP_DATA_T fitting_const = POST_OP_LITERAL(0.044715);
const POST_OP_DATA_T g = sqrt_2_over_pi * s
* (POST_OP_LITERAL(1.) + fitting_const * s * s);
return (POST_OP_LITERAL(0.5) * s * (POST_OP_LITERAL(1.) + tanh_fwd(g)));
}
POST_OP_DATA_T gelu_tanh_bwd(POST_OP_DATA_T dd, POST_OP_DATA_T s) {
const POST_OP_DATA_T sqrt_2_over_pi
= POST_OP_LITERAL(0.79788458347320556640625);
const POST_OP_DATA_T fitting_const = POST_OP_LITERAL(0.044715);
const POST_OP_DATA_T g = sqrt_2_over_pi * s
* (POST_OP_LITERAL(1.) + fitting_const * s * s);
const POST_OP_DATA_T dg = sqrt_2_over_pi
* (POST_OP_LITERAL(1.)
+ POST_OP_LITERAL(3.) * fitting_const * s * s);
const POST_OP_DATA_T v = tanh_fwd(g);
return dd * POST_OP_LITERAL(0.5) * (POST_OP_LITERAL(1.) + v)
* (POST_OP_LITERAL(1.) + s * (POST_OP_LITERAL(1.) - v) * dg);
}
POST_OP_DATA_T swish_fwd(POST_OP_DATA_T s, float alpha) {
POST_OP_DATA_T w = -alpha * s;
return s / (POST_OP_LITERAL(1.) + exp(w));
}
POST_OP_DATA_T swish_bwd(POST_OP_DATA_T dd, POST_OP_DATA_T s, float alpha) {
POST_OP_DATA_T v = logistic_fwd(alpha * s);
return dd * (v + s * alpha * v * (POST_OP_LITERAL(1.) - v));
}
POST_OP_DATA_T log_fwd(POST_OP_DATA_T s) {
return log(s);
}
POST_OP_DATA_T log_bwd(POST_OP_DATA_T dd, POST_OP_DATA_T s) {
return dd / s;
}
POST_OP_DATA_T clip_fwd(POST_OP_DATA_T s, float alpha, float beta) {
s = s > alpha ? s : alpha;
return s > beta ? beta : s;
}
POST_OP_DATA_T clip_bwd(
POST_OP_DATA_T dd, POST_OP_DATA_T s, float alpha, float beta) {
return dd * (alpha < s && s <= beta ? 1 : 0);
}
POST_OP_DATA_T clip_v2_fwd(POST_OP_DATA_T s, float alpha, float beta) {
s = s > alpha ? s : alpha;
return s < beta ? s : beta;
}
POST_OP_DATA_T clip_v2_bwd(
POST_OP_DATA_T dd, POST_OP_DATA_T s, float alpha, float beta) {
return dd * (alpha < s && s < beta ? 1 : 0);
}
POST_OP_DATA_T clip_v2_bwd_use_dst(
POST_OP_DATA_T dd, POST_OP_DATA_T d, float alpha, float beta) {
return dd * (alpha < d && d < beta ? 1 : 0);
}
POST_OP_DATA_T pow_fwd(POST_OP_DATA_T s, float alpha, float beta) {
return alpha * pow(s, (POST_OP_DATA_T)(beta));
}
POST_OP_DATA_T pow_bwd(
POST_OP_DATA_T dd, POST_OP_DATA_T s, float alpha, float beta) {
if (beta == 0) return 0;
POST_OP_DATA_T v = pow_fwd(s, alpha * beta, beta - 1);
return dd * v;
}
POST_OP_DATA_T gelu_erf_fwd(POST_OP_DATA_T s) {
const POST_OP_DATA_T sqrt_2_over_2
= POST_OP_LITERAL(0.707106769084930419921875);
POST_OP_DATA_T v = s * sqrt_2_over_2;
return POST_OP_LITERAL(0.5) * s * (POST_OP_LITERAL(1.) + erf(v));
}
POST_OP_DATA_T gelu_erf_bwd(POST_OP_DATA_T dd, POST_OP_DATA_T s) {
const POST_OP_DATA_T two_over_sqrt_pi
= POST_OP_LITERAL(1.12837922573089599609375);
const POST_OP_DATA_T sqrt_2_over_2
= POST_OP_LITERAL(0.707106769084930419921875);
POST_OP_DATA_T v = s * sqrt_2_over_2;
return dd * POST_OP_LITERAL(0.5)
* (POST_OP_LITERAL(1.) + erf(v)
+ v * two_over_sqrt_pi * exp(-v * v));
}
float round_fwd(POST_OP_DATA_T s) {
return (float)rint((float)s);
}
POST_OP_DATA_T hardsigmoid_fwd(POST_OP_DATA_T s, float alpha, float beta) {
POST_OP_DATA_T v = (POST_OP_DATA_T)alpha * s + (POST_OP_DATA_T)beta;
return v <= POST_OP_LITERAL(0.) ? POST_OP_LITERAL(0.)
: v >= POST_OP_LITERAL(1.) ? POST_OP_LITERAL(1.)
: v;
}
POST_OP_DATA_T hardsigmoid_bwd(
POST_OP_DATA_T dd, POST_OP_DATA_T s, float alpha, float beta) {
POST_OP_DATA_T v = alpha * s + beta;
return v <= 0.f ? 0.f : v >= 1.f ? 0.f : dd * alpha;
}
POST_OP_DATA_T hardswish_fwd(POST_OP_DATA_T s, float alpha, float beta) {
return s * hardsigmoid_fwd(s, alpha, beta);
}
POST_OP_DATA_T hardswish_bwd(
POST_OP_DATA_T dd, POST_OP_DATA_T s, float alpha, float beta) {
POST_OP_DATA_T v = alpha * s + beta;
POST_OP_DATA_T w = POST_OP_LITERAL(2.) * alpha * s + beta;
return (v <= 0.f ? 0.f : v >= 1.f ? dd : dd * w);
}
float fwd_eltwise_common(int eltwise_alg, POST_OP_DATA_T x, float alpha_,
float beta_, float scale_) {
switch (eltwise_alg) {
case eltwise_relu: return scale_ * relu_fwd(x, alpha_); break;
case eltwise_linear:
return scale_ * linear_fwd(x, alpha_, beta_);
break;
case eltwise_soft_relu: return scale_ * soft_relu_fwd(x, alpha_); break;
case eltwise_mish: return scale_ * mish_fwd(x); break;
case eltwise_logistic: return scale_ * logistic_fwd(x); break;
case eltwise_tanh: return scale_ * tanh_fwd(x); break;
case eltwise_elu: return scale_ * elu_fwd(x, alpha_); break;
case eltwise_square: return scale_ * square_fwd(x); break;
case eltwise_sqrt: return scale_ * sqrt_fwd(x); break;
case eltwise_abs: return scale_ * abs_fwd(x); break;
case eltwise_exp: return scale_ * exp_fwd(x); break;
case eltwise_gelu_tanh: return scale_ * gelu_tanh_fwd(x); break;
case eltwise_swish: return scale_ * swish_fwd(x, alpha_); break;
case eltwise_log: return scale_ * log_fwd(x); break;
case eltwise_clip: return scale_ * clip_fwd(x, alpha_, beta_); break;
case eltwise_clip_v2:
return scale_ * clip_v2_fwd(x, alpha_, beta_);
break;
case eltwise_pow: return scale_ * pow_fwd(x, alpha_, beta_); break;
case eltwise_gelu_erf: return scale_ * gelu_erf_fwd(x); break;
case eltwise_round: return scale_ * round_fwd(x); break;
case eltwise_hardswish:
return scale_ * hardswish_fwd(x, alpha_, beta_);
break;
case eltwise_hardsigmoid:
return scale_ * hardsigmoid_fwd(x, alpha_, beta_);
break;
case eltwise_relu_dst: return scale_ * relu_fwd(x, alpha_); break;
case eltwise_logistic_dst: return scale_ * logistic_fwd(x); break;
case eltwise_tanh_dst: return scale_ * tanh_fwd(x); break;
case eltwise_elu_dst: return scale_ * elu_fwd(x, alpha_); break;
case eltwise_sqrt_dst: return scale_ * sqrt_fwd(x); break;
case eltwise_exp_dst: return scale_ * exp_fwd(x); break;
case eltwise_clip_v2_dst:
return scale_ * clip_v2_fwd(x, alpha_, beta_);
break;
default: return x; break;
}
}
float fwd_eltwise(POST_OP_DATA_T x, float alpha_, float beta_, float scale_) {
#ifdef ELTWISE_ALG
return fwd_eltwise_common(ELTWISE_ALG, x, alpha_, beta_, scale_);
#else
return x;
#endif
}
float bwd_eltwise(
POST_OP_DATA_T x, POST_OP_DATA_T y, float alpha_, float beta_) {
#ifdef ELTWISE_ALG
switch (ELTWISE_ALG) {
case eltwise_relu: return relu_bwd(x, y, alpha_); break;
case eltwise_linear: return linear_bwd(x, alpha_); break;
case eltwise_soft_relu: return soft_relu_bwd(x, y, alpha_); break;
case eltwise_mish: return mish_bwd(x, y); break;
case eltwise_logistic: return logistic_bwd(x, y); break;
case eltwise_tanh: return tanh_bwd(x, y); break;
case eltwise_elu: return elu_bwd(x, y, alpha_); break;
case eltwise_square: return square_bwd(x, y); break;
case eltwise_sqrt: return sqrt_bwd(x, y); break;
case eltwise_abs: return abs_bwd(x, y); break;
case eltwise_exp: return exp_bwd(x, y); break;
case eltwise_gelu_tanh: return gelu_tanh_bwd(x, y); break;
case eltwise_swish: return swish_bwd(x, y, alpha_); break;
case eltwise_log: return log_bwd(x, y); break;
case eltwise_clip: return clip_bwd(x, y, alpha_, beta_); break;
case eltwise_clip_v2: return clip_v2_bwd(x, y, alpha_, beta_); break;
case eltwise_pow: return pow_bwd(x, y, alpha_, beta_); break;
case eltwise_gelu_erf: return gelu_erf_bwd(x, y); break;
case eltwise_hardswish:
return hardswish_bwd(x, y, alpha_, beta_);
break;
case eltwise_hardsigmoid:
return hardsigmoid_bwd(x, y, alpha_, beta_);
break;
case eltwise_relu_dst: return relu_bwd_use_dst(x, y, alpha_); break;
case eltwise_logistic_dst: return logistic_bwd_use_dst(x, y); break;
case eltwise_tanh_dst: return tanh_bwd_use_dst(x, y); break;
case eltwise_elu_dst: return elu_bwd_use_dst(x, y, alpha_); break;
case eltwise_sqrt_dst: return sqrt_bwd_use_dst(x, y); break;
case eltwise_exp_dst: return exp_bwd_use_dst(x, y); break;
case eltwise_clip_v2_dst:
return clip_v2_bwd_use_dst(x, y, alpha_, beta_);
break;
default: return x; break;
}
#else
return x;
#endif
}
#endif