use crate::error::{RealizarError, Result};
use crate::gguf::types::{
GGUF_TYPE_F16, GGUF_TYPE_F32, GGUF_TYPE_Q4_K, GGUF_TYPE_Q6_K, GGUF_TYPE_Q8_0,
};
use crate::gguf::GGUFModel;
use crate::quantize::dequant::{
dequantize_q4_k_into, dequantize_q6_k_into, dequantize_q8_0_into, f16_to_f32,
};
pub(crate) struct Qwen35Embedding {
data: Vec<u8>,
qtype: u32,
rows: usize,
row_len: usize,
row_bytes: usize,
}
impl Qwen35Embedding {
pub(crate) fn load(model: &GGUFModel, data: &[u8], hidden_dim: usize) -> Result<Self> {
let r = crate::gguf::QuantizedGGUFTransformer::get_tensor_ref(
model,
data,
"token_embd.weight",
)?;
let end = r.offset.checked_add(r.byte_size);
let bytes = end.and_then(|end| data.get(r.offset..end)).ok_or_else(|| {
RealizarError::FormatError {
reason: format!(
"qwen35: token_embd.weight at byte {} (+{}) lies outside the file",
r.offset, r.byte_size
),
}
})?;
Self::from_bytes(bytes.to_vec(), r.qtype, r.num_elements, hidden_dim)
}
pub(crate) fn from_bytes(
data: Vec<u8>,
qtype: u32,
num_elements: usize,
row_len: usize,
) -> Result<Self> {
let rows = if row_len == 0 {
0
} else {
num_elements / row_len
};
if rows == 0 || rows * row_len != num_elements || data.len() % rows != 0 {
return Err(RealizarError::InvalidShape {
reason: format!(
"qwen35: token_embd.weight ({num_elements} values, {} bytes, type {qtype}) \
does not split into rows of {row_len}",
data.len()
),
});
}
let table = Self {
row_bytes: data.len() / rows,
data,
qtype,
rows,
row_len,
};
if table.row(0)?.len() != row_len {
return Err(RealizarError::InvalidShape {
reason: format!("qwen35: token_embd.weight row 0 is not {row_len} values wide"),
});
}
Ok(table)
}
#[cfg(test)]
pub(crate) fn from_f32(values: &[f32], row_len: usize) -> Result<Self> {
let data = values.iter().flat_map(|v| v.to_le_bytes()).collect();
Self::from_bytes(
data,
crate::gguf::types::GGUF_TYPE_F32,
values.len(),
row_len,
)
}
pub(crate) fn rows(&self) -> usize {
self.rows
}
pub(crate) fn num_elements(&self) -> usize {
self.rows * self.row_len
}
pub(crate) fn row_len(&self) -> usize {
self.row_len
}
pub(crate) fn row(&self, token: usize) -> Result<Vec<f32>> {
let mut out = vec![0.0; self.row_len];
self.row_into(token, &mut out)?;
Ok(out)
}
pub(crate) fn row_into(&self, token: usize, out: &mut [f32]) -> Result<()> {
if token >= self.rows || out.len() != self.row_len {
return Err(RealizarError::InvalidShape {
reason: format!(
"qwen35: row {token} into {} values; the embedding table is {} rows of {}",
out.len(),
self.rows,
self.row_len
),
});
}
let start = token * self.row_bytes;
let bytes = &self.data[start..start + self.row_bytes];
match self.qtype {
GGUF_TYPE_F32 if bytes.len() == 4 * out.len() => {
for (o, b) in out.iter_mut().zip(bytes.as_chunks::<4>().0) {
*o = f32::from_le_bytes(*b);
}
},
GGUF_TYPE_F16 if bytes.len() == 2 * out.len() => {
for (o, b) in out.iter_mut().zip(bytes.as_chunks::<2>().0) {
*o = f16_to_f32(u16::from_le_bytes(*b));
}
},
GGUF_TYPE_Q8_0 => dequantize_q8_0_into(bytes, out)?,
GGUF_TYPE_Q4_K => dequantize_q4_k_into(bytes, out)?,
GGUF_TYPE_Q6_K => dequantize_q6_k_into(bytes, out)?,
_ => out.copy_from_slice(&GGUFModel::dequantize_at(
self.qtype,
bytes,
0,
self.row_len,
)?),
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::Qwen35Embedding;
use crate::gguf::types::{
GGUF_TYPE_F16, GGUF_TYPE_F32, GGUF_TYPE_Q4_0, GGUF_TYPE_Q4_K, GGUF_TYPE_Q6_K,
GGUF_TYPE_Q8_0,
};
use crate::gguf::GGUFModel;
fn q4k_bytes(n: usize) -> Vec<u8> {
let mut data = vec![0u8; n * 144];
for (sb, block) in data.chunks_exact_mut(144).enumerate() {
block[0..2].copy_from_slice(&0x3C00u16.to_le_bytes()); block[2..4].copy_from_slice(&0x3800u16.to_le_bytes()); for (i, b) in block[4..].iter_mut().enumerate() {
*b = (sb * 29 + i * 11) as u8;
}
}
data
}
#[test]
fn each_row_matches_the_whole_table() {
let (rows, row_len) = (5, 512);
let q4k = q4k_bytes(rows * 2);
let mut q8 = vec![0u8; rows * (row_len / 32) * 34];
for (b, block) in q8.chunks_exact_mut(34).enumerate() {
block[0..2].copy_from_slice(&0x3C00u16.to_le_bytes());
for (i, v) in block[2..].iter_mut().enumerate() {
*v = (b * 13 + i * 5) as u8;
}
}
let mut q6k: Vec<u8> = (0..rows * 2 * 210).map(|i| (i * 7) as u8).collect();
for block in q6k.chunks_exact_mut(210) {
block[208..].copy_from_slice(&0x3C00u16.to_le_bytes());
}
let f16: Vec<u8> = (0..rows * row_len)
.flat_map(|i| (0x3C00u16 + (i % 512) as u16).to_le_bytes())
.collect();
let mut q4_0 = vec![0u8; rows * (row_len / 32) * 18];
for (b, block) in q4_0.chunks_exact_mut(18).enumerate() {
block[0..2].copy_from_slice(&0x3800u16.to_le_bytes());
block[2..]
.iter_mut()
.enumerate()
.for_each(|(i, v)| *v = (b + i * 3) as u8);
}
for (qtype, data) in [
(GGUF_TYPE_Q4_K, q4k),
(GGUF_TYPE_Q8_0, q8),
(GGUF_TYPE_Q6_K, q6k),
(GGUF_TYPE_F16, f16),
(GGUF_TYPE_Q4_0, q4_0),
] {
let whole =
GGUFModel::dequantize_at(qtype, &data, 0, rows * row_len).expect("whole table");
let table =
Qwen35Embedding::from_bytes(data, qtype, rows * row_len, row_len).expect("table");
assert_eq!(table.rows(), rows);
for t in 0..rows {
assert!(whole.iter().all(|v| v.is_finite()), "type {qtype}");
let row = table.row(t).expect("row");
for (i, (a, b)) in row
.iter()
.zip(&whole[t * row_len..(t + 1) * row_len])
.enumerate()
{
let tol = 4.0 * f32::EPSILON * a.abs().max(b.abs()).max(1.0);
assert!(
(a - b).abs() <= tol,
"type {qtype} row {t} value {i}: {a} vs {b}"
);
}
}
}
}
#[test]
fn a_token_past_the_table_is_refused() {
let data: Vec<u8> = (0..12).flat_map(|i| (i as f32).to_le_bytes()).collect();
let table = Qwen35Embedding::from_bytes(data, GGUF_TYPE_F32, 12, 4).expect("table");
assert_eq!(table.row(2).expect("last row"), vec![8.0, 9.0, 10.0, 11.0]);
assert!(table.row(3).is_err());
assert!(table.row_into(0, &mut [0.0; 3]).is_err());
}
#[test]
fn a_table_that_does_not_split_into_rows_is_refused() {
let data: Vec<u8> = (0..10).flat_map(|i| (i as f32).to_le_bytes()).collect();
assert!(Qwen35Embedding::from_bytes(data, GGUF_TYPE_F32, 10, 4).is_err());
assert!(Qwen35Embedding::from_bytes(vec![0u8; 64], 9999, 16, 8).is_err());
}
}