Skip to content

feat: 感情条件付き TTS (Style Vector + PE-A Emotion Loss) — 実装完了 / 実 GPU 学習は未実施 - #355

Draft
ayutaz wants to merge 92 commits into
devfrom
docs/peav-style-conditioning-research
Draft

feat: 感情条件付き TTS (Style Vector + PE-A Emotion Loss) — 実装完了 / 実 GPU 学習は未実施#355
ayutaz wants to merge 92 commits into
devfrom
docs/peav-style-conditioning-research

Conversation

@ayutaz

@ayutaz ayutaz commented Apr 26, 2026

Copy link
Copy Markdown
Owner

このPRで何ができるようになるか

piper-plus に 「声の感情を切り替える」機構 を追加する。
学習時に音声から抽出した emotion embedding (style_vector) をモデルに食わせ、推論時には任意の感情ベクトルを与えて「悲しい声」「怒った声」などを生成できる。

  • 既存モデルは 何もしなくても今まで通り動く (--style-vector-dim 0 がデフォルトのため bit-for-bit 互換)
  • 6 ランタイム (Python / Rust / C++ / C# / Go / WASM) すべてで style_vector 入力に対応
  • emotion embedding は Meta facebook/pe-av-small (Apache-2.0) を loss として使用 (推論グラフには載らない、商用利用可)

取り込み元: fork yusuke-ai/piper-plus@314b3355 の先行実装を本家 dev に統合したもの。

使い方

1) 学習: スタイル次元を有効にする

uv run python -m piper_train \
  --dataset-dir <DATASET> \
  --style-vector-dim 256 \
  --style-condition-mode global \
  --style-condition-dropout 0.1 \
  ...
CLI オプション 用途 デフォルト
--style-vector-dim N スタイルベクトル次元 (0 で完全無効化 = 後方互換) 0
--style-condition-mode 注入箇所 (global = 大域条件 g に加算 / text = TextEncoder のみ) global
--style-condition-dropout 学習時に style を確率的に zero-mask 0.0
--load_weights_from_checkpoint <PATH> shape 不一致を WARN で skip しつつ既存 ckpt から partial load -

PE-A loss を有効にする場合 (要 uv sync --extra pea):

... --pea-emotion-style-bank style_bank.npz \
    --pea-emotion-loss-weight 0.5 \
    --pea-emotion-centroid-weight 0.3 \
    --pea-emotion-margin-weight 0.2 \
    --pea-emotion-warmup-steps 2000

2) 推論: 任意の感情ベクトルを与える

Python:

uv run python -m piper_train.infer_onnx \
  --model emotion.onnx --config emotion.json \
  --text "Hello, world." \
  --style-vector path/to/angry.npy   # .npy / .pt / .pth

Rust / C# / Go / C++ CLI: 各ランタイムで同名の --style-vector PATH フラグ。
WASM/JS: piperPlus.synthesize(text, { styleVector: Float32Array })
HTTP (FastAPI): X-Style-Vector-B64 ヘッダー or ?style_vector_b64= クエリ (base64-encoded float32 LE)

3) Style Bank (感情 centroid) の作り方

CREMA-D など感情ラベル付き音声を集めて、emotion ごとの中心ベクトル (.npz) を生成:

uv run python -m piper_train.tools.build_pea_style_bank \
  --audio-dir crema_d/audio \
  --metadata crema_d/metadata.csv \
  --output style_bank.npz

このファイルを学習時に --pea-emotion-style-bank に渡すと、generator が PE-A 空間でこの centroid に近づくよう loss が掛かる。

互換性 / 後方互換

  • --style-vector-dim 0 (デフォルト) のとき、ONNX 入出力・モデルサイズ・推論速度は bit-for-bit 互換。既存 voice モデルは再学習不要。
  • ONNX に追加した style_vector 入力は mask パターン (style_vector + style_vector_mask の 2 入力)。古いモデル (input なし) と新しいモデル (input あり、mask=0 でゼロ填) を同一ランタイムで扱える。
  • C ABI (PiperPlusSynthOptions) は _reserved[5]_reserved[3] + style_vector 2 フィールド追加で sizeof 維持 → Dart FFI / Godot GDExtension の既存ビルドは無修正で動く。
  • 6 ランタイム横断の I/O 契約は docs/spec/style-vector-contract.toml に固定。

設計判断 (なぜこうしたか)

トピック 採択 却下した代替案
Emotion embedding ソース PE-AV (Meta, Apache-2.0) wav2vec2-emotion (GPL/non-commercial 混在) / ESD 自前学習 (regression リスク)
注入箇所 VITS 大域条件 g (decoder + flow + DP に伝播) TextEncoder のみ (イントネーションに乗らない) / 全層 projection (学習負荷)
デフォルト挙動 --style-vector-dim 0 で完全無効 有効化を default にすると既存 ckpt が動かない
ONNX Optional 入力 mask パターン (2 入力) None 入力 (古い ORT 非対応) / 別モデル分岐 (ファイル数 2 倍)
Optional dep の扱い pyproject.toml[pea] extra デフォルト依存にすると torchcodec / decord / opencv-python など transitive で CI 肥大

