use crate::error::Result;
use crate::ops::{self, MatmulSpec};
use crate::tensor::Tensor;
pub struct Linear {
pub w: Tensor,
pub b: Option<Tensor>,
}
impl Linear {
pub fn forward(&self, x: &Tensor) -> Result<Tensor> {
ops::matmul(x, &self.w, self.b.as_ref(), MatmulSpec::default())
}
}
pub struct LayerNorm {
pub gamma: Tensor,
pub beta: Tensor,
pub eps: f32,
}
impl LayerNorm {
pub fn forward(&self, x: &Tensor) -> Result<Tensor> {
ops::layernorm(x, &self.gamma, &self.beta, self.eps)
}
}
pub struct Embedding {
pub wte_chunks: Vec<Tensor>,
pub chunk_rows: usize,
pub wpe: Tensor,
}
impl Embedding {
pub fn from_host_wte(
wte: &[f32],
vocab: usize,
n_embd: usize,
wpe: Tensor,
device: &crate::device::Device,
) -> Result<Self> {
let row_bytes = n_embd * 4;
let max_rows = (device.max_binding_bytes() / row_bytes).min(vocab);
let chunk_rows = max_rows.max(1);
let mut chunks = Vec::new();
let mut start = 0usize;
while start < vocab {
let rows = chunk_rows.min(vocab - start);
chunks.push(Tensor::from_f32(
&wte[start * n_embd..(start + rows) * n_embd],
[rows, n_embd],
device,
)?);
start += rows;
}
Ok(Embedding {
wte_chunks: chunks,
chunk_rows,
wpe,
})
}
pub fn forward(&self, ids: &Tensor, pos: usize) -> Result<Tensor> {
ops::embedding_chunked(ids, &self.wte_chunks, self.chunk_rows, Some(&self.wpe), pos)
}
}