libmir-metal 0.2.0

Metal inference backend for libmir
use super::{attention::VisionAttention, mlp::VisionMlp};
use crate::engine::{Array, LayerNorm, ModelTensors, Result, Stream};

#[derive(Debug)]
pub(super) struct EncoderLayer {
    attention_norm: LayerNorm,
    attention: VisionAttention,
    mlp_norm: LayerNorm,
    mlp: VisionMlp,
}

impl EncoderLayer {
    pub(super) fn load(
        tensors: &ModelTensors,
        prefix: &str,
        heads: usize,
        head_dim: usize,
        stream: &Stream,
    ) -> Result<Self> {
        Ok(Self {
            attention_norm: LayerNorm::load(tensors, &format!("{prefix}.norm1"), 1.0e-6)?,
            attention: VisionAttention::load(
                tensors,
                &format!("{prefix}.attn"),
                heads,
                head_dim,
                stream,
            )?,
            mlp_norm: LayerNorm::load(tensors, &format!("{prefix}.norm2"), 1.0e-6)?,
            mlp: VisionMlp::load(tensors, &format!("{prefix}.mlp"), stream)?,
        })
    }

    pub(super) fn forward(
        &self,
        input: &Array,
        positions: &Array,
        stream: &Stream,
    ) -> Result<Array> {
        let attention = self.attention.forward(
            &self.attention_norm.forward(input, stream)?,
            positions,
            stream,
        )?;
        let hidden = input.add(&attention, stream)?;
        hidden.add(&self.mlp.forward(&self.mlp_norm.forward(&hidden, stream)?, stream)?, stream)
    }
}