Windows で可搬性のある NNSVS 環境で遊ぶ mini-HOWTO

# はじめに
　[前回の記事](https://qiita.com/taroushirani/items/8706a2204924ab881b2f) では Windows 上で可搬性のある [NNSVS](https://github.com/r9y9/nnsvs) 環境を作成する方法について御紹介しました. しかし Unix ライクな環境に不慣れな方は MSYS2 を起動したあとに何をしたら良いのか途方に暮れるのではないかと思います. 本稿では前回作成した環境と [おふとん P 歌声データベース](https://sites.google.com/view/oftn-utagoedb/%E3%83%9B%E3%83%BC%E3%83%A0) を使用して NNSVS で遊ぶための簡単な HOWTO を提供します.

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

1.  前回の記事を読んで Windows 上で可搬性のある NNSVS 環境を作成できている
2.  Unix の簡単なコマンドがわかる, またはコマンドラインインターフェイスに抵抗感がない
3.  簡単なシェルスクリプト, python プログラムを読み書きできる
4.  ストレージにさらに 2GB 以上の空き領域がある


# データとレシピの準備
## MSYS2の起動と前準備

　まずは  msys64\msys2.exe を起動します. MSYS2 のターミナルエミュレータである mintty が立ち上がりますが, フォント設定を右クリック-[Options&#x2026;] で自分の好みに適宜変更してください. 私は [Ricty Diminished](https://github.com/edihbrandon/RictyDiminished) の 16pt に設定しています. 
　msys64 ディレクトリには他に mingw64.exe, mingw32.exe もありますが, これらと msys2.exe の違いはパスの設定で, それぞれ /mingw64/bin, /mingw32/bin が追加されています. NNSVS を利用する以外にも GNU 開発環境でアプリケーションの開発を行いたい場合はこちらを使用します (分からない場合は msys2.exe で大丈夫です).

![msys2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/657975/55dd8d14-384f-75d5-a506-40137960c5b5.png)


## おふとんP歌声データベースのダウンロードと展開
　[おふとんP 歌声データベース配布所](https://sites.google.com/view/oftn-utagoedb/%E3%83%9B%E3%83%BC%E3%83%A0) をウェブブラウザで開き利用規約を熟読したのち, OFUTON\_P\_UTAGOE\_DB.zip をダウンロードします.

```sh
curl -L -O https://www.dropbox.com/s/lsb007glrzztuvi/OFUTON_P_UTAGOE_DB.zip
```

ダウンロードした OFUTON_P_UTAGOE_DB.zip を ~/data 以下に展開します (~ や \$HOME は bash.exe によりホームディレクトリ(/home/<あなたの名前>)に展開されます). pacman で unzip をインストールしても良いですが, bsdtar で zip も展開できるのでそれを使います.

```sh
mkdir ~/data
bsdtar -xvf OFUTON_P_UTAGOE_DB.zip -C data
```

## おふとんP歌声データベース用のレシピのダウンロード(2020.11.18修正)
おふとんP歌声データベース用のレシピは2020.11.04にNNSVSの公式リポジトリにマージされました. それに伴いレシピ名も変更されています. 

github から再度 NNSVS をダウンロードします.

```sh
git clone https://github.com/r9y9/nnsvs 
```

　おふとんP歌声データベース用のレシピは実際には nnsvs/egs/ofuton\_p\_utagoe\_db/svs-world-conv/run.sh というシェルスクリプトの形で提供されます. まず nnsvs/egs/ofuton\_p\_utagoe\_db/svs-world-conv ディレクトリに移動します.

```sh
cd nnsvs/egs/ofuton_p_utagoe_db/svs-world-conv/
```

 おふとんP歌声データベースは上記の通りに操作すれば ~/data/OFUTON\_P\_UTAGOE\_DB に展開されているはずですが, [WinPython は MSYS2 のアプリケーションではないため POSIX パスを理解しない](https://qiita.com/taroushirani/items/8706a2204924ab881b2f#winpython-%E3%81%8C-msys2%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%83%91%E3%82%B9%E3%82%92%E7%90%86%E8%A7%A3%E3%81%97%E3%81%A6%E3%81%8F%E3%82%8C%E3%81%AA%E3%81%84) ので, config.yaml でデータベースの位置を指定している箇所を修正する必要があります. POSIX パスから Windows パスへの変換は [cygpath](https://cygwin.com/cygwin-ug-net/cygpath.html) を使うと便利です.

```sh
cygpath -m ~/data/OFUTON_P_UTAGOE_DB/
```
(出力)

    C:/<somewhere>/data/OFUTON_P_UTAGOE_DB/

　config.yaml を開いて 10 行目の db\_root を自分の環境に合わせて編集してください. 環境構築で git をインストールしたときに一緒に vim もインストールされていますが, Windows の notepad.exe も使えます.

　もしくは sed で以下のようにコマンドラインから編集することもできます.

```sh
sed -i "s#db_root:.*#db_root: \"$(cygpath -m ~/data/OFUTON_P_UTAGOE_DB)\"#g" config.yaml
```

# おふとんP歌声データベース用レシピを試す
## ステージ -1 (データのダウンロード) の実行
　ここからは基本的にレシピの提供するステージに沿って実行していきます. NNSVS ではステージ -1 はデータのダウンロードですが, 利用者に利用規約を確認する機会を提供するためにこのレシピではデータを自動的にダウンロードするようにはしていません. 予め上記の指示に従って利用規約を確認し OFUTON\_P\_UTAGOE\_DB.zip をダウンロードしておいてください.

　データのダウンロードを行わない代わりに, db\_root で設定された場所に展開された OFUTON\_P\_UTAGOE\_DB が見つからない場合はダウンロードを促すメッセージを出力するように変更してあります.

```sh
bash run.sh --stage -1 --stop-stage -1
```
　db_root の設定が正しい場合

    (出力無し)

　db_root で設定された場所にOFUTON_P_UTAGOE_DB が無い場合

    stage -1: Downloading

    This recipe does not download OFTON_P_UTAGOE_DB.zip to
    provide you the opportunity to read the original license.

    Please visit https://sites.google.com/view/oftn-utagoedb/%E3%83%9B%E3%83%BC%E3%83%A0"
    and read the term of services, and then download the singing voice database
    manually.


## ステージ 0 (データの準備)の実行
　おふとん P 歌声データベースのデータを NNSVS で扱いやすい形に整えます. レシピ中で python の文字変換ライブラリである [jaconv](https://github.com/ikegami-yukino/jaconv) を呼んでいる箇所があるので予め pip でインストールしておきます.

```sh
pip install jaconv
```

　おふとんP歌声データベースのレシピでは [fastdtw](https://github.com/slaypni/fastdtw) というライブラリを使って musicxml から変換されたラベルファイルとデータベースに付属のラベルファイルの整合性を確保していますが, fastdtw は [インストールの方法によって同じデータでも結果が異なる](https://github.com/slaypni/fastdtw/issues/46) ようです. 以下の内容を test\_fastdtw.py という名前で保存して実行した際に望ましい結果が得られない場合は fastdtw をインストールし直す必要があります. 詳細は前回の記事の [fastdtw のインストール](https://qiita.com/taroushirani/items/8706a2204924ab881b2f#fastdtw-%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E8%BF%BD%E8%A8%98-20200915) を参照してください.

```python:test_fastdtw.py
from fastdtw import fastdtw
    
x = [1, 6, 6, 33, 35]
y = [1, 6, 6, 33, 35]
    
d, path = fastdtw(x, y, radius=len(x))
    
print(f"d: {d}")
print(f"path: {path}")
```

```sh
python test_fastdtw.py
```

　望ましい出力

    d: 0.0
    path: [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]

　望ましくない出力

    d: 0.0
    path: [(0, 0), (1, 1), (1, 2), (2, 2), (3, 3), (4, 4)]

　fastdtw に問題がなければ ステージ 0 を実行します

```sh
bash run.sh --stage 0 --stop-stage 0
```

## ステージ 1 (タイムラグ, 継続長, 言語特徴量, 音響特徴量の抽出) の実行
　歌声合成に必要なタイムラグ, 継続長, 言語特徴量, 音響特徴量を抽出します. 

```sh
bash run.sh --stage 1 --stop-stage 1
```

## ステージ 2-4 (タイムラグモデル, 継続長モデル, 音響モデルの学習) の実行
　ここまでは特に GPU を必要としない処理でしたが, ここからは GPU が CUDA を使えると処理が高速になります. ステージ 2 がタイムラグモデル, ステージ 3 が継続長モデル, ステージ 4 が音響モデルの学習になります. GPU を使用しない場合, 例えば筆者のサブノートPC(CPU: Intel Core m3-7Y30, メモリ: 8GB, GPU: Intel HD Graphics 615) でステージ 2 は約 6 分, ステージ 3 は約 12 分, ステージ 4 は約2時間30分くらいかかります(因みにメインPCの NVidia GeForce RTX 2080 Ti ではそれぞれ約 3 分, 4 分, 8 分).

```sh
bash run.sh --stage 2 --stop-stage 4
```

## ステージ 5-6 (学習したモデルの出力と歌声合成) の実行
　ステージ 5 は学習したモデルを使用したパラメータの出力, ステージ 6 が学習したモデルを使った歌声合成になります.

```sh
bash run.sh --stage 5 --stop-stage 6
```
　ステージ6を実行すると, レシピで学習の評価用に設定されている曲(おふとんP歌声データベース用のレシピではharuga\_kita, kagome\_kagome)の歌声が合成されます. 合成結果は exp/ofuton\_p/synthesis 以下に出力されます. 


## 学習したモデルを使って任意の楽譜で歌声合成する
　NNSVS の多くのレシピでは nnsvs-synthesis に学習したモデルと楽譜から変換したラベルファイルを渡すことで歌声合成を行います. nnsvs-synthesis は以下の 2 通りの入力を受け付けます.

1.  合成するラベルファイルのリスト(utt\_list)とそのファイルがあるディレクトリ(in\_dir)と出力先のディレクトリ(out\_dir)
2.  合成するラベルファイル(label\_path)と出力先(out\_wav\_path)

ここでは 2 の方法を試してみましょう. 

まず musicxml をラベルファイルに変換するプログラムを作成します. 下記の内容を xml2lab.py という名前で保存してください.

```python:xml2lab.py
#! /usr/bin/env python
    
import pysinsy
import sys
import yaml

with open('config.yaml', 'r') as yml:
    config = yaml.load(yml, Loader=yaml.FullLoader)
    
if len(sys.argv) != 3:
    sys.exit("xml2lab.py input_filename output_filename")
input_filename=sys.argv[1]
output_filename=sys.argv[2]
    
sinsy = pysinsy.sinsy.Sinsy()
assert sinsy.setLanguages("j", config["sinsy_dic"])
    
assert sinsy.loadScoreFromMusicXML(input_filename)
is_mono = False
labels = sinsy.createLabelData(is_mono, 1, 1).getData()
with open(output_filename, "w") as f:
    f.write("\n".join(labels))
sinsy.clearScore()
```

　作成した xml2lab.py を使って musicxml ファイルをラベルファイルに変換します. 適当な musicxml ファイルが見付からない場合は著作権の切れている楽譜として[宮沢賢治の星めぐりの歌](https://drive.google.com/file/d/1spDUrZUh5vPsVoFZPyevxGFF4zw_Ux6Q/view?usp=sharing) を用意しましたのでご利用ください.

```sh
curl -L -o hoshi_meguri_no_uta_8vb.musicxml "https://drive.google.com/uc?export=download&id=1spDUrZUh5vPsVoFZPyevxGFF4zw_Ux6Q"
python xml2lab.py hoshi_meguri_no_uta_8vb.musicxml hoshi_meguri_no_uta_8vb.lab
```

　あとはレシピのステージ 6 と同様に nnsvs-synthesis に学習したモデルとラベルファイルを渡すだけです. ちょっとコマンドが長いですが, 楽譜に合わせて変更しなければいけないのは最後の2行だけです.

```sh
spk=ofuton_p;expname=$spk;expdir=exp/$expname;dumpdir=dump; \
dump_norm_dir=$dumpdir/$spk/norm; ground_truth_duration=false; \
nnsvs-synthesis question_path=../../_common/hed/jp_qst001_nnsvs.hed \
timelag.checkpoint=$expdir/timelag/best_loss.pth \
timelag.in_scaler_path=$dump_norm_dir/in_timelag_scaler.joblib \
timelag.out_scaler_path=$dump_norm_dir/out_timelag_scaler.joblib \
timelag.model_yaml=$expdir/timelag/model.yaml \
duration.checkpoint=$expdir/duration/best_loss.pth \
duration.in_scaler_path=$dump_norm_dir/in_duration_scaler.joblib \
duration.out_scaler_path=$dump_norm_dir/out_duration_scaler.joblib \
duration.model_yaml=$expdir/duration/model.yaml \
acoustic.checkpoint=$expdir/acoustic/best_loss.pth \
acoustic.in_scaler_path=$dump_norm_dir/in_acoustic_scaler.joblib \
acoustic.out_scaler_path=$dump_norm_dir/out_acoustic_scaler.joblib \
acoustic.model_yaml=$expdir/acoustic/model.yaml \
ground_truth_duration=$ground_truth_duration \
label_path=hoshi_meguri_no_uta_8vb.lab \
out_wav_path=hoshi_meguri_no_uta_8vb.wav 
```

　歌声合成できましたか? 参考までにここで合成したサンプルを[SoundCloud](https://soundcloud.com/) にアップロードしておきます([nnsvs\_ofuton\_p\_utagoe\_db\_00\_svs\_world\_hoshi\_meguri\_no\_uta\_8vb](https://soundcloud.com/user-883019797/hoshi-meguri-no-uta-8vb)). 


# おわりに
　2 回に分けて Windows 上で NNSVS を使う方法について解説しましたが, いかがでしたでしょうか. [拙作の Google Colaboratory 用の Jupyter Notebook](https://gist.github.com/taroushirani/987211cc4023eab174b71bfe7041fd95) で遊んだ経験のある方は, あちらが最短でわずか数回のクリックで歌声合成まで辿り着くのに比べてあまりの煩雑さに閉口されたかと思います. しかし自分の PC では Google Colaboratory のような時間制限もなく, 一度歌声合成に必要な特徴量を抽出してしまえば何回でも歌声合成が可能で, レシピや学習モデルを自分の好みに変えるなど様々な実験もし易いです. また学習済みモデルを用意してそれらのモデルと楽譜を nnsvs-synthesis に渡すような GUI アプリケーションも作成可能だと思います. 御自分の目的に合わせて適宜工夫してみてください.

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