#音声合成#TTS#信号処理#データセット

生成するたび「録音場所」が変わるTTS — 素材の音響を揃えないとスタイルが飛ぶ


音声モデルの学習コーパスを、別のTTSで生成している。同じ話者設定、同じモデル、同じサーバ。それでもクリップごとに音の質感が違う

具体的には、感情スタイルを切り替えて合成したときに気づいた。喜びスタイルから悲しみスタイルに切り替えると、声色だけでなく音質そのものが変わる。片方は近くで録ったように聞こえ、もう片方はやや遠い。同じ話者が別の部屋で喋っているような違和感がある。

原因は学習素材だった。コーパスのクリップが、生成条件ごとに違う周波数特性を持っていた。

なぜ質感が変わるのか

このコーパスは、感情ごとに違う参照音声(アンカー)を使って生成している(品質ゲートを厳しくするほど、棒読みが生き残る)。

joy の本文     → joy用アンカーを参照に生成
sadness の本文 → sadness用アンカーを参照に生成
anger の本文   → anger用アンカーを参照に生成

参照音声が違えば、TTSはその参照の声色だけでなく音響特性も真似る。アンカー自体が別々に生成されたものなので、それぞれ微妙に違うスペクトル形状を持っている。結果、感情グループごとに音の質感がずれる。

さらに極端演技(絶叫、爆笑など)の素材は、そもそも音圧のレンジが違う。並べて学習させると、モデルは「このスタイルのときは音が遠い」まで一緒に覚えてしまう。

人間の録音なら同じマイク・同じ部屋で録るので起きない問題が、生成音声では起きる。TTSは録音環境という概念を持たないので、条件が変わればチャンネル特性も変わる。

LTASを揃える

対処は、学習前に全クリップを共通の周波数特性へ寄せることだった。

LTAS(Long-Term Average Spectrum、長時間平均スペクトル)は、音声全体を平均した周波数分布のこと。話者性や部屋の特性を反映する。これを基準に合わせる。

手順はこうなる。

  1. コーパス全体、あるいは基準となるクリップ群からLTASを求めて基準スペクトルにする
  2. 各クリップのLTASを求め、基準との差分を計算する
  3. その差分を打ち消すEQを各クリップに適用する
  4. 最後にRMSを揃える
def match_ltas(wav, ref_ltas, max_gain_db=10.0):
    """クリップのLTASを基準へ寄せる(±max_gain_db でクリップ)"""
    spec = stft(wav)
    ltas = np.mean(np.abs(spec), axis=1)              # 時間方向に平均

    gain_db = 20 * np.log10((ref_ltas + eps) / (ltas + eps))
    gain_db = np.clip(gain_db, -max_gain_db, max_gain_db)   # 極端な補正を防ぐ
    gain    = 10 ** (gain_db / 20.0)

    spec = spec * gain[:, None]
    return istft(spec)

±10dBでクリップする理由

補正量に上限を置いた。無制限にすると、元のクリップに存在しない帯域を無理に持ち上げることになる。そこには信号がなくノイズしかないので、ノイズだけが増幅される。

特に高域は、生成音声だと8kHz以上がほとんど無いクリップがある。そこを基準に合わせようとすると、サーというノイズが乗る。±10dBに制限すれば、寄せきれなくても破綻はしない。

ゼロ位相で処理する

EQをかけるとき、位相を動かさないようにした。通常のフィルタは群遅延を持つので、帯域ごとに時間がずれる。人間の耳には分かりにくいが、学習素材としては望ましくない。

STFTの振幅だけを操作して位相をそのまま残すか、フィルタを前後両方向にかけて位相の回転を打ち消す(filtfilt相当)。今回は前者を採った。

最後にRMSを揃える

周波数特性を揃えたら、音量も揃える。

def normalize_rms(wav, target_dbfs=-20.0):
    rms = np.sqrt(np.mean(wav ** 2))
    gain = 10 ** (target_dbfs / 20.0) / (rms + 1e-9)
    return np.clip(wav * gain, -1.0, 1.0)

−20dBFSに揃えた。ピークではなくRMSで揃えるのがポイントで、ピーク正規化だと1発の大きな音(絶叫の頭など)に引っ張られて、全体の音量がばらつく。

効果

感情スタイルを切り替えたときの音質の飛びが消えた。これが第一の目的だった。

そして予想外の副作用があった。極端演技の素材が学習可能になった。

正規化前は、絶叫のクリップを学習させると全体が荒れる傾向があった。音圧が飛び抜けていて、スペクトルも他と違うので、モデルがそれを「別の何か」として扱いにくかったのだと思う。

