1use super::attn::freqs_cis;
16use super::compress::{
17 CompAttnCfg, CompAttnRun, IndexerCfg, LayerAttnState, SharedRuntime, yarn_freqs_cis,
18};
19use super::engram::{EngramTables, NgramHashState, regen_bf16_matrix, regen_bf16_qk, regen_table};
20use super::moe::MoeCfg;
21use super::{Golden, regen_param};
22
23mod forward;
24
25pub use forward::forward;
26
27pub struct ModelCfg {
28 pub dim: usize,
29 pub hc: usize,
30 pub iters: usize,
31 pub hc_eps: f32,
32 pub eps: f32,
33 pub n_layers: usize,
34 pub vocab: usize,
35 pub max_seq: usize,
36 pub n_heads: usize,
37 pub head_dim: usize,
38 pub rope_dim: usize,
39 pub q_rank: usize,
40 pub o_rank: usize,
41 pub groups: usize,
42 pub window: usize,
43 pub ratios: Vec<usize>,
44 pub kv_sources: Vec<usize>,
45 pub index_sources: Vec<usize>,
46 pub cand_src: i64,
47 pub cand_topk_blocks: usize,
48 pub cand_block: usize,
49 pub index_heads: usize,
50 pub index_hd: usize,
51 pub index_topk: usize,
52 pub rope_theta: f32,
53 pub compress_rope_theta: f32,
54 pub rope_factor: f32,
55 pub orig_seq: usize,
56 pub beta_fast: f32,
57 pub beta_slow: f32,
58 pub moe: MoeCfg,
59}
60
61impl ModelCfg {
62 pub fn from_golden(g: &Golden) -> Self {
63 let u = |k: &str| g.fixture_u64(k) as usize;
64 let f = |k: &str| g.fixture_f64(k) as f32;
65 let list = |k: &str| g.fixture_usize_list(k);
66 let dim = u("dim");
67 ModelCfg {
68 dim,
69 hc: u("hc_mult"),
70 iters: u("hc_sinkhorn_iters"),
71 hc_eps: f("hc_eps"),
72 eps: f("norm_eps"),
73 n_layers: u("n_layers"),
74 vocab: u("vocab_size"),
75 max_seq: u("max_seq_len"),
76 n_heads: u("n_heads"),
77 head_dim: u("head_dim"),
78 rope_dim: u("rope_head_dim"),
79 q_rank: u("q_lora_rank"),
80 o_rank: u("o_lora_rank"),
81 groups: u("o_groups"),
82 window: u("window_size"),
83 ratios: list("compress_ratios"),
84 kv_sources: list("kv_source_layers"),
85 index_sources: list("index_source_layers"),
86 cand_src: g.fixture_i64("candidate_source_layer"),
87 cand_topk_blocks: u("candidate_topk_blocks"),
88 cand_block: u("candidate_block_size"),
89 index_heads: u("index_n_heads"),
90 index_hd: u("index_head_dim"),
91 index_topk: u("index_topk"),
92 rope_theta: f("rope_theta"),
93 compress_rope_theta: f("compress_rope_theta"),
94 rope_factor: f("rope_factor"),
95 orig_seq: u("original_seq_len"),
96 beta_fast: f("beta_fast"),
97 beta_slow: f("beta_slow"),
98 moe: MoeCfg {
99 dim,
100 inter: u("moe_inter_dim"),
101 n_routed: u("n_routed_experts"),
102 topk: u("n_activated_experts"),
103 gate_temp: f("gate_temp"),
104 norm_topk_prob: true,
105 route_scale: f("route_scale"),
106 swiglu_limit: f("swiglu_limit"),
107 },
108 }
109 }
110
111 pub fn attn_cfg(&self, layer: usize) -> CompAttnCfg {
112 let ratio = self.ratios[layer];
113 CompAttnCfg {
114 dim: self.dim,
115 n_heads: self.n_heads,
116 head_dim: self.head_dim,
117 rope_dim: self.rope_dim,
118 q_rank: self.q_rank,
119 o_rank: self.o_rank,
120 groups: self.groups,
121 window: self.window,
122 eps: self.eps,
123 ratio,
124 is_kv_source: self.kv_sources.contains(&layer),
125 is_index_source: self.index_sources.contains(&layer),
126 is_candidate_source: self.cand_src == layer as i64,
127 uses_candidates: self.cand_src >= 0 && (self.cand_src as usize) < layer,
128 }
129 }
130
131 pub fn indexer_cfg(&self) -> IndexerCfg {
132 IndexerCfg {
133 n_heads: self.index_heads,
134 index_hd: self.index_hd,
135 rope_dim: self.rope_dim,
136 q_rank: self.q_rank,
137 dim: self.dim,
138 hd: self.head_dim,
139 index_topk: self.index_topk,
140 cand_topk_blocks: self.cand_topk_blocks,
141 cand_block: self.cand_block,
142 eps: self.eps,
143 }
144 }
145}
146
147pub struct EngramWeights {
148 pub table: Vec<f32>,
149 pub wkv: Vec<f32>,
150 pub q: Vec<f32>,
151 pub k: Vec<f32>,
152 pub hash_index: usize,
153}
154
155pub struct LayerWeights {
156 pub hc_attn_fn: Vec<f32>,
157 pub hc_attn_scale: Vec<f32>,
158 pub hc_attn_base: Vec<f32>,
159 pub hc_ffn_fn: Vec<f32>,
160 pub hc_ffn_scale: Vec<f32>,
161 pub hc_ffn_base: Vec<f32>,
162 pub attn_norm: Vec<f32>,
163 pub ffn_norm: Vec<f32>,
164 pub sink: Vec<f32>,
165 pub wq_a: Vec<f32>,
166 pub q_norm: Vec<f32>,
167 pub wq_b: Vec<f32>,
168 pub wkv: Vec<f32>,
169 pub kv_norm: Vec<f32>,
170 pub wo_a: Vec<f32>,
171 pub wo_b: Vec<f32>,
172 pub comp_wkv: Option<Vec<f32>>,
173 pub comp_wgate: Option<Vec<f32>>,
174 pub comp_norm: Option<Vec<f32>>,
175 pub idx_wq_b: Option<Vec<f32>>,
176 pub idx_weights_proj: Option<Vec<f32>>,
177 pub idx_wk: Option<Vec<f32>>,
178 pub idx_k_norm: Option<Vec<f32>>,
179 pub gate_w: Vec<f32>,
180 pub gate_bias: Vec<f32>,
181 pub experts: Vec<(Vec<f32>, Vec<f32>, Vec<f32>)>,
182 pub shared: (Vec<f32>, Vec<f32>, Vec<f32>),
183 pub engram: Option<EngramWeights>,
184}
185
186pub struct ModelWeights {
187 pub embed: Vec<f32>,
188 pub norm: Vec<f32>,
189 pub head: Vec<f32>,
190 pub layers: Vec<LayerWeights>,
191}
192
193impl ModelWeights {
194 pub fn from_golden(g: &Golden, c: &ModelCfg, t: &EngramTables) -> Self {
195 let layers = (0..c.n_layers)
196 .map(|l| {
197 let p = |n: &str| regen_param(g, &format!("layers.{l}.{n}"));
198 let opt = |n: &str, on: bool| if on { Some(p(n)) } else { None };
199 let ac = c.attn_cfg(l);
200 let has_comp = ac.is_kv_source;
201 let has_idx = ac.is_index_source;
202 let engram = t
203 .layer_ids
204 .iter()
205 .position(|&x| x == l)
206 .map(|hi| EngramWeights {
207 table: regen_table(t, hi),
208 wkv: regen_bf16_matrix(
209 &format!("layers.{l}.engram.wkv.weight"),
210 c.dim * (c.hc + 1),
211 t.n_hash_cols() * t.head_dim,
212 ),
213 q: regen_bf16_qk(&format!("layers.{l}.engram.q_weight"), c.hc * c.dim),
214 k: regen_bf16_qk(&format!("layers.{l}.engram.k_weight"), c.hc * c.dim),
215 hash_index: hi,
216 });
217 LayerWeights {
218 hc_attn_fn: p("hc_attn_fn"),
219 hc_attn_scale: p("hc_attn_scale"),
220 hc_attn_base: p("hc_attn_base"),
221 hc_ffn_fn: p("hc_ffn_fn"),
222 hc_ffn_scale: p("hc_ffn_scale"),
223 hc_ffn_base: p("hc_ffn_base"),
224 attn_norm: p("attn_norm.weight"),
225 ffn_norm: p("ffn_norm.weight"),
226 sink: p("attn.attn_sink"),
227 wq_a: p("attn.wq_a.weight"),
228 q_norm: p("attn.q_norm.weight"),
229 wq_b: p("attn.wq_b.weight"),
230 wkv: p("attn.wkv.weight"),
231 kv_norm: p("attn.kv_norm.weight"),
232 wo_a: p("attn.wo_a.weight"),
233 wo_b: p("attn.wo_b.weight"),
234 comp_wkv: opt("attn.compressor.wkv.weight", has_comp),
235 comp_wgate: opt("attn.compressor.wgate.weight", has_comp && ac.ratio > 1),
236 comp_norm: opt("attn.compressor.norm.weight", has_comp),
237 idx_wq_b: opt("attn.indexer.wq_b.weight", has_idx),
238 idx_weights_proj: opt("attn.indexer.weights_proj.weight", has_idx),
239 idx_wk: opt("attn.indexer.wk.weight", has_idx && has_comp),
240 idx_k_norm: opt("attn.indexer.k_norm.weight", has_idx && has_comp),
241 gate_w: p("ffn.gate.weight"),
242 gate_bias: p("ffn.gate.bias"),
243 experts: (0..c.moe.n_routed)
244 .map(|e| {
245 (
246 p(&format!("ffn.experts.{e}.w1.weight")),
247 p(&format!("ffn.experts.{e}.w2.weight")),
248 p(&format!("ffn.experts.{e}.w3.weight")),
249 )
250 })
251 .collect(),
252 shared: (
253 p("ffn.shared_experts.w1.weight"),
254 p("ffn.shared_experts.w2.weight"),
255 p("ffn.shared_experts.w3.weight"),
256 ),
257 engram,
258 }
259 })
260 .collect();
261 ModelWeights {
262 embed: regen_param(g, "embed.weight"),
263 norm: regen_param(g, "norm.weight"),
264 head: regen_param(g, "head.weight"),
265 layers,
266 }
267 }
268}
269
270pub struct ModelState<'a> {
271 pub hash: NgramHashState<'a>,
272 pub layers: Vec<LayerAttnState>,
273 pub shared: SharedRuntime,
274 pub fcs: Vec<Vec<(f32, f32)>>,
275}
276
277impl<'a> ModelState<'a> {
278 pub fn new(c: &ModelCfg, t: &'a EngramTables) -> Self {
279 ModelState {
280 hash: NgramHashState::new(t, 1, c.max_seq),
281 layers: (0..c.n_layers)
282 .map(|l| LayerAttnState::new(&c.attn_cfg(l), c.max_seq, c.index_hd))
283 .collect(),
284 shared: SharedRuntime::default(),
285 fcs: (0..c.n_layers)
286 .map(|l| {
287 if c.ratios[l] == 0 {
288 freqs_cis(c.rope_dim, c.max_seq, c.rope_theta)
289 } else {
290 yarn_freqs_cis(
291 c.rope_dim,
292 c.max_seq,
293 c.orig_seq,
294 c.compress_rope_theta,
295 c.rope_factor,
296 c.beta_fast,
297 c.beta_slow,
298 )
299 }
300 })
301 .collect(),
302 }
303 }
304}
305
306pub struct LayerTrace {
307 pub engram_out: Option<Vec<f32>>,
308 pub h_in: Vec<f32>,
309 pub pre_mix_in: Vec<f32>,
310 pub attn_pre: Vec<f32>,
311 pub attn_post: Vec<f32>,
312 pub attn_comb: Vec<f32>,
313 pub attn_in: Vec<f32>,
314 pub attn: CompAttnRun,
315 pub ffn_pre: Vec<f32>,
316 pub ffn_post: Vec<f32>,
317 pub ffn_comb: Vec<f32>,
318 pub ffn_in: Vec<f32>,
319 pub moe_weights: Vec<f32>,
320 pub moe_indices: Vec<usize>,
321 pub ffn_out: Vec<f32>,
322 pub h_out: Vec<f32>,
323 pub shared_compress_kv: Vec<f32>,
326 pub shared_index_k: Vec<f32>,
327 pub shared_topk: Vec<i32>,
328 pub shared_topk_w: usize,
329 pub shared_cand: Vec<bool>,
330 pub shared_cand_w: usize,
331}
332
333pub struct StepTrace {
334 pub tokens: usize,
335 pub embed: Vec<f32>,
336 pub layers: Vec<LayerTrace>,
337 pub h_final: Vec<f32>,
338 pub head_in: Vec<f32>,
339 pub logits: Vec<f32>,
340}
341
342#[cfg(test)]
343#[path = "model_tests.rs"]
344mod tests;