use crate::Device;
use crate::lazy::Tensor;
use fuel_ir::{Result, Shape};
pub struct Nf4Weight {
pub w_packed: Tensor,
pub absmax: Tensor,
pub n: usize,
pub k: usize,
pub block_size: usize,
}
pub fn nf4_from_bytes(
w_packed: impl Into<Vec<u8>>,
absmax: impl Into<Vec<f32>>,
n: usize,
k: usize,
block_size: usize,
device: &Device,
) -> Result<Nf4Weight> {
let w_packed: Vec<u8> = w_packed.into();
let absmax: Vec<f32> = absmax.into();
if k == 0 || !k.is_multiple_of(2) {
return Err(fuel_ir::Error::Msg(format!(
"nf4_from_bytes: k={k} must be even and non-zero",
))
.bt());
}
if block_size == 0 || !k.is_multiple_of(block_size) {
return Err(fuel_ir::Error::Msg(format!(
"nf4_from_bytes: k={k} must be a positive multiple of block_size={block_size}",
))
.bt());
}
let w_expected = n.saturating_mul(k / 2);
if w_packed.len() != w_expected {
return Err(fuel_ir::Error::Msg(format!(
"nf4_from_bytes: w_packed has {} bytes, expected {w_expected} (n={n} × k/2={})",
w_packed.len(),
k / 2,
))
.bt());
}
let abs_expected = n.saturating_mul(k / block_size);
if absmax.len() != abs_expected {
return Err(fuel_ir::Error::Msg(format!(
"nf4_from_bytes: absmax has {} f32 elements, expected {abs_expected} \
(n={n} × k/block_size={})",
absmax.len(),
k / block_size,
))
.bt());
}
let anchor = Tensor::from_f32(vec![0.0_f32], Shape::from_dims(&[1]), device)?;
let w_packed_tensor = anchor
.graph_tensor()
.const_u8_like(w_packed, Shape::from_dims(&[n, k / 2]))?;
let absmax_tensor = anchor
.graph_tensor()
.const_f32_like(absmax, Shape::from_dims(&[n, k / block_size]))?;
Ok(Nf4Weight {
w_packed: Tensor::from_graph_tensor(w_packed_tensor),
absmax: Tensor::from_graph_tensor(absmax_tensor),
n,
k,
block_size,
})
}
impl Nf4Weight {
pub fn matmul(&self, activations: &Tensor) -> Tensor {
activations.nf4_matmul(&self.w_packed, &self.absmax, self.block_size)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct BnbQuantState {
pub n: usize,
pub k: usize,
pub block_size: usize,
pub nested: Option<BnbNestedState>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct BnbNestedState {
pub block_size: usize,
pub offset: f32,
}
pub fn parse_bnb_quant_state(json_bytes: &[u8]) -> fuel_ir::Result<BnbQuantState> {
let v: serde_json::Value = serde_json::from_slice(json_bytes).map_err(|e| {
fuel_ir::Error::Msg(format!("parse_bnb_quant_state: failed to parse JSON: {e}",)).bt()
})?;
let obj = v.as_object().ok_or_else(|| {
fuel_ir::Error::Msg(
"parse_bnb_quant_state: expected a JSON object at the top level".to_string(),
)
.bt()
})?;
let quant_type = obj
.get("quant_type")
.and_then(|v| v.as_str())
.ok_or_else(|| {
fuel_ir::Error::Msg(
"parse_bnb_quant_state: missing or non-string 'quant_type' field".to_string(),
)
.bt()
})?;
if quant_type != "nf4" {
return Err(fuel_ir::Error::Msg(format!(
"parse_bnb_quant_state: only quant_type=\"nf4\" is supported, \
got {quant_type:?}. Other bnb formats (fp4, etc.) need their \
own loader path.",
))
.bt());
}
if obj.contains_key("nested_absmax") || obj.contains_key("nested_quant_map") {
return Err(fuel_ir::Error::Msg(
"parse_bnb_quant_state: nested_absmax / nested_quant_map are tensors in \
bitsandbytes checkpoints, not JSON fields; this blob is not in the \
packed quant_state format"
.to_string(),
)
.bt());
}
let nested = parse_nested(obj)?;
let shape = obj.get("shape").and_then(|v| v.as_array()).ok_or_else(|| {
fuel_ir::Error::Msg("parse_bnb_quant_state: missing or non-array 'shape' field".to_string())
.bt()
})?;
if shape.len() != 2 {
return Err(fuel_ir::Error::Msg(format!(
"parse_bnb_quant_state: 'shape' must be 2-element [N, K], got len={}",
shape.len(),
))
.bt());
}
let n = shape[0].as_u64().ok_or_else(|| {
fuel_ir::Error::Msg(
"parse_bnb_quant_state: shape[0] (N) must be a non-negative integer".to_string(),
)
.bt()
})? as usize;
let k = shape[1].as_u64().ok_or_else(|| {
fuel_ir::Error::Msg(
"parse_bnb_quant_state: shape[1] (K) must be a non-negative integer".to_string(),
)
.bt()
})? as usize;
let block_size = obj
.get("blocksize")
.and_then(|v| v.as_u64())
.ok_or_else(|| {
fuel_ir::Error::Msg(
"parse_bnb_quant_state: missing or non-integer 'blocksize' field".to_string(),
)
.bt()
})? as usize;
if block_size == 0 {
return Err(fuel_ir::Error::Msg(
"parse_bnb_quant_state: blocksize must be positive".to_string(),
)
.bt());
}
if !k.is_multiple_of(block_size) {
return Err(fuel_ir::Error::Msg(format!(
"parse_bnb_quant_state: blocksize={block_size} doesn't divide K={k} \
(this would leave a partial block at the end of each row, which \
bnb's standard format doesn't produce — your checkpoint may be \
corrupted or use a non-standard variant)",
))
.bt());
}
if !k.is_multiple_of(2) {
return Err(fuel_ir::Error::Msg(format!(
"parse_bnb_quant_state: K={k} must be even (NF4 packs 2 codes per byte)",
))
.bt());
}
Ok(BnbQuantState {
n,
k,
block_size,
nested,
})
}
fn parse_nested(
obj: &serde_json::Map<String, serde_json::Value>,
) -> fuel_ir::Result<Option<BnbNestedState>> {
match (
obj.get("nested_blocksize"),
obj.get("nested_offset"),
obj.get("nested_dtype"),
) {
(None, None, None) => Ok(None),
(Some(bs), Some(off), Some(dt)) => nested_from_fields(bs, off, dt).map(Some),
_ => Err(nested_err(
"double quantization needs all of nested_blocksize, nested_offset and nested_dtype",
)),
}
}
fn nested_err(m: &str) -> fuel_ir::Error {
fuel_ir::Error::Msg(format!("parse_bnb_quant_state: {m}")).bt()
}
fn nested_from_fields(
bs: &serde_json::Value,
off: &serde_json::Value,
dt: &serde_json::Value,
) -> fuel_ir::Result<BnbNestedState> {
if dt.as_str() != Some("float32") {
return Err(nested_err(&format!(
"only nested_dtype \"float32\" is supported, got {dt}"
)));
}
let block_size = bs
.as_u64()
.filter(|b| *b > 0)
.ok_or_else(|| nested_err("nested_blocksize must be a positive integer"))?
as usize;
let offset = off
.as_f64()
.ok_or_else(|| nested_err("nested_offset must be a number"))? as f32;
Ok(BnbNestedState { block_size, offset })
}
pub fn dequantize_nested_absmax(
q: &[u8],
nested_absmax: &[f32],
nested_quant_map: &[f32],
nested_block_size: usize,
offset: f32,
) -> fuel_ir::Result<Vec<f32>> {
let err = |m: String| fuel_ir::Error::Msg(format!("dequantize_nested_absmax: {m}")).bt();
if nested_quant_map.len() != 256 {
return Err(err(format!(
"nested_quant_map has {} entries, expected 256",
nested_quant_map.len()
)));
}
if nested_block_size == 0 {
return Err(err("nested block size must be positive".to_string()));
}
let want = q.len().div_ceil(nested_block_size);
if nested_absmax.len() != want {
return Err(err(format!(
"nested_absmax has {} scales, expected {want} ({} codes / block {nested_block_size})",
nested_absmax.len(),
q.len()
)));
}
Ok(q.iter()
.enumerate()
.map(|(i, &code)| {
nested_quant_map[code as usize] * nested_absmax[i / nested_block_size] + offset
})
.collect())
}
fn f32_from_le_bytes(bytes: &[u8], key: &str) -> fuel_ir::Result<Vec<f32>> {
if !bytes.len().is_multiple_of(4) {
return Err(fuel_ir::Error::Msg(format!(
"load_nf4_layer: {key:?} has {} bytes (not a multiple of 4 — corrupt F32 data)",
bytes.len(),
))
.bt());
}
Ok(bytes
.as_chunks::<4>()
.0
.iter()
.map(|c| f32::from_le_bytes(*c))
.collect())
}
pub fn load_nf4_layer(
st: &safetensors::SafeTensors,
prefix: &str,
device: &Device,
) -> fuel_ir::Result<Nf4Weight> {
let weight_key = format!("{prefix}.weight");
let absmax_key = format!("{prefix}.weight.absmax");
let quant_state_key = format!("{prefix}.weight.quant_state.bitsandbytes__nf4");
let weight_view = st.tensor(&weight_key).map_err(|e| {
fuel_ir::Error::Msg(format!(
"load_nf4_layer: tensor {weight_key:?} not found in safetensors: {e}",
))
.bt()
})?;
let absmax_view = st.tensor(&absmax_key).map_err(|e| {
fuel_ir::Error::Msg(format!(
"load_nf4_layer: tensor {absmax_key:?} not found in safetensors: {e}",
))
.bt()
})?;
let quant_state_view = st.tensor(&quant_state_key).map_err(|e| {
fuel_ir::Error::Msg(format!(
"load_nf4_layer: tensor {quant_state_key:?} not found in safetensors: {e}",
))
.bt()
})?;
let qs = parse_bnb_quant_state(quant_state_view.data())?;
if weight_view.dtype() != safetensors::Dtype::U8 {
return Err(fuel_ir::Error::Msg(format!(
"load_nf4_layer: {weight_key:?} dtype={:?}, expected U8",
weight_view.dtype(),
))
.bt());
}
let w_bytes: Vec<u8> = weight_view
.data()
.iter()
.map(|b| b.rotate_left(4))
.collect();
let absmax_f32: Vec<f32> = match &qs.nested {
None => {
if absmax_view.dtype() != safetensors::Dtype::F32 {
return Err(fuel_ir::Error::Msg(format!(
"load_nf4_layer: {absmax_key:?} dtype={:?}, expected F32 (the quant_state \
blob has no nested_* fields, so the absmax is not double-quantized)",
absmax_view.dtype(),
))
.bt());
}
f32_from_le_bytes(absmax_view.data(), &absmax_key)?
}
Some(nested) => {
if absmax_view.dtype() != safetensors::Dtype::U8 {
return Err(fuel_ir::Error::Msg(format!(
"load_nf4_layer: {absmax_key:?} dtype={:?}, expected U8 (the quant_state \
blob is double-quantized)",
absmax_view.dtype(),
))
.bt());
}
let read_f32 = |suffix: &str| -> fuel_ir::Result<Vec<f32>> {
let key = format!("{prefix}.weight.{suffix}");
let view = st.tensor(&key).map_err(|e| {
fuel_ir::Error::Msg(format!(
"load_nf4_layer: tensor {key:?} not found in safetensors: {e}",
))
.bt()
})?;
if view.dtype() != safetensors::Dtype::F32 {
return Err(fuel_ir::Error::Msg(format!(
"load_nf4_layer: {key:?} dtype={:?}, expected F32",
view.dtype(),
))
.bt());
}
f32_from_le_bytes(view.data(), &key)
};
let nested_absmax = read_f32("nested_absmax")?;
let nested_quant_map = read_f32("nested_quant_map")?;
dequantize_nested_absmax(
absmax_view.data(),
&nested_absmax,
&nested_quant_map,
nested.block_size,
nested.offset,
)?
}
};
nf4_from_bytes(w_bytes, absmax_f32, qs.n, qs.k, qs.block_size, device)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn nf4_weight_matmul_round_trip() {
let device = Device::cpu();
let weight = nf4_from_bytes(
vec![247_u8, 247, 127, 127],
vec![1.0_f32, 2.0, 10.0, 20.0],
2,
4,
2,
&device,
)
.expect("nf4_from_bytes");
let activations = Tensor::from_f32(
vec![1.0_f32, 2.0, 2.0, 4.0],
Shape::from_dims(&[1, 4]),
&device,
)
.unwrap();
let activations_t = weight
.w_packed
.graph_tensor()
.const_f32_like(vec![1.0_f32, 2.0, 2.0, 4.0], Shape::from_dims(&[1, 4]))
.unwrap();
let _ = activations; let act = Tensor::from_graph_tensor(activations_t);
let y = weight.matmul(&act).realize_f32();
assert_eq!(y.len(), 2);
assert!((y[0] - 10.0).abs() < 1e-5, "out 0: {}", y[0]);
assert!((y[1] - 50.0).abs() < 1e-5, "out 1: {}", y[1]);
}
#[test]
fn nf4_from_bytes_rejects_odd_k() {
let r = nf4_from_bytes(
vec![0_u8; 6],
vec![0.0_f32; 2],
2,
3,
1,
&Device::cpu(),
);
assert!(r.is_err());
}
#[test]
fn nf4_from_bytes_rejects_block_size_mismatch() {
let r = nf4_from_bytes(
vec![0_u8; 4],
vec![0.0_f32; 2],
2,
4,
3,
&Device::cpu(),
);
assert!(r.is_err());
}
#[test]
fn nf4_from_bytes_rejects_wrong_packed_size() {
let r = nf4_from_bytes(
vec![0_u8; 5], vec![0.0_f32; 2],
2,
4,
2,
&Device::cpu(),
);
assert!(r.is_err());
}
#[test]
fn parse_bnb_quant_state_minimal_nf4() {
let json = br#"{"quant_type":"nf4","shape":[256,128],"blocksize":64,"dtype":"float16"}"#;
let qs = parse_bnb_quant_state(json).expect("parse_bnb_quant_state");
assert_eq!(
qs,
BnbQuantState {
n: 256,
k: 128,
block_size: 64,
nested: None,
}
);
}
#[test]
fn parse_bnb_quant_state_rejects_fp4() {
let json = br#"{"quant_type":"fp4","shape":[256,128],"blocksize":64}"#;
let r = parse_bnb_quant_state(json);
let err = r.unwrap_err().to_string();
assert!(err.contains("nf4"), "error should mention nf4: {err}");
}
#[test]
fn parse_bnb_quant_state_rejects_nested_absmax() {
let json =
br#"{"quant_type":"nf4","shape":[256,128],"blocksize":64,"nested_absmax":[1.0,2.0]}"#;
let r = parse_bnb_quant_state(json);
let err = r.unwrap_err().to_string();
assert!(
err.contains("nested_absmax"),
"error should name the offending field: {err}"
);
}
#[test]
fn parse_bnb_quant_state_rejects_misaligned_blocksize() {
let json = br#"{"quant_type":"nf4","shape":[256,130],"blocksize":64}"#;
let r = parse_bnb_quant_state(json);
let err = r.unwrap_err().to_string();
assert!(
err.contains("doesn't divide K") || err.contains("must be even"),
"error should flag misalignment: {err}"
);
}
#[test]
fn parse_bnb_quant_state_rejects_odd_k() {
let json = br#"{"quant_type":"nf4","shape":[256,127],"blocksize":1}"#;
let r = parse_bnb_quant_state(json);
let err = r.unwrap_err().to_string();
assert!(
err.contains("must be even"),
"error should flag odd K: {err}"
);
}
#[test]
fn parse_bnb_quant_state_rejects_malformed_json() {
let r = parse_bnb_quant_state(b"not json at all");
assert!(r.is_err());
}
#[test]
fn parse_bnb_quant_state_rejects_missing_shape() {
let json = br#"{"quant_type":"nf4","blocksize":64}"#;
let r = parse_bnb_quant_state(json);
let err = r.unwrap_err().to_string();
assert!(err.contains("shape"), "error should mention shape: {err}");
}
#[test]
fn load_nf4_layer_round_trip_synthetic_safetensors() {
use safetensors::tensor::TensorView;
use std::collections::HashMap;
let n: usize = 2;
let k: usize = 4;
let block_size: usize = 2;
let weight_bytes = vec![0x7F_u8, 0x7F, 0xF7, 0xF7];
let absmax_floats: Vec<f32> = vec![1.0, 2.0, 10.0, 20.0];
let absmax_bytes: Vec<u8> = absmax_floats.iter().flat_map(|f| f.to_le_bytes()).collect();
let quant_state_json = format!(
r#"{{"quant_type":"nf4","shape":[{n},{k}],"blocksize":{block_size},"dtype":"float16"}}"#,
);
let quant_state_bytes = quant_state_json.as_bytes().to_vec();
let weight_view = TensorView::new(safetensors::Dtype::U8, vec![n * k / 2], &weight_bytes)
.expect("weight TensorView");
let absmax_view = TensorView::new(
safetensors::Dtype::F32,
vec![n * k / block_size],
&absmax_bytes,
)
.expect("absmax TensorView");
let quant_state_view = TensorView::new(
safetensors::Dtype::U8,
vec![quant_state_bytes.len()],
&quant_state_bytes,
)
.expect("quant_state TensorView");
let mut tensors: HashMap<String, TensorView<'_>> = HashMap::new();
tensors.insert("layer.weight".to_string(), weight_view);
tensors.insert("layer.weight.absmax".to_string(), absmax_view);
tensors.insert(
"layer.weight.quant_state.bitsandbytes__nf4".to_string(),
quant_state_view,
);
let metadata: Option<std::collections::HashMap<String, String>> = None;
let serialized =
safetensors::serialize(&tensors, metadata.clone()).expect("safetensors::serialize");
let st =
safetensors::SafeTensors::deserialize(&serialized).expect("SafeTensors::deserialize");
let weight = load_nf4_layer(&st, "layer", &Device::cpu()).expect("load_nf4_layer");
assert_eq!(weight.n, n);
assert_eq!(weight.k, k);
assert_eq!(weight.block_size, block_size);
let act = Tensor::from_graph_tensor(
weight
.w_packed
.graph_tensor()
.const_f32_like(vec![1.0_f32, 2.0, 2.0, 4.0], Shape::from_dims(&[1, 4]))
.unwrap(),
);
let y = weight.matmul(&act).realize_f32();
assert!((y[0] - 10.0).abs() < 1e-5, "out 0: {}", y[0]);
assert!((y[1] - 50.0).abs() < 1e-5, "out 1: {}", y[1]);
}
#[test]
fn load_nf4_layer_missing_weight_errors() {
use safetensors::tensor::TensorView;
use std::collections::HashMap;
let quant_state_bytes = br#"{"quant_type":"nf4","shape":[2,4],"blocksize":2}"#.to_vec();
let absmax_bytes: Vec<u8> = [1.0_f32, 2.0, 10.0, 20.0]
.iter()
.flat_map(|f| f.to_le_bytes())
.collect();
let mut tensors: HashMap<String, TensorView<'_>> = HashMap::new();
tensors.insert(
"layer.weight.absmax".to_string(),
TensorView::new(safetensors::Dtype::F32, vec![4], &absmax_bytes).unwrap(),
);
tensors.insert(
"layer.weight.quant_state.bitsandbytes__nf4".to_string(),
TensorView::new(
safetensors::Dtype::U8,
vec![quant_state_bytes.len()],
&quant_state_bytes,
)
.unwrap(),
);
let metadata: Option<HashMap<String, String>> = None;
let serialized = safetensors::serialize(&tensors, metadata.clone()).unwrap();
let st = safetensors::SafeTensors::deserialize(&serialized).unwrap();
let err = match load_nf4_layer(&st, "layer", &Device::cpu()) {
Ok(_) => panic!("expected an error from load_nf4_layer with missing weight tensor"),
Err(e) => e.to_string(),
};
assert!(
err.contains("layer.weight"),
"error should mention the missing tensor: {err}"
);
}
const DQ_FIXTURE: &[u8] = include_bytes!(
"../tests/fixtures/bnb_double_quant/bnb_double_quant_k_proj_16rows.safetensors"
);
const DQ_ORIGINAL_BF16: &[u8] =
include_bytes!("../tests/fixtures/bnb_double_quant/orig_k_proj_16rows_bf16.bin");
const DQ_PREFIX: &str = "model.layers.1.self_attn.k_proj";
const DQ_N: usize = 16;
const DQ_K: usize = 1024;
fn f32s(bytes: &[u8]) -> Vec<f32> {
bytes
.as_chunks::<4>()
.0
.iter()
.map(|c| f32::from_le_bytes(*c))
.collect()
}
fn rel_rms_vs_original(got: impl Fn(usize, usize) -> f32) -> f64 {
let (mut num, mut den) = (0.0f64, 0.0f64);
for n in 0..DQ_N {
for k in 0..DQ_K {
let i = n * DQ_K + k;
let bits =
u16::from_le_bytes([DQ_ORIGINAL_BF16[2 * i], DQ_ORIGINAL_BF16[2 * i + 1]]);
let want = f32::from_bits((bits as u32) << 16) as f64;
let d = got(n, k) as f64 - want;
num += d * d;
den += want * want;
}
}
(num / den).sqrt()
}
fn dequant_through_fuel(w: &Nf4Weight) -> Vec<f32> {
let mut eye = vec![0.0f32; DQ_K * DQ_K];
for i in 0..DQ_K {
eye[i * DQ_K + i] = 1.0;
}
let act = Tensor::from_graph_tensor(
w.w_packed
.graph_tensor()
.const_f32_like(eye, Shape::from_dims(&[DQ_K, DQ_K]))
.unwrap(),
);
w.matmul(&act).realize_f32()
}
#[test]
fn double_quant_fixture_json_parses_with_nested_state() {
let st = safetensors::SafeTensors::deserialize(DQ_FIXTURE).unwrap();
let blob = st
.tensor(&format!("{DQ_PREFIX}.weight.quant_state.bitsandbytes__nf4"))
.unwrap();
let qs = parse_bnb_quant_state(blob.data()).expect("real bnb blob parses");
assert_eq!((qs.n, qs.k, qs.block_size), (DQ_N, DQ_K, 64));
let nested = qs.nested.expect("double-quant blob carries nested state");
assert_eq!(nested.block_size, 256);
assert!(
(nested.offset - 0.072_918_33).abs() < 1e-7,
"{}",
nested.offset
);
}
#[test]
fn dequantize_nested_absmax_hand_computed() {
let mut map = vec![0.0f32; 256];
map[0] = -1.0;
map[1] = 0.5;
map[255] = 1.0;
let out =
dequantize_nested_absmax(&[0, 1, 255, 1, 0], &[2.0, 4.0, 8.0], &map, 2, 0.25).unwrap();
assert_eq!(out, vec![-1.75, 1.25, 4.25, 2.25, -7.75]);
}
#[test]
fn dequantize_nested_absmax_rejects_bad_geometry() {
let map = vec![0.0f32; 256];
assert!(dequantize_nested_absmax(&[0; 4], &[1.0; 2], &map[..255], 2, 0.0).is_err());
assert!(dequantize_nested_absmax(&[0; 4], &[1.0; 2], &map, 0, 0.0).is_err());
assert!(dequantize_nested_absmax(&[0; 4], &[1.0; 3], &map, 2, 0.0).is_err());
assert!(dequantize_nested_absmax(&[0; 4], &[1.0; 1], &map, 2, 0.0).is_err());
}
#[test]
fn parse_nested_requires_all_three_fields() {
let ok = br#"{"quant_type":"nf4","shape":[16,128],"blocksize":64,
"nested_blocksize":256,"nested_dtype":"float32","nested_offset":0.5}"#;
let qs = parse_bnb_quant_state(ok).unwrap();
assert_eq!(
qs.nested,
Some(BnbNestedState {
block_size: 256,
offset: 0.5
})
);
let missing_offset = br#"{"quant_type":"nf4","shape":[16,128],"blocksize":64,
"nested_blocksize":256,"nested_dtype":"float32"}"#;
assert!(parse_bnb_quant_state(missing_offset).is_err());
let wrong_dtype = br#"{"quant_type":"nf4","shape":[16,128],"blocksize":64,
"nested_blocksize":256,"nested_dtype":"float16","nested_offset":0.5}"#;
assert!(parse_bnb_quant_state(wrong_dtype).is_err());
}
#[test]
fn load_nf4_layer_double_quant_matches_original_weights() {
let st = safetensors::SafeTensors::deserialize(DQ_FIXTURE).unwrap();
let w = match load_nf4_layer(&st, DQ_PREFIX, &Device::cpu()) {
Ok(w) => w,
Err(e) => panic!("double-quant load failed: {e}"),
};
assert_eq!((w.n, w.k, w.block_size), (DQ_N, DQ_K, 64));
let y = dequant_through_fuel(&w);
let err = rel_rms_vs_original(|n, k| y[k * DQ_N + n]);
assert!(err < 0.16, "relative RMS error vs original weights {err}");
}
#[test]
fn double_quant_error_band_rejects_a_wrong_absmax_decode() {
let st = safetensors::SafeTensors::deserialize(DQ_FIXTURE).unwrap();
let get = |suffix: &str| st.tensor(&format!("{DQ_PREFIX}.weight{suffix}")).unwrap();
let q = get(".absmax").data().to_vec();
let nested_absmax = f32s(get(".nested_absmax").data());
let map = f32s(get(".nested_quant_map").data());
let raw_packed = get("").data().to_vec();
let packed: Vec<u8> = raw_packed.iter().map(|b| b.rotate_left(4)).collect();
let build = |absmax: Vec<f32>| {
let w = nf4_from_bytes(packed.clone(), absmax, DQ_N, DQ_K, 64, &Device::cpu()).unwrap();
let y = dequant_through_fuel(&w);
rel_rms_vs_original(|n, k| y[k * DQ_N + n])
};
let good =
build(dequantize_nested_absmax(&q, &nested_absmax, &map, 256, 0.072_918_33).unwrap());
let raw_nibbles = {
let absmax =
dequantize_nested_absmax(&q, &nested_absmax, &map, 256, 0.072_918_33).unwrap();
let w =
nf4_from_bytes(raw_packed.clone(), absmax, DQ_N, DQ_K, 64, &Device::cpu()).unwrap();
let y = dequant_through_fuel(&w);
rel_rms_vs_original(|n, k| y[k * DQ_N + n])
};
assert!(
raw_nibbles > 2.0 * good,
"raw-nibble {raw_nibbles} vs good {good}"
);
let no_offset =
build(dequantize_nested_absmax(&q, &nested_absmax, &map, 256, 0.0).unwrap());
let no_scale =
build(dequantize_nested_absmax(&q, &[1.0], &map, 256, 0.072_918_33).unwrap());
assert!(good < 0.16, "good decode {good}");
assert!(
no_offset > 2.0 * good,
"offset-less {no_offset} vs good {good}"
);
assert!(
no_scale > 2.0 * good,
"scale-less {no_scale} vs good {good}"
);
}
#[test]
fn load_nf4_layer_rejects_u8_absmax_without_nested_state() {
use safetensors::tensor::TensorView;
use std::collections::HashMap;
let w = vec![0u8; 4];
let am = vec![0u8; 2];
let qs = br#"{"quant_type":"nf4","shape":[2,4],"blocksize":2}"#.to_vec();
let mut t: HashMap<String, TensorView<'_>> = HashMap::new();
t.insert(
"l.weight".into(),
TensorView::new(safetensors::Dtype::U8, vec![4], &w).unwrap(),
);
t.insert(
"l.weight.absmax".into(),
TensorView::new(safetensors::Dtype::U8, vec![2], &am).unwrap(),
);
t.insert(
"l.weight.quant_state.bitsandbytes__nf4".into(),
TensorView::new(safetensors::Dtype::U8, vec![qs.len()], &qs).unwrap(),
);
let ser = safetensors::serialize(&t, None::<HashMap<String, String>>).unwrap();
let st = safetensors::SafeTensors::deserialize(&ser).unwrap();
assert!(load_nf4_layer(&st, "l", &Device::cpu()).is_err());
}
}