1use anyhow::{Result, bail};
30
31use super::binding::{KdaTensorSource, RawTensor};
32use super::tp::{KdaShard, KdaTensorPlan, KdaTpPlan};
33
34fn plan_name(checkpoint_name: &str) -> &str {
39 let n = checkpoint_name
40 .strip_prefix("self_attn.")
41 .unwrap_or(checkpoint_name);
42 n.strip_suffix(".weight").unwrap_or(n)
43}
44
45pub fn shard_bytes(plan: &KdaTensorPlan, full: &[u8]) -> Result<Vec<u8>> {
50 let e = plan.elem_bytes;
51 let expect = plan.full_rows * plan.full_row_elems * e;
52 if full.len() != expect {
53 bail!(
54 "{}: {} B on disk, the plan's full shape [{}, {}] x {e} B implies {expect} B",
55 plan.name,
56 full.len(),
57 plan.full_rows,
58 plan.full_row_elems
59 );
60 }
61 Ok(match plan.kind {
62 KdaShard::Replicated => full.to_vec(),
63 KdaShard::HeadRows | KdaShard::ChannelRows => {
65 let row = plan.full_row_elems * e;
66 let start = plan.src_row_offset * row;
67 full[start..start + plan.local_rows * row].to_vec()
68 }
69 KdaShard::ChannelCols => {
71 let row = plan.full_row_elems * e;
72 let lo = plan.src_col_offset * e;
73 let width = plan.local_row_elems * e;
74 let mut out = Vec::with_capacity(plan.local_rows * width);
75 for r in 0..plan.local_rows {
76 let base = r * row + lo;
77 out.extend_from_slice(&full[base..base + width]);
78 }
79 out
80 }
81 })
82}
83
84fn local_shape(plan: &KdaTensorPlan, disk_shape: &[usize]) -> Vec<usize> {
89 let mut s = disk_shape.to_vec();
90 match plan.kind {
91 KdaShard::Replicated => {}
92 KdaShard::HeadRows | KdaShard::ChannelRows => {
93 if let Some(first) = s.first_mut() {
94 *first = plan.local_rows;
95 }
96 }
97 KdaShard::ChannelCols => {
98 if let Some(last) = s.last_mut() {
99 *last = plan.local_row_elems;
100 }
101 }
102 }
103 s
104}
105
106pub struct KdaShardedSource<'a> {
110 inner: &'a dyn KdaTensorSource,
111 plan: &'a KdaTpPlan,
112 sliced: std::collections::BTreeMap<String, (super::binding::KdaDtype, Vec<usize>, Vec<u8>)>,
115}
116
117impl<'a> KdaShardedSource<'a> {
118 pub fn new(inner: &'a dyn KdaTensorSource, plan: &'a KdaTpPlan) -> Result<Self> {
119 let mut sliced = std::collections::BTreeMap::new();
120 for name in inner.names() {
121 let Some(p) = plan.get(plan_name(&name)) else {
125 continue;
126 };
127 let Some(t) = inner.get(&name) else { continue };
128 sliced.insert(
129 name.clone(),
130 (t.dtype, local_shape(p, &t.shape), shard_bytes(p, t.bytes)?),
131 );
132 }
133 Ok(Self {
134 inner,
135 plan,
136 sliced,
137 })
138 }
139
140 pub fn plan(&self) -> &KdaTpPlan {
141 self.plan
142 }
143}
144
145impl KdaTensorSource for KdaShardedSource<'_> {
146 fn get(&self, name: &str) -> Option<RawTensor<'_>> {
147 match self.sliced.get(name) {
148 Some((dtype, shape, bytes)) => Some(RawTensor {
149 dtype: *dtype,
150 shape: shape.clone(),
151 bytes,
152 }),
153 None => self.inner.get(name),
156 }
157 }
158
159 fn names(&self) -> Vec<String> {
160 self.inner.names()
161 }
162}
163
164#[cfg(test)]
165mod tests {
166 use super::super::binding::KdaDtype;
167 use super::*;
168
169 fn plan(rank: usize) -> KdaTpPlan {
171 KdaTpPlan::new(rank, 2, 4096, 128, 64, 4, 128).unwrap()
172 }
173
174 #[test]
175 fn plan_names_strip_the_prefix_but_not_a_missing_suffix() {
176 assert_eq!(plan_name("self_attn.q_proj.weight"), "q_proj");
177 assert_eq!(plan_name("self_attn.q_conv1d.weight"), "q_conv1d");
178 assert_eq!(plan_name("self_attn.A_log"), "A_log");
180 assert_eq!(plan_name("self_attn.dt_bias"), "dt_bias");
181 for t in &plan(0).tensors {
183 let candidates = [
184 format!("self_attn.{}.weight", t.name),
185 format!("self_attn.{}", t.name),
186 ];
187 assert!(
188 candidates.iter().any(|c| plan_name(c) == t.name),
189 "plan entry {} is unreachable from a checkpoint name",
190 t.name
191 );
192 }
193 }
194
195 #[test]
197 fn channel_rows_partition_the_tensor() {
198 let p = KdaTpPlan::new(0, 2, 4, 64, 4, 2, 4).unwrap();
202 let q = p.get("q_proj").unwrap().clone();
203 assert_eq!(q.kind, KdaShard::ChannelRows);
204 let full: Vec<u8> = (0..=255u8).flat_map(|r| [r; 8]).collect();
206
207 let r0 = shard_bytes(&q, &full).unwrap();
208 let mut q1 = q.clone();
209 q1.src_row_offset = q.local_rows;
210 let r1 = shard_bytes(&q1, &full).unwrap();
211
212 assert_eq!(
213 r0.len() + r1.len(),
214 full.len(),
215 "the two ranks partition it"
216 );
217 let mut rejoined = r0.clone();
218 rejoined.extend_from_slice(&r1);
219 assert_eq!(rejoined, full, "and rejoin to the original, in order");
220 assert!(r0.iter().all(|b| *b < 128), "rank 0 keeps the low rows");
221 assert!(r1.iter().all(|b| *b >= 128), "rank 1 keeps the high rows");
222 }
223
224 #[test]
227 fn o_proj_is_column_sliced_not_row_sliced() {
228 let p = KdaTpPlan::new(1, 2, 4, 64, 4, 2, 4).unwrap();
229 let o = p.get("o_proj").unwrap();
230 assert_eq!(o.kind, KdaShard::ChannelCols);
231 assert_eq!(o.full_rows, 4, "hidden");
232 assert_eq!(o.full_row_elems, 256, "heads * head_dim");
233 assert_eq!(o.local_rows, 4, "every row is kept");
234 assert_eq!(o.local_row_elems, 128, "half the input dim");
235
236 let full: Vec<u8> = (0..4)
238 .flat_map(|_| (0..=255u8).flat_map(|c| [c, 0]))
239 .collect();
240 let got = shard_bytes(o, &full).unwrap();
241
242 let want: Vec<u8> = (0..4)
244 .flat_map(|_| (128..=255u8).flat_map(|c| [c, 0]))
245 .collect();
246 assert_eq!(got, want);
247
248 let row_sliced = &full[full.len() / 2..];
251 assert_eq!(row_sliced.len(), got.len());
252 assert_ne!(row_sliced, got.as_slice());
253 }
254
255 #[test]
258 fn o_norm_and_the_low_rank_down_projections_are_replicated() {
259 let p = plan(1);
260 for n in ["o_norm", "f_a_proj", "g_a_proj"] {
261 let t = p.get(n).unwrap();
262 assert_eq!(t.kind, KdaShard::Replicated, "{n}");
263 let full = vec![0xABu8; t.full_bytes()];
264 assert_eq!(shard_bytes(t, &full).unwrap(), full, "{n} must be verbatim");
265 }
266 }
267
268 #[test]
271 fn a_log_and_dt_bias_shard_at_different_granularity() {
272 let p = plan(1);
273 let a = p.get("A_log").unwrap();
274 let d = p.get("dt_bias").unwrap();
275 assert_eq!((a.full_rows, a.local_rows), (64, 32), "A_log is per-head");
276 assert_eq!(
277 (d.full_rows, d.local_rows),
278 (8192, 4096),
279 "dt_bias is per-channel"
280 );
281 assert_eq!(d.src_row_offset, a.src_row_offset * 128);
283 }
284
285 #[test]
288 fn tp1_is_the_identity() {
289 let p = KdaTpPlan::new(0, 1, 4096, 128, 64, 4, 128).unwrap();
290 for t in &p.tensors {
291 assert_eq!(t.local_bytes(), t.full_bytes(), "{}", t.name);
292 let full = vec![0x5Au8; t.full_bytes()];
293 assert_eq!(shard_bytes(t, &full).unwrap(), full, "{}", t.name);
294 }
295 assert!(!p.needs_output_all_reduce());
296 }
297
298 #[test]
301 fn a_size_mismatch_is_refused() {
302 let p = plan(0);
303 let q = p.get("q_proj").unwrap();
304 let err = shard_bytes(q, &vec![0u8; q.full_bytes() - 2]).unwrap_err();
305 assert!(err.to_string().contains("on disk"), "{err}");
306 }
307
308 #[test]
311 fn local_shape_preserves_the_on_disk_rank() {
312 let p = plan(1);
313 let c = p.get("q_conv1d").unwrap();
314 assert_eq!(local_shape(c, &[8192, 1, 4]), vec![4096, 1, 4]);
315 let o = p.get("o_proj").unwrap();
316 assert_eq!(local_shape(o, &[4096, 8192]), vec![4096, 4096]);
317 let n = p.get("o_norm").unwrap();
318 assert_eq!(local_shape(n, &[128]), vec![128]);
319 }
320
321 #[test]
324 fn the_adapter_presents_local_slices_and_passes_the_rest_through() {
325 struct Src(Vec<(String, KdaDtype, Vec<usize>, Vec<u8>)>);
326 impl KdaTensorSource for Src {
327 fn get(&self, name: &str) -> Option<RawTensor<'_>> {
328 self.0
329 .iter()
330 .find(|(n, ..)| n == name)
331 .map(|(_, d, s, b)| RawTensor {
332 dtype: *d,
333 shape: s.clone(),
334 bytes: b,
335 })
336 }
337 fn names(&self) -> Vec<String> {
338 self.0.iter().map(|(n, ..)| n.clone()).collect()
339 }
340 }
341 let p = KdaTpPlan::new(1, 2, 4, 64, 4, 2, 4).unwrap();
342 let q = p.get("q_proj").unwrap();
343 let src = Src(vec![
344 (
345 "self_attn.q_proj.weight".into(),
346 KdaDtype::Bf16,
347 vec![256, 4],
348 (0..=255u8).flat_map(|r| [r; 8]).collect(),
349 ),
350 (
351 "input_layernorm.weight".into(),
352 KdaDtype::Bf16,
353 vec![4],
354 vec![0xEE; 8],
355 ),
356 ]);
357 let sh = KdaShardedSource::new(&src, &p).unwrap();
358
359 let t = sh.get("self_attn.q_proj.weight").unwrap();
360 assert_eq!(t.shape, vec![128, 4], "local rows, full row width");
361 assert_eq!(t.bytes.len(), q.local_bytes());
362 assert!(
363 t.bytes.iter().all(|b| *b >= 128),
364 "rank 1 keeps the high rows"
365 );
366
367 let n = sh.get("input_layernorm.weight").unwrap();
369 assert_eq!(n.bytes, vec![0xEE; 8]);
370 assert_eq!(sh.names().len(), 2, "the census still sees everything");
371 }
372}