#ifndef GPU_INTEL_RNN_CELL_KIND_UTILITY_H
#define GPU_INTEL_RNN_CELL_KIND_UTILITY_H
inline float one_m_square(float a) {
return 1.0f - a * a;
}
inline float x_m_square(float a) {
return (1.0f - a) * a;
}
inline float relu_fwd(float s, float alpha) {
return s > 0 ? s : s * alpha;
}
inline float tanh_fwd(float s) {
return tanh(s);
}
inline float logistic_fwd(float s) {
return 1 / (1 + exp((float)-s));
}
inline float logistic_bwd(float s) {
return x_m_square(s);
}
inline float relu_bwd(float s, float alpha) {
return s > 0 ? 1.f : alpha;
}
inline float tanh_bwd(float s) {
return (1 - s) * (1 + s);
}
inline float linear(float s, float alpha) {
return alpha * s;
}
inline float relu_fwd_tm(float s, float alpha) {
#if !IS_TESTMODE
return relu_fwd(s, alpha);
#else
return linear(s, alpha);
#endif
}
inline float tanh_fwd_tm(float s, float alpha) {
#if !IS_TESTMODE
return tanh(s);
#else
return linear(s, alpha);
#endif
}
inline float logistic_fwd_tm(float s, float alpha) {
#if !IS_TESTMODE
return logistic_fwd(s);
#else
return linear(s, alpha);
#endif
}
inline float relu_bwd_tm(float s, float alpha) {
#if !IS_TESTMODE
return relu_bwd(s, alpha);
#else
return linear(s, alpha);
#endif
}
inline float tanh_bwd_tm(float s, float alpha) {
#if !IS_TESTMODE
return tanh_bwd(s);
#else
return linear(s, alpha);
#endif
}
inline float logistic_bwd_tm(float s, float alpha) {
#if !IS_TESTMODE
return logistic_bwd(s);
#else
return linear(s, alpha);
#endif
}
inline float activation_fwd(float s, float alpha, float cliping) {
#if CELL_KIND == VANILLA_RNN
#if ACTIVATION_KIND == ELTWISE_RELU
return relu_fwd_tm(s, alpha);
#elif ACTIVATION_KIND == ELTWISE_TANH
return tanh_fwd_tm(s, alpha);
#elif ACTIVATION_KIND == ELTWISE_LOGISTIC
return logistic_fwd_tm(s, alpha);
#else
#error "Unsupported activation_kind"
#endif
#else
return 0.0f;
#endif
}
inline float activation_bwd(float s, float alpha, float cliping) {
#if CELL_KIND == VANILLA_RNN
#if ACTIVATION_KIND == ELTWISE_RELU
return relu_bwd_tm(s, alpha);
#elif ACTIVATION_KIND == ELTWISE_TANH
return tanh_bwd_tm(s, alpha);
#elif ACTIVATION_KIND == ELTWISE_LOGISTIC
return logistic_bwd_tm(s, alpha);
#else
#error "Unsupported activation_kind"
#endif
#else
return 0.0f;
#endif
}
float vanilla_rnn_compute_gates(float G0, float B0, float alpha,
const __global float *restrict tm_scales) {
float G = activation_fwd(G0 + B0,
#if IS_TESTMODE
tm_scales[0], 0);
#else
alpha, 0);
#endif
return G;
}
void store_vanilla_rnn(__global AUX_DATA_T *ws_gates, int gates_ws_ld,
__global WS_STATE_DATA_T *h_states_t_l, int states_ws_ld, int dhc,
int n, int c, float g) {
if (!RECOMPUTE_GATES && IS_TRAINING) {
ws_gates[cell_ws_gates(gates_ws_ld, dhc, n, 0, c)] = g;
}
h_states_t_l[cell_ws_state(states_ws_ld, n, c)] = TO_WS_STATE(g);
}
typedef struct vanilla_lstm_gates_t {
float G[vanilla_lstm_n_gates];
} vanilla_lstm_gates_t;
struct vanilla_lstm_gates_t vanilla_lstm_compute_gates(
const float G[vanilla_lstm_n_gates],
const float B[vanilla_lstm_n_gates],
const __global float *restrict tm_scales) {
vanilla_lstm_gates_t ret;
ret.G[0] = logistic_fwd_tm(G[0] + B[0], tm_scales[0]);
ret.G[1] = logistic_fwd_tm(G[1] + B[1], tm_scales[1]);
ret.G[2] = tanh_fwd_tm(G[2] + B[2], tm_scales[2]);
ret.G[3] = logistic_fwd_tm(G[3] + B[3], tm_scales[3]);
return ret;
}
void vanilla_lstm_store(__global AUX_DATA_T *ws_gates, int gates_ws_ld,
__global WS_STATE_DATA_T *h_states_t_l,
__global AUX_DATA_T *c_states_t_l,
const __global AUX_DATA_T *c_states_tm1_l, int states_ws_ld, int dhc,
int n, int c, float tm_cscale, vanilla_lstm_gates_t gates) {
float g_i = gates.G[0];
float g_f = gates.G[1];
float g_z = gates.G[2];
float g_o = gates.G[3];
if (!RECOMPUTE_GATES && IS_TRAINING) {
ws_gates[cell_ws_gates(gates_ws_ld, dhc, n, 0, c)] = g_i;
ws_gates[cell_ws_gates(gates_ws_ld, dhc, n, 1, c)] = g_f;
ws_gates[cell_ws_gates(gates_ws_ld, dhc, n, 2, c)] = g_z;
ws_gates[cell_ws_gates(gates_ws_ld, dhc, n, 3, c)] = g_o;
}
float Ct = g_f * c_states_tm1_l[cell_ws_state(states_ws_ld, n, c)]
+ g_i * g_z;
float Ht = g_o * tanh_fwd_tm(Ct, tm_cscale);
h_states_t_l[cell_ws_state(states_ws_ld, n, c)] = TO_WS_STATE(Ht);
c_states_t_l[cell_ws_state(states_ws_ld, n, c)] = Ct;
}
#if IS_INT8 && CELL_KIND == VANILLA_LSTM
inline WS_STATE_DATA_T q_d(float f, float data_scale, float data_shift) {
return TO_WS_STATE(f * data_scale + data_shift);
}
inline float deq_w(ACC_DATA_T s, int gate, int j, __global float *scales,
float data_scale, int dhc) {
#if WEI_QPARAM_MASK
float wei_scale = scales[gate * dhc + j];
#else
float wei_scale = scales[0];
#endif
return (float)(s) / (wei_scale * data_scale);
}
#endif
typedef struct lbr_gru_gates_t {
float Wh_b;
float G[3];
} lbr_gru_gates_t;
struct lbr_gru_gates_t compute_gates_lbr_gru(const float G[n_gates],
const float C[n_gates], const float B[n_bias],
const __global float *restrict tm_scales, int scratch_gates_ld, int dhc,
int mb, int c) {
lbr_gru_gates_t ret;
ret.Wh_b = C[2] + B[3];
ret.G[0] = logistic_fwd_tm(G[0] + C[0] + B[0], tm_scales[0]);
ret.G[1] = logistic_fwd_tm(G[1] + C[1] + B[1], tm_scales[1]);
ret.G[2] = tanh_fwd_tm(G[2] + ret.G[1] * ret.Wh_b + B[2], tm_scales[2]);
return ret;
}
struct lbr_gru_gates_t compute_gates_lbr_gru_scratch(
const __global ACC_DATA_T *restrict scratch_gates,
const __global AUX_DATA_T *restrict scratch_cell,
const __global BIAS_DATA_T *restrict bias,
const __global float *restrict tm_scales, int scratch_gates_ld, int dhc,
int mb, int c) {
float gates_[n_gates];
float cell_[n_gates];
float bias_[n_bias];
for (int gate_idx = 0; gate_idx < n_gates; gate_idx++) {
gates_[gate_idx] = convert_float(scratch_gates[cell_scratch_mem(
scratch_gates_ld, dhc, mb, gate_idx, c)]);
cell_[gate_idx] = convert_float(scratch_cell[cell_scratch_mem(
scratch_gates_ld, dhc, mb, gate_idx, c)]);
}
for (int bias_idx = 0; bias_idx < n_bias; bias_idx++) {
bias_[bias_idx] = convert_float(bias[off_ker_bias(dhc, bias_idx, c)]);
}
lbr_gru_gates_t gates = compute_gates_lbr_gru(
gates_, cell_, bias_, tm_scales, scratch_gates_ld, dhc, mb, c);
return gates;
}
void lbr_gru_store(__global AUX_DATA_T *ws_gates, int gates_ws_ld,
__global WS_STATE_DATA_T *src_iter,
__global WS_STATE_DATA_T *h_states_t_l, int states_ws_ld,
__global AUX_DATA_T *ws_grid, int dhc, int i, int j,
lbr_gru_gates_t gates) {
float Wh_b = gates.Wh_b;
float G0 = gates.G[0];
float G1 = gates.G[1];
float G2 = gates.G[2];
float Ht = G0 * TO_REF(src_iter[cell_ws_state(states_ws_ld, i, j)])
+ (1 - G0) * G2;
h_states_t_l[cell_ws_state(states_ws_ld, i, j)] = TO_WS_STATE(Ht);
if (!RECOMPUTE_GATES && IS_TRAINING) {
ws_gates[cell_ws_gates(gates_ws_ld, dhc, i, 0, j)] = G0;
ws_gates[cell_ws_gates(gates_ws_ld, dhc, i, 1, j)] = G1;
ws_gates[cell_ws_gates(gates_ws_ld, dhc, i, 2, j)] = G2;
ws_grid[cell_ws_grid_comp(dhc, i, j)] = Wh_b;
}
}
#endif