1use crate::dit::Proj;
22use crate::qtensor::QTensor;
23use crate::audiovae::SendPtr;
24use crate::pool::Pool;
25use cortiq_core::CmfModel;
26use std::sync::Arc;
27
28fn silu(v: f32) -> f32 {
29 v / (1.0 + (-v).exp())
30}
31
32struct LayerNorm {
35 gamma: Vec<f32>,
36 beta: Vec<f32>,
37}
38
39impl LayerNorm {
40 fn load(model: &Arc<CmfModel>, p: &str) -> Result<Self, String> {
41 Ok(Self {
42 gamma: crate::dit::cmf_f32(model, &format!("{p}.gamma"))?,
43 beta: crate::dit::cmf_f32(model, &format!("{p}.beta"))?,
44 })
45 }
46
47 fn apply(&self, x: &mut [f32], d: usize) {
48 for row in x.chunks_exact_mut(d) {
49 let mean = row.iter().map(|v| *v as f64).sum::<f64>() / d as f64;
50 let var = row.iter().map(|v| (*v as f64 - mean).powi(2)).sum::<f64>() / d as f64;
51 let inv = 1.0 / (var + 1e-5).sqrt();
52 for ((v, &g), &b) in row.iter_mut().zip(&self.gamma).zip(&self.beta) {
53 *v = ((*v as f64 - mean) * inv) as f32 * g + b;
54 }
55 }
56 }
57}
58
59struct Block {
60 pre_norm: LayerNorm,
61 qkv: Proj,
62 out: Proj,
63 ff_norm: LayerNorm,
64 ff_in: Proj,
65 ff_in_b: Vec<f32>,
66 ff_out: Proj,
67 ff_out_b: Vec<f32>,
68}
69
70impl Block {
71 fn load(model: &Arc<CmfModel>, p: &str) -> Result<Self, String> {
72 Ok(Self {
73 pre_norm: LayerNorm::load(model, &format!("{p}.pre_norm"))?,
74 qkv: Proj::from_model(model, &format!("{p}.self_attn.to_qkv.weight"))?,
75 out: Proj::from_model(model, &format!("{p}.self_attn.to_out.weight"))?,
76 ff_norm: LayerNorm::load(model, &format!("{p}.ff_norm"))?,
77 ff_in: Proj::from_model(model, &format!("{p}.ff.ff.0.proj.weight"))?,
78 ff_in_b: crate::dit::cmf_f32(model, &format!("{p}.ff.ff.0.proj.bias"))?,
79 ff_out: Proj::from_model(model, &format!("{p}.ff.ff.2.weight"))?,
80 ff_out_b: crate::dit::cmf_f32(model, &format!("{p}.ff.ff.2.bias"))?,
81 })
82 }
83}
84
85pub struct Music3Dit {
86 pre_conv: Vec<f32>, post_conv: Vec<f32>, fourier: Vec<f32>, t0: Proj,
90 t0_b: Vec<f32>,
91 t2: Proj,
92 t2_b: Vec<f32>,
93 project_in: Proj,
94 project_out: Proj,
95 inv_freq: Vec<f32>,
96 blocks: Vec<Block>,
97 pool: Option<Arc<Pool>>,
98 hidden: usize,
99 heads: usize,
100 hd: usize,
101 rot: usize,
102 inter: usize,
103 cond_logits: Vec<f32>,
106 cond_scale: f32,
107 lc_w: Vec<f32>,
108 lc_b: Vec<f32>,
109}
110
111impl Music3Dit {
112 pub const IN_CH: usize = 128;
113 pub const COND_CH: usize = 2048;
114 pub const CONCAT_CH: usize = 2304;
115
116 pub fn from_cmf(model: &Arc<CmfModel>) -> Result<Self, String> {
117 let cfg: serde_json::Value =
118 serde_json::from_slice(model.tensor_bytes("mdit.config_json").map_err(|e| e.to_string())?)
119 .map_err(|e| format!("mdit.config_json: {e}"))?;
120 let u = |k: &str, d: usize| cfg[k].as_u64().map(|v| v as usize).unwrap_or(d);
121 let nl = u("num_layers", 36);
122 let dt = "mdit.diffusion_transformer";
123 Ok(Self {
124 pre_conv: crate::dit::cmf_f32(model, &format!("{dt}.preprocess_conv.weight"))?,
125 post_conv: crate::dit::cmf_f32(model, &format!("{dt}.postprocess_conv.weight"))?,
126 fourier: crate::dit::cmf_f32(model, &format!("{dt}.timestep_features.weight"))?,
127 t0: Proj::from_model(model, &format!("{dt}.to_timestep_embed.0.weight"))?,
128 t0_b: crate::dit::cmf_f32(model, &format!("{dt}.to_timestep_embed.0.bias"))?,
129 t2: Proj::from_model(model, &format!("{dt}.to_timestep_embed.2.weight"))?,
130 t2_b: crate::dit::cmf_f32(model, &format!("{dt}.to_timestep_embed.2.bias"))?,
131 project_in: Proj::from_model(model, &format!("{dt}.transformer.project_in.weight"))?,
132 project_out: Proj::from_model(model, &format!("{dt}.transformer.project_out.weight"))?,
133 inv_freq: crate::dit::cmf_f32(model, &format!("{dt}.transformer.rotary_pos_emb.inv_freq"))?,
134 blocks: (0..nl)
135 .map(|i| Block::load(model, &format!("{dt}.transformer.layers.{i}")))
136 .collect::<Result<_, _>>()?,
137 pool: Pool::from_env(),
138 hidden: u("hidden", 2048),
139 heads: u("num_heads", 32),
140 hd: u("head_dim", 64),
141 rot: u("rotary_dim", 32),
142 inter: u("ff_inner", 8192),
143 cond_logits: crate::dit::cmf_f32(model, "mdit.cond_layer_logits")?,
144 cond_scale: crate::dit::cmf_f32(model, "mdit.cond_layer_scale")?[0],
145 lc_w: crate::dit::cmf_f32(model, "mdit.latent_conditioners.0.weight")?,
146 lc_b: crate::dit::cmf_f32(model, "mdit.latent_conditioners.0.bias")?,
147 })
148 }
149
150 pub fn latent_length(audio_frames: usize) -> usize {
153 ((audio_frames as f64 * 44100.0 / 24000.0 * 960.0 / 512.0) as usize).max(1)
154 }
155
156 pub fn aligned_condition(&self, hidden: &[f32], frames: usize) -> (Vec<f32>, usize) {
164 let levels = self.cond_logits.len();
165 let ar = hidden.len() / (frames * levels);
166 let mx = self.cond_logits.iter().cloned().fold(f32::MIN, f32::max);
167 let ex: Vec<f32> = self.cond_logits.iter().map(|v| (v - mx).exp()).collect();
168 let sum: f32 = ex.iter().sum();
169 let mut mixed = vec![0f32; ar * frames];
171 for t in 0..frames {
172 for l in 0..levels {
173 let w = ex[l] / sum * self.cond_scale;
174 let src = &hidden[(t * levels + l) * ar..(t * levels + l + 1) * ar];
175 for (c, &v) in src.iter().enumerate() {
176 mixed[c * frames + t] += w * v;
177 }
178 }
179 }
180 let out_ch = self.lc_b.len();
182 let mut conv = vec![0f32; out_ch * frames];
183 for o in 0..out_ch {
184 let dst = &mut conv[o * frames..(o + 1) * frames];
185 dst.fill(self.lc_b[o]);
186 for i in 0..ar {
187 let k = &self.lc_w[(o * ar + i) * 3..(o * ar + i + 1) * 3];
188 let src = &mixed[i * frames..(i + 1) * frames];
189 for t in 0..frames {
190 for (j, &kv) in k.iter().enumerate() {
191 let p = t as isize + j as isize - 1;
192 if p >= 0 && (p as usize) < frames {
193 dst[t] += kv * src[p as usize];
194 }
195 }
196 }
197 }
198 }
199 let l = Self::latent_length(frames);
200 let mut out = vec![0f32; out_ch * l];
201 for o in 0..out_ch {
202 for t in 0..l {
203 let s = (t * frames) / l.max(1);
204 out[o * l + t] = conv[o * frames + s.min(frames - 1)];
205 }
206 }
207 (out, l)
208 }
209
210 fn conv1x1_residual(w: &[f32], x: &mut [f32], ch: usize, n: usize) {
213 let mut acc = vec![0f32; ch * n];
214 for o in 0..ch {
215 let row = &w[o * ch..(o + 1) * ch];
216 let dst = &mut acc[o * n..(o + 1) * n];
217 for (i, &wv) in row.iter().enumerate() {
218 if wv == 0.0 {
219 continue;
220 }
221 for (d, &s) in dst.iter_mut().zip(&x[i * n..(i + 1) * n]) {
222 *d += wv * s;
223 }
224 }
225 }
226 for (d, a) in x.iter_mut().zip(&acc) {
227 *d += a;
228 }
229 }
230
231 fn timestep_embedding(&self, t: f32) -> Vec<f32> {
233 let half = self.fourier.len();
234 let mut feats = vec![0f32; half * 2];
235 for (i, &w) in self.fourier.iter().enumerate() {
236 let a = std::f32::consts::TAU * t * w;
237 feats[i] = a.cos();
238 feats[half + i] = a.sin();
239 }
240 let mut h = vec![0f32; self.t0_b.len()];
241 self.t0.matmat(&feats, 1, &mut h, self.pool.as_deref());
242 for (v, &b) in h.iter_mut().zip(&self.t0_b) {
243 *v = silu(*v + b);
244 }
245 let mut out = vec![0f32; self.t2_b.len()];
246 self.t2.matmat(&h, 1, &mut out, self.pool.as_deref());
247 for (v, &b) in out.iter_mut().zip(&self.t2_b) {
248 *v += b;
249 }
250 out
251 }
252
253 fn rope_packed(&self, qkv: &mut [f32], n: usize) {
263 let (hs, nh, hd) = (self.hidden, self.heads, self.hd);
264 let half = self.rot / 2;
265 let ptr = SendPtr(qkv.as_mut_ptr());
266 let work = |lo: usize, hi: usize| {
267 for p in lo..hi {
268 let base = p * 3 * hs;
269 for i in 0..half {
270 let (s, c) = (p as f32 * self.inv_freq[i]).sin_cos();
271 for h in 0..nh {
272 for off in [base + h * hd, base + hs + h * hd] {
273 let x = unsafe { ptr.row(off, hd) };
275 let (a, b) = (x[i], x[i + half]);
276 x[i] = a * c - b * s;
277 x[i + half] = a * s + b * c;
278 }
279 }
280 }
281 }
282 };
283 match self.pool.as_deref() {
284 Some(pl) => pl.run_rows(n, &work),
285 None => work(0, n),
286 }
287 }
288
289 fn block(&self, blk: &Block, x: &mut [f32], n: usize) {
291 let (hs, nh, hd) = (self.hidden, self.heads, self.hd);
292 let pool = self.pool.as_deref();
293 let mut h = x.to_vec();
294 blk.pre_norm.apply(&mut h, hs);
295 if std::env::var("CMF_MUSIC3_DEVATT").as_deref() != Ok("0") {
305 if let (Some((m1, i1)), Some((m2, i2))) = (
306 match &blk.qkv {
307 crate::dit::Proj::Q(q) => q.q4tp_mapped(),
308 _ => None,
309 },
310 match &blk.out {
311 crate::dit::Proj::Q(q) => q.q4tp_mapped(),
312 _ => None,
313 },
314 ) {
315 if std::sync::Arc::ptr_eq(m1, m2) {
316 let half = self.rot / 2;
317 let mut ang = vec![0f32; n * half];
318 for p in 0..n {
319 for (i, f) in self.inv_freq[..half].iter().enumerate() {
320 ang[p * half + i] = p as f32 * f;
321 }
322 }
323 let ones = vec![1.0f32; hd];
324 let scale = 1.0 / (hd as f32).sqrt();
325 let mut proj = vec![0f32; n * hs];
326 let _ta = prof::start();
327 if crate::gpu::dit_qkv_attn_out(
328 m1,
329 i1,
330 i2,
331 &h,
332 n,
333 hs,
334 nh,
335 hd,
336 scale,
337 (&ang, &ones, &ones, -1.0),
338 &mut proj,
339 ) {
340 prof::add(&prof::ATTN, _ta);
341 for (a, b) in x.iter_mut().zip(&proj) {
342 *a += b;
343 }
344 return self.block_ffn(blk, x, n);
345 }
346 }
347 }
348 }
349 let mut qkv = vec![0f32; n * 3 * hs];
350 let _t = prof::start();
351 blk.qkv.matmat(&h, n, &mut qkv, pool);
352 prof::add(&prof::QKV, _t);
353 self.rope_packed(&mut qkv, n);
358 let scale = 1.0 / (hd as f32).sqrt();
359 let mut attn = vec![0f32; n * hs];
360 let _ta = prof::start();
361 {
368 if crate::gpu::dit_attention_packed(&qkv, nh, n, hd, scale, None, &mut attn) {
374 prof::add(&prof::ATTN, _ta);
375 let mut proj = vec![0f32; n * hs];
376 let _t = prof::start();
377 blk.out.matmat(&attn, n, &mut proj, pool);
378 prof::add(&prof::OUT, _t);
379 for (a, b) in x.iter_mut().zip(&proj) {
380 *a += b;
381 }
382 return self.block_ffn(blk, x, n);
383 }
384 attn.fill(0.0);
385 }
386 let mut q = vec![0f32; n * hs];
388 let mut k = vec![0f32; n * hs];
389 let mut v = vec![0f32; n * hs];
390 for p in 0..n {
391 let s = &qkv[p * 3 * hs..(p + 1) * 3 * hs];
392 q[p * hs..(p + 1) * hs].copy_from_slice(&s[..hs]);
393 k[p * hs..(p + 1) * hs].copy_from_slice(&s[hs..2 * hs]);
394 v[p * hs..(p + 1) * hs].copy_from_slice(&s[2 * hs..]);
395 }
396 if crate::gpu::enabled_here() {
400 let mut qh = vec![0f32; n * hs];
401 let mut kh = vec![0f32; n * hs];
402 let mut vh = vec![0f32; n * hs];
403 for h in 0..nh {
404 for i in 0..n {
405 let (s, d) = (i * hs + h * hd, (h * n + i) * hd);
406 qh[d..d + hd].copy_from_slice(&q[s..s + hd]);
407 kh[d..d + hd].copy_from_slice(&k[s..s + hd]);
408 vh[d..d + hd].copy_from_slice(&v[s..s + hd]);
409 }
410 }
411 if crate::gpu::dit_attention(&qh, &kh, &vh, nh, nh, n, hd, scale, &mut attn) {
412 prof::add(&prof::ATTN, _ta);
413 let mut proj = vec![0f32; n * hs];
414 let _t = prof::start();
415 blk.out.matmat(&attn, n, &mut proj, pool);
416 prof::add(&prof::OUT, _t);
417 for (a, b) in x.iter_mut().zip(&proj) {
418 *a += b;
419 }
420 return self.block_ffn(blk, x, n);
421 }
422 attn.fill(0.0);
423 }
424 {
427 let ptr = SendPtr(attn.as_mut_ptr());
428 let work = |lo: usize, hi: usize| {
429 let mut scores = vec![0f32; n];
430 for hh in lo..hi {
431 for i in 0..n {
432 let qi = &q[i * hs + hh * hd..i * hs + hh * hd + hd];
433 let mut mx = f32::NEG_INFINITY;
434 for (j, sc) in scores.iter_mut().enumerate() {
435 let kj = &k[j * hs + hh * hd..j * hs + hh * hd + hd];
436 *sc = qi.iter().zip(kj).map(|(a, b)| a * b).sum::<f32>() * scale;
437 mx = mx.max(*sc);
438 }
439 let mut sum = 0.0;
440 for sc in scores.iter_mut() {
441 *sc = (*sc - mx).exp();
442 sum += *sc;
443 }
444 let inv = 1.0 / sum;
445 let dst = unsafe { ptr.row(i * hs + hh * hd, hd) };
447 for (j, &sc) in scores.iter().enumerate() {
448 let w = sc * inv;
449 let vj = &v[j * hs + hh * hd..j * hs + hh * hd + hd];
450 for (d, &vv) in dst.iter_mut().zip(vj) {
451 *d += w * vv;
452 }
453 }
454 }
455 }
456 };
457 match pool {
458 Some(p) => p.run_rows(nh, &work),
459 None => work(0, nh),
460 }
461 }
462 prof::add(&prof::ATTN, _ta);
463 let mut proj = vec![0f32; n * hs];
464 let _t = prof::start();
465 blk.out.matmat(&attn, n, &mut proj, pool);
466 prof::add(&prof::OUT, _t);
467 for (a, b) in x.iter_mut().zip(&proj) {
468 *a += b;
469 }
470 self.block_ffn(blk, x, n)
471 }
472
473 fn block_ffn(&self, blk: &Block, x: &mut [f32], n: usize) {
475 let _t = prof::start();
476 let hs = self.hidden;
477 let pool = self.pool.as_deref();
478 let mut h = x.to_vec();
479 blk.ff_norm.apply(&mut h, hs);
480 if std::env::var("CMF_MUSIC3_DEVFFN").as_deref() != Ok("0") {
486 if let (Some((m1, i1)), Some((m2, i2))) = (
487 match &blk.ff_in {
488 crate::dit::Proj::Q(q) => q.q4tp_mapped(),
489 _ => None,
490 },
491 match &blk.ff_out {
492 crate::dit::Proj::Q(q) => q.q4tp_mapped(),
493 _ => None,
494 },
495 ) {
496 if std::sync::Arc::ptr_eq(m1, m2) {
497 let mut ffo = vec![0f32; n * hs];
498 if crate::gpu::music3_ffn(
499 m1,
500 i1,
501 i2,
502 &h,
503 &blk.ff_in_b,
504 n,
505 hs,
506 self.inter,
507 &mut ffo,
508 ) {
509 for p in 0..n {
510 for j in 0..hs {
511 x[p * hs + j] += ffo[p * hs + j] + blk.ff_out_b[j];
512 }
513 }
514 prof::add(&prof::FFN, _t);
515 return;
516 }
517 }
518 }
519 }
520 let mut gu = vec![0f32; n * 2 * self.inter];
521 blk.ff_in.matmat(&h, n, &mut gu, pool);
522 let inter = self.inter;
527 let (vb, gb) = blk.ff_in_b.split_at(inter);
528 let mut act = vec![0f32; n * inter];
529 for p in 0..n {
530 let row = &gu[p * 2 * inter..(p + 1) * 2 * inter];
531 let (val, gate) = row.split_at(inter);
532 let dst = &mut act[p * inter..(p + 1) * inter];
533 for i in 0..inter {
534 dst[i] = (val[i] + vb[i]) * silu(gate[i] + gb[i]);
535 }
536 }
537 let mut ffo = vec![0f32; n * hs];
538 blk.ff_out.matmat(&act, n, &mut ffo, pool);
539 for p in 0..n {
540 for j in 0..hs {
541 x[p * hs + j] += ffo[p * hs + j] + blk.ff_out_b[j];
542 }
543 }
544 prof::add(&prof::FFN, _t);
545 }
546
547 pub const WINDOW: usize = 689;
553 pub const HOP: usize = 344;
554
555 pub fn forward_windowed(&self, x: &[f32], condition: &[f32], n: usize, t: f32) -> Vec<f32> {
558 if n <= Self::WINDOW {
559 return self.forward(x, condition, n, t);
560 }
561 let ch = Self::IN_CH;
562 let cc = Self::COND_CH;
563 let mut out = vec![0f32; ch * n];
564 let mut count = vec![0f32; n];
565 let mut start = 0usize;
566 loop {
567 let end = (start + Self::WINDOW).min(n);
568 let w = end - start;
569 let mut xw = vec![0f32; ch * w];
570 for c in 0..ch {
571 xw[c * w..(c + 1) * w].copy_from_slice(&x[c * n + start..c * n + end]);
572 }
573 let mut cw = vec![0f32; cc * w];
574 for c in 0..cc {
575 cw[c * w..(c + 1) * w].copy_from_slice(&condition[c * n + start..c * n + end]);
576 }
577 let v = self.forward(&xw, &cw, w, t);
578 for c in 0..ch {
579 for i in 0..w {
580 out[c * n + start + i] += v[c * w + i];
581 }
582 }
583 for i in 0..w {
584 count[start + i] += 1.0;
585 }
586 if end == n {
587 break;
588 }
589 start += Self::HOP;
590 }
591 for c in 0..ch {
592 for i in 0..n {
593 out[c * n + i] /= count[i];
594 }
595 }
596 out
597 }
598
599 pub fn forward(&self, x: &[f32], condition: &[f32], n: usize, t: f32) -> Vec<f32> {
602 let pool = self.pool.as_deref();
603 let mut full = vec![0f32; Self::CONCAT_CH * n];
604 full[..Self::IN_CH * n].copy_from_slice(x);
605 full[2 * Self::IN_CH * n..].copy_from_slice(condition);
607 Self::conv1x1_residual(&self.pre_conv, &mut full, Self::CONCAT_CH, n);
608
609 let mut toks = vec![0f32; n * Self::CONCAT_CH];
611 for c in 0..Self::CONCAT_CH {
612 for p in 0..n {
613 toks[p * Self::CONCAT_CH + c] = full[c * n + p];
614 }
615 }
616 let mut h = vec![0f32; n * self.hidden];
617 self.project_in.matmat(&toks, n, &mut h, pool);
618
619 let temb = self.timestep_embedding(t);
621 let mut seq = vec![0f32; (n + 1) * self.hidden];
622 seq[..self.hidden].copy_from_slice(&temb);
623 seq[self.hidden..].copy_from_slice(&h);
624 for blk in &self.blocks {
625 self.block(blk, &mut seq, n + 1);
626 }
627
628 let mut out = vec![0f32; n * Self::IN_CH];
629 self.project_out
630 .matmat(&seq[self.hidden..], n, &mut out, pool);
631 let mut ch = vec![0f32; Self::IN_CH * n];
632 for c in 0..Self::IN_CH {
633 for p in 0..n {
634 ch[c * n + p] = out[p * Self::IN_CH + c];
635 }
636 }
637 Self::conv1x1_residual(&self.post_conv, &mut ch, Self::IN_CH, n);
638 for v in ch.iter_mut() {
639 *v = -*v;
640 }
641 ch
642 }
643
644 pub fn sample(
647 &self,
648 noise: &[f32],
649 condition: &[f32],
650 n: usize,
651 steps: usize,
652 mut progress: impl FnMut(usize, usize),
653 ) -> Vec<f32> {
654 let sigmas = flow_sigmas(steps);
655 let mut x = noise.to_vec();
656 for i in 0..steps {
657 let (s, s_next) = (sigmas[i], sigmas[i + 1]);
658 let v = self.forward_windowed(&x, condition, n, 1.0 - s);
660 let dt = s_next - s;
661 for (a, b) in x.iter_mut().zip(&v) {
662 *a += dt * b;
663 }
664 progress(i + 1, steps);
665 }
666 x
667 }
668}
669
670pub fn flow_sigmas(steps: usize) -> Vec<f32> {
693 const SIGMA_MIN: f32 = 0.001;
694 let n = steps.max(1);
695 let mut s: Vec<f32> = (0..n)
696 .map(|i| {
697 if n == 1 {
698 1.0
699 } else {
700 1.0 + (SIGMA_MIN - 1.0) * i as f32 / (n - 1) as f32
701 }
702 })
703 .collect();
704 s.push(0.0);
705 s
706}
707
708struct RmsNorm {
710 w: Vec<f32>,
711}
712
713impl RmsNorm {
714 fn load(model: &Arc<CmfModel>, n: &str) -> Result<Self, String> {
715 Ok(Self {
716 w: crate::dit::cmf_f32(model, n)?,
717 })
718 }
719
720 fn apply(&self, x: &mut [f32], d: usize) {
721 for row in x.chunks_exact_mut(d) {
722 let ss = row.iter().map(|v| (*v as f64) * (*v as f64)).sum::<f64>() / d as f64;
723 let inv = 1.0 / (ss + 1e-6).sqrt();
724 for (v, &g) in row.iter_mut().zip(&self.w) {
725 *v = (*v as f64 * inv) as f32 * g;
726 }
727 }
728 }
729}
730
731struct RvqBlock {
732 n1: RmsNorm,
733 q: Proj,
734 k: Proj,
735 v: Proj,
736 o: Proj,
737 n2: RmsNorm,
738 gate: Proj,
739 up: Proj,
740 down: Proj,
741}
742
743impl RvqBlock {
744 fn load(model: &Arc<CmfModel>, p: &str) -> Result<Self, String> {
745 Ok(Self {
746 n1: RmsNorm::load(model, &format!("{p}.input_layernorm.weight"))?,
747 q: Proj::from_model(model, &format!("{p}.self_attn.q_proj.weight"))?,
748 k: Proj::from_model(model, &format!("{p}.self_attn.k_proj.weight"))?,
749 v: Proj::from_model(model, &format!("{p}.self_attn.v_proj.weight"))?,
750 o: Proj::from_model(model, &format!("{p}.self_attn.o_proj.weight"))?,
751 n2: RmsNorm::load(model, &format!("{p}.post_attention_layernorm.weight"))?,
752 gate: Proj::from_model(model, &format!("{p}.mlp.gate_proj.weight"))?,
753 up: Proj::from_model(model, &format!("{p}.mlp.up_proj.weight"))?,
754 down: Proj::from_model(model, &format!("{p}.mlp.down_proj.weight"))?,
755 })
756 }
757}
758
759pub struct RvqDepthDecoder {
767 projection: Proj,
768 pos: Vec<f32>,
769 blocks: Vec<RvqBlock>,
770 norm: RmsNorm,
771 heads: Vec<Proj>,
772 pool: Option<Arc<Pool>>,
773 hidden: usize,
774 nh: usize,
775 hd: usize,
776 inter: usize,
777}
778
779impl RvqDepthDecoder {
780 pub fn from_cmf(model: &Arc<CmfModel>) -> Result<Self, String> {
781 let cfg: serde_json::Value =
782 serde_json::from_slice(model.tensor_bytes("mte.config_json").map_err(|e| e.to_string())?)
783 .map_err(|e| format!("mte.config_json: {e}"))?;
784 let u = |k: &str, d: usize| cfg[k].as_u64().map(|v| v as usize).unwrap_or(d);
785 let hidden = u("hidden_size", 4096);
786 let nl = u("decoder_num_layers", 4);
787 let nh = u("decoder_num_heads", 16);
788 let cb = u("audio_num_codebooks", 8);
789 Ok(Self {
790 projection: Proj::from_model(model, "mte.audio_decoder.projection.weight")?,
791 pos: crate::dit::cmf_f32(model, "mte.audio_decoder.pos_embedding.weight")?,
792 blocks: (0..nl)
793 .map(|i| RvqBlock::load(model, &format!("mte.audio_decoder.layers.{i}")))
794 .collect::<Result<_, _>>()?,
795 norm: RmsNorm::load(model, "mte.audio_decoder.norm.weight")?,
796 heads: (0..cb - 1)
797 .map(|i| {
798 Proj::from_model(model, &format!("mte.audio_decoder.audio_heads.{i}.weight"))
799 })
800 .collect::<Result<_, _>>()?,
801 pool: Pool::from_env(),
802 hidden,
803 nh,
804 hd: hidden / nh,
805 inter: u("decoder_intermediate_size", 6144),
806 })
807 }
808
809 pub fn codebooks(&self) -> usize {
810 self.heads.len() + 1
811 }
812
813 pub fn project(&self, x: &[f32]) -> Vec<f32> {
816 let n = x.len() / self.hidden;
817 let mut out = vec![0f32; n * self.hidden];
818 self.projection
819 .matmat(x, n, &mut out, self.pool.as_deref());
820 out
821 }
822
823 pub fn forward_last(&self, seq: &[f32], n: usize) -> Vec<f32> {
826 let (hs, nh, hd) = (self.hidden, self.nh, self.hd);
827 let pool = self.pool.as_deref();
828 let mut x = seq.to_vec();
829 for p in 0..n {
830 for (v, &pe) in x[p * hs..(p + 1) * hs].iter_mut().zip(&self.pos[p * hs..(p + 1) * hs]) {
831 *v += pe;
832 }
833 }
834 for blk in &self.blocks {
835 let mut h = x.clone();
836 blk.n1.apply(&mut h, hs);
837 let (mut q, mut k, mut v) = (vec![0f32; n * hs], vec![0f32; n * hs], vec![0f32; n * hs]);
838 blk.q.matmat(&h, n, &mut q, pool);
839 blk.k.matmat(&h, n, &mut k, pool);
840 blk.v.matmat(&h, n, &mut v, pool);
841 let scale = 1.0 / (hd as f32).sqrt();
842 let mut attn = vec![0f32; n * hs];
843 for hh in 0..nh {
844 for i in 0..n {
845 let qi = &q[i * hs + hh * hd..i * hs + hh * hd + hd];
846 let mut sc = vec![0f32; i + 1];
848 let mut mx = f32::NEG_INFINITY;
849 for (j, s) in sc.iter_mut().enumerate() {
850 let kj = &k[j * hs + hh * hd..j * hs + hh * hd + hd];
851 *s = qi.iter().zip(kj).map(|(a, b)| a * b).sum::<f32>() * scale;
852 mx = mx.max(*s);
853 }
854 let mut sum = 0.0;
855 for s in sc.iter_mut() {
856 *s = (*s - mx).exp();
857 sum += *s;
858 }
859 let inv = 1.0 / sum;
860 let dst = &mut attn[i * hs + hh * hd..i * hs + hh * hd + hd];
861 for (j, &s) in sc.iter().enumerate() {
862 let w = s * inv;
863 let vj = &v[j * hs + hh * hd..j * hs + hh * hd + hd];
864 for (d, &vv) in dst.iter_mut().zip(vj) {
865 *d += w * vv;
866 }
867 }
868 }
869 }
870 let mut proj = vec![0f32; n * hs];
871 blk.o.matmat(&attn, n, &mut proj, pool);
872 for (a, b) in x.iter_mut().zip(&proj) {
873 *a += b;
874 }
875
876 let mut h = x.clone();
877 blk.n2.apply(&mut h, hs);
878 let (mut g, mut u) = (vec![0f32; n * self.inter], vec![0f32; n * self.inter]);
879 blk.gate.matmat(&h, n, &mut g, pool);
880 blk.up.matmat(&h, n, &mut u, pool);
881 for (a, b) in g.iter_mut().zip(&u) {
882 *a = silu(*a) * b;
883 }
884 let mut ffo = vec![0f32; n * hs];
885 blk.down.matmat(&g, n, &mut ffo, pool);
886 for (a, b) in x.iter_mut().zip(&ffo) {
887 *a += b;
888 }
889 }
890 let mut last = x[(n - 1) * hs..].to_vec();
891 self.norm.apply(&mut last, hs);
892 last
893 }
894
895 pub fn head(&self, level: usize, hidden: &[f32]) -> Vec<f32> {
897 let h = &self.heads[level - 1];
898 let rows = match h {
899 Proj::F32 { rows, .. } => *rows,
900 Proj::Q(q) => q.rows(),
901 };
902 let mut out = vec![0f32; rows];
903 h.matmat(hidden, 1, &mut out, self.pool.as_deref());
904 out
905 }
906}
907
908struct ArBlock {
913 n1: RmsNorm,
914 q: Proj,
915 k: Proj,
916 v: Proj,
917 o: Proj,
918 qn: RmsNorm,
919 kn: RmsNorm,
920 n2: RmsNorm,
921 gate: Proj,
922 up: Proj,
923 down: Proj,
924}
925
926impl ArBlock {
927 fn load(model: &Arc<CmfModel>, p: &str) -> Result<Self, String> {
928 Ok(Self {
929 n1: RmsNorm::load(model, &format!("{p}.input_layernorm.weight"))?,
930 q: Proj::from_model(model, &format!("{p}.self_attn.q_proj.weight"))?,
931 k: Proj::from_model(model, &format!("{p}.self_attn.k_proj.weight"))?,
932 v: Proj::from_model(model, &format!("{p}.self_attn.v_proj.weight"))?,
933 o: Proj::from_model(model, &format!("{p}.self_attn.o_proj.weight"))?,
934 qn: RmsNorm::load(model, &format!("{p}.self_attn.q_norm.weight"))?,
935 kn: RmsNorm::load(model, &format!("{p}.self_attn.k_norm.weight"))?,
936 n2: RmsNorm::load(model, &format!("{p}.post_attention_layernorm.weight"))?,
937 gate: Proj::from_model(model, &format!("{p}.mlp.gate_proj.weight"))?,
938 up: Proj::from_model(model, &format!("{p}.mlp.up_proj.weight"))?,
939 down: Proj::from_model(model, &format!("{p}.mlp.down_proj.weight"))?,
940 })
941 }
942}
943
944#[derive(Default, Clone)]
951struct KvRun {
952 k: Vec<Vec<f32>>,
953 v: Vec<Vec<f32>>,
954 len: usize,
955}
956
957impl KvRun {
958 fn init(nkv: usize) -> Self {
959 Self {
960 k: vec![Vec::new(); nkv],
961 v: vec![Vec::new(); nkv],
962 len: 0,
963 }
964 }
965}
966
967struct Rng(u64);
974
975impl Rng {
976 fn new(seed: u64) -> Self {
977 Self(seed.wrapping_mul(0x9E37_79B9_7F4A_7C15) | 1)
978 }
979 fn next_f32(&mut self) -> f32 {
980 let mut x = self.0;
981 x ^= x << 13;
982 x ^= x >> 7;
983 x ^= x << 17;
984 self.0 = x;
985 ((x >> 40) as f32) / (1u32 << 24) as f32
986 }
987}
988
989fn sample_topk(logits: &[f32], top_k: usize, rng: &mut Rng) -> usize {
990 let mut idx: Vec<usize> = (0..logits.len()).filter(|&i| logits[i].is_finite()).collect();
991 idx.sort_unstable_by(|&a, &b| logits[b].partial_cmp(&logits[a]).unwrap());
992 idx.truncate(top_k.max(1));
993 let mx = idx.iter().map(|&i| logits[i]).fold(f32::MIN, f32::max);
994 let exps: Vec<f32> = idx.iter().map(|&i| (logits[i] - mx).exp()).collect();
995 let sum: f32 = exps.iter().sum();
996 let mut r = rng.next_f32() * sum;
997 for (j, &e) in exps.iter().enumerate() {
998 r -= e;
999 if r <= 0.0 {
1000 return idx[j];
1001 }
1002 }
1003 *idx.last().unwrap()
1004}
1005
1006pub struct Music3Ar {
1010 blocks: Vec<ArBlock>,
1011 norm: RmsNorm,
1012 embed_prefill: QTensor,
1013 embed_audio: QTensor,
1014 embed_extra: QTensor,
1015 lm_head: Proj,
1016 pub depth: RvqDepthDecoder,
1017 inv_freq: Vec<f32>,
1018 pool: Option<Arc<Pool>>,
1019 hidden: usize,
1020 nh: usize,
1021 nkv: usize,
1022 hd: usize,
1023 inter: usize,
1024 audio_vocab: usize,
1025 codebooks: usize,
1026 pub cfg_scale: f32,
1027 pub top_k: usize,
1028 pub fps: usize,
1029 pub max_frames: usize,
1030}
1031
1032pub mod tokens {
1034 pub const IM_START: u32 = 151644;
1035 pub const IM_END: u32 = 151645;
1036 pub const AUDIO_CFG: u32 = 151654;
1037 pub const AUDIO_START: u32 = 151669;
1038 pub const CAPTION_START: u32 = 151671;
1039 pub const CAPTION_END: u32 = 151672;
1040 pub const LYRICS_START: u32 = 151673;
1041 pub const LYRICS_END: u32 = 151674;
1042}
1043
1044impl Music3Ar {
1045 pub fn from_cmf(model: &Arc<CmfModel>) -> Result<Self, String> {
1046 let cfg: serde_json::Value =
1047 serde_json::from_slice(model.tensor_bytes("mte.config_json").map_err(|e| e.to_string())?)
1048 .map_err(|e| format!("mte.config_json: {e}"))?;
1049 let u = |k: &str, d: usize| cfg[k].as_u64().map(|v| v as usize).unwrap_or(d);
1050 let f = |k: &str, d: f64| cfg[k].as_f64().unwrap_or(d);
1051 let hidden = u("hidden_size", 4096);
1052 let hd = u("head_dim", 128);
1053 let theta = f("rope_theta", 1_000_000.0) as f32;
1054 Ok(Self {
1055 blocks: (0..u("num_hidden_layers", 36))
1056 .map(|i| ArBlock::load(model, &format!("mte.layers.{i}")))
1057 .collect::<Result<_, _>>()?,
1058 norm: RmsNorm::load(model, "mte.norm.weight")?,
1059 embed_prefill: QTensor::from_model(model, "mte.embed_tokens_prefill.weight")?,
1060 embed_audio: QTensor::from_model(model, "mte.embed_tokens_audio.weight")?,
1061 embed_extra: QTensor::from_model(model, "mte.audio_extra_embedding.weight")?,
1062 lm_head: Proj::from_model(model, "mte.lm_head_pruned.weight")?,
1063 depth: RvqDepthDecoder::from_cmf(model)?,
1064 inv_freq: (0..hd / 2)
1065 .map(|i| 1.0 / theta.powf(2.0 * i as f32 / hd as f32))
1066 .collect(),
1067 pool: Pool::from_env(),
1068 hidden,
1069 nh: u("num_attention_heads", 32),
1070 nkv: u("num_key_value_heads", 8),
1071 hd,
1072 inter: u("intermediate_size", 12288),
1073 audio_vocab: u("audio_vocab_size", 1024),
1074 codebooks: u("audio_num_codebooks", 8),
1075 cfg_scale: f("cfg_scale", 1.5) as f32,
1076 top_k: u("top_k", 50),
1077 fps: u("audio_frames_per_second", 25),
1078 max_frames: u("max_audio_frames", 9000),
1079 })
1080 }
1081
1082 fn embed_row(p: &QTensor, row: usize, hidden: usize) -> Vec<f32> {
1085 let mut out = vec![0f32; hidden];
1086 p.row_f32(row, &mut out);
1087 out
1088 }
1089
1090 #[allow(clippy::type_complexity)]
1104 fn graph_step(
1105 &self,
1106 x: &mut [f32],
1107 pos: usize,
1108 cap: usize,
1109 cache: &mut [Vec<KvRun>],
1110 logits: &mut [Vec<f32>; 2],
1111 ) -> bool {
1112 let hs = self.hidden;
1113 let Some((model, _)) = self.blocks.first().and_then(|b| b.q.graph_w()) else {
1114 return false;
1115 };
1116 let model = model.clone();
1117 let Some((_, lm)) = self.lm_head.graph_w() else {
1118 return false;
1119 };
1120 let lm_rows = self.lm_head_rows();
1121 let mut staged: [(Vec<f32>, Vec<f32>); 2] = Default::default();
1122 for bi in 0..2 {
1123 let mut layers: Vec<crate::gpu::GraphLayer> = Vec::with_capacity(self.blocks.len());
1124 for (li, blk) in self.blocks.iter().enumerate() {
1125 let (Some((_, wq)), Some((_, wk)), Some((_, wv)), Some((_, wo))) = (
1126 blk.q.graph_w(),
1127 blk.k.graph_w(),
1128 blk.v.graph_w(),
1129 blk.o.graph_w(),
1130 ) else {
1131 return false;
1132 };
1133 let (Some((_, g)), Some((_, u)), Some((_, d))) = (
1134 blk.gate.graph_w(),
1135 blk.up.graph_w(),
1136 blk.down.graph_w(),
1137 ) else {
1138 return false;
1139 };
1140 layers.push(crate::gpu::GraphLayer {
1141 input_norm: &blk.n1.w,
1142 attn: crate::gpu::GraphAttn::Full {
1143 wq,
1144 wk,
1145 wv,
1146 wo,
1147 q_norm: Some(&blk.qn.w),
1148 k_norm: Some(&blk.kn.w),
1149 bias: None,
1150 output_gate: false,
1151 cpu_k: &cache[li][bi].k,
1152 cpu_v: &cache[li][bi].v,
1153 },
1154 post_norm: &blk.n2.w,
1155 ffn: crate::gpu::GraphFfn::Dense {
1156 gate: g,
1157 up: u,
1158 down: d,
1159 },
1160 });
1161 }
1162 let mut h = x[bi * hs..(bi + 1) * hs].to_vec();
1163 let mut out = Vec::new();
1164 let ok = crate::gpu::forward_token_graph(
1165 &model,
1166 bi as u64,
1167 &layers,
1168 &[],
1169 0,
1170 &self.inv_freq,
1171 &mut h,
1172 self.nh,
1173 self.nkv,
1174 self.hd,
1175 self.hd,
1176 hs,
1177 self.inter,
1178 pos,
1179 cap,
1180 false,
1181 1e-6,
1182 Some((&lm, lm_rows)),
1183 &self.norm.w,
1184 &mut out,
1185 &[],
1186 1,
1187 None,
1188 None,
1189 None,
1190 0,
1191 );
1192 if !ok || out.len() < lm_rows {
1193 return false;
1194 }
1195 staged[bi] = (h, out);
1196 }
1197 for (bi, (h, out)) in staged.into_iter().enumerate() {
1201 x[bi * hs..(bi + 1) * hs].copy_from_slice(&h);
1202 logits[bi] = out;
1203 }
1204 true
1205 }
1206
1207 fn step_blocks(&self, x: &mut [f32], b: usize, pos: usize, cache: &mut [Vec<KvRun>]) {
1210 let (hs, nh, nkv, hd) = (self.hidden, self.nh, self.nkv, self.hd);
1211 let pool = self.pool.as_deref();
1212 let kvw = nkv * hd;
1213 for (li, blk) in self.blocks.iter().enumerate() {
1214 let mut h = x.to_vec();
1215 blk.n1.apply(&mut h, hs);
1216 let mut q = vec![0f32; b * nh * hd];
1217 let mut k = vec![0f32; b * kvw];
1218 let mut v = vec![0f32; b * kvw];
1219 blk.q.matmat(&h, b, &mut q, pool);
1220 blk.k.matmat(&h, b, &mut k, pool);
1221 blk.v.matmat(&h, b, &mut v, pool);
1222 for bi in 0..b {
1225 for hh in 0..nh {
1226 let s = bi * nh * hd + hh * hd;
1227 blk.qn.apply(&mut q[s..s + hd], hd);
1228 rope_half(&mut q[s..s + hd], pos, &self.inv_freq);
1229 }
1230 for hh in 0..nkv {
1231 let s = bi * kvw + hh * hd;
1232 blk.kn.apply(&mut k[s..s + hd], hd);
1233 rope_half(&mut k[s..s + hd], pos, &self.inv_freq);
1234 }
1235 }
1236 let mut attn = vec![0f32; b * nh * hd];
1237 let per_kv = nh / nkv;
1238 for bi in 0..b {
1239 let run = &mut cache[li][bi];
1240 for g in 0..nkv {
1241 run.k[g].extend_from_slice(&k[bi * kvw + g * hd..bi * kvw + (g + 1) * hd]);
1242 run.v[g].extend_from_slice(&v[bi * kvw + g * hd..bi * kvw + (g + 1) * hd]);
1243 }
1244 run.len += 1;
1245 let n = run.len;
1246 let scale = 1.0 / (hd as f32).sqrt();
1247 for hh in 0..nh {
1248 let g = hh / per_kv;
1249 let qi = &q[bi * nh * hd + hh * hd..bi * nh * hd + hh * hd + hd];
1250 let mut sc = vec![0f32; n];
1251 let mut mx = f32::NEG_INFINITY;
1252 for (j, s) in sc.iter_mut().enumerate() {
1253 let kj = &run.k[g][j * hd..(j + 1) * hd];
1254 *s = qi.iter().zip(kj).map(|(a, c)| a * c).sum::<f32>() * scale;
1255 mx = mx.max(*s);
1256 }
1257 let mut sum = 0.0;
1258 for s in sc.iter_mut() {
1259 *s = (*s - mx).exp();
1260 sum += *s;
1261 }
1262 let inv = 1.0 / sum;
1263 let dst = &mut attn[bi * nh * hd + hh * hd..bi * nh * hd + hh * hd + hd];
1264 for (j, &s) in sc.iter().enumerate() {
1265 let w = s * inv;
1266 let vj = &run.v[g][j * hd..(j + 1) * hd];
1267 for (d, &vv) in dst.iter_mut().zip(vj) {
1268 *d += w * vv;
1269 }
1270 }
1271 }
1272 }
1273 let mut proj = vec![0f32; b * hs];
1274 blk.o.matmat(&attn, b, &mut proj, pool);
1275 for (a, c) in x.iter_mut().zip(&proj) {
1276 *a += c;
1277 }
1278 let mut h = x.to_vec();
1279 blk.n2.apply(&mut h, hs);
1280 let (mut g, mut u2) = (vec![0f32; b * self.inter], vec![0f32; b * self.inter]);
1281 blk.gate.matmat(&h, b, &mut g, pool);
1282 blk.up.matmat(&h, b, &mut u2, pool);
1283 for (a, c) in g.iter_mut().zip(&u2) {
1284 *a = silu(*a) * c;
1285 }
1286 let mut ffo = vec![0f32; b * hs];
1287 blk.down.matmat(&g, b, &mut ffo, pool);
1288 for (a, c) in x.iter_mut().zip(&ffo) {
1289 *a += c;
1290 }
1291 }
1292 }
1293
1294 pub fn generate(
1301 &self,
1302 prompt_ids: &[u32],
1303 seed: u64,
1304 frames: usize,
1305 mut progress: impl FnMut(usize, usize),
1306 ) -> Result<(Vec<f32>, usize), String> {
1307 let hs = self.hidden;
1308 let pool = self.pool.as_deref();
1309 let want = frames.min(self.max_frames);
1310 let mut cache: Vec<Vec<KvRun>> = (0..self.blocks.len())
1311 .map(|_| vec![KvRun::init(self.nkv); 2])
1312 .collect();
1313 let mut uncond = prompt_ids.to_vec();
1315 if uncond.len() > 3 {
1316 let n = uncond.len();
1317 for t in uncond[1..n - 2].iter_mut() {
1318 *t = tokens::AUDIO_CFG;
1319 }
1320 }
1321 let cap = prompt_ids.len() + want + 2;
1322 let mut graph = std::env::var("CMF_MUSIC3_GRAPH").as_deref() == Ok("1");
1335 let mut glogits: [Vec<f32>; 2] = Default::default();
1336 let mut last = vec![0f32; 2 * hs];
1337 for (pos, (&a, &b)) in prompt_ids.iter().zip(&uncond).enumerate() {
1338 let mut x = vec![0f32; 2 * hs];
1339 x[..hs].copy_from_slice(&Self::embed_row(&self.embed_prefill, a as usize, hs));
1340 x[hs..].copy_from_slice(&Self::embed_row(&self.embed_prefill, b as usize, hs));
1341 if graph {
1342 if self.graph_step(&mut x, pos, cap, &mut cache, &mut glogits) {
1343 last = x;
1344 if pos % 64 == 0 {
1345 progress(0, want);
1346 }
1347 continue;
1348 }
1349 if pos > 0 {
1352 return Err("the token graph refused mid-prefill".into());
1353 }
1354 graph = false;
1355 }
1356 self.step_blocks(&mut x, 2, pos, &mut cache);
1357 last = x;
1358 if pos % 64 == 0 {
1359 progress(0, want);
1360 }
1361 }
1362 let mut rng = Rng::new(seed);
1363 let mut out: Vec<f32> = Vec::with_capacity(want * self.codebooks * hs);
1364 let mut done = 0usize;
1365 let scale = (self.codebooks as f32).powf(-0.5);
1366 for frame in 0..want {
1367 let mut normed = last.clone();
1368 self.norm.apply(&mut normed, hs);
1369 let vocab = self.lm_head_rows();
1374 let mut logits = vec![0f32; 2 * vocab];
1375 if graph {
1376 logits[..vocab].copy_from_slice(&glogits[0][..vocab]);
1377 logits[vocab..].copy_from_slice(&glogits[1][..vocab]);
1378 } else {
1379 self.lm_head.matmat(&normed, 2, &mut logits, pool);
1380 }
1381 let (cond, unc) = logits.split_at(vocab);
1382 let mut thr: Vec<f32> = cond.to_vec();
1383 thr.sort_unstable_by(|a, b| b.partial_cmp(a).unwrap());
1384 let cut = thr[self.top_k.min(vocab) - 1];
1385 let guided: Vec<f32> = (0..vocab)
1386 .map(|i| {
1387 if cond[i] < cut {
1388 f32::NEG_INFINITY
1389 } else {
1390 unc[i] + (cond[i] - unc[i]) * self.cfg_scale
1391 }
1392 })
1393 .collect();
1394 let code = sample_topk(&guided, self.top_k, &mut rng);
1395 if code == 0 {
1396 break; }
1398 let c0 = code - 1;
1399 let c0_embed = Self::embed_row(&self.embed_audio, c0, hs);
1400 let mut seq = self.depth.project(&normed[..hs]);
1403 seq.extend_from_slice(&self.depth.project(&c0_embed));
1404 let mut codes = vec![c0];
1405 let mut frame_hidden = normed[..hs].to_vec();
1406 for level in 1..self.codebooks {
1407 let n = seq.len() / hs;
1408 let h = self.depth.forward_last(&seq, n);
1409 frame_hidden.extend_from_slice(&h);
1410 let lg = self.depth.head(level, &h);
1411 let c = sample_topk(&lg, self.top_k, &mut rng);
1412 codes.push(c);
1413 if level < self.codebooks - 1 {
1414 let e = Self::embed_row(&self.embed_extra, c + (level - 1) * self.audio_vocab, hs);
1415 seq.extend_from_slice(&self.depth.project(&e));
1416 }
1417 }
1418 out.extend_from_slice(&frame_hidden);
1419 done += 1;
1420 progress(done, want);
1421 if done >= want {
1422 break;
1423 }
1424 let mut fb = Self::embed_row(&self.embed_audio, codes[0], hs);
1427 for (level, &c) in codes.iter().enumerate().skip(1) {
1428 let e = Self::embed_row(&self.embed_extra, c + (level - 1) * self.audio_vocab, hs);
1429 for (a, b) in fb.iter_mut().zip(&e) {
1430 *a += b;
1431 }
1432 }
1433 for a in fb.iter_mut() {
1434 *a *= scale;
1435 }
1436 let mut x = vec![0f32; 2 * hs];
1437 x[..hs].copy_from_slice(&fb);
1438 x[hs..].copy_from_slice(&fb);
1439 let pos = prompt_ids.len() + frame;
1440 if !graph || !self.graph_step(&mut x, pos, cap, &mut cache, &mut glogits) {
1441 if graph {
1442 return Err("the token graph refused mid-song".into());
1443 }
1444 self.step_blocks(&mut x, 2, pos, &mut cache);
1445 }
1446 last = x;
1447 }
1448 if done == 0 {
1449 return Err("MiniMax-Music-3 generated zero audio frames".into());
1450 }
1451 Ok((out, done))
1452 }
1453
1454 fn lm_head_rows(&self) -> usize {
1455 match &self.lm_head {
1456 Proj::F32 { rows, .. } => *rows,
1457 Proj::Q(q) => q.rows(),
1458 }
1459 }
1460}
1461
1462fn rope_half(x: &mut [f32], pos: usize, inv_freq: &[f32]) {
1464 let half = x.len() / 2;
1465 for i in 0..half {
1466 let (s, c) = (pos as f32 * inv_freq[i]).sin_cos();
1467 let (a, b) = (x[i], x[i + half]);
1468 x[i] = a * c - b * s;
1469 x[i + half] = b * c + a * s;
1470 }
1471}
1472
1473#[cfg(test)]
1474mod tests {
1475 use super::*;
1476
1477 #[test]
1484 fn music3_sampler_and_vocoder_compose() {
1485 let Ok(p) = std::env::var("CMF_MUSIC3_DIT") else {
1486 eprintln!("CMF_MUSIC3_DIT unset — skipping Music-3 chain test");
1487 return;
1488 };
1489 let model = Arc::new(CmfModel::open(&p).expect("open pack"));
1490 let dit = Music3Dit::from_cmf(&model).expect("load DiT");
1491 let dav = crate::audiovae::Music3Dav::from_cmf(&model).expect("load DAV");
1492 let n = 6usize;
1493 let noise: Vec<f32> = (0..Music3Dit::IN_CH * n)
1495 .map(|i| (((i * 2654435761) % 1000) as f32 / 500.0) - 1.0)
1496 .collect();
1497 let cond = vec![0f32; Music3Dit::COND_CH * n];
1498 let steps = 3;
1499 let mut seen = 0usize;
1500 let latent = dit.sample(&noise, &cond, n, steps, |i, t| {
1501 assert_eq!(t, steps);
1502 seen = i;
1503 });
1504 assert_eq!(seen, steps, "sampler reported every step");
1505 assert_eq!(latent.len(), Music3Dit::IN_CH * n);
1506 assert!(latent.iter().all(|v| v.is_finite()), "latent went non-finite");
1507 let pcm = dav.decode(&latent, n, None);
1508 assert_eq!(
1509 pcm.len(),
1510 n * crate::audiovae::Music3Dav::HOP * 2,
1511 "the chain's sample count is frames x 512 x 2"
1512 );
1513 assert!(pcm.iter().all(|v| v.is_finite() && v.abs() <= 1.0));
1514 let secs = (n * crate::audiovae::Music3Dav::HOP) as f32
1515 / crate::audiovae::Music3Dav::SAMPLE_RATE as f32;
1516 eprintln!(
1517 "music3 chain: {n} frames -> {} stereo samples ({secs:.3} s at 44.1 kHz)",
1518 pcm.len() / 2
1519 );
1520 }
1521
1522 #[test]
1527 fn music3_rvq_depth_decoder_is_causal() {
1528 let Ok(p) = std::env::var("CMF_MUSIC3_TE") else {
1529 eprintln!("CMF_MUSIC3_TE unset — skipping RVQ decoder test");
1530 return;
1531 };
1532 let model = Arc::new(CmfModel::open(&p).expect("open packed AR stack"));
1533 let dec = RvqDepthDecoder::from_cmf(&model).expect("load RVQ decoder");
1534 assert_eq!(dec.codebooks(), 8, "eight codebooks");
1535 let hs = dec.hidden;
1536 let seq: Vec<f32> = (0..3 * hs).map(|i| 0.05 * ((i as f32) * 0.013).sin()).collect();
1537 let a = dec.forward_last(&seq[..2 * hs], 2);
1538 let b = dec.forward_last(&seq, 3);
1539 assert_eq!(a.len(), hs);
1540 assert!(a.iter().all(|v| v.is_finite()) && b.iter().all(|v| v.is_finite()));
1541 let a2 = dec.forward_last(&seq[..2 * hs], 2);
1545 let d = a.iter().zip(&a2).map(|(x, y)| (x - y).abs()).fold(0f32, f32::max);
1546 assert!(d == 0.0, "not deterministic: {d}");
1547 let logits = dec.head(1, &b);
1548 assert_eq!(logits.len(), 1024, "audio vocab is 1024 per level");
1549 assert!(logits.iter().all(|v| v.is_finite()));
1550 let spread = logits.iter().fold(f32::MIN, |m, v| m.max(*v))
1551 - logits.iter().fold(f32::MAX, |m, v| m.min(*v));
1552 assert!(spread > 1e-3, "head is flat, spread {spread}");
1553 eprintln!("music3 rvq: 8 codebooks, head spread {spread:.3}");
1554 }
1555
1556 #[test]
1565 fn music3_dit_forward_has_the_reference_geometry() {
1566 let Ok(p) = std::env::var("CMF_MUSIC3_DIT") else {
1567 eprintln!("CMF_MUSIC3_DIT unset — skipping Music-3 DiT test");
1568 return;
1569 };
1570 let model = Arc::new(CmfModel::open(&p).expect("open packed DiT"));
1571 let dit = Music3Dit::from_cmf(&model).expect("load DiT");
1572 let n = 4usize;
1573 let x: Vec<f32> = (0..Music3Dit::IN_CH * n)
1574 .map(|i| 0.3 * ((i as f32) * 0.017).sin())
1575 .collect();
1576 let cond: Vec<f32> = (0..Music3Dit::COND_CH * n)
1577 .map(|i| 0.2 * ((i as f32) * 0.011).cos())
1578 .collect();
1579 let v = dit.forward(&x, &cond, n, 0.7);
1580 assert_eq!(v.len(), Music3Dit::IN_CH * n, "velocity is [128, n]");
1581 assert!(v.iter().all(|q| q.is_finite()), "non-finite velocity");
1582 let rms = (v.iter().map(|q| q * q).sum::<f32>() / v.len() as f32).sqrt();
1583 assert!(rms > 1e-6, "velocity is silent, rms {rms}");
1584
1585 let zero_cond = vec![0f32; Music3Dit::COND_CH * n];
1586 let v0 = dit.forward(&x, &zero_cond, n, 0.7);
1587 let dc = v
1588 .iter()
1589 .zip(&v0)
1590 .map(|(a, b)| (a - b).abs())
1591 .fold(0f32, f32::max);
1592 assert!(dc > 1e-5, "condition changed nothing — concat is wrong");
1593
1594 let vt = dit.forward(&x, &cond, n, 0.2);
1595 let dt = v
1596 .iter()
1597 .zip(&vt)
1598 .map(|(a, b)| (a - b).abs())
1599 .fold(0f32, f32::max);
1600 assert!(dt > 1e-5, "timestep changed nothing — the token is lost");
1601 eprintln!("music3 dit: rms {rms:.4}, d/dcond {dc:.4}, d/dt {dt:.4}");
1602 }
1603}
1604
1605pub mod prof {
1609 use std::sync::atomic::{AtomicU64, Ordering};
1610 use std::sync::OnceLock;
1611 use std::time::Instant;
1612
1613 pub static QKV: AtomicU64 = AtomicU64::new(0);
1614 pub static ATTN: AtomicU64 = AtomicU64::new(0);
1615 pub static OUT: AtomicU64 = AtomicU64::new(0);
1616 pub static FFN: AtomicU64 = AtomicU64::new(0);
1617
1618 pub fn on() -> bool {
1619 static ON: OnceLock<bool> = OnceLock::new();
1620 *ON.get_or_init(|| std::env::var("CMF_MUSIC3_PROF").as_deref() == Ok("1"))
1621 }
1622
1623 pub fn start() -> Option<Instant> {
1625 on().then(Instant::now)
1626 }
1627
1628 pub fn add(c: &AtomicU64, t: Option<Instant>) {
1629 if let Some(t) = t {
1630 c.fetch_add(t.elapsed().as_nanos() as u64, Ordering::Relaxed);
1631 }
1632 }
1633
1634 pub fn report() -> String {
1635 let g = |c: &AtomicU64| c.load(Ordering::Relaxed) as f64 / 1e9;
1636 format!(
1637 "qkv {:.1}s, attention {:.1}s, out {:.1}s, ffn {:.1}s",
1638 g(&QKV),
1639 g(&ATTN),
1640 g(&OUT),
1641 g(&FFN)
1642 )
1643 }
1644}