qualia_core_db/inference/gguf_sharder/
hyperparams.rs1pub const DEFAULT_ROPE_FREQ_BASE: f32 = 100_000.0;
6
7pub const ARCH_UNKNOWN: u32 = 0;
9pub const ARCH_LLAMA: u32 = 1;
10pub const ARCH_GEMMA: u32 = 2;
11pub const ARCH_GEMMA2: u32 = 3;
12pub const ARCH_GEMMA3: u32 = 4;
13pub const ARCH_GEMMA4: u32 = 5;
15pub const ARCH_QWEN2: u32 = 6;
16pub const ARCH_GLM4: u32 = 7;
17pub const ARCH_PHI4: u32 = 8;
18pub const ARCH_DEEPSEEK_MOE: u32 = 9;
19pub const ARCH_OTHER: u32 = 255;
20
21pub const ARCH_FLAG_HAS_PLE: u32 = 1 << 0;
23pub const ARCH_FLAG_HAS_SWA: u32 = 1 << 1;
24pub const ARCH_FLAG_HAS_SHARED_KV: u32 = 1 << 2;
25pub const ARCH_FLAG_HAS_QK_NORM: u32 = 1 << 3;
26pub const ARCH_FLAG_HAS_SOFTCAP: u32 = 1 << 4;
27
28#[derive(Debug, Clone, Copy, Default, PartialEq)]
30pub struct GgufHyperparams {
31 pub n_layer: u32,
32 pub n_embd: u32,
33 pub n_head: u32,
34 pub n_kv_head: u32,
36 pub rope_freq_base: f32,
38 pub rope_scale: f32,
40 pub head_dim: u32,
42 pub head_dim_swa: u32,
44 pub sliding_window: u32,
46 pub shared_kv_layers: u32,
48 pub logit_softcap: f32,
50 pub architecture: u32,
52 pub arch_flags: u32,
54}
55
56impl GgufHyperparams {
57 pub fn effective_rope_freq_base(&self) -> f32 {
58 if self.rope_freq_base > 0.0 && self.rope_freq_base.is_finite() {
59 self.rope_freq_base
60 } else {
61 DEFAULT_ROPE_FREQ_BASE
62 }
63 }
64
65 pub fn effective_rope_scale(&self) -> f32 {
67 if self.rope_scale > 0.0 && self.rope_scale.is_finite() {
68 self.rope_scale
69 } else {
70 1.0
71 }
72 }
73
74 pub fn effective_head_dim(&self) -> u32 {
76 if self.head_dim > 0 {
77 self.head_dim
78 } else if self.n_head > 0 {
79 self.n_embd / self.n_head
80 } else {
81 128
82 }
83 }
84
85 pub fn head_dim(&self) -> u32 {
86 self.effective_head_dim()
87 }
88
89 pub fn effective_n_kv_head(&self) -> u32 {
90 if self.n_kv_head > 0 {
91 self.n_kv_head
92 } else {
93 self.n_head.max(1)
94 }
95 }
96
97 pub fn q_heads_per_kv(&self) -> u32 {
98 let kv = self.effective_n_kv_head();
99 if kv == 0 {
100 1
101 } else {
102 (self.n_head / kv).max(1)
103 }
104 }
105
106 pub fn gqa_ratio(&self) -> u32 {
107 self.q_heads_per_kv()
108 }
109
110 pub fn head_dim_swa_or(&self) -> u32 {
111 if self.head_dim_swa > 0 {
112 self.head_dim_swa
113 } else {
114 self.effective_head_dim()
115 }
116 }
117
118 pub fn architecture_name(&self) -> &'static str {
120 match self.architecture {
121 ARCH_LLAMA => "llama",
122 ARCH_GEMMA => "gemma",
123 ARCH_GEMMA2 => "gemma2",
124 ARCH_GEMMA3 => "gemma3",
125 ARCH_GEMMA4 => "gemma4",
126 ARCH_QWEN2 => "qwen2",
127 ARCH_GLM4 => "glm4",
128 ARCH_PHI4 => "phi4",
129 ARCH_DEEPSEEK_MOE => "deepseek_moe",
130 ARCH_OTHER => "other",
131 _ => "unknown",
132 }
133 }
134
135 pub fn decode_supported(&self) -> Result<(), String> {
142 if std::env::var_os("QUALIA_LLM_FORCE_UNSUPPORTED_ARCH").is_some() {
143 return Ok(());
144 }
145 if self.architecture == ARCH_GEMMA4
146 || (self.arch_flags & ARCH_FLAG_HAS_PLE) != 0
147 || (self.arch_flags & ARCH_FLAG_HAS_SHARED_KV) != 0
148 {
149 let mut missing = Vec::new();
150 if (self.arch_flags & ARCH_FLAG_HAS_PLE) != 0 {
151 missing.push("per-layer embeddings (PLE)");
152 }
153 if (self.arch_flags & ARCH_FLAG_HAS_SWA) != 0 {
154 missing.push("sliding-window + dual head_dim");
155 }
156 if (self.arch_flags & ARCH_FLAG_HAS_SHARED_KV) != 0 {
157 missing.push("shared KV layers");
158 }
159 if (self.arch_flags & ARCH_FLAG_HAS_QK_NORM) != 0 {
160 missing.push("QK-norm");
161 }
162 if missing.is_empty() {
163 missing.push("gemma4 decoder graph");
164 }
165 return Err(format!(
166 "architecture '{}' is not supported by the native Llama-shaped decode path yet \
167 (missing: {}). Convert/activate to p64 still works; coherent inference needs the \
168 gemma4 graph. Set QUALIA_LLM_FORCE_UNSUPPORTED_ARCH=1 to force (will be garbage).",
169 self.architecture_name(),
170 missing.join(", ")
171 ));
172 }
173 Ok(())
174 }
175}
176
177pub fn parse_architecture_id(name: &str) -> u32 {
179 let n = name.trim().to_ascii_lowercase();
180 match n.as_str() {
181 "llama" | "llama2" | "llama3" => ARCH_LLAMA,
182 "gemma" => ARCH_GEMMA,
183 "gemma2" => ARCH_GEMMA2,
184 "gemma3" => ARCH_GEMMA3,
185 "gemma4" => ARCH_GEMMA4,
186 "qwen2" | "qwen2vl" | "qwen3" | "qwen3.5" | "qwen3.6" => ARCH_QWEN2,
187 "glm" | "glm4" | "glm4.7" | "chatglm" => ARCH_GLM4,
188 "phi" | "phi3" | "phi4" => ARCH_PHI4,
189 "deepseek" | "deepseek2" | "deepseek3" | "deepseek_moe" => ARCH_DEEPSEEK_MOE,
190 "" => ARCH_UNKNOWN,
191 _ => ARCH_OTHER,
192 }
193}