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

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

- 公開日: 2026-06-25
- 著者: 友田 陽大
- タグ: 音源分離, Whisper, 文字起こし, 音声処理, Python, ASR, MLOps
- URL: https://tomodahinata.com/blog/source-separation-asr-preprocessing-whisper-accuracy

## 要点

- Whisperは『音声』で学習されている。BGM・歓声・雑音は音素エネルギーをマスクしてWERを悪化させる。音源分離でボーカル(声)だけ抜いてから渡すと、音楽下・ノイズ下の精度が上がる
- 前処理パイプラインは『分離(--two-stems=vocals)→16kHzモノ正規化→VADで非音声除去→Whisper→後処理』。Whisperは16kHz想定なので正規化を必ず1段挟む
- 万能ではない。クリーンな音声には分離アーティファクトがむしろ悪さをする場合がある。歌唱・重唱は語と音程が絡み苦手。『自分の素材でWERをA/B実測』(jiwer)してから採否を決めるのが鉄則
- コストは分離のGPU時間が乗る。常時適用ではなく『音楽/低SNRを検出したクリップだけ分離』のゲートで単価を刻む。VADで無音を捨てればWhisper側のコストも下がる
- 本番ではsha256冪等キャッシュで再分離ゼロ、SNR/WER/適用有無を構造化ログに残す、過剰VADが語頭を削る事故に注意。前処理の良し悪しが後段(翻訳・要約)の品質を決める

---

## この記事のゴール

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

本稿は、**音源分離（[Demucs](/blog/demucs-v4-music-source-separation-production-guide) / [UVR5・MDX-Net](/blog/uvr5-mdx-net-vocal-separation-production-guide)）を前処理に使って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は「自分の得意分野」に集中できます。

---

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

```text
  入力音声（動画/配信/録音）
        │
        ▼
 ① 音源分離   ── 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コマンド。

```bash
# 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 など）は[選定の記事](/blog/music-source-separation-tool-selection-demucs-uvr-spleeter)に。**声の明瞭さ最優先**なら、ボーカル特化のUVR5(MDX-Net) Vocal系も有力です。

### ② 16kHzモノラルに正規化

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

```bash
# 分離後の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` が定番です。

```python
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の記事](/blog/openai-whisper-production-guide-selfhost-vs-api)に。

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

---

## 効果をWERで実測する（感覚で決めない）

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

```python
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記事](/blog/music-source-separation-quality-evaluation-sdr-museval)）と同じ哲学です。

---

## いつ効いて、いつ逆効果か（正直な話）

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

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

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

---

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

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

- **音楽/SNR検出ゲート**：簡易な音楽検出（または平均SNR推定）で、**BGMが有意な区間だけ**分離に回す。クリーンなら素通し。
- **VADで無音カット**：発話区間だけWhisperに渡せば、**ASR側のコストも下がる**（無音を起こさない）。
- **冪等キャッシュ**：`sha256(音源 + パラメータ)`で結果をキャッシュ。同じ素材の再分離をゼロに。

```python
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にする記事](/blog/music-source-separation-production-api-gpu-worker-queue)**に。

---

## 本番で詰まる落とし穴

- **サンプルレート不一致**：分離出力は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実測で並べて選ぶのが確実（[選定記事](/blog/music-source-separation-tool-selection-demucs-uvr-spleeter)）。

**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パイプラインの構築をお考えなら、[実績](/case-studies/ai-video-localization-lipsync)をご覧のうえご相談ください。**一人 × 生成AI**で、速く・安く・安全に作ります。

---

## 出典・関連リソース

- [Whisper 本番運用ガイド（self-host vs API）](/blog/openai-whisper-production-guide-selfhost-vs-api)
- [Demucs 完全ガイド](/blog/demucs-v4-music-source-separation-production-guide) ／ [UVR5・MDX-Net 完全ガイド](/blog/uvr5-mdx-net-vocal-separation-production-guide) ／ [ツール選定](/blog/music-source-separation-tool-selection-demucs-uvr-spleeter)
- [音源分離を本番APIにする](/blog/music-source-separation-production-api-gpu-worker-queue) ／ [品質をmusevalで測る](/blog/music-source-separation-quality-evaluation-sdr-museval)
- ライブラリ：[silero-vad](https://github.com/snakers4/silero-vad) ／ [jiwer（WER計測）](https://github.com/jitsi/jiwer)

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