メインコンテンツへスキップ
友田 陽大
音源分離・音声前処理
UVR5
MDX-Net
音源分離
ボーカル抽出
Python
AI音声
MLOps
生成AI

UVR5(MDX-Net)完全ガイド:公式準拠でボーカル/伴奏を高精度分離し本番自動化する

オープンソースの音源分離ツール UVR5 と MDX-Net アーキテクチャを、公式情報(GitHub・arXiv論文)に忠実に解説。GUIでの試用から python-audio-separator によるコード自動化、モデル選定(Inst/Vocal/Karaoke)、segment_size等のチューニング、OOM・CPUフォールバック・冪等性・可観測性まで、本番運用の実装を具体コードで示します。

公開日
読了時間
31分
著者
友田 陽大
シェア
目次

この記事のゴール

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つができる状態を目指します。

  1. UVR5 と MDX-Net が何をするツールで、なぜ精度が高いのかを、人に説明できる。
  2. GUI(試す)python-audio-separator(自動化する) のどちらを選ぶべきか判断し、今日中に手を動かせる
  3. デモではなく本番——長尺での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-separatorpip install "audio-separator[gpu]"Separator クラス3行でCLI/サーバー組み込み
必要GPUGTX 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.

つまり——

  1. 周波数領域ブランチ:スペクトログラムを処理する TFC-TDF-U-Net v2(後述の系譜)でステムを推定する。
  2. 時間領域ブランチ学習済み Demucs を(追加学習なしで)使い、波形側からも推定する。
  3. ブレンド: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-Nettsurumeso残響・エコー除去、TTA/aggression等の細かい制御.pth
