pub mod config;
pub mod embeddings;
pub mod encoder;
pub mod gemm;
pub mod layer;
pub mod load;
pub use config::{ModernBertConfig, ModernBertConfigError, MAX_NUM_HIDDEN_LAYERS};
pub use embeddings::ModernBertEmbeddings;
pub use encoder::ModernBertEncoder;
pub use gemm::Linear;
pub use layer::{attention, gelu_exact, layer_norm, rope_rotate_half, ModernBertLayer};
pub use load::{expected_modernbert_tensor_names, load_tensor, ModernBertLoadError};
use std::fmt;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ModernBertError {
EmptyInput,
OutOfVocab {
position: usize,
id: u32,
vocab_size: usize,
},
InputShape {
what: &'static str,
expected: Option<usize>,
observed: usize,
},
Gemm(String),
}
impl fmt::Display for ModernBertError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::EmptyInput => write!(f, "modernbert: empty input row"),
Self::OutOfVocab {
position,
id,
vocab_size,
} => write!(
f,
"modernbert: token id {id} at position {position} is out of vocabulary (size {vocab_size})"
),
Self::InputShape {
what,
expected,
observed,
} => match expected {
Some(e) => write!(f, "modernbert: {what} has length {observed}, expected {e}"),
None => write!(
f,
"modernbert: {what} has length {observed}, and its dimensions overflow usize"
),
},
Self::Gemm(e) => write!(f, "modernbert: gemm_blis failed: {e}"),
}
}
}
impl std::error::Error for ModernBertError {}
pub(crate) fn check_len(
what: &'static str,
observed: usize,
dims: &[usize],
) -> Result<(), ModernBertError> {
let expected = dims.iter().try_fold(1usize, |acc, &d| acc.checked_mul(d));
if expected == Some(observed) {
Ok(())
} else {
Err(ModernBertError::InputShape {
what,
expected,
observed,
})
}
}
#[cfg(test)]
pub(crate) mod test_support {
use super::{ModernBertConfig, ModernBertEncoder, ModernBertLoadError};
use crate::format::v2::{AprV2Metadata, AprV2ReaderRef, AprV2Writer, TensorDType};
use std::cmp::Ordering;
use std::path::{Path, PathBuf};
pub(crate) type RawTensor = (String, Vec<usize>, Vec<u8>);
pub(crate) fn fixture_dir() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/modernbert_tiny")
}
pub(crate) fn config_bytes() -> Vec<u8> {
std::fs::read(fixture_dir().join("config.json")).expect("read modernbert_tiny/config.json")
}
pub(crate) fn fixture_config() -> ModernBertConfig {
ModernBertConfig::from_json_bytes(&config_bytes()).expect("fixture config is supported")
}
pub(crate) fn fixture_tensors() -> Vec<RawTensor> {
let bytes = std::fs::read(fixture_dir().join("model.safetensors"))
.expect("read modernbert_tiny/model.safetensors");
let st = safetensors::SafeTensors::deserialize(&bytes).expect("parse safetensors");
let mut out: Vec<RawTensor> = st
.tensors()
.into_iter()
.map(|(name, view)| {
assert_eq!(
view.dtype(),
safetensors::Dtype::F16,
"{name}: fixture is F16"
);
(name, view.shape().to_vec(), view.data().to_vec())
})
.collect();
out.sort_by(|a, b| a.0.cmp(&b.0));
out
}
pub(crate) fn write_apr(tensors: &[RawTensor], prefix: &str) -> Vec<u8> {
let mut w = AprV2Writer::new(AprV2Metadata::default());
for (name, shape, raw) in tensors {
w.add_tensor(
format!("{prefix}{name}"),
TensorDType::F16,
shape.clone(),
raw.clone(),
);
}
w.write().expect("write in-memory .apr")
}
pub(crate) fn load(
apr: &[u8],
prefix: &str,
config: &ModernBertConfig,
) -> Result<ModernBertEncoder, ModernBertLoadError> {
let reader = AprV2ReaderRef::from_bytes(apr).expect("open in-memory .apr");
ModernBertEncoder::from_apr(&reader, prefix, config)
}
pub(crate) fn fixture_encoder() -> ModernBertEncoder {
let cfg = fixture_config();
load(&write_apr(&fixture_tensors(), ""), "", &cfg).expect("load tiny fixture")
}
pub(crate) struct OracleRow {
pub(crate) ids: Vec<u32>,
pub(crate) blocks: Vec<(String, Vec<f32>)>,
}
impl OracleRow {
pub(crate) fn block(&self, name: &str) -> &[f32] {
&self
.blocks
.iter()
.find(|(n, _)| n == name)
.unwrap_or_else(|| panic!("oracle block {name} missing"))
.1
}
}
pub(crate) fn oracle_json() -> serde_json::Value {
let bytes = std::fs::read(fixture_dir().join("oracle.json"))
.expect("read modernbert_tiny/oracle.json");
serde_json::from_slice(&bytes).expect("parse oracle.json")
}
pub(crate) fn oracle_rows() -> Vec<OracleRow> {
let o = oracle_json();
let names: Vec<String> = o["blocks"]
.as_array()
.expect("oracle blocks")
.iter()
.map(|b| b.as_str().expect("block name").to_string())
.collect();
o["rows"]
.as_array()
.expect("oracle rows")
.iter()
.map(|r| OracleRow {
ids: r["ids"]
.as_array()
.expect("ids")
.iter()
.map(|v| u32::try_from(v.as_u64().expect("id")).expect("id fits u32"))
.collect(),
blocks: names
.iter()
.map(|n| {
let vals = r[n.as_str()]
.as_array()
.unwrap_or_else(|| panic!("block {n}"))
.iter()
.map(|v| v.as_f64().expect("f32 value") as f32)
.collect();
(n.clone(), vals)
})
.collect(),
})
.collect()
}
pub(crate) fn tolerance(equation: &str) -> f64 {
let path =
Path::new(env!("CARGO_MANIFEST_DIR")).join("../../contracts/laya-parity-v1.yaml");
let text = std::fs::read_to_string(&path).expect("read laya-parity-v1.yaml");
let y: serde_yaml::Value = serde_yaml::from_str(&text).expect("parse laya-parity-v1.yaml");
y["equations"][equation]["float_tolerance"]
.as_f64()
.unwrap_or_else(|| panic!("laya-parity-v1 equations.{equation}.float_tolerance"))
}
pub(crate) fn within(delta: f64, bound: f64) -> bool {
matches!(
delta.partial_cmp(&bound),
Some(Ordering::Less | Ordering::Equal)
)
}
pub(crate) fn max_abs(a: &[f32], b: &[f32]) -> f64 {
if a.len() != b.len() {
return f64::NAN;
}
a.iter().zip(b).fold(0.0f64, |m, (&x, &y)| {
let d = (f64::from(x) - f64::from(y)).abs();
if d.is_nan() || m.is_nan() {
f64::NAN
} else {
m.max(d)
}
})
}
pub(crate) fn rel_rms(a: &[f32], reference: &[f32]) -> f64 {
if a.len() != reference.len() || reference.is_empty() {
return f64::NAN;
}
let n = reference.len() as f64;
let num = a
.iter()
.zip(reference)
.map(|(&x, &y)| (f64::from(x) - f64::from(y)).powi(2))
.sum::<f64>()
/ n;
let den = reference.iter().map(|&y| f64::from(y).powi(2)).sum::<f64>() / n;
(num / den).sqrt()
}
pub(crate) fn run_taps(
encoder: &ModernBertEncoder,
ids: &[u32],
) -> (Vec<f32>, Vec<(String, Vec<f32>)>) {
let mut taps = Vec::new();
let out = encoder
.forward(ids, |name, block| {
taps.push((name.to_string(), block.to_vec()))
})
.expect("forward");
(out, taps)
}
}
#[cfg(test)]
mod tests {
use super::test_support::{
config_bytes, fixture_config, fixture_encoder, fixture_tensors, load, max_abs, oracle_json,
oracle_rows, rel_rms, run_taps, tolerance, within, write_apr,
};
use super::{ModernBertConfig, ModernBertError, ModernBertLoadError};
#[test]
fn tiny_parity() {
let emb_bar = tolerance("embeddings_abs");
let layer_bar = tolerance("per_layer_rel_rms");
let final_bar = tolerance("final_norm_abs");
let encoder = fixture_encoder();
let rows = oracle_rows();
assert!(!rows.is_empty(), "oracle has rows");
println!("modernbert tiny_parity on ARCH={}", std::env::consts::ARCH);
for (ri, row) in rows.iter().enumerate() {
let (out, taps) = run_taps(&encoder, &row.ids);
let n_layers = encoder.config().num_hidden_layers();
assert_eq!(
taps.len(),
n_layers + 2,
"row {ri}: emb + layers + final taps"
);
for (name, got) in &taps {
let want = row.block(name);
if name.starts_with("layer") {
let r = rel_rms(got, want);
println!(
"row {ri} {name}: rel_rms {r:.3e} (bar {layer_bar:.1e}) max|delta| {:.3e}",
max_abs(got, want)
);
assert!(
within(r, layer_bar),
"row {ri} {name}: rel_rms {r:e} > {layer_bar:e}"
);
} else {
let bar = if name == "emb" { emb_bar } else { final_bar };
let d = max_abs(got, want);
println!("row {ri} {name}: max|delta| {d:.3e} (bar {bar:.1e})");
assert!(
within(d, bar),
"row {ri} {name}: max|delta| {d:e} > {bar:e}"
);
}
}
let final_tap = &taps.last().expect("final tap").1;
assert_eq!(
&out, final_tap,
"row {ri}: forward returns the final-norm block"
);
}
}
#[test]
fn window_mutation() {
let bar = tolerance("per_layer_rel_rms");
let mut encoder = fixture_encoder();
let cfg = encoder.config().clone();
let w = cfg.window();
let oracle = oracle_json();
let recorded = oracle["window_mutation"]["half_window"]
.as_u64()
.expect("oracle window_mutation.half_window");
assert_eq!(w as u64, recorded, "config window agrees with the oracle's");
let first_global = cfg
.layer_is_global()
.iter()
.position(|&g| g)
.expect("a global layer");
let first_local = cfg
.layer_is_global()
.iter()
.position(|&g| !g)
.expect("a local layer");
assert!(
first_global < first_local,
"the mutation must not reach the global layer first"
);
let rows = oracle_rows();
println!(
"modernbert window_mutation on ARCH={} (w={w}, bar {bar:.1e})",
std::env::consts::ARCH
);
for mutated in [w - 1, w + 1] {
encoder.set_window_override(Some(mutated));
for (ri, row) in rows.iter().enumerate() {
let (_, taps) = run_taps(&encoder, &row.ids);
let g_name = format!("layer{first_global}");
let l_name = format!("layer{first_local}");
let g = rel_rms(&taps[first_global + 1].1, row.block(&g_name));
let l = rel_rms(&taps[first_local + 1].1, row.block(&l_name));
println!(
"window {mutated} row {ri}: {g_name} rel_rms {g:.3e}, {l_name} rel_rms {l:.3e}"
);
assert!(
within(g, bar),
"window {mutated} row {ri}: {g_name} should still pass, got {g:e}"
);
assert!(
matches!(l.partial_cmp(&bar), Some(std::cmp::Ordering::Greater)),
"window {mutated} row {ri}: {l_name} should exceed {bar:e}, got {l:e}"
);
}
}
encoder.set_window_override(None);
let (_, taps) = run_taps(&encoder, &rows[0].ids);
let l = rel_rms(
&taps[first_local + 1].1,
rows[0].block(&format!("layer{first_local}")),
);
assert!(
within(l, bar),
"override cleared restores the true window: {l:e}"
);
}
#[test]
fn prefix_reuse() {
let cfg = fixture_config();
let tensors = fixture_tensors();
let plain = load(&write_apr(&tensors, ""), "", &cfg).expect("plain load");
let prefixed_apr = write_apr(&tensors, "encoder.");
let prefixed = load(&prefixed_apr, "encoder.", &cfg).expect("prefixed load");
for row in oracle_rows() {
let (a, ta) = run_taps(&plain, &row.ids);
let (b, tb) = run_taps(&prefixed, &row.ids);
let bits = |v: &[f32]| v.iter().map(|x| x.to_bits()).collect::<Vec<_>>();
assert_eq!(bits(&a), bits(&b), "final output bit-identical");
for ((na, va), (nb, vb)) in ta.iter().zip(&tb) {
assert_eq!(na, nb);
assert_eq!(bits(va), bits(vb), "{na} bit-identical");
}
}
match load(&prefixed_apr, "", &cfg) {
Err(ModernBertLoadError::MissingTensor { name }) => {
assert_eq!(name, "embeddings.tok_embeddings.weight");
}
other => panic!("expected MissingTensor, got {other:?}"),
}
}
#[test]
fn norm_eps_honoured() {
let bar = tolerance("final_norm_abs");
let mut cfg_json: serde_json::Value =
serde_json::from_slice(&config_bytes()).expect("config json");
cfg_json["norm_eps"] = serde_json::json!(1e-1);
let big_eps = ModernBertConfig::from_json_bytes(
&serde_json::to_vec(&cfg_json).expect("serialize config"),
)
.expect("eps 1e-1 is supported");
assert!((big_eps.norm_eps() - 1e-1).abs() < 1e-12);
let tensors = fixture_tensors();
let apr = write_apr(&tensors, "");
let base = load(&apr, "", &fixture_config()).expect("base load");
let moved = load(&apr, "", &big_eps).expect("eps load");
let ids = &oracle_rows()[0].ids;
let (a, _) = run_taps(&base, ids);
let (b, _) = run_taps(&moved, ids);
let d = max_abs(&a, &b);
println!("norm_eps 1e-5 vs 1e-1: final max|delta| {d:.3e} (bar {bar:.1e})");
assert!(
matches!(d.partial_cmp(&bar), Some(std::cmp::Ordering::Greater)),
"a changed norm_eps must change the output by more than {bar:e}, got {d:e}"
);
}
#[test]
fn forward_refuses_out_of_vocab_and_empty() {
let encoder = fixture_encoder();
let vocab = encoder.config().vocab_size();
let bad = u32::try_from(vocab).expect("vocab fits u32");
let err = encoder
.forward(&[1, 5, bad, 2], |_, _| {})
.expect_err("oov refused");
assert_eq!(
err,
ModernBertError::OutOfVocab {
position: 2,
id: bad,
vocab_size: vocab
}
);
let err = encoder.forward(&[], |_, _| {}).expect_err("empty refused");
assert_eq!(err, ModernBertError::EmptyInput);
}
}