この記事のゴール
UVR5(Ultimate Vocal Remover GUI) は、1曲の音声を ボーカル(声)と伴奏(インスト)に分離するオープンソースの定番ツールです。公式README はその役割をこう書いています——「This application uses state-of-the-art source separation models to remove vocals from audio files.(最先端の音源分離モデルで音声からボーカルを除去する)」。
そして MDX-Net は、UVR5 が搭載する複数のAIアーキテクチャの中でも、ボーカル/伴奏分離で最もよく使われる中核モデルです。
本稿は、その公式情報(UVR5 GitHub / MDX-Net 論文 arXiv:2111.12203 / python-audio-separator)に厳密に基づきつつ、公式ドキュメントには書かれていない「どの場面で・どう使い・どこで詰まるか」を、実際に動くコードで埋めるものです。読み終えたときに、次の3つができる状態を目指します。
- UVR5 と MDX-Net が何をするツールで、なぜ精度が高いのかを、人に説明できる。
- GUI(試す) と python-audio-separator(自動化する) のどちらを選ぶべきか判断し、今日中に手を動かせる。
- デモではなく本番——長尺でのOOM・GPUが効かないCPUフォールバック・モデルの初回ダウンロード——に耐える回復性のある実装を組める。
筆者について(信頼性の開示):私は、動画をアップロードするだけで「音声分離 → 文字起こし → 翻訳 → 多言語吹き替え → 口元同期」まで全自動化する AI動画ローカライズ基盤を単独で設計・実装し、本番運用しています。その第1段が、まさにこの音源分離です。声と背景音楽(BGM)を分けてから文字起こし・翻訳に回すことで認識精度が上がり、伴奏を保持したまま吹き替え音声を被せられる——この前処理の良し悪しが、後段すべての品質を決めます。本稿の「落とし穴」と「回復性設計」は、デモ用の知識ではなく、その実運用で踏み抜いた地雷の記録です。後段の文字起こしはWhisper の記事、口元同期はLatentSync の記事、パイプライン全体はローカライズ基盤の記事にまとめています。
30秒のまとめ(結論を先に)
| 観点 | 結論 |
|---|---|
| 何のツールか | 1つの音声をボーカルと伴奏(その他ステム)に分離するOSS。GUI版が UVR5 v5.6(MITライセンス) |
| MDX-Netとは | UVR5搭載の中核AIアーキテクチャ。周波数領域+時間領域の二段構成でボーカル/伴奏分離に強い |
| 学術的根拠 | KUIELab-MDX-Net(arXiv:2111.12203)。ISMIR 2021 Music Demixing Challenge で Leaderboard A 2位・B 3位 |
| 試すだけ | UVR5 GUI:Win/Mac/Linux対応。ドラッグ&ドロップで分離。非エンジニアでも使える |
| 自動化する | python-audio-separator:pip install "audio-separator[gpu]"。Separator クラス3行でCLI/サーバー組み込み |
| 必要GPU | GTX 1060 6GB が最低、8GB以上のVRAM推奨(公式README)。Apple Silicon は MPS 対応 |
| 出力 | 既定で2ステム(Vocals / Instrumental)、サンプルレート 44.1kHz |
| モデルの選び方 | 伴奏が欲しい→ Inst系(UVR-MDX-NET-Inst_HQ_3)/声が欲しい→ Vocal系(Kim_Vocal_2)/ハモリ除去→ UVR_MDXNET_KARA_2 |
| 品質の主ノブ | segment_size(大=速い・VRAM増)/overlap(境界アーティファクト低減)/enable_denoise(残響ノイズ抑制・約2倍コスト) |
| 向く用途 | 動画ローカライズ前処理・カラオケ音源/アカペラ作成・ポッドキャストのBGM除去・音声データセットの前処理 |
| 向かない用途 | リアルタイム/ゼロレイテンシ処理、著作権処理を伴うステムの無断再配布 |
「まずドラッグ&ドロップで品質を見たい」なら GUI 章へ、「サーバーに組み込みたい」なら コード章へ飛んでください。
UVR5 / MDX-Net は何をするのか
入力は 1つの音声(または動画の音声トラック)、出力は 分離された複数のステムです。最も基本的な使い方では、UVR5 は音声を 「ボーカル」と「インストゥルメンタル(伴奏)」の2つに分けます。
これが効くのは、たとえば次のような場面です。
- 動画ローカライズ(吹き替え)の前処理:元動画から声だけを抜いて文字起こし・翻訳に回す。背景音楽が混ざったまま ASR にかけると認識精度が落ちるが、声を分離すれば精度が上がる。さらに伴奏トラックは保持しておき、吹き替え音声の下に再ミックスすれば、BGM ごと差し替わる違和感を防げる。
- カラオケ音源 / アカペラの作成:曲から伴奏だけを取り出してカラオケに、ボーカルだけを取り出してアカペラ・リミックス素材にする。
- ポッドキャスト / 会議音声のクリーニング:収録に紛れ込んだ BGM やノイズを除去して、声を聞き取りやすくする。
- 音声データセットの前処理:TTS / ASR 学習用に、音楽や環境音を除いたクリーンな音声を量産する。
逆に、ゼロレイテンシのリアルタイム処理(ライブ配信の即時分離など)には向きません。MDX-Net は1ファイルをまとめて処理するバッチ志向で、品質と引き換えにそれなりの計算時間を要します。
⚖️ 著作権の注意(重要):音源分離の技術それ自体は中立ですが、処理対象の音源にはほぼ常に著作権があります。市販曲を分離して得たステムを無断で再配布・公開する行為は権利侵害になり得ます。UVR5 のコードは MIT ライセンスでも、それは**「あなたが処理する音声の権利」とは別問題**です。自作曲・許諾済み素材・私的利用の範囲で使ってください。
仕組み:なぜ MDX-Net は分離精度が高いのか(論文準拠でやさしく)
ここは MDX-Net の核心を、正確さを保ったまま噛み砕く章です。実装だけ知りたい人は次章へ飛んで構いません。ただし「なぜ落とし穴がああいう形で出るのか」はここを理解していると腑に落ちます。
📌 正確性のための注記:UVR5 の README には「MDX-Net とは何か」を説明する文章はありません(搭載アーキテクチャはクレジット欄で
Kuielab & Woosung Choiに帰属表示されているだけ)。アーキテクチャの定義は、以下の学術論文を一次情報として参照します。
出発点:音源分離は「混ざった波形を解く」問題
1曲の波形は、ボーカル・ドラム・ベース・その他が足し合わさった1本の信号です。音源分離(source separation / music demixing)は、この足し算を元の成分に解き戻すタスク。アプローチは大きく2系統あります。
- 周波数領域(time-frequency):音声を STFT でスペクトログラム(時間×周波数の画像)に変換し、画像処理的な U-Net で各成分のマスクを推定する。
- 時間領域(time-domain):波形そのものを畳み込みネットワークで直接処理する(Demucs が代表)。
それぞれ得意・不得意があり、どちらか一方では限界があります。
MDX-Net の答え:二段構成(two-stream)でブレンドする
MDX-Net の原典は、韓国 KUIELab(高麗大学)の 「KUIELab-MDX-Net: A Two-Stream Neural Network for Music Demixing」(arXiv:2111.12203、Minseok Kim・Woosung Choi ほか)です。論文の要旨が設計思想を端的に表しています。
The proposed model has a time-frequency branch and a time-domain branch, where each branch separates stems, respectively. It blends results from two streams to generate the final estimation.
つまり——
- 周波数領域ブランチ:スペクトログラムを処理する TFC-TDF-U-Net v2(後述の系譜)でステムを推定する。
- 時間領域ブランチ:学習済み Demucs を(追加学習なしで)使い、波形側からも推定する。
- ブレンド:2つの推定結果を重み付き平均で統合し、最終出力とする。
周波数領域は「成分の輪郭」を、時間領域は「波形の質感」を捉えるのが得意で、両者を合成することで単独モデルより安定して高品質になる——これが MDX-Net の強さの正体です。
実績:Sony/AIcrowd の Music Demixing Challenge 2021
KUIELab-MDX-Net は、Sony と AIcrowd が主催した ISMIR 2021 Music Demixing (MDX) Challenge で、Leaderboard A で2位、Leaderboard B で3位を獲得しました(論文要旨より)。
⚠️ 正確さのために:これは「2位/3位」であって「優勝」ではありません。ネット上の解説には「優勝」と書くものもありますが、一次情報(論文要旨)に従い、本稿は正確に記載します。それでもこの順位は、限られた学習データ条件で達成されたもので、実用品質として十分に高いという評価です。
系譜:TFC-TDF ブロック(ISMIR 2020)
MDX-Net の周波数領域ブランチの土台は、同じ研究室の先行研究 「Investigating U-Nets with various Intermediate Blocks for Spectrogram-based Singing Voice Separation」(arXiv:1912.02591、ISMIR 2020、Woosung Choi ほか)にあります。ここで提案された TFC-TDF ブロック(Time-Frequency Convolutions + Time-Distributed Fully-connected) が、複素スペクトログラムを扱う U-Net の中間ブロックとして高い分離性能を出しました。
整理すると、系譜はこうです。
TFC-TDF ブロック / U-Net (ISMIR 2020, arXiv:1912.02591)
↓ 発展
TFC-TDF-U-Net v2 を内蔵した
KUIELab-MDX-Net(二段構成 + Demucs)(MDX Challenge 2021, arXiv:2111.12203)
↓ UVR5 に実装・モデル配布
UVR-MDX-NET / Kim_Vocal / KARA … (Anjok07/ultimatevocalremovergui に搭載)
この仕組みが「落とし穴の形」を決めている
仕組みを押さえると、後述のトラブルが必然だと分かります。
- 周波数領域処理は STFT のチャンク単位(
segment_size)で GPU に載せるため、ここが VRAM と速度を直接左右する。 - チャンク境界に継ぎ目アーティファクトが出るので、
overlapで重ねて緩和する(その分遅くなる)。 - 推論は ONNX Runtime(
.onnxモデル) で走るため、CUDA/cuDNN が噛み合わないと黙って CPU に落ちて激遅になる。
つまりパラメータは「気分」で回すものではなく、この設計の延長線上で意味を持つノブなのです。
アーキテクチャの選び方:MDX-Net vs VR vs Demucs vs MDX23C
UVR5 は MDX-Net 以外にも複数のアーキテクチャを搭載しています(READMEのクレジットで原作者が明示されています)。用途で選ぶのが正解で、万能の1つはありません。
| アーキテクチャ | 方式 | 原作者(README) | 得意 | 形式 |
|---|---|---|---|---|
| MDX-Net | 周波数+時間の二段構成 | Kuielab & Woosung Choi | ボーカル/伴奏の2分離・速度と品質の総合力 | .onnx |
| VR Architecture | スペクトログラムU-Net | tsurumeso | 残響・エコー除去、TTA/aggression等の細かい制御 | .pth |
| Demucs(v4 htdemucs) | 時間領域 | Adefossez & Demucs(Meta) | 4ステム分離(vocals/drums/bass/other)、Apple Silicon対応 | .ckpt |
| MDX23C / MDXC | MDXの後継・高品質化 | ZFTurbo | 最新世代の高品質分離 | .ckpt |
選び方はシンプルです。
- ボーカルと伴奏の2つに分けたいだけ → MDX-Net。最も実績があり、速度と品質のバランスが良い。本稿の主役。
- ドラム・ベース・その他まで4ステムに分けたい(リミックス・採譜・耳コピ)→ Demucs v4(htdemucs)。Apple Silicon の MPS でも動く。Demucs 単体の本番運用は専用ガイドで詳しく扱っています。
- 残響・エコーを除去したい → VR Architecture の専用モデル。
- とにかく最新の最高品質を試したい → MDX23C/MDXC や、複数モデルの アンサンブル。
💡 アンサンブルという奥の手:UVR5 は複数モデルの出力を統合する Ensemble モードを持ちます。
Kim_Vocal_2(ボーカル特化)とUVR-MDX-NET-Inst_HQ_3(伴奏特化)を組み合わせると、単独より残留が減りやすい——ただし処理時間はモデル数だけ増えるので、品質最優先のときの選択肢です。
使い方A:まず GUI で試す(UVR5 本体)
「自分の音源で品質が通用するか、まず確かめたい」段階では、コードを書かず GUI で叩くのが最短です。非エンジニアでも使えます。
- 公式リリースから OS に合うインストーラを入手(Windows 10+ / macOS Big Sur+ / Linux)。Windows は C: ドライブ直下へのインストールが推奨です。
- 起動後、Process Method で MDX-Net を選択。
- モデルに
UVR-MDX-NET-Inst_HQ_3(伴奏抽出)などを選び、初回はモデルが自動ダウンロードされる。 - 音声/動画ファイルをドラッグ&ドロップし、出力先を指定して Start Processing。
動作要件(公式README):
- GPU は NVIDIA GTX 1060 6GB が最低要件、8GB 以上の VRAM 推奨。
- AMD は現状サポートが限定的。
- Apple Silicon(M1 以降)は MPS(GPU)アクセラレーションに対応——Demucs v4 とすべての MDX-Net モデルで利用可能。
- Intel Pentium / Celeron 系 CPU は動作保証外。
GUI は手軽ですが、バッチ処理・サーバー組み込み・CI連携には向きません。「毎回手で1ファイルずつ」は本番では破綻します。自動化は次章のライブラリで行います。
使い方B:コードで自動化(python-audio-separator)
UVR5 本体は GUI アプリなのでスクリプトから直接は叩けません。コードで自動化するときの正解は、UVR と同じモデル(.onnx 等)を読み込めるライブラリ python-audio-separator を使うことです。UVR5 と同じ MDX-Net モデルを CLI / Python から実行できます。
1. インストール(公式手順に忠実)
# GPU(NVIDIA CUDA)。本番はこちら
pip install "audio-separator[gpu]"
# CPU / Apple Silicon
pip install "audio-separator[cpu]"
# conda
conda install audio-separator -c pytorch -c conda-forge
- Python は 3.10 以上が必要。
- 推論は ONNX Runtime(
.onnxの MDX-Net/VR モデル)+ PyTorch(Demucs等の.ckpt) で走る。 - 対応 CUDA は 11.8 と 12.2。GPU 版で「動くのに激遅」のときは、ほぼ CUDA/cuDNN と onnxruntime-gpu の不整合(後述の落とし穴①)。
2. 最小コード(3行で動く)
公式の最小例はこうです。Separator を作り、モデルを読み、separate() を呼ぶだけ。
from audio_separator.separator import Separator
separator = Separator() # 既定設定で初期化
separator.load_model( # MDX-Netの伴奏抽出モデルを指定(初回は自動DL)
model_filename="UVR-MDX-NET-Inst_HQ_3.onnx"
)
output_files = separator.separate("song.wav")
print(output_files)
# 例: ['song_(Vocals)_UVR-MDX-NET-Inst_HQ_3.wav',
# 'song_(Instrumental)_UVR-MDX-NET-Inst_HQ_3.wav']
separate() は生成された出力ファイルのパスのリストを返します。既定では Vocals と Instrumental の2ステムが、44.1kHz で出力されます。出力フォーマットは指定でき、ライブラリの既定は WAV です。
⚠️ 既定値の食い違い(要注意):
output_formatの既定は、Python のSeparatorではWAV、CLI(--output_format)ではFLACと異なります。後段で再ミックスするなら可逆なflac/wavを明示するのが安全です(mp3は劣化する)。
3. CLI(バッチ・シェル・CI向け)
サーバー上での単発・バッチ実行なら CLI が手軽です。
# 1ファイルを伴奏抽出モデルで分離
audio-separator song.wav \
--model_filename UVR-MDX-NET-Inst_HQ_3.onnx \
--output_dir ./stems \
--output_format flac
# 利用可能なモデルを一覧("今この瞬間"の正確なファイル名はこれで確認するのが確実)
audio-separator --list_models --list_filter vocals
# 伴奏だけ欲しい(片方のステムのみ出力=書き出しを減らす)
audio-separator song.wav \
--model_filename UVR-MDX-NET-Inst_HQ_3.onnx \
--single_stem Instrumental
🔧 CLIとライブラリで名前が違うパラメータ:片方のステムだけ出すオプションは、CLI では
--single_stem、Python のSeparatorではoutput_single_stemです。同じ機能なのに名前が違うので取り違えに注意。
4. MDX-Net のパラメータ(既定値と意味)
Separator の mdx_params で MDX-Net の挙動を制御します。以下は audio-separator の既定値です。
separator = Separator(
output_dir="stems",
output_format="flac", # 可逆。後段の品質劣化を避ける
sample_rate=44100, # 既定。CD品質
mdx_params={
"segment_size": 256, # GPUに載せるチャンクの大きさ。大=速い・VRAM増
"overlap": 0.25, # チャンク境界の重なり。大=継ぎ目低減・低速
"batch_size": 1, # まとめて処理する数。大=スループット増・VRAM増
"hop_length": 1024, # STFTのホップ幅。基本いじらない
"enable_denoise": False, # 位相反転で残響ノイズを抑制。約2倍コスト
},
)
separator.load_model(model_filename="UVR-MDX-NET-Inst_HQ_3.onnx")
💡 これらの数値はライブラリ既定です。
enable_denoiseやoverlapの内部挙動の詳細は、公式の defaults を超える部分はコミュニティ知見(UVR Discussion #831)に基づきます。まず既定で回し、不満な点だけ動かすのが鉄則です。
モデル選定ガイド:目的から逆引きする
どのステムが欲しいかでモデルを選ぶのが基本です。「伴奏が欲しいのにボーカル特化モデルを使う」と品質が落ちます。以下のファイル名は UVR 公式の model_name_mapper.json で確認したもの(✅)ですが、配布リストは更新されるため、本番投入前に必ず audio-separator --list_models で実在を確認してください。
| 目的 | おすすめモデル | 種別 | 状態 |
|---|---|---|---|
| 伴奏(インスト)を綺麗に取りたい | UVR-MDX-NET-Inst_HQ_3.onnx | Inst | ✅ 公式mapper確認済 |
| 伴奏(旧世代・長い持続音に強い比較用) | UVR-MDX-NET-Inst_HQ_2.onnx | Inst | ✅ |
| ボーカル(声)を綺麗に取りたい | Kim_Vocal_2.onnx | Vocal | ✅ |
| ボーカル(さらにクリーンなアカペラ狙い) | UVR-MDX-NET-Voc_FT.onnx | Vocal | 🟡 --list_modelsで要確認 |
| ハモリ/コーラスを除去しメイン声だけに | UVR_MDXNET_KARA_2.onnx | Karaoke | ✅ |
| 汎用(標準) | UVR_MDXNET_Main.onnx | 汎用 | ✅ |
選び方の原則(コミュニティ合意・Discussion #444):
- 「Inst」系は伴奏を綺麗に残すように、「Vocal」系は声を綺麗に抜くように最適化されている。欲しいステムに合わせて選ぶと、そのステムの品質が上がる。
- ボーカル抽出は
Kim_Vocal_2が高速かつ高品質で定番。 - 伴奏抽出は
UVR-MDX-NET-Inst_HQ_3(HQ系)が定番。 - ハモリ除去(リードボーカルだけ残す)は
UVR_MDXNET_KARA_2。 - 最高品質を狙うなら ボーカル特化 + 伴奏特化のアンサンブル(その分、時間は増える)。
📌 これらのおすすめは公式仕様ではなくコミュニティ合意です。SDR等のベンチマーク値を伴う断定は避け、自分の音源で2〜3モデルを比較して採用するのが確実です。
パラメータ実践チューニング:用途別プリセット
公式が示すのは既定値だけです。ここに実務での当たり値を足します。下表はそのまま使えるプリセットの考え方です。
| 用途 | segment_size | overlap | enable_denoise | 狙い |
|---|---|---|---|---|
| VRAMが少ない(6〜8GB) | 128〜256 | 0.25 | off | OOMを避けつつ実用品質 |
| 標準(12〜16GB) | 256 | 0.25 | off | 既定。まずここから |
| 品質最優先(24GB+) | 384〜512 | 0.5 | on | 継ぎ目とノイズを最小化 |
| 大量バッチで速度優先 | できる限り大 | 0.25 | off | スループット最大化 |
| 継ぎ目ノイズが気になる | 据え置き | ↑(0.5) | off | 境界アーティファクトを緩和 |
| 残響・残留ノイズが気になる | 据え置き | 据え置き | on | 位相反転で抑制(約2倍時間) |
ノブの意味を実務語で言い換えるとこうです。
segment_size(チャンクの大きさ):大きいほど GPU との往復が減って速いが、VRAM を食う。OOM が出たらまずここを下げる。VRAM に余裕があるなら許す限り大きく。overlap(チャンクの重なり):上げるとチャンク境界の継ぎ目ノイズが減るが、その分遅くなる。継ぎ目が気になる素材だけ上げる。enable_denoise(ノイズ抑制):通常入力と位相反転入力の両方で推論して平均し、残響・残留ノイズを抑える。計算量がおよそ2倍になるので、最終仕上げのときだけ。batch_size:上げるとスループットが上がるが VRAM 増。単発処理では 1 のままでよい。
コスト直結の原則:品質を上げるノブ(
overlap↑・denoiseon)はほぼそのまま時間=お金に跳ね返ります。「全件は既定で回し、不満なカット/曲だけ高品質設定で再処理」の二段構えが、本番の単価を最も効かせます。
応用:実務での使いどころ(公式を超えて役立てる)
公式は「分離する」までしか説明しません。ここからが実際に案件で価値になる使い方です。
① 動画ローカライズの前処理(声を抜いてから文字起こし)
吹き替えパイプラインでは、BGM が混ざった音声をそのまま文字起こしすると誤認識が増えます。先に声だけを分離してから Whisper に渡すと、認識精度が上がる。さらに伴奏トラックは保持しておき、吹き替え音声の下に再ミックスすれば、BGM ごと差し替わる違和感を防げます。
# 動画ローカライズ前処理:声だけ抽出 → ASR、伴奏は保持して後で再ミックス
from audio_separator.separator import Separator
# 声だけ欲しいので Vocal特化モデル + 単一ステム出力
vocal_sep = Separator(output_dir="work", output_format="flac",
output_single_stem="Vocals")
vocal_sep.load_model(model_filename="Kim_Vocal_2.onnx")
vocals = vocal_sep.separate("episode.wav") # 声だけのトラック
transcript = whisper_transcribe(vocals[0]) # 伴奏ノイズが消えてASRが安定
# 伴奏は別途 UVR-MDX-NET-Inst_HQ_3 で抜いておき、吹き替え音声と再ミックスする
② カラオケ音源・アカペラ・リミックス素材
曲から伴奏だけ(カラオケ)またはボーカルだけ(アカペラ/サンプリング素材)を取り出す、最も直球の用途。Inst 系で伴奏、Vocal 系で声を取り、必要なら Demucs v4 で4ステムに分けてリミックスやコピーに使います。
③ ポッドキャスト・会議音声のクリーニング
収録に紛れた BGM やテレビ音声を除去し、声を聞き取りやすくする前処理。文字起こし・要約の前段に挟むと、後段の品質が上がります。
④ 音声データセットの前処理(TTS / ASR 学習)
学習データから音楽・環境音を除いたクリーンな音声を量産する。データの質がモデルの質を決めるので、ここに音源分離を挟む価値は大きい。
本番で必ず詰まる5つの落とし穴と回復性設計
デモ(短い1ファイル・手元のGPU)では起きず、本番(大量バッチ・コンテナ・長尺)で一斉に噴出する問題です。私が実運用で踏んだ順に、原因と対策を示します。
① GPUが効かず CPU に落ちる(最頻出・最も気づきにくい)
audio-separator[gpu] を入れても、CUDA/cuDNN と onnxruntime-gpu のバージョンが噛み合わないと、ONNX Runtime は黙って CPU 実行にフォールバックします。エラーは出ず、ただ数十倍遅くなるだけ——本番で最も気づきにくく、最も高くつく罠です。
対策:起動時に CUDAExecutionProvider が利用可能か検証し、本番では起動を止める(fail-fast)。
import onnxruntime as ort
def verify_gpu(require: bool = True) -> None:
"""CUDAが効いているか起動時に検証。本番でCPUに落ちると激遅。"""
providers = ort.get_available_providers()
if "CUDAExecutionProvider" not in providers:
msg = f"CUDA未検出(利用可能: {providers})。onnxruntime-gpuとCUDA/cuDNNの整合を確認。"
if require:
raise RuntimeError(msg) # 気づけないまま遅い本番を避ける
print(f"[WARN] {msg}")
② モデルの初回ダウンロードがコールドスタート毎に走る
モデルは初回利用時に model_file_dir(既定 /tmp/audio-separator-models/)へ自動ダウンロードされます。コンテナ/サーバーレスでは /tmp が揮発するため、コールドスタートのたびに数百MBを再ダウンロード——遅延とegress課金の温床です。
対策:model_file_dir を永続ボリュームに向け、可能ならモデルをイメージに焼き込む(ビルド時に1回だけDL)。
③ 長尺・高 batch_size での VRAM 枯渇(OOM)
audio-separator は segment_size 単位で内部的にチャンク処理するため、拡散モデルほど丸ごと OOM にはなりにくいものの、segment_size や batch_size を上げすぎると CUDA out of memory で落ちます。
対策:OOM を例外ではなく正常系として扱い、segment_size を下げて作り直して再試行する。モデルの再ロードは高コストなので、最初から VRAM に合わせた segment_size を選ぶのが本筋です。
def separate_with_oom_fallback(audio: str, model: str, segment: int = 256):
for seg in (segment, segment // 2, 64): # 段階的に小さくして粘る
try:
sep = Separator(mdx_params={"segment_size": seg, "overlap": 0.25,
"batch_size": 1, "hop_length": 1024,
"enable_denoise": False})
sep.load_model(model_filename=model)
return sep.separate(audio)
except RuntimeError as exc: # onnxruntimeのOOMはRuntimeErrorで届く
if "memory" not in str(exc).lower() or seg == 64:
raise # OOM以外、または下限=本物の異常
raise RuntimeError("unreachable")
④ 入力フォーマットの不一致
入力は WAV/MP3/FLAC/M4A など一般的な形式に対応しますが、壊れたヘッダや想定外コーデックは処理失敗の原因になります。
対策:投入前に ffmpeg で正規化を1段挟む。サンプルレートとチャンネルを揃えるだけで安定性が上がります。
# 投入前の正規化:44.1kHz・ステレオ・wavに統一
ffmpeg -y -i input.m4a -ar 44100 -ac 2 normalized.wav
⑤ 品質を「耳」でしか確認していない
大量バッチで最も危険なのは、品質ゲートが人手の試聴だけであること。破綻した分離がすり抜けます。
対策:分離後に 伴奏トラックに残ったボーカル残留などを簡易指標で機械チェックし、しきい値を超えたものだけ人手レビュー or 再処理に回す。完璧な自動評価は難しくとも、「明らかな失敗を弾く」ゲートだけでもレビュー工数を激減させられます。
本番運用の設計原則を実装する(冪等性・回復性・可観測性・コスト)
落とし穴の対策を、1つの本番向けマイクロサービスに集約します。これが「動く」と「本番で落ちない」の差です。設計方針は4点——①モデルは常駐させ再利用、②入力の中身でキー化した冪等キャッシュ、③GPU検証とGPU直列化、④失敗を握りつぶさず構造化ログに残す。
# separation_service.py — 本番向け音源分離マイクロサービス(UVR5 / MDX-Net)
from __future__ import annotations
import asyncio
import hashlib
import json
import logging
import os
import threading
from pathlib import Path
import onnxruntime as ort
from audio_separator.separator import Separator
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
logger = logging.getLogger("separation")
MODEL_CACHE = Path(os.environ.get("MODEL_CACHE_DIR", "/models")) # 永続ボリューム推奨
OUTPUT_DIR = Path(os.environ.get("OUTPUT_DIR", "/data/stems"))
DEFAULT_MODEL = os.environ.get("SEPARATION_MODEL", "UVR-MDX-NET-Inst_HQ_3.onnx")
REQUIRE_GPU = os.environ.get("REQUIRE_GPU", "true").lower() == "true"
# MDXの推論パラメータ。再現性のため固定し、冪等キーの一部にする
MDX_PARAMS = {"segment_size": 256, "overlap": 0.25, "batch_size": 1,
"hop_length": 1024, "enable_denoise": False}
_separator: Separator | None = None
_gpu_sem = asyncio.Semaphore(int(os.environ.get("GPU_CONCURRENCY", "1"))) # GPUは原則直列
_manifest_lock = threading.Lock()
_MANIFEST = OUTPUT_DIR / "manifest.json"
def _verify_gpu() -> None:
"""CUDAが効いているか検証。本番でCPUに落ちると数十倍遅い(落とし穴①)。"""
providers = ort.get_available_providers()
if "CUDAExecutionProvider" not in providers:
msg = f"CUDA未検出(利用可能: {providers})。onnxruntime-gpuとCUDA/cuDNNを確認。"
if REQUIRE_GPU:
raise RuntimeError(msg)
logger.warning(msg)
def get_separator() -> Separator:
"""プロセス内シングルトン。モデルは一度だけVRAMへ常駐させ、リクエスト間で再利用する。"""
global _separator
if _separator is None:
_verify_gpu()
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
sep = Separator(
output_dir=str(OUTPUT_DIR),
output_format="flac", # 可逆。再ミックスで品質を落とさない
model_file_dir=str(MODEL_CACHE), # 初回DLを永続化(落とし穴②)
sample_rate=44100,
mdx_params=MDX_PARAMS,
)
sep.load_model(model_filename=DEFAULT_MODEL)
_separator = sep
logger.info("model loaded model=%s", DEFAULT_MODEL)
return _separator
def _content_key(path: Path) -> str:
"""ファイル名ではなく"中身+モデル+パラメータ"でキー化。再送で再計算しない。"""
h = hashlib.sha256()
with path.open("rb") as f: # 大きい音源もメモリに載せず逐次ハッシュ
for block in iter(lambda: f.read(1 << 20), b""):
h.update(block)
h.update(DEFAULT_MODEL.encode())
h.update(json.dumps(MDX_PARAMS, sort_keys=True).encode())
return h.hexdigest()[:16]
def _manifest() -> dict[str, list[str]]:
return json.loads(_MANIFEST.read_text()) if _MANIFEST.exists() else {}
def _record(key: str, stems: list[str]) -> None:
with _manifest_lock: # 単一プロセス前提。複数レプリカならRedis等の共有ストアへ
data = _manifest()
data[key] = stems
_MANIFEST.write_text(json.dumps(data))
class SeparateRequest(BaseModel):
audio_path: str = Field(..., description="サーバーからアクセス可能な入力音声パス")
class SeparateResponse(BaseModel):
job_key: str
stems: list[str]
cached: bool
app = FastAPI()
@app.on_event("startup")
def _startup() -> None:
get_separator() # 最初のリクエストを待たせない(ウォームアップ)
@app.post("/separate", response_model=SeparateResponse)
async def separate(req: SeparateRequest) -> SeparateResponse:
src = Path(req.audio_path)
if not src.is_file(): # 外部入力は境界で検証
raise HTTPException(status_code=422, detail="input audio not found")
key = _content_key(src)
cached = _manifest().get(key)
if cached and all(Path(p).exists() for p in cached): # 冪等:再送/リトライで再計算しない
logger.info("cache hit key=%s", key)
return SeparateResponse(job_key=key, stems=cached, cached=True)
try:
async with _gpu_sem: # GPUは1ジョブずつ=VRAM競合/OOM回避
stems = await asyncio.to_thread(get_separator().separate, str(src))
except Exception as exc: # 失敗を握りつぶさず構造化ログへ
logger.exception("separation failed key=%s", key)
raise HTTPException(status_code=500, detail="separation failed") from exc
_record(key, stems)
logger.info("separated key=%s stems=%d", key, len(stems))
return SeparateResponse(job_key=key, stems=stems, cached=False)
このサービスを、TypeScript(Next.js等)から型安全に叩くクライアントはこうです。境界で必ず Zod 検証します。
// lib/separation-client.ts — Python分離サービスを叩く型安全クライアント
import { z } from "zod";
const SeparateResponse = z.object({
job_key: z.string(),
stems: z.array(z.string()),
cached: z.boolean(),
});
export type SeparateResult = z.infer<typeof SeparateResponse>;
export async function separateAudio(audioPath: string): Promise<SeparateResult> {
const res = await fetch(`${process.env.SEPARATION_SERVICE_URL}/separate`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ audio_path: audioPath }),
});
if (!res.ok) throw new Error(`separation failed: ${res.status}`);
return SeparateResponse.parse(await res.json()); // 外部応答は信用せず境界で検証
}
設計原則を運用の言葉でまとめ直すと、こうです。
- 冪等性:
sha256(音源の中身 + モデル + パラメータ)をジョブキーにし、結果をマニフェストにキャッシュ。再送・連打・リトライで二重 GPU 実行をしない。ファイル名ではなく中身でキー化するのがポイント。 - 回復性:OOM・CPUフォールバックを例外ではなく設計事項として扱う。GPU 未検出は起動時に弾き、OOM は
segment_sizeを下げて再試行する。 - 可観測性:ジョブごとに キー・モデル・ステム数・キャッシュ有無を構造化ログに残し、「どのジョブがどのモデルで何を出したか」を後から追える状態にする。音声内容(PII になり得る)はログに出さない。
- コスト効率:①モデル常駐でロードコストを償却、②冪等キャッシュで再生成ゼロ、③
single_stemで不要なステム書き出しを省略、④品質ノブは全件ではなく不満分だけ上げる——の積み重ねで単価を刻む。 - テスト容易性:
_content_keyのような純関数は I/O なしで単体テストでき、分離本体(GPU依存)はサービス境界でモック差し替えできる。
他ツール・APIとの比較:結局どれを使う?
| 選択肢 | 形態 | 強み | 弱み | 向く場面 |
|---|---|---|---|---|
| UVR5(GUI) | デスクトップアプリ | 無料・GUIで手軽・MDX/VR/Demucs/MDXC全部入り | 自動化不可・1ファイルずつ | 試用・少量・非エンジニア |
| python-audio-separator | Pythonライブラリ/CLI | UVRと同じモデルをコードで・バッチ/サーバー組み込み | 環境構築(CUDA整合)が要 | 本番自動化・大量処理 |
| Demucs(単体) | Pythonライブラリ | 4ステム分離・Meta製・活発 | ボーカル/伴奏2分離ではMDXが好まれる場面も | 4ステム・リミックス用途 |
| 商用クラウドAPI | SaaS | 環境構築ゼロ・即利用 | 従量課金・データを外部に出す | PoC・データを外に出せる案件 |
実務の意思決定はおおむねこうです。
- まず品質を見たい / 少量 → UVR5 GUI。
- サーバーに組み込み、大量・継続処理する → python-audio-separator(本稿の本番設計)。
- ドラム/ベースまで分けたい → Demucs v4。
- 環境構築の手間を一切かけたくない、データを外に出せる → 商用 API。まずそこで需要を確かめ、量が増えたらセルフホストへ移すのが王道。
各モデル・ツールのライセンスや配布条件は更新されます。商用利用は必ず一次情報で確認してください。UVR5 のコードは本稿執筆時点で MIT です(処理する音源の著作権は別問題)。
よくある質問(FAQ)
Q. UVR5 と MDX-Net の関係は? A. UVR5(Ultimate Vocal Remover GUI v5.6)が「アプリ」、**MDX-Net はそのアプリが搭載する「AIアーキテクチャの一つ」**です。UVR5 は MDX-Net のほかに VR Architecture・Demucs・MDX23C/MDXC も搭載しています。ボーカル/伴奏の2分離では MDX-Net が定番です。
Q. コードから使うにはどうすれば?
A. UVR5 本体は GUI なのでスクリプトから直接は叩けません。python-audio-separator を pip install "audio-separator[gpu]" で入れ、UVR と同じ MDX-Net モデル(.onnx)を Separator から読み込みます。本稿のコード章が最短です。
Q. どのモデルを使えばいい?
A. 欲しいステムで選びます。伴奏(カラオケ)なら UVR-MDX-NET-Inst_HQ_3、ボーカル(アカペラ)なら Kim_Vocal_2、ハモリ除去なら UVR_MDXNET_KARA_2。実在は audio-separator --list_models で確認し、自分の音源で2〜3個比較するのが確実です。
Q. 必要な GPU / VRAM は?
A. 公式READMEは GTX 1060 6GB を最低要件、8GB 以上を推奨としています。VRAM が少ないときは segment_size を下げます。Apple Silicon(M1+)は MPS 対応で、Demucs v4 と全 MDX-Net モデルが動きます。
Q. GPU を入れたのに遅いです。
A. ほぼ CUDA/cuDNN と onnxruntime-gpu の不整合で CPU にフォールバックしています。対応 CUDA は 11.8 / 12.2。onnxruntime.get_available_providers() に CUDAExecutionProvider が含まれるかを起動時に検証してください(落とし穴①)。
Q. 出力フォーマットの既定は?
A. **Python ライブラリの既定は WAV、CLI の既定は FLAC**と異なります。後段で再ミックスするなら可逆な flac/wav を明示してください(mp3 は劣化します)。出力は既定で Vocals / Instrumental の2ステム・44.1kHz です。
Q. リアルタイム処理に使える? A. 向きません。MDX-Net は1ファイルをまとめて処理するバッチ志向です。即時性が要件なら別アプローチを検討してください。
Q. 市販曲を分離して公開してもいい? A. 技術的には可能でも、法的には別問題です。市販曲には著作権があり、得たステムの無断再配布・公開は権利侵害になり得ます。自作曲・許諾済み素材・私的利用の範囲で使ってください。
まとめ:UVR5/MDX-Net を「動く」から「本番で稼ぐ」へ
MDX-Net の本質は、周波数領域と時間領域の二段構成を重み付き平均でブレンドし、単独モデルより安定して高品質な分離を出す点にあります(arXiv:2111.12203)。だからこそ segment_size・overlap・denoise という設計に根ざしたノブを理解して扱う必要があります。
実装の道筋はシンプルです。
- UVR5 GUI で自分の音源の品質をまず確かめる(無料・ドラッグ&ドロップ)。
- 手応えがあれば python-audio-separator でコード化し、目的別にモデルを選び、パラメータを詰める。
- 本番は冪等性・回復性・可観測性・コストを設計に織り込む——モデル常駐、GPU検証、GPU直列化、中身ハッシュの冪等キャッシュ、OOM フォールバック、構造化ログ。
ここまでやって初めて、デモではなく「顧客の音源で落ちない」プロダクトになります。そして、ここが一番伝えたい点ですが——この一連の設計判断こそが、外注で差がつくところです。「モデルを呼ぶだけ」のデモは誰でも作れますが、CPUフォールバック・OOM・コールドスタート再DL・大量バッチで破綻しない基盤は、踏んだ地雷の数がそのまま品質になります。
私は、本稿の落とし穴と回復性設計を、音声分離を第1段に持つ AI動画ローカライズ基盤で実際に本番運用しています。音源分離を含む音声・動画 AI パイプラインの構築・改善をお考えなら、実績をご覧のうえ、お気軽にご相談ください。一人 × 生成AIで、PoCから本番運用まで一気通貫で、速く・安く・安全に作ります。
出典・公式リソース
- UVR5 公式リポジトリ(GitHub):Anjok07/ultimatevocalremovergui — README(v5.6・MIT・動作要件・アーキテクチャのクレジット)
- MDX-Net 論文(arXiv):KUIELab-MDX-Net: A Two-Stream Neural Network for Music Demixing (2111.12203) — 二段構成・ブレンド・MDX Challenge 2021 結果
- 系譜の論文(arXiv):Investigating U-Nets with various Intermediate Blocks for Spectrogram-based Singing Voice Separation (1912.02591) — TFC-TDF ブロック(ISMIR 2020)
- コードで使うライブラリ:nomadkaraoke/python-audio-separator / PyPI: audio-separator — インストール・
SeparatorAPI・CLI・モデル一覧 - モデル選定・パラメータの議論:Discussion #444(モデル推奨) / Discussion #831(segment_size 等)
※ バージョン・モデル名・パラメータ既定値・ライセンスは更新されます。実装前に必ず一次情報を確認してください(特にモデルのファイル名は audio-separator --list_models で実在確認を推奨)。本稿の事実(UVR5 v5.6・MIT、MDX Challenge 2021 で Leaderboard A 2位/B 3位、二段構成、audio-separator[gpu]・Python 3.10+・CUDA 11.8/12.2、既定2ステム/44.1kHz、output_format のライブラリWAV/CLI FLAC など)は、本稿執筆時点の公式情報に基づきます。