#include "gpu/generic/sycl/rnn/ref_rnn.hpp"
#include "common/primitive.hpp"
#include "common/primitive_desc.hpp"
#include "common/matmul_pd.hpp"
#include "common/stream.hpp"
#include "common/type_helpers.hpp"
#include "gpu/gpu_stream.hpp"
#include "xpu/sycl/types.hpp"
#include <memory>
#define DPRINT(fmt, ...) \
do { \
if (get_verbose_dev_mode(verbose_t::debuginfo) >= 2) { \
printf(fmt, __VA_ARGS__); \
fflush(nullptr); \
} \
} while (0)
namespace dnnl {
namespace impl {
namespace gpu {
namespace generic {
namespace sycl {
using namespace dnnl::impl::utils;
using namespace dnnl::impl::math;
using namespace prop_kind;
using namespace alg_kind;
using namespace rnn_utils;
using namespace dnnl::impl::memory_tracking::names;
status_t ref_rnn_fwd_t::pd_t::set_default_params() {
using namespace format_tag;
if (src_layer_md_.format_kind == format_kind::any)
CHECK(memory_desc_init_by_tag(src_layer_md_, tnc));
if (dst_layer_md_.format_kind == format_kind::any)
CHECK(memory_desc_init_by_tag(dst_layer_md_, tnc));
if ((!types::is_zero_md(&src_iter_md_))
&& (src_iter_md_.format_kind == format_kind::any))
CHECK(memory_desc_init_by_tag(src_iter_md_, ldnc));
if ((!types::is_zero_md(&bias_md_))
&& (bias_md_.format_kind == format_kind::any))
CHECK(memory_desc_init_by_tag(bias_md_, ldgo));
if ((!types::is_zero_md(&dst_iter_md_))
&& (dst_iter_md_.format_kind == format_kind::any))
CHECK(memory_desc_init_by_tag(dst_iter_md_, ldnc));
return status::success;
}
status_t ref_rnn_bwd_t::pd_t::set_default_params() {
using namespace format_tag;
if (src_layer_md_.format_kind == format_kind::any)
CHECK(memory_desc_init_by_tag(src_layer_md_, tnc));
if (weights_layer_md_.format_kind == format_kind::any)
CHECK(memory_desc_init_by_tag(weights_layer_md_, ldgoi));
if (dst_layer_md_.format_kind == format_kind::any)
CHECK(memory_desc_init_by_tag(dst_layer_md_, tnc));
if (weights_iter_md_.format_kind == format_kind::any)
CHECK(memory_desc_init_by_tag(weights_iter_md_, ldgoi));
if (diff_src_layer_md_.format_kind == format_kind::any)
CHECK(memory_desc_init_by_tag(diff_src_layer_md_, tnc));
if (diff_weights_layer_md_.format_kind == format_kind::any)
CHECK(memory_desc_init_by_tag(diff_weights_layer_md_, ldigo));
if (diff_weights_iter_md_.format_kind == format_kind::any)
CHECK(memory_desc_init_by_tag(diff_weights_iter_md_, ldigo));
if (diff_dst_layer_md_.format_kind == format_kind::any)
CHECK(memory_desc_init_by_tag(diff_dst_layer_md_, tnc));
if ((!types::is_zero_md(&src_iter_md_))
&& (src_iter_md_.format_kind == format_kind::any))
CHECK(memory_desc_init_by_tag(src_iter_md_, ldnc));
if ((!types::is_zero_md(&src_iter_c_md_))
&& (src_iter_c_md_.format_kind == format_kind::any))
CHECK(memory_desc_init_by_tag(src_iter_c_md_, ldnc));
if ((!types::is_zero_md(&bias_md_))
&& (bias_md_.format_kind == format_kind::any))
CHECK(memory_desc_init_by_tag(bias_md_, ldgo));
if ((!types::is_zero_md(&dst_iter_md_))
&& (dst_iter_md_.format_kind == format_kind::any))
CHECK(memory_desc_init_by_tag(dst_iter_md_, ldnc));
if ((!types::is_zero_md(&dst_iter_c_md_))
&& (dst_iter_c_md_.format_kind == format_kind::any))
CHECK(memory_desc_init_by_tag(dst_iter_c_md_, ldnc));
if ((!types::is_zero_md(&diff_src_iter_md_))
&& (diff_src_iter_md_.format_kind == format_kind::any))
CHECK(memory_desc_init_by_tag(diff_src_iter_md_, ldnc));
if ((!types::is_zero_md(&diff_src_iter_c_md_))
&& (diff_src_iter_c_md_.format_kind == format_kind::any))
CHECK(memory_desc_init_by_tag(diff_src_iter_c_md_, ldnc));
if ((!types::is_zero_md(&diff_bias_md_))
&& (diff_bias_md_.format_kind == format_kind::any))
CHECK(memory_desc_init_by_tag(diff_bias_md_, ldgo));
if ((!types::is_zero_md(&diff_dst_iter_md_))
&& (diff_dst_iter_md_.format_kind == format_kind::any))
CHECK(memory_desc_init_by_tag(diff_dst_iter_md_, ldnc));
if ((!types::is_zero_md(&diff_dst_iter_c_md_))
&& (diff_dst_iter_c_md_.format_kind == format_kind::any))
CHECK(memory_desc_init_by_tag(diff_dst_iter_c_md_, ldnc));
return status::success;
}
status_t create_matmul_pd(impl::engine_t *engine,
std::shared_ptr<primitive_desc_t> &matmul_pd, dim_t m, dim_t n, dim_t k,
std::pair<dim_t, dim_t> a_strides, std::pair<dim_t, dim_t> b_strides,
std::pair<dim_t, dim_t> c_strides, data_type_t a_dt, data_type_t b_dt,
data_type_t c_dt, float beta, fpmath_mode_t fpmath_mode,
bool deterministic) {
memory_desc_t a_md, b_md, c_md, bias_md;
dims_t a_dims = {n, k}, b_dims = {k, m}, c_dims = {n, m};
dims_t b_strides_md = {b_strides.first, b_strides.second};
dims_t a_strides_md = {a_strides.first, a_strides.second};
dims_t c_strides_md = {c_strides.first, c_strides.second};
CHECK(memory_desc_init_by_strides(b_md, 2, b_dims, a_dt, b_strides_md));
CHECK(memory_desc_init_by_strides(a_md, 2, a_dims, b_dt, a_strides_md));
CHECK(memory_desc_init_by_strides(c_md, 2, c_dims, c_dt, c_strides_md));
primitive_attr_t attr;
if (beta != 0) { CHECK(attr.post_ops_.append_sum(beta)); }
CHECK(attr.set_fpmath_mode(fpmath_mode));
attr.deterministic_ = deterministic;
matmul_desc_t matmul_desc;
dnnl::impl::matmul_desc_init(&matmul_desc, &a_md, &b_md, &bias_md, &c_md);
primitive_desc_iterator_t it(engine,
reinterpret_cast<op_desc_t *>(&matmul_desc), &attr, nullptr);
while (++it != it.end()) {
if (*it) {
matmul_pd = *it;
return status::success;
break;
}
}
return status::unimplemented;
}
status_t ref_rnn_fwd_t::pd_t::init(impl::engine_t *engine) {
using namespace prop_kind;
using namespace utils;
using namespace rnn_utils;
using namespace format_tag;
assert(engine->kind() == engine_kind::gpu);
const alg_kind_t cell_kind = this->desc()->cell_kind;
data_type_t src_layer_dt = this->desc()->src_layer_desc.data_type;
data_type_t weights_iter_dt = this->desc()->weights_iter_desc.data_type;
data_type_t weights_layer_dt = this->desc()->weights_layer_desc.data_type;
data_type_t bias_dt = this->desc()->bias_desc.data_type;
acc_data_t = data_type::f32;
src_type = src_layer_dt;
weights_type = weights_layer_dt;
VDISPATCH_RNN(
one_of(cell_kind, alg_kind::vanilla_rnn), VERBOSE_BAD_ALGORITHM);
VDISPATCH_RNN(weights_iter_dt == weights_layer_dt, VERBOSE_UNSUPPORTED_DT);
VDISPATCH_RNN_SC(this->set_default_params(), VERBOSE_UNSUPPORTED_TAG);
VDISPATCH_RNN(this->with_bias(), VERBOSE_UNSUPPORTED_BIAS_CFG);
VDISPATCH_RNN(IMPLICATION(this->desc()->prop_kind != forward_inference,
bias_dt == dnnl_f32),
VERBOSE_UNSUPPORTED_BIAS_CFG);
init_rnn_conf(rnn_conf, this, acc_data_t);
primitive_attr_t::skip_mask_t attr_mask
= primitive_attr_t::skip_mask_t::rnn_tparams;
if (weights_layer_dt == data_type::s8) {
attr_mask = attr_mask | primitive_attr_t::skip_mask_t::rnn_data_qparams
| primitive_attr_t::skip_mask_t::rnn_weights_qparams
| primitive_attr_t::skip_mask_t::fpmath_mode;
}
VDISPATCH_RNN(this->attr()->has_default_values(attr_mask),
VERBOSE_UNSUPPORTED_ATTR);
VDISPATCH_RNN_SC(set_weights_desc(this->weights_layer_md_, rnn_conf),
"unsupported weights layer memory descriptor");
VDISPATCH_RNN_SC(set_weights_desc(this->weights_iter_md_, rnn_conf),
"unsupported weights iter memory descriptor");
VDISPATCH_RNN((this->SIC() == this->DHC() || (this->T() == 1)),
VERBOSE_INCONSISTENT_DIM, "SIC", (int)this->SIC(), "DHC",
(int)this->DHC());
set_rnn_conf(rnn_conf, *this->desc());
dim_t workspace_size = get_workspace_size(rnn_conf);
if (rnn_conf.use_workspace) {
dims_t ws_dims = {workspace_size};
VDISPATCH_RNN_SC(memory_desc_init_by_tag(
this->ws_md_, 1, ws_dims, data_type::u8, x),
"memory_desc_init_by_tag()");
}
memory_desc_t state_md;
dims_t state_dims = {rnn_conf.n_layer, rnn_conf.n_dir, rnn_conf.n_iter + 1,
rnn_conf.mb, rnn_conf.states_ws_ld};
CHECK(memory_desc_init_by_tag(state_md, 5, state_dims,
rnn_conf.aux_data_type, format_tag::abcde));
bool is_l2r = !(this->desc()->direction == dnnl_unidirectional_right2left);
bool is_r2l = !(this->desc()->direction == dnnl_unidirectional_left2right);
bool is_sum = this->desc()->direction == dnnl_bidirectional_sum;
xpu::sycl::md_t copy_src_md = xpu::sycl::md_t(this->src_md(0));
xpu::sycl::md_t copy_dst_md = xpu::sycl::md_t(&state_md);
copy_init_layer_conf_ = sycl_rnn_copy_conf_t {copy_src_md, copy_dst_md,
rnn_conf.is_fwd ? rnn_conf.slc : rnn_conf.dhc, rnn_conf.n_dir,
rnn_conf.n_layer, rnn_conf.n_iter, rnn_conf.mb,
rnn_conf.is_fwd ? rnn_conf.states_ws_ld
: rnn_conf.scratch_diff_states_ld,
true, true, is_l2r, is_r2l, is_sum};
copy_src_md = this->src_md(1)->data_type == data_type::undef
? xpu::sycl::md_t()
: xpu::sycl::md_t(this->src_md(1));
copy_init_iter_conf_ = sycl_rnn_copy_conf_t {copy_src_md, copy_dst_md,
rnn_conf.is_fwd ? rnn_conf.sic : rnn_conf.dhc, rnn_conf.n_dir,
rnn_conf.n_layer, rnn_conf.n_iter, rnn_conf.mb,
rnn_conf.is_fwd ? rnn_conf.states_ws_ld
: rnn_conf.scratch_diff_states_ld,
false, true, is_l2r, is_r2l, is_sum};
copy_src_md = xpu::sycl::md_t(&state_md);
copy_dst_md = xpu::sycl::md_t(this->dst_md(0));
copy_res_layer_conf_ = sycl_rnn_copy_conf_t {copy_src_md, copy_dst_md,
rnn_conf.is_fwd ? rnn_conf.dhc : rnn_conf.slc, rnn_conf.n_dir,
rnn_conf.n_layer, rnn_conf.n_iter, rnn_conf.mb,
rnn_conf.is_fwd ? rnn_conf.states_ws_ld
: rnn_conf.scratch_diff_states_ld,
true, false, is_l2r, is_r2l, is_sum};
copy_src_md = xpu::sycl::md_t(&state_md);
copy_dst_md = this->dst_md(1)->data_type == data_type::undef
? xpu::sycl::md_t()
: xpu::sycl::md_t(this->dst_md(1));
copy_res_iter_conf_ = sycl_rnn_copy_conf_t {copy_src_md, copy_dst_md,
rnn_conf.is_fwd ? rnn_conf.dhc : rnn_conf.sic, rnn_conf.n_dir,
rnn_conf.n_layer, rnn_conf.n_iter, rnn_conf.mb,
rnn_conf.is_fwd ? rnn_conf.states_ws_ld
: rnn_conf.scratch_diff_states_ld,
false, false, is_l2r, is_r2l, is_sum};
sycl_rnn_bias_fwd_conf_t_ = sycl_rnn_bias_fwd_conf_t();
sycl_rnn_bias_fwd_conf_t_.gates_type = rnn_conf.ws_data_type;
sycl_rnn_bias_fwd_conf_t_.states_data_type
= xpu::sycl::md_t(&state_md).data_type();
sycl_rnn_bias_fwd_conf_t_.bias_type = bias_dt;
sycl_rnn_bias_fwd_conf_t_.batch = rnn_conf.mb;
sycl_rnn_bias_fwd_conf_t_.dhc = rnn_conf.dhc;
sycl_rnn_bias_fwd_conf_t_.gates_ws_ld = rnn_conf.gates_ws_ld;
sycl_rnn_bias_fwd_conf_t_.states_ws_ld = rnn_conf.states_ws_ld;
sycl_rnn_bias_fwd_conf_t_.activation_kind = this->activation_kind();
sycl_rnn_bias_fwd_conf_t_.alpha = this->desc()->alpha;
auto fpmath_mode = this->attr()->fpmath_.mode_;
bool deterministic = this->attr()->deterministic_;
float matmul_iter_fwd_beta = this->is_lbr() ? 0.0f : 1.0f;
dim_t batch = rnn_conf.mb;
dim_t n_gates = rnn_conf.n_gates;
dim_t slc = rnn_conf.slc;
dim_t sic = rnn_conf.sic;
dim_t dhc = rnn_conf.dhc;
dims_t wei_layer_strides;
get_outer_strides(this->weights_md(0), wei_layer_strides);
dims_t wei_iter_strides;
get_outer_strides(this->weights_md(1), wei_iter_strides);
VDISPATCH_RNN_SC(
create_matmul_pd(engine, matmul_layer_fwd_pd_, n_gates * dhc, batch,
slc, {rnn_conf.states_ws_ld, 1},
{wei_layer_strides[2], wei_layer_strides[4]},
{rnn_conf.scratch_gates_ld, 1}, weights_type,
rnn_conf.aux_data_type, rnn_conf.aux_data_type, 0.0,
fpmath_mode, deterministic),
"create_matmul_pd(matmul_layer_fwd_pd_)");
VDISPATCH_RNN_SC(
create_matmul_pd(engine, matmul_iter_fwd_pd_, n_gates * dhc, batch,
sic, {rnn_conf.states_ws_ld, 1},
{wei_iter_strides[2], wei_iter_strides[4]},
{rnn_conf.gates_ws_ld, 1}, weights_type,
rnn_conf.aux_data_type, rnn_conf.aux_data_type,
matmul_iter_fwd_beta, fpmath_mode, deterministic),
"create_matmul_pd(matmul_iter_fwd_pd_)");
init_scratchpad(rnn_conf.use_workspace ? 0 : workspace_size);
return status::success;
}
status_t ref_rnn_bwd_t::pd_t::init(impl::engine_t *engine) {
using namespace prop_kind;
using namespace utils;
using namespace rnn_utils;
using namespace format_tag;
assert(engine->kind() == engine_kind::gpu);
const alg_kind_t cell_kind = this->desc()->cell_kind;
data_type_t src_layer_dt = this->desc()->src_layer_desc.data_type;
data_type_t weights_iter_dt = this->desc()->weights_iter_desc.data_type;
data_type_t weights_layer_dt = this->desc()->weights_layer_desc.data_type;
data_type_t bias_dt = this->desc()->bias_desc.data_type;
acc_data_t = data_type::f32;
src_type = src_layer_dt;
weights_type = weights_layer_dt;
VDISPATCH_RNN(
one_of(cell_kind, alg_kind::vanilla_rnn), VERBOSE_BAD_ALGORITHM);
VDISPATCH_RNN(weights_iter_dt == weights_layer_dt, VERBOSE_UNSUPPORTED_DT);
VDISPATCH_RNN_SC(this->set_default_params(), VERBOSE_UNSUPPORTED_TAG);
VDISPATCH_RNN(this->with_bias(), VERBOSE_UNSUPPORTED_BIAS_CFG);
VDISPATCH_RNN(IMPLICATION(this->desc()->prop_kind != forward_inference,
utils::one_of(bias_dt, dnnl_f32)),
VERBOSE_UNSUPPORTED_BIAS_CFG);
init_rnn_conf(rnn_conf, this, acc_data_t);
primitive_attr_t::skip_mask_t attr_mask
= primitive_attr_t::skip_mask_t::rnn_tparams;
if (weights_layer_dt == data_type::s8) {
attr_mask = attr_mask | primitive_attr_t::skip_mask_t::rnn_data_qparams
| primitive_attr_t::skip_mask_t::rnn_weights_qparams
| primitive_attr_t::skip_mask_t::fpmath_mode;
}
VDISPATCH_RNN(this->attr()->has_default_values(attr_mask),
VERBOSE_UNSUPPORTED_ATTR);
VDISPATCH_RNN_SC(set_weights_desc(this->weights_layer_md_, rnn_conf),
"unsupported weights layer memory descriptor");
VDISPATCH_RNN_SC(set_weights_desc(this->weights_iter_md_, rnn_conf),
"unsupported weights iter memory descriptor");
VDISPATCH_RNN((this->SIC() == this->DHC() || (this->T() == 1)),
VERBOSE_INCONSISTENT_DIM, "SIC", (int)this->SIC(), "DHC",
(int)this->DHC());
set_rnn_conf(rnn_conf, *this->desc());
dim_t workspace_size = get_workspace_size(rnn_conf);
if (rnn_conf.use_workspace) {
dims_t ws_dims = {workspace_size};
VDISPATCH_RNN_SC(memory_desc_init_by_tag(
this->ws_md_, 1, ws_dims, data_type::u8, x),
"memory_desc_init_by_tag()");
}
memory_desc_t state_md;
dims_t state_dims = {rnn_conf.n_layer, rnn_conf.n_dir, rnn_conf.n_iter + 1,
rnn_conf.n_states + 1, rnn_conf.mb,
rnn_conf.scratch_diff_states_ld};
CHECK(memory_desc_init_by_tag(state_md, 6, state_dims,
rnn_conf.aux_data_type, format_tag::abcdef));
bool is_l2r = !(this->desc()->direction == dnnl_unidirectional_right2left);
bool is_r2l = !(this->desc()->direction == dnnl_unidirectional_left2right);
bool is_sum = this->desc()->direction == dnnl_bidirectional_sum;
xpu::sycl::md_t copy_src_md = xpu::sycl::md_t(this->diff_dst_md(0));
xpu::sycl::md_t copy_dst_md = xpu::sycl::md_t(&state_md);
copy_init_layer_conf_ = sycl_rnn_copy_conf_t {copy_src_md, copy_dst_md,
rnn_conf.dhc, rnn_conf.n_dir, rnn_conf.n_layer, rnn_conf.n_iter,
rnn_conf.mb, rnn_conf.scratch_diff_states_ld, true, true, is_l2r,
is_r2l, is_sum};
copy_src_md = this->diff_dst_md(1);
copy_init_iter_conf_ = sycl_rnn_copy_conf_t {copy_src_md, copy_dst_md,
rnn_conf.dhc, rnn_conf.n_dir, rnn_conf.n_layer, rnn_conf.n_iter,
rnn_conf.mb, rnn_conf.scratch_diff_states_ld, false, true, is_l2r,
is_r2l, is_sum};
copy_src_md = xpu::sycl::md_t(&state_md);
copy_dst_md = xpu::sycl::md_t(this->diff_src_md(0));
copy_res_layer_conf_ = sycl_rnn_copy_conf_t {copy_src_md, copy_dst_md,
rnn_conf.slc, rnn_conf.n_dir, rnn_conf.n_layer, rnn_conf.n_iter,
rnn_conf.mb, rnn_conf.scratch_diff_states_ld, true, false, is_l2r,
is_r2l, is_sum};
copy_src_md = xpu::sycl::md_t(&state_md);
copy_dst_md = this->diff_src_md(1);
copy_res_iter_conf_ = sycl_rnn_copy_conf_t {copy_src_md, copy_dst_md,
rnn_conf.sic, rnn_conf.n_dir, rnn_conf.n_layer, rnn_conf.n_iter,
rnn_conf.mb, rnn_conf.scratch_diff_states_ld, false, false, is_l2r,
is_r2l, is_sum};
sycl_rnn_bias_bwd_conf_t_ = sycl_rnn_bias_bwd_conf_t();
sycl_rnn_bias_bwd_conf_t_.diff_states_type = rnn_conf.diff_data_type;
sycl_rnn_bias_bwd_conf_t_.diff_gates_type = rnn_conf.ws_data_type;
sycl_rnn_bias_bwd_conf_t_.gates_type = rnn_conf.ws_data_type;
sycl_rnn_bias_bwd_conf_t_.batch = rnn_conf.mb;
sycl_rnn_bias_bwd_conf_t_.dhc = rnn_conf.dhc;
sycl_rnn_bias_bwd_conf_t_.gates_ws_ld = rnn_conf.scratch_diff_gates_ld;
sycl_rnn_bias_bwd_conf_t_.states_ws_ld = rnn_conf.states_ws_ld;
sycl_rnn_bias_bwd_conf_t_.scratch_diff_states_ld
= rnn_conf.scratch_diff_states_ld;
sycl_rnn_bias_bwd_conf_t_.activation_kind = this->activation_kind();
sycl_rnn_bias_bwd_conf_t_.alpha = this->desc()->alpha;
auto fpmath_mode = this->attr()->fpmath_.mode_;
bool deterministic = this->attr()->deterministic_;
float matmul_iter_bwd_beta = this->is_lbr() ? 1.0f : 0.0f;
auto diff_type = this->diff_src_md(0)->data_type;
dim_t batch = rnn_conf.mb;
dim_t n_gates = rnn_conf.n_gates;
dim_t slc = rnn_conf.slc;
dim_t sic = rnn_conf.sic;
dim_t dhc = rnn_conf.dhc;
dims_t wei_layer_strides;
get_outer_strides(this->weights_md(0), wei_layer_strides);
dims_t wei_iter_strides;
get_outer_strides(this->weights_md(1), wei_iter_strides);
dims_t diff_weights_layer;
get_outer_strides(this->diff_weights_md(0), diff_weights_layer);
dims_t diff_weights_iter;
get_outer_strides(this->diff_weights_md(1), diff_weights_iter);
VDISPATCH_RNN_SC(create_matmul_pd(engine, matmul_iter_bwd_pd_, sic, batch,
n_gates * dhc, {rnn_conf.scratch_diff_gates_ld, 1},
{wei_iter_strides[4], wei_iter_strides[2]},
{rnn_conf.scratch_diff_states_ld, 1}, weights_type,
diff_type, diff_type, matmul_iter_bwd_beta,
fpmath_mode, deterministic),
"create_matmul_pd(matmul_iter_bwd_pd_)");
VDISPATCH_RNN_SC(
create_matmul_pd(engine, matmul_diff_wei_iter_pd_, n_gates * dhc,
sic, batch, {1, rnn_conf.states_ws_ld},
{rnn_conf.scratch_diff_gates_ld, 1},
{diff_weights_iter[2], diff_weights_iter[4]}, diff_type,
diff_type, diff_type, 1.0f, fpmath_mode, deterministic),
"create_matmul_pd(matmul_diff_wei_iter_pd_)");
VDISPATCH_RNN_SC(
create_matmul_pd(engine, matmul_layer_bwd_pd_, slc, batch,
n_gates * dhc, {rnn_conf.scratch_diff_gates_ld, 1},
{wei_layer_strides[4], wei_layer_strides[2]},
{rnn_conf.scratch_diff_states_ld, 1}, weights_type,
diff_type, diff_type, 0.0f, fpmath_mode, deterministic),
"create_matmul_pd(matmul_layer_bwd_pd_)");
VDISPATCH_RNN_SC(
create_matmul_pd(engine, matmul_diff_wei_layer_pd_, n_gates * dhc,
slc, batch, {1, rnn_conf.states_ws_ld},
{rnn_conf.scratch_diff_gates_ld, 1},
{diff_weights_layer[2], diff_weights_layer[4]}, diff_type,
diff_type, diff_type, 1.0f, fpmath_mode, deterministic),
"create_matmul_pd(matmul_diff_wei_layer_pd_)");
init_scratchpad(rnn_conf.use_workspace ? 0 : workspace_size);
return status::success;
}
bool ref_rnn_common_base_t::create_nested_matmul(impl::engine_t *engine,
const std::shared_ptr<primitive_desc_t> &prim_desc,
std::shared_ptr<impl::primitive_t> &prim) {
std::pair<std::shared_ptr<impl::primitive_t>, cache_state_t> pair;
bool gemm_ok = prim_desc->create_primitive_nested(pair, engine)
== status::success;
prim = pair.first;
return gemm_ok;
}
status_t ref_rnn_fwd_t::init_(impl::engine_t *engine) {
using namespace rnn_utils;
switch (pd()->cell_kind()) {
case dnnl_vanilla_rnn:
cell_func = [this](const cell_ctx_t &cell_struct) -> status_t {
return this->cell_execution(cell_struct);
};
break;
default: break;
}
grid_func = [this](const grid_ctx_t &grid_struct) -> status_t {
return this->linear_execution(grid_struct);
};
const conf_t &rnn = pd()->rnn_conf;
rnn_utils::set_workspace_offsets(rnn, ws_gates_offset_, ws_states_offset_);
const auto copy_fwd_kid = ::sycl::get_kernel_id<ref_rnn_copy_fwd_t>();
this->create_kernel(engine, copy_fwd_kid, ©_fwd_kernel_);
const auto bias_fwd_kid = ::sycl::get_kernel_id<ref_rnn_bias_fwd>();
this->create_kernel(engine, bias_fwd_kid, &bias_fwd_kernel_);
bool matmul_ok = true;
matmul_ok = matmul_ok
&& create_nested_matmul(
engine, pd()->matmul_layer_fwd_pd_, matmul_layer_fwd_);
matmul_ok = matmul_ok
&& create_nested_matmul(
engine, pd()->matmul_iter_fwd_pd_, matmul_iter_fwd_);
if (!matmul_ok) return status::runtime_error;
return status::success;
}
status_t ref_rnn_bwd_t::init_(impl::engine_t *engine) {
using namespace rnn_utils;
switch (pd()->cell_kind()) {
case dnnl_vanilla_rnn:
cell_func = [this](const cell_ctx_t &cell_struct) -> status_t {
return this->cell_execution(cell_struct);
};
break;
default: break;
}
grid_func = [this](const grid_ctx_t &grid_struct) -> status_t {
return this->linear_execution(grid_struct);
};
const conf_t &rnn = pd()->rnn_conf;
rnn_utils::set_workspace_offsets(rnn, ws_gates_offset_, ws_states_offset_);
const auto copy_bwd_kid = ::sycl::get_kernel_id<ref_rnn_copy_bwd_t>();
this->create_kernel(engine, copy_bwd_kid, ©_bwd_kernel_);
const auto bias_bwd_kid = ::sycl::get_kernel_id<ref_rnn_bias_bwd>();
this->create_kernel(engine, bias_bwd_kid, &bias_bwd_kernel_);
bool matmul_ok = true;
matmul_ok = matmul_ok
&& create_nested_matmul(
engine, pd()->matmul_layer_bwd_pd_, matmul_layer_bwd_);
matmul_ok = matmul_ok
&& create_nested_matmul(
engine, pd()->matmul_iter_bwd_pd_, matmul_iter_bwd_);
matmul_ok = matmul_ok
&& create_nested_matmul(engine, pd()->matmul_diff_wei_layer_pd_,
matmul_diff_wei_layer_);
matmul_ok = matmul_ok
&& create_nested_matmul(engine, pd()->matmul_diff_wei_iter_pd_,
matmul_diff_wei_iter_);
if (!matmul_ok) return status::runtime_error;
return status::success;
}
status_t ref_rnn_fwd_t::matmul_primitive(impl::engine_t *engine,
const exec_ctx_t &ctx, std::unique_ptr<memory_storage_t> &a,
std::unique_ptr<memory_storage_t> &b,
std::unique_ptr<memory_storage_t> &c, matmul_kind_t matmul_kind) const {
std::shared_ptr<impl::primitive_desc_t> matmul_pd;
switch (matmul_kind) {
case matmul_iter_fwd: matmul_pd = pd()->matmul_iter_fwd_pd_; break;
case matmul_layer_fwd: matmul_pd = pd()->matmul_layer_fwd_pd_; break;
default: assert(!"unknown matmul_kind"); return status::runtime_error;
}
std::unique_ptr<memory_t, memory_deleter_t> arg1, arg2, arg3;
exec_args_t matmul_args;
CHECK(safe_ptr_assign(arg2,
new memory_t(
ctx.stream()->engine(), matmul_pd->src_md(0), a->clone())));
CHECK(safe_ptr_assign(arg1,
new memory_t(ctx.stream()->engine(), matmul_pd->weights_md(0),
b->clone())));
CHECK(safe_ptr_assign(arg3,
new memory_t(
ctx.stream()->engine(), matmul_pd->dst_md(0), c->clone())));
matmul_args[DNNL_ARG_SRC] = memory_arg_t {arg1.get(), true};
matmul_args[DNNL_ARG_WEIGHTS] = memory_arg_t {arg2.get(), true};
matmul_args[DNNL_ARG_DST] = memory_arg_t {arg3.get(), false};
exec_ctx_t matmul_ctx(ctx, std::move(matmul_args));
const auto init_matmul_nested_scratchpad
= [&](const std::shared_ptr<impl::primitive_t> &matmul, int key) {
auto *nested_grantor
= create_nested_grantor(ctx.get_scratchpad_grantor(), key,
matmul->pd()->scratchpad_registry());
matmul_ctx.set_scratchpad_grantor(nested_grantor);
};
switch (matmul_kind) {
case matmul_iter_fwd:
init_matmul_nested_scratchpad(
matmul_iter_fwd_, rnn_utils::scratch_t::key_gemm_iter_fwd);
CHECK(matmul_iter_fwd_->execute(matmul_ctx));
break;
case matmul_layer_fwd:
init_matmul_nested_scratchpad(matmul_layer_fwd_,
rnn_utils::scratch_t::key_gemm_layer_fwd);
CHECK(matmul_layer_fwd_->execute(matmul_ctx));
break;
default: assert(!"unknown matmul_kind"); return status::runtime_error;
}
return status::success;
}
status_t ref_rnn_bwd_t::matmul_primitive(impl::engine_t *engine,
const exec_ctx_t &ctx, std::unique_ptr<memory_storage_t> &a,
std::unique_ptr<memory_storage_t> &b,
std::unique_ptr<memory_storage_t> &c, matmul_kind_t matmul_kind) const {
std::shared_ptr<impl::primitive_desc_t> matmul_pd;
switch (matmul_kind) {
case matmul_iter_bwd: matmul_pd = pd()->matmul_iter_bwd_pd_; break;
case matmul_layer_bwd: matmul_pd = pd()->matmul_layer_bwd_pd_; break;
case matmul_diff_wei_iter:
matmul_pd = pd()->matmul_diff_wei_iter_pd_;
break;
case matmul_diff_wei_layer:
matmul_pd = pd()->matmul_diff_wei_layer_pd_;
break;
default: assert(!"unknown matmul_kind"); return status::runtime_error;
}
std::unique_ptr<memory_t, memory_deleter_t> arg1, arg2, arg3;
exec_args_t matmul_args;
CHECK(safe_ptr_assign(arg2,
new memory_t(
ctx.stream()->engine(), matmul_pd->src_md(0), a->clone())));
CHECK(safe_ptr_assign(arg1,
new memory_t(ctx.stream()->engine(), matmul_pd->weights_md(0),
b->clone())));
CHECK(safe_ptr_assign(arg3,
new memory_t(
ctx.stream()->engine(), matmul_pd->dst_md(0), c->clone())));
matmul_args[DNNL_ARG_SRC] = memory_arg_t {arg1.get(), true};
matmul_args[DNNL_ARG_WEIGHTS] = memory_arg_t {arg2.get(), true};
matmul_args[DNNL_ARG_DST] = memory_arg_t {arg3.get(), false};
exec_ctx_t matmul_ctx(ctx, std::move(matmul_args));
const auto init_matmul_nested_scratchpad
= [&](const std::shared_ptr<impl::primitive_t> &matmul, int key) {
auto *nested_grantor
= create_nested_grantor(ctx.get_scratchpad_grantor(), key,
matmul->pd()->scratchpad_registry());
matmul_ctx.set_scratchpad_grantor(nested_grantor);
};
switch (matmul_kind) {
case matmul_iter_bwd:
init_matmul_nested_scratchpad(
matmul_iter_bwd_, rnn_utils::scratch_t::key_gemm_iter_bwd);
CHECK(matmul_iter_bwd_->execute(matmul_ctx));
break;
case matmul_layer_bwd:
init_matmul_nested_scratchpad(matmul_layer_bwd_,
rnn_utils::scratch_t::key_gemm_layer_bwd);
CHECK(matmul_layer_bwd_->execute(matmul_ctx));
break;
case matmul_diff_wei_iter:
init_matmul_nested_scratchpad(matmul_diff_wei_iter_,
rnn_utils::scratch_t::key_gemm_diff_wei_iter);
CHECK(matmul_diff_wei_iter_->execute(matmul_ctx));
break;
case matmul_diff_wei_layer:
init_matmul_nested_scratchpad(matmul_diff_wei_layer_,
rnn_utils::scratch_t::key_gemm_diff_wei_layer);
CHECK(matmul_diff_wei_layer_->execute(matmul_ctx));
break;
default: assert(!"unknown matmul_kind"); return status::runtime_error;
}
return status::success;
}
status_t ref_rnn_common_base_t::execution_loop(const grid_ctx_t &grid_struct) {
dim_t n_layer = grid_struct.rnn.n_layer;
dim_t n_dir = grid_struct.rnn.n_dir;
dim_t n_iter = grid_struct.rnn.n_iter;
for (dim_t dir = 0; dir < n_dir; dir++) {
for (dim_t j = 0; j < n_layer; j++) {
dim_t lay = j;
for (dim_t i = 0; i < n_iter; i += grid_struct.rnn.iter_loop) {
dim_t iter = i;
const cell_ctx_t c_struct
= {grid_struct.engine, grid_struct.ctx, dir, lay, iter,
grid_struct.user_data, grid_struct.workspace,
grid_struct.scratch, grid_struct.rnn};
CHECK(cell_func(c_struct));
}
}
}
return status::success;
}
status_t ref_rnn_fwd_t::linear_execution(const grid_ctx_t &grid_struct) {
CHECK(execution_loop(grid_struct));
return status::success;
}
status_t ref_rnn_bwd_t::linear_execution(const grid_ctx_t &grid_struct) {
if (pd()->diff_weights_overwrite()) {
gpu::stream_t *stream
= utils::downcast<gpu::stream_t *>(grid_struct.ctx.stream());
auto zero = [&](const memory_storage_t *data, int arg_id) {
auto mdw = memory_desc_wrapper(pd()->arg_md(arg_id));
return stream->fill(*data, 0, mdw.size(), stream->ctx().get_deps(),
stream->ctx().get_deps());
};
CHECK(zero(grid_struct.user_data.diff_bias(), DNNL_ARG_DIFF_BIAS));
CHECK(zero(grid_struct.user_data.diff_wei_layer(),
DNNL_ARG_DIFF_WEIGHTS_LAYER));
CHECK(zero(grid_struct.user_data.diff_wei_iter(),
DNNL_ARG_DIFF_WEIGHTS_ITER));
}
CHECK(execution_loop(grid_struct));
return status::success;
}
status_t ref_rnn_common_base_t::launch_copy(bool fwd, const exec_ctx_t &ctx,
const kernel_t &cpy_kernel, const sycl_rnn_copy_conf_t ©_conf,
::sycl::range<3> global_range, ::sycl::range<3> local_range,
const memory_storage_t &input, const memory_storage_t &output) const {
parallel_for(ctx, cpy_kernel, [&](::sycl::handler &cgh) {
auto src_mem_arg = input
? utils::downcast<const xpu::sycl::memory_storage_base_t *>(
&input)
->get_in_memory_arg(ctx.stream(), cgh)
: xpu::sycl::memory_storage_base_t::empty_in_memory_arg(
ctx.stream(), cgh);
auto dst_mem_arg
= utils::downcast<const xpu::sycl::memory_storage_base_t *>(
&output)
->get_out_memory_arg(ctx.stream(), cgh);
if (fwd) {
ref_rnn_copy_fwd_t copy_kernel_fwd(
copy_conf, src_mem_arg, dst_mem_arg);
cgh.parallel_for(::sycl::nd_range<3>(global_range, local_range),
copy_kernel_fwd);
} else {
ref_rnn_copy_bwd_t copy_kernel_bwd(
copy_conf, src_mem_arg, dst_mem_arg);
cgh.parallel_for(::sycl::nd_range<3>(global_range, local_range),
copy_kernel_bwd);
}
});
return status::success;
}
status_t ref_rnn_common_base_t::do_copy(bool fwd, const exec_ctx_t &ctx,
size_t batch_range, size_t lay_iter_range, size_t channel_range,
const sycl_rnn_copy_conf_t ©_conf, const kernel_t &cpy_kernel,
const memory_storage_t &input, const memory_storage_t &output) const {
auto max_wg_size_per_dim = rnn_utils::calc_local_range(ctx);
size_t local_batch = max_wg_size_per_dim;
size_t local_channel = max_wg_size_per_dim;
size_t local_lay_dir = max_wg_size_per_dim;
size_t global_batch = rnn_utils::calc_global_range(
static_cast<size_t>(max_wg_size_per_dim),
static_cast<size_t>(batch_range));
size_t global_channels = rnn_utils::calc_global_range(
static_cast<size_t>(max_wg_size_per_dim), channel_range);
size_t global_lay_dir = rnn_utils::calc_global_range(
static_cast<size_t>(max_wg_size_per_dim),
static_cast<size_t>(lay_iter_range));
return launch_copy(fwd, ctx, cpy_kernel, copy_conf,
{global_lay_dir, global_batch, global_channels},
{local_lay_dir, local_batch, local_channel}, input, output);
}
status_t ref_rnn_fwd_t::copy_init_layer(const exec_ctx_t &ctx, dim_t batch,
dim_t dhc, dim_t sic, dim_t slc, dim_t n_iter, dim_t n_layer,
dim_t n_dir, dim_t states_ws_ld, const memory_storage_t &input,
const memory_storage_t &output) const {
return do_copy(true, ctx, batch, n_iter, slc, pd()->copy_init_layer_conf_,
copy_fwd_kernel_, input, output);
}
status_t ref_rnn_bwd_t::copy_init_layer(const exec_ctx_t &ctx, dim_t batch,
dim_t dhc, dim_t sic, dim_t slc, dim_t n_iter, dim_t n_layer,
dim_t n_dir, dim_t states_ws_ld, const memory_storage_t &input,
const memory_storage_t &output) const {
return do_copy(false, ctx, batch, n_iter, dhc, pd()->copy_init_layer_conf_,
copy_bwd_kernel_, input, output);
}
status_t ref_rnn_fwd_t::copy_init_iter(const exec_ctx_t &ctx, dim_t batch,
dim_t dhc, dim_t sic, dim_t slc, dim_t n_iter, dim_t n_layer,
dim_t n_dir, dim_t states_ws_ld, const memory_storage_t &input,
const memory_storage_t &output) const {
return do_copy(true, ctx, batch, n_layer * n_dir,
std::max(static_cast<size_t>(sic), static_cast<size_t>(dhc)),
pd()->copy_init_iter_conf_, copy_fwd_kernel_, input, output);
}
status_t ref_rnn_bwd_t::copy_init_iter(const exec_ctx_t &ctx, dim_t batch,
dim_t dhc, dim_t sic, dim_t slc, dim_t n_iter, dim_t n_layer,
dim_t n_dir, dim_t states_ws_ld, const memory_storage_t &input,
const memory_storage_t &output) const {
return do_copy(false, ctx, batch, n_layer * n_dir, dhc,
pd()->copy_init_iter_conf_, copy_bwd_kernel_, input, output);
}
status_t ref_rnn_fwd_t::copy_res_layer(const exec_ctx_t &ctx, dim_t batch,
dim_t dhc, dim_t sic, dim_t slc, dim_t n_iter, dim_t n_layer,
dim_t n_dir, dim_t states_ws_ld, const memory_storage_t &input,
const memory_storage_t &output) const {
return do_copy(true, ctx, batch, n_iter, dhc, pd()->copy_res_layer_conf_,
copy_fwd_kernel_, input, output);
}
status_t ref_rnn_bwd_t::copy_res_layer(const exec_ctx_t &ctx, dim_t batch,
dim_t dhc, dim_t sic, dim_t slc, dim_t n_iter, dim_t n_layer,
dim_t n_dir, dim_t states_ws_ld, const memory_storage_t &input,
const memory_storage_t &output) const {
return do_copy(false, ctx, batch, n_iter, slc, pd()->copy_res_layer_conf_,
copy_bwd_kernel_, input, output);
}
status_t ref_rnn_fwd_t::copy_res_iter(const exec_ctx_t &ctx, dim_t batch,
dim_t dhc, dim_t sic, dim_t slc, dim_t n_iter, dim_t n_layer,
dim_t n_dir, dim_t states_ws_ld, const memory_storage_t &input,
const memory_storage_t &output) const {
return do_copy(true, ctx, batch, n_layer * n_dir, dhc,
pd()->copy_res_iter_conf_, copy_fwd_kernel_, input, output);
}
status_t ref_rnn_bwd_t::copy_res_iter(const exec_ctx_t &ctx, dim_t batch,
dim_t dhc, dim_t sic, dim_t slc, dim_t n_iter, dim_t n_layer,
dim_t n_dir, dim_t states_ws_ld, const memory_storage_t &input,
const memory_storage_t &output) const {
return do_copy(false, ctx, batch, n_layer * n_dir,
std::max(static_cast<size_t>(sic), static_cast<size_t>(dhc)),
pd()->copy_res_iter_conf_, copy_bwd_kernel_, input, output);
}
status_t ref_rnn_fwd_t::rnn_bias(const exec_ctx_t &ctx, dim_t batch, dim_t dhc,
dim_t iter, dim_t lay, dim_t dir, const rnn_utils::workspace_t &ws,
const rnn_utils::scratch_t &scratch,
const rnn_utils ::user_data_t &user_data) const {
auto max_wg_size_per_dim = calc_local_range(ctx);
parallel_for(ctx, bias_fwd_kernel_, [&](::sycl::handler &cgh) {
auto src_mem_arg
= utils::downcast<const xpu::sycl::memory_storage_base_t *>(
scratch.gates(0).get())
->get_inout_memory_arg(ctx.stream(), cgh);
auto bias_mem_arg
= utils::downcast<const xpu::sycl::memory_storage_base_t *>(
user_data.bias(lay, dir).get())
->get_in_memory_arg(ctx.stream(), cgh);
auto dst_mem_arg
= utils::downcast<const xpu::sycl::memory_storage_base_t *>(
ws.states(lay + 1, dir, iter).get())
->get_out_memory_arg(ctx.stream(), cgh);
ref_rnn_bias_fwd bias_kernel(pd()->sycl_rnn_bias_fwd_conf_t_,
src_mem_arg, bias_mem_arg, dst_mem_arg);
size_t local_batch = max_wg_size_per_dim;
size_t local_channel = max_wg_size_per_dim;
size_t global_batch
= calc_global_range(static_cast<size_t>(max_wg_size_per_dim),
static_cast<size_t>(batch));
size_t global_channels
= calc_global_range(static_cast<size_t>(max_wg_size_per_dim),
static_cast<size_t>(dhc));
cgh.parallel_for(
::sycl::nd_range<3>(
::sycl::range<3>(global_channels, global_batch, 1),
::sycl::range<3>(local_channel, local_batch, 1)),
bias_kernel);
});
return status::success;
}
status_t ref_rnn_bwd_t::rnn_bias(const exec_ctx_t &ctx, dim_t batch, dim_t dhc,
dim_t iter, dim_t lay, dim_t dir, dim_t n_layer,
const std::unique_ptr<dnnl::impl::memory_storage_t> &diff_states_layer,
const std::unique_ptr<dnnl::impl::memory_storage_t> &diff_cell_iter,
const rnn_utils ::user_data_t &user_data,
const std::unique_ptr<dnnl::impl::memory_storage_t> &scratch_gate,
const std::unique_ptr<dnnl::impl::memory_storage_t> &diff_gates) const {
auto max_wg_size_per_dim = calc_local_range(ctx);
parallel_for(ctx, bias_bwd_kernel_, [&](::sycl::handler &cgh) {
auto gates_mem_arg
= utils::downcast<const xpu::sycl::memory_storage_base_t *>(
scratch_gate.get())
->get_in_memory_arg(ctx.stream(), cgh);
auto diff_lay_mem_arg
= utils::downcast<const xpu::sycl::memory_storage_base_t *>(
diff_states_layer.get())
->get_in_memory_arg(ctx.stream(), cgh);
auto diff_iter_mem_arg
= utils::downcast<const xpu::sycl::memory_storage_base_t *>(
diff_cell_iter.get())
->get_in_memory_arg(ctx.stream(), cgh);
auto scratch_diff_gates_mem_arg
= utils::downcast<const xpu::sycl::memory_storage_base_t *>(
diff_gates.get())
->get_out_memory_arg(ctx.stream(), cgh);
auto diff_bias_mem_arg
= utils::downcast<const xpu::sycl::memory_storage_base_t *>(
user_data.diff_bias(n_layer - lay - 1, dir).get())
->get_inout_memory_arg(ctx.stream(), cgh);
ref_rnn_bias_bwd bias_kernel(pd()->sycl_rnn_bias_bwd_conf_t_,
gates_mem_arg, diff_lay_mem_arg, diff_iter_mem_arg,
scratch_diff_gates_mem_arg, diff_bias_mem_arg);
size_t local_batch = max_wg_size_per_dim;
size_t local_channel = max_wg_size_per_dim;
size_t global_batch
= calc_global_range(static_cast<size_t>(max_wg_size_per_dim),
static_cast<size_t>(batch));
size_t global_channels
= calc_global_range(static_cast<size_t>(max_wg_size_per_dim),
static_cast<size_t>(dhc));
cgh.parallel_for(
::sycl::nd_range<3>(
::sycl::range<3>(global_channels, global_batch, 1),
::sycl::range<3>(local_channel, local_batch, 1)),
bias_kernel);
});
return status::success;
}
void ref_rnn_common_base_t::debug_print(const rnn_utils::conf_t &rnn, dim_t slc,
dim_t sic, bool with_bias, bool with_dst_iter) const {
DPRINT("\n%s\n", "+++++++++++++++");
DPRINT("%s\n", "+++++++++++++++");
DPRINT(" n_layer = %lld\n", static_cast<long long>(rnn.n_layer));
DPRINT(" n_dir = %lld\n", static_cast<long long>(rnn.n_dir));
DPRINT(" n_iter = %lld\n", static_cast<long long>(rnn.n_iter));
DPRINT(" n_gates = %lld\n", static_cast<long long>(rnn.n_gates));
DPRINT(" n_bias = %lld\n", static_cast<long long>(rnn.n_bias));
DPRINT(" n_weights_layer = %lld\n", static_cast<long long>(slc));
DPRINT(" n_weights_iter = %lld\n", static_cast<long long>(sic));
DPRINT(" batch = %lld\n", static_cast<long long>(rnn.mb));
DPRINT(" slc = %lld\n", static_cast<long long>(rnn.slc));
DPRINT(" sic = %lld\n", static_cast<long long>(rnn.sic));
DPRINT(" dhc = %lld\n", static_cast<long long>(rnn.dhc));
DPRINT(" dlc = %lld\n", static_cast<long long>(rnn.dlc));
DPRINT("%s\n", "+++++++++++++++");
DPRINT(" use_workspace = %s\n", rnn.use_workspace ? "yes" : "no");
DPRINT("%s\n", "+++++++++++++++");
DPRINT(" with_bias = %s\n", with_bias ? "yes" : "no");
DPRINT(" with_dst_iter = %s\n", with_dst_iter ? "yes" : "no");
DPRINT("%s\n", "+++++++++++++++");
}
void ref_rnn_common_base_t::get_user_data(const exec_ctx_t &ctx,
rnn_utils::user_data_t &user_data, cpy_ctx_t &cpy_ctx, bool is_fwd,
const rnn_pd_t *pd) const {
auto &src_layer_native_ = CTX_IN_STORAGE(DNNL_ARG_SRC_LAYER);
auto &src_iter_native_ = CTX_IN_STORAGE(DNNL_ARG_SRC_ITER);
auto &wei_layer_native_ = CTX_IN_STORAGE(DNNL_ARG_WEIGHTS_LAYER);
auto &wei_iter_native_ = CTX_IN_STORAGE(DNNL_ARG_WEIGHTS_ITER);
auto &bias_native_ = CTX_IN_STORAGE(DNNL_ARG_BIAS);
auto &dst_last_layer_native_ = is_fwd ? CTX_OUT_STORAGE(DNNL_ARG_DST_LAYER)
: CTX_IN_STORAGE(DNNL_ARG_DST_LAYER);
auto &dst_last_iter_native_ = is_fwd ? CTX_OUT_STORAGE(DNNL_ARG_DST_ITER)
: CTX_IN_STORAGE(DNNL_ARG_DST_ITER);
auto &diff_dst_layer_native_ = CTX_IN_STORAGE(DNNL_ARG_DIFF_DST_LAYER);
auto &diff_dst_iter_native_ = CTX_IN_STORAGE(DNNL_ARG_DIFF_DST_ITER);
auto &diff_src_layer_native_ = CTX_OUT_STORAGE(DNNL_ARG_DIFF_SRC_LAYER);
auto &diff_src_iter_native_ = CTX_OUT_STORAGE(DNNL_ARG_DIFF_SRC_ITER);
auto &diff_weights_layer_native_
= CTX_OUT_STORAGE(DNNL_ARG_DIFF_WEIGHTS_LAYER);
auto &diff_weights_iter_native_
= CTX_OUT_STORAGE(DNNL_ARG_DIFF_WEIGHTS_ITER);
auto &diff_bias_native_ = CTX_OUT_STORAGE(DNNL_ARG_DIFF_BIAS);
user_data = rnn_utils::user_data_t(wei_layer_native_, pd->weights_md(0),
diff_weights_layer_native_, pd->diff_weights_md(0),
wei_iter_native_, pd->weights_md(1), diff_weights_iter_native_,
pd->diff_weights_md(1), bias_native_, pd->weights_md(2),
diff_bias_native_, pd->diff_weights_md(2));
if (is_fwd) {
cpy_ctx.cpy_in_lay = &src_layer_native_;
cpy_ctx.cpy_in_iter = &src_iter_native_;
cpy_ctx.cpy_out_lay = &dst_last_layer_native_;
cpy_ctx.cpy_out_iter = &dst_last_iter_native_;
} else {
cpy_ctx.cpy_in_lay = &diff_dst_layer_native_;
cpy_ctx.cpy_in_iter = &diff_dst_iter_native_;
cpy_ctx.cpy_out_lay = &diff_src_layer_native_;
cpy_ctx.cpy_out_iter = &diff_src_iter_native_;
}
}
status_t ref_rnn_fwd_t::execute_(const exec_ctx_t &ctx) const {
impl::engine_t *engine = ctx.stream()->engine();
const conf_t &rnn = this->pd()->rnn_conf;
if (get_verbose_dev_mode(verbose_t::debuginfo) >= 2) {
debug_print(rnn, this->pd()->SLC(), this->pd()->SIC(),
this->pd()->with_bias(), this->pd()->with_dst_iter());
}
auto scratch_workspace
= ctx.get_scratchpad_grantor().get_memory_storage(key_rnn_space);
auto &workspace_ = rnn.is_training ? CTX_OUT_STORAGE(DNNL_ARG_WORKSPACE)
: *scratch_workspace;
const auto &workspace = rnn_utils::workspace_t(workspace_, rnn);
const auto scratch
= rnn_utils::scratch_t(rnn, ctx.get_scratchpad_grantor());
rnn_utils::user_data_t user_data;
cpy_ctx_t cpy_ctx;
get_user_data(ctx, user_data, cpy_ctx, true, this->pd());
CHECK(copy_init_layer(ctx, rnn.mb, rnn.dhc, rnn.sic, rnn.slc, rnn.n_iter,
rnn.n_layer, rnn.n_dir, rnn.states_ws_ld, *cpy_ctx.cpy_in_lay,
workspace.states()));
CHECK(copy_init_iter(ctx, rnn.mb, rnn.dhc, rnn.sic, rnn.slc, rnn.n_iter,
rnn.n_layer, rnn.n_dir, rnn.states_ws_ld, *cpy_ctx.cpy_in_iter,
workspace.states()));
const grid_ctx_t &grid_struct {
engine, ctx, user_data, workspace, scratch, pd()->rnn_conf};
CHECK(this->grid_func(grid_struct));
CHECK(copy_res_layer(ctx, rnn.mb, rnn.dhc, rnn.sic, rnn.slc, rnn.n_iter,
rnn.n_layer, rnn.n_dir, rnn.states_ws_ld, workspace.states(),
*cpy_ctx.cpy_out_lay));
CHECK(copy_res_iter(ctx, rnn.mb, rnn.dhc, rnn.sic, rnn.slc, rnn.n_iter,
rnn.n_layer, rnn.n_dir, rnn.states_ws_ld, workspace.states(),
*cpy_ctx.cpy_out_iter));
return status::success;
}
status_t ref_rnn_bwd_t::execute_(const exec_ctx_t &ctx) const {
impl::engine_t *engine = ctx.stream()->engine();
const conf_t &rnn = this->pd()->rnn_conf;
if (get_verbose_dev_mode(verbose_t::debuginfo) >= 2) {
debug_print(rnn, this->pd()->SLC(), this->pd()->SIC(),
this->pd()->with_bias(), this->pd()->with_dst_iter());
}
auto scratch_workspace
= ctx.get_scratchpad_grantor().get_memory_storage(key_rnn_space);
auto &workspace_ = CTX_IN_STORAGE(DNNL_ARG_WORKSPACE);
const auto &workspace = rnn_utils::workspace_t(workspace_, rnn);
const auto scratch
= rnn_utils::scratch_t(rnn, ctx.get_scratchpad_grantor());
rnn_utils::user_data_t user_data;
cpy_ctx_t cpy_ctx;
get_user_data(ctx, user_data, cpy_ctx, false, this->pd());
CHECK(copy_init_layer(ctx, rnn.mb, rnn.dhc, rnn.sic, rnn.slc, rnn.n_iter,
rnn.n_layer, rnn.n_dir, rnn.scratch_diff_states_ld,
*cpy_ctx.cpy_in_lay, scratch.diff_states()));
CHECK(copy_init_iter(ctx, rnn.mb, rnn.dhc, rnn.sic, rnn.slc, rnn.n_iter,
rnn.n_layer, rnn.n_dir, rnn.scratch_diff_states_ld,
*cpy_ctx.cpy_in_iter, scratch.diff_states()));
const grid_ctx_t &grid_struct {
engine, ctx, user_data, workspace, scratch, pd()->rnn_conf};
CHECK(this->grid_func(grid_struct));
CHECK(copy_res_layer(ctx, rnn.mb, rnn.dhc, rnn.sic, rnn.slc, rnn.n_iter,
rnn.n_layer, rnn.n_dir, rnn.scratch_diff_states_ld,
scratch.diff_states(), *cpy_ctx.cpy_out_lay));
CHECK(copy_res_iter(ctx, rnn.mb, rnn.dhc, rnn.sic, rnn.slc, rnn.n_iter,
rnn.n_layer, rnn.n_dir, rnn.scratch_diff_states_ld,
scratch.diff_states(), *cpy_ctx.cpy_out_iter));
return status::success;
}
} } } } }