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