Commit Graph
4 Commits
Author SHA1 Message Date
osobhandClaude Opus 4.7 a5cedfb46a 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]>
2026-04-30 00:01:02 -07:00
osobhandClaude Opus 4.7 d42aba0f1b rtx-csm: emotion2vec input normalization + 9-class direct mapping
Three real bugs found while running a YouTube → train → eval pipeline
end-to-end on real corpora:

1. emotion2vec was producing near-constant logits regardless of input.
   Per config.yaml `normalize: true` — data2vec2/emotion2vec expects
   per-utterance zero-mean unit-variance normalization on the raw
   waveform before the local_encoder. Added inside the EmotionDetector
   trait impl so all callers get it.

   Verified empirically: 4 different audio inputs (Carlini talk,
   audience question, McConaughey speech) now produce different argmax
   classes. Before fix: all 4 produced identical logits.

2. The 9→5 emotion fold was collapsing every real-world clip to
   [excited]. happy / surprised / other all mapped to Excited covered
   ~95% of natural speech. Replaced with a direct 9-class identity
   mapping; EmotionLabel gained Disgusted, Fearful, Happy, Surprised,
   Unk variants. Now: 132 [surprised] + 12 [excited] across the
   Carlini corpus instead of 144 [excited].

3. lora_train_emotional --peak-lr / --epochs flags. The canned 3-stage
   recipe over-fits on small (~100 clip) corpora at extended rank 8;
   users need to tune. (The recipe stays as defaults; flags are pure
   overrides.)

Plus diagnostic: examples/emotion2vec_probe — feed real audio files
into emotion2vec and dump per-class logits. Used to find bug #1.

Lib suite still 131/131 (the test that locked the 9→5 fold updated
to lock the new identity mapping).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2026-04-28 12:23:53 -07:00
osobhandClaude Opus 4.7 32a811904a rtx-csm: Phase 12.5 — self-describing LoRA adapters
Trained adapters now embed (rank, alpha, target_modules, crate_version)
as JSON in safetensors __metadata__["rtx_csm_lora"]. apply_lora_adapter
reads it at load time so users no longer have to remember matching
--lora-rank/--lora-alpha/--extended-lora flags from training.

LoraAdapterMetadata::is_extended() heuristic: target_modules contains
any MLP path or output_proj or k_proj. Handles both the canonical
extended() preset and future custom configs that overlap it.

apply_lora_adapter rank/alpha/extended params became Option<_>
(None = use file metadata, Some = override). Both callers updated.
save_lora_adapter_with_metadata is the new path used by both trainers;
the plain save_lora_adapter still exists for the metadata-less case
(per-stage curriculum snapshots).

safetensors dep bumped 0.4 → 0.7 to match candle 0.9's transitive pin
so candle's Tensor: View impl is in scope for serialize_to_file
(candle's own save wrapper hardcodes the metadata arg to None).

Backward compat: pre-12.5 adapters load fine when explicit CLI flags
are passed; auto-detect path is skipped silently.

Verified end-to-end: trained adapter saved with metadata,
`generate --lora <path>` (no other flags) auto-detected
rank=8 alpha=16 extended=true and applied. Older metadata-less adapter
still loaded with explicit flags. 3 new unit tests; lib suite 99/99.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2026-04-27 16:29:25 -07:00
osobhandClaude Opus 4.7 510cd7011c rtx-csm: Phase 12.3 — curriculum LoRA trainer for emotional fine-tunes
Closes the personal_voice_training_guide.md §4 stack: capacity (12.1) +
control tokens (12.2) + multi-stage curriculum (this).

TrainingExample gains emotion_tag + stage. Trainer::train applies the
tag via the same apply_emotion_hint helper inference uses (now
pub(crate)) — training and inference must use identical prefix
formatting or the adapter won't transfer.

TrainingDataset::load_from_manifest reads JSONL
`{wav, transcript, emotion_tag?, stage?, speaker?}` rows; wav paths
resolve relative to manifest dir.

CurriculumStage + CurriculumTrainer run N stages sequentially against a
shared VarMap. Per stage: filter by ex.stage label, build a transient
sub-dataset, run Trainer, save snapshot if requested. The "*" stage
name is a global catch-all.

examples/lora_train_emotional.rs wraps the canonical 3-stage recipe:
audiobook (3 ep × lr 1e-4) → podcast (1 ep × lr 3e-5) → va (1 ep ×
lr 1e-5). --extended-lora recommended (FFN is the prosodic-style
carrier per the guide).

Verified end-to-end on Metal: 3-row manifest → all 3 stages execute,
checkpoints + final adapter written, prompt-token lengths varied by
emotion-tag length (9 vs 11 for different tags) confirming the tag
flowed through the training tokenization. Lib suite 96/96.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2026-04-27 15:37:44 -07:00