SqueezeWave 動作メモ(CUDAとROCｍで推論を試す）

https://qiita.com/T_keigo_wwk/private/6f08a7079dbd8297af1d

上記ドキュメントのGPU版です、

#目的
CPUで動かすとcode中のaudio tensorがnanになってしまい音声が出力されないのでGPUでも再現されるか確認する
CUDA10.0環境が必須なのでnvidia-docker環境の構築メモも兼ねる

#環境構築
docker環境とnvidia-docker2が既にインストール済みであることが前提条件になります
テスト環境はCUDA10.01 + RTX2080TI


ホストマシンのホームディレクトリにリポジトリをclone


```
git clone https://github.com/tianrengao/SqueezeWave.git
cd SqueezeWave 
git submodule init
git submodule update
```


[トレーニング済みモデル](https://drive.google.com/file/d/1RyVMLY2l8JJGq_dCEAAd8rIRIn_k13UB/view?usp=sharing)
[mel-spectrograms](https://drive.google.com/file/d/1g_VXK2lpP9J25dQFhQwx7doWl_p20fXA/view?usp=sharing)

をダウンロードしてunzipで解凍

ここまではCPU版と同じようにやります。

nvidia-dockerを使ったのでdockerfileを以下のように書きました

```
FROM nvidia/cuda:10.0-cudnn7-runtime

RUN apt update && apt install -y python3-pip
RUN apt install -y git
RUN git clone https://www.github.com/nvidia/apex
WORKDIR ./apex
RUN pip3 install torch==1.0 matplotlib==2.1.0 numpy==1.13.3 inflect==0.2.5 librosa==0.6.0 scipy==1.0.0 tensorboardX==1.1 Unidecode==1.0.22
RUN python3 setup.py install
tensorboardX==1.1 Unidecode==1.0.22

```

任意のディレクトリにdockerfileを保存して


```
$ sudo docker build . -t squeezewave 
```
#NVIDIA Dockerで実行

次にdocker runします、ホストマシンのディレクトリをマウントしているのがポイントです

```
$ sudo docker run    --runtime=nvidia --rm     -it -v /home/{HOMEディレクトリ名}/SqueezeWave:/SqueezeWave             squeezewave:latest

```

コンテナに入ったら

```
# cd /SqueezeWave/
#  python3 inference.py -f <(ls mel_spectrograms/*.pt) -w pretrain_models/L64_large_pretrain  -o .  -s 0.6
/usr/local/lib/python3.6/dist-packages/torch/serialization.py:434: SourceChangeWarning: source code of class 'glow.SqueezeWave' has changed. you can retrieve the original source code by accessing the object's source attribute or set `torch.nn.Module.dump_patches = True` and use the patch tool to revert the changes.
  warnings.warn(msg, SourceChangeWarning)
/usr/local/lib/python3.6/dist-packages/torch/serialization.py:434: SourceChangeWarning: source code of class 'glow.WN' has changed. you can retrieve the original source code by accessing the object's source attribute or set `torch.nn.Module.dump_patches = True` and use the patch tool to revert the changes.
  warnings.warn(msg, SourceChangeWarning)
THCudaCheck FAIL file=/pytorch/aten/src/THC/THCGeneral.cpp line=405 error=11 : invalid argument
./LJ001-0015.wav_synthesis.wav
./LJ001-0051.wav_synthesis.wav
./LJ001-0063.wav_synthesis.wav
./LJ001-0072.wav_synthesis.wav
./LJ001-0079.wav_synthesis.wav
./LJ001-0094.wav_synthesis.wav
./LJ001-0096.wav_synthesis.wav
./LJ001-0102.wav_synthesis.wav
./LJ001-0153.wav_synthesis.wav
./LJ001-0173.wav_synthesis.wav

```

で推論できます
実行時間は2080Tiでreal 0m9.784sでした、ひとまずGPUでは最低限動くことがわかりました。

https://soundcloud.com/zsjzuobwha2e/sets/squeezewave-inferencepy-output-sound
データはこちらにあります

```--is_fp16```でFP16を有効にした場合でもreal 0m10.042sだったので性能差はそれほどない感じでした


#ROCm-Dockerでやってみる

ROCm3.1+RadeonⅦでやってみます

Dockerfileは以下の通り

```
FROM rocm/pytorch:rocm3.0_ubuntu16.04_py3.6_pytorch

RUN apt update && apt install -y python3-pip
RUN apt install -y git
#RUN git clone https://www.github.com/nvidia/apex
#WORKDIR ./apex
RUN pip3 install  matplotlib==2.1.0 numpy==1.13.3 inflect==0.2.5 librosa==0.6.0 scipy==1.0.0 tensorboardX==1.1 Unidecode==1.0.22
#RUN python3 setup.py install
#RUN pip3 install torch==1.0 matplotlib==2.1.0 numpy==1.16.2 inflect==0.2.5 librosa==0.6.0 scipy==1.0.0 tensorboardX==1.1 Unidecode==1.0.22
```

```
$  sudo docker build . -t rocm-squeezewave 
$ sudo   docker run --name pytroch_rocm -it  --privileged --rm --device=/dev/kfd --device=/dev/dri --group-add video  -v /home/{ホームディレクトリ名}/SqueezeWave:/SqueezeWave rocm-squeezewave
$ cd /SqueezeWave/
$  python3.6 inference.py -f <(ls mel_spectrograms/*.pt) -w pretrain_models/L64_large_pretrain  -o .  -s 0.6
```

最低限途中のaudio tensorの生成をするぐらいはできる.

```python
tensor([[[ 0.1525,  0.7336,  0.6206,  ..., -0.4970, -0.6939,  0.8375],
         [-0.0091,  0.4194,  0.7400,  ..., -0.1548, -0.1589,  0.9829],
         [ 0.1160, -0.0903,  0.3936,  ...,  0.4681, -0.8460,  0.1797],
         ...,
         [ 2.7151,  0.2097, -1.7632,  ..., -0.4245,  0.3499, -0.3599],
         [-0.8716, -0.1110,  0.3357,  ..., -0.5838,  0.1851, -1.3772],
         [ 0.2319,  0.9468, -0.4212,  ..., -0.3868,  1.1623, -0.9812]]],
       device='cuda:0')
````
しかしNVIDIA CUDAでよく使われる線形代数ライブラリであるMAGMAライブラリ依存で実装されている部分がある為推論完走はならなかった

```py
Traceback (most recent call last):
  File "inference.py", line 89, in <module>
    args.sampling_rate, args.is_fp16, args.denoiser_strength)
  File "inference.py", line 58, in main
    audio = squeezewave.infer(mel, sigma=sigma).float()
  File "/SqueezeWave/glow.py", line 266, in infer
    audio = self.convinv[k](audio, reverse=True)
  File "/root/.local/lib/python3.6/site-packages/torch/nn/modules/module.py", line 539, in __call__
    result = self.forward(*input, **kwargs)
  File "/SqueezeWave/glow.py", line 104, in forward
    W_inverse = W.float().inverse()
RuntimeError: inverse: MAGMA library not found in compilation. Please rebuild with MAGMA.

```
MAGMAをどうにかROCｍで動かす方法を検討しないとダメみたいですね
ひとまず無理やりnumpyで置き換えて動かすことにしました。

glow.pyの104行目をコメントアウトする代わりに以下をついかして


```py
  testout= W.cpu().numpy()
  testout=np.linalg.inv(testout)
  W_inverse=torch.from_numpy(testout).to('cuda')
```

forward()を以下のような感じに書き換えると一応動きます、まあCPUに投げてるので邪道です


```python

    def forward(self, z, reverse=False):
        # shape
        batch_size, group_size, n_of_groups = z.size()
        W = self.conv.weight.squeeze()

        if reverse:
            if not hasattr(self, 'W_inverse'):
                # Reverse computation
                #W_inverse = W.float().inverse()
                testout= W.cpu().numpy()
                testout=np.linalg.inv(testout)
                W_inverse=torch.from_numpy(testout).to('cuda')
                W_inverse = Variable(W_inverse[..., None])
                if z.type() == 'torch.cuda.HalfTensor':
                    W_inverse = W_inverse.half()
                self.W_inverse = W_inverse
            z = F.conv1d(z, self.W_inverse, bias=None, stride=1, padding=0)
            return z
        else:
            # Forward computation
            log_det_W = batch_size * n_of_groups * torch.logdet(W)
            z = self.conv(z)
            return z, log_det_W

```

同じ条件下で./LJ001-0015.wav_synthesis.wavを一個生成するのに必要な所要時間は
ROCm RadeonⅦでreal 1m6.183s
CUDA RTX2080Tiでreal	0m9.138s
でした

明らかに実用性がない速度なので素直にCUDAを使ったほうがよさそげです。

#todo

CPUで動かないのを再検証する