1use crate::dit::{Proj, cmf_f32};
23use crate::pool::Pool;
24use crate::zimage::host_gemm;
25use cortiq_core::CmfModel;
26use std::sync::Arc;
27
28pub const ARCH_NAME: &str = "kandinsky_s2v";
29pub const HEAD_DIM: usize = 128;
30pub const ROPE_PAIRS: usize = HEAD_DIM / 2;
31const NORM_EPS: f64 = 1e-5;
32const ROPE_T_MAX: i32 = 128;
34
35#[derive(Clone, Debug)]
36pub struct S2vConfig {
37 pub in_visual: usize,
38 pub out_visual: usize,
39 pub in_text: usize,
40 pub in_text2: usize,
41 pub in_audio: usize,
42 pub time_dim: usize,
43 pub patch: [usize; 3],
44 pub frame_buckets: [usize; 3],
45 pub ref_rope_index: i32,
46 pub dim: usize,
47 pub ff: usize,
48 pub n_text: usize,
49 pub n_audio: usize,
50 pub n_visual: usize,
51 pub axes: [usize; 3],
52 pub audio_layers: Vec<usize>,
53}
54
55impl S2vConfig {
56 pub fn from_json(v: &serde_json::Value) -> Result<Self, String> {
57 let u = |k: &str| -> Result<usize, String> {
58 v[k].as_u64().map(|x| x as usize).ok_or_else(|| format!("dit.config_json: no {k}"))
59 };
60 let tri = |k: &str| -> Result<[usize; 3], String> {
61 let a = v[k].as_array().ok_or_else(|| format!("dit.config_json: no {k}"))?;
62 if a.len() != 3 {
63 return Err(format!("dit.config_json: {k} is not a triple"));
64 }
65 Ok([
66 a[0].as_u64().unwrap_or(0) as usize,
67 a[1].as_u64().unwrap_or(0) as usize,
68 a[2].as_u64().unwrap_or(0) as usize,
69 ])
70 };
71 let cfg = S2vConfig {
72 in_visual: u("in_visual_dim")?,
73 out_visual: u("out_visual_dim")?,
74 in_text: u("in_text_dim")?,
75 in_text2: u("in_text_dim2")?,
76 in_audio: u("in_audio_dim")?,
77 time_dim: u("time_dim")?,
78 patch: tri("patch_size")?,
79 frame_buckets: tri("frame_buckets")?,
80 ref_rope_index: u("index_rope_ref_image")? as i32,
81 dim: u("model_dim")?,
82 ff: u("ff_dim")?,
83 n_text: u("num_text_blocks")?,
84 n_audio: u("num_audio_blocks")?,
85 n_visual: u("num_visual_blocks")?,
86 axes: tri("axes_dims")?,
87 audio_layers: v["audio_inject_layers"]
88 .as_array()
89 .ok_or("dit.config_json: no audio_inject_layers")?
90 .iter()
91 .map(|x| x.as_u64().unwrap_or(0) as usize)
92 .collect(),
93 };
94 if cfg.patch != [1, 2, 2] || cfg.axes.iter().sum::<usize>() != HEAD_DIM || cfg.dim % HEAD_DIM != 0 {
95 return Err(format!("unsupported S2V geometry: {cfg:?}"));
96 }
97 Ok(cfg)
98 }
99 pub fn heads(&self) -> usize {
100 self.dim / HEAD_DIM
101 }
102}
103
104#[derive(Clone, Copy, Debug)]
106pub struct S2vGeom {
107 pub lt: usize,
108 pub lh: usize,
109 pub lw: usize,
110 pub n4: usize,
112 pub n2: usize,
113 pub n1: usize,
114 pub nref: usize,
115 pub nvis: usize,
116}
117
118impl S2vGeom {
119 pub fn new(cfg: &S2vConfig, lt: usize, lh: usize, lw: usize) -> Self {
120 let per = |c: usize| (lh / (2 * c)) * (lw / (2 * c));
121 let b = cfg.frame_buckets;
122 S2vGeom {
123 lt,
124 lh,
125 lw,
126 n4: (b[2] / 4) * per(4),
127 n2: (b[1] / 2) * per(2),
128 n1: b[0] * per(1),
129 nref: per(1),
130 nvis: lt * per(1),
131 }
132 }
133 pub fn clean(&self) -> usize {
134 self.n4 + self.n2 + self.n1 + self.nref
135 }
136 pub fn total(&self) -> usize {
137 self.clean() + self.nvis
138 }
139 pub fn per_frame(&self) -> usize {
140 self.nvis / self.lt
141 }
142}
143
144fn freqs(d: usize) -> Vec<f32> {
146 let ln = (10000f64).ln() as f32;
147 (0..d).map(|j| (-ln * j as f32 / d as f32).exp()).collect()
148}
149
150pub fn rope_1d(pos: &[i32]) -> (Vec<f32>, Vec<f32>) {
153 let f = freqs(ROPE_PAIRS);
154 let mut c = Vec::with_capacity(pos.len() * ROPE_PAIRS);
155 let mut s = Vec::with_capacity(pos.len() * ROPE_PAIRS);
156 for &p in pos {
157 for &fr in &f {
158 let a = p as f32 * fr;
159 c.push(a.cos());
160 s.push(a.sin());
161 }
162 }
163 (c, s)
164}
165
166pub fn rope_visual(cfg: &S2vConfig, g: &S2vGeom, sf: [f32; 3]) -> (Vec<f32>, Vec<f32>) {
170 let ladders = [freqs(cfg.axes[0] / 2), freqs(cfg.axes[1] / 2), freqs(cfg.axes[2] / 2)];
171 let (ph, pw) = (g.lh / 2, g.lw / 2);
172 let b = cfg.frame_buckets;
173 let bounds = [0i32, b[0] as i32, (b[0] + b[1]) as i32, (b[0] + b[1] + b[2]) as i32];
174 let mut parts: Vec<(Vec<i32>, usize)> = Vec::new();
176 let span = |lo: i32, hi: i32, st: i32| -> Vec<i32> { (lo..hi).step_by(st as usize).collect() };
177 parts.push((span(-bounds[3], -bounds[2], 4), 4));
178 parts.push((span(-bounds[2], -bounds[1], 2), 2));
179 parts.push((span(-bounds[1], -bounds[0], 1), 1));
180 parts.push((vec![cfg.ref_rope_index], 1));
181 parts.push(((0..g.lt as i32).collect(), 1));
182 let mut cos = Vec::with_capacity(g.total() * ROPE_PAIRS);
183 let mut sin = Vec::with_capacity(g.total() * ROPE_PAIRS);
184 for (ts, st) in parts {
185 let rows = (0..(ph - ph % st)).step_by(st);
188 for &t in &ts {
189 debug_assert!(t >= -ROPE_T_MAX && t < ROPE_T_MAX);
190 for r in rows.clone() {
191 for col in (0..(pw - pw % st)).step_by(st) {
192 for (ax, lad) in ladders.iter().enumerate() {
193 let p = [t, r as i32, col as i32][ax] as f32;
194 for &fr in lad {
195 let a = p * fr / sf[ax];
196 cos.push(a.cos());
197 sin.push(a.sin());
198 }
199 }
200 }
201 }
202 }
203 }
204 debug_assert_eq!(cos.len(), g.total() * ROPE_PAIRS);
205 (cos, sin)
206}
207
208pub fn audio_groups(tokens: usize, frames: usize) -> Vec<(usize, usize)> {
211 let rest = tokens - 1;
212 let bounds: Vec<usize> = (0..frames).map(|i| rest * i / (frames - 1)).collect();
213 let mut v = vec![(0usize, 1usize)];
214 for w in bounds.windows(2) {
215 v.push((1 + w[0], w[1] - w[0]));
216 }
217 v
218}
219
220pub fn audio_rope_pos(tokens: usize, frames: usize) -> Vec<i32> {
222 let mut p = vec![0i32; tokens];
223 for (fr, (st, len)) in audio_groups(tokens, frames).into_iter().enumerate() {
224 for v in &mut p[st..st + len] {
225 *v = fr as i32;
226 }
227 }
228 p
229}
230
231pub(crate) struct Rows(pub(crate) *mut f32);
232unsafe impl Send for Rows {}
233unsafe impl Sync for Rows {}
234impl Rows {
235 #[allow(clippy::mut_from_ref)]
237 pub(crate) unsafe fn at(&self, off: usize, len: usize) -> &mut [f32] {
238 unsafe { std::slice::from_raw_parts_mut(self.0.add(off), len) }
239 }
240}
241
242pub(crate) fn pool_rows(pool: Option<&Pool>, n: usize, f: &(dyn Fn(usize, usize) + Sync)) {
243 match pool {
244 Some(p) => p.run_rows(n, f),
245 None => f(0, n),
246 }
247}
248
249#[inline]
251pub(crate) fn gelu(x: f32) -> f32 {
252 let z = x * std::f32::consts::FRAC_1_SQRT_2;
253 let a = z.abs();
254 let t = 1.0 / (1.0 + 0.327_591_1 * a);
255 let e = 1.0
256 - (((((1.061_405_4 * t - 1.453_152_1) * t) + 1.421_413_8) * t - 0.284_496_72) * t + 0.254_829_6)
257 * t
258 * (-a * a).exp();
259 0.5 * x * (1.0 + if z < 0.0 { -e } else { e })
260}
261
262#[inline]
263pub(crate) fn silu(v: f32) -> f32 {
264 v / (1.0 + (-v).exp())
265}
266
267#[inline]
269pub(crate) fn layer_norm_row(x: &[f32], eps: f64, dst: &mut [f32]) {
270 let n = x.len() as f64;
271 let mean = x.iter().map(|&v| v as f64).sum::<f64>() / n;
272 let var = x.iter().map(|&v| (v as f64 - mean) * (v as f64 - mean)).sum::<f64>() / n;
273 let inv = 1.0 / (var + eps).sqrt();
274 for (d, &v) in dst.iter_mut().zip(x) {
275 *d = ((v as f64 - mean) * inv) as f32;
276 }
277}
278
279fn rms_row(v: &mut [f32], w: &[f32], eps: f64) {
280 let ss = v.iter().map(|&x| (x as f64) * (x as f64)).sum::<f64>() / v.len() as f64;
281 let inv = 1.0 / (ss + eps).sqrt();
282 for (x, &g) in v.iter_mut().zip(w) {
283 *x = (*x as f64 * inv) as f32 * g;
284 }
285}
286
287fn softmax(row: &mut [f32]) {
288 let mx = row.iter().cloned().fold(f32::NEG_INFINITY, f32::max);
289 let mut den = 0f64;
290 for r in row.iter_mut() {
291 *r = (*r - mx).exp();
292 den += *r as f64;
293 }
294 let inv = (1.0 / den) as f32;
295 for r in row.iter_mut() {
296 *r *= inv;
297 }
298}
299
300pub(crate) struct Lin {
302 pub(crate) w: Proj,
303 pub(crate) b: Option<Vec<f32>>,
304}
305
306impl Lin {
307 pub(crate) fn load(m: &Arc<CmfModel>, p: &str) -> Result<Lin, String> {
308 let name = format!("{p}.weight");
309 let e = m.tensor(&name).ok_or_else(|| format!("missing tensor {name}"))?;
310 let w = match e.dtype {
311 cortiq_core::TensorDtype::F16 | cortiq_core::TensorDtype::Bf16 => {
312 let cols = *e.shape.last().unwrap_or(&1);
313 Proj::f32(cmf_f32(m, &name)?, cols)
314 }
315 _ => Proj::from_model(m, &name)?,
316 };
317 let bn = format!("{p}.bias");
318 let b = if m.tensor(&bn).is_some() { Some(cmf_f32(m, &bn)?) } else { None };
319 Ok(Lin { w, b })
320 }
321 pub(crate) fn rows(&self) -> usize {
322 self.w.rows()
323 }
324 pub(crate) fn apply(&self, x: &[f32], n: usize, pool: Option<&Pool>) -> Vec<f32> {
326 let rows = self.w.rows();
327 let mut y = vec![0f32; n * rows];
328 host_lin(&self.w, x, n, &mut y, pool);
329 if let Some(b) = &self.b {
330 let sr = Rows(y.as_mut_ptr());
331 pool_rows(pool, n, &|lo, hi| {
332 for r in lo..hi {
333 for (d, &v) in unsafe { sr.at(r * rows, rows) }.iter_mut().zip(b) {
335 *d += v;
336 }
337 }
338 });
339 }
340 y
341 }
342}
343
344pub(crate) fn host_lin(p: &Proj, x: &[f32], n: usize, y: &mut [f32], pool: Option<&Pool>) {
346 let (rows, cols) = (p.rows(), p.cols());
347 match p {
348 Proj::F32 { w, .. } => host_gemm::gemm_nt(x, w, y, n, cols, rows, pool),
349 Proj::Q(q) => {
350 const CH: usize = 768;
351 let mut wbuf = vec![0f32; CH.min(rows) * cols];
352 let mut r0 = 0;
353 while r0 < rows {
354 let rc = CH.min(rows - r0);
355 {
356 let wp = Rows(wbuf.as_mut_ptr());
357 pool_rows(pool, rc, &|lo, hi| {
358 for r in lo..hi {
359 q.row_f32(r0 + r, unsafe { wp.at(r * cols, cols) });
361 }
362 });
363 }
364 host_gemm::gemm_nt_ld(x, &wbuf[..rc * cols], &mut y[r0..], rows, n, cols, rc, pool);
365 r0 += rc;
366 }
367 }
368 }
369}
370
371pub(crate) struct Affine {
373 pub(crate) w: Vec<f32>,
374 pub(crate) b: Vec<f32>,
375}
376
377impl Affine {
378 pub(crate) fn load(m: &Arc<CmfModel>, p: &str) -> Result<Affine, String> {
379 Ok(Affine { w: cmf_f32(m, &format!("{p}.weight"))?, b: cmf_f32(m, &format!("{p}.bias"))? })
380 }
381 pub(crate) fn apply(&self, x: &[f32], n: usize, pool: Option<&Pool>) -> Vec<f32> {
382 let d = self.w.len();
383 let mut y = vec![0f32; n * d];
384 let sr = Rows(y.as_mut_ptr());
385 pool_rows(pool, n, &|lo, hi| {
386 for r in lo..hi {
387 let row = unsafe { sr.at(r * d, d) };
389 layer_norm_row(&x[r * d..(r + 1) * d], NORM_EPS, row);
390 for ((v, &w), &b) in row.iter_mut().zip(&self.w).zip(&self.b) {
391 *v = *v * w + b;
392 }
393 }
394 });
395 y
396 }
397}
398
399pub(crate) struct Attn {
400 pub(crate) q: Lin,
401 pub(crate) k: Lin,
402 pub(crate) v: Lin,
403 pub(crate) o: Lin,
404 pub(crate) qn: Vec<f32>,
405 pub(crate) kn: Vec<f32>,
406}
407
408impl Attn {
409 fn load(m: &Arc<CmfModel>, p: &str) -> Result<Attn, String> {
410 Ok(Attn {
411 q: Lin::load(m, &format!("{p}.to_query"))?,
412 k: Lin::load(m, &format!("{p}.to_key"))?,
413 v: Lin::load(m, &format!("{p}.to_value"))?,
414 o: Lin::load(m, &format!("{p}.out_layer"))?,
415 qn: cmf_f32(m, &format!("{p}.query_norm.weight"))?,
416 kn: cmf_f32(m, &format!("{p}.key_norm.weight"))?,
417 })
418 }
419
420 fn forward(
424 &self,
425 x: &[f32],
426 n: usize,
427 ctx: &[f32],
428 m: usize,
429 rope: Option<(&[f32], &[f32])>,
430 groups: Option<&[(usize, usize, usize, usize)]>,
431 pool: Option<&Pool>,
432 ) -> Vec<f32> {
433 let h = self.q.rows();
434 let nh = h / HEAD_DIM;
435 let mut q = self.q.apply(x, n, pool);
436 let mut k = self.k.apply(ctx, m, pool);
437 let v = self.v.apply(ctx, m, pool);
438 let norm_rot = |buf: &mut [f32], rows: usize, w: &[f32]| {
439 let sr = Rows(buf.as_mut_ptr());
440 pool_rows(pool, rows, &|lo, hi| {
441 for r in lo..hi {
442 for hh in 0..nh {
443 let row = unsafe { sr.at((r * nh + hh) * HEAD_DIM, HEAD_DIM) };
445 rms_row(row, w, NORM_EPS);
446 if let Some((cos, sin)) = rope {
447 for j in 0..ROPE_PAIRS {
448 let (c, s) = (cos[r * ROPE_PAIRS + j], sin[r * ROPE_PAIRS + j]);
449 let (a, b) = (row[2 * j], row[2 * j + 1]);
450 row[2 * j] = a * c - b * s;
451 row[2 * j + 1] = a * s + b * c;
452 }
453 }
454 }
455 }
456 });
457 };
458 norm_rot(&mut q, n, &self.qn);
459 norm_rot(&mut k, m, &self.kn);
460 let whole = [(0usize, n, 0usize, m)];
461 let gs: &[(usize, usize, usize, usize)] = groups.unwrap_or(&whole);
462 let scale = 1.0 / (HEAD_DIM as f32).sqrt();
463 let mut att = vec![0f32; n * h];
464 for &(q0, qn, k0, kn) in gs {
465 let mut qh = vec![0f32; qn * HEAD_DIM];
466 let mut kh = vec![0f32; kn * HEAD_DIM];
467 let mut vt = vec![0f32; HEAD_DIM * kn];
468 let mut sc = vec![0f32; qn * kn];
469 let mut oh = vec![0f32; qn * HEAD_DIM];
470 for hh in 0..nh {
471 for r in 0..qn {
472 for d in 0..HEAD_DIM {
473 qh[r * HEAD_DIM + d] = q[((q0 + r) * nh + hh) * HEAD_DIM + d] * scale;
474 }
475 }
476 for r in 0..kn {
477 let base = ((k0 + r) * nh + hh) * HEAD_DIM;
478 kh[r * HEAD_DIM..(r + 1) * HEAD_DIM].copy_from_slice(&k[base..base + HEAD_DIM]);
479 for d in 0..HEAD_DIM {
480 vt[d * kn + r] = v[base + d];
481 }
482 }
483 host_gemm::gemm_nt(&qh, &kh, &mut sc, qn, HEAD_DIM, kn, pool);
484 let sp = Rows(sc.as_mut_ptr());
485 pool_rows(pool, qn, &|lo, hi| {
486 for r in lo..hi {
487 softmax(unsafe { sp.at(r * kn, kn) });
489 }
490 });
491 host_gemm::gemm_nt(&sc, &vt, &mut oh, qn, kn, HEAD_DIM, pool);
492 for r in 0..qn {
493 let o = ((q0 + r) * nh + hh) * HEAD_DIM;
494 att[o..o + HEAD_DIM].copy_from_slice(&oh[r * HEAD_DIM..(r + 1) * HEAD_DIM]);
495 }
496 }
497 }
498 self.o.apply(&att, n, pool)
499 }
500}
501
502pub(crate) struct Ffn {
503 pub(crate) w1: Lin,
504 pub(crate) w2: Lin,
505}
506
507impl Ffn {
508 fn load(m: &Arc<CmfModel>, p: &str) -> Result<Ffn, String> {
509 Ok(Ffn {
510 w1: Lin::load(m, &format!("{p}.in_layer"))?,
511 w2: Lin::load(m, &format!("{p}.out_layer"))?,
512 })
513 }
514 fn forward(&self, x: &[f32], n: usize, pool: Option<&Pool>) -> Vec<f32> {
515 let mut hid = self.w1.apply(x, n, pool);
516 let inner = self.w1.rows();
517 let sr = Rows(hid.as_mut_ptr());
518 pool_rows(pool, n, &|lo, hi| {
519 for r in lo..hi {
520 for v in unsafe { sr.at(r * inner, inner) } {
522 *v = gelu(*v);
523 }
524 }
525 });
526 self.w2.apply(&hid, n, pool)
527 }
528}
529
530pub(crate) struct VisualBlock {
531 pub(crate) sa: Attn,
532 pub(crate) ca: Attn,
533 pub(crate) v2a: Option<(Affine, Attn)>,
534 pub(crate) ffn: Ffn,
535}
536
537pub(crate) struct TextBlock {
538 pub(crate) attn: Attn,
539 pub(crate) ffn: Ffn,
540}
541
542pub(crate) struct AudioBlock {
543 pub(crate) sa_norm: Affine,
544 pub(crate) attn: Attn,
545 pub(crate) ff_norm: Affine,
546 pub(crate) ffn: Ffn,
547}
548
549pub struct S2vDit {
550 pub(crate) model: Arc<CmfModel>,
551 pub cfg: S2vConfig,
552 pub(crate) pool: Option<Arc<Pool>>,
553 pub(crate) time_in: Lin,
554 pub(crate) time_out: Lin,
555 pub(crate) time_freqs: Vec<f32>,
556 pub(crate) text_in: Lin,
557 pub(crate) text_norm: Affine,
558 pub(crate) pooled_in: Lin,
559 pub(crate) pooled_norm: Affine,
560 pub(crate) audio_in: Lin,
561 pub(crate) audio_norm: Affine,
562 pub(crate) emb1: Lin,
563 pub(crate) emb_p1: Lin,
564 pub(crate) emb_p2: Lin,
565 pub(crate) emb_p4: Lin,
566 pub(crate) mask: Vec<f32>,
567 pub(crate) text: Vec<TextBlock>,
568 pub(crate) audio: Vec<AudioBlock>,
569 pub(crate) visual: Vec<VisualBlock>,
570 pub(crate) out_w: Lin,
571}
572
573pub struct S2vInput<'a> {
575 pub x: &'a [f32],
576 pub reference: &'a [f32],
577 pub mem1: &'a [f32],
578 pub mem2: &'a [f32],
579 pub mem4: &'a [f32],
580 pub t: f32,
581 pub text_feats: &'a [f32],
582 pub audio_feats: &'a [f32],
583 pub pooled: &'a [f32],
584 pub geom: S2vGeom,
585 pub scale_factor: [f32; 3],
586}
587
588pub fn patchify(x: &[f32], c: usize, pt: usize, ps: usize, h: usize, w: usize) -> Vec<f32> {
591 let frames = x.len() / (h * w * c);
592 let (th, tw, tt) = (h / ps, w / ps, frames / pt);
593 let dim = pt * ps * ps * c;
594 let mut out = vec![0f32; tt * th * tw * dim];
595 for it in 0..tt {
596 for ih in 0..th {
597 for iw in 0..tw {
598 let row = (it * th + ih) * tw + iw;
599 let mut o = row * dim;
600 for dt in 0..pt {
601 for dh in 0..ps {
602 for dw in 0..ps {
603 let src = (((it * pt + dt) * h + ih * ps + dh) * w + iw * ps + dw) * c;
604 out[o..o + c].copy_from_slice(&x[src..src + c]);
605 o += c;
606 }
607 }
608 }
609 }
610 }
611 }
612 out
613}
614
615pub fn unpatchify_out(tok: &[f32], g: &S2vGeom, c: usize) -> Vec<f32> {
617 let (ph, pw) = (g.lh / 2, g.lw / 2);
618 let mut out = vec![0f32; g.lt * g.lh * g.lw * c];
619 for t in 0..g.lt {
620 for r in 0..ph {
621 for col in 0..pw {
622 let row = (t * ph + r) * pw + col;
623 for dh in 0..2 {
624 for dw in 0..2 {
625 let dst = ((t * g.lh + r * 2 + dh) * g.lw + col * 2 + dw) * c;
626 for ch in 0..c {
627 out[dst + ch] = tok[row * 4 * c + ch * 4 + dh * 2 + dw];
628 }
629 }
630 }
631 }
632 }
633 }
634 out
635}
636
637impl S2vDit {
638 pub fn from_cmf(model: &Arc<CmfModel>) -> Result<S2vDit, String> {
639 let raw = model.tensor_bytes("dit.config_json").map_err(|e| e.to_string())?;
640 let v: serde_json::Value = serde_json::from_slice(raw).map_err(|e| format!("dit.config_json: {e}"))?;
641 let cfg = S2vConfig::from_json(&v)?;
642 let m = model;
643 let mut text = Vec::with_capacity(cfg.n_text);
644 for i in 0..cfg.n_text {
645 let p = format!("dit.text_transformer_blocks.{i}");
646 text.push(TextBlock {
647 attn: Attn::load(m, &format!("{p}.self_attention"))?,
648 ffn: Ffn::load(m, &format!("{p}.feed_forward"))?,
649 });
650 }
651 let mut audio = Vec::with_capacity(cfg.n_audio);
652 for i in 0..cfg.n_audio {
653 let p = format!("dit.audio_transformer_blocks.{i}");
654 audio.push(AudioBlock {
655 sa_norm: Affine::load(m, &format!("{p}.self_attention_norm"))?,
656 attn: Attn::load(m, &format!("{p}.self_attention"))?,
657 ff_norm: Affine::load(m, &format!("{p}.feed_forward_norm"))?,
658 ffn: Ffn::load(m, &format!("{p}.feed_forward"))?,
659 });
660 }
661 let mut visual = Vec::with_capacity(cfg.n_visual);
662 for i in 0..cfg.n_visual {
663 let p = format!("dit.visual_transformer_blocks.{i}");
664 let v2a = if cfg.audio_layers.contains(&i) {
665 Some((
666 Affine::load(m, &format!("{p}.cross_attention_norm_v2a"))?,
667 Attn::load(m, &format!("{p}.cross_attention_v2a"))?,
668 ))
669 } else {
670 None
671 };
672 visual.push(VisualBlock {
673 sa: Attn::load(m, &format!("{p}.self_attention"))?,
674 ca: Attn::load(m, &format!("{p}.cross_attention"))?,
675 v2a,
676 ffn: Ffn::load(m, &format!("{p}.feed_forward"))?,
677 });
678 }
679 Ok(S2vDit {
680 model: m.clone(),
681 pool: Pool::from_env(),
682 time_in: Lin::load(m, "dit.time_embeddings.in_layer")?,
683 time_out: Lin::load(m, "dit.time_embeddings.out_layer")?,
684 time_freqs: freqs(cfg.dim / 2),
685 text_in: Lin::load(m, "dit.text_embeddings.in_layer")?,
686 text_norm: Affine::load(m, "dit.text_embeddings.norm")?,
687 pooled_in: Lin::load(m, "dit.pooled_text_embeddings.in_layer")?,
688 pooled_norm: Affine::load(m, "dit.pooled_text_embeddings.norm")?,
689 audio_in: Lin::load(m, "dit.audio_embeddings.in_layer")?,
690 audio_norm: Affine::load(m, "dit.audio_embeddings.norm")?,
691 emb1: Lin::load(m, "dit.visual_embeddings.in_layer")?,
692 emb_p1: Lin::load(m, "dit.visual_embeddings_proj1x.in_layer")?,
693 emb_p2: Lin::load(m, "dit.visual_embeddings_proj2x.in_layer")?,
694 emb_p4: Lin::load(m, "dit.visual_embeddings_proj4x.in_layer")?,
695 mask: cmf_f32(m, "dit.mask_embeddings.weight")?,
696 text,
697 audio,
698 visual,
699 out_w: Lin::load(m, "dit.out_layer.out_layer")?,
700 cfg,
701 })
702 }
703
704 pub(crate) fn pool(&self) -> Option<&Pool> {
705 self.pool.as_deref()
706 }
707
708 pub(crate) fn modulate(&self, name: &str, te_silu: &[f32], n: usize) -> Result<Vec<f32>, String> {
712 let l = Lin::load(&self.model, name)?;
713 Ok(l.apply(te_silu, n, self.pool()))
714 }
715
716 pub(crate) fn modulate_all(&self, names: &[String], te_silu: &[f32], n: usize) -> Result<Vec<Vec<f32>>, String> {
719 let threads = Pool::effective_threads().clamp(1, 16);
720 let next = std::sync::atomic::AtomicUsize::new(0);
721 let out: Vec<std::sync::Mutex<Option<Result<Vec<f32>, String>>>> = names.iter().map(|_| std::sync::Mutex::new(None)).collect();
722 std::thread::scope(|sc| {
723 for _ in 0..threads {
724 sc.spawn(|| {
725 loop {
726 let i = next.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
727 if i >= names.len() {
728 break;
729 }
730 let r = Lin::load(&self.model, &names[i]).map(|l| l.apply(te_silu, n, None));
731 *out[i].lock().unwrap() = Some(r);
732 }
733 });
734 }
735 });
736 out.into_iter().map(|m| m.into_inner().unwrap().unwrap()).collect()
737 }
738
739 pub fn time_embed(&self, t: f32, pooled_emb: &[f32]) -> Vec<f32> {
741 let d = self.cfg.dim / 2;
742 let mut e = vec![0f32; self.cfg.dim];
743 for j in 0..d {
744 let a = t * self.time_freqs[j];
745 e[j] = a.cos();
746 e[d + j] = a.sin();
747 }
748 let mut h = self.time_in.apply(&e, 1, None);
749 for v in &mut h {
750 *v = silu(*v);
751 }
752 let mut out = self.time_out.apply(&h, 1, None);
753 for (o, &p) in out.iter_mut().zip(pooled_emb) {
754 *o += p;
755 }
756 out
757 }
758
759 pub fn pooled_embed(&self, pooled: &[f32]) -> Vec<f32> {
760 let y = self.pooled_in.apply(pooled, 1, None);
761 self.pooled_norm.apply(&y, 1, None)
762 }
763
764 pub fn embed_text(&self, feats: &[f32]) -> Vec<f32> {
765 let n = feats.len() / self.cfg.in_text;
766 let y = self.text_in.apply(feats, n, self.pool());
767 self.text_norm.apply(&y, n, self.pool())
768 }
769
770 pub fn embed_audio(&self, feats: &[f32]) -> Vec<f32> {
771 let n = feats.len() / self.cfg.in_audio;
772 let y = self.audio_in.apply(feats, n, self.pool());
773 self.audio_norm.apply(&y, n, self.pool())
774 }
775
776 fn text_block(&self, b: &TextBlock, x: &mut [f32], m: &[f32], rope: (&[f32], &[f32])) {
778 let h = self.cfg.dim;
779 let n = x.len() / h;
780 let pool = self.pool();
781 let xn = modulated_norm(x, n, h, &[&m[..3 * h]], &|_| 0, pool);
782 let o = b.attn.forward(&xn, n, &xn, n, Some(rope), None, pool);
783 gated_add(x, &o, n, h, &[&m[2 * h..3 * h]], &|_| 0, pool);
784 let xn = modulated_norm(x, n, h, &[&m[3 * h..6 * h]], &|_| 0, pool);
785 let o = b.ffn.forward(&xn, n, pool);
786 gated_add(x, &o, n, h, &[&m[5 * h..6 * h]], &|_| 0, pool);
787 }
788
789 pub fn embed_visual(&self, i: &S2vInput<'_>) -> Vec<f32> {
791 let (c, g) = (self.cfg.in_visual, &i.geom);
792 let h = self.cfg.dim;
793 let pool = self.pool();
794 let part = |lin: &Lin, data: &[f32], pt: usize, ps: usize, mask: usize| -> Vec<f32> {
795 let (hh, ww) = (g.lh - g.lh % ps, g.lw - g.lw % ps);
796 let tok = patchify(data, c, pt, ps, hh, ww);
797 let n = tok.len() / lin.w.cols();
798 let mut y = lin.apply(&tok, n, pool);
799 for row in y.chunks_exact_mut(h) {
800 for (v, &m) in row.iter_mut().zip(&self.mask[mask * h..(mask + 1) * h]) {
801 *v += m;
802 }
803 }
804 y
805 };
806 let mut out = Vec::with_capacity(g.total() * h);
807 out.extend(part(&self.emb_p4, i.mem4, 4, 8, 2));
808 out.extend(part(&self.emb_p2, i.mem2, 2, 4, 2));
809 out.extend(part(&self.emb_p1, i.mem1, 1, 2, 2));
810 out.extend(part(&self.emb1, i.reference, 1, 2, 1));
811 out.extend(part(&self.emb1, i.x, 1, 2, 0));
812 out
813 }
814
815 pub fn embed_clean(&self, reference: &[f32], memory: &[Vec<f32>; 3], g: &S2vGeom) -> Vec<f32> {
817 let (c, h) = (self.cfg.in_visual, self.cfg.dim);
818 let pool = self.pool();
819 let part = |lin: &Lin, data: &[f32], pt: usize, ps: usize, mask: usize| -> Vec<f32> {
820 let (hh, ww) = (g.lh - g.lh % ps, g.lw - g.lw % ps);
821 let tok = patchify(data, c, pt, ps, hh, ww);
822 let n = tok.len() / lin.w.cols();
823 let mut y = lin.apply(&tok, n, pool);
824 for row in y.chunks_exact_mut(h) {
825 for (v, &m) in row.iter_mut().zip(&self.mask[mask * h..(mask + 1) * h]) {
826 *v += m;
827 }
828 }
829 y
830 };
831 let mut out = Vec::with_capacity(g.clean() * h);
832 out.extend(part(&self.emb_p4, &memory[2], 4, 8, 2));
833 out.extend(part(&self.emb_p2, &memory[1], 2, 4, 2));
834 out.extend(part(&self.emb_p1, &memory[0], 1, 2, 2));
835 out.extend(part(&self.emb1, reference, 1, 2, 1));
836 out
837 }
838
839 pub fn forward(
842 &self,
843 i: &S2vInput<'_>,
844 mut tap: Option<&mut dyn FnMut(&str, &[f32])>,
845 ) -> Result<Vec<f32>, String> {
846 let (h, g) = (self.cfg.dim, &i.geom);
847 let pool = self.pool();
848 let pe = self.pooled_embed(i.pooled);
849 let te = self.time_embed(i.t, &pe);
850 let te0 = self.time_embed(0.0, &pe);
851 let silu_all = |v: &[f32]| -> Vec<f32> { v.iter().map(|&x| silu(x)).collect() };
852 let (s, s0) = (silu_all(&te), silu_all(&te0));
853
854 let mut text = self.embed_text(i.text_feats);
855 let (tc, ts) = rope_1d(&(0..(text.len() / h) as i32).collect::<Vec<_>>());
856 for (bi, b) in self.text.iter().enumerate() {
857 let name = format!("dit.text_transformer_blocks.{bi}.text_modulation.out_layer");
858 let m = self.modulate(&name, &s, 1)?;
859 self.text_block(b, &mut text, &m, (&tc, &ts));
860 if let Some(t) = tap.as_mut() {
861 t(&format!("text_transformer_blocks.{bi}"), &text);
862 }
863 }
864 let mut audio = self.embed_audio(i.audio_feats);
865 {
866 let n = audio.len() / h;
867 let (ac, as_) = rope_1d(&audio_rope_pos(n, g.lt));
868 for (bi, b) in self.audio.iter().enumerate() {
869 let xn = b.sa_norm.apply(&audio, n, pool);
870 let o = b.attn.forward(&xn, n, &xn, n, Some((&ac, &as_)), None, pool);
871 add_assign(&mut audio, &o);
872 let xn = b.ff_norm.apply(&audio, n, pool);
873 let o = b.ffn.forward(&xn, n, pool);
874 add_assign(&mut audio, &o);
875 if let Some(t) = tap.as_mut() {
876 t(&format!("audio_transformer_blocks.{bi}"), &audio);
877 }
878 }
879 }
880 let mut x = self.embed_visual(i);
881 let (vc, vs) = rope_visual(&self.cfg, g, i.scale_factor);
882 let n = g.total();
883 let clean = g.clean();
884 let sel = move |r: usize| usize::from(r >= clean);
885 let na = audio.len() / h;
886 let nt = text.len() / h;
887 let groups: Vec<(usize, usize, usize, usize)> = audio_groups(na, g.lt)
888 .into_iter()
889 .enumerate()
890 .map(|(f, (k0, kn))| (f * g.per_frame(), g.per_frame(), k0, kn))
891 .collect();
892 let mut st = [s0.clone(), s.clone()].concat();
893 for (bi, b) in self.visual.iter().enumerate() {
894 let name = format!("dit.visual_transformer_blocks.{bi}.visual_modulation.out_layer");
895 let m = self.modulate(&name, &st, 2)?;
896 let row = |r: usize, a: usize, e: usize| &m[r * 9 * h + a * h..r * 9 * h + e * h];
897 let xn = modulated_norm(&x, n, h, &[row(0, 0, 3), row(1, 0, 3)], &sel, pool);
899 let o = b.sa.forward(&xn, n, &xn, n, Some((&vc, &vs)), None, pool);
900 gated_add(&mut x, &o, n, h, &[row(0, 2, 3), row(1, 2, 3)], &sel, pool);
901 let xn = modulated_norm(&x, n, h, &[row(0, 3, 6), row(1, 3, 6)], &sel, pool);
903 let o = b.ca.forward(&xn, n, &text, nt, None, None, pool);
904 gated_add(&mut x, &o, n, h, &[row(0, 5, 6), row(1, 5, 6)], &sel, pool);
905 if let Some((norm, att)) = &b.v2a {
907 let tail = &x[clean * h..];
908 let xn = norm.apply(tail, g.nvis, pool);
909 let o = att.forward(&xn, g.nvis, &audio, na, None, Some(&groups), pool);
910 add_assign(&mut x[clean * h..], &o);
911 }
912 let xn = modulated_norm(&x, n, h, &[row(0, 6, 9), row(1, 6, 9)], &sel, pool);
914 let o = b.ffn.forward(&xn, n, pool);
915 gated_add(&mut x, &o, n, h, &[row(0, 8, 9), row(1, 8, 9)], &sel, pool);
916 if let Some(t) = tap.as_mut() {
917 t(&format!("visual_transformer_blocks.{bi}"), &x);
918 }
919 }
920 st.clear();
921 let m = self.modulate("dit.out_layer.modulation.out_layer", &s, 1)?;
923 let tail = &x[clean * h..];
924 let sc: &[&[f32]] = &[&m[..2 * h]];
925 let xn = modulated_norm(tail, g.nvis, h, sc, &|_| 0, pool);
926 let y = self.out_w.apply(&xn, g.nvis, pool);
927 Ok(unpatchify_out(&y, g, self.cfg.out_visual))
928 }
929}
930
931fn add_assign(x: &mut [f32], y: &[f32]) {
932 for (a, &b) in x.iter_mut().zip(y) {
933 *a += b;
934 }
935}
936
937fn modulated_norm(
939 x: &[f32],
940 n: usize,
941 h: usize,
942 chunks: &[&[f32]],
943 sel: &(dyn Fn(usize) -> usize + Sync),
944 pool: Option<&Pool>,
945) -> Vec<f32> {
946 let mut y = vec![0f32; n * h];
947 let sr = Rows(y.as_mut_ptr());
948 pool_rows(pool, n, &|lo, hi| {
949 for r in lo..hi {
950 let row = unsafe { sr.at(r * h, h) };
952 layer_norm_row(&x[r * h..(r + 1) * h], NORM_EPS, row);
953 let c = chunks[sel(r)];
954 let (shift, scale) = (&c[..h], &c[h..2 * h]);
955 for ((v, &sc), &sh) in row.iter_mut().zip(scale).zip(shift) {
956 *v = *v * (sc + 1.0) + sh;
957 }
958 }
959 });
960 y
961}
962
963fn gated_add(
964 x: &mut [f32],
965 o: &[f32],
966 n: usize,
967 h: usize,
968 gates: &[&[f32]],
969 sel: &(dyn Fn(usize) -> usize + Sync),
970 pool: Option<&Pool>,
971) {
972 let sr = Rows(x.as_mut_ptr());
973 pool_rows(pool, n, &|lo, hi| {
974 for r in lo..hi {
975 let row = unsafe { sr.at(r * h, h) };
977 let g = gates[sel(r)];
978 for ((v, &gg), &b) in row.iter_mut().zip(g).zip(&o[r * h..(r + 1) * h]) {
979 *v += gg * b;
980 }
981 }
982 });
983}