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