Windows で可搬性のある NNSVS 環境を作る mini-HOWTO

# はじめに

　[御丹宮くるみさんの歌声](https://www.nicovideo.jp/watch/sm37452833), かわいいですよね. さて [前回の記事](https://qiita.com/taroushirani/items/ec16cb9a6b3b691f5e74) では [Google Colaboratory](https://colab.research.google.com/notebooks/welcome.ipynb?hl=ja) で [NNSVS](https://github.com/r9y9/nnsvs) を利用する方法について御紹介しましたが, 実験を進めていくにあたって学習モデルを時間がかかるものに変更したり複数の歌声データベースを使い分けたりすると, Google Colaboratory の連続使用時間の制限や Google Drive の容量制限が問題になってきます. 
　そうするとやはり自分の PC で実験したいと考えるのが自然な流れですが, Windows 上で GPU を使うことのできる python のうち [公式の python](https://www.python.org/) や [Anaconda (Minoconda)](https://www.anaconda.com/) はインストーラがレジストリに色々登録するタイプのアプリケーションであり, 複数の環境を併存させるのが難しく他人に環境構築を勧め辛いという問題がありました. また python の可搬性のある実装である Embeddable Python (参考:[超軽量, 超高速な配布用 Python 「 embeddable python 」 (Qiita 上の紹介記事)](https://qiita.com/mm_sys/items/1fd3a50a930dac3db299)) はインストールに C/C++ コンパイラを必要とするような python ライブラリをインストールできず, NNSVS に必要なライブラリの導入ができませんでした.
　しかし先日可搬性のある python のもう一つの実装である [WinPython](https://winpython.github.io/) を知り, また折良く以前は不可能であった Windows 上での [Pysinsy](https://github.com/taroushirani/pysinsy) のビルドに成功しました. これと [MSYS2](https://www.msys2.org/) と組み合わせることで NNSVS で GPU を使用して学習から歌声合成まで実行できる環境の構築に成功しましたので, 御紹介致します.

　想定している読者は次の通りです. 

1.  Windows のコマンドプロンプトや Unix の簡単なコマンドがわかる, またはコマンドラインインターフェイスに抵抗感がない
2.  簡単なバッチファイルやシェルスクリプト, python プログラムを読み書きできる
3.  Windows 10 64bit RS4 (1803) 以降を使用している (WinPython や MSYS2 のダウンロードや展開に curl や tar を使用するため. 他の解凍ソフトを準備するならそれ以前の Windows 10 でも構築可能かもしれません)
4.  ストレージに 4GB 以上の空き領域がある

# 前準備
## [Visual Studio Build Tools 2019](https://visualstudio.microsoft.com/visual-cpp-build-tools/) と [Windows 10 SDK 10.0.14393.0](https://developer.microsoft.com/windows/downloads/sdk-archive/) のインストール (必須)
　NNSVS が依存している python ライブラリの中にはインストール時に Microsoft Visual Studio 14 2015 を必要とするものがあります. これは Microsoft が無償で配布している [Visual Studio Build Tools 2019](https://visualstudio.microsoft.com/visual-cpp-build-tools/) から利用可能です (他に [Visual Studio 2019 Community](https://visualstudio.microsoft.com/downloads/) も利用できます). しかし必要なプログラムがいくつかのパッケージに分散しているため, インストール時には注意が必要です.

1.  "MSVC v140 - VS 2015 C++ ビルド ツール (v14.00)" は Visual Studio 14 2015 のツール相当を含んでいますが, MSBuild.exe を含んでいません.
2.  "MSVC v142 - VS 2019 C++ x64/x86 ビルド ツール (v14.27)" は MSBuild.exe を含んでいます.
3.  Microsoft Visual Studio 14 2015 が Windows 10 上で扱える Windows 10 SDK の最終バージョンは 10.0.14393.0 であるようです (参考: [VS: Do not select a Windows SDK too high for current VS version (!2388) · Merge Requests · CMake / CMake · GitLab](https://gitlab.kitware.com/cmake/cmake/-/merge_requests/2388)). これは [Windows SDK archive](https://developer.microsoft.com/windows/downloads/sdk-archive/) からダウンロードできますが, rc.exe を含んでいません.
4.  最新版の Windows 10 SDK (10.0.18362.0) は rc.exe を含んでいます.

　Visual Studio Build Tools 2019 をインストールする際には, "MSVC v142 - VS 2019 C++ x64/x86 ビルド ツール (v14.27)", "Windows 10 SDK (10.0.18362.0)", "Windows 用 C++ CMake ツール", "MSVC v140 - VS 2015 C++ ビルド ツール (v14.00)" に忘れずにチェックを入れるようにしてください.

![visual_studio_buid_tool.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/657975/3f2451a0-0e84-fb78-4510-23dd2e395376.png)

## [NVidia CUDA Toolkit (10.1/10.2)](https://developer.nvidia.com/cuda-toolkit) と[NVIDIA cuDNN](https://developer.nvidia.com/cudnn)のインストール (推奨)
　環境構築に必須ではありませんが, GPU が CUDA を使用可能であると NNSVS の学習が高速になります. NNSVS が使用している深層学習用のフレームワークである [PyTorch](https://pytorch.org/) は CUDA 10.1 と CUDA 10.2 を使用可能です. 2020年9月現在 [PyTorch における CUDA11.0 はまだバイナリパッケージが準備されていないこと](https://discuss.pytorch.org/t/pytorch-with-cuda-11-compatibility/89254) に注意してください (ソースファイルから手動でインストールすることは可能なようです). また使用する CUDA のバージョンに合わせて cuDNN もインストールしてください.


# 環境構築
　ここからはコマンドラインインターフェイスで操作していきます. Windows のメニューから [Visual Studio 2015] → [VS2015 x64 Native Tools コマンドプロンプト] を選択し NNSVS 環境を構築したいディレクトリにカレントディレクトリを変更してください. 通常のコマンドプロンプトも使用できますが, Visual Studio 14 2015 のツールが使用できるように環境変数 INCLUDE, LIB, LIBPATH を自分で設定する必要があります. コマンドプロンプトにおけるカレントディレクトリの変更は CD/CHDIR を使います (Web 上に情報が沢山あるので分からない場合は調べてください).
![windows_menu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/657975/37609c7b-d3d6-4285-33c9-3e0df9688c87.png)

## WinPython, MSYS2 のダウンロードと展開から MSYS2 の初期化まで
### WinPython のダウンロードと展開
　[WinPython の公式ページ](https://winpython.github.io/) から python 3.8 のみを含んだ最小構成である [WinPython64-3.8.5.0dot.exe](https://github.com/winpython/winpython/releases/download/3.0.20200808/Winpython64-3.8.5.0dot.exe) をダウンロードします.

```cmd
curl -L -o winpython.exe https://github.com/winpython/winpython/releases/download/3.0.20200808/Winpython64-3.8.5.0dot.exe
```

winpython.exe は自己展開形式の 7-zip アーカイブです. 現在のディレクトリに解凍します. 

```cmd
winpython.exe -C. -y
```

### MSYS2 のダウンロードと展開
　[sourceforge](https://sourceforge.net/projects/msys2/files/Base/x86_64/) から [msys2-base-x86\_64-20200903.tar.xz](https://sourceforge.net/projects/msys2/files/Base/x86_64/msys2-base-x86_64-20200903.tar.xz/download) をダウンロードします.

```cmd
curl -L -o msys2.tar.xz https://sourceforge.net/projects/msys2/files/Base/x86_64/msys2-base-x86_64-20200903.tar.xz
```

tar.xz ファイルの展開は Windows の標準ソフトウェアのみでは不可能ですが, 先程ダウンロードした python に tarfile モジュールがあるのでこれを利用します. 以下の内容を extract\_tar\_xz.py というファイル名で現在のディレクトリに保存します.

```python:extract_tar_xz.py
import sys
import tarfile

if(len(sys.argv) != 3):
    print("extract_tar_xz archive_file destination")
    sys.exit(-1)
    
tar = tarfile.open(sys.argv[1])
tar.extractall(sys.argv[2])
tar.close()
````

　先程展開した WinPython で extract\_tar\_xz.py を実行して msys2.tar.xz を展開します.

```cmd
WPy64-3850\python-3.8.5.amd64\python.exe extract_tar_xz.py msys2.tar.xz .
```

### WinPython の移動, MSYS2 の初期化

　MSYS2 から WinPython を利用しやすいように WinPython を MSYS2 の /opt に移動します.

```cmd
move WPy64-3850\python-3.8.5.amd64 msys64\opt\python
```

　MSYS2 を初回起動して初期化します (1 分ほどかかります). (追記:2020/09/14 msys2_shell.cmd を使用するように変更しました).

```cmd
msys64\msys2_shell.cmd -mingw64 -defterm -no-start -c /bin/false 
```

　先程移動した WinPython を MSYS2 から利用しやすいように, bash のユーザ共通の環境設定である /etc/bash.bashrc に PATH の設定を追加します.

```cmd
echo export PATH=/opt/python:/opt/python/Scripts:$PATH >> msys64\etc\bash.bashrc
```

## pacman の初期化 から NNSVS と関連ライブラリのインストール, クリーンアップまで

　ここまではコマンドプロンプト上の操作でしたが, ここからは MSYS2 の bash で作業します. 以下のコマンドで MSYS2 の bash を起動します. (追記:2020/09/14 msys2_shell.cmd を使用するように変更しました).

```cmd
msys64\msys2_shell.cmd -mingw64 -defterm -no-start
```


### pacman の初期化とアップデート

　MSYS2 で採用されているパッケージマネージャである pacman を初期化します.

```sh
pacman-key --init
```

　続いて pacman のリポジトリをアップデートします.

```sh
pacman -Syuu --noconfirm
```

### git のインストール

pacman で git をインストールします.

```sh
pacman -Su --noconfirm git
```
### pip のアップグレード(追記: 2020/09/15)
　pip で python ライブラリを追加していく前に, まずは pip をアップグレードします.

```sh
python -m pip install -U pip
```

### numpy, cython のインストール

　pip で numpy, cython をインストールします.

```sh
pip install -U numpy cython
```

### PyTorchのインストール
　pip で PyTorch をインストールします. 使用する CUDA に合わせてインストールするバージョンを変更してください.

(2020.11.08追記) [Shallow ARモデルがマージされた](https://github.com/r9y9/nnsvs/commit/dd62ecbef634106196c5ecbfe94fb2771f02eaa4) のに伴いtorchaudioが必要になります. 既に環境を構築済みの方はお使いの CUDA のバージョンに合わせて torchaudio をインストールしてください.

- CUDA 10.2用

```sh
pip install torch===1.7.0 torchvision===0.8.1 torchaudio===0.7.0 -f https://download.pytorch.org/whl/torch_stable.html
```

- CUDA 10.1用

```sh
pip install torch==1.7.0+cu101 torchvision==0.8.1+cu101 torchaudio===0.7.0 -f https://download.pytorch.org/whl/torch_stable.html
```

- CUDA なし

```sh
pip install torch==1.7.0+cpu torchvision==0.8.1+cpu torchaudio===0.7.0 -f https://download.pytorch.org/whl/torch_stable.html
```

### pysptk のインストール
　pysptk はインストールに C/C++ コンパイラが必要なライブラリです. MSYS2 からも Visual Studio 14 2015 のツール等が見えるように PATH を設定し直します. この設定では Visual Studio Build Tools 2019 を使う場合と Visual Studio 2019 Community を使う場合の設定が両方含まれていますが, 自分の環境に合わせて適宜変更してください.

```sh
export PATH=/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio/2019/BuildTools/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/bin:/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio/2019/BuildTools/MSBuild/Current/Bin/amd64/:/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio/2019/Community/Common7/IDE/CommonExtensions/Microsoft/CMake/CMake/bin/:/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio/2019/Community/MSBuild/Current/Bin/amd64/:/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio\ 14.0/VC/bin/amd64:/c/Program\ Files\ \(x86\)/Windows\ Kits/10/bin/10.0.14393.0/x64/:/c/Program\ Files\ \(x86\)/Windows\ Kits/10/bin/10.0.18362.0/x64/:$PATH
pip install pysptk
```
### bandmat のインストール

　bandmat は [python3.7 以降で pip から自動でインストールできない](https://github.com/MattShannon/bandmat/issues/10) という問題があります. bandmat の git リポジトリを取得してインストールします. 以降 /tmp に移動して作業します.

```sh
cd /tmp
git clone https://github.com/MattShannon/bandmat.git
cd bandmat && pip install . 
cd /tmp
````

### fastdtw のインストール(追記: 2020/09/15)
　[fastdtw](https://github.com/slaypni/fastdtw) は [インストールの方法によって同じデータでも結果が異なる](https://github.com/slaypni/fastdtw/issues/46) ようです.  Visual Studio 14 2015 でコンパイルされたバージョンがインストールされるように, [私が fork した fastdtw](https://github.com/taroushirani/fastdtw) の [vs\_2015 ブランチ](https://github.com/taroushirani/fastdtw/tree/vs_2015) を使用します.

```sh
git clone -b vs_2015 https://github.com/taroushirani/fastdtw.git
cd fastdtw && pip install . 
cd /tmp
````

### nnmnkwii, NNSVS のインストール
　nnmnkwii, NNSVS をインストールします. 最新版をインストールするために pip による自動インストールではなく git リポジトリを取得してインストールします.

```sh
git clone https://github.com/r9y9/nnmnkwii
cd nnmnkwii && pip install . && cd /tmp
git clone https://github.com/r9y9/nnsvs 
cd nnsvs && pip install . && cd /tmp
```

### hts\_engine\_API, Sinsy のビルド
　Pysinsy のインストールに必要な [hts\_engine\_API](http://hts-engine.sourceforge.net/), [Sinsy](http://sinsy.sourceforge.net/) をビルドします. それぞれ公式からのリリースではなく NNSVS の作者である Ryuichi Yamamoto 氏の fork を使います.  
　Linux 上で gcc を使って共有ライブラリをビルドするのと異なり, Visual Studio は \_\_declspec (dllexport) が宣言された関数が無いとインポートライブラリを生成しません. そのため Windows 上では -DBUILD\_SHARE\_LIBS=ON を渡して生成された共有ライブラリ(sinsy.dll)を pysinsy のビルドに使うことができません. -DBUILD\_SHARED\_LIBS=OFF として静的ライブラリを生成します.

```sh
git clone https://github.com/r9y9/hts_engine_API
cd hts_engine_API/src && mkdir -p build && cd build && cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX=/opt/hts_engine_API .. && make -j > hts_engine_API_build.log 2>&1 &&  make install && cd /tmp
```

```sh
git clone  -q https://github.com/r9y9/sinsy
cd sinsy/src/ && mkdir -p build && cd build 
cmake -G "Visual Studio 14 2015 Win64" -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX=/opt/sinsy -DHTS_ENGINE_INCLUDE_DIR=/opt/hts_engine_API/include/ -DHTS_ENGINE_LIB=/opt/hts_engine_API/lib/hts_engine_API.lib ..
cmake --build . --config Release 
cmake -DCMAKE_INSTALL_CONFIG_NAME=Release -P cmake_install.cmake
cd /tmp
```

### Pysinsy のインストール
　Pysinsy をインストールします. Sinsy を静的にリンクするように変更したため, 本来 sinsy.dll が呼ぶはずだった hts\_engine\_API を明示的にリンクする必要があります. 私が fork した pysinsy の vc\_2015 ブランチにその修正が含まれているので使用します.

```sh
git clone -b vc_2015 https://github.com/taroushirani/pysinsy.git
cd pysinsy
SINSY_INSTALL_PREFIX=/opt/sinsy/ HTS_ENGINE_API_INSTALL_PREFIX=/opt/hts_engine_API/ pip install .
cd /tmp
```

### hts\_engine\_API-1.dll のコピー
　Python では python モジュールの共有ライブラリ (.pyd ファイル) は sys.path で設定された検索パスが使われますが, それらの python モジュールが依存している外部の DLL は OS の環境変数 PATH で設定された検索パスが使われます. hts\_engine\_API-1.dll を PATH で設定されたディレクトリのどこかにコピーします (ここでは /opt/python).

```sh
cp /opt/hts_engine_API/lib/hts_engine_API-1.dll /opt/python/
```

### クリーンアップと pnew - Portable NNSVS environment for Windows の紹介

　MSYS2ではLinuxと違い /tmp 以下が定期的にクリーンアップされないので, 手動で不要になったファイルを削除します

```
rm -rf /tmp/bandmat /tmp/nnmnkwii /tmp/pysinsy /tmp/hts_engine_API /tmp/nnsvs /tmp/sinsy
```

　以上で環境構築は終了です. お疲れさまでした! コマンドプロンプトを閉じて msys64\msys2.exe を起動すればそこは NNSVS が使える Unixライクな開発環境です!  

　見ての通り手順が煩雑なので, これを自動化するために [pnew](https://github.com/taroushirani/pnew) というリポジトリを作成しました. 上述の前準備のあとに環境構築したいディレクトリに pnew をダウンロードして, VS2015 x64 Native Tools コマンドプロンプト上から bootstrap.bat を実行すれば最初の WinPython, MSYS2 のダウンロードから最後のクリーンアップまで全自動で行います. 行っている内容はほぼ上で説明した通りなので, カスタマイズしたりエラーが発生した場合は参考にしてください.

# 既知の問題点と対策
　MSYS2 はあくまで Unix ライクな開発環境を提供するものであり Unix そのものではないので, それに起因する問題がいくつかあります.

## mintty から WinPython を対話モードで利用できない
MSYS2 由来ではない Windows のコンソールアプリケーションと Unix の仮想端末の非互換性を吸収してくれる [winpty](https://github.com/rprichard/winpty) というソフトウェアが必要になります. pacman で winpty をインストールして, python の前に winpty を付けて起動してください (他の Windows コンソールアプリケーションも同じです).

```sh
pacman -Su winpty
winpty python
```

## tar jxvf が途中で止まってしまう
　MSYS2 には標準で [GNU tar](https://www.gnu.org/software/tar/) ではなく [bsdtar](https://www.libarchive.org/) がインストールされています. 従って MSYS2 から tar を呼ぶと Windows の tar が呼ばれます (これも由来は bsdtar). そして Windows の tar は MSYS2 の bzip2 と相性が悪いのか, tar に -j オプションをつけると展開の途中で tar がスリープしてしまい反応しなくなるようです. これは nit-song070 や jsut-song のレシピのステージ -1 でダウンロードした HTS-demo\_NIT-SONG070-F001.tar.bz2 を展開するときに問題になります. run.sh を修正して tar ではなく bsdtar を呼ぶか, pacman で GNU tar をインストールするか, alias tar=bsdtar のようにエイリアスを設定することをお勧めします.

## シンボリックリンクが作成できない
　MSYS2 はデフォルトではシンボリックリンクが作成できません. NNSVS の公式に含まれているレシピのうち nit-song070, jsut-song, pjs は conf/jp\_qst001\_nnsvs.hed を kiritan\_singing のものとシンボリックリンクで共有しているので, これらのレシピのステージ 1 を実行すると conf/jp\_qst001\_nnsvs.hed が読めずエラーになります. また kiritan\_singing のレシピもステージ 0 でシンボリックリンクを設定している箇所がありエラーになります. 環境変数 MSYS を書きかえて, ユーザに適切な権限を設定する (参考: [MSYS2 でシンボリックリンクを作れるようにしてみた](https://qiita.com/shinyay/items/587fd5cc19033c1bad82)) か, シンボリックリンクを使っている場所を通常のコピーに手作業で修正する必要があります.

## WinPython が MSYS2のファイルパスを理解してくれない

WinPython は元々 MSYS2 のアプリケーションではないため, POSIX ファイルパスを理解しません. 例えば Sinsy 用の辞書ファイルは MSYS2 上では /opt/sinsy/lib/sinsy/dic にインストールされていますが, これを WinPython に直接渡すとエラーになります.

```python
import pysinsy
sinsy = pysinsy.sinsy.Sinsy()
assert sinsy.setLanguages("j", "/opt/sinsy/lib/sinsy/dic")
```

(出力)

    [ERR] Cannot open phoneme table file : /opt/sinsy/lib/sinsy/dic/japanese.utf_8.t
    able
    [ERR] Cannot read phoneme table file : /opt/sinsy/lib/sinsy/dic/japanese.utf_8.t
    able
    [ERR] Cannot read Japanese table or config or macron file : /opt/sinsy/lib/sinsy
    /dic/japanese.utf_8.table, /opt/sinsy/lib/sinsy/dic/japanese.utf_8.conf
    Traceback (most recent call last):
    : File "<stdin>", line 1, in <module>
    AssertionError

　MSYS2 には [Cygwin](https://cygwin.com/) 由来の [cygpath](https://cygwin.com/cygwin-ug-net/cygpath.html) があるので, それで POSIX ファイルパスを Windows のファイルパスに変換します.

```sh
cygpath.exe -m /opt/sinsy/lib/sinsy/dic
```

(出力)

    C:/<somewhere>/msys64/opt/sinsy/lib/sinsy/dic

```python
import pysinsy
sinsy = pysinsy.sinsy.Sinsy()
assert sinsy.setLanguages("j", "C:/<somewhere>/msys64/opt/sinsy/lib/sinsy/dic")
````

(出力)

    (エラーなし)


# おわりに
　Windows で可搬性のある NNSVS 環境を作る方法を簡単に解説しました. 今回作成した環境は完全に動作する Unix ライクな開発環境と完全に動作する python 一式を含んでおり, 使用するディスク容量が 3.1GB, zip で圧縮しても 1.7GB とかなり大きなものですが, その代わり深層学習の学習から推論までこなせる汎用性の高いものになっています. 
　今回は後からプログラムを追加する際の容易さから MSYS2 を選択しましたが, 他の開発ツールが不要であれば MSYS2 を [Git Bash](https://gitforwindows.org/) に変更する, または環境構築したあとは MSYS2 部分を削除して Windows に付属している PowerShell から WinPython を使うといった運用も考えられると思います. 御自分の用途に合わせて適宜工夫してみてください.

# 関連記事
- [Google Colaboratory で NNSVS で遊ぶ mini-HOWTO](https://qiita.com/taroushirani/items/ec16cb9a6b3b691f5e74) (2020/06/18)
- [Windows で可搬性のある NNSVS 環境で遊ぶ mini-HOWTO](https://qiita.com/taroushirani/items/26658cb691b8e5fcd698) (2020/09/16)