use crate::error::Result;
use crate::gguf::Gguf;
use crate::gpu::{Buffer, Channels, Epilogue, Gpu, Linear, Pass};
use crate::transformer::{self, Encoder as Blocks};
pub const STEM: [(usize, usize); 3] = [(127, 64), (7, 3), (3, 2)];
pub struct Encoder {
conv0: Linear,
norm: Channels,
eps: f32,
conv1: Linear,
conv2: Linear,
pub blocks: Blocks,
}
pub struct Buffers {
pub samples: usize,
pub pcm: Buffer,
cols: Buffer,
conv: Buffer,
pub t: transformer::Buffers,
}
pub fn frames(n: usize) -> [usize; 3] {
let mut t = n;
STEM.map(|(kernel, stride)| {
t = if t < kernel { 0 } else { (t - kernel) / stride + 1 };
t
})
}
impl Encoder {
pub fn load(gpu: &Gpu, g: &Gguf, blocks: transformer::Config, eps: f32) -> Result<Self> {
let d = blocks.d;
let f32s = |name: &str, n: usize| g.tensor(name, &[n])?.to_f32();
let conv = |i: usize, ch: usize, out: usize| {
let bias = if i == 0 { Vec::new() } else { f32s(&format!("enc.conv.{i}.bias"), out)? };
gpu.conv(g.tensor(&format!("enc.conv.{i}.weight"), &[STEM[i].0, ch, out])?, &bias)
};
Ok(Self {
conv0: conv(0, 1, d)?,
norm: gpu.channels(&f32s("enc.conv.norm.weight", d)?, &f32s("enc.conv.norm.bias", d)?)?,
eps,
conv1: conv(1, d, 2 * d)?,
conv2: conv(2, 2 * d, d)?,
blocks: Blocks::load(gpu, g, blocks)?,
})
}
pub fn buffers(&self, gpu: &Gpu, samples: usize) -> Buffers {
let b = &self.blocks.cfg;
let [t1, t2, t] = frames(samples);
let cols = [t1 * 128, t2 * (STEM[1].0 * b.d).next_multiple_of(32), t * 6 * b.d];
Buffers {
samples,
pcm: gpu.buffer(samples),
cols: gpu.buffer(cols.into_iter().max().unwrap()),
conv: gpu.buffer((t1 * b.d).max(t2 * 2 * b.d)),
t: transformer::Buffers {
x: gpu.buffer(t * b.d),
y: gpu.buffer(t * b.d),
qkv: gpu.buffer(t.next_multiple_of(64) * 3 * b.d + 4),
h: gpu.buffer(t * b.d_ff.max(2 * b.d)),
s: gpu.buffer(gpu.scores_len(t, b.heads, b.head_dim(), false)),
},
}
}
pub fn record(&self, p: &mut Pass, b: &Buffers, n: usize, rope: &Buffer) {
let d = self.blocks.cfg.d;
let [t1, t2, t] = frames(n);
p.im2col(&b.pcm, &b.cols, n, 1, [STEM[0].0, STEM[0].1, 0]);
p.gemm(&b.cols, &self.conv0, &b.conv, t1, Epilogue::Tanh);
p.group_norm(&b.conv, &self.norm, t1, d, self.eps);
p.im2col(&b.conv, &b.cols, t1, d, [STEM[1].0, STEM[1].1, 0]);
p.gemm(&b.cols, &self.conv1, &b.conv, t2, Epilogue::Gelu);
p.im2col(&b.conv, &b.cols, t2, 2 * d, [STEM[2].0, STEM[2].1, 0]);
p.gemm(&b.cols, &self.conv2, &b.t.x, t, Epilogue::Gelu);
self.blocks.record(p, &b.t, t, Some(rope));
}
}