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(&self, q: &mut [f32], k: &mut [f32], n: usize) {
255 let half = self.rot / 2;
256 for p in 0..n {
257 for h in 0..self.heads {
258 let off = p * self.heads * self.hd + h * self.hd;
259 for i in 0..half {
260 let (s, c) = (p as f32 * self.inv_freq[i]).sin_cos();
261 for x in [&mut *q, &mut *k] {
262 let (a, b) = (x[off + i], x[off + i + half]);
263 x[off + i] = a * c - b * s;
264 x[off + i + half] = a * s + b * c;
265 }
266 }
267 }
268 }
269 }
270
271 fn block(&self, blk: &Block, x: &mut [f32], n: usize) {
273 let (hs, nh, hd) = (self.hidden, self.heads, self.hd);
274 let pool = self.pool.as_deref();
275 let mut h = x.to_vec();
276 blk.pre_norm.apply(&mut h, hs);
277 let mut qkv = vec![0f32; n * 3 * hs];
278 blk.qkv.matmat(&h, n, &mut qkv, pool);
279 let mut q = vec![0f32; n * hs];
282 let mut k = vec![0f32; n * hs];
283 let mut v = vec![0f32; n * hs];
284 for p in 0..n {
285 let s = &qkv[p * 3 * hs..(p + 1) * 3 * hs];
286 q[p * hs..(p + 1) * hs].copy_from_slice(&s[..hs]);
287 k[p * hs..(p + 1) * hs].copy_from_slice(&s[hs..2 * hs]);
288 v[p * hs..(p + 1) * hs].copy_from_slice(&s[2 * hs..]);
289 }
290 self.rope(&mut q, &mut k, n);
291 let scale = 1.0 / (hd as f32).sqrt();
292 let mut attn = vec![0f32; n * hs];
293 {
299 let ptr = SendPtr(attn.as_mut_ptr());
300 let work = |lo: usize, hi: usize| {
301 let mut scores = vec![0f32; n];
302 for hh in lo..hi {
303 for i in 0..n {
304 let qi = &q[i * hs + hh * hd..i * hs + hh * hd + hd];
305 let mut mx = f32::NEG_INFINITY;
306 for (j, sc) in scores.iter_mut().enumerate() {
307 let kj = &k[j * hs + hh * hd..j * hs + hh * hd + hd];
308 *sc = qi.iter().zip(kj).map(|(a, b)| a * b).sum::<f32>() * scale;
309 mx = mx.max(*sc);
310 }
311 let mut sum = 0.0;
312 for sc in scores.iter_mut() {
313 *sc = (*sc - mx).exp();
314 sum += *sc;
315 }
316 let inv = 1.0 / sum;
317 let dst = unsafe { ptr.row(i * hs + hh * hd, hd) };
319 for (j, &sc) in scores.iter().enumerate() {
320 let w = sc * inv;
321 let vj = &v[j * hs + hh * hd..j * hs + hh * hd + hd];
322 for (d, &vv) in dst.iter_mut().zip(vj) {
323 *d += w * vv;
324 }
325 }
326 }
327 }
328 };
329 match pool {
330 Some(p) => p.run_rows(nh, &work),
331 None => work(0, nh),
332 }
333 }
334 let mut proj = vec![0f32; n * hs];
335 blk.out.matmat(&attn, n, &mut proj, pool);
336 for (a, b) in x.iter_mut().zip(&proj) {
337 *a += b;
338 }
339
340 let mut h = x.to_vec();
341 blk.ff_norm.apply(&mut h, hs);
342 let mut gu = vec![0f32; n * 2 * self.inter];
343 blk.ff_in.matmat(&h, n, &mut gu, pool);
344 let inter = self.inter;
349 let (vb, gb) = blk.ff_in_b.split_at(inter);
350 let mut act = vec![0f32; n * inter];
351 for p in 0..n {
352 let row = &gu[p * 2 * inter..(p + 1) * 2 * inter];
353 let (val, gate) = row.split_at(inter);
354 let dst = &mut act[p * inter..(p + 1) * inter];
355 for i in 0..inter {
356 dst[i] = (val[i] + vb[i]) * silu(gate[i] + gb[i]);
357 }
358 }
359 let mut ffo = vec![0f32; n * hs];
360 blk.ff_out.matmat(&act, n, &mut ffo, pool);
361 for p in 0..n {
362 for j in 0..hs {
363 x[p * hs + j] += ffo[p * hs + j] + blk.ff_out_b[j];
364 }
365 }
366 }
367
368 pub const WINDOW: usize = 689;
374 pub const HOP: usize = 344;
375
376 pub fn forward_windowed(&self, x: &[f32], condition: &[f32], n: usize, t: f32) -> Vec<f32> {
379 if n <= Self::WINDOW {
380 return self.forward(x, condition, n, t);
381 }
382 let ch = Self::IN_CH;
383 let cc = Self::COND_CH;
384 let mut out = vec![0f32; ch * n];
385 let mut count = vec![0f32; n];
386 let mut start = 0usize;
387 loop {
388 let end = (start + Self::WINDOW).min(n);
389 let w = end - start;
390 let mut xw = vec![0f32; ch * w];
391 for c in 0..ch {
392 xw[c * w..(c + 1) * w].copy_from_slice(&x[c * n + start..c * n + end]);
393 }
394 let mut cw = vec![0f32; cc * w];
395 for c in 0..cc {
396 cw[c * w..(c + 1) * w].copy_from_slice(&condition[c * n + start..c * n + end]);
397 }
398 let v = self.forward(&xw, &cw, w, t);
399 for c in 0..ch {
400 for i in 0..w {
401 out[c * n + start + i] += v[c * w + i];
402 }
403 }
404 for i in 0..w {
405 count[start + i] += 1.0;
406 }
407 if end == n {
408 break;
409 }
410 start += Self::HOP;
411 }
412 for c in 0..ch {
413 for i in 0..n {
414 out[c * n + i] /= count[i];
415 }
416 }
417 out
418 }
419
420 pub fn forward(&self, x: &[f32], condition: &[f32], n: usize, t: f32) -> Vec<f32> {
423 let pool = self.pool.as_deref();
424 let mut full = vec![0f32; Self::CONCAT_CH * n];
425 full[..Self::IN_CH * n].copy_from_slice(x);
426 full[2 * Self::IN_CH * n..].copy_from_slice(condition);
428 Self::conv1x1_residual(&self.pre_conv, &mut full, Self::CONCAT_CH, n);
429
430 let mut toks = vec![0f32; n * Self::CONCAT_CH];
432 for c in 0..Self::CONCAT_CH {
433 for p in 0..n {
434 toks[p * Self::CONCAT_CH + c] = full[c * n + p];
435 }
436 }
437 let mut h = vec![0f32; n * self.hidden];
438 self.project_in.matmat(&toks, n, &mut h, pool);
439
440 let temb = self.timestep_embedding(t);
442 let mut seq = vec![0f32; (n + 1) * self.hidden];
443 seq[..self.hidden].copy_from_slice(&temb);
444 seq[self.hidden..].copy_from_slice(&h);
445 for blk in &self.blocks {
446 self.block(blk, &mut seq, n + 1);
447 }
448
449 let mut out = vec![0f32; n * Self::IN_CH];
450 self.project_out
451 .matmat(&seq[self.hidden..], n, &mut out, pool);
452 let mut ch = vec![0f32; Self::IN_CH * n];
453 for c in 0..Self::IN_CH {
454 for p in 0..n {
455 ch[c * n + p] = out[p * Self::IN_CH + c];
456 }
457 }
458 Self::conv1x1_residual(&self.post_conv, &mut ch, Self::IN_CH, n);
459 for v in ch.iter_mut() {
460 *v = -*v;
461 }
462 ch
463 }
464
465 pub fn sample(
468 &self,
469 noise: &[f32],
470 condition: &[f32],
471 n: usize,
472 steps: usize,
473 mut progress: impl FnMut(usize, usize),
474 ) -> Vec<f32> {
475 let sigmas = flow_sigmas(steps);
476 let mut x = noise.to_vec();
477 for i in 0..steps {
478 let (s, s_next) = (sigmas[i], sigmas[i + 1]);
479 let v = self.forward_windowed(&x, condition, n, 1.0 - s);
481 let dt = s_next - s;
482 for (a, b) in x.iter_mut().zip(&v) {
483 *a += dt * b;
484 }
485 progress(i + 1, steps);
486 }
487 x
488 }
489}
490
491pub fn flow_sigmas(steps: usize) -> Vec<f32> {
514 const SIGMA_MIN: f32 = 0.001;
515 let n = steps.max(1);
516 let mut s: Vec<f32> = (0..n)
517 .map(|i| {
518 if n == 1 {
519 1.0
520 } else {
521 1.0 + (SIGMA_MIN - 1.0) * i as f32 / (n - 1) as f32
522 }
523 })
524 .collect();
525 s.push(0.0);
526 s
527}
528
529struct RmsNorm {
531 w: Vec<f32>,
532}
533
534impl RmsNorm {
535 fn load(model: &Arc<CmfModel>, n: &str) -> Result<Self, String> {
536 Ok(Self {
537 w: crate::dit::cmf_f32(model, n)?,
538 })
539 }
540
541 fn apply(&self, x: &mut [f32], d: usize) {
542 for row in x.chunks_exact_mut(d) {
543 let ss = row.iter().map(|v| (*v as f64) * (*v as f64)).sum::<f64>() / d as f64;
544 let inv = 1.0 / (ss + 1e-6).sqrt();
545 for (v, &g) in row.iter_mut().zip(&self.w) {
546 *v = (*v as f64 * inv) as f32 * g;
547 }
548 }
549 }
550}
551
552struct RvqBlock {
553 n1: RmsNorm,
554 q: Proj,
555 k: Proj,
556 v: Proj,
557 o: Proj,
558 n2: RmsNorm,
559 gate: Proj,
560 up: Proj,
561 down: Proj,
562}
563
564impl RvqBlock {
565 fn load(model: &Arc<CmfModel>, p: &str) -> Result<Self, String> {
566 Ok(Self {
567 n1: RmsNorm::load(model, &format!("{p}.input_layernorm.weight"))?,
568 q: Proj::from_model(model, &format!("{p}.self_attn.q_proj.weight"))?,
569 k: Proj::from_model(model, &format!("{p}.self_attn.k_proj.weight"))?,
570 v: Proj::from_model(model, &format!("{p}.self_attn.v_proj.weight"))?,
571 o: Proj::from_model(model, &format!("{p}.self_attn.o_proj.weight"))?,
572 n2: RmsNorm::load(model, &format!("{p}.post_attention_layernorm.weight"))?,
573 gate: Proj::from_model(model, &format!("{p}.mlp.gate_proj.weight"))?,
574 up: Proj::from_model(model, &format!("{p}.mlp.up_proj.weight"))?,
575 down: Proj::from_model(model, &format!("{p}.mlp.down_proj.weight"))?,
576 })
577 }
578}
579
580pub struct RvqDepthDecoder {
588 projection: Proj,
589 pos: Vec<f32>,
590 blocks: Vec<RvqBlock>,
591 norm: RmsNorm,
592 heads: Vec<Proj>,
593 pool: Option<Arc<Pool>>,
594 hidden: usize,
595 nh: usize,
596 hd: usize,
597 inter: usize,
598}
599
600impl RvqDepthDecoder {
601 pub fn from_cmf(model: &Arc<CmfModel>) -> Result<Self, String> {
602 let cfg: serde_json::Value =
603 serde_json::from_slice(model.tensor_bytes("mte.config_json").map_err(|e| e.to_string())?)
604 .map_err(|e| format!("mte.config_json: {e}"))?;
605 let u = |k: &str, d: usize| cfg[k].as_u64().map(|v| v as usize).unwrap_or(d);
606 let hidden = u("hidden_size", 4096);
607 let nl = u("decoder_num_layers", 4);
608 let nh = u("decoder_num_heads", 16);
609 let cb = u("audio_num_codebooks", 8);
610 Ok(Self {
611 projection: Proj::from_model(model, "mte.audio_decoder.projection.weight")?,
612 pos: crate::dit::cmf_f32(model, "mte.audio_decoder.pos_embedding.weight")?,
613 blocks: (0..nl)
614 .map(|i| RvqBlock::load(model, &format!("mte.audio_decoder.layers.{i}")))
615 .collect::<Result<_, _>>()?,
616 norm: RmsNorm::load(model, "mte.audio_decoder.norm.weight")?,
617 heads: (0..cb - 1)
618 .map(|i| {
619 Proj::from_model(model, &format!("mte.audio_decoder.audio_heads.{i}.weight"))
620 })
621 .collect::<Result<_, _>>()?,
622 pool: Pool::from_env(),
623 hidden,
624 nh,
625 hd: hidden / nh,
626 inter: u("decoder_intermediate_size", 6144),
627 })
628 }
629
630 pub fn codebooks(&self) -> usize {
631 self.heads.len() + 1
632 }
633
634 pub fn project(&self, x: &[f32]) -> Vec<f32> {
637 let n = x.len() / self.hidden;
638 let mut out = vec![0f32; n * self.hidden];
639 self.projection
640 .matmat(x, n, &mut out, self.pool.as_deref());
641 out
642 }
643
644 pub fn forward_last(&self, seq: &[f32], n: usize) -> Vec<f32> {
647 let (hs, nh, hd) = (self.hidden, self.nh, self.hd);
648 let pool = self.pool.as_deref();
649 let mut x = seq.to_vec();
650 for p in 0..n {
651 for (v, &pe) in x[p * hs..(p + 1) * hs].iter_mut().zip(&self.pos[p * hs..(p + 1) * hs]) {
652 *v += pe;
653 }
654 }
655 for blk in &self.blocks {
656 let mut h = x.clone();
657 blk.n1.apply(&mut h, hs);
658 let (mut q, mut k, mut v) = (vec![0f32; n * hs], vec![0f32; n * hs], vec![0f32; n * hs]);
659 blk.q.matmat(&h, n, &mut q, pool);
660 blk.k.matmat(&h, n, &mut k, pool);
661 blk.v.matmat(&h, n, &mut v, pool);
662 let scale = 1.0 / (hd as f32).sqrt();
663 let mut attn = vec![0f32; n * hs];
664 for hh in 0..nh {
665 for i in 0..n {
666 let qi = &q[i * hs + hh * hd..i * hs + hh * hd + hd];
667 let mut sc = vec![0f32; i + 1];
669 let mut mx = f32::NEG_INFINITY;
670 for (j, s) in sc.iter_mut().enumerate() {
671 let kj = &k[j * hs + hh * hd..j * hs + hh * hd + hd];
672 *s = qi.iter().zip(kj).map(|(a, b)| a * b).sum::<f32>() * scale;
673 mx = mx.max(*s);
674 }
675 let mut sum = 0.0;
676 for s in sc.iter_mut() {
677 *s = (*s - mx).exp();
678 sum += *s;
679 }
680 let inv = 1.0 / sum;
681 let dst = &mut attn[i * hs + hh * hd..i * hs + hh * hd + hd];
682 for (j, &s) in sc.iter().enumerate() {
683 let w = s * inv;
684 let vj = &v[j * hs + hh * hd..j * hs + hh * hd + hd];
685 for (d, &vv) in dst.iter_mut().zip(vj) {
686 *d += w * vv;
687 }
688 }
689 }
690 }
691 let mut proj = vec![0f32; n * hs];
692 blk.o.matmat(&attn, n, &mut proj, pool);
693 for (a, b) in x.iter_mut().zip(&proj) {
694 *a += b;
695 }
696
697 let mut h = x.clone();
698 blk.n2.apply(&mut h, hs);
699 let (mut g, mut u) = (vec![0f32; n * self.inter], vec![0f32; n * self.inter]);
700 blk.gate.matmat(&h, n, &mut g, pool);
701 blk.up.matmat(&h, n, &mut u, pool);
702 for (a, b) in g.iter_mut().zip(&u) {
703 *a = silu(*a) * b;
704 }
705 let mut ffo = vec![0f32; n * hs];
706 blk.down.matmat(&g, n, &mut ffo, pool);
707 for (a, b) in x.iter_mut().zip(&ffo) {
708 *a += b;
709 }
710 }
711 let mut last = x[(n - 1) * hs..].to_vec();
712 self.norm.apply(&mut last, hs);
713 last
714 }
715
716 pub fn head(&self, level: usize, hidden: &[f32]) -> Vec<f32> {
718 let h = &self.heads[level - 1];
719 let rows = match h {
720 Proj::F32 { rows, .. } => *rows,
721 Proj::Q(q) => q.rows(),
722 };
723 let mut out = vec![0f32; rows];
724 h.matmat(hidden, 1, &mut out, self.pool.as_deref());
725 out
726 }
727}
728
729struct ArBlock {
734 n1: RmsNorm,
735 q: Proj,
736 k: Proj,
737 v: Proj,
738 o: Proj,
739 qn: RmsNorm,
740 kn: RmsNorm,
741 n2: RmsNorm,
742 gate: Proj,
743 up: Proj,
744 down: Proj,
745}
746
747impl ArBlock {
748 fn load(model: &Arc<CmfModel>, p: &str) -> Result<Self, String> {
749 Ok(Self {
750 n1: RmsNorm::load(model, &format!("{p}.input_layernorm.weight"))?,
751 q: Proj::from_model(model, &format!("{p}.self_attn.q_proj.weight"))?,
752 k: Proj::from_model(model, &format!("{p}.self_attn.k_proj.weight"))?,
753 v: Proj::from_model(model, &format!("{p}.self_attn.v_proj.weight"))?,
754 o: Proj::from_model(model, &format!("{p}.self_attn.o_proj.weight"))?,
755 qn: RmsNorm::load(model, &format!("{p}.self_attn.q_norm.weight"))?,
756 kn: RmsNorm::load(model, &format!("{p}.self_attn.k_norm.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
765#[derive(Default, Clone)]
767struct KvRun {
768 k: Vec<f32>,
769 v: Vec<f32>,
770 len: usize,
771}
772
773struct Rng(u64);
780
781impl Rng {
782 fn new(seed: u64) -> Self {
783 Self(seed.wrapping_mul(0x9E37_79B9_7F4A_7C15) | 1)
784 }
785 fn next_f32(&mut self) -> f32 {
786 let mut x = self.0;
787 x ^= x << 13;
788 x ^= x >> 7;
789 x ^= x << 17;
790 self.0 = x;
791 ((x >> 40) as f32) / (1u32 << 24) as f32
792 }
793}
794
795fn sample_topk(logits: &[f32], top_k: usize, rng: &mut Rng) -> usize {
796 let mut idx: Vec<usize> = (0..logits.len()).filter(|&i| logits[i].is_finite()).collect();
797 idx.sort_unstable_by(|&a, &b| logits[b].partial_cmp(&logits[a]).unwrap());
798 idx.truncate(top_k.max(1));
799 let mx = idx.iter().map(|&i| logits[i]).fold(f32::MIN, f32::max);
800 let exps: Vec<f32> = idx.iter().map(|&i| (logits[i] - mx).exp()).collect();
801 let sum: f32 = exps.iter().sum();
802 let mut r = rng.next_f32() * sum;
803 for (j, &e) in exps.iter().enumerate() {
804 r -= e;
805 if r <= 0.0 {
806 return idx[j];
807 }
808 }
809 *idx.last().unwrap()
810}
811
812pub struct Music3Ar {
816 blocks: Vec<ArBlock>,
817 norm: RmsNorm,
818 embed_prefill: QTensor,
819 embed_audio: QTensor,
820 embed_extra: QTensor,
821 lm_head: Proj,
822 pub depth: RvqDepthDecoder,
823 inv_freq: Vec<f32>,
824 pool: Option<Arc<Pool>>,
825 hidden: usize,
826 nh: usize,
827 nkv: usize,
828 hd: usize,
829 inter: usize,
830 audio_vocab: usize,
831 codebooks: usize,
832 pub cfg_scale: f32,
833 pub top_k: usize,
834 pub fps: usize,
835 pub max_frames: usize,
836}
837
838pub mod tokens {
840 pub const IM_START: u32 = 151644;
841 pub const IM_END: u32 = 151645;
842 pub const AUDIO_CFG: u32 = 151654;
843 pub const AUDIO_START: u32 = 151669;
844 pub const CAPTION_START: u32 = 151671;
845 pub const CAPTION_END: u32 = 151672;
846 pub const LYRICS_START: u32 = 151673;
847 pub const LYRICS_END: u32 = 151674;
848}
849
850impl Music3Ar {
851 pub fn from_cmf(model: &Arc<CmfModel>) -> Result<Self, String> {
852 let cfg: serde_json::Value =
853 serde_json::from_slice(model.tensor_bytes("mte.config_json").map_err(|e| e.to_string())?)
854 .map_err(|e| format!("mte.config_json: {e}"))?;
855 let u = |k: &str, d: usize| cfg[k].as_u64().map(|v| v as usize).unwrap_or(d);
856 let f = |k: &str, d: f64| cfg[k].as_f64().unwrap_or(d);
857 let hidden = u("hidden_size", 4096);
858 let hd = u("head_dim", 128);
859 let theta = f("rope_theta", 1_000_000.0) as f32;
860 Ok(Self {
861 blocks: (0..u("num_hidden_layers", 36))
862 .map(|i| ArBlock::load(model, &format!("mte.layers.{i}")))
863 .collect::<Result<_, _>>()?,
864 norm: RmsNorm::load(model, "mte.norm.weight")?,
865 embed_prefill: QTensor::from_model(model, "mte.embed_tokens_prefill.weight")?,
866 embed_audio: QTensor::from_model(model, "mte.embed_tokens_audio.weight")?,
867 embed_extra: QTensor::from_model(model, "mte.audio_extra_embedding.weight")?,
868 lm_head: Proj::from_model(model, "mte.lm_head_pruned.weight")?,
869 depth: RvqDepthDecoder::from_cmf(model)?,
870 inv_freq: (0..hd / 2)
871 .map(|i| 1.0 / theta.powf(2.0 * i as f32 / hd as f32))
872 .collect(),
873 pool: Pool::from_env(),
874 hidden,
875 nh: u("num_attention_heads", 32),
876 nkv: u("num_key_value_heads", 8),
877 hd,
878 inter: u("intermediate_size", 12288),
879 audio_vocab: u("audio_vocab_size", 1024),
880 codebooks: u("audio_num_codebooks", 8),
881 cfg_scale: f("cfg_scale", 1.5) as f32,
882 top_k: u("top_k", 50),
883 fps: u("audio_frames_per_second", 25),
884 max_frames: u("max_audio_frames", 9000),
885 })
886 }
887
888 fn embed_row(p: &QTensor, row: usize, hidden: usize) -> Vec<f32> {
891 let mut out = vec![0f32; hidden];
892 p.row_f32(row, &mut out);
893 out
894 }
895
896 fn step_blocks(&self, x: &mut [f32], b: usize, pos: usize, cache: &mut [Vec<KvRun>]) {
899 let (hs, nh, nkv, hd) = (self.hidden, self.nh, self.nkv, self.hd);
900 let pool = self.pool.as_deref();
901 let kvw = nkv * hd;
902 for (li, blk) in self.blocks.iter().enumerate() {
903 let mut h = x.to_vec();
904 blk.n1.apply(&mut h, hs);
905 let mut q = vec![0f32; b * nh * hd];
906 let mut k = vec![0f32; b * kvw];
907 let mut v = vec![0f32; b * kvw];
908 blk.q.matmat(&h, b, &mut q, pool);
909 blk.k.matmat(&h, b, &mut k, pool);
910 blk.v.matmat(&h, b, &mut v, pool);
911 for bi in 0..b {
914 for hh in 0..nh {
915 let s = bi * nh * hd + hh * hd;
916 blk.qn.apply(&mut q[s..s + hd], hd);
917 rope_half(&mut q[s..s + hd], pos, &self.inv_freq);
918 }
919 for hh in 0..nkv {
920 let s = bi * kvw + hh * hd;
921 blk.kn.apply(&mut k[s..s + hd], hd);
922 rope_half(&mut k[s..s + hd], pos, &self.inv_freq);
923 }
924 }
925 let mut attn = vec![0f32; b * nh * hd];
926 let per_kv = nh / nkv;
927 for bi in 0..b {
928 let run = &mut cache[li][bi];
929 run.k.extend_from_slice(&k[bi * kvw..(bi + 1) * kvw]);
930 run.v.extend_from_slice(&v[bi * kvw..(bi + 1) * kvw]);
931 run.len += 1;
932 let n = run.len;
933 let scale = 1.0 / (hd as f32).sqrt();
934 for hh in 0..nh {
935 let g = hh / per_kv;
936 let qi = &q[bi * nh * hd + hh * hd..bi * nh * hd + hh * hd + hd];
937 let mut sc = vec![0f32; n];
938 let mut mx = f32::NEG_INFINITY;
939 for (j, s) in sc.iter_mut().enumerate() {
940 let kj = &run.k[j * kvw + g * hd..j * kvw + g * hd + hd];
941 *s = qi.iter().zip(kj).map(|(a, c)| a * c).sum::<f32>() * scale;
942 mx = mx.max(*s);
943 }
944 let mut sum = 0.0;
945 for s in sc.iter_mut() {
946 *s = (*s - mx).exp();
947 sum += *s;
948 }
949 let inv = 1.0 / sum;
950 let dst = &mut attn[bi * nh * hd + hh * hd..bi * nh * hd + hh * hd + hd];
951 for (j, &s) in sc.iter().enumerate() {
952 let w = s * inv;
953 let vj = &run.v[j * kvw + g * hd..j * kvw + g * hd + hd];
954 for (d, &vv) in dst.iter_mut().zip(vj) {
955 *d += w * vv;
956 }
957 }
958 }
959 }
960 let mut proj = vec![0f32; b * hs];
961 blk.o.matmat(&attn, b, &mut proj, pool);
962 for (a, c) in x.iter_mut().zip(&proj) {
963 *a += c;
964 }
965 let mut h = x.to_vec();
966 blk.n2.apply(&mut h, hs);
967 let (mut g, mut u2) = (vec![0f32; b * self.inter], vec![0f32; b * self.inter]);
968 blk.gate.matmat(&h, b, &mut g, pool);
969 blk.up.matmat(&h, b, &mut u2, pool);
970 for (a, c) in g.iter_mut().zip(&u2) {
971 *a = silu(*a) * c;
972 }
973 let mut ffo = vec![0f32; b * hs];
974 blk.down.matmat(&g, b, &mut ffo, pool);
975 for (a, c) in x.iter_mut().zip(&ffo) {
976 *a += c;
977 }
978 }
979 }
980
981 pub fn generate(
988 &self,
989 prompt_ids: &[u32],
990 seed: u64,
991 frames: usize,
992 mut progress: impl FnMut(usize, usize),
993 ) -> Result<(Vec<f32>, usize), String> {
994 let hs = self.hidden;
995 let pool = self.pool.as_deref();
996 let want = frames.min(self.max_frames);
997 let mut cache: Vec<Vec<KvRun>> = (0..self.blocks.len())
998 .map(|_| vec![KvRun::default(); 2])
999 .collect();
1000 let mut uncond = prompt_ids.to_vec();
1002 if uncond.len() > 3 {
1003 let n = uncond.len();
1004 for t in uncond[1..n - 2].iter_mut() {
1005 *t = tokens::AUDIO_CFG;
1006 }
1007 }
1008 let mut last = vec![0f32; 2 * hs];
1009 for (pos, (&a, &b)) in prompt_ids.iter().zip(&uncond).enumerate() {
1010 let mut x = vec![0f32; 2 * hs];
1011 x[..hs].copy_from_slice(&Self::embed_row(&self.embed_prefill, a as usize, hs));
1012 x[hs..].copy_from_slice(&Self::embed_row(&self.embed_prefill, b as usize, hs));
1013 self.step_blocks(&mut x, 2, pos, &mut cache);
1014 last = x;
1015 if pos % 64 == 0 {
1016 progress(0, want);
1017 }
1018 }
1019 let mut rng = Rng::new(seed);
1020 let mut out: Vec<f32> = Vec::with_capacity(want * self.codebooks * hs);
1021 let mut done = 0usize;
1022 let scale = (self.codebooks as f32).powf(-0.5);
1023 for frame in 0..want {
1024 let mut normed = last.clone();
1025 self.norm.apply(&mut normed, hs);
1026 let mut logits = vec![0f32; 2 * self.lm_head_rows()];
1029 self.lm_head.matmat(&normed, 2, &mut logits, pool);
1030 let vocab = self.lm_head_rows();
1031 let (cond, unc) = logits.split_at(vocab);
1032 let mut thr: Vec<f32> = cond.to_vec();
1033 thr.sort_unstable_by(|a, b| b.partial_cmp(a).unwrap());
1034 let cut = thr[self.top_k.min(vocab) - 1];
1035 let guided: Vec<f32> = (0..vocab)
1036 .map(|i| {
1037 if cond[i] < cut {
1038 f32::NEG_INFINITY
1039 } else {
1040 unc[i] + (cond[i] - unc[i]) * self.cfg_scale
1041 }
1042 })
1043 .collect();
1044 let code = sample_topk(&guided, self.top_k, &mut rng);
1045 if code == 0 {
1046 break; }
1048 let c0 = code - 1;
1049 let c0_embed = Self::embed_row(&self.embed_audio, c0, hs);
1050 let mut seq = self.depth.project(&normed[..hs]);
1053 seq.extend_from_slice(&self.depth.project(&c0_embed));
1054 let mut codes = vec![c0];
1055 let mut frame_hidden = normed[..hs].to_vec();
1056 for level in 1..self.codebooks {
1057 let n = seq.len() / hs;
1058 let h = self.depth.forward_last(&seq, n);
1059 frame_hidden.extend_from_slice(&h);
1060 let lg = self.depth.head(level, &h);
1061 let c = sample_topk(&lg, self.top_k, &mut rng);
1062 codes.push(c);
1063 if level < self.codebooks - 1 {
1064 let e = Self::embed_row(&self.embed_extra, c + (level - 1) * self.audio_vocab, hs);
1065 seq.extend_from_slice(&self.depth.project(&e));
1066 }
1067 }
1068 out.extend_from_slice(&frame_hidden);
1069 done += 1;
1070 progress(done, want);
1071 if done >= want {
1072 break;
1073 }
1074 let mut fb = Self::embed_row(&self.embed_audio, codes[0], hs);
1077 for (level, &c) in codes.iter().enumerate().skip(1) {
1078 let e = Self::embed_row(&self.embed_extra, c + (level - 1) * self.audio_vocab, hs);
1079 for (a, b) in fb.iter_mut().zip(&e) {
1080 *a += b;
1081 }
1082 }
1083 for a in fb.iter_mut() {
1084 *a *= scale;
1085 }
1086 let mut x = vec![0f32; 2 * hs];
1087 x[..hs].copy_from_slice(&fb);
1088 x[hs..].copy_from_slice(&fb);
1089 self.step_blocks(&mut x, 2, prompt_ids.len() + frame, &mut cache);
1090 last = x;
1091 }
1092 if done == 0 {
1093 return Err("MiniMax-Music-3 generated zero audio frames".into());
1094 }
1095 Ok((out, done))
1096 }
1097
1098 fn lm_head_rows(&self) -> usize {
1099 match &self.lm_head {
1100 Proj::F32 { rows, .. } => *rows,
1101 Proj::Q(q) => q.rows(),
1102 }
1103 }
1104}
1105
1106fn rope_half(x: &mut [f32], pos: usize, inv_freq: &[f32]) {
1108 let half = x.len() / 2;
1109 for i in 0..half {
1110 let (s, c) = (pos as f32 * inv_freq[i]).sin_cos();
1111 let (a, b) = (x[i], x[i + half]);
1112 x[i] = a * c - b * s;
1113 x[i + half] = b * c + a * s;
1114 }
1115}
1116
1117#[cfg(test)]
1118mod tests {
1119 use super::*;
1120
1121 #[test]
1128 fn music3_sampler_and_vocoder_compose() {
1129 let Ok(p) = std::env::var("CMF_MUSIC3_DIT") else {
1130 eprintln!("CMF_MUSIC3_DIT unset — skipping Music-3 chain test");
1131 return;
1132 };
1133 let model = Arc::new(CmfModel::open(&p).expect("open pack"));
1134 let dit = Music3Dit::from_cmf(&model).expect("load DiT");
1135 let dav = crate::audiovae::Music3Dav::from_cmf(&model).expect("load DAV");
1136 let n = 6usize;
1137 let noise: Vec<f32> = (0..Music3Dit::IN_CH * n)
1139 .map(|i| (((i * 2654435761) % 1000) as f32 / 500.0) - 1.0)
1140 .collect();
1141 let cond = vec![0f32; Music3Dit::COND_CH * n];
1142 let steps = 3;
1143 let mut seen = 0usize;
1144 let latent = dit.sample(&noise, &cond, n, steps, |i, t| {
1145 assert_eq!(t, steps);
1146 seen = i;
1147 });
1148 assert_eq!(seen, steps, "sampler reported every step");
1149 assert_eq!(latent.len(), Music3Dit::IN_CH * n);
1150 assert!(latent.iter().all(|v| v.is_finite()), "latent went non-finite");
1151 let pcm = dav.decode(&latent, n, None);
1152 assert_eq!(
1153 pcm.len(),
1154 n * crate::audiovae::Music3Dav::HOP * 2,
1155 "the chain's sample count is frames x 512 x 2"
1156 );
1157 assert!(pcm.iter().all(|v| v.is_finite() && v.abs() <= 1.0));
1158 let secs = (n * crate::audiovae::Music3Dav::HOP) as f32
1159 / crate::audiovae::Music3Dav::SAMPLE_RATE as f32;
1160 eprintln!(
1161 "music3 chain: {n} frames -> {} stereo samples ({secs:.3} s at 44.1 kHz)",
1162 pcm.len() / 2
1163 );
1164 }
1165
1166 #[test]
1171 fn music3_rvq_depth_decoder_is_causal() {
1172 let Ok(p) = std::env::var("CMF_MUSIC3_TE") else {
1173 eprintln!("CMF_MUSIC3_TE unset — skipping RVQ decoder test");
1174 return;
1175 };
1176 let model = Arc::new(CmfModel::open(&p).expect("open packed AR stack"));
1177 let dec = RvqDepthDecoder::from_cmf(&model).expect("load RVQ decoder");
1178 assert_eq!(dec.codebooks(), 8, "eight codebooks");
1179 let hs = dec.hidden;
1180 let seq: Vec<f32> = (0..3 * hs).map(|i| 0.05 * ((i as f32) * 0.013).sin()).collect();
1181 let a = dec.forward_last(&seq[..2 * hs], 2);
1182 let b = dec.forward_last(&seq, 3);
1183 assert_eq!(a.len(), hs);
1184 assert!(a.iter().all(|v| v.is_finite()) && b.iter().all(|v| v.is_finite()));
1185 let a2 = dec.forward_last(&seq[..2 * hs], 2);
1189 let d = a.iter().zip(&a2).map(|(x, y)| (x - y).abs()).fold(0f32, f32::max);
1190 assert!(d == 0.0, "not deterministic: {d}");
1191 let logits = dec.head(1, &b);
1192 assert_eq!(logits.len(), 1024, "audio vocab is 1024 per level");
1193 assert!(logits.iter().all(|v| v.is_finite()));
1194 let spread = logits.iter().fold(f32::MIN, |m, v| m.max(*v))
1195 - logits.iter().fold(f32::MAX, |m, v| m.min(*v));
1196 assert!(spread > 1e-3, "head is flat, spread {spread}");
1197 eprintln!("music3 rvq: 8 codebooks, head spread {spread:.3}");
1198 }
1199
1200 #[test]
1209 fn music3_dit_forward_has_the_reference_geometry() {
1210 let Ok(p) = std::env::var("CMF_MUSIC3_DIT") else {
1211 eprintln!("CMF_MUSIC3_DIT unset — skipping Music-3 DiT test");
1212 return;
1213 };
1214 let model = Arc::new(CmfModel::open(&p).expect("open packed DiT"));
1215 let dit = Music3Dit::from_cmf(&model).expect("load DiT");
1216 let n = 4usize;
1217 let x: Vec<f32> = (0..Music3Dit::IN_CH * n)
1218 .map(|i| 0.3 * ((i as f32) * 0.017).sin())
1219 .collect();
1220 let cond: Vec<f32> = (0..Music3Dit::COND_CH * n)
1221 .map(|i| 0.2 * ((i as f32) * 0.011).cos())
1222 .collect();
1223 let v = dit.forward(&x, &cond, n, 0.7);
1224 assert_eq!(v.len(), Music3Dit::IN_CH * n, "velocity is [128, n]");
1225 assert!(v.iter().all(|q| q.is_finite()), "non-finite velocity");
1226 let rms = (v.iter().map(|q| q * q).sum::<f32>() / v.len() as f32).sqrt();
1227 assert!(rms > 1e-6, "velocity is silent, rms {rms}");
1228
1229 let zero_cond = vec![0f32; Music3Dit::COND_CH * n];
1230 let v0 = dit.forward(&x, &zero_cond, n, 0.7);
1231 let dc = v
1232 .iter()
1233 .zip(&v0)
1234 .map(|(a, b)| (a - b).abs())
1235 .fold(0f32, f32::max);
1236 assert!(dc > 1e-5, "condition changed nothing — concat is wrong");
1237
1238 let vt = dit.forward(&x, &cond, n, 0.2);
1239 let dt = v
1240 .iter()
1241 .zip(&vt)
1242 .map(|(a, b)| (a - b).abs())
1243 .fold(0f32, f32::max);
1244 assert!(dt > 1e-5, "timestep changed nothing — the token is lost");
1245 eprintln!("music3 dit: rms {rms:.4}, d/dcond {dc:.4}, d/dt {dt:.4}");
1246 }
1247}