metrale_model_arch/deepseek_v41_ref/
hc.rs1use super::to_bf16_rne;
30
31fn sigmoid(x: f32) -> f32 {
32 1.0 / (1.0 + (-x).exp())
33}
34
35pub fn split_sinkhorn(
39 mixes: &[f32],
40 scale: &[f32],
41 base: &[f32],
42 hc: usize,
43 iters: usize,
44 eps: f32,
45) -> (Vec<f32>, Vec<f32>, Vec<f32>) {
46 let pre: Vec<f32> = (0..hc)
47 .map(|j| sigmoid(mixes[j] * scale[0] + base[j]) + eps)
48 .collect();
49 let post: Vec<f32> = (0..hc)
50 .map(|j| 2.0 * sigmoid(mixes[hc + j] * scale[1] + base[hc + j]))
51 .collect();
52 let mut comb: Vec<f32> = (0..hc * hc)
53 .map(|i| mixes[2 * hc + i] * scale[2] + base[2 * hc + i])
54 .collect();
55 for j in 0..hc {
56 let row = &mut comb[j * hc..(j + 1) * hc];
57 let m = row.iter().cloned().fold(f32::NEG_INFINITY, f32::max);
58 let mut sum = 0f32;
59 for v in row.iter_mut() {
60 *v = (*v - m).exp();
61 sum += *v;
62 }
63 for v in row.iter_mut() {
64 *v = *v / sum + eps;
65 }
66 }
67 let col_norm = |c: &mut [f32]| {
68 for k in 0..hc {
69 let s: f32 = (0..hc).map(|j| c[j * hc + k]).sum();
70 for j in 0..hc {
71 c[j * hc + k] /= s + eps;
72 }
73 }
74 };
75 let row_norm = |c: &mut [f32]| {
76 for j in 0..hc {
77 let s: f32 = c[j * hc..(j + 1) * hc].iter().sum();
78 for v in &mut c[j * hc..(j + 1) * hc] {
79 *v /= s + eps;
80 }
81 }
82 };
83 col_norm(&mut comb);
84 for _ in 1..iters {
85 row_norm(&mut comb);
86 col_norm(&mut comb);
87 }
88 (pre, post, comb)
89}
90
91pub fn hc_mixes(
95 x: &[f32],
96 tokens: usize,
97 hc: usize,
98 dim: usize,
99 hc_fn: &[f32],
100 scale: &[f32],
101 base: &[f32],
102 iters: usize,
103 hc_eps: f32,
104 norm_eps: f32,
105) -> (Vec<f32>, Vec<f32>, Vec<f32>) {
106 let n = hc * dim;
107 let mix_hc = (2 + hc) * hc;
108 let (mut pre, mut post, mut comb) = (
109 Vec::with_capacity(tokens * hc),
110 Vec::with_capacity(tokens * hc),
111 Vec::with_capacity(tokens * hc * hc),
112 );
113 for t in 0..tokens {
114 let xf = &x[t * n..(t + 1) * n];
115 let rsqrt = (xf.iter().map(|v| v * v).sum::<f32>() / n as f32 + norm_eps)
117 .sqrt()
118 .recip();
119 let mixes: Vec<f32> = (0..mix_hc)
120 .map(|m| {
121 hc_fn[m * n..(m + 1) * n]
122 .iter()
123 .zip(xf)
124 .map(|(a, b)| a * b)
125 .sum::<f32>()
126 * rsqrt
127 })
128 .collect();
129 let (p, q, c) = split_sinkhorn(&mixes, scale, base, hc, iters, hc_eps);
130 pre.extend(p);
131 post.extend(q);
132 comb.extend(c);
133 }
134 (pre, post, comb)
135}
136
137pub fn hc_pre(x: &[f32], pre: &[f32], tokens: usize, hc: usize, dim: usize) -> Vec<f32> {
139 let mut y = vec![0f32; tokens * dim];
140 for t in 0..tokens {
141 for d in 0..dim {
142 let mut acc = 0f32;
143 for c in 0..hc {
144 acc += pre[t * hc + c] * x[(t * hc + c) * dim + d];
145 }
146 y[t * dim + d] = to_bf16_rne(acc);
147 }
148 }
149 y
150}
151
152pub fn hc_post(
154 x: &[f32],
155 residual: &[f32],
156 post: &[f32],
157 comb: &[f32],
158 tokens: usize,
159 hc: usize,
160 dim: usize,
161) -> Vec<f32> {
162 let mut y = vec![0f32; tokens * hc * dim];
163 for t in 0..tokens {
164 for k in 0..hc {
165 for d in 0..dim {
166 let mut acc = post[t * hc + k] * x[t * dim + d];
167 for j in 0..hc {
168 acc += comb[(t * hc + j) * hc + k] * residual[(t * hc + j) * dim + d];
169 }
170 y[(t * hc + k) * dim + d] = to_bf16_rne(acc);
171 }
172 }
173 }
174 y
175}
176
177pub fn rms_norm(x: &[f32], w: &[f32], tokens: usize, dim: usize, eps: f32) -> Vec<f32> {
179 let mut y = vec![0f32; tokens * dim];
180 for t in 0..tokens {
181 let row = &x[t * dim..(t + 1) * dim];
182 let rsqrt = (row.iter().map(|v| v * v).sum::<f32>() / dim as f32 + eps)
183 .sqrt()
184 .recip();
185 for d in 0..dim {
186 y[t * dim + d] = to_bf16_rne(w[d] * (row[d] * rsqrt));
187 }
188 }
189 y
190}
191
192#[cfg(test)]
193#[path = "hc_tests.rs"]
194mod tests;