1use crate::dit::Proj;
22use crate::qtensor::QTensor;
23use crate::pool::Pool;
24use cortiq_core::CmfModel;
25use std::sync::Arc;
26
27fn silu(v: f32) -> f32 {
28 v / (1.0 + (-v).exp())
29}
30
31struct LayerNorm {
34 gamma: Vec<f32>,
35 beta: Vec<f32>,
36}
37
38impl LayerNorm {
39 fn load(model: &Arc<CmfModel>, p: &str) -> Result<Self, String> {
40 Ok(Self {
41 gamma: crate::dit::cmf_f32(model, &format!("{p}.gamma"))?,
42 beta: crate::dit::cmf_f32(model, &format!("{p}.beta"))?,
43 })
44 }
45
46 fn apply(&self, x: &mut [f32], d: usize) {
47 for row in x.chunks_exact_mut(d) {
48 let mean = row.iter().map(|v| *v as f64).sum::<f64>() / d as f64;
49 let var = row.iter().map(|v| (*v as f64 - mean).powi(2)).sum::<f64>() / d as f64;
50 let inv = 1.0 / (var + 1e-5).sqrt();
51 for ((v, &g), &b) in row.iter_mut().zip(&self.gamma).zip(&self.beta) {
52 *v = ((*v as f64 - mean) * inv) as f32 * g + b;
53 }
54 }
55 }
56}
57
58struct Block {
59 pre_norm: LayerNorm,
60 qkv: Proj,
61 out: Proj,
62 ff_norm: LayerNorm,
63 ff_in: Proj,
64 ff_in_b: Vec<f32>,
65 ff_out: Proj,
66 ff_out_b: Vec<f32>,
67}
68
69impl Block {
70 fn load(model: &Arc<CmfModel>, p: &str) -> Result<Self, String> {
71 Ok(Self {
72 pre_norm: LayerNorm::load(model, &format!("{p}.pre_norm"))?,
73 qkv: Proj::from_model(model, &format!("{p}.self_attn.to_qkv.weight"))?,
74 out: Proj::from_model(model, &format!("{p}.self_attn.to_out.weight"))?,
75 ff_norm: LayerNorm::load(model, &format!("{p}.ff_norm"))?,
76 ff_in: Proj::from_model(model, &format!("{p}.ff.ff.0.proj.weight"))?,
77 ff_in_b: crate::dit::cmf_f32(model, &format!("{p}.ff.ff.0.proj.bias"))?,
78 ff_out: Proj::from_model(model, &format!("{p}.ff.ff.2.weight"))?,
79 ff_out_b: crate::dit::cmf_f32(model, &format!("{p}.ff.ff.2.bias"))?,
80 })
81 }
82}
83
84pub struct Music3Dit {
85 pre_conv: Vec<f32>, post_conv: Vec<f32>, fourier: Vec<f32>, t0: Proj,
89 t0_b: Vec<f32>,
90 t2: Proj,
91 t2_b: Vec<f32>,
92 project_in: Proj,
93 project_out: Proj,
94 inv_freq: Vec<f32>,
95 blocks: Vec<Block>,
96 pool: Option<Arc<Pool>>,
97 hidden: usize,
98 heads: usize,
99 hd: usize,
100 rot: usize,
101 inter: usize,
102 cond_logits: Vec<f32>,
105 cond_scale: f32,
106 lc_w: Vec<f32>,
107 lc_b: Vec<f32>,
108}
109
110impl Music3Dit {
111 pub const IN_CH: usize = 128;
112 pub const COND_CH: usize = 2048;
113 pub const CONCAT_CH: usize = 2304;
114
115 pub fn from_cmf(model: &Arc<CmfModel>) -> Result<Self, String> {
116 let cfg: serde_json::Value =
117 serde_json::from_slice(model.tensor_bytes("mdit.config_json").map_err(|e| e.to_string())?)
118 .map_err(|e| format!("mdit.config_json: {e}"))?;
119 let u = |k: &str, d: usize| cfg[k].as_u64().map(|v| v as usize).unwrap_or(d);
120 let nl = u("num_layers", 36);
121 let dt = "mdit.diffusion_transformer";
122 Ok(Self {
123 pre_conv: crate::dit::cmf_f32(model, &format!("{dt}.preprocess_conv.weight"))?,
124 post_conv: crate::dit::cmf_f32(model, &format!("{dt}.postprocess_conv.weight"))?,
125 fourier: crate::dit::cmf_f32(model, &format!("{dt}.timestep_features.weight"))?,
126 t0: Proj::from_model(model, &format!("{dt}.to_timestep_embed.0.weight"))?,
127 t0_b: crate::dit::cmf_f32(model, &format!("{dt}.to_timestep_embed.0.bias"))?,
128 t2: Proj::from_model(model, &format!("{dt}.to_timestep_embed.2.weight"))?,
129 t2_b: crate::dit::cmf_f32(model, &format!("{dt}.to_timestep_embed.2.bias"))?,
130 project_in: Proj::from_model(model, &format!("{dt}.transformer.project_in.weight"))?,
131 project_out: Proj::from_model(model, &format!("{dt}.transformer.project_out.weight"))?,
132 inv_freq: crate::dit::cmf_f32(model, &format!("{dt}.transformer.rotary_pos_emb.inv_freq"))?,
133 blocks: (0..nl)
134 .map(|i| Block::load(model, &format!("{dt}.transformer.layers.{i}")))
135 .collect::<Result<_, _>>()?,
136 pool: Pool::from_env(),
137 hidden: u("hidden", 2048),
138 heads: u("num_heads", 32),
139 hd: u("head_dim", 64),
140 rot: u("rotary_dim", 32),
141 inter: u("ff_inner", 8192),
142 cond_logits: crate::dit::cmf_f32(model, "mdit.cond_layer_logits")?,
143 cond_scale: crate::dit::cmf_f32(model, "mdit.cond_layer_scale")?[0],
144 lc_w: crate::dit::cmf_f32(model, "mdit.latent_conditioners.0.weight")?,
145 lc_b: crate::dit::cmf_f32(model, "mdit.latent_conditioners.0.bias")?,
146 })
147 }
148
149 pub fn latent_length(audio_frames: usize) -> usize {
152 ((audio_frames as f64 * 44100.0 / 24000.0 * 960.0 / 512.0) as usize).max(1)
153 }
154
155 pub fn aligned_condition(&self, hidden: &[f32], frames: usize) -> (Vec<f32>, usize) {
163 let levels = self.cond_logits.len();
164 let ar = hidden.len() / (frames * levels);
165 let mx = self.cond_logits.iter().cloned().fold(f32::MIN, f32::max);
166 let ex: Vec<f32> = self.cond_logits.iter().map(|v| (v - mx).exp()).collect();
167 let sum: f32 = ex.iter().sum();
168 let mut mixed = vec![0f32; ar * frames];
170 for t in 0..frames {
171 for l in 0..levels {
172 let w = ex[l] / sum * self.cond_scale;
173 let src = &hidden[(t * levels + l) * ar..(t * levels + l + 1) * ar];
174 for (c, &v) in src.iter().enumerate() {
175 mixed[c * frames + t] += w * v;
176 }
177 }
178 }
179 let out_ch = self.lc_b.len();
181 let mut conv = vec![0f32; out_ch * frames];
182 for o in 0..out_ch {
183 let dst = &mut conv[o * frames..(o + 1) * frames];
184 dst.fill(self.lc_b[o]);
185 for i in 0..ar {
186 let k = &self.lc_w[(o * ar + i) * 3..(o * ar + i + 1) * 3];
187 let src = &mixed[i * frames..(i + 1) * frames];
188 for t in 0..frames {
189 for (j, &kv) in k.iter().enumerate() {
190 let p = t as isize + j as isize - 1;
191 if p >= 0 && (p as usize) < frames {
192 dst[t] += kv * src[p as usize];
193 }
194 }
195 }
196 }
197 }
198 let l = Self::latent_length(frames);
199 let mut out = vec![0f32; out_ch * l];
200 for o in 0..out_ch {
201 for t in 0..l {
202 let s = (t * frames) / l.max(1);
203 out[o * l + t] = conv[o * frames + s.min(frames - 1)];
204 }
205 }
206 (out, l)
207 }
208
209 fn conv1x1_residual(w: &[f32], x: &mut [f32], ch: usize, n: usize) {
212 let mut acc = vec![0f32; ch * n];
213 for o in 0..ch {
214 let row = &w[o * ch..(o + 1) * ch];
215 let dst = &mut acc[o * n..(o + 1) * n];
216 for (i, &wv) in row.iter().enumerate() {
217 if wv == 0.0 {
218 continue;
219 }
220 for (d, &s) in dst.iter_mut().zip(&x[i * n..(i + 1) * n]) {
221 *d += wv * s;
222 }
223 }
224 }
225 for (d, a) in x.iter_mut().zip(&acc) {
226 *d += a;
227 }
228 }
229
230 fn timestep_embedding(&self, t: f32) -> Vec<f32> {
232 let half = self.fourier.len();
233 let mut feats = vec![0f32; half * 2];
234 for (i, &w) in self.fourier.iter().enumerate() {
235 let a = std::f32::consts::TAU * t * w;
236 feats[i] = a.cos();
237 feats[half + i] = a.sin();
238 }
239 let mut h = vec![0f32; self.t0_b.len()];
240 self.t0.matmat(&feats, 1, &mut h, self.pool.as_deref());
241 for (v, &b) in h.iter_mut().zip(&self.t0_b) {
242 *v = silu(*v + b);
243 }
244 let mut out = vec![0f32; self.t2_b.len()];
245 self.t2.matmat(&h, 1, &mut out, self.pool.as_deref());
246 for (v, &b) in out.iter_mut().zip(&self.t2_b) {
247 *v += b;
248 }
249 out
250 }
251
252 fn rope(&self, q: &mut [f32], k: &mut [f32], n: usize) {
254 let half = self.rot / 2;
255 for p in 0..n {
256 for h in 0..self.heads {
257 let off = p * self.heads * self.hd + h * self.hd;
258 for i in 0..half {
259 let (s, c) = (p as f32 * self.inv_freq[i]).sin_cos();
260 for x in [&mut *q, &mut *k] {
261 let (a, b) = (x[off + i], x[off + i + half]);
262 x[off + i] = a * c - b * s;
263 x[off + i + half] = a * s + b * c;
264 }
265 }
266 }
267 }
268 }
269
270 fn block(&self, blk: &Block, x: &mut [f32], n: usize) {
272 let (hs, nh, hd) = (self.hidden, self.heads, self.hd);
273 let pool = self.pool.as_deref();
274 let mut h = x.to_vec();
275 blk.pre_norm.apply(&mut h, hs);
276 let mut qkv = vec![0f32; n * 3 * hs];
277 blk.qkv.matmat(&h, n, &mut qkv, pool);
278 let mut q = vec![0f32; n * hs];
281 let mut k = vec![0f32; n * hs];
282 let mut v = vec![0f32; n * hs];
283 for p in 0..n {
284 let s = &qkv[p * 3 * hs..(p + 1) * 3 * hs];
285 q[p * hs..(p + 1) * hs].copy_from_slice(&s[..hs]);
286 k[p * hs..(p + 1) * hs].copy_from_slice(&s[hs..2 * hs]);
287 v[p * hs..(p + 1) * hs].copy_from_slice(&s[2 * hs..]);
288 }
289 self.rope(&mut q, &mut k, n);
290 let scale = 1.0 / (hd as f32).sqrt();
291 let mut attn = vec![0f32; n * hs];
292 for hh in 0..nh {
293 for i in 0..n {
294 let qi = &q[i * hs + hh * hd..i * hs + hh * hd + hd];
295 let mut scores = vec![0f32; n];
296 let mut mx = f32::NEG_INFINITY;
297 for (j, sc) in scores.iter_mut().enumerate() {
298 let kj = &k[j * hs + hh * hd..j * hs + hh * hd + hd];
299 *sc = qi.iter().zip(kj).map(|(a, b)| a * b).sum::<f32>() * scale;
300 mx = mx.max(*sc);
301 }
302 let mut sum = 0.0;
303 for sc in scores.iter_mut() {
304 *sc = (*sc - mx).exp();
305 sum += *sc;
306 }
307 let inv = 1.0 / sum;
308 let dst = &mut attn[i * hs + hh * hd..i * hs + hh * hd + hd];
309 for (j, &sc) in scores.iter().enumerate() {
310 let w = sc * inv;
311 let vj = &v[j * hs + hh * hd..j * hs + hh * hd + hd];
312 for (d, &vv) in dst.iter_mut().zip(vj) {
313 *d += w * vv;
314 }
315 }
316 }
317 }
318 let mut proj = vec![0f32; n * hs];
319 blk.out.matmat(&attn, n, &mut proj, pool);
320 for (a, b) in x.iter_mut().zip(&proj) {
321 *a += b;
322 }
323
324 let mut h = x.to_vec();
325 blk.ff_norm.apply(&mut h, hs);
326 let mut gu = vec![0f32; n * 2 * self.inter];
327 blk.ff_in.matmat(&h, n, &mut gu, pool);
328 let inter = self.inter;
333 let (vb, gb) = blk.ff_in_b.split_at(inter);
334 let mut act = vec![0f32; n * inter];
335 for p in 0..n {
336 let row = &gu[p * 2 * inter..(p + 1) * 2 * inter];
337 let (val, gate) = row.split_at(inter);
338 let dst = &mut act[p * inter..(p + 1) * inter];
339 for i in 0..inter {
340 dst[i] = (val[i] + vb[i]) * silu(gate[i] + gb[i]);
341 }
342 }
343 let mut ffo = vec![0f32; n * hs];
344 blk.ff_out.matmat(&act, n, &mut ffo, pool);
345 for p in 0..n {
346 for j in 0..hs {
347 x[p * hs + j] += ffo[p * hs + j] + blk.ff_out_b[j];
348 }
349 }
350 }
351
352 pub const WINDOW: usize = 689;
358 pub const HOP: usize = 344;
359
360 pub fn forward_windowed(&self, x: &[f32], condition: &[f32], n: usize, t: f32) -> Vec<f32> {
363 if n <= Self::WINDOW {
364 return self.forward(x, condition, n, t);
365 }
366 let ch = Self::IN_CH;
367 let cc = Self::COND_CH;
368 let mut out = vec![0f32; ch * n];
369 let mut count = vec![0f32; n];
370 let mut start = 0usize;
371 loop {
372 let end = (start + Self::WINDOW).min(n);
373 let w = end - start;
374 let mut xw = vec![0f32; ch * w];
375 for c in 0..ch {
376 xw[c * w..(c + 1) * w].copy_from_slice(&x[c * n + start..c * n + end]);
377 }
378 let mut cw = vec![0f32; cc * w];
379 for c in 0..cc {
380 cw[c * w..(c + 1) * w].copy_from_slice(&condition[c * n + start..c * n + end]);
381 }
382 let v = self.forward(&xw, &cw, w, t);
383 for c in 0..ch {
384 for i in 0..w {
385 out[c * n + start + i] += v[c * w + i];
386 }
387 }
388 for i in 0..w {
389 count[start + i] += 1.0;
390 }
391 if end == n {
392 break;
393 }
394 start += Self::HOP;
395 }
396 for c in 0..ch {
397 for i in 0..n {
398 out[c * n + i] /= count[i];
399 }
400 }
401 out
402 }
403
404 pub fn forward(&self, x: &[f32], condition: &[f32], n: usize, t: f32) -> Vec<f32> {
407 let pool = self.pool.as_deref();
408 let mut full = vec![0f32; Self::CONCAT_CH * n];
409 full[..Self::IN_CH * n].copy_from_slice(x);
410 full[2 * Self::IN_CH * n..].copy_from_slice(condition);
412 Self::conv1x1_residual(&self.pre_conv, &mut full, Self::CONCAT_CH, n);
413
414 let mut toks = vec![0f32; n * Self::CONCAT_CH];
416 for c in 0..Self::CONCAT_CH {
417 for p in 0..n {
418 toks[p * Self::CONCAT_CH + c] = full[c * n + p];
419 }
420 }
421 let mut h = vec![0f32; n * self.hidden];
422 self.project_in.matmat(&toks, n, &mut h, pool);
423
424 let temb = self.timestep_embedding(t);
426 let mut seq = vec![0f32; (n + 1) * self.hidden];
427 seq[..self.hidden].copy_from_slice(&temb);
428 seq[self.hidden..].copy_from_slice(&h);
429 for blk in &self.blocks {
430 self.block(blk, &mut seq, n + 1);
431 }
432
433 let mut out = vec![0f32; n * Self::IN_CH];
434 self.project_out
435 .matmat(&seq[self.hidden..], n, &mut out, pool);
436 let mut ch = vec![0f32; Self::IN_CH * n];
437 for c in 0..Self::IN_CH {
438 for p in 0..n {
439 ch[c * n + p] = out[p * Self::IN_CH + c];
440 }
441 }
442 Self::conv1x1_residual(&self.post_conv, &mut ch, Self::IN_CH, n);
443 for v in ch.iter_mut() {
444 *v = -*v;
445 }
446 ch
447 }
448
449 pub fn sample(
452 &self,
453 noise: &[f32],
454 condition: &[f32],
455 n: usize,
456 steps: usize,
457 mut progress: impl FnMut(usize, usize),
458 ) -> Vec<f32> {
459 let sigmas = flow_sigmas(steps);
460 let mut x = noise.to_vec();
461 for i in 0..steps {
462 let (s, s_next) = (sigmas[i], sigmas[i + 1]);
463 let v = self.forward_windowed(&x, condition, n, 1.0 - s);
465 let dt = s_next - s;
466 for (a, b) in x.iter_mut().zip(&v) {
467 *a += dt * b;
468 }
469 progress(i + 1, steps);
470 }
471 x
472 }
473}
474
475pub fn flow_sigmas(steps: usize) -> Vec<f32> {
490 (0..=steps)
491 .map(|i| 1.0 - i as f32 / steps as f32)
492 .collect()
493}
494
495struct RmsNorm {
497 w: Vec<f32>,
498}
499
500impl RmsNorm {
501 fn load(model: &Arc<CmfModel>, n: &str) -> Result<Self, String> {
502 Ok(Self {
503 w: crate::dit::cmf_f32(model, n)?,
504 })
505 }
506
507 fn apply(&self, x: &mut [f32], d: usize) {
508 for row in x.chunks_exact_mut(d) {
509 let ss = row.iter().map(|v| (*v as f64) * (*v as f64)).sum::<f64>() / d as f64;
510 let inv = 1.0 / (ss + 1e-6).sqrt();
511 for (v, &g) in row.iter_mut().zip(&self.w) {
512 *v = (*v as f64 * inv) as f32 * g;
513 }
514 }
515 }
516}
517
518struct RvqBlock {
519 n1: RmsNorm,
520 q: Proj,
521 k: Proj,
522 v: Proj,
523 o: Proj,
524 n2: RmsNorm,
525 gate: Proj,
526 up: Proj,
527 down: Proj,
528}
529
530impl RvqBlock {
531 fn load(model: &Arc<CmfModel>, p: &str) -> Result<Self, String> {
532 Ok(Self {
533 n1: RmsNorm::load(model, &format!("{p}.input_layernorm.weight"))?,
534 q: Proj::from_model(model, &format!("{p}.self_attn.q_proj.weight"))?,
535 k: Proj::from_model(model, &format!("{p}.self_attn.k_proj.weight"))?,
536 v: Proj::from_model(model, &format!("{p}.self_attn.v_proj.weight"))?,
537 o: Proj::from_model(model, &format!("{p}.self_attn.o_proj.weight"))?,
538 n2: RmsNorm::load(model, &format!("{p}.post_attention_layernorm.weight"))?,
539 gate: Proj::from_model(model, &format!("{p}.mlp.gate_proj.weight"))?,
540 up: Proj::from_model(model, &format!("{p}.mlp.up_proj.weight"))?,
541 down: Proj::from_model(model, &format!("{p}.mlp.down_proj.weight"))?,
542 })
543 }
544}
545
546pub struct RvqDepthDecoder {
554 projection: Proj,
555 pos: Vec<f32>,
556 blocks: Vec<RvqBlock>,
557 norm: RmsNorm,
558 heads: Vec<Proj>,
559 pool: Option<Arc<Pool>>,
560 hidden: usize,
561 nh: usize,
562 hd: usize,
563 inter: usize,
564}
565
566impl RvqDepthDecoder {
567 pub fn from_cmf(model: &Arc<CmfModel>) -> Result<Self, String> {
568 let cfg: serde_json::Value =
569 serde_json::from_slice(model.tensor_bytes("mte.config_json").map_err(|e| e.to_string())?)
570 .map_err(|e| format!("mte.config_json: {e}"))?;
571 let u = |k: &str, d: usize| cfg[k].as_u64().map(|v| v as usize).unwrap_or(d);
572 let hidden = u("hidden_size", 4096);
573 let nl = u("decoder_num_layers", 4);
574 let nh = u("decoder_num_heads", 16);
575 let cb = u("audio_num_codebooks", 8);
576 Ok(Self {
577 projection: Proj::from_model(model, "mte.audio_decoder.projection.weight")?,
578 pos: crate::dit::cmf_f32(model, "mte.audio_decoder.pos_embedding.weight")?,
579 blocks: (0..nl)
580 .map(|i| RvqBlock::load(model, &format!("mte.audio_decoder.layers.{i}")))
581 .collect::<Result<_, _>>()?,
582 norm: RmsNorm::load(model, "mte.audio_decoder.norm.weight")?,
583 heads: (0..cb - 1)
584 .map(|i| {
585 Proj::from_model(model, &format!("mte.audio_decoder.audio_heads.{i}.weight"))
586 })
587 .collect::<Result<_, _>>()?,
588 pool: Pool::from_env(),
589 hidden,
590 nh,
591 hd: hidden / nh,
592 inter: u("decoder_intermediate_size", 6144),
593 })
594 }
595
596 pub fn codebooks(&self) -> usize {
597 self.heads.len() + 1
598 }
599
600 pub fn project(&self, x: &[f32]) -> Vec<f32> {
603 let n = x.len() / self.hidden;
604 let mut out = vec![0f32; n * self.hidden];
605 self.projection
606 .matmat(x, n, &mut out, self.pool.as_deref());
607 out
608 }
609
610 pub fn forward_last(&self, seq: &[f32], n: usize) -> Vec<f32> {
613 let (hs, nh, hd) = (self.hidden, self.nh, self.hd);
614 let pool = self.pool.as_deref();
615 let mut x = seq.to_vec();
616 for p in 0..n {
617 for (v, &pe) in x[p * hs..(p + 1) * hs].iter_mut().zip(&self.pos[p * hs..(p + 1) * hs]) {
618 *v += pe;
619 }
620 }
621 for blk in &self.blocks {
622 let mut h = x.clone();
623 blk.n1.apply(&mut h, hs);
624 let (mut q, mut k, mut v) = (vec![0f32; n * hs], vec![0f32; n * hs], vec![0f32; n * hs]);
625 blk.q.matmat(&h, n, &mut q, pool);
626 blk.k.matmat(&h, n, &mut k, pool);
627 blk.v.matmat(&h, n, &mut v, pool);
628 let scale = 1.0 / (hd as f32).sqrt();
629 let mut attn = vec![0f32; n * hs];
630 for hh in 0..nh {
631 for i in 0..n {
632 let qi = &q[i * hs + hh * hd..i * hs + hh * hd + hd];
633 let mut sc = vec![0f32; i + 1];
635 let mut mx = f32::NEG_INFINITY;
636 for (j, s) in sc.iter_mut().enumerate() {
637 let kj = &k[j * hs + hh * hd..j * hs + hh * hd + hd];
638 *s = qi.iter().zip(kj).map(|(a, b)| a * b).sum::<f32>() * scale;
639 mx = mx.max(*s);
640 }
641 let mut sum = 0.0;
642 for s in sc.iter_mut() {
643 *s = (*s - mx).exp();
644 sum += *s;
645 }
646 let inv = 1.0 / sum;
647 let dst = &mut attn[i * hs + hh * hd..i * hs + hh * hd + hd];
648 for (j, &s) in sc.iter().enumerate() {
649 let w = s * inv;
650 let vj = &v[j * hs + hh * hd..j * hs + hh * hd + hd];
651 for (d, &vv) in dst.iter_mut().zip(vj) {
652 *d += w * vv;
653 }
654 }
655 }
656 }
657 let mut proj = vec![0f32; n * hs];
658 blk.o.matmat(&attn, n, &mut proj, pool);
659 for (a, b) in x.iter_mut().zip(&proj) {
660 *a += b;
661 }
662
663 let mut h = x.clone();
664 blk.n2.apply(&mut h, hs);
665 let (mut g, mut u) = (vec![0f32; n * self.inter], vec![0f32; n * self.inter]);
666 blk.gate.matmat(&h, n, &mut g, pool);
667 blk.up.matmat(&h, n, &mut u, pool);
668 for (a, b) in g.iter_mut().zip(&u) {
669 *a = silu(*a) * b;
670 }
671 let mut ffo = vec![0f32; n * hs];
672 blk.down.matmat(&g, n, &mut ffo, pool);
673 for (a, b) in x.iter_mut().zip(&ffo) {
674 *a += b;
675 }
676 }
677 let mut last = x[(n - 1) * hs..].to_vec();
678 self.norm.apply(&mut last, hs);
679 last
680 }
681
682 pub fn head(&self, level: usize, hidden: &[f32]) -> Vec<f32> {
684 let h = &self.heads[level - 1];
685 let rows = match h {
686 Proj::F32 { rows, .. } => *rows,
687 Proj::Q(q) => q.rows(),
688 };
689 let mut out = vec![0f32; rows];
690 h.matmat(hidden, 1, &mut out, self.pool.as_deref());
691 out
692 }
693}
694
695struct ArBlock {
700 n1: RmsNorm,
701 q: Proj,
702 k: Proj,
703 v: Proj,
704 o: Proj,
705 qn: RmsNorm,
706 kn: RmsNorm,
707 n2: RmsNorm,
708 gate: Proj,
709 up: Proj,
710 down: Proj,
711}
712
713impl ArBlock {
714 fn load(model: &Arc<CmfModel>, p: &str) -> Result<Self, String> {
715 Ok(Self {
716 n1: RmsNorm::load(model, &format!("{p}.input_layernorm.weight"))?,
717 q: Proj::from_model(model, &format!("{p}.self_attn.q_proj.weight"))?,
718 k: Proj::from_model(model, &format!("{p}.self_attn.k_proj.weight"))?,
719 v: Proj::from_model(model, &format!("{p}.self_attn.v_proj.weight"))?,
720 o: Proj::from_model(model, &format!("{p}.self_attn.o_proj.weight"))?,
721 qn: RmsNorm::load(model, &format!("{p}.self_attn.q_norm.weight"))?,
722 kn: RmsNorm::load(model, &format!("{p}.self_attn.k_norm.weight"))?,
723 n2: RmsNorm::load(model, &format!("{p}.post_attention_layernorm.weight"))?,
724 gate: Proj::from_model(model, &format!("{p}.mlp.gate_proj.weight"))?,
725 up: Proj::from_model(model, &format!("{p}.mlp.up_proj.weight"))?,
726 down: Proj::from_model(model, &format!("{p}.mlp.down_proj.weight"))?,
727 })
728 }
729}
730
731#[derive(Default, Clone)]
733struct KvRun {
734 k: Vec<f32>,
735 v: Vec<f32>,
736 len: usize,
737}
738
739struct Rng(u64);
746
747impl Rng {
748 fn new(seed: u64) -> Self {
749 Self(seed.wrapping_mul(0x9E37_79B9_7F4A_7C15) | 1)
750 }
751 fn next_f32(&mut self) -> f32 {
752 let mut x = self.0;
753 x ^= x << 13;
754 x ^= x >> 7;
755 x ^= x << 17;
756 self.0 = x;
757 ((x >> 40) as f32) / (1u32 << 24) as f32
758 }
759}
760
761fn sample_topk(logits: &[f32], top_k: usize, rng: &mut Rng) -> usize {
762 let mut idx: Vec<usize> = (0..logits.len()).filter(|&i| logits[i].is_finite()).collect();
763 idx.sort_unstable_by(|&a, &b| logits[b].partial_cmp(&logits[a]).unwrap());
764 idx.truncate(top_k.max(1));
765 let mx = idx.iter().map(|&i| logits[i]).fold(f32::MIN, f32::max);
766 let exps: Vec<f32> = idx.iter().map(|&i| (logits[i] - mx).exp()).collect();
767 let sum: f32 = exps.iter().sum();
768 let mut r = rng.next_f32() * sum;
769 for (j, &e) in exps.iter().enumerate() {
770 r -= e;
771 if r <= 0.0 {
772 return idx[j];
773 }
774 }
775 *idx.last().unwrap()
776}
777
778pub struct Music3Ar {
782 blocks: Vec<ArBlock>,
783 norm: RmsNorm,
784 embed_prefill: QTensor,
785 embed_audio: QTensor,
786 embed_extra: QTensor,
787 lm_head: Proj,
788 pub depth: RvqDepthDecoder,
789 inv_freq: Vec<f32>,
790 pool: Option<Arc<Pool>>,
791 hidden: usize,
792 nh: usize,
793 nkv: usize,
794 hd: usize,
795 inter: usize,
796 audio_vocab: usize,
797 codebooks: usize,
798 pub cfg_scale: f32,
799 pub top_k: usize,
800 pub fps: usize,
801 pub max_frames: usize,
802}
803
804pub mod tokens {
806 pub const IM_START: u32 = 151644;
807 pub const IM_END: u32 = 151645;
808 pub const AUDIO_CFG: u32 = 151654;
809 pub const AUDIO_START: u32 = 151669;
810 pub const CAPTION_START: u32 = 151671;
811 pub const CAPTION_END: u32 = 151672;
812 pub const LYRICS_START: u32 = 151673;
813 pub const LYRICS_END: u32 = 151674;
814}
815
816impl Music3Ar {
817 pub fn from_cmf(model: &Arc<CmfModel>) -> Result<Self, String> {
818 let cfg: serde_json::Value =
819 serde_json::from_slice(model.tensor_bytes("mte.config_json").map_err(|e| e.to_string())?)
820 .map_err(|e| format!("mte.config_json: {e}"))?;
821 let u = |k: &str, d: usize| cfg[k].as_u64().map(|v| v as usize).unwrap_or(d);
822 let f = |k: &str, d: f64| cfg[k].as_f64().unwrap_or(d);
823 let hidden = u("hidden_size", 4096);
824 let hd = u("head_dim", 128);
825 let theta = f("rope_theta", 1_000_000.0) as f32;
826 Ok(Self {
827 blocks: (0..u("num_hidden_layers", 36))
828 .map(|i| ArBlock::load(model, &format!("mte.layers.{i}")))
829 .collect::<Result<_, _>>()?,
830 norm: RmsNorm::load(model, "mte.norm.weight")?,
831 embed_prefill: QTensor::from_model(model, "mte.embed_tokens_prefill.weight")?,
832 embed_audio: QTensor::from_model(model, "mte.embed_tokens_audio.weight")?,
833 embed_extra: QTensor::from_model(model, "mte.audio_extra_embedding.weight")?,
834 lm_head: Proj::from_model(model, "mte.lm_head_pruned.weight")?,
835 depth: RvqDepthDecoder::from_cmf(model)?,
836 inv_freq: (0..hd / 2)
837 .map(|i| 1.0 / theta.powf(2.0 * i as f32 / hd as f32))
838 .collect(),
839 pool: Pool::from_env(),
840 hidden,
841 nh: u("num_attention_heads", 32),
842 nkv: u("num_key_value_heads", 8),
843 hd,
844 inter: u("intermediate_size", 12288),
845 audio_vocab: u("audio_vocab_size", 1024),
846 codebooks: u("audio_num_codebooks", 8),
847 cfg_scale: f("cfg_scale", 1.5) as f32,
848 top_k: u("top_k", 50),
849 fps: u("audio_frames_per_second", 25),
850 max_frames: u("max_audio_frames", 9000),
851 })
852 }
853
854 fn embed_row(p: &QTensor, row: usize, hidden: usize) -> Vec<f32> {
857 let mut out = vec![0f32; hidden];
858 p.row_f32(row, &mut out);
859 out
860 }
861
862 fn step_blocks(&self, x: &mut [f32], b: usize, pos: usize, cache: &mut [Vec<KvRun>]) {
865 let (hs, nh, nkv, hd) = (self.hidden, self.nh, self.nkv, self.hd);
866 let pool = self.pool.as_deref();
867 let kvw = nkv * hd;
868 for (li, blk) in self.blocks.iter().enumerate() {
869 let mut h = x.to_vec();
870 blk.n1.apply(&mut h, hs);
871 let mut q = vec![0f32; b * nh * hd];
872 let mut k = vec![0f32; b * kvw];
873 let mut v = vec![0f32; b * kvw];
874 blk.q.matmat(&h, b, &mut q, pool);
875 blk.k.matmat(&h, b, &mut k, pool);
876 blk.v.matmat(&h, b, &mut v, pool);
877 for bi in 0..b {
880 for hh in 0..nh {
881 let s = bi * nh * hd + hh * hd;
882 blk.qn.apply(&mut q[s..s + hd], hd);
883 rope_half(&mut q[s..s + hd], pos, &self.inv_freq);
884 }
885 for hh in 0..nkv {
886 let s = bi * kvw + hh * hd;
887 blk.kn.apply(&mut k[s..s + hd], hd);
888 rope_half(&mut k[s..s + hd], pos, &self.inv_freq);
889 }
890 }
891 let mut attn = vec![0f32; b * nh * hd];
892 let per_kv = nh / nkv;
893 for bi in 0..b {
894 let run = &mut cache[li][bi];
895 run.k.extend_from_slice(&k[bi * kvw..(bi + 1) * kvw]);
896 run.v.extend_from_slice(&v[bi * kvw..(bi + 1) * kvw]);
897 run.len += 1;
898 let n = run.len;
899 let scale = 1.0 / (hd as f32).sqrt();
900 for hh in 0..nh {
901 let g = hh / per_kv;
902 let qi = &q[bi * nh * hd + hh * hd..bi * nh * hd + hh * hd + hd];
903 let mut sc = vec![0f32; n];
904 let mut mx = f32::NEG_INFINITY;
905 for (j, s) in sc.iter_mut().enumerate() {
906 let kj = &run.k[j * kvw + g * hd..j * kvw + g * hd + hd];
907 *s = qi.iter().zip(kj).map(|(a, c)| a * c).sum::<f32>() * scale;
908 mx = mx.max(*s);
909 }
910 let mut sum = 0.0;
911 for s in sc.iter_mut() {
912 *s = (*s - mx).exp();
913 sum += *s;
914 }
915 let inv = 1.0 / sum;
916 let dst = &mut attn[bi * nh * hd + hh * hd..bi * nh * hd + hh * hd + hd];
917 for (j, &s) in sc.iter().enumerate() {
918 let w = s * inv;
919 let vj = &run.v[j * kvw + g * hd..j * kvw + g * hd + hd];
920 for (d, &vv) in dst.iter_mut().zip(vj) {
921 *d += w * vv;
922 }
923 }
924 }
925 }
926 let mut proj = vec![0f32; b * hs];
927 blk.o.matmat(&attn, b, &mut proj, pool);
928 for (a, c) in x.iter_mut().zip(&proj) {
929 *a += c;
930 }
931 let mut h = x.to_vec();
932 blk.n2.apply(&mut h, hs);
933 let (mut g, mut u2) = (vec![0f32; b * self.inter], vec![0f32; b * self.inter]);
934 blk.gate.matmat(&h, b, &mut g, pool);
935 blk.up.matmat(&h, b, &mut u2, pool);
936 for (a, c) in g.iter_mut().zip(&u2) {
937 *a = silu(*a) * c;
938 }
939 let mut ffo = vec![0f32; b * hs];
940 blk.down.matmat(&g, b, &mut ffo, pool);
941 for (a, c) in x.iter_mut().zip(&ffo) {
942 *a += c;
943 }
944 }
945 }
946
947 pub fn generate(
954 &self,
955 prompt_ids: &[u32],
956 seed: u64,
957 frames: usize,
958 mut progress: impl FnMut(usize, usize),
959 ) -> Result<(Vec<f32>, usize), String> {
960 let hs = self.hidden;
961 let pool = self.pool.as_deref();
962 let want = frames.min(self.max_frames);
963 let mut cache: Vec<Vec<KvRun>> = (0..self.blocks.len())
964 .map(|_| vec![KvRun::default(); 2])
965 .collect();
966 let mut uncond = prompt_ids.to_vec();
968 if uncond.len() > 3 {
969 let n = uncond.len();
970 for t in uncond[1..n - 2].iter_mut() {
971 *t = tokens::AUDIO_CFG;
972 }
973 }
974 let mut last = vec![0f32; 2 * hs];
975 for (pos, (&a, &b)) in prompt_ids.iter().zip(&uncond).enumerate() {
976 let mut x = vec![0f32; 2 * hs];
977 x[..hs].copy_from_slice(&Self::embed_row(&self.embed_prefill, a as usize, hs));
978 x[hs..].copy_from_slice(&Self::embed_row(&self.embed_prefill, b as usize, hs));
979 self.step_blocks(&mut x, 2, pos, &mut cache);
980 last = x;
981 if pos % 64 == 0 {
982 progress(0, want);
983 }
984 }
985 let mut rng = Rng::new(seed);
986 let mut out: Vec<f32> = Vec::with_capacity(want * self.codebooks * hs);
987 let mut done = 0usize;
988 let scale = (self.codebooks as f32).powf(-0.5);
989 for frame in 0..want {
990 let mut normed = last.clone();
991 self.norm.apply(&mut normed, hs);
992 let mut logits = vec![0f32; 2 * self.lm_head_rows()];
995 self.lm_head.matmat(&normed, 2, &mut logits, pool);
996 let vocab = self.lm_head_rows();
997 let (cond, unc) = logits.split_at(vocab);
998 let mut thr: Vec<f32> = cond.to_vec();
999 thr.sort_unstable_by(|a, b| b.partial_cmp(a).unwrap());
1000 let cut = thr[self.top_k.min(vocab) - 1];
1001 let guided: Vec<f32> = (0..vocab)
1002 .map(|i| {
1003 if cond[i] < cut {
1004 f32::NEG_INFINITY
1005 } else {
1006 unc[i] + (cond[i] - unc[i]) * self.cfg_scale
1007 }
1008 })
1009 .collect();
1010 let code = sample_topk(&guided, self.top_k, &mut rng);
1011 if code == 0 {
1012 break; }
1014 let c0 = code - 1;
1015 let c0_embed = Self::embed_row(&self.embed_audio, c0, hs);
1016 let mut seq = self.depth.project(&normed[..hs]);
1019 seq.extend_from_slice(&self.depth.project(&c0_embed));
1020 let mut codes = vec![c0];
1021 let mut frame_hidden = normed[..hs].to_vec();
1022 for level in 1..self.codebooks {
1023 let n = seq.len() / hs;
1024 let h = self.depth.forward_last(&seq, n);
1025 frame_hidden.extend_from_slice(&h);
1026 let lg = self.depth.head(level, &h);
1027 let c = sample_topk(&lg, self.top_k, &mut rng);
1028 codes.push(c);
1029 if level < self.codebooks - 1 {
1030 let e = Self::embed_row(&self.embed_extra, c + (level - 1) * self.audio_vocab, hs);
1031 seq.extend_from_slice(&self.depth.project(&e));
1032 }
1033 }
1034 out.extend_from_slice(&frame_hidden);
1035 done += 1;
1036 progress(done, want);
1037 if done >= want {
1038 break;
1039 }
1040 let mut fb = Self::embed_row(&self.embed_audio, codes[0], hs);
1043 for (level, &c) in codes.iter().enumerate().skip(1) {
1044 let e = Self::embed_row(&self.embed_extra, c + (level - 1) * self.audio_vocab, hs);
1045 for (a, b) in fb.iter_mut().zip(&e) {
1046 *a += b;
1047 }
1048 }
1049 for a in fb.iter_mut() {
1050 *a *= scale;
1051 }
1052 let mut x = vec![0f32; 2 * hs];
1053 x[..hs].copy_from_slice(&fb);
1054 x[hs..].copy_from_slice(&fb);
1055 self.step_blocks(&mut x, 2, prompt_ids.len() + frame, &mut cache);
1056 last = x;
1057 }
1058 if done == 0 {
1059 return Err("MiniMax-Music-3 generated zero audio frames".into());
1060 }
1061 Ok((out, done))
1062 }
1063
1064 fn lm_head_rows(&self) -> usize {
1065 match &self.lm_head {
1066 Proj::F32 { rows, .. } => *rows,
1067 Proj::Q(q) => q.rows(),
1068 }
1069 }
1070}
1071
1072fn rope_half(x: &mut [f32], pos: usize, inv_freq: &[f32]) {
1074 let half = x.len() / 2;
1075 for i in 0..half {
1076 let (s, c) = (pos as f32 * inv_freq[i]).sin_cos();
1077 let (a, b) = (x[i], x[i + half]);
1078 x[i] = a * c - b * s;
1079 x[i + half] = b * c + a * s;
1080 }
1081}
1082
1083#[cfg(test)]
1084mod tests {
1085 use super::*;
1086
1087 #[test]
1094 fn music3_sampler_and_vocoder_compose() {
1095 let Ok(p) = std::env::var("CMF_MUSIC3_DIT") else {
1096 eprintln!("CMF_MUSIC3_DIT unset — skipping Music-3 chain test");
1097 return;
1098 };
1099 let model = Arc::new(CmfModel::open(&p).expect("open pack"));
1100 let dit = Music3Dit::from_cmf(&model).expect("load DiT");
1101 let dav = crate::audiovae::Music3Dav::from_cmf(&model).expect("load DAV");
1102 let n = 6usize;
1103 let noise: Vec<f32> = (0..Music3Dit::IN_CH * n)
1105 .map(|i| (((i * 2654435761) % 1000) as f32 / 500.0) - 1.0)
1106 .collect();
1107 let cond = vec![0f32; Music3Dit::COND_CH * n];
1108 let steps = 3;
1109 let mut seen = 0usize;
1110 let latent = dit.sample(&noise, &cond, n, steps, |i, t| {
1111 assert_eq!(t, steps);
1112 seen = i;
1113 });
1114 assert_eq!(seen, steps, "sampler reported every step");
1115 assert_eq!(latent.len(), Music3Dit::IN_CH * n);
1116 assert!(latent.iter().all(|v| v.is_finite()), "latent went non-finite");
1117 let pcm = dav.decode(&latent, n, None);
1118 assert_eq!(
1119 pcm.len(),
1120 n * crate::audiovae::Music3Dav::HOP * 2,
1121 "the chain's sample count is frames x 512 x 2"
1122 );
1123 assert!(pcm.iter().all(|v| v.is_finite() && v.abs() <= 1.0));
1124 let secs = (n * crate::audiovae::Music3Dav::HOP) as f32
1125 / crate::audiovae::Music3Dav::SAMPLE_RATE as f32;
1126 eprintln!(
1127 "music3 chain: {n} frames -> {} stereo samples ({secs:.3} s at 44.1 kHz)",
1128 pcm.len() / 2
1129 );
1130 }
1131
1132 #[test]
1137 fn music3_rvq_depth_decoder_is_causal() {
1138 let Ok(p) = std::env::var("CMF_MUSIC3_TE") else {
1139 eprintln!("CMF_MUSIC3_TE unset — skipping RVQ decoder test");
1140 return;
1141 };
1142 let model = Arc::new(CmfModel::open(&p).expect("open packed AR stack"));
1143 let dec = RvqDepthDecoder::from_cmf(&model).expect("load RVQ decoder");
1144 assert_eq!(dec.codebooks(), 8, "eight codebooks");
1145 let hs = dec.hidden;
1146 let seq: Vec<f32> = (0..3 * hs).map(|i| 0.05 * ((i as f32) * 0.013).sin()).collect();
1147 let a = dec.forward_last(&seq[..2 * hs], 2);
1148 let b = dec.forward_last(&seq, 3);
1149 assert_eq!(a.len(), hs);
1150 assert!(a.iter().all(|v| v.is_finite()) && b.iter().all(|v| v.is_finite()));
1151 let a2 = dec.forward_last(&seq[..2 * hs], 2);
1155 let d = a.iter().zip(&a2).map(|(x, y)| (x - y).abs()).fold(0f32, f32::max);
1156 assert!(d == 0.0, "not deterministic: {d}");
1157 let logits = dec.head(1, &b);
1158 assert_eq!(logits.len(), 1024, "audio vocab is 1024 per level");
1159 assert!(logits.iter().all(|v| v.is_finite()));
1160 let spread = logits.iter().fold(f32::MIN, |m, v| m.max(*v))
1161 - logits.iter().fold(f32::MAX, |m, v| m.min(*v));
1162 assert!(spread > 1e-3, "head is flat, spread {spread}");
1163 eprintln!("music3 rvq: 8 codebooks, head spread {spread:.3}");
1164 }
1165
1166 #[test]
1175 fn music3_dit_forward_has_the_reference_geometry() {
1176 let Ok(p) = std::env::var("CMF_MUSIC3_DIT") else {
1177 eprintln!("CMF_MUSIC3_DIT unset — skipping Music-3 DiT test");
1178 return;
1179 };
1180 let model = Arc::new(CmfModel::open(&p).expect("open packed DiT"));
1181 let dit = Music3Dit::from_cmf(&model).expect("load DiT");
1182 let n = 4usize;
1183 let x: Vec<f32> = (0..Music3Dit::IN_CH * n)
1184 .map(|i| 0.3 * ((i as f32) * 0.017).sin())
1185 .collect();
1186 let cond: Vec<f32> = (0..Music3Dit::COND_CH * n)
1187 .map(|i| 0.2 * ((i as f32) * 0.011).cos())
1188 .collect();
1189 let v = dit.forward(&x, &cond, n, 0.7);
1190 assert_eq!(v.len(), Music3Dit::IN_CH * n, "velocity is [128, n]");
1191 assert!(v.iter().all(|q| q.is_finite()), "non-finite velocity");
1192 let rms = (v.iter().map(|q| q * q).sum::<f32>() / v.len() as f32).sqrt();
1193 assert!(rms > 1e-6, "velocity is silent, rms {rms}");
1194
1195 let zero_cond = vec![0f32; Music3Dit::COND_CH * n];
1196 let v0 = dit.forward(&x, &zero_cond, n, 0.7);
1197 let dc = v
1198 .iter()
1199 .zip(&v0)
1200 .map(|(a, b)| (a - b).abs())
1201 .fold(0f32, f32::max);
1202 assert!(dc > 1e-5, "condition changed nothing — concat is wrong");
1203
1204 let vt = dit.forward(&x, &cond, n, 0.2);
1205 let dt = v
1206 .iter()
1207 .zip(&vt)
1208 .map(|(a, b)| (a - b).abs())
1209 .fold(0f32, f32::max);
1210 assert!(dt > 1e-5, "timestep changed nothing — the token is lost");
1211 eprintln!("music3 dit: rms {rms:.4}, d/dcond {dc:.4}, d/dt {dt:.4}");
1212 }
1213}