Demucs v4の簡単インストーラ

[Demucs](https://github.com/facebookresearch/demucs)は音楽データをAIを使ってドラム・ベース・ボーカル・その他に高精度に分離するツールです。

詳細は[試用記事やサンプル](https://www.google.com/search?q=demucs)を見てもらうとして、音楽ゲーム(BeatSaber)の譜面作成の音取りに便利そうなので紹介したいのですが、一般の人には結構ハードルが高いです。

GUI版の[Demucs-Gui](https://github.com/CarlGao4/Demucs-Gui)もありますが、~~Demucs v3で開発が止まっていて最新のv4には対応していません。~~ →現在はv4に対応しています。

DemucsのインストールはPythonでpip installするだけですが、環境を汚さないようにvenvで仮想環境を作ってとか、[Python3.10や3.11ではインストールに問題があるので3.9を使う](https://github.com/facebookresearch/demucs/issues/286)とかあって、どうしようか悩みます。

なので、バージョンと環境の問題は、Python embeddableを使って、Demucsを含めたpipでのパッケージインストーラーのバッチファイルを作成することにします。また、実行時のGUIは作るのが大変なので、バッチファイルに分離したい音楽データを投げ込んで使う様にしたいと思います。今回はその作成までの記事です。

記事の内容はどうでもいいのでDemucs v4をインストールしたい人は下記を参照してください。ドキュメントもあるので簡単に使えるようになっています。

https://drive.google.com/drive/u/1/folders/1bm_OMCmlPIrX1vOgWgVwGNfBB4HrXUnA

ただし、BeatSaberの作譜用に作っているので、分離データの ~~.oggへ変換＆~~ コピー処理が入っています。~~他の用途で使用する場合は、ffmpegの処理などは変えた方がいいかもしれません。~~ →ChroMapperは.wavでも読めるためoggへの変換は止めました。

# 使うもの

### [Python embeddable package](https://www.python.org/downloads/windows/)
超軽量なPythonの実行環境です。インストールが不要で単独で実行できるので、何かのソフトに組み込んで使うとか配布するのに便利です。

### [get-pip.py](https://github.com/pypa/get-pip)
Python embeddableでpipを使うために必要です。

### [FFmpeg](https://www.gyan.dev/ffmpeg/builds/)
Windowsでは入力データフォーマットのtorchaudioサポートが限定的なのでffmpegが必要になります。あと、今回は分離後のデータをoggに変換するのにも使用します。

# 配布方法
Python embeddableでDemucsや必要パッケージをインストール完了した状態で、まるっとzipで固めて配布も考えたのですが以下の理由で止めました。

* サイズが巨大になる(GPU[CUDA]対応だと5GBぐらいになります)
* 環境によってPyTorchをCPUのみ・CUDA対応など変えたい
* pipでのインストール時に、インストール環境のPythonパスがScriptsフォルダのexeや、Lib\site-packagesの__pycache__のpycに埋め込まれる
* 分離学習データが初回実行時にC:\Users\ユーザ名\.cache\torch\hub\checkpointsに保存される。結局なんらかのダウンロードが必須になる
* インストールされたパッケージのライセンス確認がめんどくさい

なので、Python embeddable, get-pip.py, FFmpeg の3つを固めて配布することにします。
Demucsや実行に必要なパッケージはバッチファイルでインストールするようにします。

デメリットとしては、今はインストールできるけど将来的にPythonのバージョンが合わなくなってインストールできなくなるでしょう。そのときにインストーラを作り直すための備忘録的記事でもあります。

# 配布ツールのダウンロード

### Python embeddable package
[ここ](https://www.python.org/downloads/windows/)から、Python3.9の一番新しい下記をダウンロードします。
Windows embeddable package (64-bit) 3.9.13
https://www.python.org/ftp/python/3.9.13/python-3.9.13-embed-amd64.zip

※3.10や3.11で試しましたが、やはりDemucsのインストール途中で止まるので3.9を使います。

### FFmpeg
[ここ](https://www.gyan.dev/ffmpeg/builds/)から、latest git master branch buildをダウンロードします。バージョンはREADME.txtに記載があります。私がダウンロードしたのは、version: 2023-07-06-git-f00222e81f でした
https://www.gyan.dev/ffmpeg/builds/ffmpeg-git-full.7z

### get-pip.py
下記をダウンロードします。
https://bootstrap.pypa.io/get-pip.py
MITライセンスなので、こちらもダウンロードしてget-pip_LICENSE.txtとして一緒に置いておきます。
https://raw.githubusercontent.com/pypa/get-pip/main/LICENSE.txt

# 配布環境構築

pythonとffmpegを置くフォルダを作成して解凍します。
わかりやすいようにバージョン表記のフォルダ名にしました。
pythonのフォルダにはget-pip.pyとget-pip_LICENSE.txtもコピーします。

最終的にはこんな感じにします。

```
+-+- ffmpeg-2023-07-06-git-f00222e81f-full_build  →(ffmpeg-git-full.7zを解凍)
| +- python-3.9.13-embed-amd64 +                  →(python-3.9.13-embed-amd64.zipを解凍)
| |                            +- get-pip.py      →(ダウンロードしたものを追加)
| |                            +- get-pip_LICENSE.txt →(get-pipのMIT LICENSE)
| |                            +- python_cmd.bat  →(Python環境コマンドプロンプト表示用:実行用)
| |                            +- python_open.bat →(Python環境コマンドプロンプト表示用)
| |                            +- python39._pth   →(編集：import siteのコメントアウトを外す)
| +- INSTALLER +- INSTALL_CPU.BAT                 →(インストーラバッチファイル、環境毎に作成)
|              +- INSTALL_CPU_GIT.BAT
|              +- INSTALL_GPU_CUDA117.BAT
|              +- INSTALL_GPU_CUDA117_GIT.BAT
|              +- INSTALL_GPU_CUDA118.BAT
|              +- INSTALL_GPU_CUDA118_GIT.BAT
+- htdemucs_split.bat                             →(実行用バッチファイル、分離モデル毎に作成)
+- htdemucs_ft_split.bat
+- htdemucs_6s_split.bat
+- hdemucs_mmi_split.bat
+- mdx_split.bat
+- mdx_extra_split.bat
+- mdx_q_split.bat
+- mdx_extra_q_split.bat
+- README.TXT
```

# Python embeddableでpipを使えるようにする

Python embeddableは、そのままだとpipが使えません。
まずは、`python39._pth`を編集して`import site`のコメントアウトを外します。

```python39._pth
python39.zip
.

# Uncomment to run site.main() automatically
import site
```

これで、`get-pip.py`を実行するとpipが使えるようになります。

# コマンドプロンプト表示用バッチファイル

Pythonがインストール済みの環境でパスが通っていたりすると、どのPythonが対象なのかわからなくなります。なのでPython embeddableを対象としたコマンドプロンプトが表示できるバッチファイルを作成します。

まずは、環境変数のPATHの変更と、PYTHON＊環境変数の初期化をした状態でコマンドプロンプトが開くようにします。

```python_open.bat
@ECHO OFF
SET A=%~dp0
SET A=%A:~0,-2%
FOR %%A IN (%A%) DO SET A=%%~dpA
SET PATH=%~dp0;%~dp0Scripts;%A%ffmpeg-2023-07-06-git-f00222e81f-full_build\bin;%PATH%
SET PYTHONHOME=
SET PYTHONPATH=
SET PYTHONSTARTUP=
```
2～4行目は%A%に、バッチファイル置き場所のひとつ上のフォルダパスを取るためです。
5行目でPATHの先頭にPython embeddableとffmpegのパスを追加します。
6～8行目はPythonの実行に影響がでそうな環境変数の初期化をします。

このままだと、バッチファイルを実行しても閉じてしまうので、このバッチファイルを呼び出すためのバッチファイルを作成します。

```python_cmd.bat
@ECHO OFF
cmd /k python_open.bat
```

cmd /k で呼ぶと、バッチファイルが終了してもコマンドプロンプトが閉じなくなります。
使用時はpython_cmd.batを実行します。

これでPython embeddable環境で手動インストールしてみて、問題なければインストール用のバッチファイルを作成します。

# インストール用バッチファイル

インストール自体のコマンドは以下の5つです。(PyTorchはCUDA1.18用、demucsはGitHubから最新版)

```
python get-pip.py
python -m pip install -U ffmpeg
python -m pip install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/test/cu118
python -m pip install -U soundfile
python -m pip install -U diffq
python -m pip install -U git+https://github.com/facebookresearch/demucs#egg=demucs
```

このうち、PyTorchはCPU,CUDAv1.17,CUDAv1.18で下記３種類あります。

```
REM CPU用
python -m pip install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/test/cpu
REM CUDA1.17用
python -m pip install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/test/cu117
REM CUDA1.18用
python -m pip install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/test/cu118
```

また、demucsもリリースされているv4.0.0か、Gitの最新版v4.0.1a2で下記２種類あります。

```
REM 通常版(v4.0.0)
python -m pip install -U demucs
REM GitHub最新版(v4.0.1a2)
python -m pip install -U git+https://github.com/facebookresearch/demucs#egg=demucs
```

これらはIFで選択でも良いですが、インストール中の選択は、それだけでハードルが上がるのでバッチファイルを分けることにします。

あとgitを使うバッチファイルは、gitが無い場合は実行しないように下記を追加します。

```
git -v
if %errorlevel% neq 0 (
  echo Git is not installed!!
  PAUSE
  exit /b
)
```

あとは、コマンドプロンプト表示用バッチファイルと合体させて、PATHの環境変数を修正して完成です。

```INSTALL_GPU_CUDA118_GIT.BAT
@ECHO OFF
SET A=%~dp0
SET A=%A:~0,-2%
FOR %%A IN (%A%) DO SET A=%%~dpA
SET PATH=%A%python-3.9.13-embed-amd64;%A%python-3.9.13-embed-amd64\Scripts;%A%ffmpeg-2023-07-06-git-f00222e81f-full_build\bin;%PATH%
SET PYTHONHOME=
SET PYTHONPATH=
SET PYTHONSTARTUP=
CD %A%python-3.9.13-embed-amd64
git -v
if %errorlevel% neq 0 (
  echo Git is not installed!!
  PAUSE
  exit /b
)
python get-pip.py
python -m pip install -U ffmpeg
python -m pip install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/test/cu118
python -m pip install -U soundfile
python -m pip install -U diffq
python -m pip install -U git+https://github.com/facebookresearch/demucs#egg=demucs
ECHO ***********************************
ECHO ****** Installation complete ******
ECHO ***********************************
PAUSE
```

# 実行用バッチファイル

実行用のバッチファイルは、以下の様にします。
Python embeddableとFFmpegのPATH設定と、PYTHON＊環境変数の初期化、demucsで分離とffmpegでoggへの変換です。


```htdemucs_ft_split.bat
@ECHO OFF
SET PATH=%~dp0python-3.9.13-embed-amd64;%~dp0python-3.9.13-embed-amd64\Scripts;%~dp0ffmpeg-2023-07-06-git-f00222e81f-full_build\bin;
SET PYTHONHOME=
SET PYTHONPATH=
SET PYTHONSTARTUP=
python -m demucs -n htdemucs_ft -o "%~dp1separated" %1
python -m demucs --two-stems=vocals -n htdemucs_ft -o "%~dp1separated" %1
ffmpeg -i "%~dp1separated\htdemucs_ft\%~n1\bass.wav" -y -vn -ab 500k -acodec libvorbis -f ogg "%~dp1bass.ogg"
ffmpeg -i "%~dp1separated\htdemucs_ft\%~n1\drums.wav" -y -vn -ab 500k -acodec libvorbis -f ogg "%~dp1drums.ogg"
ffmpeg -i "%~dp1separated\htdemucs_ft\%~n1\no_vocals.wav" -y -vn -ab 500k -acodec libvorbis -f ogg "%~dp1no_vocals.ogg"
ffmpeg -i "%~dp1separated\htdemucs_ft\%~n1\other.wav" -y -vn -ab 500k -acodec libvorbis -f ogg "%~dp1other.ogg"
ffmpeg -i "%~dp1separated\htdemucs_ft\%~n1\vocals.wav" -y -vn -ab 500k -acodec libvorbis -f ogg "%~dp1vocals.ogg"
PAUSE
```

demucs は `-n 分離モデル名`で、分離用のAI学習モデルを指定します。指定しないと`htdemucs`になります。

| 分離モデル名 | 説明 |
|:--------|------|
| htdemucs | htdemucsモデル デフォルトモデル (Demucs V4モデル) |
| htdemucs_ft | htdemucsの微調整版で、分離には4倍の時間がかかるが、少し良くなるかもしれない。|
| htdemucs_6s | htdemucsの6ソースバージョンで、ピアノと ギターが追加されている。ピアノは現在うまく動作していないので注意。|
| hdemucs_mmi | Demucs V3モデル |
| mdx | MusDB HQ(2021年の音楽分離コンテスト)用にトレーニングされ、 MDXチャレンジのトラックAで優勝したモデル。|
| mdx_extra | 追加のトレーニングデータ(MusDBテストセットを含む)でトレーニングされ、 MDXチャレンジのトラックBで2位にランクされたモデル。|
| mdx_q, mdx_extra_q | 以前のモデルの量子化バージョン。ダウンロード容量と保存容量が小さくなったが、品質は若干悪くなる可能性がある。|

あと、`-o 出力フォルダ`で、分離後のデータ保存先を指定できます。指定しないと元データと同じフォルダに"separated\モデル名\トラック名\ステム名.拡張子"で保存されます。

バッチファイルを直接実行する場合は-o指定しなくても良いですが、なぜかバッチファイルのショートカットを作成して、そこから実行すると出力先フォルダがバッチファイルのあるフォルダになってしまいます。そのため、`-o "%~dp1separated"` で未指定と同じになるように指定しています。

あと、ボーカル以外(いわゆるインスト・カラオケ)も欲しいので、`--two-stems=vocals`もつけて再実行しています。

ffmpegはoggへの変換と、変換データを元データと同じフォルダにコピーするためです。
BeatSaberの譜面データは、曲フォルダにsong.oggで曲データを保存するのが一般的なので、同じフォルダにステム毎に別れたoggファイルがあれば作譜ソフトで切り替えやすいので、こうしています。

flacやmp3化ならdemucsだけでできるので、ffmpegの処理を止めてdemucsに--flac, --mp3, --mp3-bitrate指定しても良いでしょう。

demucsのオプションの説明は[公式のREADME](https://github.com/facebookresearch/demucs)に説明がありますが、微妙に説明が足らないのでコマンドの--helpも読んだほうがよいです。DeepLで日本語訳したものを下記に乗せておきます。

| オプション | 説明 |
|:----------|------|
| -h, --help | このヘルプメッセージを表示して終了します。|
| -s SIG, --sig SIG | ローカルで学習されたXPのシグネチャ。|
| -n NAME, --name NAME | 事前学習されたモデル名またはシグネチャ。デフォルトは htdemucs |
| --repo REPO | -nで使用するすべての事前学習済みモデルを含むフォルダ。|
| -v, --verbose | |
| -o OUT, --out OUT | 抽出されたトラックを置くフォルダ。モデル名のサブフォルダが作成されます。|
| --filename FILENAME | 出力ファイル名を設定。"{track}", "{trackext}", "{stem}", "{ext}" を使用すると、拡張子なしのトラック名、トラック拡張子、ステム名、およびデフォルトの出力ファイル拡張子の変数を使用できます。デフォルトは "{track}/{stem}.{ext}"。|
| -d DEVICE, --device DEVICE | 使用するデバイス、デフォルトは利用可能なら cuda、そうでなければ cpu。|
| --shifts SHIFTS | 等変量安定化のためのランダムシフト数.分離時間は増えるが、Demucsの品質は向上。元の論文では10を使用。|
| --overlap OVERLAP | 分割の重なり。|
| --no-split | チャンクでオーディオを分割しません。これは大量のメモリを使う可能性があります。|
| --segment SEGMENT | 各チャンクの分割サイズを設定します。グラフィックカードのメモリを節約できます。|
| --two-stems STEM | 音声を {STEM} と no_{STEM} にのみ分割します。|
| --int24 | wav出力を24ビットwavとして保存します。|
| --float32 | float32としてwav出力を保存します（2倍大きい）。|
| --clip-mode {rescale,clamp} | クリッピングを避けるための戦略：必要に応じて信号全体を再スケーリングするか（rescale）、ハードクリッピングするか（clamp）。|
| --flac | 出力wavを flacに変換します。|
| --mp3 | 出力wavを mp3 に変換します。|
| --mp3-bitrate MP3_BITRATE | 変換後のmp3のビットレート。|
| -j JOBS, --jobs JOBS | ジョブの数。これはメモリ使用量を増加させますが、マルチコアが利用可能な場合はより高速になります。|

# 配布
全部準備ができたら、READMEを作成して、[ZIPで固めて配布](https://drive.google.com/drive/u/1/folders/1bm_OMCmlPIrX1vOgWgVwGNfBB4HrXUnA)します。

# 使い方
インストールはインストール用バッチファイルを実行するだけです。基本的にはCUDA1.18用の通常版`INSTALL_GPU_CUDA118.BAT`なら、CUDAが使えない場合はCPU動作になるので、誰でも問題なく動くはずです。

実行時は分離したい音楽データを、実行バッチファイルにドラッグ＆ドロップで貼り付けて実行します。ショートカットを作成しても動作するので、別の場所や[SendTo](https://atmarkit.itmedia.co.jp/ait/articles/1109/30/news131.html)にいれて、右クリックの送るから実行しても良いでしょう。