use cudarc::driver::{CudaStream, LaunchConfig, PushKernelArg};
use tract_core::internal::*;
use tract_gpu::tensor::DeviceTensor;
use crate::context::{TractCudaStream, cuda_context};
use crate::kernels::launch_args::TractLaunchArgs;
use crate::kernels::{LibraryName, get_cuda_view};
#[derive(Debug, Clone, Default, PartialEq)]
pub struct LeakyRelu;
impl LeakyRelu {
pub fn is_supported_dt(dt: DatumType) -> bool {
matches!(dt, DatumType::F32 | DatumType::F16)
}
pub fn kernel_name(&self, dt: DatumType) -> TractResult<String> {
ensure!(Self::is_supported_dt(dt), "Unsupported dt {:?} for cuda geluop", dt);
let tname = DeviceTensor::tname(dt)?;
Ok(format!("leaky_relu_{tname}"))
}
pub fn eval(
&self,
stream: &TractCudaStream,
input: &DeviceTensor,
alpha: f32,
) -> TractResult<DeviceTensor> {
let output = unsafe { DeviceTensor::uninitialized_dt(input.datum_type(), input.shape())? };
self.dispatch_eval(stream, input, alpha, &output)?;
stream.synchronize()?;
Ok(output)
}
pub fn dispatch_eval(
&self,
stream: &TractCudaStream,
input: &DeviceTensor,
alpha: f32,
output: &DeviceTensor,
) -> TractResult<()> {
ensure!(output.shape() == input.shape());
ensure!(output.datum_type() == input.datum_type());
let kernel_name = self.kernel_name(input.datum_type())?;
let i_view = get_cuda_view(input);
let o_view = get_cuda_view(output);
let len = output.len();
let func = cuda_context().load_pipeline(LibraryName::NN, kernel_name)?;
let mut launch_args = TractLaunchArgs::new(stream, &func);
launch_args.push_view(&i_view);
launch_args.push_view(&o_view);
launch_args.push_i32(len);
launch_args.push::<f32>(alpha);
let cfg = LaunchConfig::for_num_elems(input.len() as _);
unsafe {
launch_args.launch(cfg);
}
Ok(())
}
}
pub fn cuda_leaky_relu_dispatch(
alpha: f32,
input: &DeviceTensor,
output: &DeviceTensor,
) -> TractResult<()> {
crate::with_cuda_stream(|stream| LeakyRelu.dispatch_eval(stream, input, alpha, output))
}
crate::register_cuda_op!(tract_core::ops::element_wise::ElementWiseOp, |_source, _node, op| {
rule_if_some!(leaky = op.0.downcast_ref::<tract_core::ops::nn::LeakyRelu>());
Ok(Some(Box::new(tract_gpu::ops::leaky_relu::GpuLeakyRelu::new(
leaky.alpha,
"Cuda",
cuda_leaky_relu_dispatch,
))))
});