1use crate::audiovae::SendPtr;
22use crate::dit::Proj;
23use crate::pool::Pool;
24use crate::qtensor::QTensor;
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 = serde_json::from_slice(
118 model
119 .tensor_bytes("mdit.config_json")
120 .map_err(|e| e.to_string())?,
121 )
122 .map_err(|e| format!("mdit.config_json: {e}"))?;
123 let u = |k: &str, d: usize| cfg[k].as_u64().map(|v| v as usize).unwrap_or(d);
124 let nl = u("num_layers", 36);
125 let dt = "mdit.diffusion_transformer";
126 Ok(Self {
127 pre_conv: crate::dit::cmf_f32(model, &format!("{dt}.preprocess_conv.weight"))?,
128 post_conv: crate::dit::cmf_f32(model, &format!("{dt}.postprocess_conv.weight"))?,
129 fourier: crate::dit::cmf_f32(model, &format!("{dt}.timestep_features.weight"))?,
130 t0: Proj::from_model(model, &format!("{dt}.to_timestep_embed.0.weight"))?,
131 t0_b: crate::dit::cmf_f32(model, &format!("{dt}.to_timestep_embed.0.bias"))?,
132 t2: Proj::from_model(model, &format!("{dt}.to_timestep_embed.2.weight"))?,
133 t2_b: crate::dit::cmf_f32(model, &format!("{dt}.to_timestep_embed.2.bias"))?,
134 project_in: Proj::from_model(model, &format!("{dt}.transformer.project_in.weight"))?,
135 project_out: Proj::from_model(model, &format!("{dt}.transformer.project_out.weight"))?,
136 inv_freq: crate::dit::cmf_f32(
137 model,
138 &format!("{dt}.transformer.rotary_pos_emb.inv_freq"),
139 )?,
140 blocks: (0..nl)
141 .map(|i| Block::load(model, &format!("{dt}.transformer.layers.{i}")))
142 .collect::<Result<_, _>>()?,
143 pool: Pool::from_env(),
144 hidden: u("hidden", 2048),
145 heads: u("num_heads", 32),
146 hd: u("head_dim", 64),
147 rot: u("rotary_dim", 32),
148 inter: u("ff_inner", 8192),
149 cond_logits: crate::dit::cmf_f32(model, "mdit.cond_layer_logits")?,
150 cond_scale: crate::dit::cmf_f32(model, "mdit.cond_layer_scale")?[0],
151 lc_w: crate::dit::cmf_f32(model, "mdit.latent_conditioners.0.weight")?,
152 lc_b: crate::dit::cmf_f32(model, "mdit.latent_conditioners.0.bias")?,
153 })
154 }
155
156 pub fn latent_length(audio_frames: usize) -> usize {
159 ((audio_frames as f64 * 44100.0 / 24000.0 * 960.0 / 512.0) as usize).max(1)
160 }
161
162 pub fn aligned_condition(&self, hidden: &[f32], frames: usize) -> (Vec<f32>, usize) {
170 let levels = self.cond_logits.len();
171 let ar = hidden.len() / (frames * levels);
172 let mx = self.cond_logits.iter().cloned().fold(f32::MIN, f32::max);
173 let ex: Vec<f32> = self.cond_logits.iter().map(|v| (v - mx).exp()).collect();
174 let sum: f32 = ex.iter().sum();
175 let mut mixed = vec![0f32; ar * frames];
177 for t in 0..frames {
178 for l in 0..levels {
179 let w = ex[l] / sum * self.cond_scale;
180 let src = &hidden[(t * levels + l) * ar..(t * levels + l + 1) * ar];
181 for (c, &v) in src.iter().enumerate() {
182 mixed[c * frames + t] += w * v;
183 }
184 }
185 }
186 let out_ch = self.lc_b.len();
188 let mut conv = vec![0f32; out_ch * frames];
189 for o in 0..out_ch {
190 let dst = &mut conv[o * frames..(o + 1) * frames];
191 dst.fill(self.lc_b[o]);
192 for i in 0..ar {
193 let k = &self.lc_w[(o * ar + i) * 3..(o * ar + i + 1) * 3];
194 let src = &mixed[i * frames..(i + 1) * frames];
195 for t in 0..frames {
196 for (j, &kv) in k.iter().enumerate() {
197 let p = t as isize + j as isize - 1;
198 if p >= 0 && (p as usize) < frames {
199 dst[t] += kv * src[p as usize];
200 }
201 }
202 }
203 }
204 }
205 let l = Self::latent_length(frames);
206 let mut out = vec![0f32; out_ch * l];
207 for o in 0..out_ch {
208 for t in 0..l {
209 let s = (t * frames) / l.max(1);
210 out[o * l + t] = conv[o * frames + s.min(frames - 1)];
211 }
212 }
213 (out, l)
214 }
215
216 fn conv1x1_residual(w: &[f32], x: &mut [f32], ch: usize, n: usize) {
219 let mut acc = vec![0f32; ch * n];
220 for o in 0..ch {
221 let row = &w[o * ch..(o + 1) * ch];
222 let dst = &mut acc[o * n..(o + 1) * n];
223 for (i, &wv) in row.iter().enumerate() {
224 if wv == 0.0 {
225 continue;
226 }
227 for (d, &s) in dst.iter_mut().zip(&x[i * n..(i + 1) * n]) {
228 *d += wv * s;
229 }
230 }
231 }
232 for (d, a) in x.iter_mut().zip(&acc) {
233 *d += a;
234 }
235 }
236
237 fn timestep_embedding(&self, t: f32) -> Vec<f32> {
239 let half = self.fourier.len();
240 let mut feats = vec![0f32; half * 2];
241 for (i, &w) in self.fourier.iter().enumerate() {
242 let a = std::f32::consts::TAU * t * w;
243 feats[i] = a.cos();
244 feats[half + i] = a.sin();
245 }
246 let mut h = vec![0f32; self.t0_b.len()];
247 self.t0.matmat(&feats, 1, &mut h, self.pool.as_deref());
248 for (v, &b) in h.iter_mut().zip(&self.t0_b) {
249 *v = silu(*v + b);
250 }
251 let mut out = vec![0f32; self.t2_b.len()];
252 self.t2.matmat(&h, 1, &mut out, self.pool.as_deref());
253 for (v, &b) in out.iter_mut().zip(&self.t2_b) {
254 *v += b;
255 }
256 out
257 }
258
259 fn rope_packed(&self, qkv: &mut [f32], n: usize) {
269 let (hs, nh, hd) = (self.hidden, self.heads, self.hd);
270 let half = self.rot / 2;
271 let ptr = SendPtr(qkv.as_mut_ptr());
272 let work = |lo: usize, hi: usize| {
273 for p in lo..hi {
274 let base = p * 3 * hs;
275 for i in 0..half {
276 let (s, c) = (p as f32 * self.inv_freq[i]).sin_cos();
277 for h in 0..nh {
278 for off in [base + h * hd, base + hs + h * hd] {
279 let x = unsafe { ptr.row(off, hd) };
281 let (a, b) = (x[i], x[i + half]);
282 x[i] = a * c - b * s;
283 x[i + half] = a * s + b * c;
284 }
285 }
286 }
287 }
288 };
289 match self.pool.as_deref() {
290 Some(pl) => pl.run_rows(n, &work),
291 None => work(0, n),
292 }
293 }
294
295 fn block(&self, blk: &Block, x: &mut [f32], n: usize) {
297 let (hs, nh, hd) = (self.hidden, self.heads, self.hd);
298 let pool = self.pool.as_deref();
299 let mut h = x.to_vec();
300 blk.pre_norm.apply(&mut h, hs);
301 if std::env::var("CMF_MUSIC3_DEVATT").as_deref() != Ok("0") {
311 if let (Some((m1, i1)), Some((m2, i2))) = (
312 match &blk.qkv {
313 crate::dit::Proj::Q(q) => q.q4tp_mapped(),
314 _ => None,
315 },
316 match &blk.out {
317 crate::dit::Proj::Q(q) => q.q4tp_mapped(),
318 _ => None,
319 },
320 ) {
321 if std::sync::Arc::ptr_eq(m1, m2) {
322 let half = self.rot / 2;
323 let mut ang = vec![0f32; n * half];
324 for p in 0..n {
325 for (i, f) in self.inv_freq[..half].iter().enumerate() {
326 ang[p * half + i] = p as f32 * f;
327 }
328 }
329 let ones = vec![1.0f32; hd];
330 let scale = 1.0 / (hd as f32).sqrt();
331 let mut proj = vec![0f32; n * hs];
332 let _ta = prof::start();
333 if crate::gpu::dit_qkv_attn_out(
334 m1,
335 i1,
336 i2,
337 &h,
338 n,
339 hs,
340 nh,
341 hd,
342 scale,
343 (&ang, &ones, &ones, -1.0),
344 &mut proj,
345 ) {
346 prof::add(&prof::ATTN, _ta);
347 for (a, b) in x.iter_mut().zip(&proj) {
348 *a += b;
349 }
350 return self.block_ffn(blk, x, n);
351 }
352 }
353 }
354 }
355 let mut qkv = vec![0f32; n * 3 * hs];
356 let _t = prof::start();
357 blk.qkv.matmat(&h, n, &mut qkv, pool);
358 prof::add(&prof::QKV, _t);
359 self.rope_packed(&mut qkv, n);
364 let scale = 1.0 / (hd as f32).sqrt();
365 let mut attn = vec![0f32; n * hs];
366 let _ta = prof::start();
367 {
374 if crate::gpu::dit_attention_packed(&qkv, nh, n, hd, scale, None, &mut attn) {
380 prof::add(&prof::ATTN, _ta);
381 let mut proj = vec![0f32; n * hs];
382 let _t = prof::start();
383 blk.out.matmat(&attn, n, &mut proj, pool);
384 prof::add(&prof::OUT, _t);
385 for (a, b) in x.iter_mut().zip(&proj) {
386 *a += b;
387 }
388 return self.block_ffn(blk, x, n);
389 }
390 attn.fill(0.0);
391 }
392 let mut q = vec![0f32; n * hs];
394 let mut k = vec![0f32; n * hs];
395 let mut v = vec![0f32; n * hs];
396 for p in 0..n {
397 let s = &qkv[p * 3 * hs..(p + 1) * 3 * hs];
398 q[p * hs..(p + 1) * hs].copy_from_slice(&s[..hs]);
399 k[p * hs..(p + 1) * hs].copy_from_slice(&s[hs..2 * hs]);
400 v[p * hs..(p + 1) * hs].copy_from_slice(&s[2 * hs..]);
401 }
402 if crate::gpu::enabled_here() {
406 let mut qh = vec![0f32; n * hs];
407 let mut kh = vec![0f32; n * hs];
408 let mut vh = vec![0f32; n * hs];
409 for h in 0..nh {
410 for i in 0..n {
411 let (s, d) = (i * hs + h * hd, (h * n + i) * hd);
412 qh[d..d + hd].copy_from_slice(&q[s..s + hd]);
413 kh[d..d + hd].copy_from_slice(&k[s..s + hd]);
414 vh[d..d + hd].copy_from_slice(&v[s..s + hd]);
415 }
416 }
417 if crate::gpu::dit_attention(&qh, &kh, &vh, nh, nh, n, hd, scale, &mut attn) {
418 prof::add(&prof::ATTN, _ta);
419 let mut proj = vec![0f32; n * hs];
420 let _t = prof::start();
421 blk.out.matmat(&attn, n, &mut proj, pool);
422 prof::add(&prof::OUT, _t);
423 for (a, b) in x.iter_mut().zip(&proj) {
424 *a += b;
425 }
426 return self.block_ffn(blk, x, n);
427 }
428 attn.fill(0.0);
429 }
430 {
433 let ptr = SendPtr(attn.as_mut_ptr());
434 let work = |lo: usize, hi: usize| {
435 let mut scores = vec![0f32; n];
436 for hh in lo..hi {
437 for i in 0..n {
438 let qi = &q[i * hs + hh * hd..i * hs + hh * hd + hd];
439 let mut mx = f32::NEG_INFINITY;
440 for (j, sc) in scores.iter_mut().enumerate() {
441 let kj = &k[j * hs + hh * hd..j * hs + hh * hd + hd];
442 *sc = qi.iter().zip(kj).map(|(a, b)| a * b).sum::<f32>() * scale;
443 mx = mx.max(*sc);
444 }
445 let mut sum = 0.0;
446 for sc in scores.iter_mut() {
447 *sc = (*sc - mx).exp();
448 sum += *sc;
449 }
450 let inv = 1.0 / sum;
451 let dst = unsafe { ptr.row(i * hs + hh * hd, hd) };
453 for (j, &sc) in scores.iter().enumerate() {
454 let w = sc * inv;
455 let vj = &v[j * hs + hh * hd..j * hs + hh * hd + hd];
456 for (d, &vv) in dst.iter_mut().zip(vj) {
457 *d += w * vv;
458 }
459 }
460 }
461 }
462 };
463 match pool {
464 Some(p) => p.run_rows(nh, &work),
465 None => work(0, nh),
466 }
467 }
468 prof::add(&prof::ATTN, _ta);
469 let mut proj = vec![0f32; n * hs];
470 let _t = prof::start();
471 blk.out.matmat(&attn, n, &mut proj, pool);
472 prof::add(&prof::OUT, _t);
473 for (a, b) in x.iter_mut().zip(&proj) {
474 *a += b;
475 }
476 self.block_ffn(blk, x, n)
477 }
478
479 fn block_ffn(&self, blk: &Block, x: &mut [f32], n: usize) {
481 let _t = prof::start();
482 let hs = self.hidden;
483 let pool = self.pool.as_deref();
484 let mut h = x.to_vec();
485 blk.ff_norm.apply(&mut h, hs);
486 if std::env::var("CMF_MUSIC3_DEVFFN").as_deref() != Ok("0") {
492 if let (Some((m1, i1)), Some((m2, i2))) = (
493 match &blk.ff_in {
494 crate::dit::Proj::Q(q) => q.q4tp_mapped(),
495 _ => None,
496 },
497 match &blk.ff_out {
498 crate::dit::Proj::Q(q) => q.q4tp_mapped(),
499 _ => None,
500 },
501 ) {
502 if std::sync::Arc::ptr_eq(m1, m2) {
503 let mut ffo = vec![0f32; n * hs];
504 if crate::gpu::music3_ffn(
505 m1,
506 i1,
507 i2,
508 &h,
509 &blk.ff_in_b,
510 n,
511 hs,
512 self.inter,
513 &mut ffo,
514 ) {
515 for p in 0..n {
516 for j in 0..hs {
517 x[p * hs + j] += ffo[p * hs + j] + blk.ff_out_b[j];
518 }
519 }
520 prof::add(&prof::FFN, _t);
521 return;
522 }
523 }
524 }
525 }
526 let mut gu = vec![0f32; n * 2 * self.inter];
527 blk.ff_in.matmat(&h, n, &mut gu, pool);
528 let inter = self.inter;
533 let (vb, gb) = blk.ff_in_b.split_at(inter);
534 let mut act = vec![0f32; n * inter];
535 for p in 0..n {
536 let row = &gu[p * 2 * inter..(p + 1) * 2 * inter];
537 let (val, gate) = row.split_at(inter);
538 let dst = &mut act[p * inter..(p + 1) * inter];
539 for i in 0..inter {
540 dst[i] = (val[i] + vb[i]) * silu(gate[i] + gb[i]);
541 }
542 }
543 let mut ffo = vec![0f32; n * hs];
544 blk.ff_out.matmat(&act, n, &mut ffo, pool);
545 for p in 0..n {
546 for j in 0..hs {
547 x[p * hs + j] += ffo[p * hs + j] + blk.ff_out_b[j];
548 }
549 }
550 prof::add(&prof::FFN, _t);
551 }
552
553 pub const WINDOW: usize = 689;
559 pub const HOP: usize = 344;
560
561 pub fn forward_windowed(&self, x: &[f32], condition: &[f32], n: usize, t: f32) -> Vec<f32> {
564 if n <= Self::WINDOW {
565 return self.forward(x, condition, n, t);
566 }
567 let ch = Self::IN_CH;
568 let cc = Self::COND_CH;
569 let mut out = vec![0f32; ch * n];
570 let mut count = vec![0f32; n];
571 let mut start = 0usize;
572 loop {
573 let end = (start + Self::WINDOW).min(n);
574 let w = end - start;
575 let mut xw = vec![0f32; ch * w];
576 for c in 0..ch {
577 xw[c * w..(c + 1) * w].copy_from_slice(&x[c * n + start..c * n + end]);
578 }
579 let mut cw = vec![0f32; cc * w];
580 for c in 0..cc {
581 cw[c * w..(c + 1) * w].copy_from_slice(&condition[c * n + start..c * n + end]);
582 }
583 let v = self.forward(&xw, &cw, w, t);
584 for c in 0..ch {
585 for i in 0..w {
586 out[c * n + start + i] += v[c * w + i];
587 }
588 }
589 for i in 0..w {
590 count[start + i] += 1.0;
591 }
592 if end == n {
593 break;
594 }
595 start += Self::HOP;
596 }
597 for c in 0..ch {
598 for i in 0..n {
599 out[c * n + i] /= count[i];
600 }
601 }
602 out
603 }
604
605 pub fn forward(&self, x: &[f32], condition: &[f32], n: usize, t: f32) -> Vec<f32> {
608 let pool = self.pool.as_deref();
609 let mut full = vec![0f32; Self::CONCAT_CH * n];
610 full[..Self::IN_CH * n].copy_from_slice(x);
611 full[2 * Self::IN_CH * n..].copy_from_slice(condition);
613 Self::conv1x1_residual(&self.pre_conv, &mut full, Self::CONCAT_CH, n);
614
615 let mut toks = vec![0f32; n * Self::CONCAT_CH];
617 for c in 0..Self::CONCAT_CH {
618 for p in 0..n {
619 toks[p * Self::CONCAT_CH + c] = full[c * n + p];
620 }
621 }
622 let mut h = vec![0f32; n * self.hidden];
623 self.project_in.matmat(&toks, n, &mut h, pool);
624
625 let temb = self.timestep_embedding(t);
627 let mut seq = vec![0f32; (n + 1) * self.hidden];
628 seq[..self.hidden].copy_from_slice(&temb);
629 seq[self.hidden..].copy_from_slice(&h);
630 for blk in &self.blocks {
631 self.block(blk, &mut seq, n + 1);
632 }
633
634 let mut out = vec![0f32; n * Self::IN_CH];
635 self.project_out
636 .matmat(&seq[self.hidden..], n, &mut out, pool);
637 let mut ch = vec![0f32; Self::IN_CH * n];
638 for c in 0..Self::IN_CH {
639 for p in 0..n {
640 ch[c * n + p] = out[p * Self::IN_CH + c];
641 }
642 }
643 Self::conv1x1_residual(&self.post_conv, &mut ch, Self::IN_CH, n);
644 for v in ch.iter_mut() {
645 *v = -*v;
646 }
647 ch
648 }
649
650 pub fn sample(
653 &self,
654 noise: &[f32],
655 condition: &[f32],
656 n: usize,
657 steps: usize,
658 mut progress: impl FnMut(usize, usize),
659 ) -> Vec<f32> {
660 let sigmas = flow_sigmas(steps);
661 let mut x = noise.to_vec();
662 for i in 0..steps {
663 let (s, s_next) = (sigmas[i], sigmas[i + 1]);
664 let v = self.forward_windowed(&x, condition, n, 1.0 - s);
666 let dt = s_next - s;
667 for (a, b) in x.iter_mut().zip(&v) {
668 *a += dt * b;
669 }
670 progress(i + 1, steps);
671 }
672 x
673 }
674}
675
676pub fn flow_sigmas(steps: usize) -> Vec<f32> {
699 const SIGMA_MIN: f32 = 0.001;
700 let n = steps.max(1);
701 let mut s: Vec<f32> = (0..n)
702 .map(|i| {
703 if n == 1 {
704 1.0
705 } else {
706 1.0 + (SIGMA_MIN - 1.0) * i as f32 / (n - 1) as f32
707 }
708 })
709 .collect();
710 s.push(0.0);
711 s
712}
713
714struct RmsNorm {
716 w: Vec<f32>,
717}
718
719impl RmsNorm {
720 fn load(model: &Arc<CmfModel>, n: &str) -> Result<Self, String> {
721 Ok(Self {
722 w: crate::dit::cmf_f32(model, n)?,
723 })
724 }
725
726 fn apply(&self, x: &mut [f32], d: usize) {
727 for row in x.chunks_exact_mut(d) {
728 let ss = row.iter().map(|v| (*v as f64) * (*v as f64)).sum::<f64>() / d as f64;
729 let inv = 1.0 / (ss + 1e-6).sqrt();
730 for (v, &g) in row.iter_mut().zip(&self.w) {
731 *v = (*v as f64 * inv) as f32 * g;
732 }
733 }
734 }
735}
736
737struct RvqBlock {
738 n1: RmsNorm,
739 q: Proj,
740 k: Proj,
741 v: Proj,
742 o: Proj,
743 n2: RmsNorm,
744 gate: Proj,
745 up: Proj,
746 down: Proj,
747}
748
749impl RvqBlock {
750 fn load(model: &Arc<CmfModel>, p: &str) -> Result<Self, String> {
751 Ok(Self {
752 n1: RmsNorm::load(model, &format!("{p}.input_layernorm.weight"))?,
753 q: Proj::from_model(model, &format!("{p}.self_attn.q_proj.weight"))?,
754 k: Proj::from_model(model, &format!("{p}.self_attn.k_proj.weight"))?,
755 v: Proj::from_model(model, &format!("{p}.self_attn.v_proj.weight"))?,
756 o: Proj::from_model(model, &format!("{p}.self_attn.o_proj.weight"))?,
757 n2: RmsNorm::load(model, &format!("{p}.post_attention_layernorm.weight"))?,
758 gate: Proj::from_model(model, &format!("{p}.mlp.gate_proj.weight"))?,
759 up: Proj::from_model(model, &format!("{p}.mlp.up_proj.weight"))?,
760 down: Proj::from_model(model, &format!("{p}.mlp.down_proj.weight"))?,
761 })
762 }
763}
764
765pub struct RvqDepthDecoder {
773 projection: Proj,
774 pos: Vec<f32>,
775 blocks: Vec<RvqBlock>,
776 norm: RmsNorm,
777 heads: Vec<Proj>,
778 pool: Option<Arc<Pool>>,
779 hidden: usize,
780 nh: usize,
781 hd: usize,
782 inter: usize,
783}
784
785impl RvqDepthDecoder {
786 pub fn from_cmf(model: &Arc<CmfModel>) -> Result<Self, String> {
787 let cfg: serde_json::Value = serde_json::from_slice(
788 model
789 .tensor_bytes("mte.config_json")
790 .map_err(|e| e.to_string())?,
791 )
792 .map_err(|e| format!("mte.config_json: {e}"))?;
793 let u = |k: &str, d: usize| cfg[k].as_u64().map(|v| v as usize).unwrap_or(d);
794 let hidden = u("hidden_size", 4096);
795 let nl = u("decoder_num_layers", 4);
796 let nh = u("decoder_num_heads", 16);
797 let cb = u("audio_num_codebooks", 8);
798 Ok(Self {
799 projection: Proj::from_model(model, "mte.audio_decoder.projection.weight")?,
800 pos: crate::dit::cmf_f32(model, "mte.audio_decoder.pos_embedding.weight")?,
801 blocks: (0..nl)
802 .map(|i| RvqBlock::load(model, &format!("mte.audio_decoder.layers.{i}")))
803 .collect::<Result<_, _>>()?,
804 norm: RmsNorm::load(model, "mte.audio_decoder.norm.weight")?,
805 heads: (0..cb - 1)
806 .map(|i| {
807 Proj::from_model(model, &format!("mte.audio_decoder.audio_heads.{i}.weight"))
808 })
809 .collect::<Result<_, _>>()?,
810 pool: Pool::from_env(),
811 hidden,
812 nh,
813 hd: hidden / nh,
814 inter: u("decoder_intermediate_size", 6144),
815 })
816 }
817
818 pub fn codebooks(&self) -> usize {
819 self.heads.len() + 1
820 }
821
822 pub fn project(&self, x: &[f32]) -> Vec<f32> {
825 let n = x.len() / self.hidden;
826 let mut out = vec![0f32; n * self.hidden];
827 self.projection.matmat(x, n, &mut out, self.pool.as_deref());
828 out
829 }
830
831 pub fn forward_last(&self, seq: &[f32], n: usize) -> Vec<f32> {
834 let (hs, nh, hd) = (self.hidden, self.nh, self.hd);
835 let pool = self.pool.as_deref();
836 let mut x = seq.to_vec();
837 for p in 0..n {
838 for (v, &pe) in x[p * hs..(p + 1) * hs]
839 .iter_mut()
840 .zip(&self.pos[p * hs..(p + 1) * hs])
841 {
842 *v += pe;
843 }
844 }
845 for blk in &self.blocks {
846 let mut h = x.clone();
847 blk.n1.apply(&mut h, hs);
848 let (mut q, mut k, mut v) =
849 (vec![0f32; n * hs], vec![0f32; n * hs], vec![0f32; n * hs]);
850 blk.q.matmat(&h, n, &mut q, pool);
851 blk.k.matmat(&h, n, &mut k, pool);
852 blk.v.matmat(&h, n, &mut v, pool);
853 let scale = 1.0 / (hd as f32).sqrt();
854 let mut attn = vec![0f32; n * hs];
855 for hh in 0..nh {
856 for i in 0..n {
857 let qi = &q[i * hs + hh * hd..i * hs + hh * hd + hd];
858 let mut sc = vec![0f32; i + 1];
860 let mut mx = f32::NEG_INFINITY;
861 for (j, s) in sc.iter_mut().enumerate() {
862 let kj = &k[j * hs + hh * hd..j * hs + hh * hd + hd];
863 *s = qi.iter().zip(kj).map(|(a, b)| a * b).sum::<f32>() * scale;
864 mx = mx.max(*s);
865 }
866 let mut sum = 0.0;
867 for s in sc.iter_mut() {
868 *s = (*s - mx).exp();
869 sum += *s;
870 }
871 let inv = 1.0 / sum;
872 let dst = &mut attn[i * hs + hh * hd..i * hs + hh * hd + hd];
873 for (j, &s) in sc.iter().enumerate() {
874 let w = s * inv;
875 let vj = &v[j * hs + hh * hd..j * hs + hh * hd + hd];
876 for (d, &vv) in dst.iter_mut().zip(vj) {
877 *d += w * vv;
878 }
879 }
880 }
881 }
882 let mut proj = vec![0f32; n * hs];
883 blk.o.matmat(&attn, n, &mut proj, pool);
884 for (a, b) in x.iter_mut().zip(&proj) {
885 *a += b;
886 }
887
888 let mut h = x.clone();
889 blk.n2.apply(&mut h, hs);
890 let (mut g, mut u) = (vec![0f32; n * self.inter], vec![0f32; n * self.inter]);
891 blk.gate.matmat(&h, n, &mut g, pool);
892 blk.up.matmat(&h, n, &mut u, pool);
893 for (a, b) in g.iter_mut().zip(&u) {
894 *a = silu(*a) * b;
895 }
896 let mut ffo = vec![0f32; n * hs];
897 blk.down.matmat(&g, n, &mut ffo, pool);
898 for (a, b) in x.iter_mut().zip(&ffo) {
899 *a += b;
900 }
901 }
902 let mut last = x[(n - 1) * hs..].to_vec();
903 self.norm.apply(&mut last, hs);
904 last
905 }
906
907 pub fn head(&self, level: usize, hidden: &[f32]) -> Vec<f32> {
909 let h = &self.heads[level - 1];
910 let rows = match h {
911 Proj::F32 { rows, .. } => *rows,
912 Proj::Q(q) => q.rows(),
913 };
914 let mut out = vec![0f32; rows];
915 h.matmat(hidden, 1, &mut out, self.pool.as_deref());
916 out
917 }
918}
919
920struct ArBlock {
925 n1: RmsNorm,
926 q: Proj,
927 k: Proj,
928 v: Proj,
929 o: Proj,
930 qn: RmsNorm,
931 kn: RmsNorm,
932 n2: RmsNorm,
933 gate: Proj,
934 up: Proj,
935 down: Proj,
936}
937
938impl ArBlock {
939 fn load(model: &Arc<CmfModel>, p: &str) -> Result<Self, String> {
940 Ok(Self {
941 n1: RmsNorm::load(model, &format!("{p}.input_layernorm.weight"))?,
942 q: Proj::from_model(model, &format!("{p}.self_attn.q_proj.weight"))?,
943 k: Proj::from_model(model, &format!("{p}.self_attn.k_proj.weight"))?,
944 v: Proj::from_model(model, &format!("{p}.self_attn.v_proj.weight"))?,
945 o: Proj::from_model(model, &format!("{p}.self_attn.o_proj.weight"))?,
946 qn: RmsNorm::load(model, &format!("{p}.self_attn.q_norm.weight"))?,
947 kn: RmsNorm::load(model, &format!("{p}.self_attn.k_norm.weight"))?,
948 n2: RmsNorm::load(model, &format!("{p}.post_attention_layernorm.weight"))?,
949 gate: Proj::from_model(model, &format!("{p}.mlp.gate_proj.weight"))?,
950 up: Proj::from_model(model, &format!("{p}.mlp.up_proj.weight"))?,
951 down: Proj::from_model(model, &format!("{p}.mlp.down_proj.weight"))?,
952 })
953 }
954}
955
956#[derive(Default, Clone)]
963struct KvRun {
964 k: Vec<Vec<f32>>,
965 v: Vec<Vec<f32>>,
966 len: usize,
967}
968
969impl KvRun {
970 fn init(nkv: usize) -> Self {
971 Self {
972 k: vec![Vec::new(); nkv],
973 v: vec![Vec::new(); nkv],
974 len: 0,
975 }
976 }
977}
978
979struct Rng(u64);
986
987impl Rng {
988 fn new(seed: u64) -> Self {
989 Self(seed.wrapping_mul(0x9E37_79B9_7F4A_7C15) | 1)
990 }
991 fn next_f32(&mut self) -> f32 {
992 let mut x = self.0;
993 x ^= x << 13;
994 x ^= x >> 7;
995 x ^= x << 17;
996 self.0 = x;
997 ((x >> 40) as f32) / (1u32 << 24) as f32
998 }
999}
1000
1001fn sample_topk(logits: &[f32], top_k: usize, rng: &mut Rng) -> usize {
1002 let mut idx: Vec<usize> = (0..logits.len())
1003 .filter(|&i| logits[i].is_finite())
1004 .collect();
1005 idx.sort_unstable_by(|&a, &b| logits[b].partial_cmp(&logits[a]).unwrap());
1006 idx.truncate(top_k.max(1));
1007 let mx = idx.iter().map(|&i| logits[i]).fold(f32::MIN, f32::max);
1008 let exps: Vec<f32> = idx.iter().map(|&i| (logits[i] - mx).exp()).collect();
1009 let sum: f32 = exps.iter().sum();
1010 let mut r = rng.next_f32() * sum;
1011 for (j, &e) in exps.iter().enumerate() {
1012 r -= e;
1013 if r <= 0.0 {
1014 return idx[j];
1015 }
1016 }
1017 *idx.last().unwrap()
1018}
1019
1020pub struct Music3Ar {
1024 blocks: Vec<ArBlock>,
1025 norm: RmsNorm,
1026 embed_prefill: QTensor,
1027 embed_audio: QTensor,
1028 embed_extra: QTensor,
1029 lm_head: Proj,
1030 pub depth: RvqDepthDecoder,
1031 inv_freq: Vec<f32>,
1032 pool: Option<Arc<Pool>>,
1033 hidden: usize,
1034 nh: usize,
1035 nkv: usize,
1036 hd: usize,
1037 inter: usize,
1038 audio_vocab: usize,
1039 codebooks: usize,
1040 pub cfg_scale: f32,
1041 pub top_k: usize,
1042 pub fps: usize,
1043 pub max_frames: usize,
1044}
1045
1046pub mod tokens {
1048 pub const IM_START: u32 = 151644;
1049 pub const IM_END: u32 = 151645;
1050 pub const AUDIO_CFG: u32 = 151654;
1051 pub const AUDIO_START: u32 = 151669;
1052 pub const CAPTION_START: u32 = 151671;
1053 pub const CAPTION_END: u32 = 151672;
1054 pub const LYRICS_START: u32 = 151673;
1055 pub const LYRICS_END: u32 = 151674;
1056}
1057
1058impl Music3Ar {
1059 pub fn from_cmf(model: &Arc<CmfModel>) -> Result<Self, String> {
1060 let cfg: serde_json::Value = serde_json::from_slice(
1061 model
1062 .tensor_bytes("mte.config_json")
1063 .map_err(|e| e.to_string())?,
1064 )
1065 .map_err(|e| format!("mte.config_json: {e}"))?;
1066 let u = |k: &str, d: usize| cfg[k].as_u64().map(|v| v as usize).unwrap_or(d);
1067 let f = |k: &str, d: f64| cfg[k].as_f64().unwrap_or(d);
1068 let hidden = u("hidden_size", 4096);
1069 let hd = u("head_dim", 128);
1070 let theta = f("rope_theta", 1_000_000.0) as f32;
1071 Ok(Self {
1072 blocks: (0..u("num_hidden_layers", 36))
1073 .map(|i| ArBlock::load(model, &format!("mte.layers.{i}")))
1074 .collect::<Result<_, _>>()?,
1075 norm: RmsNorm::load(model, "mte.norm.weight")?,
1076 embed_prefill: QTensor::from_model(model, "mte.embed_tokens_prefill.weight")?,
1077 embed_audio: QTensor::from_model(model, "mte.embed_tokens_audio.weight")?,
1078 embed_extra: QTensor::from_model(model, "mte.audio_extra_embedding.weight")?,
1079 lm_head: Proj::from_model(model, "mte.lm_head_pruned.weight")?,
1080 depth: RvqDepthDecoder::from_cmf(model)?,
1081 inv_freq: (0..hd / 2)
1082 .map(|i| 1.0 / theta.powf(2.0 * i as f32 / hd as f32))
1083 .collect(),
1084 pool: Pool::from_env(),
1085 hidden,
1086 nh: u("num_attention_heads", 32),
1087 nkv: u("num_key_value_heads", 8),
1088 hd,
1089 inter: u("intermediate_size", 12288),
1090 audio_vocab: u("audio_vocab_size", 1024),
1091 codebooks: u("audio_num_codebooks", 8),
1092 cfg_scale: f("cfg_scale", 1.5) as f32,
1093 top_k: u("top_k", 50),
1094 fps: u("audio_frames_per_second", 25),
1095 max_frames: u("max_audio_frames", 9000),
1096 })
1097 }
1098
1099 fn embed_row(p: &QTensor, row: usize, hidden: usize) -> Vec<f32> {
1102 let mut out = vec![0f32; hidden];
1103 p.row_f32(row, &mut out);
1104 out
1105 }
1106
1107 #[allow(clippy::type_complexity)]
1121 fn graph_step(
1122 &self,
1123 x: &mut [f32],
1124 pos: usize,
1125 cap: usize,
1126 cache: &mut [Vec<KvRun>],
1127 logits: &mut [Vec<f32>; 2],
1128 ) -> bool {
1129 let hs = self.hidden;
1130 let Some((model, _)) = self.blocks.first().and_then(|b| b.q.graph_w()) else {
1131 return false;
1132 };
1133 let model = model.clone();
1134 let Some((_, lm)) = self.lm_head.graph_w() else {
1135 return false;
1136 };
1137 let lm_rows = self.lm_head_rows();
1138 let mut staged: [(Vec<f32>, Vec<f32>); 2] = Default::default();
1139 for bi in 0..2 {
1140 let mut layers: Vec<crate::gpu::GraphLayer> = Vec::with_capacity(self.blocks.len());
1141 for (li, blk) in self.blocks.iter().enumerate() {
1142 let (Some((_, wq)), Some((_, wk)), Some((_, wv)), Some((_, wo))) = (
1143 blk.q.graph_w(),
1144 blk.k.graph_w(),
1145 blk.v.graph_w(),
1146 blk.o.graph_w(),
1147 ) else {
1148 return false;
1149 };
1150 let (Some((_, g)), Some((_, u)), Some((_, d))) =
1151 (blk.gate.graph_w(), blk.up.graph_w(), blk.down.graph_w())
1152 else {
1153 return false;
1154 };
1155 layers.push(crate::gpu::GraphLayer {
1156 input_norm: &blk.n1.w,
1157 attn: crate::gpu::GraphAttn::Full {
1158 wq,
1159 wk,
1160 wv,
1161 wo,
1162 q_norm: Some(&blk.qn.w),
1163 k_norm: Some(&blk.kn.w),
1164 bias: None,
1165 output_gate: false,
1166 cpu_k: &cache[li][bi].k,
1167 cpu_v: &cache[li][bi].v,
1168 },
1169 post_norm: &blk.n2.w,
1170 ffn: crate::gpu::GraphFfn::Dense {
1171 gate: g,
1172 up: u,
1173 down: d,
1174 },
1175 });
1176 }
1177 let mut h = x[bi * hs..(bi + 1) * hs].to_vec();
1178 let mut out = Vec::new();
1179 let ok = crate::gpu::forward_token_graph(
1180 &model,
1181 bi as u64,
1182 &layers,
1183 &[],
1184 0,
1185 &self.inv_freq,
1186 &mut h,
1187 self.nh,
1188 self.nkv,
1189 self.hd,
1190 self.hd,
1191 hs,
1192 self.inter,
1193 pos,
1194 cap,
1195 false,
1196 1e-6,
1197 Some((&lm, lm_rows)),
1198 &self.norm.w,
1199 &mut out,
1200 &[],
1201 1,
1202 None,
1203 None,
1204 None,
1205 0,
1206 false,
1207 );
1208 if !ok || out.len() < lm_rows {
1209 return false;
1210 }
1211 staged[bi] = (h, out);
1212 }
1213 for (bi, (h, out)) in staged.into_iter().enumerate() {
1217 x[bi * hs..(bi + 1) * hs].copy_from_slice(&h);
1218 logits[bi] = out;
1219 }
1220 true
1221 }
1222
1223 fn step_blocks(&self, x: &mut [f32], b: usize, pos: usize, cache: &mut [Vec<KvRun>]) {
1226 let (hs, nh, nkv, hd) = (self.hidden, self.nh, self.nkv, self.hd);
1227 let pool = self.pool.as_deref();
1228 let kvw = nkv * hd;
1229 for (li, blk) in self.blocks.iter().enumerate() {
1230 let mut h = x.to_vec();
1231 blk.n1.apply(&mut h, hs);
1232 let mut q = vec![0f32; b * nh * hd];
1233 let mut k = vec![0f32; b * kvw];
1234 let mut v = vec![0f32; b * kvw];
1235 blk.q.matmat(&h, b, &mut q, pool);
1236 blk.k.matmat(&h, b, &mut k, pool);
1237 blk.v.matmat(&h, b, &mut v, pool);
1238 for bi in 0..b {
1241 for hh in 0..nh {
1242 let s = bi * nh * hd + hh * hd;
1243 blk.qn.apply(&mut q[s..s + hd], hd);
1244 rope_half(&mut q[s..s + hd], pos, &self.inv_freq);
1245 }
1246 for hh in 0..nkv {
1247 let s = bi * kvw + hh * hd;
1248 blk.kn.apply(&mut k[s..s + hd], hd);
1249 rope_half(&mut k[s..s + hd], pos, &self.inv_freq);
1250 }
1251 }
1252 let mut attn = vec![0f32; b * nh * hd];
1253 let per_kv = nh / nkv;
1254 for bi in 0..b {
1255 let run = &mut cache[li][bi];
1256 for g in 0..nkv {
1257 run.k[g].extend_from_slice(&k[bi * kvw + g * hd..bi * kvw + (g + 1) * hd]);
1258 run.v[g].extend_from_slice(&v[bi * kvw + g * hd..bi * kvw + (g + 1) * hd]);
1259 }
1260 run.len += 1;
1261 let n = run.len;
1262 let scale = 1.0 / (hd as f32).sqrt();
1263 for hh in 0..nh {
1264 let g = hh / per_kv;
1265 let qi = &q[bi * nh * hd + hh * hd..bi * nh * hd + hh * hd + hd];
1266 let mut sc = vec![0f32; n];
1267 let mut mx = f32::NEG_INFINITY;
1268 for (j, s) in sc.iter_mut().enumerate() {
1269 let kj = &run.k[g][j * hd..(j + 1) * hd];
1270 *s = qi.iter().zip(kj).map(|(a, c)| a * c).sum::<f32>() * scale;
1271 mx = mx.max(*s);
1272 }
1273 let mut sum = 0.0;
1274 for s in sc.iter_mut() {
1275 *s = (*s - mx).exp();
1276 sum += *s;
1277 }
1278 let inv = 1.0 / sum;
1279 let dst = &mut attn[bi * nh * hd + hh * hd..bi * nh * hd + hh * hd + hd];
1280 for (j, &s) in sc.iter().enumerate() {
1281 let w = s * inv;
1282 let vj = &run.v[g][j * hd..(j + 1) * hd];
1283 for (d, &vv) in dst.iter_mut().zip(vj) {
1284 *d += w * vv;
1285 }
1286 }
1287 }
1288 }
1289 let mut proj = vec![0f32; b * hs];
1290 blk.o.matmat(&attn, b, &mut proj, pool);
1291 for (a, c) in x.iter_mut().zip(&proj) {
1292 *a += c;
1293 }
1294 let mut h = x.to_vec();
1295 blk.n2.apply(&mut h, hs);
1296 let (mut g, mut u2) = (vec![0f32; b * self.inter], vec![0f32; b * self.inter]);
1297 blk.gate.matmat(&h, b, &mut g, pool);
1298 blk.up.matmat(&h, b, &mut u2, pool);
1299 for (a, c) in g.iter_mut().zip(&u2) {
1300 *a = silu(*a) * c;
1301 }
1302 let mut ffo = vec![0f32; b * hs];
1303 blk.down.matmat(&g, b, &mut ffo, pool);
1304 for (a, c) in x.iter_mut().zip(&ffo) {
1305 *a += c;
1306 }
1307 }
1308 }
1309
1310 pub fn generate(
1317 &self,
1318 prompt_ids: &[u32],
1319 seed: u64,
1320 frames: usize,
1321 mut progress: impl FnMut(usize, usize),
1322 ) -> Result<(Vec<f32>, usize), String> {
1323 let hs = self.hidden;
1324 let pool = self.pool.as_deref();
1325 let want = frames.min(self.max_frames);
1326 let mut cache: Vec<Vec<KvRun>> = (0..self.blocks.len())
1327 .map(|_| vec![KvRun::init(self.nkv); 2])
1328 .collect();
1329 let mut uncond = prompt_ids.to_vec();
1331 if uncond.len() > 3 {
1332 let n = uncond.len();
1333 for t in uncond[1..n - 2].iter_mut() {
1334 *t = tokens::AUDIO_CFG;
1335 }
1336 }
1337 let cap = prompt_ids.len() + want + 2;
1338 let mut graph = std::env::var("CMF_MUSIC3_GRAPH").as_deref() == Ok("1");
1351 let mut glogits: [Vec<f32>; 2] = Default::default();
1352 let mut last = vec![0f32; 2 * hs];
1353 for (pos, (&a, &b)) in prompt_ids.iter().zip(&uncond).enumerate() {
1354 let mut x = vec![0f32; 2 * hs];
1355 x[..hs].copy_from_slice(&Self::embed_row(&self.embed_prefill, a as usize, hs));
1356 x[hs..].copy_from_slice(&Self::embed_row(&self.embed_prefill, b as usize, hs));
1357 if graph {
1358 if self.graph_step(&mut x, pos, cap, &mut cache, &mut glogits) {
1359 last = x;
1360 if pos % 64 == 0 {
1361 progress(0, want);
1362 }
1363 continue;
1364 }
1365 if pos > 0 {
1368 return Err("the token graph refused mid-prefill".into());
1369 }
1370 graph = false;
1371 }
1372 self.step_blocks(&mut x, 2, pos, &mut cache);
1373 last = x;
1374 if pos % 64 == 0 {
1375 progress(0, want);
1376 }
1377 }
1378 let mut rng = Rng::new(seed);
1379 let mut out: Vec<f32> = Vec::with_capacity(want * self.codebooks * hs);
1380 let mut done = 0usize;
1381 let scale = (self.codebooks as f32).powf(-0.5);
1382 for frame in 0..want {
1383 let mut normed = last.clone();
1384 self.norm.apply(&mut normed, hs);
1385 let vocab = self.lm_head_rows();
1390 let mut logits = vec![0f32; 2 * vocab];
1391 if graph {
1392 logits[..vocab].copy_from_slice(&glogits[0][..vocab]);
1393 logits[vocab..].copy_from_slice(&glogits[1][..vocab]);
1394 } else {
1395 self.lm_head.matmat(&normed, 2, &mut logits, pool);
1396 }
1397 let (cond, unc) = logits.split_at(vocab);
1398 let mut thr: Vec<f32> = cond.to_vec();
1399 thr.sort_unstable_by(|a, b| b.partial_cmp(a).unwrap());
1400 let cut = thr[self.top_k.min(vocab) - 1];
1401 let guided: Vec<f32> = (0..vocab)
1402 .map(|i| {
1403 if cond[i] < cut {
1404 f32::NEG_INFINITY
1405 } else {
1406 unc[i] + (cond[i] - unc[i]) * self.cfg_scale
1407 }
1408 })
1409 .collect();
1410 let code = sample_topk(&guided, self.top_k, &mut rng);
1411 if code == 0 {
1412 break; }
1414 let c0 = code - 1;
1415 let c0_embed = Self::embed_row(&self.embed_audio, c0, hs);
1416 let mut seq = self.depth.project(&normed[..hs]);
1419 seq.extend_from_slice(&self.depth.project(&c0_embed));
1420 let mut codes = vec![c0];
1421 let mut frame_hidden = normed[..hs].to_vec();
1422 for level in 1..self.codebooks {
1423 let n = seq.len() / hs;
1424 let h = self.depth.forward_last(&seq, n);
1425 frame_hidden.extend_from_slice(&h);
1426 let lg = self.depth.head(level, &h);
1427 let c = sample_topk(&lg, self.top_k, &mut rng);
1428 codes.push(c);
1429 if level < self.codebooks - 1 {
1430 let e =
1431 Self::embed_row(&self.embed_extra, c + (level - 1) * self.audio_vocab, hs);
1432 seq.extend_from_slice(&self.depth.project(&e));
1433 }
1434 }
1435 out.extend_from_slice(&frame_hidden);
1436 done += 1;
1437 progress(done, want);
1438 if done >= want {
1439 break;
1440 }
1441 let mut fb = Self::embed_row(&self.embed_audio, codes[0], hs);
1444 for (level, &c) in codes.iter().enumerate().skip(1) {
1445 let e = Self::embed_row(&self.embed_extra, c + (level - 1) * self.audio_vocab, hs);
1446 for (a, b) in fb.iter_mut().zip(&e) {
1447 *a += b;
1448 }
1449 }
1450 for a in fb.iter_mut() {
1451 *a *= scale;
1452 }
1453 let mut x = vec![0f32; 2 * hs];
1454 x[..hs].copy_from_slice(&fb);
1455 x[hs..].copy_from_slice(&fb);
1456 let pos = prompt_ids.len() + frame;
1457 if !graph || !self.graph_step(&mut x, pos, cap, &mut cache, &mut glogits) {
1458 if graph {
1459 return Err("the token graph refused mid-song".into());
1460 }
1461 self.step_blocks(&mut x, 2, pos, &mut cache);
1462 }
1463 last = x;
1464 }
1465 if done == 0 {
1466 return Err("MiniMax-Music-3 generated zero audio frames".into());
1467 }
1468 Ok((out, done))
1469 }
1470
1471 fn lm_head_rows(&self) -> usize {
1472 match &self.lm_head {
1473 Proj::F32 { rows, .. } => *rows,
1474 Proj::Q(q) => q.rows(),
1475 }
1476 }
1477}
1478
1479fn rope_half(x: &mut [f32], pos: usize, inv_freq: &[f32]) {
1481 let half = x.len() / 2;
1482 for i in 0..half {
1483 let (s, c) = (pos as f32 * inv_freq[i]).sin_cos();
1484 let (a, b) = (x[i], x[i + half]);
1485 x[i] = a * c - b * s;
1486 x[i + half] = b * c + a * s;
1487 }
1488}
1489
1490#[cfg(test)]
1491mod tests {
1492 use super::*;
1493
1494 #[test]
1501 fn music3_sampler_and_vocoder_compose() {
1502 let Ok(p) = std::env::var("CMF_MUSIC3_DIT") else {
1503 eprintln!("CMF_MUSIC3_DIT unset — skipping Music-3 chain test");
1504 return;
1505 };
1506 let model = Arc::new(CmfModel::open(&p).expect("open pack"));
1507 let dit = Music3Dit::from_cmf(&model).expect("load DiT");
1508 let dav = crate::audiovae::Music3Dav::from_cmf(&model).expect("load DAV");
1509 let n = 6usize;
1510 let noise: Vec<f32> = (0..Music3Dit::IN_CH * n)
1512 .map(|i| (((i * 2654435761) % 1000) as f32 / 500.0) - 1.0)
1513 .collect();
1514 let cond = vec![0f32; Music3Dit::COND_CH * n];
1515 let steps = 3;
1516 let mut seen = 0usize;
1517 let latent = dit.sample(&noise, &cond, n, steps, |i, t| {
1518 assert_eq!(t, steps);
1519 seen = i;
1520 });
1521 assert_eq!(seen, steps, "sampler reported every step");
1522 assert_eq!(latent.len(), Music3Dit::IN_CH * n);
1523 assert!(
1524 latent.iter().all(|v| v.is_finite()),
1525 "latent went non-finite"
1526 );
1527 let pcm = dav.decode(&latent, n, None);
1528 assert_eq!(
1529 pcm.len(),
1530 n * crate::audiovae::Music3Dav::HOP * 2,
1531 "the chain's sample count is frames x 512 x 2"
1532 );
1533 assert!(pcm.iter().all(|v| v.is_finite() && v.abs() <= 1.0));
1534 let secs = (n * crate::audiovae::Music3Dav::HOP) as f32
1535 / crate::audiovae::Music3Dav::SAMPLE_RATE as f32;
1536 eprintln!(
1537 "music3 chain: {n} frames -> {} stereo samples ({secs:.3} s at 44.1 kHz)",
1538 pcm.len() / 2
1539 );
1540 }
1541
1542 #[test]
1547 fn music3_rvq_depth_decoder_is_causal() {
1548 let Ok(p) = std::env::var("CMF_MUSIC3_TE") else {
1549 eprintln!("CMF_MUSIC3_TE unset — skipping RVQ decoder test");
1550 return;
1551 };
1552 let model = Arc::new(CmfModel::open(&p).expect("open packed AR stack"));
1553 let dec = RvqDepthDecoder::from_cmf(&model).expect("load RVQ decoder");
1554 assert_eq!(dec.codebooks(), 8, "eight codebooks");
1555 let hs = dec.hidden;
1556 let seq: Vec<f32> = (0..3 * hs)
1557 .map(|i| 0.05 * ((i as f32) * 0.013).sin())
1558 .collect();
1559 let a = dec.forward_last(&seq[..2 * hs], 2);
1560 let b = dec.forward_last(&seq, 3);
1561 assert_eq!(a.len(), hs);
1562 assert!(a.iter().all(|v| v.is_finite()) && b.iter().all(|v| v.is_finite()));
1563 let a2 = dec.forward_last(&seq[..2 * hs], 2);
1567 let d = a
1568 .iter()
1569 .zip(&a2)
1570 .map(|(x, y)| (x - y).abs())
1571 .fold(0f32, f32::max);
1572 assert!(d == 0.0, "not deterministic: {d}");
1573 let logits = dec.head(1, &b);
1574 assert_eq!(logits.len(), 1024, "audio vocab is 1024 per level");
1575 assert!(logits.iter().all(|v| v.is_finite()));
1576 let spread = logits.iter().fold(f32::MIN, |m, v| m.max(*v))
1577 - logits.iter().fold(f32::MAX, |m, v| m.min(*v));
1578 assert!(spread > 1e-3, "head is flat, spread {spread}");
1579 eprintln!("music3 rvq: 8 codebooks, head spread {spread:.3}");
1580 }
1581
1582 #[test]
1591 fn music3_dit_forward_has_the_reference_geometry() {
1592 let Ok(p) = std::env::var("CMF_MUSIC3_DIT") else {
1593 eprintln!("CMF_MUSIC3_DIT unset — skipping Music-3 DiT test");
1594 return;
1595 };
1596 let model = Arc::new(CmfModel::open(&p).expect("open packed DiT"));
1597 let dit = Music3Dit::from_cmf(&model).expect("load DiT");
1598 let n = 4usize;
1599 let x: Vec<f32> = (0..Music3Dit::IN_CH * n)
1600 .map(|i| 0.3 * ((i as f32) * 0.017).sin())
1601 .collect();
1602 let cond: Vec<f32> = (0..Music3Dit::COND_CH * n)
1603 .map(|i| 0.2 * ((i as f32) * 0.011).cos())
1604 .collect();
1605 let v = dit.forward(&x, &cond, n, 0.7);
1606 assert_eq!(v.len(), Music3Dit::IN_CH * n, "velocity is [128, n]");
1607 assert!(v.iter().all(|q| q.is_finite()), "non-finite velocity");
1608 let rms = (v.iter().map(|q| q * q).sum::<f32>() / v.len() as f32).sqrt();
1609 assert!(rms > 1e-6, "velocity is silent, rms {rms}");
1610
1611 let zero_cond = vec![0f32; Music3Dit::COND_CH * n];
1612 let v0 = dit.forward(&x, &zero_cond, n, 0.7);
1613 let dc = v
1614 .iter()
1615 .zip(&v0)
1616 .map(|(a, b)| (a - b).abs())
1617 .fold(0f32, f32::max);
1618 assert!(dc > 1e-5, "condition changed nothing — concat is wrong");
1619
1620 let vt = dit.forward(&x, &cond, n, 0.2);
1621 let dt = v
1622 .iter()
1623 .zip(&vt)
1624 .map(|(a, b)| (a - b).abs())
1625 .fold(0f32, f32::max);
1626 assert!(dt > 1e-5, "timestep changed nothing — the token is lost");
1627 eprintln!("music3 dit: rms {rms:.4}, d/dcond {dc:.4}, d/dt {dt:.4}");
1628 }
1629}
1630
1631pub mod prof {
1635 use std::sync::OnceLock;
1636 use std::sync::atomic::{AtomicU64, Ordering};
1637 use std::time::Instant;
1638
1639 pub static QKV: AtomicU64 = AtomicU64::new(0);
1640 pub static ATTN: AtomicU64 = AtomicU64::new(0);
1641 pub static OUT: AtomicU64 = AtomicU64::new(0);
1642 pub static FFN: AtomicU64 = AtomicU64::new(0);
1643
1644 pub fn on() -> bool {
1645 static ON: OnceLock<bool> = OnceLock::new();
1646 *ON.get_or_init(|| std::env::var("CMF_MUSIC3_PROF").as_deref() == Ok("1"))
1647 }
1648
1649 pub fn start() -> Option<Instant> {
1651 on().then(Instant::now)
1652 }
1653
1654 pub fn add(c: &AtomicU64, t: Option<Instant>) {
1655 if let Some(t) = t {
1656 c.fetch_add(t.elapsed().as_nanos() as u64, Ordering::Relaxed);
1657 }
1658 }
1659
1660 pub fn report() -> String {
1661 let g = |c: &AtomicU64| c.load(Ordering::Relaxed) as f64 / 1e9;
1662 format!(
1663 "qkv {:.1}s, attention {:.1}s, out {:.1}s, ffn {:.1}s",
1664 g(&QKV),
1665 g(&ATTN),
1666 g(&OUT),
1667 g(&FFN)
1668 )
1669 }
1670}