1pub fn layer_norm(x: &[f32], d: usize, w: &[f32], b: Option<&[f32]>, eps: f64, out: &mut [f32]) {
14 assert_eq!(x.len(), out.len());
15 assert_eq!(w.len(), d);
16 if d == 0 {
17 return;
18 }
19 for (row, o) in x.chunks_exact(d).zip(out.chunks_exact_mut(d)) {
20 let mean = row.iter().map(|&v| f64::from(v)).sum::<f64>() / d as f64;
21 let var = row.iter().map(|&v| (f64::from(v) - mean).powi(2)).sum::<f64>() / d as f64;
22 let rstd = 1.0 / (var + eps).sqrt();
23 for i in 0..d {
24 let n = ((f64::from(row[i]) - mean) * rstd) as f32;
25 o[i] = match b {
26 Some(b) => n * w[i] + b[i],
27 None => n * w[i],
28 };
29 }
30 }
31}
32
33#[inline]
41#[must_use]
42pub fn gelu(x: f32) -> f32 {
43 let q = erfc_sqrt_half(x.abs());
44 let p = if x >= 0.0 { 1.0 - 0.5 * q } else { 0.5 * q };
45 if x < -13.0 { -0.0 } else { x * p }
47}
48
49#[inline]
55fn erfc_sqrt_half(a: f32) -> f32 {
56 let a = a.min(13.0);
57 let k = 1.0 / (1.0 + 0.5 * std::f32::consts::FRAC_1_SQRT_2 * a);
58 let mut r = 0.170_872_77f32;
59 for c in [
60 -0.822_152_23,
61 1.488_515_9,
62 -1.135_204,
63 0.278_868_07,
64 -0.186_288_06,
65 0.096_784_18,
66 0.374_091_96,
67 1.000_023_7,
68 -1.265_512_2,
69 ] {
70 r = r * k + c;
71 }
72 let ah = f32::from_bits(a.to_bits() & 0xffff_f000);
73 k * exp(-0.5 * ah * ah, 0.5 * (ah - a) * (ah + a) + r)
74}
75
76#[inline]
79#[must_use]
80pub fn exp_neg(y: f32) -> f32 {
81 exp(y.max(-87.0), 0.0)
82}
83
84#[inline]
90fn exp(hi: f32, lo: f32) -> f32 {
91 const MAGIC: f32 = 12_582_912.0; let n = ((hi + lo) * std::f32::consts::LOG2_E + MAGIC) - MAGIC;
93 let r = hi - n * 0.693_359_4;
95 let r = r + n * 2.121_944_4e-4 + lo;
96 let mut e = 1.0 / 720.0f32;
97 for c in [1.0 / 120.0, 1.0 / 24.0, 1.0 / 6.0, 0.5, 1.0, 1.0] {
98 e = e * r + c;
99 }
100 e * f32::from_bits(((n as i32 + 127) as u32) << 23)
101}
102
103pub fn geglu(u: &[f32], inter: usize, out: &mut [f32]) {
110 assert_eq!(u.len(), 2 * out.len());
111 if inter == 0 {
112 return;
113 }
114 for (row, o) in u.chunks_exact(2 * inter).zip(out.chunks_exact_mut(inter)) {
115 let (a, g) = row.split_at(inter);
116 o.iter_mut().zip(a).zip(g).for_each(|((o, &a), &g)| *o = gelu(a) * g);
117 }
118}
119
120pub fn add(x: &mut [f32], y: &[f32]) {
126 assert_eq!(x.len(), y.len());
127 x.iter_mut().zip(y).for_each(|(a, b)| *a += b);
128}
129
130#[derive(Debug, Clone)]
132pub struct Rope {
133 half: usize,
134 cos: Vec<f32>,
135 sin: Vec<f32>,
136}
137
138impl Rope {
139 #[must_use]
145 pub fn new(theta: f64, dim: usize, len: usize) -> Self {
146 assert!(dim.is_multiple_of(2));
147 let half = dim / 2;
148 let inv: Vec<f32> = (0..half)
150 .map(|i| {
151 let e = (2 * i) as f32 / dim as f32;
152 1.0 / (theta.powf(f64::from(e)) as f32)
153 })
154 .collect();
155 let mut cos = Vec::with_capacity(len * half);
156 let mut sin = Vec::with_capacity(len * half);
157 for p in 0..len {
158 for &f in &inv {
159 let a = f64::from(p as f32 * f);
160 cos.push(a.cos() as f32);
161 sin.push(a.sin() as f32);
162 }
163 }
164 Self { half, cos, sin }
165 }
166
167 #[must_use]
169 pub fn len(&self) -> usize {
170 self.cos.len() / self.half.max(1)
171 }
172
173 #[must_use]
175 pub fn is_empty(&self) -> bool {
176 self.cos.is_empty()
177 }
178
179 #[inline]
185 pub fn apply(&self, x: &mut [f32], pos: usize) {
186 let h = self.half;
187 assert_eq!(x.len(), 2 * h);
188 let c = &self.cos[pos * h..(pos + 1) * h];
189 let s = &self.sin[pos * h..(pos + 1) * h];
190 for i in 0..h {
191 let (a, b) = (x[i], x[i + h]);
192 x[i] = a * c[i] + -b * s[i];
194 x[i + h] = b * c[i] + a * s[i];
195 }
196 }
197}
198
199#[cfg(test)]
200mod tests {
201 use super::*;
202 use crate::testing::{Rng, close};
203
204 #[test]
205 fn layer_norm_against_the_formula() {
206 let mut rng = Rng(3);
207 for (rows, d) in [(0, 4), (1, 1), (3, 7), (2, 1024)] {
208 let x = rng.vec(rows * d);
209 let w = rng.vec(d);
210 let b = rng.vec(d);
211 let mut out = vec![0f32; rows * d];
212 layer_norm(&x, d, &w, Some(&b), 1e-5, &mut out);
213 let mut want = vec![0f32; rows * d];
214 for r in 0..rows {
215 let row = &x[r * d..(r + 1) * d];
216 let mean: f32 = row.iter().sum::<f32>() / d as f32;
217 let var: f32 = row.iter().map(|v| (v - mean) * (v - mean)).sum::<f32>() / d as f32;
218 for i in 0..d {
219 want[r * d + i] = (row[i] - mean) / (var + 1e-5).sqrt() * w[i] + b[i];
220 }
221 }
222 close(&out, &want, 1e-4, "layer_norm");
223 }
224 }
225
226 #[test]
227 fn gelu_values() {
228 let cases = [
230 (0.0, 0.0),
231 (1.0, 0.841_344_746_068_542_9),
232 (-1.0, -0.158_655_253_931_457_07),
233 (3.0, 2.995_950_305_905_11),
234 (-6.0, -5.919_525_869_479_969e-9),
235 ];
236 for (x, want) in cases {
237 let got = gelu(x as f32);
238 assert!((f64::from(got) - want).abs() <= want.abs() * 1e-6 + 1e-12, "{x}: {got}");
239 }
240 let mut out = [0f32; 2];
241 geglu(&[1.0, -1.0, 2.0, 3.0], 2, &mut out);
242 close(&out, &[gelu(1.0) * 2.0, gelu(-1.0) * 3.0], 0.0, "geglu");
243 }
244
245 #[test]
246 fn gelu_matches_f64_erf_over_the_range() {
247 let (mut worst, mut at) = (0f64, 0f32);
250 let mut x = -12f32;
251 while x < 12.0 {
252 let want =
253 0.5 * f64::from(x) * libm::erfc(-f64::from(x) * std::f64::consts::FRAC_1_SQRT_2);
254 let got = f64::from(gelu(x));
255 let err = (got - want).abs() / want.abs().max(1e-30);
256 let err = if x < -8.0 { (got - want).abs() * 1e6 } else { err };
257 if err > worst {
258 (worst, at) = (err, x);
259 }
260 x += 1.0 / 4096.0 + x.abs() * 1e-4;
261 }
262 assert!(worst < 6e-7, "worst {worst:e} at {at}");
263 for x in [13.0, 20.0, 100.0, 1e30, f32::MAX, f32::INFINITY] {
264 assert_eq!(gelu(x).to_bits(), x.to_bits(), "{x}");
265 let g = gelu(-x);
266 assert!(g <= 0.0 && g > -1e-30, "{}: {g}", -x);
267 }
268 assert!(gelu(f32::NAN).is_nan());
269 }
270
271 #[test]
272 fn rope_rotates() {
273 let r = Rope::new(10000.0, 4, 3);
274 assert_eq!(r.len(), 3);
275 let mut x = [1.0, 2.0, 3.0, 4.0];
276 r.apply(&mut x, 0);
277 close(&x, &[1.0, 2.0, 3.0, 4.0], 0.0, "position 0");
278 let mut x = [1.0, 2.0, 3.0, 4.0];
280 r.apply(&mut x, 1);
281 let (c0, s0, c1, s1) = (1f32.cos(), 1f32.sin(), 0.01f32.cos(), 0.01f32.sin());
282 close(
283 &x,
284 &[c0 - 3.0 * s0, 2.0 * c1 - 4.0 * s1, 3.0 * c0 + s0, 4.0 * c1 + 2.0 * s1],
285 1e-6,
286 "rope",
287 );
288 }
289}