pub struct AudioTokenizer {
pub cfg: TokenizerConfig,
/* private fields */
}Expand description
The MiMo audio tokenizer encoder and its residual VQ.
Fields§
§cfg: TokenizerConfigImplementations§
Source§impl AudioTokenizer
impl AudioTokenizer
Sourcepub fn features(
&self,
mel: &[f32],
m: usize,
pool: Option<&Pool>,
) -> Result<Vec<f32>, String>
pub fn features( &self, mel: &[f32], m: usize, pool: Option<&Pool>, ) -> Result<Vec<f32>, String>
Pre-RVQ features of ONE segment of m mel frames (mel [m][n_mels]):
rows [⌈⌈m/2⌉/2⌉][d] after down_sample_norm.
Sourcepub fn quantize(
&self,
feats: &[f32],
rows: usize,
bf16_books: bool,
pool: Option<&Pool>,
) -> Vec<u32>
pub fn quantize( &self, feats: &[f32], rows: usize, bf16_books: bool, pool: Option<&Pool>, ) -> Vec<u32>
Residual VQ in f32: per level, the nearest codeword by
‖E‖² − 2 r·E (the row’s ‖r‖² does not move the argmin), then
r −= E[idx]. bf16_books selects the bf16-rounded codebooks a
bf16 serving load holds. Returns [rows][levels].
Examples found in repository?
examples/mimo_audio_dump.rs (line 253)
175fn main() {
176 let args: Vec<String> = std::env::args().collect();
177 let cmd = args.get(1).map(String::as_str).unwrap_or("");
178 let out = PathBuf::from(arg(&args, "--out").expect("--out"));
179 match cmd {
180 "decode" => {
181 let wav = std::fs::read(arg(&args, "--wav").expect("--wav")).unwrap();
182 let w = mimo_audio::decode_wav(&wav).unwrap();
183 let flat: Vec<f32> = w.channels.concat();
184 save_f32(&out, &[w.channels.len(), w.frames()], &flat);
185 println!(
186 "rate {} channels {} frames {}",
187 w.sample_rate,
188 w.channels.len(),
189 w.frames()
190 );
191 }
192 "frontend" => {
193 std::fs::create_dir_all(&out).unwrap();
194 let wav = std::fs::read(arg(&args, "--wav").expect("--wav")).unwrap();
195 let t0 = Instant::now();
196 let w = mimo_audio::decode_wav(&wav).unwrap();
197 save_f32(
198 &out.join("dec.npy"),
199 &[w.channels.len(), w.frames()],
200 &w.channels.concat(),
201 );
202 let chans: Vec<Vec<f32>> = w
203 .channels
204 .iter()
205 .map(|c| mimo_audio::resample_sinc(c, w.sample_rate, mimo_audio::SAMPLE_RATE))
206 .collect();
207 save_f32(
208 &out.join("chan24k.npy"),
209 &[chans.len(), chans[0].len()],
210 &chans.concat(),
211 );
212 let mono = mimo_audio::wav_to_mono_24k(&w).unwrap();
213 save_f32(&out.join("wave24k.npy"), &[mono.len()], &mono);
214 let pool = cortiq_engine::pool::Pool::from_env();
215 let (mel, m) = mimo_audio::log_mel(&mono, pool.as_deref()).unwrap();
216 save_f32(&out.join("mel.npy"), &[m, mimo_audio::N_MELS], &mel);
217 println!(
218 "rate {} channels {} frames {} -> {} samples, {m} mel frames, K {} ({:.3}s)",
219 w.sample_rate,
220 w.channels.len(),
221 w.frames(),
222 mono.len(),
223 mimo_audio::audio_token_count(m, 4),
224 t0.elapsed().as_secs_f64()
225 );
226 }
227 "tower" => {
228 std::fs::create_dir_all(&out).unwrap();
229 let src = PathBuf::from(arg(&args, "--src").expect("--src"));
230 let t0 = Instant::now();
231 let audio = if src.extension().is_some_and(|e| e == "cmf") {
232 let model = Arc::new(cortiq_core::CmfModel::open(&src).expect("open cmf"));
233 MimoAudio::from_model(&model).expect("load towers")
234 } else {
235 MimoAudio::from_hf_dir(&src).expect("load towers")
236 };
237 let t_load = t0.elapsed().as_secs_f64();
238 let (mel, m) = if let Some(mp) = arg(&args, "--mel") {
239 let (shape, v) = load_f32(Path::new(&mp));
240 assert_eq!(shape[1], mimo_audio::N_MELS);
241 (v, shape[0])
242 } else {
243 let wav = std::fs::read(arg(&args, "--wav").expect("--wav or --mel")).unwrap();
244 audio.wav_to_mel(&wav).unwrap()
245 };
246 let t1 = Instant::now();
247 let feats = audio.features(&mel, m).unwrap();
248 let t_feats = t1.elapsed().as_secs_f64();
249 let d = audio.tokenizer.cfg.d_model;
250 let rows = feats.len() / d;
251 save_f32(&out.join("feats.npy"), &[rows, d], &feats);
252 let t2 = Instant::now();
253 let exact = audio.tokenizer.quantize(&feats, rows, false, audio.pool());
254 let t_rvq = t2.elapsed().as_secs_f64();
255 let rounded = audio.tokenizer.quantize(&feats, rows, true, audio.pool());
256 let levels = exact.len() / rows;
257 save_i32(&out.join("codes_exact.npy"), &[rows, levels], &exact);
258 save_i32(&out.join("codes_bf16books.npy"), &[rows, levels], &rounded);
259 let own = mimo_audio::AudioCodes {
260 frames: rows,
261 levels,
262 codes: if audio.bf16_codebooks {
263 rounded.clone()
264 } else {
265 exact.clone()
266 },
267 };
268 let t3 = Instant::now();
269 let emb_own = audio.embed_codes(&own).unwrap();
270 let t_enc = t3.elapsed().as_secs_f64();
271 save_f32(
272 &out.join("embeds_own.npy"),
273 &[emb_own.n_tokens, emb_own.dim],
274 &emb_own.rows,
275 );
276 let fixed = match arg(&args, "--codes") {
277 Some(cp) => {
278 let (shape, v) = load_codes(Path::new(&cp));
279 mimo_audio::AudioCodes {
280 frames: shape[0],
281 levels: shape[1],
282 codes: v,
283 }
284 }
285 None => own.clone(),
286 };
287 let emb = audio.embed_codes(&fixed).unwrap();
288 save_f32(&out.join("embeds.npy"), &[emb.n_tokens, emb.dim], &emb.rows);
289 let k = mimo_audio::audio_token_count(m, audio.encoder.cfg.group);
290 let meta = serde_json::json!({
291 "src": src.display().to_string(),
292 "mel_frames": m,
293 "segments": mimo_audio::segment_lengths(m),
294 "codes": rows,
295 "placeholder_count_K": k,
296 "embed_rows_own": emb_own.n_tokens,
297 "embed_rows_fixed": emb.n_tokens,
298 "load_s": t_load,
299 "features_s": t_feats,
300 "rvq_s": t_rvq,
301 "encoder_s": t_enc,
302 "bf16_codebooks_default": audio.bf16_codebooks,
303 "threads": cortiq_engine::pool::Pool::effective_threads(),
304 });
305 std::fs::write(
306 out.join("tower.json"),
307 serde_json::to_string_pretty(&meta).unwrap(),
308 )
309 .unwrap();
310 println!("{meta}");
311 assert_eq!(emb_own.n_tokens, k, "placeholder count != encoder rows");
312 }
313 "calib" => {
314 let src = PathBuf::from(arg(&args, "--src").expect("--src"));
315 let model = Arc::new(cortiq_core::CmfModel::open(&src).expect("open cmf"));
316 let audio = MimoAudio::from_model(&model).expect("load towers");
317 let dir = PathBuf::from(arg(&args, "--wav-dir").expect("--wav-dir"));
318 let mut wavs: Vec<PathBuf> = std::fs::read_dir(&dir)
319 .unwrap()
320 .filter_map(|e| e.ok().map(|e| e.path()))
321 .filter(|p| p.extension().is_some_and(|e| e == "wav"))
322 .collect();
323 wavs.sort();
324 let t0 = Instant::now();
325 cortiq_engine::gptq_capture::begin(true);
326 let mut frames = 0usize;
327 for w in &wavs {
328 let emb = audio.embed_wav(&std::fs::read(w).unwrap()).unwrap();
329 frames += emb.n_tokens;
330 eprintln!(
331 " {} -> {} rows ({:.0}s)",
332 w.display(),
333 emb.n_tokens,
334 t0.elapsed().as_secs_f64()
335 );
336 }
337 let hess = cortiq_engine::gptq_capture::end();
338 save_hessians(&out, &hess);
339 println!(
340 "{} clips, {frames} LLM rows, {} linears -> {} ({:.0}s)",
341 wavs.len(),
342 hess.len(),
343 out.display(),
344 t0.elapsed().as_secs_f64()
345 );
346 }
347 _ => {
348 eprintln!(
349 "usage: mimo_audio_dump (decode|frontend|tower|calib) --out ... (see the source header)"
350 );
351 std::process::exit(2);
352 }
353 }
354}Auto Trait Implementations§
impl Freeze for AudioTokenizer
impl RefUnwindSafe for AudioTokenizer
impl Send for AudioTokenizer
impl Sync for AudioTokenizer
impl Unpin for AudioTokenizer
impl UnsafeUnpin for AudioTokenizer
impl UnwindSafe for AudioTokenizer
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more