正規化後は、絶叫の時間構造(ピッチが急激に上下する掃引のような動き)が学習に乗るようになった。音圧とスペクトルの違いが取り除かれて、残った「動き」の情報がモデルに届いた、という理解をしている。

つまり正規化は「揃えて情報を捨てる」処理に見えて、捨てるべき情報(チャンネル特性)を捨てることで、残すべき情報(韻律の動き)を際立たせる働きをしていた。

どこまで揃えるか

やりすぎると別の問題が出る。

話者性まで消える危険がある。 LTASには話者の声道特性も含まれるので、強く揃えると声の個性が薄まる。今回は同一話者のコーパス内で揃えているので問題にならなかったが、複数話者を混ぜる場合は注意が要る。

感情の音響的特徴も一部は周波数に出る。 怒りは高域が強く、悲しみは弱い、といった傾向がある。完全に揃えるとこれが消える。±10dBの制限は、この意味でも効いていた。強い補正がかからないので、感情由来の差はある程度残る。

基準をどう決めるかも判断が要る。今回はコーパス全体の平均を使ったが、「一番良い状態のクリップ群」を基準にする選び方もある。平均だと、悪い素材が多いときに基準自体が引きずられる。

実装上の注意

処理は学習の直前に一括でやる。 生成時に1本ずつ正規化すると、基準スペクトルが決まる前に処理することになる。全部揃ってから、まとめて通す。

元のクリップは残す。 正規化はやり直しが効くようにしておく。パラメータ(上限dB、目標RMS)を変えて再学習したくなることがある。

正規化後の音を聴く。 数値上は揃っていても、聴くとノイズが乗っていたり不自然だったりすることがある。特に補正量が上限に張り付いたクリップは要確認だ。

# 補正量が上限に達したクリップを記録しておく
clipped = np.sum(np.abs(gain_db_raw) >= max_gain_db) / len(gain_db_raw)
if clipped > 0.3:
    logger.warning(f"{clip_id}: 補正量の30%以上が上限に張り付いた(元素材が基準から遠い)")

これが多いクリップは、そもそも他と違いすぎる素材なので、揃えるより除外したほうがいいこともある。

まとめ

  • 生成音声は「録音環境」を持たないので、条件が変わればチャンネル特性も変わる。人間の録音では起きない問題
  • 感情ごとに参照を変えると、感情ごとに音質が変わる。切り替え時の音質の飛びとして現れる
  • LTASマッチング+RMS正規化で揃える。補正は±10dB程度に制限し、位相は動かさない
  • 揃えることで、残すべき情報が際立つ。極端演技の時間構造が学習に乗るようになった
  • 揃えすぎない。話者性や感情由来の周波数差まで消える。上限を置くことが品質を守る

シリーズ: 拡散TTSから実用ボイスを量産する

キャプション1行から声を設計し、学習コーパスを製造して、役割別の実用ボイスを量産するまでの記録です。この記事は第2部 製造にあたります。

← 前: 学習後に話速は変えられない → 次: クリップ1本の粗さが、スタイル全体を嗄れさせる

シリーズ全18本
  1. 音質で選んだTTSが、会話には遅すぎた
  2. 声をガチャで引く
  3. 「ナレーターっぽい声」を24候補から機械に選ばせる
  4. 品質ゲートを厳しくするほど、棒読みが生き残る
  5. 学習後に話速は変えられない 6. 生成するたび「録音場所」が変わるTTS ← いまここ
  6. クリップ1本の粗さが、スタイル全体を嗄れさせる
  7. AIが「こんにちわー」と伸ばす癖は、どこで身についたのか
  8. 「少々」が「しょも」になる — 許可文字リストが日本語を削っていた
  9. ハルシネーション対策のコードが、ハルシネーションの時だけ動かなかった
  10. 品質ゲートが許した「3文字」が、モデルの口癖になった
  11. 治せる欠陥で候補を落としていた
  12. 文字起こしでは見つからない欠陥がある
  13. 70分かけた学習素材が、ネットワークの一瞬の瞬きで消えた
  14. “ja” を “JP” と書いて喃語モデルができるまで
  15. 登録経路が4つ、管理画面が0
  16. デプロイのたびに互いの成果を消していた
  17. 測れていないものを閾値で追い込むと、必ず失敗する

知見の元になったノートは 拡散TTSから実用ボイスを量産する製造パイプライン にまとめてあります。

← 記事一覧へ