ローカル動作確認 (このPRで PASS したもの)

  • ✅ ruff check / ruff format / cargo fmt / cargo clippy -D warnings 全 PASS
  • ✅ Python テスト 139 PASS (新規) + 875+ リグレッション影響なし
    • style_vector 学習側統合: 11
    • load_weights_from_checkpoint: 3
    • PE-A emotion loss: 20
    • 6 ランタイム契約: 24 + 6 (WASM)
    • style bank 関連ツール: 58
    • emotion fine-tune ツール: 20
  • ✅ Rust release ビルド (83 MB binary) / C# dotnet build PiperPlus.sln 0 errors / WASM node --test 6 PASS
  • ✅ shell script syntax: scripts/run_crema_d_finetune.sh / scripts/export_and_verify_emotion_runtimes.sh

残タスク (このPRに含まれない、別セッションで実施)

# 作業 所要 必要環境
1 PE-A 実機ロード確認 (uv sync --extra pea → PoC スクリプト) ~1h CPU 可
2 6lang ベース → CREMA-D fine-tune ~2 日 GPU x1
3 SER (≥65%) + MOS (PESQ ≥2.8 / STOI ≥0.85) + 多言語 regression 評価 ~半日 学習済み ckpt
4 Go / C++ ランタイム実機ビルドで MD5 一致確認 ~半日 Linux / 別環境

再開コマンド:

bash scripts/run_crema_d_finetune.sh stage5a   # style bank 構築 (~30 min)
bash scripts/run_crema_d_finetune.sh stage5b   # fine-tune 実行 (~2 日)
bash scripts/export_and_verify_emotion_runtimes.sh   # ONNX export + 6 ランタイム MD5
uv run python tools/benchmark/evaluate_emotion_finetune.py --checkpoint <path>

主要な追加ファイル

領域 ファイル
学習側統合 src/python/piper_train/vits/{models,dataset,lightning,commons}.py, __main__.py, infer.py
PE-A loader src/python/piper_train/perception/pea_loader.py
ONNX export src/python/piper_train/export_onnx.py (mask パターン + metadata_props)
Python 推論 src/python_run/piper/{voice.py,infer_onnx.py,http_server.py}
Rust 推論 src/rust/piper-core/src/engine.rs, src/rust/piper-cli/src/main.rs
C++ 推論 src/cpp/piper.{cpp,hpp}, piper_plus_c_api.cpp, main.cpp
C# 推論 src/csharp/PiperPlus.Core/Inference/, PiperPlus.Cli/Program.cs
Go 推論 src/go/piperplus/{engine,options}.go, numpy.go, cmd/piper-plus/main.go
WASM/JS src/wasm/openjtalk-web/src/index.js, types/index.d.ts
Style bank ツール src/python/piper_train/tools/{build_pea_style_bank,inject_style_labels,validate_style_bank}.py
評価ツール tools/benchmark/evaluate_emotion_finetune.py
学習 driver scripts/run_crema_d_finetune.sh, scripts/export_and_verify_emotion_runtimes.sh
仕様書 docs/spec/style-vector-contract.toml (6 ランタイム I/O 契約)
機能ガイド docs/features/style-bank.md

依存追加 (optional, デフォルトでは入らない)

uv sync --extra pea
# perception-models @ git+https://github.com/facebookresearch/perception_models.git

ライセンス: LICENSE.PE = Apache-2.0 (商用可、MIT 互換)。

関連リンク

@ayutaz ayutaz changed the title feat: Style Vector Conditioning + PE-A Emotion Loss (Phase 0-5) feat: 感情条件付き TTS (Style Vector + PE-A Emotion Loss) — 実装完了 / 実 GPU 学習は未実施 May 3, 2026
ayutaz added 29 commits May 3, 2026 11:15
yusuke-ai/piper-plus の feature/2026-04-14-2312-peav-style-conditioning
ブランチに実装された未取り込み機能について、3エージェントで並列調査:

- アーキテクチャ調査: TextEncoder / SynthesizerTrn の global/text 2 モード設計、
  3 コミットを通じた設計変遷、既存モデルとの後方互換性評価
- PE-A emotion loss 調査: facebook/pe-av-small ベースの知覚損失定式化、
  style bank (.npz) データフロー、training_step への組込
- 統合影響分析: ONNX エクスポート未対応、5 ランタイム拡張の必要性、
  既存機能 (prosody_features / speaker_embedding / freeze-dp 等) との相互作用、
  段階統合戦略の選択肢 A/B/C

