metrale_model_arch/deepseek_v41_ref/
engram.rs1use super::{Golden, fixed_value, to_bf16_rne};
29
30pub struct EngramTables {
33 pub layer_ids: Vec<usize>,
34 pub max_ngram: usize,
35 pub n_heads: usize,
36 pub head_dim: usize,
37 pub num_embeddings: Vec<usize>,
38 pub pad_id: i64,
44 pub token_map: Vec<i64>,
45 pub multipliers: Vec<Vec<i64>>,
46 pub primes: Vec<Vec<Vec<i64>>>,
47 pub offsets: Vec<Vec<i64>>,
48 pub scale_block: usize,
49 pub scales: Vec<Vec<f32>>,
50}
51
52impl EngramTables {
53 pub fn n_hash_cols(&self) -> usize {
54 (self.max_ngram - 1) * self.n_heads
55 }
56
57 pub fn from_golden(g: &Golden) -> Self {
58 let e = &g.0["fixture"]["engram"];
59 let ints = |v: &serde_json::Value| -> Vec<i64> {
60 v.as_array()
61 .expect("array")
62 .iter()
63 .map(|x| x.as_i64().expect("int"))
64 .collect()
65 };
66 EngramTables {
67 layer_ids: ints(&e["layer_ids"])
68 .into_iter()
69 .map(|x| x as usize)
70 .collect(),
71 max_ngram: e["max_ngram_size"].as_u64().unwrap() as usize,
72 n_heads: e["n_heads"].as_u64().unwrap() as usize,
73 head_dim: e["head_dim"].as_u64().unwrap() as usize,
74 num_embeddings: ints(&e["num_embeddings"])
75 .into_iter()
76 .map(|x| x as usize)
77 .collect(),
78 pad_id: e["pad_id_compressed"].as_i64().unwrap(),
79 token_map: ints(&e["token_map"]),
80 multipliers: e["multipliers"]
81 .as_array()
82 .unwrap()
83 .iter()
84 .map(ints)
85 .collect(),
86 primes: e["primes"]
87 .as_array()
88 .unwrap()
89 .iter()
90 .map(|l| l.as_array().unwrap().iter().map(ints).collect())
91 .collect(),
92 offsets: e["offsets"].as_array().unwrap().iter().map(ints).collect(),
93 scale_block: e["scale_block"].as_u64().unwrap() as usize,
94 scales: e["scales"]
95 .as_array()
96 .unwrap()
97 .iter()
98 .map(|l| {
99 l.as_array()
100 .unwrap()
101 .iter()
102 .map(|x| x.as_f64().unwrap() as f32)
103 .collect()
104 })
105 .collect(),
106 }
107 }
108}
109
110pub struct NgramHashState<'a> {
114 pub t: &'a EngramTables,
115 pub batch: usize,
116 pub max_seq: usize,
117 cache: Vec<i64>,
118}
119
120impl<'a> NgramHashState<'a> {
121 pub fn new(t: &'a EngramTables, batch: usize, max_seq: usize) -> Self {
122 NgramHashState {
123 t,
124 batch,
125 max_seq,
126 cache: vec![0; batch * max_seq],
127 }
128 }
129
130 pub fn forward(&mut self, input_ids: &[i64], seqlen: usize, start_pos: usize) -> Vec<i64> {
133 let t = self.t;
134 let (b_n, ng, nl, cols) = (self.batch, t.max_ngram, t.layer_ids.len(), t.n_hash_cols());
135 assert_eq!(input_ids.len(), b_n * seqlen);
136 assert!(start_pos + seqlen <= self.max_seq);
137 for b in 0..b_n {
138 for s in 0..seqlen {
139 self.cache[b * self.max_seq + start_pos + s] =
140 t.token_map[input_ids[b * seqlen + s] as usize];
141 }
142 }
143 let mut out = vec![0i64; b_n * seqlen * nl * cols];
144 let mut tokens = vec![0i64; ng];
145 for b in 0..b_n {
146 for s in 0..seqlen {
147 let pos = start_pos + s;
148 let mut blocked = false;
151 for (shift, tok) in tokens.iter_mut().enumerate() {
152 let src = self.cache[b * self.max_seq + pos.saturating_sub(shift)];
153 blocked = blocked || pos < shift || src == -1;
154 *tok = if blocked { t.pad_id } else { src };
155 }
156 for (li, mults) in t.multipliers.iter().enumerate() {
157 let mut rolling = tokens[0].wrapping_mul(mults[0]);
158 for i in 1..ng {
159 rolling ^= tokens[i].wrapping_mul(mults[i]);
160 for h in 0..t.n_heads {
161 let col = (i - 1) * t.n_heads + h;
162 out[((b * seqlen + s) * nl + li) * cols + col] =
163 rolling.rem_euclid(t.primes[li][i - 1][h]) + t.offsets[li][col];
164 }
165 }
166 }
167 }
168 }
169 out
170 }
171}
172
173pub fn f32_to_e4m3_rne(x: f32) -> u8 {
176 if x.is_nan() {
177 return 0x7F;
178 }
179 let sign: u8 = if x.is_sign_negative() { 0x80 } else { 0 };
180 let bits = x.abs().to_bits();
181 let exp_field = ((bits >> 23) & 0xFF) as i32;
182 if exp_field == 0 {
183 return sign;
184 }
185 let a = x.abs() as f64;
186 if a > 448.0 {
187 return sign | 0x7E;
188 }
189 let e = exp_field - 127;
190 if e < -6 {
191 let r = (a * 512.0).round_ties_even() as u8;
194 return sign | r;
195 }
196 let mant = ((a * 2f64.powi(-e) - 1.0) * 8.0).round_ties_even() as u8;
197 let (e, mant) = if mant == 8 { (e + 1, 0u8) } else { (e, mant) };
198 sign | (((e + 7) as u8) << 3) | mant
199}
200
201pub fn e4m3_to_f32(b: u8) -> f32 {
202 let sign = if b & 0x80 != 0 { -1.0f32 } else { 1.0 };
203 let exp_field = ((b >> 3) & 0x0F) as i32;
204 let mant = (b & 0x07) as f32;
205 if exp_field == 15 && mant == 7.0 {
206 return f32::NAN;
207 }
208 if exp_field == 0 {
209 return sign * mant / 8.0 * 2f32.powi(-6);
210 }
211 sign * (1.0 + mant / 8.0) * 2f32.powi(exp_field - 7)
212}
213
214pub fn f32_to_e8m0_rne(x: f32) -> f32 {
218 let bits = x.to_bits();
219 let mut e = ((bits >> 23) & 0xFF) as i32;
220 let m = bits & 0x7F_FFFF;
221 if m > 0x40_0000 || (m == 0x40_0000 && (e & 1) == 1) {
222 e += 1;
223 }
224 f32::from_bits((e as u32) << 23)
225}
226
227pub fn regen_table(t: &EngramTables, layer_idx: usize) -> Vec<f32> {
232 let lid = t.layer_ids[layer_idx];
233 let (rows, hd, blk) = (t.num_embeddings[layer_idx], t.head_dim, t.scale_block);
234 let name = format!("layers.{lid}.engram.embed.weight");
235 let scales = &t.scales[layer_idx];
236 (0..(rows * hd) as u64)
237 .map(|i| {
238 let v = e4m3_to_f32(f32_to_e4m3_rne(fixed_value(&name, i, 0.5, 0.0)));
239 let (r, d) = ((i as usize) / hd, (i as usize) % hd);
240 to_bf16_rne(v * scales[r * (hd / blk) + d / blk])
241 })
242 .collect()
243}
244
245pub fn embed_rows(table: &[f32], head_dim: usize, hash_ids: &[i64]) -> Vec<f32> {
247 let mut out = Vec::with_capacity(hash_ids.len() * head_dim);
248 for &id in hash_ids {
249 let r = id as usize * head_dim;
250 out.extend_from_slice(&table[r..r + head_dim]);
251 }
252 out
253}
254
255pub fn regen_bf16_matrix(name: &str, out_f: usize, in_f: usize) -> Vec<f32> {
258 let scale = (in_f as f64).powf(-0.5);
259 (0..(out_f * in_f) as u64)
260 .map(|i| to_bf16_rne(fixed_value(name, i, scale, 0.0)))
261 .collect()
262}
263
264pub fn regen_bf16_qk(name: &str, n: usize) -> Vec<f32> {
267 (0..n as u64)
268 .map(|i| to_bf16_rne(fixed_value(name, i, 0.05, 1.0)))
269 .collect()
270}
271
272pub fn linear_bf16(x: &[f32], rows: usize, in_f: usize, w: &[f32], out_f: usize) -> Vec<f32> {
275 let mut y = vec![0f32; rows * out_f];
276 for r in 0..rows {
277 let xr = &x[r * in_f..(r + 1) * in_f];
278 for o in 0..out_f {
279 let wr = &w[o * in_f..(o + 1) * in_f];
280 let acc: f32 = xr.iter().zip(wr).map(|(a, b)| a * b).sum();
281 y[r * out_f + o] = to_bf16_rne(acc);
282 }
283 }
284 y
285}
286
287pub fn gate_and_add(
291 x: &[f32],
292 kv: &[f32],
293 q_w: &[f32],
294 k_w: &[f32],
295 tokens: usize,
296 hc: usize,
297 dim: usize,
298 eps: f32,
299) -> Vec<f32> {
300 let kv_w = dim * (hc + 1);
301 let inv_sqrt_dim = (dim as f32).powf(-0.5);
302 let mut out = vec![0f32; tokens * hc * dim];
303 for t in 0..tokens {
304 let value = &kv[t * kv_w + hc * dim..(t + 1) * kv_w];
305 for c in 0..hc {
306 let h = &x[(t * hc + c) * dim..(t * hc + c + 1) * dim];
307 let key = &kv[t * kv_w + c * dim..t * kv_w + (c + 1) * dim];
308 let (mut hh, mut kk, mut dot) = (0f32, 0f32, 0f32);
309 for d in 0..dim {
310 hh += h[d] * h[d];
311 kk += key[d] * key[d];
312 dot += h[d] * (q_w[c * dim + d] * k_w[c * dim + d]) * key[d];
314 }
315 let rstd =
316 (hh / dim as f32 + eps).sqrt().recip() * (kk / dim as f32 + eps).sqrt().recip();
317 let dot = dot * rstd * inv_sqrt_dim;
318 let g = dot.abs().max(1e-6).sqrt().copysign(dot);
320 let gate = 1.0 / (1.0 + (-g).exp());
321 for d in 0..dim {
322 out[(t * hc + c) * dim + d] = to_bf16_rne(h[d] + gate * value[d]);
323 }
324 }
325 }
326 out
327}
328
329#[cfg(test)]
330#[path = "engram_tests.rs"]
331mod tests;