libmir-cuda 0.1.0

CUDA inference backend for libmir
use mircuda::{DeviceBuffer, LaunchConfig, Stream, bf16};

use super::{Fp8OutputKernels, Fp8ResidualWeightBuffers};
use crate::{Result, kernels::geometry::narrow};

impl Fp8OutputKernels {
    pub fn quantize_weight_residual(
        &self,
        stream: &Stream,
        source: &DeviceBuffer<bf16>,
        buffers: &mut Fp8ResidualWeightBuffers<'_>,
    ) -> Result<()> {
        super::require("residual output source", self.spec.weight_elements()?, source.len())?;
        super::require(
            "residual output block scales",
            self.spec.weight_scale_elements()?,
            buffers.block_scales.len(),
        )?;
        self.validate_storage(
            buffers.weight,
            buffers.row_scales,
            buffers.residual,
            buffers.residual_scales,
        )?;
        self.quantize_weight(
            stream,
            source,
            buffers.weight,
            buffers.block_scales,
            buffers.row_scales,
        )?;
        Ok(self.quantize_residual.launch(
            stream,
            LaunchConfig {
                grid: (
                    narrow(self.spec.output_features)?,
                    narrow(self.spec.input_features / 128)?,
                    1,
                ),
                block: (128, 1, 1),
                shared_memory_bytes: 0,
            },
            (
                source,
                buffers.weight,
                buffers.row_scales,
                buffers.residual,
                buffers.residual_scales,
                narrow(self.spec.output_features)?,
                narrow(self.spec.input_features)?,
            ),
        )?)
    }

    #[allow(clippy::too_many_arguments)]
    pub fn project_residual(
        &self,
        stream: &Stream,
        input: &DeviceBuffer<bf16>,
        weight: &DeviceBuffer<u8>,
        row_scales: &DeviceBuffer<f32>,
        residual: &DeviceBuffer<u8>,
        residual_scales: &DeviceBuffer<f32>,
        output: &mut DeviceBuffer<bf16>,
    ) -> Result<()> {
        super::require("residual output input", self.spec.input_features, input.len())?;
        self.validate_storage(weight, row_scales, residual, residual_scales)?;
        super::require("residual output logits", self.spec.output_features, output.len())?;
        Ok(self.residual.launch(
            stream,
            LaunchConfig {
                grid: (narrow(self.spec.output_features.div_ceil(64))?, 1, 1),
                block: (256, 1, 1),
                shared_memory_bytes: 0,
            },
            (
                input,
                weight,
                row_scales,
                residual,
                residual_scales,
                output,
                narrow(self.spec.output_features)?,
                narrow(self.spec.input_features)?,
            ),
        )?)
    }

    fn validate_storage(
        &self,
        weight: &DeviceBuffer<u8>,
        row_scales: &DeviceBuffer<f32>,
        residual: &DeviceBuffer<u8>,
        residual_scales: &DeviceBuffer<f32>,
    ) -> Result<()> {
        super::require("residual output weight", self.spec.weight_elements()?, weight.len())?;
        super::require("residual output row scales", self.spec.output_features, row_scales.len())?;
        super::require(
            "residual output correction",
            self.spec.residual_elements()?,
            residual.len(),
        )?;
        super::require(
            "residual output scales",
            self.spec.residual_scale_elements()?,
            residual_scales.len(),
        )
    }
}