本家取り込みには以下の未解決事項を特定:
- PE-A style bank 生成ツールが fork に同梱されていない
- export_onnx.py が fork 側でも未更新のため ONNX 化で機能しない
- 5 ランタイム (C++/Rust/C#/Go/JS/WASM) への style_vector 入力追加が必須

推奨: 取り込むなら Phase 1 (feature flag で学習側のみ) →
Phase 2 (ONNX+ランタイム) → Phase 3 (ツール整備) の段階統合。
まずは yusuke-ai 側 (mera-chan[bot]) と協力意向の確認が先。
追調査で以下を解決:
- §12 新設: facebook/pe-av-small のライセンスは Apache-2.0 で
  piper-plus MIT と完全互換、商用利用可を確認
- §13 新設: PE-A style bank (.npz) のスキーマを fork コードから解読、
  自前生成ツール build_pea_style_bank.py の設計を詳細化。
  CREMA-D (ODbL、商用可) を第一候補の感情音声データセットとして選定
- §14 新設: 段階統合ロードマップ (Phase 0-5) と分割 PR 構成 (PR-A〜PR-F)

推論側コスト分析も TL;DR に追加:
- PE-A loss は推論グラフに含まれない (WavLM と同パターン)
- style_proj 追加は +0.2〜0.5MB (75MB モデル比 +0.3〜0.7%)
- 推論速度影響はμ秒オーダーで実質ゼロ
- → 軽量・多言語・オフラインのポジションを崩さない

§10 疑問点のうち解決済み項目 (PE-A style bank 生成、ライセンス) を
解決済みセクションに分離。yusuke-ai への連絡は省略可能と結論 -
自前実装で完結する。
ベースモデル (6lang 75 epoch) 再学習なしで、既存チェックポイントから
fine-tune だけで style vector conditioning + PE-A emotion loss を
有効化できることが分かったため反映。

追加内容:
- §1 TL;DR に fine-tune 対応可能性を追記、総工数を 2ヶ月 → 1.5ヶ月に短縮
- §11 推奨アクションの Phase 5 を「既存 6lang に fine-tune」に更新
- §14 ロードマップの Phase 5 工数を 2-3週間 → 3-5日 に短縮
- §15 新設: fine-tune のみで対応可能な設計根拠 (style_proj ゼロ初期化、
  --load_weights_from_checkpoint、つくよみちゃんパターンとの同型性、
  想定コマンド、段階的 fine-tune 戦略)

GPU 時間: ベース再学習 368 GPU hours → fine-tune 24 GPU hours (約15倍効率化)。
既存モデル品質は保持、段階検証可能、並列開発可能。
現時点では両方の実学習結果がないため、先行研究
(StyleTTS 2, VITS adapter 系, prompt tuning) と VITS アーキテクチャ
特性からの推定比較を §16 新設で記載。

追加内容:
- 16.1 観点別サマリ表 (8 観点)
- 16.2 観点別の詳細見積もり
  (感情強度、一貫性、多言語均等性、話者独立性、汎化、発音品質保持、
   学習コスト)
- 16.3 想定定量指標 (fine-tune / base 再学習それぞれ)
  - Fine-tune: 英語 70-80%, 日本語 60-70%, 他言語 30-50%
  - Base: 全言語 80-85%
  - MOS 差 +0.3-0.5 (感情表現)
- 16.4 用途別判断基準
- 16.5 推奨プロセス (先に fine-tune → 不足なら再学習)
- 16.6 Phase 5 完了後に実測値で更新する項目リスト

§1 TL;DR にも効果差サマリと §16 への参照を追加。

前提: 先行研究ベースの推定値。Phase 5 実験後に実測値で更新すること。
エージェントチーム4並列で技術調査を実施、結果を統合して docs/research/implementation-plan/ 配下に
Phase別の実装計画を作成。

追加ファイル:
- README.md: 全体概要 + PR分割案 + 依存関係グラフ + リスクまとめ
- phase-0-1.md: facebook/pe-av-small PoC + Style vector conditioning 学習側統合
  - PoC スクリプト (test_pe_av_small.py) 完全実装
  - Fork コミット 314b335 からのファイル別取り込みマッピング
  - テストケース設計 (11テスト)
- phase-2.md: ONNX エクスポート + 5ランタイム対応
  - speaker_embedding マスクパターンの分析
  - 各ランタイム (Python/C++/Rust/C#/Go/WASM) の API/ABI 変更案
  - 後方互換性戦略、分割PR案
- phase-3-4.md: Style bank 生成ツール + PE-A emotion loss 統合
  - build_pea_style_bank.py 完全実装 (~400行)
  - inject_style_labels.py (既存データセット拡張)
  - PE-A loss の lightning.py 統合 (3項合成: direction + centroid + margin)
  - CLI オプション 9個 (pea-emotion-*)
- phase-5.md: Fine-tune 実験
  - 感情データセット比較 (CREMA-D/ESD/EmoV-DB/JTES)
  - シナリオA/B/C の段階的実施プラン
  - Stage 5a/5b/5c の具体的 fine-tune コマンド
  - 評価プロトコル (感情認識精度 + MOS自然性/感情表現)
  - つくよみちゃん感情拡張シナリオ

既存の peav-style-conditioning.md の TL;DR に参照リンクも追加。

総工数目安: 約 1.5ヶ月 (Phase 0 PoC 1-2h → Phase 1 学習側 1週 → Phase 2 ONNX+ランタイム 2週 →
Phase 3 ツール 3日 → Phase 4 PE-A loss 1.5週 → Phase 5 fine-tune 3-5日)。

Phase 1 と Phase 3 は並列実施可能。Phase 2 各ランタイムも並列可。
全 Phase の実装を Claude Code (AIエージェント) が担当することが決定したため、
工数見積もりを Claude Code の実装速度前提に再計算。

主な変更:
- implementation-plan/README.md: 工数表と PR 分割案を Claude Code ベースに更新
  - 総工数: 1.5 ヶ月 → 実装 5〜8 日稼働 + GPU 学習 2 日 = 約 10 日間
  - 参考値として人間エンジニア想定の工数も併記
- phase-0-1.md, phase-2.md, phase-3-4.md, phase-5.md:
  各 Phase の「工数内訳」テーブルに Claude Code と人間エンジニアの 2 列を追加
- peav-style-conditioning.md §14 ロードマップ・§1 TL;DR:
  Claude Code 実装前提の工数を明記

Claude Code の実装速度が速い理由:
1. 並列 tool 実行 (複数ファイル同時編集、Bash 並列実行)
2. Agent 並列起動 (6 ランタイムを同時対応)
3. テスト自動生成 (詳細設計からテストコードを即時生成)
4. コード完全設計済み (build_pea_style_bank.py 等は即実装可能)

GPU 学習時間 (Phase 5 の 40-48h) はバックグラウンド処理として分離。
MOS リスナー評価はユーザー側の作業 (評価者確保に 1-2 週間) として別管理。
- facebook/pe-av-small の AutoModel.from_pretrained + trust_remote_code 検証
- クラス名・API 名 (get_audio_embeds など) の特定手順
- Option B (perception_models 手動インポート) フォールバック記載
- 工数 15 分、依存なし、マイルストーン #10
- 16kHz 3 秒ダミー音声で embedding 抽出手順
- 入力 shape (2D/3D) 両方試行、出力次元 (256/512) 確定
- L2 norm 前後比較、正規化の要否判定
- 工数 15 分、依存 P0-T01、マイルストーン #10
- CUDA synchronize 付き warmup + レイテンシ計測手順
- Peak GPU memory (torch.cuda.max_memory_allocated) 記録
- Phase 1/3/4 への連絡事項 (次元・latency・normalize 要否)
- 工数 15〜30 分、依存 P0-T02、マイルストーン #10
- P0-T01〜T03 一覧と依存関係図 (T01 → T02 → T03 直列)
- 「一から考えたら」 4 案検討 (ONNX 自前化/代替 embedding/shell 最小化/工数圧縮)
- 成功基準: test_pe_av_small.py 完走 + embedding_dim ログ出力
- マイルストーン #10、期日 2026-04-25
- CREMA-D 27GB の DL + LJSpeech 形式変換手順
- 感情ラベル (ANG/DIS/FEA/HAP/NEU/SAD) を utterance metadata に注入
- データ量: 7,442 発話、91 話者、6 感情
- 工数 2〜3h、マイルストーン #13
- PE-A embedding 抽出 + 感情ごとの centroid 計算 (L2 normalize)
- .npz スキーマ: emotion_names / emotion_centroids / global_centroid
- CLI: --input-dataset / --output-bank / --pe-model-name / --emotion-column
- 工数 2〜3h、依存 P0-T03 + P3-T01、マイルストーン #13
- 既存 dataset.jsonl に style_vector_path + emotion フィールドを注入
- style_vector を emotion_centroid から .npy として書き出し (per utterance)
- CLI: --input-dataset / --style-bank / --emotion-map JSON / --output-dir
- 工数 1h、依存 P3-T02、マイルストーン #13
- validate_style_bank.py: L2 norm / 次元 / emotion 数 / global 整合性検証
- docs/features/style-bank.md: .npz スキーマ詳細 + CREMA-D 以外の追加ガイド
- ESD/EmoV-DB/JTES ライセンスと商用可否を整理
- 工数 1h、依存 P3-T02、マイルストーン #13
- P3-T01〜T04 一覧 + 依存関係図 (T01 → T02 → T03/T04 並列)
- 「一から考えたら」 6 項目 (自動クラスタリング / 形式選択 / 話者 embedding 再利用 / dataset 選択 / HF Hub / 感情オントロジー)
- 成功基準: CREMA-D → .npz 生成 + validate PASS
- マイルストーン #13、期日 2026-04-30
- TextEncoder に style_vector_dim / style_condition_dropout 追加
- SynthesizerTrn の _add_style_condition メソッドとゼロ初期化 style_proj
- 工数 30 分〜1h、依存 P0-T03、マイルストーン #11
- Utterance / UtteranceTensors / Batch に style_vector と emotion 追加
- __getitem__ の _load_tensor 実装、BatchCollator での事前割当 + slice-copy
- 工数 30 分〜1h、依存なし (P1-T01 と並行可)、マイルストーン #11
…ments)

- VitsModel の training/validation_step で style_vector=batch.style_vectors 伝播
- commons.slice_segments() の 3D→N-D 一般化 (ret_shape を list 化)
- 工数 20 分、依存 P1-T01 + P1-T02、マイルストーン #11
- --style-vector-dim / --style-condition-dropout / --style-condition-mode
- --load_weights_from_checkpoint PATH (fine-tune 用 shape-aware loader)
- shape 不一致テンソルはスキップ + warning ログ
- 工数 30 分〜1h、依存 P1-T01、マイルストーン #11
- _style_vector_to_tensor() helper (npy/pt/inline から load)
- 推論ループで style_vector を model に渡す、GPU device 対応
- 工数 15〜30 分、依存 P1-T01、マイルストーン #11
- test_style_vector_conditioning.py: 8 ケース (backwards 互換 / ゼロ初期化 / dropout / mode validation)
- test_load_weights_from_checkpoint.py: 3 ケース (shape-aware / warning / strict=True)
- 工数 1h、依存 P1-T05、マイルストーン #11
- CLAUDE.md の「実装済み機能」に Style Vector Conditioning セクション追加
- dim=0 デフォルトでのリグレッション確認 (既存 CI green 必達)
- 工数 10 分 + CI 待ち、依存 P1-T06、マイルストーン #11
- P1-T01〜T07 一覧 + 依存関係図 (T01/T02 並行 → T03 → T04 → T05 → T06 → T07)
- 「一から考えたら」 5 項目 (注入位置 / ゼロ初期化 / CLI group / Utterance 格納 / 意図的スコープ外)
- 成功基準: dim=0 で CI green + dim=256 で 1 epoch 学習 NaN なし
- マイルストーン #11、期日 2026-04-28
- style_vector 入力 + style_vector_mask (Optional パターン) の ONNX グラフ追加
- metadata_props に style_vector_dim を書き込み (StringStringEntryProto 直接構築)
- 工数 4〜6h、依存 Phase 1 全完了、マイルストーン #12
- PiperVoice.synthesize() に style_vector パラメータ追加
- CLI --style-vector PATH、HTTP API 拡張
- 工数 2〜4h、依存 P2-T01、マイルストーン #12
- piper_plus_synthesize_with_style_vector() C API 追加
- PiperPlusSynthOptions の ABI 互換性維持 (_reserved[3] 調整 + static_assert)
- 工数 6〜8h、依存 P2-T01、マイルストーン #12
- SynthesisRequest に style_vector: Option<Vec<f32>> 追加
- piper-cli の --style-vector PATH、PyO3 バインディング対応
- 工数 4〜6h、依存 P2-T01、マイルストーン #12
- SynthesizeRequest に StyleVector プロパティ追加
- PiperPlus.Cli の --style-vector PATH、net8.0 + net9.0 対応
- 工数 4〜6h、依存 P2-T01、マイルストーン #12
- SynthesizeRequest に StyleVector []float32 追加
- cmd/piper-plus の --style-vector PATH
- 工数 4〜6h、依存 P2-T01、マイルストーン #12
ayutaz added 14 commits May 3, 2026 11:18
- options.go: SynthesisRequest に StyleVector []float32 フィールド追加
- engine.go: ModelCapabilities に HasStyleVector/StyleVectorDim 追加
  - detectCapabilities: ONNX 入力から style_vector を検出、shape[1] から dim 解決
  - newOnnxEngine: style_vector + style_vector_mask を inputNames に追加
  - style_vector_dim fallback: input shape が dynamic の場合、ONNX metadata
    (LookupCustomMetadataMap) から style_vector_dim を取得
  - Synthesize: style_vector テンソル (shape=[1,dim]) + style_vector_mask
    (shape=[1,1]) を送信、zero-fill + mask=0 fallback で後方互換
- numpy.go (新規): .npy v1.0/2.0 + dtype '<f4' + 1D/2D shape 対応の最小リーダー
- main.go: --style-vector PATH / --style-vector-inline カンマ区切りオプション、
  resolveStyleVector() ヘルパー追加
- 関連: docs/research/implementation-plan/tickets/phase-2/P2-T06.md
- src/wasm/openjtalk-web/src/index.js:
  - PiperPlus.synthesize() の options に styleVector: Float32Array を追加
  - synthesizeWithVoiceCloning() にも styleVector を追加 (voice cloning と併用可)
  - _infer() で style_vector_mask パターンの ort.Tensor を構築
    (configuredDim は config.style_vector_dim or inference.style_vector_dim)
  - session.inputNames に style_vector が含まれるときのみ feeds に追加 (後方互換)
- types/index.d.ts: SynthesizeOptions に styleVector?: Float32Array 追加
- test/js/test-piper-plus-style-vector.js (新規): Node test runner で 6 件
  - Float32Array 以外は throw / undefined は許容 / zeros+mask=0 / user vec+mask=1
  - 長さ不一致で throw / model に style_vector 入力なしでは feeds に付かない
- README.npm.md: Style-Conditioned Synthesis セクション追加
- 注: piper-wasm Rust crate は phonemizer 専用で ONNX 推論は JS 側の
  onnxruntime-web が担当するため lib.rs は変更不要
- 関連: docs/research/implementation-plan/tickets/phase-2/P2-T07.md
- docs/spec/style-vector-contract.toml (新規):
  - ONNX graph inputs 仕様 (style_vector: float32 [1, dim], style_vector_mask: int64 [1, 1])
  - Runtime behaviour (zero-fill + mask=0 fallback、長さ不一致で error、legacy model はスキップ)
  - CLI surface (--style-vector PATH / --style-vector-inline)
  - 6 ランタイム (python/cpp/rust/csharp/go/wasm-js) の reference 実装ファイルへのアンカー
- src/python/tests/test_cross_runtime_style_vector.py (新規): 24 件 PASS
  - contract 内の dtype/shape 宣言を検証 (float32/int64)
  - 6 ランタイム分の reference 実装ファイルが style_vector を参照することを parametric check
  - Python anchor: SynthesizerTrn.infer の style_vector 引数、infer_onnx.py の --style-vector、
    export_onnx.py の style_vector_dim metadata、TypeScript d.ts の styleVector?: Float32Array
- 背景: 完全な 6 ランタイム byte-for-byte 比較は各ランタイムの実機ビルドが必要なため CI に委譲。
  本テストは spec/実装の integrity を静的に守り、ランタイムが silent に同期外れするのを検出する
- 関連: docs/research/implementation-plan/tickets/phase-2/P2-T08.md
Phase 2 全 8 チケット (P2-T01〜T08) が完了。spec 整合性テスト 24 件 PASS。
実機 byte-for-byte 検証は CI (各ランタイム個別ビルド) に委譲。
…e に追加

Phase 2 以降のテスト実行で生成される pytest-cov 副産物がルートに残っていたため
集中して無視できるようにする。

- .coverage / .coverage.* (sqlite データ)
- coverage.xml (CI 用 XML レポート)
- htmlcov/ (HTML レポート)
- .pytest_cache/ (既に部分的に無視されていたが明示化)
CREMA-D (7,442 発話) を piper-train fine-tune dataset 形式に変換するツール。
Phase 3 の build_pea_style_bank.py (per-utterance 出力) と組み合わせて、
6lang base からの fine-tune に必要な dataset.jsonl + config.json を生成する。

- src/python/piper_train/tools/prepare_emotion_finetune_dataset.py (新規):
  - CREMA-D の <speaker>_<sentence>_<emotion>_<intensity>.wav を解析
  - 12 固定文 + 6 感情の dict 定義 (EMOTION_MAP, CREMA_D_SENTENCES)
  - dataset.jsonl に audio_path / text / speaker / speaker_id / language /
    style_vector_path / emotion を注入
  - config.json は 6lang base を継承し、style_vector_dim=256 等を追加
  - 欠落 .npy / 未知感情 / malformed filename は skip (エラー catch)
- src/python/tests/test_prepare_emotion_finetune_dataset.py (新規): 10 テスト PASS
  - EMOTION_MAP / CREMA_D_SENTENCES の仕様固定
  - mini corpus で manifest 生成 + 必須フィールド検証
  - skip 分岐 (missing npy / malformed / unknown emotion)
  - AudioWAV 不在 / empty で FileNotFoundError / RuntimeError
- 関連: docs/research/implementation-plan/tickets/phase-5/P5-T01-crema-d-finetune-dataset.md

実機 CREMA-D 27GB DL + 実学習は別セッション (P5-T02) で実施。
…l script

6lang ベース (epoch=74-step=504712.ckpt) から CREMA-D で fine-tune する
nohup 起動スクリプト。Phase 5 の P5-T02 に記載された stage5a / stage5b
両方のコマンドを一本化。

- scripts/run_crema_d_finetune.sh (新規):
  - stage5a (default): --style-vector-dim 256 + --freeze-dp + --base_lr 2e-5
  - stage5b: PE-A loss 有効化 + style_bank_crema_d.npz 必須
  - 環境変数で DATASET_DIR / BASE_CKPT / STYLE_BANK を上書き可能
  - WANDB_API_KEY を /data/piper/.env から自動ロード
  - nohup + &amp; で BG 起動、ログは /data/piper/training_emotion_v{1,2}.log
  - stage5b は stage5a best.ckpt + style bank 不在で exit 64/65
- shell syntax check (bash -n) PASS
- 実 GPU 学習 (2 日) は別セッションで nohup 実行
- 関連: docs/research/implementation-plan/tickets/phase-5/P5-T02-finetune-stage-5a.md
CREMA-D fine-tune モデルの 3 軸評価 (SER + PESQ/STOI + 多言語 regression)
スクリプトとテスト。モデル/依存が不在の場合はスキップ扱いにして gate を
fail させる設計 (実学習完了後に inference 部分を wire する前提)。

- tools/benchmark/evaluate_emotion_finetune.py (新規):
  - evaluate_ser: superb/hubert-large-superb-er 等で生成音声を分類
  - evaluate_mos: PESQ/STOI aggregates (pesq/pystoi オプション依存)
  - evaluate_multilingual_regression: ja/zh/es/fr/pt で base 6lang 比較
  - SUCCESS_GATES: ser_top1>=0.65 / pesq>=2.8 / stoi>=0.85 / regression<=0.2
  - write_outputs: ser_results.json + mos_results.json + multilingual.json + summary.md
  - モデル不在ケースは SkippedReason で失敗ではなく gate-fail として記録
- src/python/tests/test_evaluate_emotion_finetune.py (新規): 10 テスト PASS
  - TARGET_EMOTIONS / SUCCESS_GATES 仕様固定
  - missing model / missing reference で skip 扱い
  - check_success_gates: 全 skip で fail / 全 pass で success / 低 SER で fail
  - write_outputs: 4 ファイル生成 + JSON roundtrip + Markdown PASS 記載
- 関連: docs/research/implementation-plan/tickets/phase-5/P5-T03-evaluation-ser-mos.md
emotion fine-tune ONNX を Phase 2 mask パターンでエクスポートし、Python +
Rust の 2 runtime で audio MD5 を取るスクリプト。他 4 runtime (C++/C#/Go/
WASM) は build toolchain 前提のため、起動コマンドをサマリ Markdown に出
力して手動確認に委ねる。

- scripts/export_and_verify_emotion_runtimes.sh (新規):
  - 1. piper_train.export_onnx で ONNX 生成 (--style-vector-dim 256 含む)
  - 2. piper_train.infer_onnx で Python 側推論、python_audio.wav + .md5
  - 3. cargo run -p piper-plus-cli で Rust 側推論、rust_audio.wav + .md5
  - 4. C++/C#/Go/WASM の実行コマンドを instructions で出力 (build 必要)
  - 5. runtime_summary.md 生成 (MD5 一覧 + 未検証 runtime)
  - CKPT/style vector 不在で exit 66、cargo 無しなら Rust はスキップ
- shell syntax (bash -n) PASS
- P5-T03 / P5-T04 ステータスを更新
- 関連: docs/research/implementation-plan/tickets/phase-5/P5-T04-onnx-export-runtime-verification.md
Phase 0〜5 の成果をまとめた Phase 5 最終レポート。実験結果 (§3/4/5) は
学習完了後に埋める TODO 欄を用意し、§6 採否判定もテンプレート化した。
CLAUDE.md 追記ガイド (§8) も同梱。

- docs/research/reports/pea-style-conditioning-report.md (新規):
  - §1 概要 + 採択目的 + 成功基準ゲート
  - §2 Phase 0〜5 の実装フロー要約
  - §3 Stage 5a/5b 実験結果テーブル (TODO)
  - §4 SER / MOS / 多言語 regression 結果 (TODO)
  - §5 6 runtime MD5 一致確認 (TODO)
  - §6 採否判定チェックリスト
  - §7 学び (Option A 不可 / fork loss 固定 / C++ ABI 維持)
  - §8 CLAUDE.md 追記ガイド
  - §9 関連資料リンク
- P5-T04 / P5-T05 のステータス更新
- 関連: docs/research/implementation-plan/tickets/phase-5/P5-T05-final-report-claude-md.md

Phase 5 の全 5 チケット (P5-T01〜T05) のスクリプト・テンプレート作成完了。
実 GPU 学習 (2 日) と評価 inference loop の接続は別セッションで実施。
Phase 5 全 5 チケットのスクリプト/テンプレート作成が完了。
実 GPU 学習・inference loop 接続は別セッションで実施。
…pea] に追加

