# 音源分離の品質を数値で測る：SDR / museval とCIの品質ゲート

> 音源分離の品質を『耳』ではなく数値で評価する方法を解説。BSSEval v4のSDR/ISR/SIR/SARが何を測るのか、museval（公式評価ツール）での実装、自分の素材での比較、モデル/パラメータ変更時にCIで退行を止める品質ゲート、リファレンスが無い実素材での代替指標まで、本番品質を担保する設計を実コードで示します。

- 公開日: 2026-06-25
- 著者: 友田 陽大
- タグ: 音源分離, 品質評価, SDR, テスト, Python, MLOps, 可観測性
- URL: https://tomodahinata.com/blog/music-source-separation-quality-evaluation-sdr-museval

## 要点

- 音源分離の品質は耳だけでは守れない。大量バッチでは破綻が必ずすり抜け、モデル/パラメータ変更の良し悪しも主観では判断できない。BSSEval v4のSDR/ISR/SIR/SARで数値化する
- 4指標の意味：SDR=総合品質、SIR=他ソースの混入(消し残り)、SAR=不自然なアーティファクト、ISR=定位/空間歪み。museval(pip install museval)で算出し、フレーム中央値→曲中央値で集計する
- musevalは正解ステム(リファレンス)が必要。ツール選定や退行検知は固定の評価セット(MUSDB18 or 自前ラベル)で測る。museval.evaluate(references, estimates)はnumpy配列だけで動く
- モデル/パラメータ変更で品質が落ちていないかをCIの品質ゲートで止める。固定評価セットのSDR中央値が閾値を割ったらテスト失敗——『動く』だけでなく『前より悪くなっていない』を機械で保証する
- 実素材は正解ステムが無いのが普通。残留エネルギー比などのリファレンスフリー代替指標＋低スコア曲の人手サンプリングで本番監視する。SDRはデータ/版依存の相対値、論文間で直接比較しない

---

## この記事のゴール

[Demucs](/blog/demucs-v4-music-source-separation-production-guide) や [UVR5](/blog/uvr5-mdx-net-vocal-separation-production-guide) で音源分離を動かすと、次に必ず聞かれます——**「で、品質はどれくらい？」**。これに「耳で聞いた感じ良いです」としか答えられないと、本番でも、案件の提案でも詰みます。

本稿は、**音源分離の品質を客観的な数値で測る**方法を、実コードで示します。読み終えたときに、次ができる状態を目指します。

1. **SDR/ISR/SIR/SAR** の4指標が何を測るのかを、人に説明できる。
2. **museval** で品質を数値化し、ツール・パラメータを**同じ土俵で比較**できる。
3. モデル/パラメータ変更で品質が落ちていないかを、**CIの品質ゲート**で自動的に止められる。

> **筆者について（信頼性の開示）**：私は、動画をアップロードするだけで多言語ローカライズまで全自動化する**AI動画ローカライズ基盤を単独で設計・実装し、本番運用**しています。第1段の音源分離では、**品質を耳だけで確認していた頃、破綻したクリップが本番をすり抜けて**後段の文字起こし・吹き替えを巻き込みました。本稿の評価設計は、その反省から「品質を数値で見張る」ように組み直した記録です。

---

## 30秒のまとめ

| 観点 | 結論 |
| --- | --- |
| **なぜ数値化** | 耳だけでは大量バッチの破綻を見逃す。モデル/パラメータ変更の良し悪しも主観では判断不能 |
| **使う指標** | **BSSEval v4**：SDR（総合）／SIR（混入・消し残り）／SAR（アーティファクト）／ISR（空間歪み） |
| **ツール** | **museval**（公式評価ツール）。`pip install museval`。`museval.evaluate(references, estimates)` |
| **集計** | フレームごとに算出 → **フレーム中央値 → 曲中央値**（外れ値に強い） |
| **前提** | **正解ステム（リファレンス）が必要**。固定評価セット（MUSDB18 or 自前ラベル）で測る |
| **CI品質ゲート** | 変更時に評価セットのSDR中央値を測り、**閾値を割ったらテスト失敗** |
| **実素材（正解なし）** | リファレンスフリーの代替指標＋低スコア曲の人手サンプリング |
| **注意** | SDRはデータ/版/評価法に依存する相対値。**論文間で直接比較しない** |

