#ifndef GPU_NVIDIA_CUDNN_ELTWISE_IMPL_HPP
#define GPU_NVIDIA_CUDNN_ELTWISE_IMPL_HPP
#include "cudnn.h"
#include "gpu/nvidia/sycl_cuda_utils.hpp"
namespace dnnl {
namespace impl {
namespace gpu {
namespace nvidia {
struct cudnn_eltwise_impl_base_t {
public:
virtual void execute(cudnnHandle_t handle, void **x, int size) const = 0;
virtual status_t create_and_set_act_descriptor() {
CHECK(CUDNN_EXECUTE_FUNC_S(
cudnnCreateActivationDescriptor, &act_desc_));
CHECK(CUDNN_EXECUTE_FUNC_S(cudnnSetActivationDescriptor, act_desc_,
alg_kind, cudnnNanPropagation_t::CUDNN_PROPAGATE_NAN, coef));
return status::success;
}
status_t convert_alg_kind(
alg_kind_t alg_kind, cudnnActivationMode_t *cuda_alg_kind) const {
switch (alg_kind) {
case alg_kind::eltwise_relu:
*cuda_alg_kind = cudnnActivationMode_t::CUDNN_ACTIVATION_RELU;
break;
case alg_kind::eltwise_tanh:
*cuda_alg_kind = cudnnActivationMode_t::CUDNN_ACTIVATION_TANH;
break;
case alg_kind::eltwise_elu:
*cuda_alg_kind = cudnnActivationMode_t::CUDNN_ACTIVATION_ELU;
break;
case alg_kind::eltwise_logistic:
*cuda_alg_kind
= cudnnActivationMode_t::CUDNN_ACTIVATION_SIGMOID;
break;
default: return status::unimplemented;
}
return status::success;
}
virtual ~cudnn_eltwise_impl_base_t() {
if (act_desc_) {
CUDNN_EXECUTE_FUNC_V(cudnnDestroyActivationDescriptor, act_desc_);
}
}
protected:
int ndims;
cudnnActivationDescriptor_t act_desc_ = nullptr;
cudnnActivationMode_t alg_kind;
float alpha = 1;
float beta = 0;
double coef = 0;
};
struct cudnn_eltwise_fwd_impl_t : public cudnn_eltwise_impl_base_t {
public:
status_t init(const eltwise_fwd_pd_t *pd) {
if (has_zero_dims(pd->src_md()->dims, pd->ndims())) {
return status::success;
}
if (pd->ndims() > CUDNN_DIM_MAX) { return status::invalid_arguments; }
ndims = pd->ndims() < 4 ? 4 : pd->ndims();
for (int i = 0; i < ndims; ++i) {
if (pd->src_md()->padded_dims[i]
> std::numeric_limits<int>::max()) {
return status::unimplemented;
}
}
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;
CHECK(convert_alg_kind(alg, &alg_kind));
coef = pd->desc()->alpha;
CHECK(create_and_set_tensor_descriptor(
&tensor_desc_, data_type_, ndims, dims_, strides_));
CHECK(create_and_set_act_descriptor());
return status::success;
}
void execute(cudnnHandle_t handle, void **x, int size) const override {
assert(size == 2);
CUDNN_EXECUTE_FUNC(cudnnActivationForward, handle, act_desc_, &alpha,
tensor_desc_, x[0], &beta, tensor_desc_, x[1]);
}
~cudnn_eltwise_fwd_impl_t() {
CUDNN_EXECUTE_FUNC_V(cudnnDestroyTensorDescriptor, tensor_desc_);
}
private:
int strides_[DNNL_MAX_NDIMS];
int dims_[DNNL_MAX_NDIMS];
cudnnDataType_t data_type_;
cudnnTensorDescriptor_t tensor_desc_;
};
struct cudnn_eltwise_bwd_impl_t : public cudnn_eltwise_impl_base_t {
public:
status_t init(const eltwise_bwd_pd_t *pd) {
if (memory_desc_wrapper(pd->data_md()).has_zero_dim())
return status::success;
if (pd->ndims() > CUDNN_DIM_MAX) { return status::invalid_arguments; }
ndims = pd->ndims() < 4 ? 4 : pd->ndims();
for (int i = 0; i < ndims; ++i) {
if (pd->src_md()->padded_dims[i]
> std::numeric_limits<int>::max()) {
return status::unimplemented;
}
}
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;
CHECK(convert_alg_kind(alg, &alg_kind));
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_));
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(cudnnHandle_t handle, void **x, int size) const override {
assert(size == 3);
void *dy = x[1];
void *dx = x[2];
CUDNN_EXECUTE_FUNC(cudnnActivationBackward, handle, act_desc_, &alpha,
tensor_desc_src_, x[0], tensor_diff_desc_, dy, tensor_desc_src_,
x[0], &beta, tensor_diff_desc_, dx);
}
~cudnn_eltwise_bwd_impl_t() {
CUDNN_EXECUTE_FUNC_V(cudnnDestroyTensorDescriptor, tensor_desc_src_);
CUDNN_EXECUTE_FUNC_V(cudnnDestroyTensorDescriptor, tensor_diff_desc_);
}
private:
int dims_[DNNL_MAX_NDIMS];
int strides_[DNNL_MAX_NDIMS];
cudnnTensorDescriptor_t tensor_diff_desc_;
cudnnDataType_t data_type_;
cudnnTensorDescriptor_t tensor_desc_src_;
};
} } } }
#endif