1use crate::pool::Pool;
22
23pub trait Fp:
28 Copy
29 + PartialOrd
30 + core::ops::Add<Output = Self>
31 + core::ops::Sub<Output = Self>
32 + core::ops::Mul<Output = Self>
33 + core::ops::Div<Output = Self>
34 + core::ops::Neg<Output = Self>
35 + core::ops::AddAssign
36 + core::ops::MulAssign
37 + Send
38 + Sync
39 + 'static
40{
41 const ZERO: Self;
42 const ONE: Self;
43 fn exp(self) -> Self;
44 fn sqrt(self) -> Self;
45 fn maxf(self, o: Self) -> Self;
46 fn fromf(x: f64) -> Self;
47 fn f64(self) -> f64;
48}
49
50impl Fp for f32 {
51 const ZERO: Self = 0.0;
52 const ONE: Self = 1.0;
53 #[inline]
54 fn exp(self) -> Self {
55 f32::exp(self)
56 }
57 #[inline]
58 fn sqrt(self) -> Self {
59 f32::sqrt(self)
60 }
61 #[inline]
62 fn maxf(self, o: Self) -> Self {
63 f32::max(self, o)
64 }
65 #[inline]
66 fn fromf(x: f64) -> Self {
67 x as f32
68 }
69 #[inline]
70 fn f64(self) -> f64 {
71 self as f64
72 }
73}
74
75impl Fp for f64 {
76 const ZERO: Self = 0.0;
77 const ONE: Self = 1.0;
78 #[inline]
79 fn exp(self) -> Self {
80 f64::exp(self)
81 }
82 #[inline]
83 fn sqrt(self) -> Self {
84 f64::sqrt(self)
85 }
86 #[inline]
87 fn maxf(self, o: Self) -> Self {
88 f64::max(self, o)
89 }
90 #[inline]
91 fn fromf(x: f64) -> Self {
92 x
93 }
94 #[inline]
95 fn f64(self) -> f64 {
96 self
97 }
98}
99
100#[inline]
101fn dot<F: Fp>(a: &[F], b: &[F]) -> F {
102 let mut s = F::ZERO;
103 for (x, y) in a.iter().zip(b) {
104 s += *x * *y;
105 }
106 s
107}
108
109pub fn matmul_nt<F: Fp>(x: &[F], w: &[F], y: &mut [F], n: usize, k: usize, m: usize) {
114 for i in 0..n {
115 let xr = &x[i * k..(i + 1) * k];
116 for o in 0..m {
117 y[i * m + o] = dot(xr, &w[o * k..(o + 1) * k]);
118 }
119 }
120}
121
122pub fn matmul_nt_dx<F: Fp>(dy: &[F], w: &[F], dx: &mut [F], n: usize, k: usize, m: usize) {
124 for i in 0..n {
125 let dxr = &mut dx[i * k..(i + 1) * k];
126 for o in 0..m {
127 let g = dy[i * m + o];
128 for (d, wv) in dxr.iter_mut().zip(&w[o * k..(o + 1) * k]) {
129 *d += g * *wv;
130 }
131 }
132 }
133}
134
135pub fn matmul_nt_dw<F: Fp>(dy: &[F], x: &[F], dw: &mut [F], n: usize, k: usize, m: usize) {
137 for i in 0..n {
138 let xr = &x[i * k..(i + 1) * k];
139 for o in 0..m {
140 let g = dy[i * m + o];
141 for (d, xv) in dw[o * k..(o + 1) * k].iter_mut().zip(xr) {
142 *d += g * *xv;
143 }
144 }
145 }
146}
147
148const GEMM_BLOCK: usize = 128;
153
154struct SendMut<T>(*mut T);
157unsafe impl<T> Send for SendMut<T> {}
158unsafe impl<T> Sync for SendMut<T> {}
159impl<T> SendMut<T> {
160 #[inline]
161 #[allow(clippy::mut_from_ref)]
165 unsafe fn slice(&self, off: usize, len: usize) -> &mut [T] {
166 unsafe { std::slice::from_raw_parts_mut(self.0.add(off), len) }
167 }
168}
169
170pub fn gemm_nt(x: &[f32], w: &[f32], y: &mut [f32], n: usize, k: usize, m: usize, pool: Option<&Pool>) {
173 debug_assert_eq!(x.len(), n * k);
174 debug_assert_eq!(w.len(), m * k);
175 debug_assert_eq!(y.len(), n * m);
176 let nb = n.div_ceil(GEMM_BLOCK);
177 let block = |r0: usize, r1: usize, y: &mut [f32]| {
178 for o in 0..m {
179 let wr = &w[o * k..(o + 1) * k];
180 for i in r0..r1 {
181 y[(i - r0) * m + o] = crate::attention::dot_f32(&x[i * k..(i + 1) * k], wr);
182 }
183 }
184 };
185 match pool {
186 Some(p) if nb > 1 => {
187 let yp = SendMut(y.as_mut_ptr());
188 p.run(&|widx, nw| {
189 for bi in (widx..nb).step_by(nw) {
190 let (r0, r1) = (bi * GEMM_BLOCK, ((bi + 1) * GEMM_BLOCK).min(n));
191 let ys = unsafe { yp.slice(r0 * m, (r1 - r0) * m) };
193 block(r0, r1, ys);
194 }
195 });
196 }
197 _ => {
198 for bi in 0..nb {
199 let (r0, r1) = (bi * GEMM_BLOCK, ((bi + 1) * GEMM_BLOCK).min(n));
200 block(r0, r1, &mut y[r0 * m..r1 * m]);
201 }
202 }
203 }
204}
205
206pub fn gemm_dx(dy: &[f32], w: &[f32], dx: &mut [f32], n: usize, k: usize, m: usize, pool: Option<&Pool>) {
208 debug_assert_eq!(dy.len(), n * m);
209 debug_assert_eq!(w.len(), m * k);
210 debug_assert_eq!(dx.len(), n * k);
211 let nb = n.div_ceil(GEMM_BLOCK);
212 let block = |r0: usize, r1: usize, dxs: &mut [f32]| {
213 for o in 0..m {
214 let wr = &w[o * k..(o + 1) * k];
215 for i in r0..r1 {
216 let g = dy[i * m + o];
217 if g != 0.0 {
218 crate::attention::axpy_f32(&mut dxs[(i - r0) * k..(i - r0 + 1) * k], wr, g);
219 }
220 }
221 }
222 };
223 match pool {
224 Some(p) if nb > 1 => {
225 let dxp = SendMut(dx.as_mut_ptr());
226 p.run(&|widx, nw| {
227 for bi in (widx..nb).step_by(nw) {
228 let (r0, r1) = (bi * GEMM_BLOCK, ((bi + 1) * GEMM_BLOCK).min(n));
229 let dxs = unsafe { dxp.slice(r0 * k, (r1 - r0) * k) };
231 block(r0, r1, dxs);
232 }
233 });
234 }
235 _ => {
236 for bi in 0..nb {
237 let (r0, r1) = (bi * GEMM_BLOCK, ((bi + 1) * GEMM_BLOCK).min(n));
238 block(r0, r1, &mut dx[r0 * k..r1 * k]);
239 }
240 }
241 }
242}
243
244pub fn gemm_dw(dy: &[f32], x: &[f32], dw: &mut [f32], n: usize, k: usize, m: usize, pool: Option<&Pool>) {
247 debug_assert_eq!(dy.len(), n * m);
248 debug_assert_eq!(x.len(), n * k);
249 debug_assert_eq!(dw.len(), m * k);
250 let range = |o0: usize, o1: usize, dws: &mut [f32]| {
251 let nb = n.div_ceil(GEMM_BLOCK);
253 for bi in 0..nb {
254 let (r0, r1) = (bi * GEMM_BLOCK, ((bi + 1) * GEMM_BLOCK).min(n));
255 for o in o0..o1 {
256 let dwr = &mut dws[(o - o0) * k..(o - o0 + 1) * k];
257 for i in r0..r1 {
258 let g = dy[i * m + o];
259 if g != 0.0 {
260 crate::attention::axpy_f32(dwr, &x[i * k..(i + 1) * k], g);
261 }
262 }
263 }
264 }
265 };
266 match pool {
267 Some(p) if m >= 8 => {
268 let dwp = SendMut(dw.as_mut_ptr());
269 p.run(&|widx, nw| {
270 let (o0, o1) = (widx * m / nw, (widx + 1) * m / nw);
271 if o0 < o1 {
272 let dws = unsafe { dwp.slice(o0 * k, (o1 - o0) * k) };
274 range(o0, o1, dws);
275 }
276 });
277 }
278 _ => range(0, m, dw),
279 }
280}
281
282#[inline]
285pub fn silu<F: Fp>(x: F) -> F {
286 x / (F::ONE + (-x).exp())
287}
288
289#[inline]
291pub fn silu_bwd<F: Fp>(x: F) -> F {
292 let s = F::ONE / (F::ONE + (-x).exp());
293 s * (F::ONE + x * (F::ONE - s))
294}
295
296pub fn rmsnorm_fwd<F: Fp>(x: &[F], w: &[F], eps: f64, gemma: bool, y: &mut [F], inv_out: &mut [F]) {
303 let d = w.len();
304 let n = x.len() / d;
305 for r in 0..n {
306 let xr = &x[r * d..(r + 1) * d];
307 let mut ss = 0f64;
308 for v in xr {
309 ss += v.f64() * v.f64();
310 }
311 let inv = F::fromf(1.0 / (ss / d as f64 + eps).sqrt());
312 inv_out[r] = inv;
313 let yr = &mut y[r * d..(r + 1) * d];
314 for j in 0..d {
315 let weff = if gemma { F::ONE + w[j] } else { w[j] };
316 yr[j] = xr[j] * inv * weff;
317 }
318 }
319}
320
321pub fn rmsnorm_bwd<F: Fp>(
327 x: &[F],
328 w: &[F],
329 inv: &[F],
330 dy: &[F],
331 gemma: bool,
332 dx: &mut [F],
333 mut dw: Option<&mut [F]>,
334) {
335 let d = w.len();
336 let n = x.len() / d;
337 for r in 0..n {
338 let xr = &x[r * d..(r + 1) * d];
339 let dyr = &dy[r * d..(r + 1) * d];
340 let iv = inv[r];
341 let mut s = 0f64;
342 for j in 0..d {
343 let weff = if gemma { F::ONE + w[j] } else { w[j] };
344 s += (dyr[j] * weff * xr[j]).f64();
345 }
346 let coef = F::fromf(s / d as f64) * iv * iv * iv;
347 let dxr = &mut dx[r * d..(r + 1) * d];
348 for j in 0..d {
349 let weff = if gemma { F::ONE + w[j] } else { w[j] };
350 dxr[j] += iv * weff * dyr[j] - xr[j] * coef;
351 }
352 if let Some(dwv) = dw.as_deref_mut() {
353 for j in 0..d {
354 dwv[j] += dyr[j] * xr[j] * iv;
355 }
356 }
357 }
358}
359
360pub fn rope_fwd<F: Fp>(x: &mut [F], position: usize, inv_freq: &[f64]) {
365 let half = inv_freq.len();
366 for (i, &freq) in inv_freq.iter().enumerate() {
367 let angle = position as f64 * freq;
368 let (sin, cos) = (F::fromf(angle.sin()), F::fromf(angle.cos()));
369 let x0 = x[i];
370 let x1 = x[i + half];
371 x[i] = x0 * cos - x1 * sin;
372 x[i + half] = x0 * sin + x1 * cos;
373 }
374}
375
376pub fn rope_bwd<F: Fp>(dy: &mut [F], position: usize, inv_freq: &[f64]) {
379 let half = inv_freq.len();
380 for (i, &freq) in inv_freq.iter().enumerate() {
381 let angle = position as f64 * freq;
382 let (sin, cos) = (F::fromf(angle.sin()), F::fromf(angle.cos()));
383 let g0 = dy[i];
384 let g1 = dy[i + half];
385 dy[i] = g0 * cos + g1 * sin;
386 dy[i + half] = -g0 * sin + g1 * cos;
387 }
388}
389
390pub fn seg_means<F: Fp>(x: &[F], t: usize, d: usize, m: usize, out: &mut [F]) {
395 for i in 0..m {
396 let (lo, hi) = (i * t / m, (i + 1) * t / m);
397 let or = &mut out[i * d..(i + 1) * d];
398 for v in or.iter_mut() {
399 *v = F::ZERO;
400 }
401 for j in lo..hi {
402 for c in 0..d {
403 or[c] += x[j * d + c];
404 }
405 }
406 let inv = F::fromf(1.0 / (hi - lo) as f64);
407 for v in or.iter_mut() {
408 *v *= inv;
409 }
410 }
411}
412
413pub fn seg_means_bwd<F: Fp>(dl: &[F], t: usize, d: usize, m: usize, dx: &mut [F]) {
416 for i in 0..m {
417 let (lo, hi) = (i * t / m, (i + 1) * t / m);
418 let inv = F::fromf(1.0 / (hi - lo) as f64);
419 let dlr = &dl[i * d..(i + 1) * d];
420 for j in lo..hi {
421 for c in 0..d {
422 dx[j * d + c] += dlr[c] * inv;
423 }
424 }
425 }
426}
427
428#[allow(clippy::needless_range_loop)] pub fn attn_head_fwd<F: Fp>(q: &[F], k: &[F], v: &[F], t: usize, d: usize, dv: usize, out: &mut [F]) {
434 let scale = F::fromf(1.0 / (d as f64).sqrt());
435 let mut row = vec![F::ZERO; t];
436 for ti in 0..t {
437 let qr = &q[ti * d..(ti + 1) * d];
438 let mut mx = F::fromf(f64::NEG_INFINITY);
439 for j in 0..=ti {
440 let s = dot(qr, &k[j * d..(j + 1) * d]) * scale;
441 row[j] = s;
442 mx = mx.maxf(s);
443 }
444 let mut den = F::ZERO;
445 for j in 0..=ti {
446 row[j] = (row[j] - mx).exp();
447 den += row[j];
448 }
449 let or = &mut out[ti * dv..(ti + 1) * dv];
450 for o in or.iter_mut() {
451 *o = F::ZERO;
452 }
453 for j in 0..=ti {
454 let p = row[j] / den;
455 for (o, vv) in or.iter_mut().zip(&v[j * dv..(j + 1) * dv]) {
456 *o += p * *vv;
457 }
458 }
459 }
460}
461
462#[allow(clippy::too_many_arguments, clippy::needless_range_loop)]
466pub fn attn_head_bwd<F: Fp>(
467 q: &[F],
468 k: &[F],
469 v: &[F],
470 dout: &[F],
471 t: usize,
472 d: usize,
473 dv: usize,
474 dq: &mut [F],
475 dk: &mut [F],
476 dvv: &mut [F],
477) {
478 let scale = F::fromf(1.0 / (d as f64).sqrt());
479 let mut row = vec![F::ZERO; t];
480 for ti in 0..t {
481 let qr = &q[ti * d..(ti + 1) * d];
482 let mut mx = F::fromf(f64::NEG_INFINITY);
483 for j in 0..=ti {
484 let s = dot(qr, &k[j * d..(j + 1) * d]) * scale;
485 row[j] = s;
486 mx = mx.maxf(s);
487 }
488 let mut den = F::ZERO;
489 for j in 0..=ti {
490 row[j] = (row[j] - mx).exp();
491 den += row[j];
492 }
493 let dor = &dout[ti * dv..(ti + 1) * dv];
494 let mut pdp = F::ZERO;
496 let mut dp = vec![F::ZERO; ti + 1];
497 for j in 0..=ti {
498 let p = row[j] / den;
499 row[j] = p; dp[j] = dot(dor, &v[j * dv..(j + 1) * dv]);
501 pdp += p * dp[j];
502 }
503 let dqr = &mut dq[ti * d..(ti + 1) * d];
504 for j in 0..=ti {
505 let p = row[j];
506 for (dvo, o) in dvv[j * dv..(j + 1) * dv].iter_mut().zip(dor) {
508 *dvo += p * *o;
509 }
510 let ds = p * (dp[j] - pdp) * scale;
512 let kr = &k[j * d..(j + 1) * d];
513 for c in 0..d {
514 dqr[c] += ds * kr[c];
515 }
516 let dkr = &mut dk[j * d..(j + 1) * d];
517 for c in 0..d {
518 dkr[c] += ds * qr[c];
519 }
520 }
521 }
522}
523
524#[derive(Clone, Copy, Debug)]
528pub struct NysCfg {
529 pub m: usize,
531 pub w: usize,
533 pub sink: usize,
535 pub prefill: Option<usize>,
547}
548
549impl NysCfg {
550 #[inline]
553 pub fn prefill_len(&self, t: usize) -> usize {
554 self.prefill.unwrap_or(t / 2).clamp(1, t)
555 }
556}
557
558const NYS_DEN_EPS: f64 = 1e-30;
560
561struct NysGraph<F: Fp> {
565 m_eff: usize,
566 tp: usize,
569 q_l: Vec<F>,
570 k_l: Vec<F>,
571 mu: Vec<F>,
572 fu: Vec<F>,
573 e: Vec<F>,
574 fumu: Vec<F>,
575 far_keep: Vec<bool>,
584 wmat: Vec<F>,
587 c_row: Vec<F>,
588 den: Vec<F>,
589}
590
591#[inline]
596fn nys_exact_row(ti: usize, tp: usize) -> bool {
597 ti < tp
598}
599
600#[inline]
602fn nys_near(ti: usize, j: usize, w: usize, sink: usize) -> bool {
603 ti - j < w || j < sink
604}
605
606fn nys_graph<F: Fp>(
611 q: &[F],
612 k: &[F],
613 t: usize,
614 d: usize,
615 cfg: &NysCfg,
616 mu_override: Option<&[F]>,
617) -> NysGraph<F> {
618 let scale = 1.0 / (d as f64).sqrt();
619 let fscale = F::fromf(scale);
620 let tp = cfg.prefill_len(t);
625 let m_eff = (tp / 8).clamp(4, cfg.m);
626 let mut q_l = vec![F::ZERO; m_eff * d];
627 let mut k_l = vec![F::ZERO; m_eff * d];
628 seg_means(&q[..tp * d], tp, d, m_eff, &mut q_l);
629 seg_means(&k[..tp * d], tp, d, m_eff, &mut k_l);
630
631 let mut au = vec![0f64; m_eff * m_eff];
633 for i in 0..m_eff {
634 for j in 0..m_eff {
635 let mut s = 0f64;
636 for c in 0..d {
637 s += q_l[i * d + c].f64() * k_l[j * d + c].f64();
638 }
639 au[i * m_eff + j] = (s * scale).exp();
640 }
641 }
642 let mu: Vec<F> = match mu_override {
643 Some(m) => m.to_vec(),
644 None => crate::nystrom::ridge_pinv(&au, m_eff)
645 .iter()
646 .map(|&x| F::fromf(x))
647 .collect(),
648 };
649
650 let mut fu = vec![F::ZERO; t * m_eff];
652 for ti in 0..t {
653 for i in 0..m_eff {
654 fu[ti * m_eff + i] =
655 (dot(&q[ti * d..(ti + 1) * d], &k_l[i * d..(i + 1) * d]) * fscale).exp();
656 }
657 }
658 let mut e = vec![F::ZERO; m_eff * t];
659 for i in 0..m_eff {
660 for j in 0..t {
661 e[i * t + j] =
662 (dot(&q_l[i * d..(i + 1) * d], &k[j * d..(j + 1) * d]) * fscale).exp();
663 }
664 }
665 let mut fumu = vec![F::ZERO; t * m_eff];
666 matmul_nt(
667 &fu,
668 &transpose(&mu, m_eff, m_eff),
671 &mut fumu,
672 t,
673 m_eff,
674 m_eff,
675 );
676 let mut a = vec![F::ZERO; t * t];
681 for ti in tp..t {
682 let fr = &fumu[ti * m_eff..(ti + 1) * m_eff];
683 let ar = &mut a[ti * t..ti * t + ti + 1]; for (i, &f) in fr.iter().enumerate() {
685 let er = &e[i * t..i * t + ti + 1];
686 for (av, ev) in ar.iter_mut().zip(er) {
687 *av += f * *ev;
688 }
689 }
690 }
691
692 let mut wmat = vec![F::ZERO; t * t];
695 let mut c_row = vec![F::ZERO; t];
696 let mut den = vec![F::ZERO; t];
697 let mut far_keep = vec![false; t];
698 let mut lg_row = vec![F::ZERO; t];
699 for ti in 0..t {
700 let qr = &q[ti * d..(ti + 1) * d];
701 let mut c = F::fromf(f64::NEG_INFINITY);
702 for j in 0..=ti {
703 let s = dot(qr, &k[j * d..(j + 1) * d]) * fscale;
704 lg_row[j] = s;
705 c = c.maxf(s);
706 }
707 c_row[ti] = c;
708 let emc = (-c).exp();
709 let exact_row = nys_exact_row(ti, tp);
710
711 let mut far_sum = F::ZERO;
726 if !exact_row {
727 for j in 0..=ti {
728 if !nys_near(ti, j, cfg.w, cfg.sink) {
729 far_sum += a[ti * t + j];
730 }
731 }
732 }
733 let keep = !exact_row && far_sum.f64() >= 0.0;
734 far_keep[ti] = keep;
735
736 let wr = &mut wmat[ti * t..(ti + 1) * t];
737 let mut dsum = F::ZERO;
738 for j in 0..=ti {
739 let wv = if exact_row || nys_near(ti, j, cfg.w, cfg.sink) {
740 (lg_row[j] - c).exp()
741 } else if keep {
742 a[ti * t + j] * emc
743 } else {
744 F::ZERO
745 };
746 wr[j] = wv;
747 dsum += wv;
748 }
749 den[ti] = dsum.maxf(F::fromf(NYS_DEN_EPS));
750 }
751 NysGraph { m_eff, tp, q_l, k_l, mu, fu, e, fumu, far_keep, wmat, c_row, den }
752}
753
754fn transpose<F: Fp>(x: &[F], rows: usize, cols: usize) -> Vec<F> {
755 let mut out = vec![F::ZERO; rows * cols];
756 for r in 0..rows {
757 for c in 0..cols {
758 out[c * rows + r] = x[r * cols + c];
759 }
760 }
761 out
762}
763
764#[allow(clippy::too_many_arguments)]
767pub fn nystrom_head_fwd<F: Fp>(
768 q: &[F],
769 k: &[F],
770 v: &[F],
771 t: usize,
772 d: usize,
773 dv: usize,
774 cfg: &NysCfg,
775 out: &mut [F],
776) {
777 if nys_degenerate(t, cfg) {
778 attn_head_fwd(q, k, v, t, d, dv, out);
779 return;
780 }
781 nystrom_head_fwd_mu(q, k, v, t, d, dv, cfg, None, out);
782}
783
784#[inline]
793fn nys_degenerate(t: usize, cfg: &NysCfg) -> bool {
794 cfg.prefill_len(t) <= cfg.w + cfg.sink + 8
795}
796
797#[doc(hidden)]
800pub fn nystrom_mu_for_test<F: Fp>(q: &[F], k: &[F], t: usize, d: usize, cfg: &NysCfg) -> Vec<F> {
801 nys_graph(q, k, t, d, cfg, None).mu
802}
803
804#[doc(hidden)]
807#[allow(clippy::too_many_arguments)]
808pub fn nystrom_head_fwd_mu<F: Fp>(
809 q: &[F],
810 k: &[F],
811 v: &[F],
812 t: usize,
813 d: usize,
814 dv: usize,
815 cfg: &NysCfg,
816 mu_override: Option<&[F]>,
817 out: &mut [F],
818) {
819 let g = nys_graph(q, k, t, d, cfg, mu_override);
820 for ti in 0..t {
821 let wr = &g.wmat[ti * t..(ti + 1) * t];
822 let den = g.den[ti];
823 let or = &mut out[ti * dv..(ti + 1) * dv];
824 for o in or.iter_mut() {
825 *o = F::ZERO;
826 }
827 for j in 0..=ti {
828 let p = wr[j] / den;
829 if p.f64() != 0.0 {
830 for (o, vv) in or.iter_mut().zip(&v[j * dv..(j + 1) * dv]) {
831 *o += p * *vv;
832 }
833 }
834 }
835 }
836}
837
838#[allow(clippy::too_many_arguments)]
849pub fn nystrom_head_bwd<F: Fp>(
850 q: &[F],
851 k: &[F],
852 v: &[F],
853 dout: &[F],
854 t: usize,
855 d: usize,
856 dv: usize,
857 cfg: &NysCfg,
858 dq: &mut [F],
859 dk: &mut [F],
860 dvv: &mut [F],
861) {
862 if nys_degenerate(t, cfg) {
863 attn_head_bwd(q, k, v, dout, t, d, dv, dq, dk, dvv);
864 return;
865 }
866 nystrom_head_bwd_mu(q, k, v, dout, t, d, dv, cfg, None, dq, dk, dvv);
867}
868
869#[doc(hidden)]
871#[allow(clippy::too_many_arguments)]
872pub fn nystrom_head_bwd_mu<F: Fp>(
873 q: &[F],
874 k: &[F],
875 v: &[F],
876 dout: &[F],
877 t: usize,
878 d: usize,
879 dv: usize,
880 cfg: &NysCfg,
881 mu_override: Option<&[F]>,
882 dq: &mut [F],
883 dk: &mut [F],
884 dvv: &mut [F],
885) {
886 let scale = F::fromf(1.0 / (d as f64).sqrt());
887 let g = nys_graph(q, k, t, d, cfg, mu_override);
888 let m_eff = g.m_eff;
889
890 let mut dwmat = vec![F::ZERO; t * t];
892 let mut out_row = vec![F::ZERO; dv];
893 for ti in 0..t {
894 let wr = &g.wmat[ti * t..(ti + 1) * t];
895 let den = g.den[ti];
896 for o in out_row.iter_mut() {
897 *o = F::ZERO;
898 }
899 for j in 0..=ti {
900 let p = wr[j] / den;
901 if p.f64() != 0.0 {
902 for (o, vv) in out_row.iter_mut().zip(&v[j * dv..(j + 1) * dv]) {
903 *o += p * *vv;
904 }
905 }
906 }
907 let dor = &dout[ti * dv..(ti + 1) * dv];
908 let dwr = &mut dwmat[ti * t..(ti + 1) * t];
909 for j in 0..=ti {
910 let p = wr[j] / den;
912 if p.f64() != 0.0 {
913 for (dvo, o) in dvv[j * dv..(j + 1) * dv].iter_mut().zip(dor) {
914 *dvo += p * *o;
915 }
916 }
917 let mut s = F::ZERO;
919 for c in 0..dv {
920 s += dor[c] * (v[j * dv + c] - out_row[c]);
921 }
922 dwr[j] = s / den;
923 }
924 }
925
926 for ti in 0..t {
929 let qr = &q[ti * d..(ti + 1) * d];
930 let dqr_base = ti * d;
931 for j in 0..=ti {
932 if !(nys_exact_row(ti, g.tp) || nys_near(ti, j, cfg.w, cfg.sink)) {
933 continue;
934 }
935 let dlg = dwmat[ti * t + j] * g.wmat[ti * t + j] * scale;
936 if dlg.f64() == 0.0 {
937 continue;
938 }
939 let kr = &k[j * d..(j + 1) * d];
940 for c in 0..d {
941 dq[dqr_base + c] += dlg * kr[c];
942 }
943 let dkr = &mut dk[j * d..(j + 1) * d];
944 for c in 0..d {
945 dkr[c] += dlg * qr[c];
946 }
947 }
948 }
949
950 let mut da = vec![F::ZERO; t * t];
965 for ti in g.tp..t {
966 if !g.far_keep[ti] {
967 continue; }
969 let emc = (-g.c_row[ti]).exp();
970 for j in 0..=ti {
971 if nys_near(ti, j, cfg.w, cfg.sink) {
972 continue;
973 }
974 da[ti * t + j] = dwmat[ti * t + j] * emc;
975 }
976 }
977 let mut dfumu = vec![F::ZERO; t * m_eff];
979 for ti in 0..t {
980 let dar = &da[ti * t..ti * t + ti + 1];
981 let dfr = &mut dfumu[ti * m_eff..(ti + 1) * m_eff];
982 for (i, df) in dfr.iter_mut().enumerate() {
983 let er = &g.e[i * t..i * t + ti + 1];
984 let mut s = F::ZERO;
985 for (av, ev) in dar.iter().zip(er) {
986 s += *av * *ev;
987 }
988 *df = s;
989 }
990 }
991 let mut dfu = vec![F::ZERO; t * m_eff];
993 matmul_nt(&dfumu, &g.mu, &mut dfu, t, m_eff, m_eff);
994 let mut de = vec![F::ZERO; m_eff * t];
996 for ti in 0..t {
997 let dar = &da[ti * t..ti * t + ti + 1];
998 let fr = &g.fumu[ti * m_eff..(ti + 1) * m_eff];
999 for (i, &f) in fr.iter().enumerate() {
1000 if f.f64() == 0.0 {
1001 continue;
1002 }
1003 let der = &mut de[i * t..i * t + ti + 1];
1004 for (dev, av) in der.iter_mut().zip(dar) {
1005 *dev += f * *av;
1006 }
1007 }
1008 }
1009 let mut dq_l = vec![F::ZERO; m_eff * d];
1012 let mut dk_l = vec![F::ZERO; m_eff * d];
1013 for ti in 0..t {
1014 let qr = &q[ti * d..(ti + 1) * d];
1015 for i in 0..m_eff {
1016 let dlg = dfu[ti * m_eff + i] * g.fu[ti * m_eff + i] * scale;
1017 if dlg.f64() == 0.0 {
1018 continue;
1019 }
1020 let klr = &g.k_l[i * d..(i + 1) * d];
1021 for c in 0..d {
1022 dq[ti * d + c] += dlg * klr[c];
1023 }
1024 let dklr = &mut dk_l[i * d..(i + 1) * d];
1025 for c in 0..d {
1026 dklr[c] += dlg * qr[c];
1027 }
1028 }
1029 }
1030 for i in 0..m_eff {
1031 let qlr = &g.q_l[i * d..(i + 1) * d];
1032 for j in 0..t {
1033 let dlg = de[i * t + j] * g.e[i * t + j] * scale;
1034 if dlg.f64() == 0.0 {
1035 continue;
1036 }
1037 let kr = &k[j * d..(j + 1) * d];
1038 let dqlr = &mut dq_l[i * d..(i + 1) * d];
1039 for c in 0..d {
1040 dqlr[c] += dlg * kr[c];
1041 }
1042 for c in 0..d {
1043 dk[j * d + c] += dlg * qlr[c];
1044 }
1045 }
1046 }
1047 let tp = g.tp;
1051 seg_means_bwd(&dq_l, tp, d, m_eff, &mut dq[..tp * d]);
1052 seg_means_bwd(&dk_l, tp, d, m_eff, &mut dk[..tp * d]);
1053}
1054
1055pub fn ce_kl_position<F: Fp>(
1063 s_logits: &[F],
1064 t_logits: &[F],
1065 target: usize,
1066 kl_w: f64,
1067 inv_n: f64,
1068 dlogits: &mut [F],
1069) -> (f64, f64) {
1070 let vsz = s_logits.len();
1071 debug_assert_eq!(t_logits.len(), vsz);
1072 let mut smax = f64::NEG_INFINITY;
1074 let mut tmax = f64::NEG_INFINITY;
1075 for i in 0..vsz {
1076 smax = smax.max(s_logits[i].f64());
1077 tmax = tmax.max(t_logits[i].f64());
1078 }
1079 let mut ssum = 0f64;
1080 let mut tsum = 0f64;
1081 for i in 0..vsz {
1082 ssum += (s_logits[i].f64() - smax).exp();
1083 tsum += (t_logits[i].f64() - tmax).exp();
1084 }
1085 let slz = smax + ssum.ln();
1086 let tlz = tmax + tsum.ln();
1087 let ce = slz - s_logits[target].f64();
1088 let mut kl = 0f64;
1089 for i in 0..vsz {
1090 let ls = s_logits[i].f64() - slz;
1091 let lt = t_logits[i].f64() - tlz;
1092 let pt = lt.exp();
1093 let ps = ls.exp();
1094 if pt > 0.0 {
1095 kl += pt * (lt - ls);
1096 }
1097 let mut gd = (1.0 - kl_w) * ps + kl_w * (ps - pt);
1098 if i == target {
1099 gd -= 1.0 - kl_w;
1100 }
1101 dlogits[i] = F::fromf(gd * inv_n);
1102 }
1103 (ce, kl)
1104}
1105
1106pub struct GdnSeqCfg<'a> {
1123 pub nv: usize,
1124 pub nk: usize,
1125 pub dk: usize,
1126 pub dv: usize,
1127 pub kk: usize,
1128 pub rms_eps: f64,
1129 pub conv: &'a [f32],
1132 pub a_log: &'a [f32],
1134 pub dt_bias: &'a [f32],
1136 pub norm: &'a [f32],
1138}
1139
1140impl GdnSeqCfg<'_> {
1141 pub fn c_dim(&self) -> usize {
1142 2 * self.nk * self.dk + self.nv * self.dv
1143 }
1144}
1145
1146#[inline]
1147fn softplus_f<F: Fp>(x: F) -> F {
1148 if x.f64() > 20.0 {
1151 x
1152 } else {
1153 F::fromf(x.f64().exp().ln_1p())
1154 }
1155}
1156
1157#[inline]
1158fn sigmoid_f<F: Fp>(x: F) -> F {
1159 F::ONE / (F::ONE + (-x).exp())
1160}
1161
1162pub fn gdn_conv_fwd<F: Fp>(
1166 raw: &[F],
1167 t: usize,
1168 c_dim: usize,
1169 kk: usize,
1170 conv: &[f32],
1171 pre: &mut [F],
1172 cq: &mut [F],
1173) {
1174 for ti in 0..t {
1175 for c in 0..c_dim {
1176 let taps = &conv[c * kk..(c + 1) * kk];
1177 let mut acc = F::ZERO;
1178 for (j, &tap) in taps.iter().enumerate() {
1179 let p = ti as isize - (kk as isize - 1) + j as isize;
1181 if p >= 0 {
1182 acc += raw[p as usize * c_dim + c] * F::fromf(tap as f64);
1183 }
1184 }
1185 pre[ti * c_dim + c] = acc;
1186 cq[ti * c_dim + c] = silu(acc);
1187 }
1188 }
1189}
1190
1191pub fn gdn_conv_bwd<F: Fp>(
1193 pre: &[F],
1194 t: usize,
1195 c_dim: usize,
1196 kk: usize,
1197 conv: &[f32],
1198 dcq: &[F],
1199 draw: &mut [F],
1200) {
1201 for ti in 0..t {
1202 for c in 0..c_dim {
1203 let g = dcq[ti * c_dim + c];
1204 if g.f64() == 0.0 {
1205 continue;
1206 }
1207 let dp = g * silu_bwd(pre[ti * c_dim + c]);
1208 let taps = &conv[c * kk..(c + 1) * kk];
1209 for (j, &tap) in taps.iter().enumerate() {
1210 let p = ti as isize - (kk as isize - 1) + j as isize;
1211 if p >= 0 {
1212 draw[p as usize * c_dim + c] += dp * F::fromf(tap as f64);
1213 }
1214 }
1215 }
1216 }
1217}
1218
1219#[inline]
1222fn gdn_inv<F: Fp>(x: &[F], extra_scale: f64) -> (F, F) {
1223 let mut n2 = F::ZERO;
1224 for v in x {
1225 n2 += *v * *v;
1226 }
1227 let n2e = n2 + F::fromf(1e-6);
1228 let inv = F::ONE / (n2e.sqrt() * F::fromf(extra_scale));
1229 (inv, n2e)
1230}
1231
1232#[allow(clippy::too_many_arguments)]
1235pub fn gdn_group_fwd<F: Fp>(
1236 cq: &[F],
1237 z: &[F],
1238 a: &[F],
1239 b: &[F],
1240 t: usize,
1241 cfg: &GdnSeqCfg,
1242 ko: usize,
1243 out: &mut [F],
1244) {
1245 let (nv, nk, dk, dv) = (cfg.nv, cfg.nk, cfg.dk, cfg.dv);
1246 let c_dim = cfg.c_dim();
1247 let kd = nk * dk;
1248 let rep = nv / nk;
1249 let vd = nv * dv;
1250 let sqdk = (dk as f64).sqrt();
1251 for hh in 0..rep {
1252 let h = ko * rep + hh;
1253 let ea = F::fromf((cfg.a_log[h] as f64).exp());
1254 let mut s = vec![F::ZERO; dk * dv];
1255 let mut kv = vec![F::ZERO; dv];
1256 let mut o = vec![F::ZERO; dv];
1257 for ti in 0..t {
1258 let qrow = &cq[ti * c_dim + ko * dk..ti * c_dim + (ko + 1) * dk];
1259 let krow = &cq[ti * c_dim + kd + ko * dk..ti * c_dim + kd + (ko + 1) * dk];
1260 let vrow = &cq[ti * c_dim + 2 * kd + h * dv..ti * c_dim + 2 * kd + (h + 1) * dv];
1261 let (invq, _) = gdn_inv(qrow, sqdk);
1262 let (invk, _) = gdn_inv(krow, 1.0);
1263 let g = (-ea * softplus_f(a[ti * nv + h] + F::fromf(cfg.dt_bias[h] as f64))).exp();
1264 let beta = sigmoid_f(b[ti * nv + h]);
1265 for x in kv.iter_mut() {
1267 *x = F::ZERO;
1268 }
1269 for di in 0..dk {
1270 let kf = krow[di] * invk;
1271 let row = &mut s[di * dv..(di + 1) * dv];
1272 for dj in 0..dv {
1273 row[dj] *= g;
1274 kv[dj] += row[dj] * kf;
1275 }
1276 }
1277 for x in o.iter_mut() {
1278 *x = F::ZERO;
1279 }
1280 for di in 0..dk {
1281 let kf = krow[di] * invk;
1282 let qf = qrow[di] * invq;
1283 let row = &mut s[di * dv..(di + 1) * dv];
1284 for dj in 0..dv {
1285 row[dj] += kf * (vrow[dj] - kv[dj]) * beta;
1286 o[dj] += qf * row[dj];
1287 }
1288 }
1289 let mut ss = 0f64;
1291 for v in &o {
1292 ss += v.f64() * v.f64();
1293 }
1294 let inv = F::fromf(1.0 / (ss / dv as f64 + cfg.rms_eps).sqrt());
1295 for dj in 0..dv {
1296 let zv = z[ti * vd + h * dv + dj];
1297 out[ti * vd + h * dv + dj] =
1298 o[dj] * inv * F::fromf(cfg.norm[dj] as f64) * silu(zv);
1299 }
1300 }
1301 }
1302}
1303
1304#[allow(clippy::too_many_arguments)]
1308pub fn gdn_group_bwd<F: Fp>(
1309 cq: &[F],
1310 z: &[F],
1311 a: &[F],
1312 b: &[F],
1313 t: usize,
1314 cfg: &GdnSeqCfg,
1315 ko: usize,
1316 dout: &[F],
1317 dcq: &mut [F],
1318 dz: &mut [F],
1319 da: &mut [F],
1320 db: &mut [F],
1321) {
1322 let (nv, nk, dk, dv) = (cfg.nv, cfg.nk, cfg.dk, cfg.dv);
1323 let c_dim = cfg.c_dim();
1324 let kd = nk * dk;
1325 let rep = nv / nk;
1326 let vd = nv * dv;
1327 let sqdk = (dk as f64).sqrt();
1328 for hh in 0..rep {
1329 let h = ko * rep + hh;
1330 let ea = F::fromf((cfg.a_log[h] as f64).exp());
1331
1332 let mut s_hist = vec![F::ZERO; (t + 1) * dk * dv]; let mut kv_hist = vec![F::ZERO; t * dv];
1335 let mut o_hist = vec![F::ZERO; t * dv];
1336 let mut g_v = vec![F::ZERO; t];
1337 let mut beta_v = vec![F::ZERO; t];
1338 let mut sp_arg = vec![F::ZERO; t]; for ti in 0..t {
1340 let qrow = &cq[ti * c_dim + ko * dk..ti * c_dim + (ko + 1) * dk];
1341 let krow = &cq[ti * c_dim + kd + ko * dk..ti * c_dim + kd + (ko + 1) * dk];
1342 let vrow = &cq[ti * c_dim + 2 * kd + h * dv..ti * c_dim + 2 * kd + (h + 1) * dv];
1343 let (invq, _) = gdn_inv(qrow, sqdk);
1344 let (invk, _) = gdn_inv(krow, 1.0);
1345 let arg = a[ti * nv + h] + F::fromf(cfg.dt_bias[h] as f64);
1346 let g = (-ea * softplus_f(arg)).exp();
1347 let beta = sigmoid_f(b[ti * nv + h]);
1348 sp_arg[ti] = arg;
1349 g_v[ti] = g;
1350 beta_v[ti] = beta;
1351 let (prev, cur) = s_hist.split_at_mut((ti + 1) * dk * dv);
1352 let sp = &prev[ti * dk * dv..];
1353 let sn = &mut cur[..dk * dv];
1354 let kvr = &mut kv_hist[ti * dv..(ti + 1) * dv];
1355 for di in 0..dk {
1356 let kf = krow[di] * invk;
1357 for dj in 0..dv {
1358 let dec = sp[di * dv + dj] * g;
1359 sn[di * dv + dj] = dec;
1360 kvr[dj] += dec * kf;
1361 }
1362 }
1363 let or = &mut o_hist[ti * dv..(ti + 1) * dv];
1364 for di in 0..dk {
1365 let kf = krow[di] * invk;
1366 let qf = qrow[di] * invq;
1367 for dj in 0..dv {
1368 let sv = sn[di * dv + dj] + kf * (vrow[dj] - kvr[dj]) * beta_v[ti];
1369 sn[di * dv + dj] = sv;
1370 or[dj] += qf * sv;
1371 }
1372 }
1373 }
1374
1375 let mut ds = vec![F::ZERO; dk * dv];
1377 let mut do_o = vec![F::ZERO; dv];
1378 let mut du = vec![F::ZERO; dv];
1379 let mut dkv = vec![F::ZERO; dv];
1380 let mut dqh = vec![F::ZERO; dk];
1381 let mut dkh = vec![F::ZERO; dk];
1382 for ti in (0..t).rev() {
1383 let qrow = &cq[ti * c_dim + ko * dk..ti * c_dim + (ko + 1) * dk];
1384 let krow = &cq[ti * c_dim + kd + ko * dk..ti * c_dim + kd + (ko + 1) * dk];
1385 let vrow = &cq[ti * c_dim + 2 * kd + h * dv..ti * c_dim + 2 * kd + (h + 1) * dv];
1386 let (invq, nq2) = gdn_inv(qrow, sqdk);
1387 let (invk, nk2) = gdn_inv(krow, 1.0);
1388 let g = g_v[ti];
1389 let beta = beta_v[ti];
1390 let s_t = &s_hist[(ti + 1) * dk * dv..(ti + 2) * dk * dv];
1391 let s_prev = &s_hist[ti * dk * dv..(ti + 1) * dk * dv];
1392 let kvr = &kv_hist[ti * dv..(ti + 1) * dv];
1393 let or = &o_hist[ti * dv..(ti + 1) * dv];
1394
1395 let mut ss = 0f64;
1397 for v in or {
1398 ss += v.f64() * v.f64();
1399 }
1400 let inv = F::fromf(1.0 / (ss / dv as f64 + cfg.rms_eps).sqrt());
1401 let dofr = &dout[ti * vd + h * dv..ti * vd + (h + 1) * dv];
1402 let mut sdot = 0f64; for dj in 0..dv {
1405 let zv = z[ti * vd + h * dv + dj];
1406 let w = F::fromf(cfg.norm[dj] as f64);
1407 let weff = w * silu(zv);
1408 sdot += (dofr[dj] * weff * or[dj]).f64();
1409 dz[ti * vd + h * dv + dj] += dofr[dj] * or[dj] * inv * w * silu_bwd(zv);
1410 }
1411 let coef = F::fromf(sdot / dv as f64) * inv * inv * inv;
1412 for dj in 0..dv {
1413 let zv = z[ti * vd + h * dv + dj];
1414 let weff = F::fromf(cfg.norm[dj] as f64) * silu(zv);
1415 do_o[dj] = inv * weff * dofr[dj] - or[dj] * coef;
1416 }
1417
1418 for x in dqh.iter_mut() {
1420 *x = F::ZERO;
1421 }
1422 for di in 0..dk {
1423 let qf = qrow[di] * invq;
1424 let row = &s_t[di * dv..(di + 1) * dv];
1425 let dsr = &mut ds[di * dv..(di + 1) * dv];
1426 let mut acc = F::ZERO;
1427 for dj in 0..dv {
1428 dsr[dj] += qf * do_o[dj];
1429 acc += row[dj] * do_o[dj];
1430 }
1431 dqh[di] = acc;
1432 }
1433
1434 for x in du.iter_mut() {
1437 *x = F::ZERO;
1438 }
1439 for x in dkh.iter_mut() {
1440 *x = F::ZERO;
1441 }
1442 for di in 0..dk {
1443 let kf = krow[di] * invk;
1444 let dsr = &ds[di * dv..(di + 1) * dv];
1445 let mut acc = F::ZERO;
1446 for dj in 0..dv {
1447 du[dj] += dsr[dj] * kf;
1448 acc += dsr[dj] * (vrow[dj] - kvr[dj]) * beta;
1449 }
1450 dkh[di] = acc;
1451 }
1452 let mut dbeta = F::ZERO;
1453 for dj in 0..dv {
1454 dbeta += du[dj] * (vrow[dj] - kvr[dj]);
1455 dcq[ti * c_dim + 2 * kd + h * dv + dj] += beta * du[dj];
1457 dkv[dj] = -(beta * du[dj]);
1458 }
1459
1460 let mut dg = F::ZERO;
1465 for di in 0..dk {
1466 let kf = krow[di] * invk;
1467 let spr = &s_prev[di * dv..(di + 1) * dv];
1468 let dsr = &mut ds[di * dv..(di + 1) * dv];
1469 let mut acc = F::ZERO;
1470 for dj in 0..dv {
1471 let dspre = dsr[dj] + kf * dkv[dj];
1472 acc += (spr[dj] * g) * dkv[dj];
1473 dg += dspre * spr[dj];
1474 dsr[dj] = g * dspre;
1475 }
1476 dkh[di] += acc;
1477 }
1478
1479 let sig = sigmoid_f(sp_arg[ti]);
1481 da[ti * nv + h] += dg * g * (-ea) * sig;
1482 db[ti * nv + h] += dbeta * beta * (F::ONE - beta);
1483
1484 let mut qdot = F::ZERO;
1488 let mut kdot = F::ZERO;
1489 for di in 0..dk {
1490 qdot += dqh[di] * qrow[di];
1491 kdot += dkh[di] * krow[di];
1492 }
1493 for di in 0..dk {
1494 dcq[ti * c_dim + ko * dk + di] +=
1495 invq * dqh[di] - qrow[di] * qdot * invq / nq2;
1496 dcq[ti * c_dim + kd + ko * dk + di] +=
1497 invk * dkh[di] - krow[di] * kdot * invk / nk2;
1498 }
1499 }
1500 }
1501}
1502
1503pub fn gdn_seq_fwd<F: Fp>(
1507 qkv: &[F],
1508 z: &[F],
1509 a: &[F],
1510 b: &[F],
1511 t: usize,
1512 cfg: &GdnSeqCfg,
1513 out: &mut [F],
1514) {
1515 let c_dim = cfg.c_dim();
1516 let mut pre = vec![F::ZERO; t * c_dim];
1517 let mut cq = vec![F::ZERO; t * c_dim];
1518 gdn_conv_fwd(qkv, t, c_dim, cfg.kk, cfg.conv, &mut pre, &mut cq);
1519 for ko in 0..cfg.nk {
1520 gdn_group_fwd(&cq, z, a, b, t, cfg, ko, out);
1521 }
1522}
1523
1524#[allow(clippy::too_many_arguments)]
1527pub fn gdn_seq_bwd<F: Fp>(
1528 qkv: &[F],
1529 z: &[F],
1530 a: &[F],
1531 b: &[F],
1532 t: usize,
1533 cfg: &GdnSeqCfg,
1534 dout: &[F],
1535 dqkv: &mut [F],
1536 dz: &mut [F],
1537 da: &mut [F],
1538 db: &mut [F],
1539) {
1540 let c_dim = cfg.c_dim();
1541 let mut pre = vec![F::ZERO; t * c_dim];
1542 let mut cq = vec![F::ZERO; t * c_dim];
1543 gdn_conv_fwd(qkv, t, c_dim, cfg.kk, cfg.conv, &mut pre, &mut cq);
1544 let mut dcq = vec![F::ZERO; t * c_dim];
1545 for ko in 0..cfg.nk {
1546 gdn_group_bwd(&cq, z, a, b, t, cfg, ko, dout, &mut dcq, dz, da, db);
1547 }
1548 gdn_conv_bwd(&pre, t, c_dim, cfg.kk, cfg.conv, &dcq, dqkv);
1549}