Demucs(v4 htdemucs)時間領域Adefossez & Demucs(Meta)4ステム分離(vocals/drums/bass/other)、Apple Silicon対応.ckpt
MDX23C / MDXCMDXの後継・高品質化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 で叩くのが最短です。非エンジニアでも使えます。

  1. 公式リリースから OS に合うインストーラを入手(Windows 10+ / macOS Big Sur+ / Linux)。Windows は C: ドライブ直下へのインストールが推奨です。
  2. 起動後、Process MethodMDX-Net を選択。
  3. モデルUVR-MDX-NET-Inst_HQ_3(伴奏抽出)などを選び、初回はモデルが自動ダウンロードされる。
  4. 音声/動画ファイルをドラッグ&ドロップし、出力先を指定して 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 では WAVCLI(--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_stemPython の Separator では output_single_stem です。同じ機能なのに名前が違うので取り違えに注意。

4. MDX-Net のパラメータ(既定値と意味)

Separatormdx_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_denoiseoverlap の内部挙動の詳細は、公式の defaults を超える部分はコミュニティ知見(UVR Discussion #831)に基づきます。まず既定で回し、不満な点だけ動かすのが鉄則です。


モデル選定ガイド:目的から逆引きする

どのステムが欲しいかでモデルを選ぶのが基本です。「伴奏が欲しいのにボーカル特化モデルを使う」と品質が落ちます。以下のファイル名は UVR 公式の model_name_mapper.json で確認したもの(✅)ですが、配布リストは更新されるため、本番投入前に必ず audio-separator --list_models で実在を確認してください。

目的おすすめモデル種別状態
伴奏(インスト)を綺麗に取りたいUVR-MDX-NET-Inst_HQ_3.onnxInst✅ 公式mapper確認済
伴奏(旧世代・長い持続音に強い比較用)UVR-MDX-NET-Inst_HQ_2.onnxInst
ボーカル(声)を綺麗に取りたいKim_Vocal_2.onnxVocal
ボーカル(さらにクリーンなアカペラ狙い)UVR-MDX-NET-Voc_FT.onnxVocal🟡 --list_modelsで要確認
ハモリ/コーラスを除去しメイン声だけにUVR_MDXNET_KARA_2.onnxKaraoke
汎用(標準)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_sizeoverlapenable_denoise狙い
VRAMが少ない(6〜8GB)128〜2560.25offOOMを避けつつ実用品質
標準(12〜16GB)2560.25off既定。まずここから
品質最優先(24GB+)384〜5120.5on継ぎ目とノイズを最小化
大量バッチで速度優先できる限り大0.25offスループット最大化
継ぎ目ノイズが気になる据え置き↑(0.5)off境界アーティファクトを緩和
残響・残留ノイズが気になる据え置き据え置きon位相反転で抑制(約2倍時間)

ノブの意味を実務語で言い換えるとこうです。

  • segment_size(チャンクの大きさ):大きいほど GPU との往復が減って速いが、VRAM を食う。OOM が出たらまずここを下げる。VRAM に余裕があるなら許す限り大きく
  • overlap(チャンクの重なり):上げるとチャンク境界の継ぎ目ノイズが減るが、その分遅くなる。継ぎ目が気になる素材だけ上げる。
  • enable_denoise(ノイズ抑制):通常入力と位相反転入力の両方で推論して平均し、残響・残留ノイズを抑える。計算量がおよそ2倍になるので、最終仕上げのときだけ。
  • batch_size:上げるとスループットが上がるが VRAM 増。単発処理では 1 のままでよい。

コスト直結の原則:品質を上げるノブ(overlap↑・denoise on)はほぼそのまま時間=お金に跳ね返ります。「全件は既定で回し、不満なカット/曲だけ高品質設定で再処理」の二段構えが、本番の単価を最も効かせます。


応用:実務での使いどころ(公式を超えて役立てる)

公式は「分離する」までしか説明しません。ここからが実際に案件で価値になる使い方です。

① 動画ローカライズの前処理(声を抜いてから文字起こし)

吹き替えパイプラインでは、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-separatorsegment_size 単位で内部的にチャンク処理するため、拡散モデルほど丸ごと OOM にはなりにくいものの、segment_sizebatch_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-separatorPythonライブラリ/CLIUVRと同じモデルをコードで・バッチ/サーバー組み込み環境構築(CUDA整合)が要本番自動化・大量処理
Demucs(単体)Pythonライブラリ4ステム分離・Meta製・活発ボーカル/伴奏2分離ではMDXが好まれる場面も4ステム・リミックス用途
商用クラウドAPISaaS環境構築ゼロ・即利用従量課金・データを外部に出す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-separatorpip 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.2onnxruntime.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_sizeoverlapdenoise という設計に根ざしたノブを理解して扱う必要があります。

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

  1. UVR5 GUI で自分の音源の品質をまず確かめる(無料・ドラッグ&ドロップ)。
  2. 手応えがあれば python-audio-separator でコード化し、目的別にモデルを選び、パラメータを詰める。
  3. 本番は冪等性・回復性・可観測性・コストを設計に織り込む——モデル常駐、GPU検証、GPU直列化、中身ハッシュの冪等キャッシュ、OOM フォールバック、構造化ログ。

ここまでやって初めて、デモではなく「顧客の音源で落ちない」プロダクトになります。そして、ここが一番伝えたい点ですが——この一連の設計判断こそが、外注で差がつくところです。「モデルを呼ぶだけ」のデモは誰でも作れますが、CPUフォールバック・OOM・コールドスタート再DL・大量バッチで破綻しない基盤は、踏んだ地雷の数がそのまま品質になります。

私は、本稿の落とし穴と回復性設計を、音声分離を第1段に持つ AI動画ローカライズ基盤で実際に本番運用しています。音源分離を含む音声・動画 AI パイプラインの構築・改善をお考えなら、実績をご覧のうえ、お気軽にご相談ください。一人 × 生成AIで、PoCから本番運用まで一気通貫で、速く・安く・安全に作ります。


出典・公式リソース

※ バージョン・モデル名・パラメータ既定値・ライセンスは更新されます。実装前に必ず一次情報を確認してください(特にモデルのファイル名は 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 など)は、本稿執筆時点の公式情報に基づきます。

友田

友田 陽大

経済産業大臣賞 受賞プロダクト開発者。TypeScript + Python + AWS で、SaaS・業界DX・ 実用レベルの生成AI(RAG)を、要件定義からインフラ・運用まで一人で完遂します。

この記事で解説した技術の適用事例

AI動画ローカライズ・リップシンク基盤

ケーススタディを見る