Chuyển đến nội dung chính
友田 陽大
Audio source separation & preprocessing
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フォールバック・冪等性・可観測性まで、本番運用の実装を具体コードで示します。

Published
Reading time
31 min read
Author
友田 陽大
Chia sẻ
Mục lục

この記事のゴール

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 など)は、本稿執筆時点の公式情報に基づきます。

友田

友田 陽大

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