1use crate::abac::{BitModel, Decoder, Encoder, ONE};
41use crate::bitio::{ByteReader, ByteWriter, DecodeError};
42
43const MAGIC: &[u8; 4] = b"TKV1";
44const NCLASS: usize = 48;
45const NACT: usize = 3;
46const UBITS: usize = 24;
47
48#[derive(Clone, Copy, Debug, PartialEq, Eq)]
50pub enum Kind {
51 K,
53 V,
55}
56
57#[derive(Clone, Debug)]
59pub struct KvParams {
60 pub kind: Kind,
62 pub heads: usize,
64 pub hd: usize,
66 pub theta: f64,
68 pub pre_rope: bool,
70 pub step: f64,
72 pub sink: usize,
74 pub sink_div: u32,
76 pub block: usize,
78 pub ar: bool,
80 pub gpu: bool,
82 pub lane_ch: usize,
87}
88
89impl KvParams {
90 pub fn new(kind: Kind, heads: usize, hd: usize, step: f64) -> Self {
92 Self {
93 kind,
94 heads,
95 hd,
96 theta: 1e5,
97 pre_rope: true,
98 step,
99 sink: 4,
100 sink_div: 16,
101 block: 128,
102 ar: true,
103 gpu: false,
104 lane_ch: 0,
105 }
106 }
107 pub fn lane_width(&self) -> usize {
109 if self.lane_ch == 0 {
110 self.hd
111 } else {
112 self.lane_ch
113 }
114 }
115 pub fn lane_groups(&self) -> usize {
117 self.hd / self.lane_width()
118 }
119 fn rotated(&self) -> bool {
120 self.kind == Kind::K && self.pre_rope && !self.gpu
121 }
122 pub fn unit(&self) -> f32 {
124 (self.step / self.sink_div as f64) as f32
125 }
126}
127
128#[derive(Clone, Debug)]
130struct Stats {
131 mu: Vec<i64>,
133 rho: Vec<u8>,
135 class: Vec<u8>,
137}
138
139fn rope_token(x: &mut [f64], heads: usize, hd: usize, theta: f64, pos: usize, sign: f64) {
142 let half = hd / 2;
143 for i in 0..half {
144 let f = pos as f64 / theta.powf(2.0 * i as f64 / hd as f64);
145 let (s, c) = f.sin_cos();
146 let s = sign * s;
147 for h in 0..heads {
148 let a = x[h * hd + i];
149 let b = x[h * hd + half + i];
150 x[h * hd + i] = a * c - b * s;
151 x[h * hd + half + i] = b * c + a * s;
152 }
153 }
154}
155
156#[derive(Clone)]
159struct Ctx {
160 zero: BitModel,
161 unary: [BitModel; UBITS],
162 mant: [BitModel; UBITS],
163}
164
165impl Ctx {
166 fn prior(sd: f64) -> Self {
167 let b = (sd / std::f64::consts::SQRT_2).max(0.05);
168 let r = (-1.0 / b).exp();
169 let p = |x: f64| ((x * ONE as f64) as u32).clamp(64, ONE - 64);
170 let pz = 1.0 - (-0.5 / b).exp();
171 let mut unary = [BitModel::default(); UBITS];
172 let mut mant = [BitModel::default(); UBITS];
173 for i in 0..UBITS {
174 let ri = r.powf((1u64 << i.min(40)) as f64);
175 unary[i] = BitModel::new(p(ri));
176 let rh = if i == 0 {
177 0.5
178 } else {
179 r.powf((1u64 << (i - 1)) as f64)
180 };
181 mant[i] = BitModel::new(p(rh / (1.0 + rh)));
182 }
183 Self {
184 zero: BitModel::new(p(pz)),
185 unary,
186 mant,
187 }
188 }
189}
190
191fn class_sd(class: u8) -> f64 {
192 2f64.powf((class as f64 - 8.0) / 4.0)
193}
194
195fn fresh_models(heads: usize) -> Vec<Ctx> {
197 let mut v = Vec::with_capacity(heads * NCLASS * NACT);
198 for _ in 0..heads {
199 for c in 0..NCLASS {
200 for a in 0..NACT {
201 let sd = class_sd(c as u8) * [0.8, 1.0, 1.4][a];
203 v.push(Ctx::prior(sd));
204 }
205 }
206 }
207 v
208}
209
210fn put(e: &mut Encoder, m: &mut Ctx, q: i64) {
211 e.encode(q == 0, &mut m.zero);
212 if q == 0 {
213 return;
214 }
215 e.encode_p(q < 0, ONE / 2);
216 let w = q.unsigned_abs(); let k = 63 - w.leading_zeros() as usize;
218 for i in 0..k {
219 e.encode(true, &mut m.unary[i.min(UBITS - 1)]);
220 }
221 e.encode(false, &mut m.unary[k.min(UBITS - 1)]);
222 for i in (0..k).rev() {
223 let bit = (w >> i) & 1 == 1;
224 if i + 1 == k {
225 e.encode(bit, &mut m.mant[k]);
226 } else {
227 e.encode_p(bit, ONE / 2);
228 }
229 }
230}
231
232fn get(d: &mut Decoder, m: &mut Ctx) -> i64 {
233 if d.decode(&mut m.zero) {
234 return 0;
235 }
236 let neg = d.decode_p(ONE / 2);
237 let mut k = 0;
238 while k < 62 && d.decode(&mut m.unary[k.min(UBITS - 1)]) {
239 k += 1;
240 }
241 let mut w = 1u64;
242 for i in (0..k).rev() {
243 let bit = if i + 1 == k {
244 d.decode(&mut m.mant[k])
245 } else {
246 d.decode_p(ONE / 2)
247 };
248 w = (w << 1) | bit as u64;
249 }
250 if neg {
251 -(w as i64)
252 } else {
253 w as i64
254 }
255}
256
257struct Lane<'a> {
260 p: &'a KvParams,
261 s: &'a Stats,
262 step: &'a [f64],
263 prev: Vec<f64>,
264 act: Vec<u8>,
265 models: Vec<Ctx>,
266 first: bool,
267}
268
269impl<'a> Lane<'a> {
270 fn new(p: &'a KvParams, s: &'a Stats, step: &'a [f64]) -> Self {
271 let n = p.heads * p.hd;
272 Self {
273 p,
274 s,
275 step,
276 prev: vec![0.0; n],
277 act: vec![0; n],
278 models: fresh_models(p.heads),
279 first: true,
280 }
281 }
282 #[inline]
283 fn pred(&self, j: usize) -> f64 {
284 let mu = self.s.mu[j] as f64 * self.step[j];
285 if self.first {
286 mu
287 } else {
288 mu + self.s.rho[j] as f64 / 16.0 * (self.prev[j] - mu)
289 }
290 }
291 #[inline]
292 fn ctx(&self, j: usize) -> usize {
293 let h = j / self.p.hd;
294 (h * NCLASS + self.s.class[j] as usize) * NACT + self.act[j] as usize
295 }
296 #[inline]
297 fn set(&mut self, j: usize, q: i64, st: f64) -> f64 {
298 let y = self.pred(j) + q as f64 * st;
299 self.act[j] = q.unsigned_abs().min(2) as u8;
300 y
301 }
302}
303
304fn steps(p: &KvParams) -> Vec<f64> {
305 vec![p.step; p.heads * p.hd]
306}
307
308fn tok_step(p: &KvParams, pos: usize) -> f64 {
309 if pos < p.sink {
310 1.0 / p.sink_div as f64
311 } else {
312 1.0
313 }
314}
315
316#[inline]
318pub fn lane_chan(hd: usize, w: usize, g: usize, i: usize) -> usize {
319 let base = g * w / 2;
320 if i < w / 2 {
321 base + i
322 } else {
323 hd / 2 + base + i - w / 2
324 }
325}
326
327fn encode_block(
330 p: &KvParams,
331 s: &Stats,
332 step: &[f64],
333 y: &[f64],
334 pos0: usize,
335 n: usize,
336) -> Vec<u8> {
337 let m = p.heads * p.hd;
338 let mut lane = Lane::new(p, s, step);
339 let mut e = Encoder::new();
340 for t in 0..n {
341 let ts = tok_step(p, pos0 + t);
342 let mut row = vec![0.0; m];
343 for j in 0..m {
344 let st = step[j] * ts;
345 let q = ((y[t * m + j] - lane.pred(j)) / st).round() as i64;
346 let ci = lane.ctx(j);
347 put(&mut e, &mut lane.models[ci], q);
348 row[j] = lane.set(j, q, st);
349 }
350 lane.prev = row;
351 lane.first = false;
352 }
353 e.finish()
354}
355
356fn decode_block(
357 p: &KvParams,
358 s: &Stats,
359 step: &[f64],
360 bytes: &[u8],
361 pos0: usize,
362 n: usize,
363 out: &mut [f64],
364) {
365 let m = p.heads * p.hd;
366 let mut lane = Lane::new(p, s, step);
367 let mut d = Decoder::new(bytes);
368 for t in 0..n {
369 let ts = tok_step(p, pos0 + t);
370 for j in 0..m {
371 let st = step[j] * ts;
372 let ci = lane.ctx(j);
373 let q = get(&mut d, &mut lane.models[ci]);
374 out[t * m + j] = lane.set(j, q, st);
375 }
376 lane.prev.copy_from_slice(&out[t * m..(t + 1) * m]);
377 lane.first = false;
378 }
379}
380
381fn encode_block_gpu(p: &KvParams, s: &Stats, y: &[f64], pos0: usize, n: usize) -> Vec<Vec<u8>> {
383 let (h, d) = (p.heads, p.hd);
384 let m = h * d;
385 let u = p.unit() as f64;
386 let (w, ng) = (p.lane_width(), p.lane_groups());
387 (0..h * ng)
388 .map(|lane| {
389 let (hh, g) = (lane / ng, lane % ng);
390 let mut models = fresh_models(1);
391 let mut e = Encoder::new();
392 let mut prev = vec![0i64; w];
393 let mut act = vec![0u8; w];
394 for t in 0..n {
395 let ts = if pos0 + t < p.sink {
396 1
397 } else {
398 p.sink_div as i64
399 };
400 for c in 0..w {
401 let j = hh * d + lane_chan(d, w, g, c);
402 let mu = s.mu[j];
403 let pred = if t == 0 {
404 mu
405 } else {
406 mu + ((s.rho[j] as i64 * (prev[c] - mu)) >> 4)
407 };
408 let q = ((y[t * m + j] / u - pred as f64) / ts as f64).round() as i64;
409 let ci = s.class[j] as usize * NACT + act[c] as usize;
410 put(&mut e, &mut models[ci], q);
411 let r = pred + q * ts;
412 assert!(
413 r.abs() < 1 << 24,
414 "kv gpu layout: value out of i24 range (step too small)"
415 );
416 prev[c] = r;
417 act[c] = q.unsigned_abs().min(2) as u8;
418 }
419 }
420 e.finish()
421 })
422 .collect()
423}
424
425#[allow(clippy::too_many_arguments)]
429fn decode_lane_gpu(
430 p: &KvParams,
431 s: &Stats,
432 hh: usize,
433 g: usize,
434 bytes: &[u8],
435 pos0: usize,
436 n: usize,
437 out: &mut [f32],
438) {
439 let d = p.hd;
440 let u = p.unit();
441 let mut models = fresh_models(1);
442 let mut dec = Decoder::new(bytes);
443 let w = p.lane_width();
444 let mut prev = vec![0i64; w];
445 let mut act = vec![0u8; w];
446 for t in 0..n {
447 let ts = if pos0 + t < p.sink {
448 1
449 } else {
450 p.sink_div as i64
451 };
452 for c in 0..w {
453 let cc = lane_chan(d, w, g, c);
454 let j = hh * d + cc;
455 let mu = s.mu[j];
456 let pred = if t == 0 {
457 mu
458 } else {
459 mu + ((s.rho[j] as i64 * (prev[c] - mu)) >> 4)
460 };
461 let ci = s.class[j] as usize * NACT + act[c] as usize;
462 let q = get(&mut dec, &mut models[ci]);
463 let r = pred + q * ts;
464 prev[c] = r;
465 act[c] = q.unsigned_abs().min(2) as u8;
466 out[t * d + cc] = (r as i32 as f32) * u;
467 }
468 }
469}
470
471fn to_coded(p: &KvParams, x: &[f32], n: usize, pos0: usize) -> Vec<f64> {
474 let (h, d) = (p.heads, p.hd);
475 assert_eq!(x.len(), h * n * d, "shape mismatch");
476 let mut y = vec![0.0; n * h * d];
477 for t in 0..n {
478 for hh in 0..h {
479 for c in 0..d {
480 y[t * h * d + hh * d + c] = x[(hh * n + t) * d + c] as f64;
481 }
482 }
483 if p.rotated() {
484 rope_token(
485 &mut y[t * h * d..(t + 1) * h * d],
486 h,
487 d,
488 p.theta,
489 pos0 + t,
490 -1.0,
491 );
492 }
493 }
494 y
495}
496
497fn from_coded(p: &KvParams, y: &mut [f64], n: usize, pos0: usize) -> Vec<f32> {
498 let (h, d) = (p.heads, p.hd);
499 let mut x = vec![0f32; n * h * d];
500 for t in 0..n {
501 if p.rotated() {
502 rope_token(
503 &mut y[t * h * d..(t + 1) * h * d],
504 h,
505 d,
506 p.theta,
507 pos0 + t,
508 1.0,
509 );
510 }
511 for hh in 0..h {
512 for c in 0..d {
513 x[(hh * n + t) * d + c] = y[t * h * d + hh * d + c] as f32;
514 }
515 }
516 }
517 x
518}
519
520fn fit_stats(p: &KvParams, y: &[f64], n: usize, step: &[f64]) -> Stats {
521 let m = p.heads * p.hd;
522 let half = p.hd / 2;
523 let mut mean = vec![0.0; m];
524 for t in 0..n {
525 for j in 0..m {
526 mean[j] += y[t * m + j];
527 }
528 }
529 mean.iter_mut().for_each(|v| *v /= n.max(1) as f64);
530 let (mut c0, mut c1) = (vec![0.0; m], vec![0.0; m]);
531 for t in 0..n {
532 for j in 0..m {
533 let r = y[t * m + j] - mean[j];
534 c0[j] += r * r;
535 if t > 0 {
536 c1[j] += r * (y[(t - 1) * m + j] - mean[j]);
537 }
538 }
539 }
540 let mut rho = vec![0u8; m];
541 let mut var = vec![0.0; m];
542 for j in 0..m {
543 let a = if p.ar && c0[j] > 0.0 {
544 c1[j] / c0[j]
545 } else {
546 0.0
547 };
548 let a = (a * 16.0).round().clamp(0.0, 15.0);
549 rho[j] = a as u8;
550 let a = a / 16.0;
551 var[j] = (c0[j] / n.max(1) as f64) * (1.0 - a * a).max(0.05);
553 }
554 let mut class = vec![0u8; m];
555 for j in 0..m {
556 let pair = if p.kind == Kind::K {
557 j - (j % p.hd) + (j % p.hd + half) % p.hd
558 } else {
559 j
560 };
561 let v = if p.kind == Kind::K {
562 0.5 * (var[j] + var[pair])
563 } else {
564 var[j]
565 };
566 let r = v.sqrt() / step[j];
567 class[j] = ((4.0 * r.max(1e-9).log2()).round() + 8.0).clamp(0.0, NCLASS as f64 - 1.0) as u8;
568 }
569 let mu = if p.gpu {
570 let u = p.unit() as f64;
571 (0..m).map(|j| (mean[j] / u).round() as i64).collect()
572 } else {
573 (0..m).map(|j| (mean[j] / step[j]).round() as i64).collect()
574 };
575 Stats { mu, rho, class }
576}
577
578pub struct KvEncoder {
580 pub params: KvParams,
582 stats: Stats,
583 step: Vec<f64>,
584 blocks: Vec<Vec<u8>>,
585 gblocks: Vec<Vec<Vec<u8>>>,
587 tail: Vec<f64>,
589 tokens: usize,
590}
591
592impl KvEncoder {
593 pub fn new(params: KvParams, prefill: &[f32], n: usize) -> Self {
596 assert!(params.hd.is_multiple_of(2) && params.block > 0 && n > 0);
597 let step = steps(¶ms);
598 let y = to_coded(¶ms, prefill, n, 0);
599 let stats = fit_stats(¶ms, &y, n, &step);
600 if params.gpu {
601 assert!(
602 !(params.kind == Kind::K && params.pre_rope),
603 "gpu layout codes pre-RoPE K given by the caller (set pre_rope = false)"
604 );
605 }
606 let mut e = Self {
607 params,
608 stats,
609 step,
610 blocks: Vec::new(),
611 gblocks: Vec::new(),
612 tail: Vec::new(),
613 tokens: 0,
614 };
615 e.push_coded(y, n);
616 e
617 }
618
619 pub fn append(&mut self, x: &[f32], n: usize) {
621 let y = to_coded(&self.params, x, n, self.tokens);
622 self.push_coded(y, n);
623 }
624
625 fn push_coded(&mut self, y: Vec<f64>, n: usize) {
626 let m = self.params.heads * self.params.hd;
627 let b = self.params.block;
628 self.tail.extend_from_slice(&y);
629 self.tokens += n;
630 while self.tail.len() >= b * m {
631 let pos0 = self.sealed_blocks() * b;
632 if self.params.gpu {
633 let blk = encode_block_gpu(&self.params, &self.stats, &self.tail[..b * m], pos0, b);
634 self.gblocks.push(blk);
635 } else {
636 let blk = encode_block(
637 &self.params,
638 &self.stats,
639 &self.step,
640 &self.tail[..b * m],
641 pos0,
642 b,
643 );
644 self.blocks.push(blk);
645 }
646 self.tail.drain(..b * m);
647 }
648 }
649
650 pub fn tokens(&self) -> usize {
652 self.tokens
653 }
654
655 pub fn sealed_blocks(&self) -> usize {
657 self.blocks.len() + self.gblocks.len()
658 }
659
660 pub fn to_bytes(&self) -> Vec<u8> {
663 let p = &self.params;
664 let mut w = ByteWriter::new();
665 w.bytes(MAGIC);
666 w.u8(match p.kind {
667 Kind::K => 0,
668 Kind::V => 1,
669 } | (p.pre_rope as u8) << 1
670 | (p.ar as u8) << 2
671 | (p.gpu as u8) << 3
672 | ((p.gpu && p.lane_groups() > 1) as u8) << 4);
673 w.varint(p.heads as u64);
674 w.varint(p.hd as u64);
675 w.f64(p.theta);
676 w.f64(p.step);
677 w.varint(p.sink as u64);
678 w.varint(p.sink_div as u64);
679 w.varint(p.block as u64);
680 w.varint(self.tokens as u64);
681 if p.gpu && p.lane_groups() > 1 {
682 w.varint(p.lane_width() as u64);
683 }
684 for j in 0..p.heads * p.hd {
685 w.svarint(self.stats.mu[j]);
686 w.u8(self.stats.class[j] | if p.ar { 0 } else { 0x80 });
687 if p.ar {
688 w.u8(self.stats.rho[j]);
690 }
691 }
692 for blk in &self.blocks {
693 w.block(blk);
694 }
695 for blk in &self.gblocks {
696 blk.iter().for_each(|sub| w.block(sub));
697 }
698 let m = p.heads * p.hd;
699 let nt = self.tail.len() / m;
700 if nt > 0 {
701 let pos0 = self.sealed_blocks() * p.block;
702 if p.gpu {
703 encode_block_gpu(p, &self.stats, &self.tail, pos0, nt)
704 .iter()
705 .for_each(|sub| w.block(sub));
706 } else {
707 w.block(&encode_block(
708 p,
709 &self.stats,
710 &self.step,
711 &self.tail,
712 pos0,
713 nt,
714 ));
715 }
716 }
717 w.buf
718 }
719}
720
721pub struct KvStream<'a> {
723 pub params: KvParams,
725 pub tokens: usize,
727 stats: Stats,
728 blocks: Vec<&'a [u8]>,
729 offsets: Vec<usize>,
731}
732
733impl<'a> KvStream<'a> {
734 pub fn parse(bytes: &'a [u8]) -> Result<Self, DecodeError> {
736 let mut r = ByteReader::new(bytes);
737 if r.take(4)? != MAGIC {
738 return Err(DecodeError::Invalid("not a TKV1 stream"));
739 }
740 let f = r.u8()?;
741 let kind = if f & 1 == 0 { Kind::K } else { Kind::V };
742 let heads = r.varint()? as usize;
743 let hd = r.varint()? as usize;
744 let theta = r.f64()?;
745 let step = r.f64()?;
746 let sink = r.varint()? as usize;
747 let sink_div = r.varint()? as u32;
748 let block = r.varint()? as usize;
749 let tokens = r.varint()? as usize;
750 let lane_ch = if f & 16 != 0 { r.varint()? as usize } else { 0 };
751 if !hd.is_multiple_of(2) || block == 0 || heads == 0 || sink_div == 0 {
752 return Err(DecodeError::Invalid("bad header"));
753 }
754 if lane_ch != 0 && (!lane_ch.is_multiple_of(2) || !hd.is_multiple_of(lane_ch)) {
755 return Err(DecodeError::Invalid("bad lane width"));
756 }
757 let ar = f & 4 != 0;
758 let gpu = f & 8 != 0;
759 let params = KvParams {
760 kind,
761 heads,
762 hd,
763 theta,
764 pre_rope: f & 2 != 0,
765 step,
766 sink,
767 sink_div,
768 block,
769 ar,
770 gpu,
771 lane_ch,
772 };
773 let m = heads * hd;
774 let (mut mu, mut rho, mut class) = (
775 Vec::with_capacity(m),
776 Vec::with_capacity(m),
777 Vec::with_capacity(m),
778 );
779 for _ in 0..m {
780 mu.push(r.svarint()?);
781 class.push(r.u8()? & 0x7f);
782 rho.push(if ar { r.u8()?.min(15) } else { 0 });
783 }
784 if class.iter().any(|&c| c as usize >= NCLASS) {
785 return Err(DecodeError::Invalid("class out of range"));
786 }
787 let nb = tokens.div_ceil(block) * if gpu { heads * params.lane_groups() } else { 1 };
788 let mut blocks = Vec::with_capacity(nb);
789 let mut offsets = Vec::with_capacity(nb);
790 for _ in 0..nb {
791 let b = r.block()?;
792 offsets.push(b.as_ptr() as usize - bytes.as_ptr() as usize);
793 blocks.push(b);
794 }
795 if gpu && mu.iter().any(|&v| v.abs() >= 1 << 24) {
796 return Err(DecodeError::Invalid("mean out of range"));
797 }
798 Ok(Self {
799 params,
800 tokens,
801 stats: Stats { mu, rho, class },
802 blocks,
803 offsets,
804 })
805 }
806
807 pub fn decode_range(&self, t0: usize, t1: usize) -> Vec<f32> {
810 assert!(t0 <= t1 && t1 <= self.tokens);
811 let p = &self.params;
812 if p.gpu {
813 return self.decode_range_gpu(t0, t1);
814 }
815 let m = p.heads * p.hd;
816 let step = steps(p);
817 let (b0, b1) = (t0 / p.block, t1.div_ceil(p.block));
818 let mut y = Vec::with_capacity((b1 - b0) * p.block * m);
819 let mut buf = vec![0.0; p.block * m];
820 for b in b0..b1 {
821 let pos0 = b * p.block;
822 let n = p.block.min(self.tokens - pos0);
823 decode_block(
824 p,
825 &self.stats,
826 &step,
827 self.blocks[b],
828 pos0,
829 n,
830 &mut buf[..n * m],
831 );
832 y.extend_from_slice(&buf[..n * m]);
833 }
834 let off = t0 - b0 * p.block;
835 let mut sel = y[off * m..(off + t1 - t0) * m].to_vec();
836 from_coded(p, &mut sel, t1 - t0, t0)
837 }
838
839 fn decode_range_gpu(&self, t0: usize, t1: usize) -> Vec<f32> {
840 let p = &self.params;
841 let (h, d, nt) = (p.heads, p.hd, t1 - t0);
842 let mut x = vec![0f32; h * nt * d];
843 let mut buf = vec![0f32; p.block * d];
844 for b in t0 / p.block..t1.div_ceil(p.block) {
845 let pos0 = b * p.block;
846 let n = p.block.min(self.tokens - pos0);
847 let ng = p.lane_groups();
848 for hh in 0..h {
849 for g in 0..ng {
850 decode_lane_gpu(
851 p,
852 &self.stats,
853 hh,
854 g,
855 self.blocks[(b * h + hh) * ng + g],
856 pos0,
857 n,
858 &mut buf[..n * d],
859 );
860 }
861 for t in pos0.max(t0)..(pos0 + n).min(t1) {
862 let dst = (hh * nt + t - t0) * d;
863 x[dst..dst + d].copy_from_slice(&buf[(t - pos0) * d..(t - pos0 + 1) * d]);
864 }
865 }
866 }
867 x
868 }
869
870 pub fn gpu_tables(&self) -> Option<GpuTables> {
874 let p = &self.params;
875 if !p.gpu {
876 return None;
877 }
878 let ng = p.lane_groups();
879 let lanes = (0..self.blocks.len())
880 .map(|i| {
881 let (b, hh, g) = (i / (p.heads * ng), i / ng % p.heads, i % ng);
882 let pos0 = b * p.block;
883 [
884 self.offsets[i] as u32,
885 self.blocks[i].len() as u32,
886 (pos0) as u32,
887 p.block.min(self.tokens - pos0) as u32,
888 hh as u32,
889 g as u32,
890 ]
891 })
892 .collect();
893 Some(GpuTables {
894 mu: self.stats.mu.iter().map(|&v| v as i32).collect(),
895 rho: self.stats.rho.iter().map(|&v| v as u32).collect(),
896 class: self.stats.class.iter().map(|&v| v as u32).collect(),
897 lanes,
898 })
899 }
900}
901
902pub struct GpuTables {
904 pub mu: Vec<i32>,
906 pub rho: Vec<u32>,
908 pub class: Vec<u32>,
910 pub lanes: Vec<[u32; 6]>,
913}
914
915pub fn gpu_prior_table() -> Vec<u32> {
919 let mut v = Vec::with_capacity(NCLASS * NACT * (1 + 2 * UBITS));
920 for c in fresh_models(1) {
921 for m in std::iter::once(&c.zero)
922 .chain(c.unary.iter())
923 .chain(c.mant.iter())
924 {
925 v.push(m.packed());
926 }
927 }
928 v
929}
930
931pub const GPU_CTX_MODELS: usize = 1 + 2 * UBITS;
933pub const GPU_CTXS: usize = NCLASS * NACT;
935
936pub fn encode(params: KvParams, x: &[f32], n: usize) -> Vec<u8> {
938 KvEncoder::new(params, x, n).to_bytes()
939}
940
941pub fn decode(bytes: &[u8]) -> Result<(KvParams, usize, Vec<f32>), DecodeError> {
943 let s = KvStream::parse(bytes)?;
944 let x = s.decode_range(0, s.tokens);
945 Ok((s.params, s.tokens, x))
946}
947
948pub fn step_for_bpv(mut params: KvParams, x: &[f32], n: usize, bpv: f64) -> f64 {
951 let vals = x.len() as f64;
952 let rms = (x.iter().map(|&v| v as f64 * v as f64).sum::<f64>() / vals)
953 .sqrt()
954 .max(1e-30);
955 let (mut lo, mut hi) = ((rms * 1e-5).ln(), (rms * 10.0).ln());
956 for _ in 0..30 {
957 let mid = 0.5 * (lo + hi);
958 params.step = mid.exp();
959 let b = 8.0 * encode(params.clone(), x, n).len() as f64 / vals;
960 if b > bpv {
961 lo = mid;
962 } else {
963 hi = mid;
964 }
965 }
966 hi.exp()
967}
968
969#[cfg(test)]
970mod tests {
971 use super::*;
972
973 fn synth(h: usize, n: usize, d: usize, seed: u64) -> Vec<f32> {
974 let mut s = seed;
975 let mut rnd = || {
976 s = s
977 .wrapping_mul(6364136223846793005)
978 .wrapping_add(1442695040888963407);
979 ((s >> 11) as f64 / (1u64 << 53) as f64) - 0.5
980 };
981 let mut x = vec![0f32; h * n * d];
982 for hh in 0..h {
983 for c in 0..d {
984 let mu = 3.0 * rnd();
985 let mut prev = 0.0;
986 for t in 0..n {
987 prev = 0.5 * prev + rnd() * (1.0 + c as f64 / 16.0);
988 x[(hh * n + t) * d + c] = (mu + prev) as f32;
989 }
990 }
991 }
992 x
993 }
994
995 fn pre(p: &KvParams, x: &[f32], n: usize) -> Vec<f64> {
996 to_coded(p, x, n, 0)
997 }
998
999 #[test]
1000 fn error_bound_and_append_and_ranges() {
1001 let (h, n, d) = (3, 300, 16);
1002 for kind in [Kind::K, Kind::V] {
1003 let x = synth(h, n, d, 7);
1004 let mut p = KvParams::new(kind, h, d, 0.05);
1005 p.block = 32;
1006 let one = encode(p.clone(), &x, n);
1008 let (_, nt, y) = decode(&one).unwrap();
1009 assert_eq!(nt, n);
1010 let (a, b) = (pre(&p, &x, n), pre(&p, &y, n));
1011 for t in 0..n {
1012 let lim = p.step / 2.0 * tok_step(&p, t) + 1e-4;
1013 for j in 0..h * d {
1014 let e = (a[t * h * d + j] - b[t * h * d + j]).abs();
1015 assert!(e <= lim, "{kind:?} t={t} j={j} err {e} > {lim}");
1016 }
1017 }
1018 let slice = |t0: usize, t1: usize| -> Vec<f32> {
1021 let mut v = Vec::new();
1022 for hh in 0..h {
1023 v.extend_from_slice(&x[(hh * n + t0) * d..(hh * n + t1) * d]);
1024 }
1025 v
1026 };
1027 let mut e = KvEncoder::new(p.clone(), &slice(0, 100), 100);
1028 let mut sealed: Vec<Vec<u8>> = Vec::new();
1029 for t in 100..n {
1030 e.append(&slice(t, t + 1), 1);
1031 if e.sealed_blocks() > sealed.len() {
1032 sealed = e.blocks.clone();
1033 }
1034 assert_eq!(&e.blocks[..sealed.len()], &sealed[..]);
1035 }
1036 let bytes = e.to_bytes();
1037 let s = KvStream::parse(&bytes).unwrap();
1038 let full = s.decode_range(0, n);
1039 for (t0, t1) in [(0, 1), (31, 33), (100, 300), (250, 300), (64, 64)] {
1040 let r = s.decode_range(t0, t1);
1041 for hh in 0..h {
1042 for t in t0..t1 {
1043 for c in 0..d {
1044 assert_eq!(
1045 r[(hh * (t1 - t0) + t - t0) * d + c],
1046 full[(hh * n + t) * d + c]
1047 );
1048 }
1049 }
1050 }
1051 }
1052 let (a, b) = (pre(&p, &x, n), pre(&p, &full, n));
1053 let me = a
1054 .iter()
1055 .zip(&b)
1056 .map(|(u, v)| (u - v).abs())
1057 .fold(0.0, f64::max);
1058 assert!(me <= p.step / 2.0 + 1e-4);
1059 }
1060 }
1061
1062 #[test]
1063 fn gpu_layout_bound_ranges_append() {
1064 let (h, n, d) = (3, 300, 16);
1065 for (kind, lc) in [(Kind::K, 0), (Kind::V, 0), (Kind::K, 4), (Kind::V, 2)] {
1066 let x = synth(h, n, d, 11);
1067 let mut p = KvParams::new(kind, h, d, 0.05);
1068 p.block = 32;
1069 p.pre_rope = false;
1070 p.gpu = true;
1071 p.lane_ch = lc;
1072 let bytes = encode(p.clone(), &x, n);
1073 let s = KvStream::parse(&bytes).unwrap();
1074 let y = s.decode_range(0, n);
1075 for hh in 0..h {
1076 for t in 0..n {
1077 let lim = p.step / 2.0 * tok_step(&p, t) + 1e-5;
1078 for c in 0..d {
1079 let i = (hh * n + t) * d + c;
1080 assert!(((x[i] - y[i]) as f64).abs() <= lim, "{kind:?} t={t} c={c}");
1081 }
1082 }
1083 }
1084 for (t0, t1) in [(0, 1), (31, 33), (250, 300)] {
1085 let r = s.decode_range(t0, t1);
1086 for hh in 0..h {
1087 for t in t0..t1 {
1088 assert_eq!(
1089 r[(hh * (t1 - t0) + t - t0) * d..][..d],
1090 y[(hh * n + t) * d..][..d]
1091 );
1092 }
1093 }
1094 }
1095 let tb = s.gpu_tables().unwrap();
1096 assert_eq!(tb.lanes.len(), n.div_ceil(32) * h * p.lane_groups());
1097 }
1098 }
1099
1100 #[test]
1101 fn rate_target() {
1102 let (h, n, d) = (2, 256, 32);
1103 let x = synth(h, n, d, 3);
1104 let p = KvParams::new(Kind::V, h, d, 1.0);
1105 let st = step_for_bpv(p.clone(), &x, n, 3.0);
1106 let b = 8.0 * encode(KvParams { step: st, ..p }, &x, n).len() as f64 / x.len() as f64;
1107 assert!(b <= 3.0 && b > 2.7, "bpv {b}");
1108 }
1109}