use anyhow::{anyhow, bail, Result};
use mlx_native::gguf::{GgufFile, MetadataValue};
pub mod activation_capture_real;
pub mod chunk_allocs_arena;
pub mod decode_pool;
pub mod delta_net;
pub mod dense;
pub mod dense_ffn_arena;
pub mod dn_prefill_arena;
pub mod dump_bisect;
pub(super) mod encoder_stage;
pub mod fa_prefill_arena;
pub mod fa_projections_arena;
pub mod ffn;
pub mod forward_cpu;
pub mod forward_gpu;
pub mod full_attn;
pub mod gpu_delta_net;
pub mod gpu_ffn;
pub mod gpu_full_attn;
pub mod in_memory_loader;
pub use chunk_allocs_arena::ChunkAllocsArena;
pub use dense_ffn_arena::{
DenseFfnArena, DenseFfnOutputRingBuffer, LayerBoundaryArena, MoeFfnArena,
MoeFfnOutputRingBuffer,
};
pub use dn_prefill_arena::DnPrefillArena;
pub use fa_prefill_arena::FaPrefillArena;
pub use fa_projections_arena::FaProjectionsArena;
pub mod io_heads;
pub mod kernels;
pub mod kv_cache;
pub mod model;
pub mod moe;
pub mod mtp;
pub mod mtp_weights_load;
pub mod spec_decode;
pub mod tokenizer;
pub mod wave5b8_profile;
pub mod weight_loader;
pub mod weight_pool;
pub const ARCH_QWEN35: &str = "qwen35";
pub const ARCH_QWEN35MOE: &str = "qwen35moe";
pub const ARCH_QWEN3_VL: &str = "qwen3_vl";
pub const ARCH_QWEN3VL_UPSTREAM: &str = "qwen3vl";
pub const ARCH_QWEN3VLMOE_UPSTREAM: &str = "qwen3vlmoe";
pub fn is_qwen3_vl_arch(arch: &str) -> bool {
arch == ARCH_QWEN3_VL || arch == ARCH_QWEN3VL_UPSTREAM || arch == ARCH_QWEN3VLMOE_UPSTREAM
}
pub fn is_qwen3_vl_moe_arch(arch: &str) -> bool {
arch == ARCH_QWEN3VLMOE_UPSTREAM
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Qwen35Variant {
Dense,
Moe,
}
impl Qwen35Variant {
pub fn from_arch(arch: &str) -> Option<Self> {
match arch {
ARCH_QWEN35 => Some(Qwen35Variant::Dense),
ARCH_QWEN35MOE => Some(Qwen35Variant::Moe),
_ => None,
}
}
pub fn key_prefix(&self) -> &'static str {
match self {
Qwen35Variant::Dense => ARCH_QWEN35,
Qwen35Variant::Moe => ARCH_QWEN35MOE,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Qwen35LayerKind {
LinearAttention,
FullAttention,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Qwen35MoeConfig {
pub moe_intermediate_size: u32,
pub num_experts: u32,
pub num_experts_per_tok: u32,
pub shared_expert_intermediate_size: u32,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Qwen35Config {
pub variant: Qwen35Variant,
pub hidden_size: u32,
pub num_hidden_layers: u32,
pub num_attention_heads: u32,
pub num_key_value_heads: u32,
pub head_dim: u32,
pub linear_num_key_heads: u32,
pub linear_num_value_heads: u32,
pub linear_key_head_dim: u32,
pub linear_value_head_dim: u32,
pub linear_conv_kernel_dim: u32,
pub full_attention_interval: u32,
pub layer_types: Vec<Qwen35LayerKind>,
pub partial_rotary_factor: f32, pub rope_theta: f64, pub rotary_dim: u32, pub mrope_section: [u32; 4], pub mrope_interleaved: bool,
pub rms_norm_eps: f32,
pub max_position_embeddings: u32,
pub vocab_size: u32,
pub attn_output_gate: bool, pub mtp_num_hidden_layers: u32, pub mtp_use_dedicated_embeddings: bool,
pub intermediate_size: Option<u32>, pub moe: Option<Qwen35MoeConfig>, }
fn required_u32(gguf: &GgufFile, key: &str) -> Result<u32> {
gguf.metadata_u32(key).ok_or_else(|| {
anyhow!(
"qwen35 config: required key '{}' missing or wrong type",
key
)
})
}
fn required_f32(gguf: &GgufFile, key: &str) -> Result<f32> {
gguf.metadata_f32(key).ok_or_else(|| {
anyhow!(
"qwen35 config: required key '{}' missing or wrong type",
key
)
})
}
fn required_i32_array_4(gguf: &GgufFile, key: &str) -> Result<[u32; 4]> {
let mv = gguf
.metadata(key)
.ok_or_else(|| anyhow!("qwen35 config: required key '{}' missing", key))?;
let arr = match mv {
MetadataValue::Array(a) => a,
_ => bail!(
"qwen35 config: key '{}' has type {:?}, expected Array",
key,
std::mem::discriminant(mv)
),
};
if arr.len() != 4 {
bail!(
"qwen35 config: key '{}' length {} != 4 (mrope sections)",
key,
arr.len()
);
}
let mut out = [0u32; 4];
for (i, v) in arr.iter().enumerate() {
out[i] = match v {
MetadataValue::Int32(x) if *x >= 0 => *x as u32,
MetadataValue::Uint32(x) => *x,
MetadataValue::Int8(x) if *x >= 0 => *x as u32,
MetadataValue::Int16(x) if *x >= 0 => *x as u32,
MetadataValue::Uint8(x) => *x as u32,
MetadataValue::Uint16(x) => *x as u32,
other => bail!(
"qwen35 config: key '{}' element {} has unexpected variant {:?}",
key,
i,
std::mem::discriminant(other)
),
};
}
Ok(out)
}
pub fn default_layer_types(num_hidden_layers: u32, interval: u32) -> Vec<Qwen35LayerKind> {
if interval == 0 {
return vec![Qwen35LayerKind::LinearAttention; num_hidden_layers as usize];
}
(0..num_hidden_layers)
.map(|i| {
if (i + 1) % interval == 0 {
Qwen35LayerKind::FullAttention
} else {
Qwen35LayerKind::LinearAttention
}
})
.collect()
}
impl Qwen35Config {
pub fn from_gguf(gguf: &GgufFile) -> Result<Self> {
let arch = gguf
.metadata_string("general.architecture")
.ok_or_else(|| anyhow!("GGUF missing required key 'general.architecture'"))?;
let variant = Qwen35Variant::from_arch(arch).ok_or_else(|| {
anyhow!(
"general.architecture = {:?} is not a Qwen3.5 variant (expected {:?} or {:?})",
arch,
ARCH_QWEN35,
ARCH_QWEN35MOE
)
})?;
let p = variant.key_prefix();
let total_block_count = required_u32(gguf, &format!("{p}.block_count"))?;
let mtp_num_hidden_layers = gguf
.metadata_u32(&format!("{p}.nextn_predict_layers"))
.or_else(|| gguf.metadata_u32(&format!("{p}.mtp.num_hidden_layers")))
.unwrap_or(0);
let mtp_use_dedicated_embeddings = gguf
.metadata(&format!("{p}.nextn.use_dedicated_embeddings"))
.and_then(|v| match v {
MetadataValue::Bool(b) => Some(*b),
_ => None,
})
.unwrap_or_else(|| {
if mtp_num_hidden_layers == 0 {
true
} else {
let layer_index = total_block_count.saturating_sub(mtp_num_hidden_layers);
let tname = format!("blk.{layer_index}.nextn.embed_tokens.weight");
gguf.tensor_info(&tname).is_some()
}
});
if mtp_num_hidden_layers > total_block_count {
bail!(
"qwen35 config: {p}.nextn_predict_layers ({}) exceeds {p}.block_count ({})",
mtp_num_hidden_layers,
total_block_count
);
}
let num_hidden_layers = total_block_count - mtp_num_hidden_layers;
let hidden_size = required_u32(gguf, &format!("{p}.embedding_length"))?;
let num_attention_heads = required_u32(gguf, &format!("{p}.attention.head_count"))?;
let num_key_value_heads = required_u32(gguf, &format!("{p}.attention.head_count_kv"))?;
let key_length = required_u32(gguf, &format!("{p}.attention.key_length"))?;
let value_length = required_u32(gguf, &format!("{p}.attention.value_length"))?;
if key_length != value_length {
bail!(
"qwen35 config: attention.key_length ({}) != attention.value_length ({}); \
Qwen3.5 requires them equal",
key_length,
value_length
);
}
let head_dim = key_length;
let rms_norm_eps = required_f32(gguf, &format!("{p}.attention.layer_norm_rms_epsilon"))?;
let max_position_embeddings = required_u32(gguf, &format!("{p}.context_length"))?;
let rope_theta = required_f32(gguf, &format!("{p}.rope.freq_base"))? as f64;
let rotary_dim = required_u32(gguf, &format!("{p}.rope.dimension_count"))?;
let mrope_section = required_i32_array_4(gguf, &format!("{p}.rope.dimension_sections"))?;
let full_attention_interval = required_u32(gguf, &format!("{p}.full_attention_interval"))?;
let ssm_state_size = required_u32(gguf, &format!("{p}.ssm.state_size"))?;
let ssm_group_count = required_u32(gguf, &format!("{p}.ssm.group_count"))?;
let ssm_inner_size = required_u32(gguf, &format!("{p}.ssm.inner_size"))?;
let ssm_conv_kernel = required_u32(gguf, &format!("{p}.ssm.conv_kernel"))?;
if ssm_state_size == 0 {
bail!("qwen35 config: {p}.ssm.state_size must be > 0");
}
if ssm_inner_size % ssm_state_size != 0 {
bail!(
"qwen35 config: {p}.ssm.inner_size ({}) must be a multiple of \
{p}.ssm.state_size ({})",
ssm_inner_size,
ssm_state_size
);
}
let linear_num_value_heads = ssm_inner_size / ssm_state_size;
let attn_output_gate = gguf
.metadata(&format!("{p}.attention.output_gate"))
.and_then(|v| match v {
MetadataValue::Bool(b) => Some(*b),
_ => None,
})
.unwrap_or(true);
if head_dim == 0 {
bail!("qwen35 config: head_dim is 0");
}
let partial_rotary_factor = (rotary_dim as f32) / (head_dim as f32);
let vocab_size = gguf
.metadata_u32(&format!("{p}.vocab_size"))
.or_else(|| {
gguf.metadata("tokenizer.ggml.tokens")
.and_then(|v| match v {
MetadataValue::Array(a) => Some(a.len() as u32),
_ => None,
})
})
.ok_or_else(|| {
anyhow!(
"qwen35 config: can't determine vocab_size \
(neither {p}.vocab_size nor tokenizer.ggml.tokens present)"
)
})?;
let (intermediate_size, moe) = match variant {
Qwen35Variant::Dense => {
let fl = required_u32(gguf, &format!("{p}.feed_forward_length"))?;
(Some(fl), None)
}
Qwen35Variant::Moe => {
let num_experts = required_u32(gguf, &format!("{p}.expert_count"))?;
let num_experts_per_tok = required_u32(gguf, &format!("{p}.expert_used_count"))?;
let moe_intermediate_size =
required_u32(gguf, &format!("{p}.expert_feed_forward_length"))?;
let shared_expert_intermediate_size =
required_u32(gguf, &format!("{p}.expert_shared_feed_forward_length"))?;
(
None,
Some(Qwen35MoeConfig {
moe_intermediate_size,
num_experts,
num_experts_per_tok,
shared_expert_intermediate_size,
}),
)
}
};
let layer_types = default_layer_types(num_hidden_layers, full_attention_interval);
Ok(Qwen35Config {
variant,
hidden_size,
num_hidden_layers,
num_attention_heads,
num_key_value_heads,
head_dim,
linear_num_key_heads: ssm_group_count,
linear_num_value_heads,
linear_key_head_dim: ssm_state_size,
linear_value_head_dim: ssm_state_size,
linear_conv_kernel_dim: ssm_conv_kernel,
full_attention_interval,
layer_types,
partial_rotary_factor,
rope_theta,
rotary_dim,
mrope_section,
mrope_interleaved: true, rms_norm_eps,
max_position_embeddings,
vocab_size,
attn_output_gate,
mtp_num_hidden_layers,
mtp_use_dedicated_embeddings,
intermediate_size,
moe,
})
}
}
pub fn is_qwen36_gguf(gguf: &mlx_native::gguf::GgufFile) -> bool {
gguf.metadata_string("general.name")
.map(|name| name.to_lowercase().contains("qwen3.6"))
.unwrap_or(false)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn variant_from_arch() {
assert_eq!(
Qwen35Variant::from_arch("qwen35"),
Some(Qwen35Variant::Dense)
);
assert_eq!(
Qwen35Variant::from_arch("qwen35moe"),
Some(Qwen35Variant::Moe)
);
assert_eq!(Qwen35Variant::from_arch("gemma4"), None);
assert_eq!(Qwen35Variant::from_arch("qwen3"), None);
assert_eq!(Qwen35Variant::from_arch(""), None);
}
#[test]
fn layer_types_interval_4() {
let lt = default_layer_types(40, 4);
assert_eq!(lt.len(), 40);
for (i, kind) in lt.iter().enumerate() {
let want = if (i + 1) % 4 == 0 {
Qwen35LayerKind::FullAttention
} else {
Qwen35LayerKind::LinearAttention
};
assert_eq!(*kind, want, "layer {} kind mismatch", i);
}
use Qwen35LayerKind::*;
assert_eq!(
<[..8],
&[
LinearAttention,
LinearAttention,
LinearAttention,
FullAttention,
LinearAttention,
LinearAttention,
LinearAttention,
FullAttention,
]
);
}
#[test]
fn layer_types_dense_27b_64layer() {
let lt = default_layer_types(64, 4);
let full_count = lt
.iter()
.filter(|k| **k == Qwen35LayerKind::FullAttention)
.count();
assert_eq!(full_count, 16); }
#[test]
fn layer_types_interval_zero_all_linear() {
let lt = default_layer_types(8, 0);
assert!(lt.iter().all(|k| *k == Qwen35LayerKind::LinearAttention));
}
fn write_meta_only_gguf(path: &std::path::Path, name_value: Option<&str>) {
const GGUF_TYPE_STRING: u32 = 8;
let mut buf: Vec<u8> = Vec::new();
buf.extend_from_slice(b"GGUF");
buf.extend_from_slice(&3u32.to_le_bytes());
buf.extend_from_slice(&0u64.to_le_bytes());
let n_kv: u64 = if name_value.is_some() { 1 } else { 0 };
buf.extend_from_slice(&n_kv.to_le_bytes());
if let Some(value) = name_value {
let key = "general.name";
buf.extend_from_slice(&(key.len() as u64).to_le_bytes());
buf.extend_from_slice(key.as_bytes());
buf.extend_from_slice(&GGUF_TYPE_STRING.to_le_bytes());
buf.extend_from_slice(&(value.len() as u64).to_le_bytes());
buf.extend_from_slice(value.as_bytes());
}
while buf.len() % 32 != 0 {
buf.push(0);
}
std::fs::write(path, &buf).expect("write meta-only gguf");
}
#[test]
fn is_qwen36_gguf_matches_canonical_name() {
let tmp = std::env::temp_dir().join(format!("qwen36_pos_{}.gguf", std::process::id()));
write_meta_only_gguf(&tmp, Some("Qwen3.6 35B A3B Abliterix EGA Abliterated Apex"));
let gguf = mlx_native::gguf::GgufFile::open(&tmp).expect("open");
assert!(is_qwen36_gguf(&gguf));
std::fs::remove_file(&tmp).ok();
}
#[test]
fn is_qwen36_gguf_case_insensitive() {
for name in &["qwen3.6-27b", "QWEN3.6-27B", "Some Qwen3.6 model"] {
let tmp = std::env::temp_dir().join(format!(
"qwen36_case_{}_{}.gguf",
std::process::id(),
name.len()
));
write_meta_only_gguf(&tmp, Some(name));
let gguf = mlx_native::gguf::GgufFile::open(&tmp).expect("open");
assert!(is_qwen36_gguf(&gguf), "name {:?} should match", name);
std::fs::remove_file(&tmp).ok();
}
}
#[test]
fn is_qwen36_gguf_rejects_qwen35_canonical_name() {
let tmp = std::env::temp_dir().join(format!("qwen35_neg_{}.gguf", std::process::id()));
write_meta_only_gguf(&tmp, Some("Qwen3.5 27B"));
let gguf = mlx_native::gguf::GgufFile::open(&tmp).expect("open");
assert!(!is_qwen36_gguf(&gguf));
std::fs::remove_file(&tmp).ok();
}
#[test]
fn is_qwen36_gguf_rejects_other_families() {
for name in &["Gemma 4 26B", "Llama 3 70B", "DeepSeek V3", ""] {
let tmp = std::env::temp_dir().join(format!(
"other_family_{}_{}.gguf",
std::process::id(),
name.len()
));
write_meta_only_gguf(&tmp, Some(name));
let gguf = mlx_native::gguf::GgufFile::open(&tmp).expect("open");
assert!(!is_qwen36_gguf(&gguf), "name {:?} should not match", name);
std::fs::remove_file(&tmp).ok();
}
}
#[test]
fn is_qwen36_gguf_returns_false_when_name_missing() {
let tmp = std::env::temp_dir().join(format!("no_name_{}.gguf", std::process::id()));
write_meta_only_gguf(&tmp, None);
let gguf = mlx_native::gguf::GgufFile::open(&tmp).expect("open");
assert!(!is_qwen36_gguf(&gguf));
std::fs::remove_file(&tmp).ok();
}
#[test]
fn key_prefix_roundtrip() {
assert_eq!(Qwen35Variant::Dense.key_prefix(), ARCH_QWEN35);
assert_eq!(Qwen35Variant::Moe.key_prefix(), ARCH_QWEN35MOE);
}
#[test]
fn iter227_recognizes_underscored_qwen3_vl_arch_string() {
assert!(is_qwen3_vl_arch(ARCH_QWEN3_VL));
assert!(is_qwen3_vl_arch("qwen3_vl"));
assert!(!is_qwen3_vl_moe_arch("qwen3_vl"));
}
#[test]
fn iter227_recognizes_upstream_no_underscore_qwen3vl_arch_string() {
assert!(is_qwen3_vl_arch(ARCH_QWEN3VL_UPSTREAM));
assert!(is_qwen3_vl_arch("qwen3vl"));
assert!(!is_qwen3_vl_moe_arch("qwen3vl"));
}
#[test]
fn iter227_recognizes_upstream_qwen3vlmoe_arch_string() {
assert!(is_qwen3_vl_arch(ARCH_QWEN3VLMOE_UPSTREAM));
assert!(is_qwen3_vl_moe_arch("qwen3vlmoe"));
}
#[test]
fn iter227_does_not_widen_onto_existing_arches() {
for arch in &[
"qwen35",
"qwen35moe",
"gemma4",
"gemma3",
"bert",
"nomic-bert",
"llama",
"qwen3", "qwen2",
"",
"totally-fake-arch-name",
] {
assert!(
!is_qwen3_vl_arch(arch),
"is_qwen3_vl_arch({arch:?}) must be false (regression guard for iter-227 dispatch)"
);
assert!(
!is_qwen3_vl_moe_arch(arch),
"is_qwen3_vl_moe_arch({arch:?}) must be false (regression guard for iter-227 dispatch)"
);
}
}
#[test]
fn iter227_qwen3_vl_is_not_a_qwen35_variant() {
assert_eq!(Qwen35Variant::from_arch(ARCH_QWEN3_VL), None);
assert_eq!(Qwen35Variant::from_arch(ARCH_QWEN3VL_UPSTREAM), None);
assert_eq!(Qwen35Variant::from_arch(ARCH_QWEN3VLMOE_UPSTREAM), None);
}
#[test]
fn parses_real_apex_gguf() {
let path = std::path::PathBuf::from(
"/opt/hf2q/models/qwen3.6-35b-a3b-abliterix-ega-abliterated-apex/\
APEX-Q5_K_M.gguf",
);
if !path.exists() {
eprintln!("skipping: apex GGUF not at expected path");
return;
}
let gguf = match GgufFile::open(&path) {
Ok(g) => g,
Err(e) => {
eprintln!("skipping: apex GGUF open failed ({e})");
return;
}
};
let cfg = Qwen35Config::from_gguf(&gguf).expect("parse qwen35 config");
assert_eq!(cfg.variant, Qwen35Variant::Moe);
assert_eq!(cfg.num_hidden_layers, 40);
assert_eq!(cfg.hidden_size, 2048);
assert_eq!(cfg.num_attention_heads, 16);
assert_eq!(cfg.num_key_value_heads, 2);
assert_eq!(cfg.head_dim, 256);
assert_eq!(cfg.linear_num_key_heads, 16);
assert_eq!(cfg.linear_num_value_heads, 32); assert_eq!(cfg.linear_key_head_dim, 128);
assert_eq!(cfg.linear_value_head_dim, 128);
assert_eq!(cfg.linear_conv_kernel_dim, 4);
assert_eq!(cfg.full_attention_interval, 4);
assert_eq!(cfg.rotary_dim, 64);
assert_eq!(cfg.mrope_section, [11, 11, 10, 0]);
assert!(cfg.mrope_interleaved);
assert!((cfg.partial_rotary_factor - 0.25).abs() < 1e-6);
assert!((cfg.rope_theta - 1e7).abs() < 1.0);
assert!(cfg.rms_norm_eps > 0.0 && cfg.rms_norm_eps < 1e-5);
assert_eq!(cfg.layer_types.len(), 40);
assert_eq!(cfg.layer_types[3], Qwen35LayerKind::FullAttention);
assert_eq!(cfg.layer_types[0], Qwen35LayerKind::LinearAttention);
let moe = cfg.moe.as_ref().expect("moe fields");
assert_eq!(moe.num_experts, 256);
assert_eq!(moe.num_experts_per_tok, 8);
assert_eq!(moe.moe_intermediate_size, 512);
assert_eq!(moe.shared_expert_intermediate_size, 512);
assert!(cfg.intermediate_size.is_none());
assert_eq!(cfg.mtp_num_hidden_layers, 0);
}
#[test]
fn dequantizes_real_apex_q5k_tensor() {
let path = std::path::PathBuf::from(
"/opt/hf2q/models/qwen3.6-35b-a3b-abliterix-ega-abliterated-apex/\
APEX-Q5_K_M.gguf",
);
if !path.exists() {
eprintln!("skipping: apex GGUF not at expected path");
return;
}
let device = match mlx_native::MlxDevice::new() {
Ok(d) => d,
Err(e) => {
eprintln!("skipping: no Metal device: {e}");
return;
}
};
let gguf = GgufFile::open(&path).expect("open apex gguf");
let buf = gguf
.load_tensor_f32("blk.0.attn_gate.weight", &device)
.expect("load Q5_K tensor");
let got: &[f32] = buf.as_slice().expect("slice");
assert_eq!(got.len(), 2048 * 4096, "element count");
let mut n_nan = 0usize;
let mut n_inf = 0usize;
let mut sum = 0.0_f64;
let mut sum_sq = 0.0_f64;
for v in got {
if v.is_nan() {
n_nan += 1;
} else if !v.is_finite() {
n_inf += 1;
} else {
sum += *v as f64;
sum_sq += (*v as f64) * (*v as f64);
}
}
assert_eq!(n_nan, 0, "Q5_K dequant produced NaN values");
assert_eq!(n_inf, 0, "Q5_K dequant produced Inf values");
let n = got.len() as f64;
let mean = sum / n;
let variance = (sum_sq / n) - mean * mean;
let stddev = variance.max(0.0).sqrt();
assert!(
stddev > 1e-6,
"Q5_K dequant produced degenerate (all-equal) tensor; stddev = {}",
stddev
);
assert!(
stddev < 10.0,
"Q5_K dequant stddev absurdly large: {}",
stddev
);
eprintln!(
"blk.0.attn_gate.weight (Q5_K → f32): count={}, mean={:.6}, stddev={:.6}",
got.len(),
mean,
stddev
);
}
}