use crate::error::Result;
use crate::gguf::Gguf;
use crate::gpu::{Buffer, Epilogue, Gpu, Linear, Pass};
use crate::transformer::{self, Encoder as Blocks};
pub struct Config {
pub mels: usize,
pub frames: usize,
}
pub struct Encoder {
pub cfg: Config,
conv0: Linear,
conv1: Linear,
pub positions: Vec<f32>,
pub blocks: Blocks,
}
pub struct Buffers {
pub mel: Buffer,
pub t: transformer::Buffers,
}
impl Encoder {
pub fn load(gpu: &Gpu, g: &Gguf, cfg: Config, blocks: transformer::Config) -> Result<Self> {
let d = blocks.d;
let conv = |name: &str, ch: usize| {
let bias = g.tensor(&format!("{name}.bias"), &[d])?.to_f32()?;
gpu.conv(g.tensor(&format!("{name}.weight"), &[3, ch, d])?, &bias)
};
Ok(Self {
conv0: conv("enc.conv.0", cfg.mels)?,
conv1: conv("enc.conv.1", d)?,
positions: g.tensor("enc.pos_emb.weight", &[d, cfg.frames])?.to_f32()?,
blocks: Blocks::load(gpu, g, blocks)?,
cfg,
})
}
pub fn buffers(&self, gpu: &Gpu) -> Buffers {
let (c, b) = (&self.cfg, &self.blocks.cfg);
let rows = c.frames.next_multiple_of(64);
Buffers {
mel: gpu.buffer(2 * c.frames * c.mels),
t: transformer::Buffers {
x: gpu.buffer(rows * b.d),
y: gpu.buffer(rows * b.d),
qkv: gpu.buffer((rows * 3 * b.d).max(2 * c.frames * (3 * c.mels).next_multiple_of(32))),
h: gpu.buffer(c.frames * b.d_ff.max(2 * b.d)),
s: gpu.buffer(gpu.scores_len(c.frames, b.heads, b.head_dim(), false)),
},
}
}
pub fn record(&self, p: &mut Pass, b: &Buffers, t: usize) {
let (d, mels, a) = (self.blocks.cfg.d, self.cfg.mels, &b.t);
p.im2col(&b.mel, &a.qkv, 2 * t, mels, [3, 1, 1]);
p.gemm(&a.qkv, &self.conv0, &a.h, 2 * t, Epilogue::Gelu);
p.im2col(&a.h, &a.qkv, 2 * t, d, [3, 2, 1]);
p.gemm(&a.qkv, &self.conv1, &a.x, t, Epilogue::GeluResidual);
self.blocks.record(p, a, t, None);
}
}