pub struct KvParams {
pub kind: Kind,
pub heads: usize,
pub hd: usize,
pub theta: f64,
pub pre_rope: bool,
pub step: f64,
pub sink: usize,
pub sink_div: u32,
pub block: usize,
pub ar: bool,
pub gpu: bool,
pub lane_ch: usize,
}Expand description
Encoder settings.
Fields§
§kind: KindK or V.
heads: usizeNumber of KV heads.
hd: usizeHead dimension (even).
theta: f64RoPE base (HF-Llama half-split convention).
pre_rope: boolCode K before RoPE (undo, code, redo). Ignored for V.
step: f64Quantizer step in data units (max abs error is step / 2).
sink: usizeNumber of leading absolute positions treated as attention sinks.
sink_div: u32Step divisor for sink positions.
block: usizeTokens per independent block.
ar: boolFit a per-channel AR(1) predictor (else predict the channel mean).
gpu: boolGPU layout: integer reconstruction, one substream per (block, head).
lane_ch: usizeGPU layout: channels per substream (even, divides hd; 0 = hd).
Each block then has heads × hd / lane_ch substreams; lane g of a
head holds the RoPE pairs g·lane_ch/2 .. (channels c and
c + hd/2 together) so the decoder can rotate on write.
Implementations§
Source§impl KvParams
impl KvParams
Sourcepub fn new(kind: Kind, heads: usize, hd: usize, step: f64) -> Self
pub fn new(kind: Kind, heads: usize, hd: usize, step: f64) -> Self
Defaults for a cache with heads × hd per token (SmolLM2 RoPE base).
Examples found in repository?
35fn main() {
36 let args: Vec<String> = std::env::args().collect();
37 if args.len() < 4 {
38 usage()
39 }
40 match args[1].as_str() {
41 "encode" => {
42 let x = read_f32(&args[2]);
43 let shape: Vec<usize> = flag(&args, "--shape")
44 .unwrap_or_else(|| usage())
45 .split('x')
46 .map(|s| s.parse().unwrap())
47 .collect();
48 let (h, n, d) = (shape[0], shape[1], shape[2]);
49 let kind = match flag(&args, "--kind").as_deref() {
50 Some("k") => Kind::K,
51 Some("v") => Kind::V,
52 _ => usage(),
53 };
54 let mut p = KvParams::new(kind, h, d, 1.0);
55 p.pre_rope = !args.iter().any(|a| a == "--post");
56 p.ar = !args.iter().any(|a| a == "--noar");
57 p.gpu = args.iter().any(|a| a == "--gpu");
58 if let Some(v) = flag(&args, "--sink") {
59 p.sink = v.parse().unwrap();
60 }
61 if let Some(v) = flag(&args, "--sinkdiv") {
62 p.sink_div = v.parse().unwrap();
63 }
64 if let Some(v) = flag(&args, "--block") {
65 p.block = v.parse().unwrap();
66 }
67 if let Some(v) = flag(&args, "--theta") {
68 p.theta = v.parse().unwrap();
69 }
70 let t = Instant::now();
71 p.step = if let Some(r) = flag(&args, "--rmse") {
72 r.parse::<f64>().unwrap() * 12f64.sqrt()
73 } else if let Some(e) = flag(&args, "--maxabs") {
74 // pre-RoPE pair rotation can move a per-element error by sqrt(2)
75 let e: f64 = e.parse().unwrap();
76 if kind == Kind::K && p.pre_rope {
77 e * std::f64::consts::SQRT_2
78 } else {
79 2.0 * e
80 }
81 } else if let Some(b) = flag(&args, "--bpv") {
82 step_for_bpv(p.clone(), &x, n, b.parse().unwrap())
83 } else {
84 usage()
85 };
86 let pre: usize = flag(&args, "--prefill")
87 .map(|v| v.parse().unwrap())
88 .unwrap_or(n);
89 let slice = |t0: usize, t1: usize| -> Vec<f32> {
90 let mut v = Vec::with_capacity(h * (t1 - t0) * d);
91 for hh in 0..h {
92 v.extend_from_slice(&x[(hh * n + t0) * d..(hh * n + t1) * d]);
93 }
94 v
95 };
96 let mut e = KvEncoder::new(p.clone(), &slice(0, pre), pre);
97 let ta = Instant::now();
98 for t in pre..n {
99 e.append(&slice(t, t + 1), 1);
100 }
101 let append_s = ta.elapsed().as_secs_f64();
102 let bytes = e.to_bytes();
103 let enc = t.elapsed().as_secs_f64();
104 std::fs::write(&args[3], &bytes).unwrap();
105 println!(
106 "{{\"bytes\":{},\"bpv\":{},\"step\":{},\"encode_s\":{enc},\"append_s\":{append_s},\"appended\":{}}}",
107 bytes.len(),
108 8.0 * bytes.len() as f64 / x.len() as f64,
109 p.step,
110 n - pre
111 );
112 }
113 "decode" => {
114 let bytes = std::fs::read(&args[2]).unwrap();
115 let s = KvStream::parse(&bytes).unwrap();
116 let (t0, t1) = match flag(&args, "--range") {
117 Some(r) => {
118 let (a, b) = r.split_once(':').unwrap();
119 (a.parse().unwrap(), b.parse().unwrap())
120 }
121 None => (0, s.tokens),
122 };
123 let reps: usize = flag(&args, "--reps")
124 .map(|v| v.parse().unwrap())
125 .unwrap_or(1);
126 let t = Instant::now();
127 let mut y = Vec::new();
128 for _ in 0..reps {
129 y = s.decode_range(t0, t1);
130 }
131 let dec = t.elapsed().as_secs_f64() / reps as f64;
132 let out: Vec<u8> = y.iter().flat_map(|v| v.to_le_bytes()).collect();
133 std::fs::write(&args[3], out).unwrap();
134 println!(
135 "{{\"decode_s\":{dec},\"ns_per_value\":{}}}",
136 1e9 * dec / y.len().max(1) as f64
137 );
138 }
139 _ => usage(),
140 }
141}Sourcepub fn lane_width(&self) -> usize
pub fn lane_width(&self) -> usize
Channels per GPU substream.
Sourcepub fn lane_groups(&self) -> usize
pub fn lane_groups(&self) -> usize
GPU substreams per (block, head).