指標の意味は[この章](#4つの指標が測るもの)から。

---

## なぜ「耳」だけではダメなのか

音源分離の品質確認を人間の耳に任せると、3つの場面で必ず破綻します。

- **スケール**：1日に何千本も処理するバッチで、全曲を人が聴くのは不可能。**破綻したクリップが必ずすり抜ける**。
- **退行（リグレッション）**：モデルを更新した、`shifts`を変えた、ツールを乗り換えた——**「前より良くなったか？」を主観では判断できない**。
- **比較**：Demucs と UVR5 のどちらが自分の素材で上か。**同じ物差し**が無ければ議論が水掛け論になる。

解決は、**品質を再現可能な数値にする**こと。それが BSSEval v4 と museval です。

---

## 4つの指標が測るもの

音源分離の標準指標は **BSSEval v4** の4つ。`museval` が算出します。いずれも**dB（高いほど良い）**。直感的に言い換えると——

| 指標 | 正式名 | 何を測るか（直感） |
| --- | --- | --- |
| **SDR** | Source-to-Distortion Ratio | **総合品質**。歪み全体に対する目的音の強さ。「ざっくり良し悪し」はこれ |
| **SIR** | Source-to-Interference Ratio | **他ソースの混入**。ボーカルにドラムが漏れていないか＝**消し残り**の少なさ |
| **SAR** | Source-to-Artifacts Ratio | **アーティファクト**。分離が生んだ不自然なノイズ・金属音の少なさ |
| **ISR** | Image-to-Spatial-distortion Ratio | **空間（定位）歪み**。ステレオの左右の像が崩れていないか |

**使い分けの勘所**：

- 全体の良し悪しは **SDR** を主指標に。
- 「**伴奏にボーカルが残る**」のが問題なら **SIR** を見る（混入の指標）。
- 「**声に変なノイズが乗る**」なら **SAR** を見る（アーティファクトの指標）。

つまり、**「総合はSDR、症状の切り分けはSIR/SAR」**。これで「なんとなく悪い」を「混入が多いのか、アーティファクトが多いのか」まで分解できます。

---

## museval で測る（最小実装）

`museval` は SiSEC / Music Demixing Challenge の**公式評価ツール**で、MUSDB18データセットと組み合わせて使われます。中核の `museval.evaluate` は、**numpy配列さえあれば**動きます（musdb非依存）。

```bash
pip install museval
```

```python
import museval
import numpy as np

# references / estimates の形状はいずれも (n_sources, n_samples, n_channels)
# references = 正解ステム（ground truth）, estimates = モデルの分離結果
SDR, ISR, SIR, SAR = museval.evaluate(references, estimates)

# 返り値は (n_sources, n_frames) の配列。曲のスコアは「フレーム中央値」で集計する
sdr_per_source = np.nanmedian(SDR, axis=1)   # nan に強い中央値
print("vocals SDR:", sdr_per_source[0], "dB")
```

MUSDB18 を使うなら、トラック単位の高水準APIが便利です。

```python
import musdb, museval

mus = musdb.DB(root="/path/to/musdb18", subsets="test")
results = museval.EvalStore()  # 複数トラックの結果を集計するストア

for track in mus:
    estimates = run_my_separation(track.audio)   # {"vocals": ndarray, "accompaniment": ndarray}
    scores = museval.eval_mus_track(track, estimates)  # 1曲を評価
    results.add_track(scores)

# 集計の作法: frames_agg='median'（フレーム中央値）→ tracks_agg='median'（曲中央値）
print(results)  # source別の SDR/SIR/SAR/ISR をまとめて表示
```

> 📌 **集計が中央値な理由**：曲の途中には無音や音の薄い区間があり、そこのSDRは極端な値（時に−∞）になります。**平均だと外れ値に引きずられる**ので、musevalは**フレーム中央値 → 曲中央値**で集計します。自前で測るときも必ず中央値で。

---

## ツール・パラメータを同じ土俵で比較する

[ツール選定の記事](/blog/music-source-separation-tool-selection-demucs-uvr-spleeter)で「**自分の素材で実測しろ**」と書きました。その実測がこれです。**同じ評価セットに、候補ツールを順にかけてSDRを並べる**。

```python
def benchmark(separators: dict, eval_set) -> dict[str, float]:
    """各ツールの『曲中央値SDR』を返す。同じ素材・同じ指標で公平に比較する。"""
    results: dict[str, float] = {}
    for name, separate in separators.items():
        store = museval.EvalStore()
        for track in eval_set:
            store.add_track(museval.eval_mus_track(track, separate(track.audio)))
        results[name] = store.df.query("metric == 'SDR'")["score"].median()
    return results

scores = benchmark({"demucs": demucs_sep, "uvr_mdx": uvr_sep, "spleeter": spleeter_sep}, eval_set)
# 例: {"demucs": 8.9, "uvr_mdx": 8.4, "spleeter": 6.1} ← この素材ではDemucsが最良
```

これで「Demucsが良い気がする」が「この素材ではDemucsが+0.5dB上」に変わります。**意思決定が主観から数値に乗る**——これがそのまま提案の説得力になります。

---

## CIの品質ゲート：退行を機械で止める

ここが本稿の**本丸**であり、私が案件で**最も評価されるポイント**です。モデルを更新した、パラメータを変えた、ライブラリを上げた——その時に**品質が落ちていないか**を、人ではなく**CIで自動チェック**します。

```python
# tests/test_separation_quality.py
import pytest

# 固定の評価セット（小さくてよい：5〜10曲、正解ステム付き）でSDRを測り、
# 閾値を割ったらテストを失敗させる＝「前より悪い変更」をmainに入れない
QUALITY_THRESHOLDS_DB = {"vocals": 7.5, "drums": 7.0, "bass": 6.5, "other": 4.5}

@pytest.mark.parametrize("source, floor", QUALITY_THRESHOLDS_DB.items())
def test_separation_quality_does_not_regress(source: str, floor: float):
    sdr = evaluate_fixed_set(model=load_model())   # {source: 曲中央値SDR}
    assert sdr[source] >= floor, (
        f"{source} SDR が退行: {sdr[source]:.2f} dB < 閾値 {floor} dB"
    )
```

これで実現するのは、**「動く」だけでなく「前より悪くなっていない」をコードで保証**することです。CLAUDE.mdの原則——**検証経路を実装前に用意する**——を、音源分離という主観的に見えるドメインにも適用できる。閾値はMVPとして余裕を持たせ、改善のたびに引き上げていきます（ratchet）。

> 💡 **評価セットの作り方**：MUSDB18のtestを使うのが王道。社内案件なら、**顧客の代表素材を5〜10本、人手で正解ステムを用意**して固定セットにする。小さくていい——**退行を検知できれば目的達成**です。

---

## リファレンスが無い実素材をどう見張るか

museval の前提は**正解ステム（リファレンス）**です。しかし**本番に流れてくる実素材には正解が無い**のが普通。ここで現実的な代替手段に切り替えます。

- **リファレンスフリーの代替指標**：例えば「**伴奏トラックに残るボーカル成分のエネルギー比**」を簡易推定する。消し残りが多い＝品質が低い、の近似になる。完璧ではないが**外れ値検知には十分**。
- **人手サンプリング**：全曲は無理でも、**ランダム抽出 or 低スコア疑いだけ**を人がスポットチェック。代替指標で怪しい順に並べれば、レビュー工数は激減。
- **本番監視**：処理ごとに代替指標を**構造化ログ＋メトリクス**に出し、分布の異常（急に悪化）でアラート。可観測性の組み込みは[本番APIの記事](/blog/music-source-separation-production-api-gpu-worker-queue)に。

```python
def vocal_bleed_proxy(no_vocals: np.ndarray, vocals: np.ndarray) -> float:
    """伴奏に残るボーカル成分の近似。低いほど良い（消し残りが少ない）。
    正解ステムが無い実素材の『リファレンスフリーな品質プロキシ』として使う。"""
    # 相関ベースで no_vocals に vocals がどれだけ漏れているかを推定
    return float(np.corrcoef(no_vocals.flatten(), vocals.flatten())[0, 1] ** 2)
```

**割り切り**：実素材の品質は**「正確な絶対値」より「悪化の検知」**が目的。代替指標で十分役立ちます。

---

## SDRを読むときの注意（罠）

- **データ/版依存の相対値**：SDRは評価データセット・モデル版・評価法（フレーム集計）で変わる。**論文Aの9.2dBと記事Bの数字を直接比較しない**。比較は常に**同じ評価セット・同じ設定**で。
- **無音ソースの−∞**：曲中にそのソースが鳴っていない区間はSDRが極端値に。**中央値集計**で吸収する。
- **アライメント**：推定と正解の長さ・位相がずれていると不当に低く出る。**前処理で揃える**。
- **SDRが全てではない**：聴感はSIR/SARにも左右される。**主指標SDR＋症状別SIR/SAR**で立体的に見る。

---

## よくある質問（FAQ）

**Q. SDRはいくつあれば「良い」？**
A. 絶対基準はありません（データ依存）。目安として、ボーカルでMUSDB系の評価なら**7〜9dB台が高品質**。ただし**自分の評価セットでの相対比較**が本質です。

**Q. museval は重い？**
A. それなりに計算します。CIの品質ゲートは**小さな固定セット（5〜10曲）**で十分。全MUSDBを毎回回す必要はありません。

**Q. 正解ステムをどう用意する？**
A. MUSDB18はステム付き。社内案件は**マルチトラック音源（DAWのトラック）**があれば作れます。無ければ少数を人手で。

**Q. PESQやSI-SDRは？**
A. PESQは音声品質（通話）寄り、SI-SDRはスケール不変版SDRで近年よく使われます。**museval(BSSEval v4)が音源分離の事実上の標準**なので、まずはこれで揃えるのが無難です。

**Q. 耳での確認はもう不要？**
A. **併用が正解**。数値で全件を見張り、**怪しい所だけ耳で確認**する。耳と数値は役割が違います。

---

## まとめ：品質を「主観」から「数値」へ

音源分離は一見、評価が主観的に見えます。しかし——**SDR/ISR/SIR/SARという確立した指標**があり、**museval**という公式ツールがあり、**CIの品質ゲート**で退行を止められます。「動く」で終わらせず、**「測れる・比べられる・退行しない」**まで持っていくのが本番品質です。

1. **museval で SDR を数値化**し、フレーム中央値→曲中央値で集計する。
2. **同じ評価セットでツール・パラメータを比較**し、意思決定を数値に乗せる。
3. **CIの品質ゲート**で、変更時の退行を機械的に止める。
4. **実素材は代替指標＋人手サンプリング**で本番監視する。

そして——**この「品質を数値で担保する」姿勢こそ、外注で最も信頼を生むところ**です。「たぶん良いです」と「評価セットでSDR中央値8.9dB、CIで退行ゲート済み」では、提案の重みがまるで違います。

> 私は、本稿の評価・品質ゲートを**実際に本番運用しているAI動画ローカライズ基盤**に組み込んでいます。音源分離に限らず、AI処理の品質を数値で担保する設計・テスト基盤の構築をお考えなら、[実績](/case-studies/ai-video-localization-lipsync)をご覧のうえご相談ください。**一人 × 生成AI**で、検証可能な品質まで作り込みます。

---

## 出典・関連リソース

- **評価ツール**：[sigsep/sigsep-mus-eval（museval）](https://github.com/sigsep/sigsep-mus-eval) — BSSEval v4（SDR/ISR/SIR/SAR）
- **データセット**：[MUSDB18](https://sigsep.github.io/datasets/musdb.html) — 正解ステム付きの標準評価データ
- 関連：[ツール選定](/blog/music-source-separation-tool-selection-demucs-uvr-spleeter) ／ [Demucs](/blog/demucs-v4-music-source-separation-production-guide) ／ [UVR5・MDX-Net](/blog/uvr5-mdx-net-vocal-separation-production-guide) ／ [本番API設計](/blog/music-source-separation-production-api-gpu-worker-queue)

※ SDRは評価条件に依存する相対値です。**比較は必ず同じ評価セット・同じ設定**で行い、論文間の数字を直接比較しないでください。
