#ifndef GPU_AMD_MIOPEN_ELTWISE_IMPL_HPP
#define GPU_AMD_MIOPEN_ELTWISE_IMPL_HPP
#include <gpu/amd/engine.hpp>
#include <gpu/amd/sycl_hip_utils.hpp>
#include <miopen/miopen.h>
namespace dnnl {
namespace impl {
namespace gpu {
namespace amd {
struct miopen_eltwise_impl_base_t {
public:
virtual status_t init(const eltwise_pd_t *pd) = 0;
virtual void execute(miopenHandle_t handle, void **x, int size) const = 0;
virtual status_t create_and_set_act_descriptor() {
CHECK(MIOPEN_EXECUTE_FUNC_S(
miopenCreateActivationDescriptor, &act_desc_));
CHECK(MIOPEN_EXECUTE_FUNC_S(miopenSetActivationDescriptor, act_desc_,
alg_kind, activAlpha, activBeta, activGamma));
return status::success;
}
status_t convert_alg_kind(alg_kind_t alg_kind,
miopenActivationMode_t *miopen_alg_kind) const {
switch (alg_kind) {
case alg_kind::eltwise_relu:
*miopen_alg_kind
= miopenActivationMode_t::miopenActivationLEAKYRELU;
break;
case alg_kind::eltwise_tanh:
*miopen_alg_kind = miopenActivationMode_t::miopenActivationTANH;
break;
case alg_kind::eltwise_elu:
*miopen_alg_kind = miopenActivationMode_t::miopenActivationELU;
break;
case alg_kind::eltwise_logistic:
*miopen_alg_kind
= miopenActivationMode_t::miopenActivationLOGISTIC;
break;
case alg_kind::eltwise_abs:
*miopen_alg_kind = miopenActivationMode_t::miopenActivationABS;
break;
case alg_kind::eltwise_soft_relu:
*miopen_alg_kind
= miopenActivationMode_t::miopenActivationSOFTRELU;
break;
default: return status::unimplemented;
}
return status::success;
}
virtual ~miopen_eltwise_impl_base_t() {
if (act_desc_) {
MIOPEN_EXECUTE_FUNC_V(miopenDestroyActivationDescriptor, act_desc_);
}
}
protected:
int ndims;
miopenActivationDescriptor_t act_desc_ = nullptr;
miopenActivationMode_t alg_kind;
float alpha = 1;
float beta = 0;
double coef = 1;
float activAlpha;
float activBeta;
float activGamma;
};
struct miopen_eltwise_fwd_impl_t : public miopen_eltwise_impl_base_t {
public:
status_t init(const eltwise_pd_t *pd) override {
if (has_zero_dims(pd->src_md()->dims, pd->ndims())) {
return status::success;
}
if (pd->ndims() > MIOPEN_DIM_MAX) { return status::invalid_arguments; }
ndims = pd->ndims() < 4 ? 4 : pd->ndims();
convert_dims(pd->src_md()->padded_dims, dims_, pd->ndims());
convert_dims(pd->src_md()->format_desc.blocking.strides, strides_,
pd->ndims());
CHECK(convert_data_type(pd->src_md(), &data_type_));
alg_kind_t alg = pd->desc()->alg_kind;
auto alg_ok = convert_alg_kind(alg, &alg_kind);
if (alg_ok != status::success) { return status::unimplemented; }
coef = pd->desc()->alpha;
if (alg_kind == miopenActivationMode_t::miopenActivationTANH)
activAlpha = activBeta = 1;
else if (alg_kind == miopenActivationMode_t::miopenActivationELU)
activAlpha = coef;
else if (alg_kind
== miopenActivationMode_t::miopenActivationCLIPPEDRELU)
activAlpha = coef;
else if (alg_kind == miopenActivationMode_t::miopenActivationLEAKYRELU)
activAlpha = coef;
CHECK(create_and_set_tensor_descriptor(
&tensor_desc_, data_type_, ndims, dims_, strides_));
CHECK(create_and_set_act_descriptor());
return status::success;
}
void execute(miopenHandle_t handle, void **x, int size) const override {
assert(size == 2);
MIOPEN_EXECUTE_FUNC(miopenActivationForward, handle, act_desc_, &alpha,
tensor_desc_, x[0], &beta, tensor_desc_, x[1]);
}
~miopen_eltwise_fwd_impl_t() {
MIOPEN_EXECUTE_FUNC_V(miopenDestroyTensorDescriptor, tensor_desc_);
}
private:
int strides_[DNNL_MAX_NDIMS];
int dims_[DNNL_MAX_NDIMS];
miopenDataType_t data_type_;
miopenTensorDescriptor_t tensor_desc_;
};
struct miopen_eltwise_bwd_impl_t : public miopen_eltwise_impl_base_t {
public:
status_t init(const eltwise_pd_t *pd) override {
if (memory_desc_wrapper(pd->src_md()).has_zero_dim())
return status::success;
if (pd->ndims() > MIOPEN_DIM_MAX) { return status::invalid_arguments; }
ndims = pd->ndims() < 4 ? 4 : pd->ndims();
convert_dims(pd->src_md()->padded_dims, dims_, pd->ndims());
convert_dims(pd->src_md()->format_desc.blocking.strides, strides_,
pd->ndims());
alg_kind_t alg = pd->desc()->alg_kind;
auto alg_ok = convert_alg_kind(alg, &alg_kind);
if (alg_ok != status::success) { return status::unimplemented; }
coef = pd->desc()->alpha;
assert(pd->diff_dst_md()->data_type == pd->src_md()->data_type);
assert(pd->diff_dst_md()->data_type == pd->diff_src_md()->data_type);
CHECK(convert_data_type(pd->src_md(), &data_type_));
if (alg_kind == miopenActivationMode_t::miopenActivationCLIPPEDRELU)
activAlpha = coef;
else if (alg_kind == miopenActivationMode_t::miopenActivationLEAKYRELU)
activAlpha = coef;
CHECK(create_and_set_tensor_descriptor(
&tensor_desc_src_, data_type_, ndims, dims_, strides_));
CHECK(create_and_set_tensor_descriptor(
&tensor_diff_desc_, data_type_, ndims, dims_, strides_));
CHECK(create_and_set_act_descriptor());
return status::success;
}
void execute(miopenHandle_t handle, void **x, int size) const override {
assert(size == 3);
void *dy = x[1];
void *dx = x[2];
MIOPEN_EXECUTE_FUNC(miopenActivationBackward, handle, act_desc_, &alpha,
tensor_desc_src_, x[0], tensor_diff_desc_, dy, tensor_desc_src_,
x[0], &beta, tensor_diff_desc_, dx);
}
~miopen_eltwise_bwd_impl_t() {
MIOPEN_EXECUTE_FUNC_V(miopenDestroyTensorDescriptor, tensor_desc_src_);
MIOPEN_EXECUTE_FUNC_V(miopenDestroyTensorDescriptor, tensor_diff_desc_);
}
private:
int dims_[DNNL_MAX_NDIMS];
int strides_[DNNL_MAX_NDIMS];
miopenTensorDescriptor_t tensor_diff_desc_;
miopenDataType_t data_type_;
miopenTensorDescriptor_t tensor_desc_src_;
};
} } } }
#endif