use std::collections::BTreeMap;
pub const FOCR_INT8_ATTN_ENV: &str = "FOCR_INT8_ATTN";
pub const FOCR_INT8_LMHEAD_ENV: &str = "FOCR_INT8_LMHEAD";
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QuantPolicy {
KeepBf16,
Int8,
Gated(GatedKind),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GatedKind {
Attention,
LmHead,
}
impl GatedKind {
#[must_use]
pub fn env_var(self) -> &'static str {
match self {
GatedKind::Attention => FOCR_INT8_ATTN_ENV,
GatedKind::LmHead => FOCR_INT8_LMHEAD_ENV,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ResolvedPolicy {
KeepBf16,
Int8,
}
impl ResolvedPolicy {
#[must_use]
pub fn is_quantized(self) -> bool {
matches!(self, ResolvedPolicy::Int8)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Classification {
pub policy: QuantPolicy,
pub reason: &'static str,
}
fn is_vision(name: &str) -> bool {
name.starts_with("model.vision_model.")
|| name.starts_with("model.sam_model.")
|| name.starts_with("vision_model.")
|| name.starts_with("sam_model.")
}
fn is_projector(name: &str) -> bool {
name.starts_with("model.projector.") || name.starts_with("projector.")
}
fn is_embed_tokens(name: &str) -> bool {
name == "model.embed_tokens.weight" || name == "embed_tokens.weight"
}
fn is_connector_param(name: &str) -> bool {
name == "model.image_newline"
|| name == "model.view_seperator"
|| name == "image_newline"
|| name == "view_seperator"
}
fn is_router_gate(name: &str) -> bool {
name.ends_with(".mlp.gate.weight") || name.ends_with(".mlp.gate.bias")
}
fn is_norm(name: &str) -> bool {
let lower_has = |needle: &str| name.contains(needle);
lower_has("layernorm")
|| lower_has("layer_norm")
|| lower_has("LayerNorm")
|| name == "model.norm.weight"
|| name.ends_with(".norm.weight")
|| name.ends_with(".norm.bias")
|| name.contains(".norm1.")
|| name.contains(".norm2.")
|| name.contains(".ln_")
|| name.ends_with(".ln_post.weight")
|| name.ends_with(".ln_post.bias")
}
fn is_decoder_attn_proj(name: &str) -> bool {
name.contains(".self_attn.")
&& (name.ends_with(".q_proj.weight")
|| name.ends_with(".k_proj.weight")
|| name.ends_with(".v_proj.weight")
|| name.ends_with(".o_proj.weight"))
}
fn is_lm_head(name: &str) -> bool {
name == "lm_head.weight"
}
fn is_decoder_ffn_proj(name: &str) -> bool {
let is_proj = name.ends_with(".gate_proj.weight")
|| name.ends_with(".up_proj.weight")
|| name.ends_with(".down_proj.weight");
if !is_proj {
return false;
}
(name.starts_with("model.layers.") || name.starts_with("layers.")) && name.contains(".mlp.")
}
#[must_use]
pub fn classify(name: &str) -> Classification {
if is_vision(name) {
return Classification {
policy: QuantPolicy::KeepBf16,
reason: "keep-bf16: vision tower (SAM/CLIP) — quantizing it wrecks OCR (doctrine #2)",
};
}
if is_projector(name) {
return Classification {
policy: QuantPolicy::KeepBf16,
reason: "keep-bf16: projector (2048->1280) — high-precision set (doctrine #2)",
};
}
if is_embed_tokens(name) {
return Classification {
policy: QuantPolicy::KeepBf16,
reason: "keep-bf16: embed_tokens — high-precision set (doctrine #2)",
};
}
if is_connector_param(name) {
return Classification {
policy: QuantPolicy::KeepBf16,
reason: "keep-bf16: connector param (image_newline/view_seperator)",
};
}
if is_router_gate(name) {
return Classification {
policy: QuantPolicy::KeepBf16,
reason: "keep-bf16: MoE router gate — gate-drift cliff, NEVER quantized (doctrine #2)",
};
}
if is_norm(name) {
return Classification {
policy: QuantPolicy::KeepBf16,
reason: "keep-bf16: norm tensor — all norms stay high precision (doctrine #2)",
};
}
if is_decoder_attn_proj(name) {
return Classification {
policy: QuantPolicy::Gated(GatedKind::Attention),
reason: "gated: attention q/k/v/o_proj — int8 only behind FOCR_INT8_ATTN (OQ-14)",
};
}
if is_lm_head(name) {
return Classification {
policy: QuantPolicy::Gated(GatedKind::LmHead),
reason: "gated: lm_head — int8 only behind FOCR_INT8_LMHEAD (OQ-14)",
};
}
if is_decoder_ffn_proj(name) {
return Classification {
policy: QuantPolicy::Int8,
reason: "int8: decoder FFN/expert GEMM — the validated quantizable set (doctrine #2)",
};
}
Classification {
policy: QuantPolicy::KeepBf16,
reason: "keep-bf16: unclassified tensor — conservative default (refuse to quantize)",
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WasmInt4Policy {
ExpertInt4,
Int8,
KeepHighPrecision,
}
#[must_use]
pub fn classify_wasm_experts_int4(name: &str) -> WasmInt4Policy {
if is_embed_tokens(name) {
return WasmInt4Policy::Int8;
}
match classify(name).policy {
QuantPolicy::Int8 => WasmInt4Policy::ExpertInt4,
QuantPolicy::Gated(_) => WasmInt4Policy::Int8,
QuantPolicy::KeepBf16 => WasmInt4Policy::KeepHighPrecision,
}
}
#[must_use]
pub fn resolve_with(policy: QuantPolicy, attn_on: bool, lmhead_on: bool) -> ResolvedPolicy {
match policy {
QuantPolicy::KeepBf16 => ResolvedPolicy::KeepBf16,
QuantPolicy::Int8 => ResolvedPolicy::Int8,
QuantPolicy::Gated(GatedKind::Attention) => {
if attn_on {
ResolvedPolicy::Int8
} else {
ResolvedPolicy::KeepBf16
}
}
QuantPolicy::Gated(GatedKind::LmHead) => {
if lmhead_on {
ResolvedPolicy::Int8
} else {
ResolvedPolicy::KeepBf16
}
}
}
}
#[must_use]
pub fn resolve(name: &str) -> ResolvedPolicy {
let attn_on = switch_on(FOCR_INT8_ATTN_ENV);
let lmhead_on = switch_on(FOCR_INT8_LMHEAD_ENV);
resolve_with(classify(name).policy, attn_on, lmhead_on)
}
#[must_use]
pub fn switch_on(var: &str) -> bool {
match std::env::var(var) {
Ok(v) => is_truthy(&v),
Err(_) => false,
}
}
#[must_use]
pub fn is_truthy(value: &str) -> bool {
matches!(
value.trim().to_ascii_lowercase().as_str(),
"1" | "true" | "on" | "yes"
)
}
#[derive(Debug, Clone, Copy)]
pub struct Recipe {
attn_int8: bool,
lmhead_int8: bool,
}
impl Recipe {
#[must_use]
pub fn new(attn_int8: bool, lmhead_int8: bool) -> Self {
Self {
attn_int8,
lmhead_int8,
}
}
#[must_use]
pub fn from_env() -> Self {
Self::new(
switch_on(FOCR_INT8_ATTN_ENV),
switch_on(FOCR_INT8_LMHEAD_ENV),
)
}
#[must_use]
pub fn validated_default() -> Self {
Self::new(false, false)
}
#[must_use]
pub fn attn_int8(&self) -> bool {
self.attn_int8
}
#[must_use]
pub fn lmhead_int8(&self) -> bool {
self.lmhead_int8
}
#[must_use]
pub fn classify(&self, name: &str) -> Classification {
classify(name)
}
#[must_use]
pub fn resolve(&self, name: &str) -> ResolvedPolicy {
resolve_with(classify(name).policy, self.attn_int8, self.lmhead_int8)
}
#[must_use]
pub fn is_quantized(&self, name: &str) -> bool {
self.resolve(name).is_quantized()
}
#[must_use]
pub fn resolve_manifest<I, S>(&self, names: I) -> BTreeMap<String, ResolvedPolicy>
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
names
.into_iter()
.map(|n| {
let name = n.as_ref().to_owned();
let policy = self.resolve(&name);
(name, policy)
})
.collect()
}
#[must_use]
pub fn quantizable_names<I, S>(&self, names: I) -> Vec<String>
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
let mut out: Vec<String> = names
.into_iter()
.filter_map(|n| {
let name = n.as_ref();
if self.is_quantized(name) {
Some(name.to_owned())
} else {
None
}
})
.collect();
out.sort();
out.dedup();
out
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn refuses_vision_tower() {
let clip_attn = "model.vision_model.transformer.layers.15.self_attn.out_proj.weight";
let clip_qkv = "model.vision_model.transformer.layers.3.self_attn.qkv_proj.weight";
let sam_block = "model.sam_model.blocks.5.attn.qkv.weight";
let clip_mlp = "model.vision_model.transformer.layers.7.mlp.fc1.weight";
for n in [clip_attn, clip_qkv, sam_block, clip_mlp] {
assert_eq!(
classify(n).policy,
QuantPolicy::KeepBf16,
"vision tensor {n} must be KEEP_BF16"
);
assert_eq!(resolve(n), ResolvedPolicy::KeepBf16);
}
}
#[test]
fn refuses_projector() {
for n in [
"model.projector.layers.weight",
"model.projector.layers.bias",
] {
assert_eq!(classify(n).policy, QuantPolicy::KeepBf16, "{n}");
}
}
#[test]
fn refuses_embed_tokens() {
assert_eq!(
classify("model.embed_tokens.weight").policy,
QuantPolicy::KeepBf16
);
}
#[test]
fn refuses_connector_params() {
assert_eq!(
classify("model.image_newline").policy,
QuantPolicy::KeepBf16
);
assert_eq!(
classify("model.view_seperator").policy,
QuantPolicy::KeepBf16
);
}
#[test]
fn refuses_moe_router_gate_but_not_gate_proj() {
assert_eq!(
classify("model.layers.5.mlp.gate.weight").policy,
QuantPolicy::KeepBf16
);
assert_eq!(
classify("model.layers.0.mlp.gate_proj.weight").policy,
QuantPolicy::Int8
);
assert_eq!(
classify("model.layers.5.mlp.experts.10.gate_proj.weight").policy,
QuantPolicy::Int8
);
}
#[test]
fn refuses_all_norms() {
for n in [
"model.norm.weight",
"model.layers.0.input_layernorm.weight",
"model.layers.11.post_attention_layernorm.weight",
"model.vision_model.transformer.layers.2.norm1.weight",
"model.sam_model.blocks.4.norm2.weight",
] {
assert_eq!(
classify(n).policy,
QuantPolicy::KeepBf16,
"norm tensor {n} must be KEEP_BF16"
);
}
}
#[test]
fn allows_dense_layer0_ffn() {
for n in [
"model.layers.0.mlp.gate_proj.weight",
"model.layers.0.mlp.up_proj.weight",
"model.layers.0.mlp.down_proj.weight",
] {
assert_eq!(classify(n).policy, QuantPolicy::Int8, "{n}");
assert_eq!(resolve(n), ResolvedPolicy::Int8);
}
}
#[test]
fn allows_routed_experts() {
let n = "model.layers.10.mlp.experts.8.down_proj.weight";
assert_eq!(classify(n).policy, QuantPolicy::Int8);
let n2 = "model.layers.7.mlp.experts.63.up_proj.weight";
assert_eq!(classify(n2).policy, QuantPolicy::Int8);
}
#[test]
fn allows_shared_experts() {
for proj in ["gate_proj", "up_proj", "down_proj"] {
let n = format!("model.layers.11.mlp.shared_experts.{proj}.weight");
assert_eq!(classify(&n).policy, QuantPolicy::Int8, "{n}");
}
}
#[test]
fn attention_proj_is_gated_default_off() {
for proj in ["q_proj", "k_proj", "v_proj", "o_proj"] {
let n = format!("model.layers.11.self_attn.{proj}.weight");
assert_eq!(
classify(&n).policy,
QuantPolicy::Gated(GatedKind::Attention),
"{n}"
);
assert_eq!(
resolve_with(classify(&n).policy, false, false),
ResolvedPolicy::KeepBf16
);
assert_eq!(
resolve_with(classify(&n).policy, true, false),
ResolvedPolicy::Int8
);
}
}
#[test]
fn lm_head_is_gated_default_off() {
let n = "lm_head.weight";
assert_eq!(classify(n).policy, QuantPolicy::Gated(GatedKind::LmHead));
assert_eq!(
resolve_with(classify(n).policy, false, false),
ResolvedPolicy::KeepBf16
);
assert_eq!(
resolve_with(classify(n).policy, false, true),
ResolvedPolicy::Int8
);
assert_eq!(
resolve_with(classify(n).policy, true, false),
ResolvedPolicy::KeepBf16
);
}
#[test]
fn gated_kind_env_vars_are_distinct() {
assert_eq!(GatedKind::Attention.env_var(), FOCR_INT8_ATTN_ENV);
assert_eq!(GatedKind::LmHead.env_var(), FOCR_INT8_LMHEAD_ENV);
assert_ne!(FOCR_INT8_ATTN_ENV, FOCR_INT8_LMHEAD_ENV);
}
#[test]
fn wasm_recipe_puts_expert_ffn_in_int4() {
for n in [
"model.layers.0.mlp.gate_proj.weight",
"model.layers.0.mlp.up_proj.weight",
"model.layers.0.mlp.down_proj.weight",
"model.layers.7.mlp.experts.63.up_proj.weight",
"model.layers.11.mlp.shared_experts.down_proj.weight",
] {
assert_eq!(
classify_wasm_experts_int4(n),
WasmInt4Policy::ExpertInt4,
"{n}"
);
}
}
#[test]
fn wasm_recipe_puts_attn_lmhead_embed_in_int8() {
for n in [
"model.layers.11.self_attn.q_proj.weight",
"model.layers.0.self_attn.o_proj.weight",
"lm_head.weight",
"model.embed_tokens.weight",
] {
assert_eq!(classify_wasm_experts_int4(n), WasmInt4Policy::Int8, "{n}");
}
}
#[test]
fn wasm_recipe_keeps_vision_router_norms_high_precision() {
for n in [
"model.vision_model.transformer.layers.15.self_attn.out_proj.weight",
"model.sam_model.blocks.5.attn.qkv.weight",
"model.projector.layers.weight",
"model.layers.5.mlp.gate.weight", "model.norm.weight",
"model.layers.0.input_layernorm.weight",
"model.image_newline",
"some.unknown.tensor",
] {
assert_eq!(
classify_wasm_experts_int4(n),
WasmInt4Policy::KeepHighPrecision,
"{n}"
);
}
}
#[test]
fn truthiness_rule() {
for on in ["1", "true", "TRUE", "On", "yes", " yes ", "Yes"] {
assert!(is_truthy(on), "{on:?} should be truthy");
}
for off in ["0", "false", "", "off", "no", "2", "enabled", "ON1"] {
assert!(!is_truthy(off), "{off:?} should be falsy");
}
}
#[test]
fn recipe_default_keeps_attn_and_lmhead_bf16() {
let r = Recipe::validated_default();
assert!(!r.attn_int8());
assert!(!r.lmhead_int8());
assert_eq!(
r.resolve("model.layers.0.self_attn.q_proj.weight"),
ResolvedPolicy::KeepBf16
);
assert_eq!(r.resolve("lm_head.weight"), ResolvedPolicy::KeepBf16);
assert!(r.is_quantized("model.layers.3.mlp.experts.0.down_proj.weight"));
}
#[test]
fn recipe_with_switches_on_quantizes_gated() {
let r = Recipe::new(true, true);
assert!(r.is_quantized("model.layers.0.self_attn.v_proj.weight"));
assert!(r.is_quantized("lm_head.weight"));
assert!(!r.is_quantized("model.norm.weight"));
assert!(
!r.is_quantized("model.vision_model.transformer.layers.0.self_attn.qkv_proj.weight")
);
}
#[test]
fn quantizable_names_default_excludes_vision_attn_lmhead_router() {
let names = vec![
"model.vision_model.transformer.layers.0.self_attn.out_proj.weight",
"model.sam_model.blocks.0.attn.qkv.weight",
"model.projector.layers.weight",
"model.embed_tokens.weight",
"model.norm.weight",
"model.layers.5.mlp.gate.weight", "model.layers.0.input_layernorm.weight",
"model.layers.0.self_attn.q_proj.weight", "lm_head.weight", "model.layers.0.mlp.down_proj.weight", "model.layers.3.mlp.experts.7.up_proj.weight", "model.layers.3.mlp.shared_experts.gate_proj.weight", ];
let r = Recipe::validated_default();
let q = r.quantizable_names(names.iter().copied());
assert_eq!(
q,
vec![
"model.layers.0.mlp.down_proj.weight".to_string(),
"model.layers.3.mlp.experts.7.up_proj.weight".to_string(),
"model.layers.3.mlp.shared_experts.gate_proj.weight".to_string(),
]
);
}
#[test]
fn resolve_manifest_is_deterministic_and_sorted() {
let r = Recipe::validated_default();
let names = ["zzz.unknown", "model.norm.weight", "lm_head.weight"];
let m = r.resolve_manifest(names);
let keys: Vec<&String> = m.keys().collect();
assert_eq!(
keys,
vec!["lm_head.weight", "model.norm.weight", "zzz.unknown"]
);
assert_eq!(m["zzz.unknown"], ResolvedPolicy::KeepBf16);
}
#[test]
fn unclassified_tensor_is_kept_bf16() {
let c = classify("some.weird.tensor.we.do.not.know");
assert_eq!(c.policy, QuantPolicy::KeepBf16);
assert!(c.reason.contains("conservative"));
}
#[test]
fn reasons_are_present_and_stable() {
for n in [
"model.vision_model.x.weight",
"model.layers.0.mlp.down_proj.weight",
"model.layers.0.self_attn.q_proj.weight",
"lm_head.weight",
"model.norm.weight",
] {
assert!(!classify(n).reason.is_empty(), "{n}");
}
}
}