libmir-cuda 0.2.0

CUDA inference backend for libmir
use mircuda::{
    CompileOptions, Compiler, DeviceBuffer, LaunchConfig, Stream, TypedKernel, bf16, cuda_export,
    cuda_kernel_file,
};

use super::geometry::{narrow, product, require};
use crate::{Error, Result};

cuda_export!(
    SplitKernel = "libmir_cuda_gated_attention_split_bf16"(
        input: &DeviceBuffer<bf16>, query: &mut DeviceBuffer<bf16>,
        gate: &mut DeviceBuffer<bf16>, elements: u32, heads: u32, head_dim: u32,
    )
);

#[derive(Clone, Debug)]
pub struct GatedAttentionSplit {
    kernel: TypedKernel<SplitKernel>,
    tokens: usize,
    heads: usize,
    head_dim: usize,
}

impl GatedAttentionSplit {
    pub fn compile(
        compiler: &Compiler,
        tokens: usize,
        heads: usize,
        head_dim: usize,
    ) -> Result<Self> {
        if tokens == 0 || heads == 0 || head_dim == 0 {
            return Err(Error::InvalidDecoderKernel("empty gated attention split"));
        }
        let source = cuda_kernel_file!("../../kernels/gated_attention_bf16.cu");
        let module = compiler.compile(source, &CompileOptions::default())?;
        Ok(Self {
            kernel: module.kernel()?,
            tokens,
            heads,
            head_dim,
        })
    }

    pub fn execute(
        &self,
        stream: &Stream,
        input: &DeviceBuffer<bf16>,
        query: &mut DeviceBuffer<bf16>,
        gate: &mut DeviceBuffer<bf16>,
    ) -> Result<()> {
        let width = product(self.heads, self.head_dim)?;
        let elements = product(self.tokens, width)?;
        require("gated query projection", product(elements, 2)?, input.len())?;
        require("gated query", elements, query.len())?;
        require("attention output gate", elements, gate.len())?;
        let threads = 256_usize;
        Ok(self.kernel.launch(
            stream,
            LaunchConfig {
                grid: (narrow(elements.div_ceil(threads))?, 1, 1),
                block: (narrow(threads)?, 1, 1),
                shared_memory_bytes: 0,
            },
            (
                input,
                query,
                gate,
                narrow(elements)?,
                narrow(self.heads)?,
                narrow(self.head_dim)?,
            ),
        )?)
    }
}