Phase 5c — pure-Rust converter for microsoft/wavlm-base-plus-sv with auto-detecting weight_norm merger; verified on real 100M-param weights: load + embed + cosine-similarity round-trip works on Metal. - wavlm_sv_convert.rs: candle_core::pickle reads pytorch_model.bin directly. merge_weight_norm_auto picks the kept dim from g's shape (dim=0 for AudioSeal SEANet, dim=2 for WavLM pos_conv_embed). Skips classifier.*/objective.* (train-only AMSoftmax head). - examples/wavlm_sv_convert: HF download + convert CLI. Verified output: 1 weight_norm pair merged + 261 passthrough + 3 skipped = 262 tensors. - examples/wavlm_sv_demo: load + embed pair of WAVs + cosine similarity. - examples/audioseal_inspect: gains --which wavlm-sv variant for key discovery. - hub.rs: REPO_WAVLM_SV + resolve_wavlm_sv() helper. - wavlm_sv::XVectorHead bug fix: layer_weights is top-level, not nested under prefix. Verified end-to-end on Metal: cosine sim 0.9985 on same-speaker pair (CSM vs CSM-watermarked, 10s @ 24 kHz resampled to 16 kHz). Numerical parity vs HF reference is Phase 5d. 3 converter tests + 12 wavlm_sv tests; 78 lib tests total green. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
44 lines
1.3 KiB
Rust
44 lines
1.3 KiB
Rust
//! Convert `microsoft/wavlm-base-plus-sv/pytorch_model.bin` → flat
|
|
//! safetensors with weight_norm merged.
|
|
//!
|
|
//! Usage:
|
|
//! ```
|
|
//! cargo run -p rtx-csm --release --example wavlm_sv_convert -- \
|
|
//! --out /tmp/wavlm_sv.safetensors
|
|
//! ```
|
|
|
|
use anyhow::{Context, Result};
|
|
use clap::Parser;
|
|
use rtx_csm::{hub, wavlm_sv_convert};
|
|
use std::path::PathBuf;
|
|
|
|
#[derive(Debug, Parser)]
|
|
#[command(name = "wavlm_sv_convert")]
|
|
struct Cli {
|
|
/// Optional override; defaults to HF-fetched pytorch_model.bin.
|
|
#[arg(long)]
|
|
input: Option<PathBuf>,
|
|
/// Output safetensors.
|
|
#[arg(long)]
|
|
out: PathBuf,
|
|
}
|
|
|
|
fn main() -> Result<()> {
|
|
tracing_subscriber::fmt().init();
|
|
let cli = Cli::parse();
|
|
let input = match cli.input {
|
|
Some(p) => p,
|
|
None => hub::resolve_wavlm_sv().context("resolve_wavlm_sv")?,
|
|
};
|
|
tracing::info!("converting {} -> {}", input.display(), cli.out.display());
|
|
let report = wavlm_sv_convert::convert_pth(&input, &cli.out)?;
|
|
println!(
|
|
"merged {} weight_norm pairs, {} passthrough, {} skipped (classifier/objective), {} total tensors written",
|
|
report.merged_weight_norm_pairs,
|
|
report.passthrough_tensors,
|
|
report.skipped_tensors,
|
|
report.total_tensors_written
|
|
);
|
|
Ok(())
|
|
}
|