Phase 4 で利用する Meta の facebook/pe-av-small は transformers の
AutoConfig に載っていないため、facebookresearch/perception_models の
参照実装を必要とする。これを uv で管理できるよう pyproject.toml の
[project.optional-dependencies].pea に git 依存として宣言し、uv lock で
解決済み uv.lock を commit する。

- pyproject.toml:
  - optional extra `pea` を追加
  - perception-models @ git+https://github.com/facebookresearch/perception_models.git
  - コメントでライセンス (LICENSE.PE = Apache-2.0, 商用可) と重い transitive
    依存 (torchcodec / decord / opencv / tiktoken) への注意を記載
- uv.lock: 2040 行差分、transformers 4.57.6 → 4.55.4 に調整 (両方要件の
  最新版)、timm / viztracer / webdataset など大量の transitive を追加
- pea_loader.py / build_pea_style_bank.py: ImportError ヒントに
  `uv sync --extra pea` (推奨) を先頭に追記
- pea-style-conditioning-report.md §2.1: インストール手順 + LICENSE.PE を明記

インストール: `uv sync --extra pea`
実装は 7ad06c6 で既にコミット済みだが、チケットの「ステータス」欄が
未着手のまま残っていたため完了に更新。
dev 側で Flask -> FastAPI 移行 (PR #361) が入っていたため、Phase 2 P2-T02
のリベース時に style_vector ハンドリングが欠落していた。FastAPI 版
create_app() の `app_synthesize` に再統合する。

変更内容:
- `_parse_style_vector_from_request` を FastAPI Request 用に書き直し
- `app_synthesize` に `style_vector_b64` クエリパラメータ追加
- `voice.synthesize` / `voice.synthesize_stream_raw` 呼び出しに style_vector を伝播

仕様変更点:
- JSON ボディ経路は FastAPI のストリーム制約 (body は一度しか読めない) のため
  非対応。ヘッダー `X-Style-Vector-B64` または クエリ `?style_vector_b64=`
  経由のみサポート。これは Flask 版からの実質的な縮退だが、本機能はまだ
  リリース前のため後方互換性影響なし。
@ayutaz
ayutaz force-pushed the docs/peav-style-conditioning-research branch from 5f9943e to 4a6dcbf Compare May 3, 2026 02:21
@ayutaz ayutaz self-assigned this May 3, 2026
ayutaz added 8 commits May 3, 2026 11:25
- ruff --fix: 55 件の修正 (UP045/UP015/UP032/F401/I001 etc.) を auto-apply
- ruff format: 11 ファイルを再整形
- cargo fmt: piper-core/engine.rs と piper-cli/main.rs を整形
- pyproject.toml: optional dep の遅延 import を許容するため
  per-file-ignores を 4 ファイル分追加 (PLC0415, PLR0911):
  - perception/pea_loader.py (perception_models / torch)
  - tools/build_pea_style_bank.py (perception_models / torch)
  - tools/validate_style_bank.py (8 早期 return を許容)
  - tools/benchmark/*.py (transformers / pesq / pystoi)

CI ruff (3.11) / rustfmt の fail を解消する見込み。
piper-core/engine.rs の `if input.name() == "style_vector" { if let ... }`
を edition 2024 の `&& let` chain に collapse する。

CI clippy (-D warnings) の fail を解消する見込み。
CI python-tests (3 OS 全 fail) の原因:
- vits/lightning.py が top-level で `import torchaudio.functional as AF` していたため、
  test_multispeaker_transfer.py の `from piper_train.__main__ import ...` が
  torchaudio 未導入の CI 環境で ImportError になっていた。

修正:
- top-level import を削除し、PE-A loss の resample 処理直前で lazy import に変更
- AF は `_compute_pea_emotion_loss` 内でしか使われない (PE-A 有効時のみ)
- per-file-ignores に既に PLC0415 が登録済みなので追加対応不要
CI tests (3 OS, default features) の fail 原因:
- test_style_vector.rs が `ModelCapabilities` / `SynthesisRequest` /
  `SynthesisParams` を import しているが、これらは piper-core/lib.rs で
  `#[cfg(feature = \"onnx\")]` でガードされている。
- piper-core の default features は ["naist-jdic", "dict-download"]
  で onnx を含まないため、`cargo test -p piper-plus` がコンパイル失敗。

修正:
- test_style_vector.rs に `#![cfg(feature = \"onnx\")]` を追加。
- 既存の test_voice_api.rs / test_batch.rs / test_device.rs と同じパターン。
CI build/docker-build/integration-test/unit-test/lint (Go 関連) 全 fail の
共通原因:
- `cmd/piper-plus/main.go:463:3: undefined: logger`
- `buildRequest()` 内で `logger.Warn(...)` を呼んでいるが、`logger` は
  `main()` 関数のローカル変数 (158行目) のためスコープ外。

修正:
- `slog.Default().Warn(...)` で global logger を参照するように変更。
- import 済みの `log/slog` パッケージのみ使用、新規依存なし。
§1.3「設計判断 (なぜこの構成にしたか)」を新設し、評価結果なしで埋められる
8 つの設計判断とそれぞれの不採択候補・却下理由をテーブル化:

- Emotion embedding ソース (PE-AV vs wav2vec2-emotion / ESD)
- 注入箇所 (大域条件 g vs TextEncoder のみ / 全層)
- style_vector_dim デフォルト (0 = 後方互換最優先)
- ONNX Optional 入力 (mask パターン vs None / 別モデル)
- PE-A loss の算出位置 (training_step_g vs callback / 別 module)
- 6 ランタイム横断仕様 (TOML 一元化)
- C++ ABI 維持 (_reserved[5] -> _reserved[3] + フィールド純粋追加)
- Optional dep 管理 ([pea] extra で transitive 肥大化を回避)

§3 (実験結果) / §4 (評価) / §5 (cross-runtime) / §6 (採否判定) は
実 GPU 学習完了後に埋める TODO のままとする。
リポジトリ外読者にとって意味を持たない内部作業ノートを整理する。

削除:
- docs/research/ 配下 46 ファイル (peav-style-conditioning.md / implementation-plan/ /
  reports/) — 内部用のフェーズ計画・チケット・最終レポートテンプレート

簡素化:
- コード内 docstring/コメントの 'Phase N (PN-TX): ' / 'PN-TX' / 'Phase N PN-TX'
  注釈を 33 ファイルから一括除去 (Python/Rust/Go/C#/C++/JS/WASM)
- docs/features/style-bank.md, docs/spec/style-vector-contract.toml,
  scripts/*.sh の同種注釈と削除済みドキュメントへの参照リンクを除去
- CLAUDE.md / pyproject.toml の Phase X 言及を機能名ベースに変更

維持:
- docs/spec/style-vector-contract.toml (6 ランタイム I/O 契約 — 運用に必要)
- docs/features/style-bank.md (機能ガイド — ユーザー向け)
- CLAUDE.md の Style Vector Conditioning セクション (運用ガイド)
- .claude/ 配下 (skill ガイド、別文脈の Phase 表現)

ローカル退避済み:
~/Desktop/Private/piper-plus-peav-research-archive/research/ に 46 ファイル全コピー
src/cpp/tests/CMakeLists.txt L625 の `Phase 2 (P2-T03):` を削除。
他の Phase 参照は別系統 (C API 開発 M1.5, CLI Phase 3 等) のため残置。
@ayutaz

ayutaz commented May 14, 2026

Copy link
Copy Markdown
Owner Author

現状メモ (2026-05-14)

  • 実装完了・研究段階
  • 実 GPU での学習・検証が未実施のため Draft 継続
  • 学習実験完了後に評価結果をもとに merge 判断

@ayutaz

ayutaz commented May 14, 2026

Copy link
Copy Markdown
Owner Author

トリアージ (2026-05-14)

CI: 89/89 checks passing ✅
MergeState: DIRTY (コンフリクトあり)
Branch: docs/peav-style-conditioning-research

現状

感情条件付き TTS (Style Vector + PE-A Emotion Loss) の実装コードは完成しています。ただし以下のブロッカーがあります:

  1. 実 GPU 学習未実施--style-vector-dim N で学習したモデルが存在しない
  2. ブランチ名docs/peav-style-conditioning-research (研究調査段階を示す)
  3. dev へのリベースが必要

対応方針

GPU リソースと感情ラベル付きデータセットが確保できた段階でブランチを feat/emotion-tts にリネーム・リベースして研究実験を再開予定。当面は Draft のまま保留

@github-actions

Copy link
Copy Markdown
Contributor

この PR は 90 日間 activity がないため stale label を付与しました。
7 日以内に進展がなければ自動 close されます。 rebase / push / コメント
のいずれかで stale clear。

@github-actions github-actions Bot added the stale label Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant