Chuyển đến nội dung chính
友田 陽大
Audio source separation & preprocessing
音源分離
Whisper
文字起こし
音声処理
Python
ASR
MLOps

音源分離でWhisperの文字起こし精度を上げる:音声前処理パイプライン設計

BGMや雑音が乗った音声の文字起こし精度を、音源分離(Demucs / UVR5)の前処理で底上げする方法を解説。ボーカル抽出→16kHz正規化→VAD→Whisperのパイプラインを実コードで示し、いつ効いていつ逆効果か、jiwerでのWER実測、冪等性・コスト・可観測性まで、本番運用の設計を網羅します。

Published
Reading time
12 min read
Author
友田 陽大
Chia sẻ

この記事のゴール

「BGMが大きくて文字起こしが崩れる」「ライブ音源・街頭インタビューの認識精度が出ない」——Whisper を本番で使うと必ずぶつかる壁です。多くの人はモデルを大きく(large-v3へ)したり、プロンプトを工夫したりしますが、もっと効く打ち手は入力側にあります——音源分離で「声」だけを抜いてからASRに渡すことです。

本稿は、音源分離(Demucs / UVR5・MDX-Net)を前処理に使ってWhisperの精度を上げる設計を、実コードで示します。読み終えたときに、次ができる状態を目指します。

  1. なぜBGM・雑音が文字起こしを壊すのかを理解し、前処理パイプラインを設計できる。
  2. 「分離 → 正規化 → VAD → Whisper」を実装し、効果をWERで実測できる。
  3. いつ効いて・いつ逆効果かを見極め、コストに見合う形で本番適用できる。

筆者について(信頼性の開示):私は、動画をアップロードするだけで「音声分離 → 文字起こし → 翻訳 → 多言語吹き替え → 口元同期」まで全自動化するAI動画ローカライズ基盤を単独で設計・実装し、本番運用しています。第1段の音源分離と第2段の文字起こしは直結しており、前処理の良し悪しが後段すべて(翻訳・要約・字幕)の品質を決めます。本稿は、その繋ぎ目で実際に効いた前処理の記録です。


30秒のまとめ

観点結論
なぜ効くかWhisperはBGM・歓声・雑音が苦手。声だけ抜くと音素が際立ち、音楽/ノイズ下のWERが下がる
パイプライン分離(--two-stems=vocals)→ 16kHzモノ正規化 → VAD(非音声除去)→ Whisper → 後処理
使う分離ツール声/伴奏の2分離で十分。Demucs --two-stems=vocals か UVR5(MDX-Net)のVocal系
いつ効くBGM・音楽・雑踏・低SNRの音声(動画・ライブ・街頭・配信)
いつ逆効果元がクリーンな音声(分離アーティファクトが悪さをする)/歌唱・重唱
採否の決め方自分の素材でWERをA/B実測(jiwer)。感覚で決めない
コスト分離のGPU時間が乗る。音楽検出ゲートで必要な時だけ適用、VADで無音を捨てる
本番設計sha256冪等キャッシュ・構造化ログ(SNR/WER/適用有無)・過剰VAD対策

パイプラインの全体像はこの図です。


なぜBGM・雑音が文字起こしを壊すのか

Whisperを含む音声認識(ASR)は、「人の声(音声)」を主対象に学習されています。そこへBGMや歓声、機械音が混ざると何が起きるか。

  • 音素のマスキング:音楽のエネルギーが、子音・母音の微細な特徴を覆い隠す。特に子音(s/t/k など)は弱く、BGMに埋もれやすい。
  • 誤った言語モデル推論:歌詞・コーラスを「話し言葉」と誤認し、存在しない単語を幻覚する(ハルシネーション)。
  • タイムスタンプのズレ:音楽のリズムを発話境界と取り違え、字幕の同期が崩れる。

結果として、WER(Word Error Rate、単語誤り率。低いほど良い)が悪化します。モデルを大きくしても、入力が濁っていれば限界がある。ならば入力をきれいにする——それが音源分離による前処理です。声と伴奏を分け、声のトラックだけをASRに渡すことで、Whisperは「自分の得意分野」に集中できます。


前処理パイプラインの全体像

  入力音声(動画/配信/録音)
        │
        ▼
 ① 音源分離   ── Demucs --two-stems=vocals  →  vocals.wav(声だけ)
        │                                       no_vocals.wav(BGM・効果音)※吹替で再利用
        ▼
 ② 正規化     ── ffmpeg で 16kHz / モノラル / wav に統一(Whisperの想定形)
        │
        ▼
 ③ VAD        ── 発話区間だけ残す(無音・非音声を捨てる=精度↑・コスト↓)
        │
        ▼
 ④ Whisper    ── 文字起こし(self-host or API)
        │
        ▼
 ⑤ 後処理     ── タイムスタンプ整形・用語辞書補正・句読点

各段の**狙い(SRP)**を1行で。

  • ①分離:声を伴奏・雑音から切り離す。WER改善の本体。
  • ②正規化:Whisperは16kHzモノラルを想定。フォーマットを揃えて再現性を上げる。
  • ③VAD:非音声を捨て、幻覚を減らし、Whisperの処理コストも下げる。
  • ④ASR:きれいな声だけを起こす。
  • ⑤後処理:用途(字幕・議事録・翻訳)に整える。

実装:分離 → 正規化 → VAD → Whisper

① 声を抜く(音源分離)

声/伴奏の2分離で十分です。Demucsなら--two-stems=vocalsの1コマンド。

# vocals.wav(声)と no_vocals.wav(BGM・効果音)に分離
demucs --two-stems=vocals -o sep input.wav
# → sep/htdemucs/input/vocals.wav をASRに回す
#   no_vocals.wav は吹き替え時のBGM再利用に取っておく(ローカライズ用途)

ツール選定(Demucs vs UVR5 など)は選定の記事に。声の明瞭さ最優先なら、ボーカル特化のUVR5(MDX-Net) Vocal系も有力です。

② 16kHzモノラルに正規化

Whisperは内部で16kHzを想定します。ここを揃えないと再現性が落ち、稀に音ズレします。

# 分離後のvocalsを 16kHz / モノラル / PCM wav に統一
ffmpeg -y -i sep/htdemucs/input/vocals.wav -ar 16000 -ac 1 -c:a pcm_s16le vocals_16k.wav

③ VADで非音声を捨てる

無音・笑い声・拍手などの非音声区間を落とすと、幻覚が減り、Whisperのコストも下がります。silero-vad が定番です。

import torch

# silero-vad: 発話区間(タイムスタンプ)を返す軽量VAD
model, utils = torch.hub.load("snakers4/silero-vad", "silero_vad", trust_repo=True)
get_speech_timestamps, _, read_audio, *_ = utils

wav = read_audio("vocals_16k.wav", sampling_rate=16000)
speech = get_speech_timestamps(wav, model, sampling_rate=16000)
# speech = [{"start": サンプル, "end": サンプル}, ...]:発話だけ抜き出してASRへ

⚠️ 過剰VADの罠:閾値を上げすぎると語頭・語尾を削り、かえってWERが悪化します。VADは「明らかな無音」を落とす程度に留め、**前後に余白(padding)**を付けるのが安全。後述のWER実測で、VADあり/なしも比較します。

④ Whisperへ

きれいになった声を文字起こしします。self-host vs API の選定・コストはWhisperの記事に。

whisper vocals_16k.wav --language ja --model large-v3 --output_format srt

効果をWERで実測する(感覚で決めない)

ここが本稿で最も重要です。「分離したら良くなった気がする」では本番に載せられません。自分の素材で、分離あり/なしのWERを数値比較します。正解テキスト(リファレンス)を用意し、jiwerで測ります。

from jiwer import wer

# 同じ音声を「分離なし」「分離あり」で起こし、正解と比較
reference = "本日はお集まりいただきありがとうございます"          # 正解
hyp_raw      = transcribe("input_16k.wav")                       # 分離なし
hyp_separated = transcribe("vocals_16k.wav")                      # 分離あり

print("WER (raw):      ", wer(reference, hyp_raw))
print("WER (separated):", wer(reference, hyp_separated))
# 例: raw=0.32 → separated=0.11 のように下がれば、その素材では分離が効いている

評価の作法

  • 代表サンプルを10〜30本用意する(ジャンル・SNR・話者がばらつくように)。
  • WERの中央値で比較する(1本の外れ値に引きずられない)。
  • 分離あり/なし、VADあり/なしを組み合わせて表にする。「いつ効くか」が見える。

この「候補を同じ素材・同じ指標で並べて選ぶ」姿勢は、音源分離ツールの選定(museval記事)と同じ哲学です。


いつ効いて、いつ逆効果か(正直な話)

音源分離の前処理は万能ではありません。誠実に線を引きます。

入力の素性分離前処理の効果
BGM・音楽が大きい(動画・配信・CM)◎ 大きく効く。WERが目に見えて下がる
雑踏・環境音(街頭・店内・車内)○ 効く。声が際立つ
クリーンな会議・電話(BGMなし)△〜× 逆効果も。分離アーティファクトが微妙に悪さをする場合がある
歌唱・重唱(カラオケの歌詞起こし)× 苦手。語と音程・重なりが絡み、ASR自体が不得手

結論「音楽・雑音が混じる素材」には積極的に、「元がクリーンな音声」には不要(むしろ測って判断)。だからこそ、前項のWER実測で素材ごとに採否を決めるのが正解です。


コスト最適化:必要な時だけ分離する

分離はGPU時間がそのままコストです。全件に常時かけるのは無駄。ゲートを設けます。

  • 音楽/SNR検出ゲート:簡易な音楽検出(または平均SNR推定)で、BGMが有意な区間だけ分離に回す。クリーンなら素通し。
  • VADで無音カット:発話区間だけWhisperに渡せば、ASR側のコストも下がる(無音を起こさない)。
  • 冪等キャッシュsha256(音源 + パラメータ)で結果をキャッシュ。同じ素材の再分離をゼロに。
def needs_separation(audio_path: str, *, snr_threshold_db: float = 15.0) -> bool:
    """BGM/雑音が有意なクリップだけTrue。クリーンな音声は分離をスキップしてコストを節約。"""
    snr = estimate_snr_db(audio_path)        # 簡易SNR推定(声と背景のエネルギー比)
    return snr < snr_threshold_db            # SNRが低い=背景が大きい=分離が効く

私の基盤では、この「音楽がある所だけ分離 + VADで無音スキップ」で、前処理のGPUコストを必要最小限に抑えています。**本番設計(冪等性・回復性・可観測性)の詳細は音源分離を本番APIにする記事**に。


本番で詰まる落とし穴

  • サンプルレート不一致:分離出力は44.1kHz、Whisperは16kHz想定。正規化を必ず挟む(②)。これを忘れると稀に音ズレ・精度低下。
  • 過剰VADで語頭欠け:VADを攻めすぎると単語の頭を削る。控えめ+paddingで。WERで検証。
  • アーティファクトの混入:分離が強すぎると、声に金属的なノイズが乗りASRが誤る。クリーン素材には分離しない判断を。
  • 二重処理:同じ音源を分離→起こしを何度も回すと、GPU×API代が二重に乗る。冪等キャッシュで防ぐ。
  • 可観測性の欠如:どのクリップで分離を適用し、SNR/WERがどうだったかを構造化ログに残す。後から「なぜこの回だけ精度が悪い」を追える状態に。音声内容(PII)はログに出さない

よくある質問(FAQ)

Q. Whisperをlarge-v3にすれば分離は要らない? A. モデル拡大と前処理は別の効き方です。BGMが大きい素材では、largeにしても分離前処理の上積みが出ることが多い。両方を実測して費用対効果を見てください。

Q. 分離ツールはDemucsとUVR5どちら? A. 声の明瞭さ最優先ならUVR5(MDX-Net)のVocal系、手軽さ・総合力ならDemucs --two-stems=vocals。WER実測で並べて選ぶのが確実(選定記事)。

Q. リアルタイム字幕にも使える? A. 分離は基本オフライン処理でレイテンシが乗ります。準リアルタイムまでが現実的。厳密なライブは、軽量分離+ストリーミングASRの別設計を検討。

Q. 歌の歌詞を起こしたい。 A. 苦手領域です。歌唱はASR自体が不得手で、分離しても限界がある。専用の歌詞認識手法を検討してください。

Q. WERのリファレンス(正解)が無い。 A. 少数でいいので人手で正解を作るのが結局最速です。10本でも、分離あり/なしの傾向は十分見えます。


まとめ:精度は「モデル」より「入力」で決まることがある

文字起こしの精度を上げる、と聞くと多くの人はモデルやプロンプトに向かいます。しかし入力が濁っていれば、どんな高性能モデルも本領を出せません。音源分離で声をきれいにする前処理は、BGM・雑音が混じる素材で最も費用対効果の高い一手です。

実装の道筋はシンプルです。

  1. 分離(声を抜く)→ 16kHz正規化 → VAD → Whisper のパイプラインを組む。
  2. 自分の素材でWERをA/B実測し、「いつ効くか」を見極める。
  3. 音楽検出ゲート+冪等キャッシュで、必要な時だけ・一度だけ分離する。

そして——この「繋ぎ目の設計」こそ、外注で差がつくところです。WhisperやDemucsを単体で動かすのは誰でもできますが、前処理と後段を一本のパイプラインとして繋ぎ、WERで検証し、コストを刻むのは、実運用の経験がそのまま品質になります。

私は、本稿の前処理を実際に本番運用しているAI動画ローカライズ基盤の「分離→文字起こし」の繋ぎ目で実装しました。文字起こし・翻訳・字幕・吹き替えを含む音声/動画AIパイプラインの構築をお考えなら、実績をご覧のうえご相談ください。一人 × 生成AIで、速く・安く・安全に作ります。


出典・関連リソース

※ 効果は素材に強く依存します。本番適用前に必ず自分のデータでWERを実測してください。

友田

友田 陽大

Người phát triển sản phẩm đoạt Giải thưởng Bộ trưởng (METI). Với TypeScript + Python + AWS, tôi một mình triển khai trọn gói SaaS, chuyển đổi số công nghiệp và AI tạo sinh (RAG) sẵn sàng cho production — từ phân tích yêu cầu đến hạ tầng và vận hành.

I can take on the implementation from this article as an engagement

GPU inference pipelines for source separation, lip-sync, and speech synthesis — from design to production

I single-handedly built a fully automated GPU pipeline that takes an uploaded video all the way through source separation → transcription → translation → multilingual dubbing → lip-sync, running on spot GPUs (Tesla T4). Resumable per-segment processing for long jobs, ~40% less GPU work via speech-segment detection, and graceful degradation when lip-sync fails — I design and implement for both cost and completion.

Nhận cả dự án trọn gói lẫn vai trò cố vấn kỹ thuật. Hãy bắt đầu bằng buổi tư vấn miễn phí 30 phút.

最短ルート:カレンダーから直接予約

相談内容が固まっている方は、フォーム送信よりその場で日程を確定する方がスムーズです。下記から空き時間をお選びください。

  • 30分のオンライン無料相談
  • Google Meet / Zoom / Microsoft Teams
  • NDA 商談前締結可・無理な営業はいたしません
無料相談の空き枠を予約する

Cũng đáng đọc