rtx-csm: emotional_speech_guide — CREMA-D vs RAVDESS firdhokk verdict
8-gen bench (4 emotions × 2 corpora) at seed=42 against firdhokk Whisper-LV3: target RAVDESS CREMA-D happy happy (0.999) ✓ happy (0.999) ✓ angry neutral (0.92) sad (0.99) fearful happy (0.998) fearful (0.984) ✓ sad angry (0.99) fearful (0.99) CREMA-D 2/4 vs RAVDESS 1/4. Larger / more naturalistic corpus produces more class-pure fearful direction. Neither corpus solves angry or sad — recipe shifts into 'vague expressivity' rather than class-specific corners. Practical: prefer CREMA-D when available; A/B both per emotion if class precision matters. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
@@ -29,8 +29,8 @@
|
||||
//! enough of the PyTorch pickle format to extract a `state_dict`-style nested
|
||||
//! `Dict`. So we don't need a Python step in the conversion pipeline.
|
||||
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use candle_core::{pickle, safetensors as ct_safetensors, DType, Device, Tensor};
|
||||
use anyhow::{Context, Result, anyhow};
|
||||
use candle_core::{DType, Device, Tensor, pickle, safetensors as ct_safetensors};
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
|
||||
@@ -71,9 +71,9 @@ pub fn convert_pth(
|
||||
let weight_v = v_tensors
|
||||
.remove(&stem)
|
||||
.expect("weight_v stem present after sort");
|
||||
let weight_g = g_tensors.remove(&stem).ok_or_else(|| {
|
||||
anyhow!("orphan weight_v at {stem} (no matching weight_g entry)")
|
||||
})?;
|
||||
let weight_g = g_tensors
|
||||
.remove(&stem)
|
||||
.ok_or_else(|| anyhow!("orphan weight_v at {stem} (no matching weight_g entry)"))?;
|
||||
let merged = merge_weight_norm(&weight_v, &weight_g)
|
||||
.with_context(|| format!("merging weight_norm at {stem}"))?;
|
||||
out_map.insert(format!("{stem}.weight"), merged);
|
||||
@@ -82,7 +82,9 @@ pub fn convert_pth(
|
||||
|
||||
if !g_tensors.is_empty() {
|
||||
let orphans: Vec<_> = g_tensors.keys().cloned().collect();
|
||||
return Err(anyhow!("orphan weight_g entries (no matching weight_v): {orphans:?}"));
|
||||
return Err(anyhow!(
|
||||
"orphan weight_g entries (no matching weight_v): {orphans:?}"
|
||||
));
|
||||
}
|
||||
|
||||
let pass_count = passthrough.len();
|
||||
@@ -167,12 +169,7 @@ mod tests {
|
||||
fn weight_norm_merge_matches_manual() {
|
||||
// Reproduce PyTorch weight_norm formula on a small (2, 3) tensor.
|
||||
let device = Device::Cpu;
|
||||
let v = Tensor::from_slice(
|
||||
&[1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0],
|
||||
(2, 3),
|
||||
&device,
|
||||
)
|
||||
.unwrap();
|
||||
let v = Tensor::from_slice(&[1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0], (2, 3), &device).unwrap();
|
||||
let g = Tensor::from_slice(&[2.0f32, 3.0], (2, 1), &device).unwrap();
|
||||
let merged = merge_weight_norm(&v, &g).unwrap();
|
||||
let merged: Vec<f32> = merged.flatten_all().unwrap().to_vec1().unwrap();
|
||||
@@ -181,8 +178,12 @@ mod tests {
|
||||
let n0 = (1.0f32 + 4.0 + 9.0).sqrt();
|
||||
let n1 = (16.0f32 + 25.0 + 36.0).sqrt();
|
||||
let expected = vec![
|
||||
2.0 * 1.0 / n0, 2.0 * 2.0 / n0, 2.0 * 3.0 / n0,
|
||||
3.0 * 4.0 / n1, 3.0 * 5.0 / n1, 3.0 * 6.0 / n1,
|
||||
2.0 * 1.0 / n0,
|
||||
2.0 * 2.0 / n0,
|
||||
2.0 * 3.0 / n0,
|
||||
3.0 * 4.0 / n1,
|
||||
3.0 * 5.0 / n1,
|
||||
3.0 * 6.0 / n1,
|
||||
];
|
||||
for (a, b) in merged.iter().zip(expected.iter()) {
|
||||
assert!((a - b).abs() < 1e-6, "merge mismatch: got {a}, want {b}");
|
||||
|
||||
Reference in New Issue
Block a user