libmir-cuda 0.2.0

CUDA inference backend for libmir
mod execution;

use models::layout::SpatialMergeVisionConfig;

use super::super::{
    super::super::CudaBackend,
    linear::{VisionLinear, required},
};
use crate::{
    CudaTensor, CudaTensorSet, Result,
    kernels::{
        SpatialMergeKernels, VisionAttention, VisionAttentionSpec, VisionElementwise,
        VisionElementwiseSpec,
    },
};

#[derive(Debug)]
pub(super) struct SpatialMergeLayer {
    backend: CudaBackend,
    norm1_weight: CudaTensor,
    norm1_bias: CudaTensor,
    norm2_weight: CudaTensor,
    norm2_bias: CudaTensor,
    qkv: VisionLinear,
    projection: VisionLinear,
    fc1: VisionLinear,
    fc2: VisionLinear,
    elementwise_hidden: VisionElementwise,
    elementwise_intermediate: VisionElementwise,
    attention: VisionAttention,
    kernels: SpatialMergeKernels,
    tokens: usize,
    heads: usize,
    head_dim: usize,
}

impl SpatialMergeLayer {
    pub(super) fn new(
        backend: &CudaBackend,
        config: &SpatialMergeVisionConfig,
        tensors: &CudaTensorSet,
        prefix: &str,
        index: usize,
        tokens: usize,
        kernels: SpatialMergeKernels,
    ) -> Result<Self> {
        let layer = format!("{prefix}.blocks.{index}");
        let linear = |name: &str, input, output| {
            VisionLinear::new(backend, tensors, name, tokens, input, output, false)
        };
        let compiler = &backend.inner.compiler;
        let head_dim = config.hidden_size / config.num_attention_heads;
        let scale = 1.0 / head_dim.to_string().parse::<f32>()?.sqrt();
        Ok(Self {
            backend: backend.clone(),
            norm1_weight: required(tensors, &format!("{layer}.norm1.weight"))?,
            norm1_bias: required(tensors, &format!("{layer}.norm1.bias"))?,
            norm2_weight: required(tensors, &format!("{layer}.norm2.weight"))?,
            norm2_bias: required(tensors, &format!("{layer}.norm2.bias"))?,
            qkv: linear(&format!("{layer}.attn.qkv"), config.hidden_size, 3 * config.hidden_size)?,
            projection: linear(
                &format!("{layer}.attn.proj"),
                config.hidden_size,
                config.hidden_size,
            )?,
            fc1: linear(
                &format!("{layer}.mlp.linear_fc1"),
                config.hidden_size,
                config.intermediate_size,
            )?,
            fc2: linear(
                &format!("{layer}.mlp.linear_fc2"),
                config.intermediate_size,
                config.hidden_size,
            )?,
            elementwise_hidden: VisionElementwise::compile(
                compiler,
                VisionElementwiseSpec {
                    rows: tokens,
                    columns: config.hidden_size,
                    epsilon: 1.0e-6,
                },
            )?,
            elementwise_intermediate: VisionElementwise::compile(
                compiler,
                VisionElementwiseSpec {
                    rows: tokens,
                    columns: config.intermediate_size,
                    epsilon: 0.0,
                },
            )?,
            attention: VisionAttention::compile(
                compiler,
                VisionAttentionSpec {
                    tokens,
                    query_heads: config.num_attention_heads,
                    kv_heads: config.num_attention_heads,
                    head_dim,
                    scale,
                },
            )?,
            kernels,
            tokens,
            heads: config.num_attention_heads,
            head_dim,
        })
    }
}