lm_forward_probe/
lm_forward_probe.rs1use burn::tensor::{Int, Tensor, TensorData};
7use maolan_generate::acestep::lm::{self, AceStepLm, AudioCodeVocab, SamplingConfig};
8use maolan_generate::acestep::qwen3::{Qwen3Config, Qwen3Model};
9use std::path::Path;
10
11type B = burn::backend::NdArray<f32>;
12
13fn main() -> anyhow::Result<()> {
14 let model_dir = std::env::args()
15 .nth(1)
16 .unwrap_or_else(|| "/home/meka/repos/ace".to_string());
17 let model_dir = Path::new(&model_dir);
18 let device = Default::default();
19
20 let config = Qwen3Config::load(&model_dir.join("lm_config.json"))?;
21 let lm = AceStepLm::<B>::from_burnpack(&config, &model_dir.join("acestep-lm.bpk"), &device)?;
22 let vocab = AudioCodeVocab::from_tokenizer_json(&model_dir.join("lm_tokenizer.json"))?;
23
24 let cot = lm::build_cot_block(
25 "Metal guitar with a lot of distortion",
26 Some(120.0),
27 Some("A minor"),
28 Some("4/4"),
29 4,
30 );
31 let prompt = lm::build_codes_prompt("Metal guitar with a lot of distortion", &cot);
32 let ids = lm::tokenize_prompt(&model_dir.join("lm_tokenizer.json"), &prompt)?;
33 println!("prompt: {} tokens", ids.len());
34
35 let model: &Qwen3Model<B> = &lm.model;
37 let ids_i64: Vec<i64> = ids.iter().map(|&id| i64::from(id)).collect();
38 let len = ids_i64.len();
39 let input = Tensor::<B, 2, Int>::from_data(TensorData::new(ids_i64, [1, len]), &device);
40 let hidden = model.forward(input, true);
41 let [_, _, hidden_dim] = hidden.dims();
42 let last = hidden.narrow(1, len - 1, 1).reshape([1, hidden_dim]);
43 let weight = model.embedding_weight();
44 let logits = last
45 .matmul(weight.clone().transpose())
46 .reshape([config.vocab_size as usize]);
47 let values: Vec<f32> = logits
48 .into_data()
49 .convert::<f32>()
50 .to_vec()
51 .map_err(|e| anyhow::anyhow!("{e}"))?;
52 let mut order: Vec<usize> = (0..values.len()).collect();
53 order.sort_by(|&a, &b| values[b].total_cmp(&values[a]));
54 println!("\ntop-10 next-token predictions:");
55 for &idx in order.iter().take(10) {
56 let id = idx as u32;
57 let label = vocab
58 .token_id_to_code(id)
59 .map(|c| format!("audio_code_{c}"))
60 .unwrap_or_else(|| format!("token {id}"));
61 println!(" id {id:>7} logit {:>8.3} {label}", values[idx]);
62 }
63
64 let greedy = SamplingConfig {
66 temperature: 1e-5,
67 top_k: 1,
68 cfg_scale: 1.0,
69 ..SamplingConfig::new(28, 0)
70 };
71 for (name, sampling) in [
72 ("greedy", greedy),
73 ("sampled official", SamplingConfig::new(28, 0)),
74 ] {
75 let codes = lm.generate_codes(&ids, None, &vocab, &sampling, None);
76 println!("\n{name}: {} codes: {codes:?}", codes.len());
77 }
78
79 let mut full_ids = ids.clone();
82 let mut full_codes = Vec::new();
83 for _ in 0..20 {
84 let ids_i64: Vec<i64> = full_ids.iter().map(|&id| i64::from(id)).collect();
85 let len = ids_i64.len();
86 let input = Tensor::<B, 2, Int>::from_data(TensorData::new(ids_i64, [1, len]), &device);
87 let hidden = model.forward(input, true);
88 let last = hidden.narrow(1, len - 1, 1).reshape([1, hidden_dim]);
89 let logits = last
90 .matmul(weight.clone().transpose())
91 .reshape([config.vocab_size as usize]);
92 let values: Vec<f32> = logits
93 .into_data()
94 .convert::<f32>()
95 .to_vec()
96 .map_err(|e| anyhow::anyhow!("{e}"))?;
97 let next = values
98 .iter()
99 .enumerate()
100 .max_by(|(_, a), (_, b)| a.total_cmp(b))
101 .map(|(i, _)| i as u32)
102 .unwrap();
103 if next == AudioCodeVocab::IM_END_ID {
104 break;
105 }
106 if let Some(code) = vocab.token_id_to_code(next) {
107 full_codes.push(code);
108 }
109 full_ids.push(next);
110 }
111 println!(
112 "\nfull-forward greedy: {} codes: {full_codes:?}",
113 full_codes.len()
114 );
115 Ok(())
116}