use anyhow::{Context, Result, bail, ensure};
use std::io::{Read, Seek, SeekFrom};
pub fn quantize_q1(w: &[f32], m: usize, n: usize) -> (Vec<f32>, Vec<u32>) {
assert_eq!(w.len(), m * n, "weight is not [m, n]");
assert_eq!(n % 128, 0, "Q1 rows pack in 128-weight blocks");
let nsc = n / 128;
let nblk = n / 32;
let mut scales = vec![0f32; m * nsc];
let mut bits = vec![0u32; m * nblk];
for r in 0..m {
let row = &w[r * n..(r + 1) * n];
for sb in 0..nsc {
let blk = &row[sb * 128..(sb + 1) * 128];
let mean_abs = blk.iter().map(|v| v.abs()).sum::<f32>() / 128.0;
scales[r * nsc + sb] = if mean_abs > 0.0 { mean_abs } else { 1.0 };
for (j, &v) in blk.iter().enumerate() {
if v >= 0.0 {
let word = sb * 4 + j / 32;
bits[r * nblk + word] |= 1u32 << (j % 32);
}
}
}
}
(scales, bits)
}
pub fn dequantize_q1(scales: &[f32], bits: &[u32], m: usize, n: usize) -> Vec<f32> {
let nsc = n / 128;
let nblk = n / 32;
let mut w = vec![0f32; m * n];
for r in 0..m {
for j in 0..n {
let s = scales[r * nsc + j / 128];
let b = (bits[r * nblk + j / 32] >> (j % 32)) & 1;
w[r * n + j] = if b == 1 { s } else { -s };
}
}
w
}
pub fn q1_0_disk_to_engine(raw: &[u8], nblocks: usize) -> Result<(Vec<f32>, Vec<u32>)> {
ensure!(
raw.len() >= nblocks * 18,
"Q1_0 data short: {} < {}",
raw.len(),
nblocks * 18
);
let mut scales = Vec::with_capacity(nblocks);
let mut bits = Vec::with_capacity(nblocks * 4);
for b in 0..nblocks {
let base = b * 18;
let sc = u16::from_le_bytes([raw[base], raw[base + 1]]);
scales.push(f16_bits_to_f32(sc));
for w in 0..4 {
let o = base + 2 + w * 4;
bits.push(u32::from_le_bytes([
raw[o],
raw[o + 1],
raw[o + 2],
raw[o + 3],
]));
}
}
Ok((scales, bits))
}
pub fn dequant_ggml(raw: &[u8], ggml_type: u32, count: usize) -> Result<Vec<f32>> {
match ggml_type {
8 => dequant_q8_0(raw, count),
2 => dequant_q4_0(raw, count),
6 => dequant_q5_0(raw, count),
10 => dequant_q2_k(raw, count),
11 => dequant_q3_k(raw, count),
12 => dequant_q4_k(raw, count),
13 => dequant_q5_k(raw, count),
14 => dequant_q6_k(raw, count),
16 => dequant_iq2_xxs(raw, count),
17 => dequant_iq2_xs(raw, count),
18 => dequant_iq3_xxs(raw, count),
19 => dequant_iq1_s(raw, count),
20 => dequant_iq4_nl(raw, count),
21 => dequant_iq3_s(raw, count),
22 => dequant_iq2_s(raw, count),
23 => dequant_iq4_xs(raw, count),
29 => dequant_iq1_m(raw, count),
30 => {
ensure!(raw.len() >= count * 2, "BF16 data short");
Ok(raw[..count * 2]
.chunks_exact(2)
.map(|c| f32::from_bits(u32::from(u16::from_le_bytes([c[0], c[1]])) << 16))
.collect())
}
other => bail!(
"dequant_ggml: ggml type {other} ({}) not decodable",
GgufFile::type_name(other)
),
}
}
fn dequant_q5_0(raw: &[u8], count: usize) -> Result<Vec<f32>> {
ensure!(count.is_multiple_of(32), "Q5_0 count {count} not /32");
let (nb, bs) = (count / 32, 22);
ensure!(raw.len() >= nb * bs, "Q5_0 data short");
let mut out = vec![0f32; count];
for b in 0..nb {
let o = b * bs;
let d = f16_bits_to_f32(u16::from_le_bytes([raw[o], raw[o + 1]]));
let qh = u32::from_le_bytes([raw[o + 2], raw[o + 3], raw[o + 4], raw[o + 5]]);
let qs = &raw[o + 6..o + 22];
for l in 0..16 {
let byte = qs[l];
let hlo = ((qh >> l) & 1) as u8;
let hhi = ((qh >> (l + 16)) & 1) as u8;
let qlo = (byte & 0x0F) | (hlo << 4);
let qhi = (byte >> 4) | (hhi << 4);
out[b * 32 + l] = d * (qlo as i32 - 16) as f32;
out[b * 32 + l + 16] = d * (qhi as i32 - 16) as f32;
}
}
Ok(out)
}
fn dequant_q8_0(raw: &[u8], count: usize) -> Result<Vec<f32>> {
ensure!(count.is_multiple_of(32), "Q8_0 count {count} not /32");
let (nb, bs) = (count / 32, 34);
ensure!(raw.len() >= nb * bs, "Q8_0 data short");
let mut out = Vec::with_capacity(count);
for b in 0..nb {
let o = b * bs;
let d = f16_bits_to_f32(u16::from_le_bytes([raw[o], raw[o + 1]]));
for i in 0..32 {
out.push(d * (raw[o + 2 + i] as i8 as f32));
}
}
Ok(out)
}
fn dequant_q4_0(raw: &[u8], count: usize) -> Result<Vec<f32>> {
ensure!(count.is_multiple_of(32), "Q4_0 count {count} not /32");
let (nb, bs) = (count / 32, 18);
ensure!(raw.len() >= nb * bs, "Q4_0 data short");
let mut out = vec![0f32; count];
for b in 0..nb {
let o = b * bs;
let d = f16_bits_to_f32(u16::from_le_bytes([raw[o], raw[o + 1]]));
for l in 0..16 {
let byte = raw[o + 2 + l];
out[b * 32 + l] = d * (((byte & 0x0F) as i32 - 8) as f32);
out[b * 32 + l + 16] = d * (((byte >> 4) as i32 - 8) as f32);
}
}
Ok(out)
}
fn q4k_scale_min(s: &[u8]) -> ([u8; 8], [u8; 8]) {
let (mut sc, mut mn) = ([0u8; 8], [0u8; 8]);
for i in 0..4 {
sc[i] = s[i] & 0x3F;
mn[i] = s[i + 4] & 0x3F;
sc[i + 4] = (s[i + 8] & 0x0F) | ((s[i] >> 2) & 0x30);
mn[i + 4] = (s[i + 8] >> 4) | ((s[i + 4] >> 2) & 0x30);
}
(sc, mn)
}
fn dequant_q4_k(raw: &[u8], count: usize) -> Result<Vec<f32>> {
ensure!(count.is_multiple_of(256), "Q4_K count {count} not /256");
let (nb, bs) = (count / 256, 144);
ensure!(raw.len() >= nb * bs, "Q4_K data short");
let mut out = vec![0f32; count];
for b in 0..nb {
let o = b * bs;
let d = f16_bits_to_f32(u16::from_le_bytes([raw[o], raw[o + 1]]));
let dmin = f16_bits_to_f32(u16::from_le_bytes([raw[o + 2], raw[o + 3]]));
let (sc, mn) = q4k_scale_min(&raw[o + 4..o + 16]);
let qs = &raw[o + 16..o + 144];
for s in 0..8 {
let (g, p) = (s / 2, s % 2);
let ds = d * sc[s] as f32;
let ms = dmin * mn[s] as f32;
for l in 0..32 {
let nib = (qs[g * 32 + l] >> (4 * p)) & 0x0F;
out[b * 256 + s * 32 + l] = ds * nib as f32 - ms;
}
}
}
Ok(out)
}
fn dequant_q5_k(raw: &[u8], count: usize) -> Result<Vec<f32>> {
ensure!(count.is_multiple_of(256), "Q5_K count {count} not /256");
let (nb, bs) = (count / 256, 176);
ensure!(raw.len() >= nb * bs, "Q5_K data short");
let mut out = vec![0f32; count];
for b in 0..nb {
let o = b * bs;
let d = f16_bits_to_f32(u16::from_le_bytes([raw[o], raw[o + 1]]));
let dmin = f16_bits_to_f32(u16::from_le_bytes([raw[o + 2], raw[o + 3]]));
let (sc, mn) = q4k_scale_min(&raw[o + 4..o + 16]);
let qh = &raw[o + 16..o + 48];
let qs = &raw[o + 48..o + 176];
for s in 0..8 {
let (g, p) = (s / 2, s % 2);
let ds = d * sc[s] as f32;
let ms = dmin * mn[s] as f32;
for l in 0..32 {
let nib = (qs[g * 32 + l] >> (4 * p)) & 0x0F;
let hi = (qh[l] >> s) & 1;
out[b * 256 + s * 32 + l] = ds * (nib | (hi << 4)) as f32 - ms;
}
}
}
Ok(out)
}
fn dequant_q2_k(raw: &[u8], count: usize) -> Result<Vec<f32>> {
ensure!(count.is_multiple_of(256), "Q2_K count {count} not /256");
let (nb, bs) = (count / 256, 84);
ensure!(raw.len() >= nb * bs, "Q2_K data short");
let mut out = vec![0f32; count];
for b in 0..nb {
let o = b * bs;
let scales = &raw[o..o + 16];
let qs = &raw[o + 16..o + 80];
let d = f16_bits_to_f32(u16::from_le_bytes([raw[o + 80], raw[o + 81]]));
let dmin = f16_bits_to_f32(u16::from_le_bytes([raw[o + 82], raw[o + 83]]));
for e in 0..256usize {
let (g, w) = (e / 128, e % 128);
let (sh, l) = (w / 32, w % 32);
let q = (qs[g * 32 + l] >> (2 * sh)) & 3;
let sc = scales[e / 16];
out[b * 256 + e] = d * (sc & 0x0F) as f32 * q as f32 - dmin * (sc >> 4) as f32;
}
}
Ok(out)
}
fn dequant_q3_k(raw: &[u8], count: usize) -> Result<Vec<f32>> {
ensure!(count.is_multiple_of(256), "Q3_K count {count} not /256");
let (nb, bs) = (count / 256, 110);
ensure!(raw.len() >= nb * bs, "Q3_K data short");
let mut out = vec![0f32; count];
for b in 0..nb {
let o = b * bs;
let hmask = &raw[o..o + 32];
let qs = &raw[o + 32..o + 96];
let scb = &raw[o + 96..o + 108];
let d = f16_bits_to_f32(u16::from_le_bytes([raw[o + 108], raw[o + 109]]));
let mut dl = [0f32; 16];
for (j, slot) in dl.iter_mut().enumerate() {
let lo = (scb[j % 8] >> (4 * (j / 8))) & 0x0F;
let hi = (scb[8 + (j % 4)] >> (2 * (j / 4))) & 0x03;
*slot = d * (((lo | (hi << 4)) as i8 as i32) - 32) as f32;
}
for e in 0..256usize {
let (g, w) = (e / 128, e % 128);
let (sh, l) = (w / 32, w % 32);
let q = ((qs[g * 32 + l] >> (2 * sh)) & 3) as i32;
let hbit = (hmask[e % 32] >> (e / 32)) & 1;
let q = q - if hbit == 0 { 4 } else { 0 };
out[b * 256 + e] = dl[e / 16] * q as f32;
}
}
Ok(out)
}
fn dequant_q6_k(raw: &[u8], count: usize) -> Result<Vec<f32>> {
ensure!(count.is_multiple_of(256), "Q6_K count {count} not /256");
let (nb, bs) = (count / 256, 210);
ensure!(raw.len() >= nb * bs, "Q6_K data short");
let mut out = vec![0f32; count];
for b in 0..nb {
let o = b * bs;
let ql = &raw[o..o + 128];
let qh = &raw[o + 128..o + 192];
let sc = &raw[o + 192..o + 208];
let d = f16_bits_to_f32(u16::from_le_bytes([raw[o + 208], raw[o + 209]]));
for half in 0..2 {
let (qlh, qhh, sch) = (&ql[half * 64..], &qh[half * 32..], &sc[half * 8..]);
let base = b * 256 + half * 128;
for l in 0..32 {
let is = l / 16;
let q1 = ((qlh[l] & 0x0F) | (((qhh[l] >> 0) & 3) << 4)) as i32 - 32;
let q2 = ((qlh[l + 32] & 0x0F) | (((qhh[l] >> 2) & 3) << 4)) as i32 - 32;
let q3 = ((qlh[l] >> 4) | (((qhh[l] >> 4) & 3) << 4)) as i32 - 32;
let q4 = ((qlh[l + 32] >> 4) | (((qhh[l] >> 6) & 3) << 4)) as i32 - 32;
out[base + l] = d * sch[is] as i8 as f32 * q1 as f32;
out[base + l + 32] = d * sch[is + 2] as i8 as f32 * q2 as f32;
out[base + l + 64] = d * sch[is + 4] as i8 as f32 * q3 as f32;
out[base + l + 96] = d * sch[is + 6] as i8 as f32 * q4 as f32;
}
}
}
Ok(out)
}
fn f16_bits_to_f32(bits: u16) -> f32 {
let sign = u32::from(bits >> 15) << 31;
let exp = u32::from(bits >> 10) & 0x1f;
let man = u32::from(bits) & 0x3ff;
if exp == 0x1f {
return f32::from_bits(sign | 0x7f80_0000 | (man << 13));
}
if exp == 0 {
if man == 0 {
return f32::from_bits(sign);
}
let shift = man.leading_zeros() - 21;
let man = (man << shift) & 0x3ff;
let exp = 127 - 15 + 1 - shift;
return f32::from_bits(sign | (exp << 23) | (man << 13));
}
f32::from_bits(sign | ((exp + 127 - 15) << 23) | (man << 13))
}
#[derive(Debug, Clone)]
pub struct GgufTensor {
pub name: String,
pub dims: Vec<u64>,
pub ggml_type: u32,
pub offset: u64,
}
pub struct GgufFile {
file: std::fs::File,
pub version: u32,
pub kvs: std::collections::BTreeMap<String, GgufValue>,
pub tensors: Vec<GgufTensor>,
pub data_start: u64,
}
#[derive(Debug, Clone)]
pub enum GgufValue {
U64(u64),
I64(i64),
F64(f64),
Bool(bool),
Str(String),
Array(u32, u64),
StrArray(Vec<String>),
}
impl GgufFile {
pub fn open(path: &std::path::Path) -> Result<Self> {
let mut f = std::fs::File::open(path).with_context(|| format!("open {path:?}"))?;
let mut r = std::io::BufReader::new(&mut f);
let mut magic = [0u8; 4];
r.read_exact(&mut magic)?;
ensure!(&magic == b"GGUF", "not a GGUF file (magic {magic:?})");
let version = read_u32(&mut r)?;
ensure!(
(2..=3).contains(&version),
"GGUF v{version} unsupported (v2/v3 only)"
);
let n_tensors = read_u64(&mut r)?;
let n_kvs = read_u64(&mut r)?;
let mut kvs = std::collections::BTreeMap::new();
for _ in 0..n_kvs {
let key = read_string(&mut r)?;
let ty = read_u32(&mut r)?;
let val = read_value(&mut r, ty, &key)?;
kvs.insert(key, val);
}
let mut tensors = Vec::with_capacity(n_tensors as usize);
for _ in 0..n_tensors {
let name = read_string(&mut r)?;
let n_dims = read_u32(&mut r)?;
ensure!(n_dims <= 8, "tensor {name}: {n_dims} dims");
let mut dims = Vec::with_capacity(n_dims as usize);
for _ in 0..n_dims {
dims.push(read_u64(&mut r)?);
}
let ggml_type = read_u32(&mut r)?;
let offset = read_u64(&mut r)?;
tensors.push(GgufTensor {
name,
dims,
ggml_type,
offset,
});
}
let align = match kvs.get("general.alignment") {
Some(GgufValue::U64(a)) if *a > 0 => *a,
_ => 32,
};
let here = r.stream_position()?;
let data_start = here.div_ceil(align) * align;
drop(r);
Ok(Self {
file: f,
version,
kvs,
tensors,
data_start,
})
}
pub fn read_tensor_raw(&mut self, t: &GgufTensor, len: usize) -> Result<Vec<u8>> {
self.file
.seek(SeekFrom::Start(self.data_start + t.offset))?;
let mut buf = vec![0u8; len];
self.file.read_exact(&mut buf)?;
Ok(buf)
}
pub fn shape(&self, name: &str) -> Result<Vec<usize>> {
let t = self.tensor(name)?;
Ok(t.dims.iter().rev().map(|&d| d as usize).collect())
}
fn tensor(&self, name: &str) -> Result<&GgufTensor> {
self.tensors
.iter()
.find(|t| t.name == name)
.with_context(|| format!("GGUF missing tensor {name}"))
}
pub fn tensor_f32(&mut self, name: &str) -> Result<Vec<f32>> {
let t = self.tensor(name)?.clone();
let count: usize = t.dims.iter().map(|&d| d as usize).product();
match t.ggml_type {
0 => {
let raw = self.read_tensor_raw(&t, count * 4)?;
Ok(raw
.chunks_exact(4)
.map(|c| f32::from_le_bytes(c.try_into().unwrap()))
.collect())
}
1 => {
let raw = self.read_tensor_raw(&t, count * 2)?;
Ok(raw
.chunks_exact(2)
.map(|c| f16_bits_to_f32(u16::from_le_bytes([c[0], c[1]])))
.collect())
}
41 => {
anyhow::ensure!(
count.is_multiple_of(128),
"{name}: Q1_0 count {count} not /128"
);
let nblocks = count / 128;
let raw = self.read_tensor_raw(&t, nblocks * 18)?;
let (scales, bits) = q1_0_disk_to_engine(&raw, nblocks)?;
let inner: usize = t.dims[0] as usize; let outer = count / inner;
Ok(dequantize_q1(&scales, &bits, outer, inner))
}
2 | 6 | 8 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29
| 30 => {
let (be, bb) = match t.ggml_type {
8 => (32usize, 34usize), 2 => (32, 18), 6 => (32, 22), 10 => (256, 84), 11 => (256, 110), 12 => (256, 144), 13 => (256, 176), 14 => (256, 210), 16 => (256, 66), 17 => (256, 74), 18 => (256, 98), 19 => (256, 50), 20 => (32, 18), 21 => (256, 110), 22 => (256, 82), 23 => (256, 136), 29 => (256, 56), 30 => (1, 2), _ => unreachable!(),
};
anyhow::ensure!(
count.is_multiple_of(be),
"{name}: {} count {count} not /{be}",
Self::type_name(t.ggml_type)
);
let raw = self.read_tensor_raw(&t, (count / be) * bb)?;
dequant_ggml(&raw, t.ggml_type, count)
}
other => bail!(
"{name}: ggml type {other} ({}) not decodable",
Self::type_name(other)
),
}
}
pub fn type_name(ty: u32) -> &'static str {
match ty {
0 => "F32",
1 => "F16",
2 => "Q4_0",
8 => "Q8_0",
16 => "IQ2_XXS",
17 => "IQ2_XS",
18 => "IQ3_XXS",
19 => "IQ1_S",
20 => "IQ4_NL",
21 => "IQ3_S",
22 => "IQ2_S",
23 => "IQ4_XS",
29 => "IQ1_M",
30 => "BF16",
34 => "TQ1_0",
35 => "TQ2_0",
41 => "Q1_0",
other => {
let _ = other;
"unknown"
}
}
}
}
fn read_u32(r: &mut impl Read) -> Result<u32> {
let mut b = [0u8; 4];
r.read_exact(&mut b)?;
Ok(u32::from_le_bytes(b))
}
fn read_u64(r: &mut impl Read) -> Result<u64> {
let mut b = [0u8; 8];
r.read_exact(&mut b)?;
Ok(u64::from_le_bytes(b))
}
fn read_string(r: &mut impl Read) -> Result<String> {
let len = read_u64(r)?;
ensure!(len <= 1 << 24, "unreasonable GGUF string length {len}");
let mut b = vec![0u8; len as usize];
r.read_exact(&mut b)?;
Ok(String::from_utf8_lossy(&b).into_owned())
}
fn scalar_size(ty: u32) -> Result<u64> {
Ok(match ty {
0 | 1 | 7 => 1, 2 | 3 => 2, 4..=6 => 4, 10..=12 => 8, other => bail!("non-scalar GGUF type {other} where scalar expected"),
})
}
fn read_value(r: &mut (impl Read + Seek), ty: u32, key: &str) -> Result<GgufValue> {
Ok(match ty {
0 => GgufValue::U64(u64::from({
let mut b = [0u8; 1];
r.read_exact(&mut b)?;
b[0]
})),
1 => GgufValue::I64(i64::from({
let mut b = [0u8; 1];
r.read_exact(&mut b)?;
b[0] as i8
})),
2 => GgufValue::U64(u64::from(read_u16(r)?)),
3 => GgufValue::I64(i64::from(read_u16(r)? as i16)),
4 => GgufValue::U64(u64::from(read_u32(r)?)),
5 => GgufValue::I64(i64::from(read_u32(r)? as i32)),
6 => GgufValue::F64(f64::from(f32::from_bits(read_u32(r)?))),
7 => GgufValue::Bool({
let mut b = [0u8; 1];
r.read_exact(&mut b)?;
b[0] != 0
}),
8 => GgufValue::Str(read_string(r)?),
9 => {
let elem = read_u32(r)?;
let count = read_u64(r)?;
if elem == 8 {
ensure!(count <= 1 << 20, "{key}: string array of {count}");
let mut v = Vec::with_capacity(count as usize);
for _ in 0..count {
v.push(read_string(r)?);
}
GgufValue::StrArray(v)
} else {
let sz = scalar_size(elem)?;
r.seek(SeekFrom::Current((sz * count) as i64))?;
GgufValue::Array(elem, count)
}
}
10 => GgufValue::U64(read_u64(r)?),
11 => GgufValue::I64({
let mut b = [0u8; 8];
r.read_exact(&mut b)?;
i64::from_le_bytes(b)
}),
12 => GgufValue::F64({
let mut b = [0u8; 8];
r.read_exact(&mut b)?;
f64::from_le_bytes(b)
}),
other => bail!("{key}: unknown GGUF value type {other}"),
})
}
fn read_u16(r: &mut impl Read) -> Result<u16> {
let mut b = [0u8; 2];
r.read_exact(&mut b)?;
Ok(u16::from_le_bytes(b))
}
#[cfg(not(target_arch = "wasm32"))]
pub fn load_bonsai(ctx: &crate::GpuCtx, path: &std::path::Path) -> Result<crate::weights::Weights> {
use crate::weights::{Arch, EdgeCfg, Layer, Lfm2Config, Op, Q4, WDtype, Weights, f32_to_f16_bytes};
let mut g = GgufFile::open(path)?;
let ku = |k: &str| -> Result<usize> {
match g.kvs.get(k) {
Some(GgufValue::U64(v)) => Ok(*v as usize),
_ => bail!("GGUF missing u64 metadata {k}"),
}
};
let kf = |k: &str| -> Result<f32> {
match g.kvs.get(k) {
Some(GgufValue::F64(v)) => Ok(*v as f32),
_ => bail!("GGUF missing f32 metadata {k}"),
}
};
let arch = match g.kvs.get("general.architecture") {
Some(GgufValue::Str(s)) if s == "qwen35" => Arch::Qwen35,
other => bail!("load_bonsai: architecture {other:?} != qwen35"),
};
let hidden = ku("qwen35.embedding_length")?;
let n_layers = ku("qwen35.block_count")?;
let n_heads = ku("qwen35.attention.head_count")?;
let n_kv_heads = ku("qwen35.attention.head_count_kv")?;
let head_dim = ku("qwen35.attention.key_length")?;
let intermediate = ku("qwen35.feed_forward_length")?;
let eps = kf("qwen35.attention.layer_norm_rms_epsilon")?;
let rope_theta = kf("qwen35.rope.freq_base")?;
let rotary_dim = ku("qwen35.rope.dimension_count")?;
let full_iv = ku("qwen35.full_attention_interval")?;
let vocab = g.shape("token_embd.weight")?[0];
let dn_nv = ku("qwen35.ssm.time_step_rank")?;
let dn_dv = ku("qwen35.ssm.state_size")?;
let dn_kernel = ku("qwen35.ssm.conv_kernel")?;
let dn_nk = ku("qwen35.ssm.group_count")?;
let inner = ku("qwen35.ssm.inner_size")?; anyhow::ensure!(inner == dn_nv * dn_dv, "ssm inner {inner} != nv·dv");
let qkv_w = g.shape("blk.0.attn_qkv.weight")?[0]; let dn_dk = (qkv_w - inner) / (2 * dn_nk);
anyhow::ensure!(2 * dn_nk * dn_dk + inner == qkv_w, "DeltaNet dk derivation");
let layer_is_attn: Vec<bool> = (0..n_layers).map(|i| (i + 1) % full_iv == 0).collect();
let cfg = Lfm2Config {
arch,
hidden,
vocab,
n_layers,
intermediate,
n_heads,
n_kv_heads,
head_dim,
conv_l: 0,
eps,
rope_theta,
rope_local_theta: rope_theta,
sliding_window: 0,
layer_is_attn: layer_is_attn.clone(),
layer_is_sliding: vec![false; n_layers],
layer_k_eq_v: vec![false; n_layers],
act_gelu: false, num_experts: 0,
top_k_experts: 0,
moe_intermediate: 0,
stage_first: true,
stage_last: true,
rotary_dim,
mrope_section: None, dn_nk,
dn_nv,
dn_dk,
dn_dv,
dn_kernel,
wdtype: WDtype::Q4,
head_wdtype: WDtype::Q4,
layer_wdtype: Vec::new(),
layer_kinds: Vec::new(),
head_kind: None,
edge: EdgeCfg::default(),
};
let mk_q1 = |g: &mut GgufFile, name: &str| -> Result<Q4> {
let sh = g.shape(name)?;
let (m, n) = (sh[0], sh[1]);
let f = g.tensor_f32(name)?;
let (scales, bits) = quantize_q1(&f, m, n);
Ok(Q4 {
scales: ctx.storage_bytes(&f32_to_f16_bytes(&scales)),
quants: ctx.storage(bytemuck::cast_slice::<u32, f32>(&bits)),
})
};
let mk_q1_f = |f: &[f32], m: usize, n: usize| -> Q4 {
let (scales, bits) = quantize_q1(f, m, n);
Q4 {
scales: ctx.storage_bytes(&f32_to_f16_bytes(&scales)),
quants: ctx.storage(bytemuck::cast_slice::<u32, f32>(&bits)),
}
};
let norm = |g: &mut GgufFile, name: &str| -> Result<wgpu::Buffer> {
Ok(ctx.storage(&g.tensor_f32(name)?)) };
let (nk, nv, dk, dv) = (dn_nk, dn_nv, dn_dk, dn_dv);
let (qd, kd) = (n_heads * head_dim, n_kv_heads * head_dim);
let mut layers = Vec::with_capacity(n_layers);
for li in 0..n_layers {
let p = format!("blk.{li}");
let op = if layer_is_attn[li] {
let qp = g.tensor_f32(&format!("{p}.attn_q.weight"))?;
let hd2 = 2 * head_dim;
let mut qrows = vec![0f32; qd * hidden];
let mut grows = vec![0f32; qd * hidden];
for h in 0..n_heads {
let src = h * hd2 * hidden;
let dst = h * head_dim * hidden;
let half = head_dim * hidden;
qrows[dst..dst + half].copy_from_slice(&qp[src..src + half]);
grows[dst..dst + half].copy_from_slice(&qp[src + half..src + 2 * half]);
}
let kp = g.tensor_f32(&format!("{p}.attn_k.weight"))?;
let vp = g.tensor_f32(&format!("{p}.attn_v.weight"))?;
let mut qkv_f = qrows;
qkv_f.extend_from_slice(&kp);
qkv_f.extend_from_slice(&vp);
Op::Attn {
qkv: mk_q1_f(&qkv_f, qd + 2 * kd, hidden),
o: mk_q1(&mut g, &format!("{p}.attn_output.weight"))?,
q_norm: norm(&mut g, &format!("{p}.attn_q_norm.weight"))?,
k_norm: norm(&mut g, &format!("{p}.attn_k_norm.weight"))?,
window: 0,
local_rope: false,
attn_gate: Some(mk_q1_f(&grows, qd, hidden)),
qkv_bias: None,
}
} else {
let mut in_f = g.tensor_f32(&format!("{p}.attn_qkv.weight"))?;
in_f.extend_from_slice(&g.tensor_f32(&format!("{p}.attn_gate.weight"))?);
in_f.extend_from_slice(&g.tensor_f32(&format!("{p}.ssm_beta.weight"))?);
in_f.extend_from_slice(&g.tensor_f32(&format!("{p}.ssm_alpha.weight"))?);
let rows = 2 * nk * dk + nv * dv + nv * dv + 2 * nv;
let conv = g.tensor_f32(&format!("{p}.ssm_conv1d.weight"))?;
let mut gpar = g.tensor_f32(&format!("{p}.ssm_a"))?;
gpar.extend_from_slice(&g.tensor_f32(&format!("{p}.ssm_dt.bias"))?);
gpar.extend_from_slice(&g.tensor_f32(&format!("{p}.ssm_norm.weight"))?);
Op::DeltaNet {
in_proj: mk_q1_f(&in_f, rows, hidden),
conv_w: ctx.storage(&conv),
gpar: ctx.storage(&gpar),
out_proj: mk_q1(&mut g, &format!("{p}.ssm_out.weight"))?,
}
};
let layer = Layer {
operator_norm: norm(&mut g, &format!("{p}.attn_norm.weight"))?,
ffn_norm: norm(&mut g, &format!("{p}.post_attention_norm.weight"))?,
op,
w1: mk_q1(&mut g, &format!("{p}.ffn_gate.weight"))?,
w2: mk_q1(&mut g, &format!("{p}.ffn_down.weight"))?,
w3: mk_q1(&mut g, &format!("{p}.ffn_up.weight"))?,
post_op_norm: None,
post_ffn_norm: None,
moe: None,
edge: None,
};
layers.push(layer);
ctx.queue.submit(std::iter::empty());
let _ = ctx.device.poll(wgpu::PollType::wait_indefinitely());
eprintln!("bonsai load: layer {li} done");
}
let ef32 = g.tensor_f32("token_embd.weight")?;
let split_row = (cfg.vocab / 2) as u32;
let split_at = (split_row as usize) * cfg.hidden;
let embed = ctx.storage(&ef32[..split_at]);
let embed_split = Some((ctx.storage(&ef32[split_at..]), split_row));
let embed_f16 = Some(ctx.storage_bytes(&f32_to_f16_bytes(&ef32)));
drop(ef32);
let embed_q4 = mk_q1(&mut g, "output.weight")?;
let embedding_norm = norm(&mut g, "output_norm.weight")?;
eprintln!("bonsai load: embed + head done");
Ok(Weights {
cfg,
embed,
embed_q4,
embedding_norm,
layers,
mtp: None,
embed_f16,
embed_split,
ple: None,
})
}
#[cfg(not(target_arch = "wasm32"))]
pub fn load_gguf(
ctx: &crate::GpuCtx,
path: &std::path::Path,
wdtype: crate::weights::WDtype,
) -> Result<crate::weights::Weights> {
use crate::weights::{Arch, EdgeCfg, Layer, Lfm2Config, Op, Weights, pack_weight};
let mut g = GgufFile::open(path)?;
let arch_name = match g.kvs.get("general.architecture") {
Some(GgufValue::Str(s)) => s.clone(),
other => bail!("load_gguf: missing general.architecture ({other:?})"),
};
ensure!(
arch_name == "llama" || arch_name == "qwen2",
"load_gguf handles the `llama`/`qwen2` arches (got {arch_name:?}); load_bonsai for qwen35"
);
let is_llama = arch_name == "llama";
let ku = |g: &GgufFile, k: &str| -> Result<usize> {
match g.kvs.get(k) {
Some(GgufValue::U64(v)) => Ok(*v as usize),
_ => bail!("GGUF missing u64 metadata {k}"),
}
};
let kf = |g: &GgufFile, k: &str| -> Result<f32> {
match g.kvs.get(k) {
Some(GgufValue::F64(v)) => Ok(*v as f32),
_ => bail!("GGUF missing f32 metadata {k}"),
}
};
let pre = arch_name.clone();
let hidden = ku(&g, &format!("{pre}.embedding_length"))?;
let n_layers = ku(&g, &format!("{pre}.block_count"))?;
let n_heads = ku(&g, &format!("{pre}.attention.head_count"))?;
let n_kv_heads = ku(&g, &format!("{pre}.attention.head_count_kv"))?;
let intermediate = ku(&g, &format!("{pre}.feed_forward_length"))?;
let eps = kf(&g, &format!("{pre}.attention.layer_norm_rms_epsilon"))?;
let rope_theta = kf(&g, &format!("{pre}.rope.freq_base")).unwrap_or(10_000.0);
let head_dim = ku(&g, &format!("{pre}.attention.key_length"))
.or_else(|_| ku(&g, &format!("{pre}.rope.dimension_count")))
.unwrap_or(hidden / n_heads);
let rotary_dim = ku(&g, &format!("{pre}.rope.dimension_count")).unwrap_or(head_dim);
let vocab = g.shape("token_embd.weight")?[0];
let cfg = Lfm2Config {
arch: if is_llama { Arch::Llama } else { Arch::Qwen2 },
hidden,
vocab,
n_layers,
intermediate,
n_heads,
n_kv_heads,
head_dim,
conv_l: 0,
eps,
rope_theta,
rope_local_theta: rope_theta,
sliding_window: 0,
layer_is_attn: vec![true; n_layers],
layer_is_sliding: vec![false; n_layers],
layer_k_eq_v: vec![false; n_layers],
act_gelu: false, num_experts: 0,
top_k_experts: 0,
moe_intermediate: 0,
stage_first: true,
stage_last: true,
rotary_dim,
mrope_section: None,
dn_nk: 0,
dn_nv: 0,
dn_dk: 0,
dn_dv: 0,
dn_kernel: 0,
wdtype,
head_wdtype: wdtype,
layer_wdtype: Vec::new(),
layer_kinds: Vec::new(),
head_kind: None,
edge: EdgeCfg::default(),
};
let pk = |g: &mut GgufFile, name: &str| -> Result<crate::weights::Q4> {
let sh = g.shape(name)?;
let (rows, cols) = (sh[0], sh[1]);
let f = g.tensor_f32(name)?;
pack_weight(ctx, &f, rows, cols, wdtype)
};
let un_permute = |w: &[f32], n_head: usize| -> Vec<f32> {
if !is_llama {
return w.to_vec(); }
let hd = head_dim;
let mut out = vec![0f32; w.len()];
for h in 0..n_head {
for g in 0..hd {
let (a, b) = (g & 1, g >> 1);
let f = a * (hd / 2) + b;
let (src, dst) = ((h * hd + g) * hidden, (h * hd + f) * hidden);
out[dst..dst + hidden].copy_from_slice(&w[src..src + hidden]);
}
}
out
};
let pk_qkv = |g: &mut GgufFile, li: usize| -> Result<crate::weights::Q4> {
let (qd, kd) = (n_heads * head_dim, n_kv_heads * head_dim);
let qf = un_permute(&g.tensor_f32(&format!("blk.{li}.attn_q.weight"))?, n_heads);
let kf = un_permute(&g.tensor_f32(&format!("blk.{li}.attn_k.weight"))?, n_kv_heads);
let mut f = qf;
f.extend_from_slice(&kf);
f.extend_from_slice(&g.tensor_f32(&format!("blk.{li}.attn_v.weight"))?);
pack_weight(ctx, &f, qd + 2 * kd, hidden, wdtype)
};
let norm = |g: &mut GgufFile, name: &str| -> Result<wgpu::Buffer> {
Ok(ctx.storage(&g.tensor_f32(name)?)) };
let mut layers = Vec::with_capacity(n_layers);
for li in 0..n_layers {
let qkv_bias = if !is_llama {
let mut b = g.tensor_f32(&format!("blk.{li}.attn_q.bias"))?;
b.extend_from_slice(&g.tensor_f32(&format!("blk.{li}.attn_k.bias"))?);
b.extend_from_slice(&g.tensor_f32(&format!("blk.{li}.attn_v.bias"))?);
Some(ctx.storage(&b))
} else {
None
};
let op = Op::Attn {
qkv: pk_qkv(&mut g, li)?,
o: pk(&mut g, &format!("blk.{li}.attn_output.weight"))?,
q_norm: ctx.storage(&vec![1.0f32; head_dim]),
k_norm: ctx.storage(&vec![1.0f32; head_dim]),
window: 0,
local_rope: false,
attn_gate: None,
qkv_bias,
};
layers.push(Layer {
operator_norm: norm(&mut g, &format!("blk.{li}.attn_norm.weight"))?,
ffn_norm: norm(&mut g, &format!("blk.{li}.ffn_norm.weight"))?,
op,
w1: pk(&mut g, &format!("blk.{li}.ffn_gate.weight"))?,
w2: pk(&mut g, &format!("blk.{li}.ffn_down.weight"))?,
w3: pk(&mut g, &format!("blk.{li}.ffn_up.weight"))?,
post_op_norm: None,
post_ffn_norm: None,
moe: None,
edge: None,
});
}
let embed = ctx.storage(&g.tensor_f32("token_embd.weight")?);
let head_name = if g.tensors.iter().any(|t| t.name == "output.weight") {
"output.weight"
} else {
"token_embd.weight"
};
let embed_q4 = pk(&mut g, head_name)?;
let embedding_norm = norm(&mut g, "output_norm.weight")?;
Ok(Weights {
cfg,
embed,
embed_q4,
embedding_norm,
layers,
mtp: None,
embed_f16: None,
embed_split: None,
ple: None,
})
}
#[cfg(not(target_arch = "wasm32"))]
pub fn load_gguf_native(
ctx: &crate::GpuCtx,
path: &std::path::Path,
) -> Result<crate::weights::Weights> {
use crate::weights::{Arch, EdgeCfg, Layer, LayerKinds, Lfm2Config, Op, Q4, WDtype, WKind, Weights};
let mut g = GgufFile::open(path)?;
let arch_name = match g.kvs.get("general.architecture") {
Some(GgufValue::Str(s)) => s.clone(),
other => bail!("load_gguf_native: missing general.architecture ({other:?})"),
};
ensure!(
arch_name == "llama" || arch_name == "qwen2",
"load_gguf_native handles the `llama`/`qwen2` arches"
);
let is_llama = arch_name == "llama";
let pre = arch_name.clone();
let ku = |g: &GgufFile, k: &str| -> Result<usize> {
match g.kvs.get(k) {
Some(GgufValue::U64(v)) => Ok(*v as usize),
_ => bail!("GGUF missing u64 metadata {k}"),
}
};
let kf = |g: &GgufFile, k: &str| -> Result<f32> {
match g.kvs.get(k) {
Some(GgufValue::F64(v)) => Ok(*v as f32),
_ => bail!("GGUF missing f32 metadata {k}"),
}
};
let hidden = ku(&g, &format!("{pre}.embedding_length"))?;
let n_layers = ku(&g, &format!("{pre}.block_count"))?;
let n_heads = ku(&g, &format!("{pre}.attention.head_count"))?;
let n_kv_heads = ku(&g, &format!("{pre}.attention.head_count_kv"))?;
let intermediate = ku(&g, &format!("{pre}.feed_forward_length"))?;
let eps = kf(&g, &format!("{pre}.attention.layer_norm_rms_epsilon"))?;
let rope_theta = kf(&g, &format!("{pre}.rope.freq_base")).unwrap_or(10_000.0);
let head_dim = ku(&g, &format!("{pre}.attention.key_length"))
.or_else(|_| ku(&g, &format!("{pre}.rope.dimension_count")))
.unwrap_or(hidden / n_heads);
let rotary_dim = ku(&g, &format!("{pre}.rope.dimension_count")).unwrap_or(head_dim);
let vocab = g.shape("token_embd.weight")?[0];
ensure!(hidden.is_multiple_of(32), "native serving needs hidden % 32 == 0");
let mut cfg = Lfm2Config {
arch: if is_llama { Arch::Llama } else { Arch::Qwen2 },
hidden,
vocab,
n_layers,
intermediate,
n_heads,
n_kv_heads,
head_dim,
conv_l: 0,
eps,
rope_theta,
rope_local_theta: rope_theta,
sliding_window: 0,
layer_is_attn: vec![true; n_layers],
layer_is_sliding: vec![false; n_layers],
layer_k_eq_v: vec![false; n_layers],
act_gelu: false,
num_experts: 0,
top_k_experts: 0,
moe_intermediate: 0,
stage_first: true,
stage_last: true,
rotary_dim,
mrope_section: None,
dn_nk: 0,
dn_nv: 0,
dn_dk: 0,
dn_dv: 0,
dn_kernel: 0,
wdtype: WDtype::Q4,
head_wdtype: WDtype::Q4,
layer_wdtype: Vec::new(),
layer_kinds: Vec::new(),
head_kind: None,
edge: EdgeCfg::default(),
};
let raw_of = |g: &mut GgufFile, name: &str| -> Result<(u32, usize, usize, Vec<u8>)> {
let t = g
.tensors
.iter()
.find(|t| t.name == name)
.with_context(|| format!("GGUF missing tensor {name}"))?
.clone();
let cols = t.dims[0] as usize;
let rows: usize = t.dims.iter().skip(1).map(|&d| d as usize).product();
let (be, bb) = match t.ggml_type {
2 => (32usize, 18usize),
6 => (32, 22),
8 => (32, 34),
12 => (256, 144),
13 => (256, 176), 14 => (256, 210),
20 => (32, 18), 23 => (256, 136), 16 => (256, 66), 17 => (256, 74), 22 => (256, 82), 18 => (256, 98), 21 => (256, 110), 19 => (256, 50), 29 => (256, 56), other => {
let _ = other;
(0, 0)
}
};
if be == 0 {
return Ok((t.ggml_type, rows, cols, Vec::new()));
}
ensure!(cols.is_multiple_of(be), "{name}: cols {cols} not /{be}");
let raw = g.read_tensor_raw(&t, rows * (cols / be) * bb)?;
Ok((t.ggml_type, rows, cols, raw))
};
let to_q8n = |ty: u32, raw: &[u8], nblocks: usize| -> Result<Vec<u8>> {
Ok(match ty {
8 => crate::q8_0_pad_blocks(raw, nblocks),
6 => crate::q5_0_to_q8_0n(raw, nblocks),
2 => crate::q4_0_to_q8_0n(raw, nblocks),
other => bail!("no lossless Q8_0N upcast for ggml type {other}"),
})
};
let unpermute_raw = |raw: &[u8], n_head: usize, hd: usize, row_bytes: usize| -> Vec<u8> {
if !is_llama {
return raw.to_vec(); }
let mut out = vec![0u8; raw.len()];
for h in 0..n_head {
for gidx in 0..hd {
let (a, b) = (gidx & 1, gidx >> 1);
let f = a * (hd / 2) + b;
let (src, dst) = ((h * hd + gidx) * row_bytes, (h * hd + f) * row_bytes);
out[dst..dst + row_bytes].copy_from_slice(&raw[src..src + row_bytes]);
}
}
out
};
let native = |ctx: &crate::GpuCtx, padded: &[u8]| -> Q4 {
Q4 {
scales: ctx.storage_bytes(&[0u8; 4]),
quants: ctx.storage_bytes(padded),
}
};
let f16_fallback = |g: &mut GgufFile, name: &str| -> Result<Q4> {
let sh = g.shape(name)?;
let f = g.tensor_f32(name)?;
crate::weights::pack_weight(ctx, &f, sh[0], sh[1], WDtype::F16)
};
let single_native = |ctx: &crate::GpuCtx,
g: &mut GgufFile,
name: &str|
-> Result<(Q4, WKind)> {
let (ty, rows, cols, raw) = raw_of(g, name)?;
ensure!(
raw.is_empty()
== !matches!(ty, 2 | 6 | 8 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29),
"{name}: ggml type {ty} claimed native but raw_of returned {} bytes",
raw.len()
);
Ok(match ty {
12 => (native(ctx, &raw), WKind::Q4K),
13 => (native(ctx, &raw), WKind::Q5K),
14 => (
native(ctx, &crate::q6k_pad_blocks(&raw, rows * cols / 256)),
WKind::Q6K,
),
6 => (
native(ctx, &crate::q5_0_pad_blocks(&raw, rows * cols / 32)),
WKind::Q5_0N,
),
8 => (
native(ctx, &crate::q8_0_pad_blocks(&raw, rows * cols / 32)),
WKind::Q8_0N,
),
2 => (
native(ctx, &crate::q4_0_to_q8_0n(&raw, rows * cols / 32)),
WKind::Q8_0N,
),
20 => (
native(ctx, &crate::iq4_nl_pad_blocks(&raw, rows * cols / 32)),
WKind::Iq4Nl,
),
23 => (native(ctx, &raw), WKind::Iq4Xs),
16 | 17 | 18 | 19 | 21 | 22 | 29 => {
let (words, table, bb) = crate::iq_grid_geom(ty);
let nb = rows * cols / 256;
let padded = if bb % 4 == 0 && bb == words * 4 {
raw.clone()
} else {
crate::iq_pad_blocks(&raw, nb, bb, words * 4)
};
let tb: &[u8] = bytemuck::cast_slice(table);
let kind = match ty {
16 => WKind::Iq2Xxs,
17 => WKind::Iq2Xs,
22 => WKind::Iq2S,
18 => WKind::Iq3Xxs,
21 => WKind::Iq3S,
19 => WKind::Iq1S,
_ => WKind::Iq1M,
};
(
Q4 {
scales: ctx.storage_bytes(tb),
quants: ctx.storage_bytes(&padded),
},
kind,
)
}
_ => (f16_fallback(g, name)?, WKind::F16),
})
};
let (qd, kd) = (n_heads * head_dim, n_kv_heads * head_dim);
let norm = |g: &mut GgufFile, name: &str| -> Result<wgpu::Buffer> {
Ok(ctx.storage(&g.tensor_f32(name)?))
};
let mut layers = Vec::with_capacity(n_layers);
let mut kinds = Vec::with_capacity(n_layers);
for li in 0..n_layers {
let (qt, _, _, qraw) = raw_of(&mut g, &format!("blk.{li}.attn_q.weight"))?;
let (kt, _, _, kraw) = raw_of(&mut g, &format!("blk.{li}.attn_k.weight"))?;
let (vt, _, _, vraw) = raw_of(&mut g, &format!("blk.{li}.attn_v.weight"))?;
let legacy = |t: u32| matches!(t, 2 | 6 | 8);
let nb_row = hidden / 32;
let (qkv, qkv_kind) = if legacy(qt) && legacy(kt) && legacy(vt) {
let rb = |t: u32| nb_row * match t {
2 => 18,
6 => 22,
_ => 34,
};
let qp = unpermute_raw(&qraw, n_heads, head_dim, rb(qt));
let kp = unpermute_raw(&kraw, n_kv_heads, head_dim, rb(kt));
let mut blocks = to_q8n(qt, &qp, qd * nb_row)?;
blocks.extend_from_slice(&to_q8n(kt, &kp, kd * nb_row)?);
blocks.extend_from_slice(&to_q8n(vt, &vraw, kd * nb_row)?);
(native(ctx, &blocks), WKind::Q8_0N)
} else {
let un = |w: &[f32], nh: usize| -> Vec<f32> {
if !is_llama {
return w.to_vec();
}
let hd = head_dim;
let mut out = vec![0f32; w.len()];
for h in 0..nh {
for gi in 0..hd {
let (a, b) = (gi & 1, gi >> 1);
let f = a * (hd / 2) + b;
let (src, dst) = ((h * hd + gi) * hidden, (h * hd + f) * hidden);
out[dst..dst + hidden].copy_from_slice(&w[src..src + hidden]);
}
}
out
};
let qf = un(&g.tensor_f32(&format!("blk.{li}.attn_q.weight"))?, n_heads);
let kf2 = un(&g.tensor_f32(&format!("blk.{li}.attn_k.weight"))?, n_kv_heads);
let mut f = qf;
f.extend_from_slice(&kf2);
f.extend_from_slice(&g.tensor_f32(&format!("blk.{li}.attn_v.weight"))?);
(
crate::weights::pack_weight(ctx, &f, qd + 2 * kd, hidden, WDtype::F16)?,
WKind::F16,
)
};
let (o, o_kind) = single_native(ctx, &mut g, &format!("blk.{li}.attn_output.weight"))?;
let (gt, _, _, graw) = raw_of(&mut g, &format!("blk.{li}.ffn_gate.weight"))?;
let (ut, _, _, uraw) = raw_of(&mut g, &format!("blk.{li}.ffn_up.weight"))?;
let gu_blocks = intermediate * (hidden / 32);
let (w1, w3, gu_kind) = if legacy(gt) && legacy(ut) {
(
native(ctx, &to_q8n(gt, &graw, gu_blocks)?),
native(ctx, &to_q8n(ut, &uraw, gu_blocks)?),
WKind::Q8_0N,
)
} else {
(
f16_fallback(&mut g, &format!("blk.{li}.ffn_gate.weight"))?,
f16_fallback(&mut g, &format!("blk.{li}.ffn_up.weight"))?,
WKind::F16,
)
};
let (w2, w2_kind) = single_native(ctx, &mut g, &format!("blk.{li}.ffn_down.weight"))?;
kinds.push(LayerKinds {
qkv: qkv_kind,
o: o_kind,
gate_up: gu_kind,
down: w2_kind,
});
let qkv_bias = if !is_llama {
let mut bv = g.tensor_f32(&format!("blk.{li}.attn_q.bias"))?;
bv.extend_from_slice(&g.tensor_f32(&format!("blk.{li}.attn_k.bias"))?);
bv.extend_from_slice(&g.tensor_f32(&format!("blk.{li}.attn_v.bias"))?);
Some(ctx.storage(&bv))
} else {
None
};
layers.push(Layer {
operator_norm: norm(&mut g, &format!("blk.{li}.attn_norm.weight"))?,
ffn_norm: norm(&mut g, &format!("blk.{li}.ffn_norm.weight"))?,
op: Op::Attn {
qkv,
o,
q_norm: ctx.storage(&vec![1.0f32; head_dim]),
k_norm: ctx.storage(&vec![1.0f32; head_dim]),
window: 0,
local_rope: false,
attn_gate: None,
qkv_bias,
},
w1,
w2,
w3,
post_op_norm: None,
post_ffn_norm: None,
moe: None,
edge: None,
});
}
let embed = ctx.storage(&g.tensor_f32("token_embd.weight")?);
let head_name = if g.tensors.iter().any(|t| t.name == "output.weight") {
"output.weight"
} else {
"token_embd.weight"
};
let (embed_q4, hk) = {
let (ty, rows, cols, raw) = raw_of(&mut g, head_name)?;
if matches!(ty, 2 | 6 | 8) {
(native(ctx, &to_q8n(ty, &raw, rows * cols / 32)?), WKind::Q8_0N)
} else {
(f16_fallback(&mut g, head_name)?, WKind::F16)
}
};
cfg.layer_kinds = kinds;
cfg.head_kind = Some(hk);
let embedding_norm = norm(&mut g, "output_norm.weight")?;
Ok(Weights {
cfg,
embed,
embed_q4,
embedding_norm,
layers,
mtp: None,
embed_f16: None,
embed_split: None,
ple: None,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn q1_round_trips_binary_valued_weights() {
let (m, n) = (3usize, 256usize);
let mut w = vec![0f32; m * n];
for r in 0..m {
for j in 0..n {
let s = 0.02 + 0.01 * (r as f32) + 0.005 * ((j / 128) as f32);
w[r * n + j] = if (r + j) % 3 == 0 { s } else { -s };
}
}
let (scales, bits) = quantize_q1(&w, m, n);
let back = dequantize_q1(&scales, &bits, m, n);
for (a, b) in w.iter().zip(&back) {
assert!((a - b).abs() < 1e-6, "{a} vs {b}");
}
}
#[test]
fn disk_blocks_decode_to_the_engine_layout() {
let mut raw = vec![0u8; 18];
let scale_bits: u16 = 0x2800; raw[..2].copy_from_slice(&scale_bits.to_le_bytes());
raw[2] = 0b1010_0101; let (scales, bits) = q1_0_disk_to_engine(&raw, 1).unwrap();
assert!((scales[0] - 0.03125).abs() < 1e-6);
assert_eq!(bits[0] & 0xFF, 0b1010_0101);
assert_eq!(bits.len(), 4);
}
}
use crate::iq_tables as iqt;
fn iq_f16(b: &[u8]) -> f32 {
half::f16::from_le_bytes([b[0], b[1]]).to_f32()
}
fn ksign(i: u32) -> u8 {
(i as u8) | (((i.count_ones() & 1) as u8) << 7)
}
fn sgn(byte: u8, bit: usize) -> f32 {
if (byte >> bit) & 1 == 0 { 1.0 } else { -1.0 }
}
fn dequant_iq2_xxs(raw: &[u8], count: usize) -> Result<Vec<f32>> {
ensure!(count.is_multiple_of(256) && raw.len() >= count / 256 * 66);
let mut out = Vec::with_capacity(count);
for blk in raw[..count / 256 * 66].chunks_exact(66) {
let d = iq_f16(blk);
let w32 = |i: usize| {
u32::from_le_bytes([blk[2 + i * 4], blk[3 + i * 4], blk[4 + i * 4], blk[5 + i * 4]])
};
for g in 0..8 {
let (w0, w1) = (w32(2 * g), w32(2 * g + 1));
let db = d * (0.5 + (w1 >> 28) as f32) * 0.25;
for j in 0..4 {
let row = ((w0 >> (8 * j)) & 0xFF) as usize;
let sb = ksign((w1 >> (7 * j)) & 0x7F);
for k in 0..8 {
out.push(db * iqt::IQ2_XXS_GRID[row * 8 + k] as f32 * sgn(sb, k));
}
}
}
}
Ok(out)
}
fn dequant_iq2_xs(raw: &[u8], count: usize) -> Result<Vec<f32>> {
ensure!(count.is_multiple_of(256) && raw.len() >= count / 256 * 74);
let mut out = Vec::with_capacity(count);
for blk in raw[..count / 256 * 74].chunks_exact(74) {
let d = iq_f16(blk);
for w in 0..32 {
let v = u16::from_le_bytes([blk[2 + w * 2], blk[3 + w * 2]]);
let sc = (blk[66 + w / 4] >> (4 * ((w / 2) % 2))) & 0x0F;
let db = d * (0.5 + sc as f32) * 0.25;
let row = (v & 511) as usize;
let sb = ksign(u32::from(v >> 9));
for k in 0..8 {
out.push(db * iqt::IQ2_XS_GRID[row * 8 + k] as f32 * sgn(sb, k));
}
}
}
Ok(out)
}
fn dequant_iq2_s(raw: &[u8], count: usize) -> Result<Vec<f32>> {
ensure!(count.is_multiple_of(256) && raw.len() >= count / 256 * 82);
let (qs0, sg0, qh0, sc0) = (2usize, 34usize, 66usize, 74usize);
let mut out = Vec::with_capacity(count);
for blk in raw[..count / 256 * 82].chunks_exact(82) {
let d = iq_f16(blk);
for b8 in 0..32 {
let sc = (blk[sc0 + b8 / 4] >> (4 * ((b8 / 2) % 2))) & 0x0F;
let db = d * (0.5 + sc as f32) * 0.25;
let row =
blk[qs0 + b8] as usize | ((((blk[qh0 + b8 / 4] >> (2 * (b8 % 4))) & 3) as usize) << 8);
let sb = blk[sg0 + b8];
for k in 0..8 {
out.push(db * iqt::IQ2_S_GRID[row * 8 + k] as f32 * sgn(sb, k));
}
}
}
Ok(out)
}
fn dequant_iq3_xxs(raw: &[u8], count: usize) -> Result<Vec<f32>> {
ensure!(count.is_multiple_of(256) && raw.len() >= count / 256 * 98);
let mut out = Vec::with_capacity(count);
for blk in raw[..count / 256 * 98].chunks_exact(98) {
let d = iq_f16(blk);
let w32 = |i: usize| {
u32::from_le_bytes([blk[66 + i * 4], blk[67 + i * 4], blk[68 + i * 4], blk[69 + i * 4]])
};
for g in 0..8 {
let w = w32(g);
let db = d * (0.5 + (w >> 28) as f32) * 0.5;
for j in 0..4 {
let sb = ksign((w >> (7 * j)) & 0x7F);
for t in 0..2 {
let row = blk[2 + g * 8 + j * 2 + t] as usize;
for k in 0..4 {
out.push(db * iqt::IQ3_XXS_GRID[row * 4 + k] as f32 * sgn(sb, t * 4 + k));
}
}
}
}
}
Ok(out)
}
fn dequant_iq3_s(raw: &[u8], count: usize) -> Result<Vec<f32>> {
ensure!(count.is_multiple_of(256) && raw.len() >= count / 256 * 110);
let (qs0, qh0, sg0, sc0) = (2usize, 66usize, 74usize, 106usize);
let mut out = Vec::with_capacity(count);
for blk in raw[..count / 256 * 110].chunks_exact(110) {
let d = iq_f16(blk);
for i in 0..64 {
let e0 = i * 4; let sc = (blk[sc0 + e0 / 64] >> (4 * ((e0 / 32) % 2))) & 0x0F;
let db = d * (1 + 2 * sc as i32) as f32;
let row = blk[qs0 + i] as usize | ((((blk[qh0 + i / 8] >> (i % 8)) & 1) as usize) << 8);
let sb = blk[sg0 + e0 / 8];
for k in 0..4 {
out.push(db * iqt::IQ3_S_GRID[row * 4 + k] as f32 * sgn(sb, (e0 + k) % 8));
}
}
}
Ok(out)
}
fn dequant_iq1_s(raw: &[u8], count: usize) -> Result<Vec<f32>> {
ensure!(count.is_multiple_of(256) && raw.len() >= count / 256 * 50);
let mut out = Vec::with_capacity(count);
for blk in raw[..count / 256 * 50].chunks_exact(50) {
let d = iq_f16(blk);
for g in 0..8 {
let h = u16::from_le_bytes([blk[34 + g * 2], blk[35 + g * 2]]);
let dl = d * (2 * ((h >> 12) & 7) + 1) as f32;
let delta = if h & 0x8000 == 0 { 0.125f32 } else { -0.125 };
for j in 0..4 {
let row = blk[2 + g * 4 + j] as usize | ((((h >> (3 * j)) & 7) as usize) << 8);
for k in 0..8 {
out.push(dl * (iqt::IQ1_GRID[row * 8 + k] as f32 + delta));
}
}
}
}
Ok(out)
}
fn dequant_iq1_m(raw: &[u8], count: usize) -> Result<Vec<f32>> {
ensure!(count.is_multiple_of(256) && raw.len() >= count / 256 * 56);
let mut out = Vec::with_capacity(count);
for blk in raw[..count / 256 * 56].chunks_exact(56) {
let sc16 = |i: usize| u16::from_le_bytes([blk[48 + i * 2], blk[49 + i * 2]]);
let dbits = ((sc16(0) & 0xF000) >> 12)
| ((sc16(1) & 0xF000) >> 8)
| ((sc16(2) & 0xF000) >> 4)
| (sc16(3) & 0xF000);
let d = half::f16::from_bits(dbits).to_f32();
for s in 0..16 {
let sc = (sc16(s / 4) >> (3 * (s % 4))) & 0x07;
let dl = d * (2 * sc + 1) as f32;
for half_i in 0..2 {
let b8 = s * 2 + half_i; let nib = (blk[32 + b8 / 2] >> (4 * (b8 % 2))) & 0x0F;
let row = blk[b8] as usize | (((nib & 7) as usize) << 8);
let delta = if nib & 8 == 0 { 0.125f32 } else { -0.125 };
for k in 0..8 {
out.push(dl * (iqt::IQ1_GRID[row * 8 + k] as f32 + delta));
}
}
}
}
Ok(out)
}
fn dequant_iq4_nl(raw: &[u8], count: usize) -> Result<Vec<f32>> {
ensure!(count.is_multiple_of(32) && raw.len() >= count / 32 * 18);
let mut out = Vec::with_capacity(count);
for blk in raw[..count / 32 * 18].chunks_exact(18) {
let d = iq_f16(blk);
for l in 0..16 {
out.push(d * iqt::IQ4_KVALUES[(blk[2 + l] & 0x0F) as usize] as f32);
}
for l in 0..16 {
out.push(d * iqt::IQ4_KVALUES[(blk[2 + l] >> 4) as usize] as f32);
}
}
Ok(out)
}
fn dequant_iq4_xs(raw: &[u8], count: usize) -> Result<Vec<f32>> {
ensure!(count.is_multiple_of(256) && raw.len() >= count / 256 * 136);
let mut out = Vec::with_capacity(count);
for blk in raw[..count / 256 * 136].chunks_exact(136) {
let d = iq_f16(blk);
let sh = u16::from_le_bytes([blk[2], blk[3]]);
for sb in 0..8 {
let ls = ((blk[4 + sb / 2] >> (4 * (sb % 2))) & 0x0F) | ((((sh >> (2 * sb)) & 3) as u8) << 4);
let dl = d * (ls as i8 as i32 - 32) as f32;
let q = &blk[8 + sb * 16..8 + sb * 16 + 16];
for l in 0..16 {
out.push(dl * iqt::IQ4_KVALUES[(q[l] & 0x0F) as usize] as f32);
}
for l in 0..16 {
out.push(dl * iqt::IQ4_KVALUES[(q[l] >> 4) as usize] as f32);
}
}
}
Ok(out)
}