tacotronについてのメモ

https://github.com/keithito/tacotron
TensorFlowでのTacotron音声合成の実装です。
cudaとrocmでtrainの動作テストをしたのですが色々あったので今後再現性を確保するためのメモとして残します

#環境を揃える

python仮想環境はminicondaを使用
ROCm versionは2.7
CUDA versionはV10.1.243 (Driver Version: 430.26 )

GPUはRadeonⅦとGTX1080TI


```
git clone https://github.com/keithito/tacotron
```
requirements.txt にかかれているバージョンが古いみたいなので若干修正

```
falcon
inflect
librosa
matplotlib
numpy
scipy
tqdm
Unidecode
```

データーセットの用意と下処理
LJ Speechデーターセットを今回は使用

```
wget https://data.keithito.com/data/speech/LJSpeech-1.1.tar.bz2
tar xf ./ LJSpeech-1.1.tar.bz2
python preprocess.py --dataset ljspeech
```

#rocmでの環境構築と動作


```
sudo apt update
pip install tensorflow-rocm==1.14.1
sudo apt-get update &&       sudo apt-get install -y --allow-unauthenticated       rocm-dkms rocm-dev rocm-libs       rocm-device-libs       hsa-ext-rocr-dev hsakmt-roct-dev hsa-rocr-dev       rocm-opencl rocm-opencl-dev       rocm-utils       rocm-profiler cxlactivitylogger       miopen-hip miopengemm
pip install -r ./requirements.txt 
```

どうもrocm1.13.1では動かず1.14.1でテストを行った。

実行したところRadeonⅦの16GB RAMがほとんど使われてしまい学習もCPUより遅くなるという事態になってしまいました・・・
![Screenshot from 2019-09-25 10-43-38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232732/9e921b4c-ad45-8bf4-de6f-b99749f0eaeb.png)

```
Step 1       [169.216 sec/step, loss=0.94706, avg_loss=0.94706]
```






#NVIDIA-CUDAでの環境構築と動作テスト

nvidia用環境構築

```
conda create -n cuda  python=3.6
pip install tensorflow-gpu==1.14.0
pip install -r requirements.txt
```


##注意
CUDA10.1ではGPUが無視されて動かないのでCUDA10.0環境を構築する or Docker環境を立てるのが無難です


```
sudo docker pull tensorflow/tensorflow:1.14.0-gpu-py3
sudo docker run --runtime=nvidia --rm -it tensorflow/tensorflow:1.14.0-gpu-py3 
```
コンテナ内ではpip3で既にtf1.14.0が動いているはずなので適時置き換えて使えば動きます。


https://hub.docker.com/r/tensorflow/tensorflow/tags?page=1&name=1.14.0
tf1.14.0コンテナを立てるのが無難かもしれません。

なんかsound関連でエラーが出たらここらへんが参考になる
http://www.codemarvels.com/2017/09/sndfile-not-found-error-while-installing-scikits-audiolabs/
https://improve-future.com/python-caution-on-scikits-audiolab-installation.html


##動作テスト
![Screenshot from 2019-09-26 07-44-28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232732/e74b9960-beaf-4469-4996-f6b0b25cc770.png)
それなりに10GBほどVRAMを消費します

#プロファイリング

train.pyのdef trainを下記のように書き換えると任意のstepでtimeline.jsonが出力されます

```python
def train(log_dir, args):
  commit = get_git_commit() if args.git else 'None'
  checkpoint_path = os.path.join(log_dir, 'model.ckpt')
  input_path = os.path.join(args.base_dir, args.input)
  log('Checkpoint path: %s' % checkpoint_path)
  log('Loading training data from: %s' % input_path)
  log('Using model: %s' % args.model)
  log(hparams_debug_string())

  # Set up DataFeeder:
  coord = tf.train.Coordinator()
  with tf.variable_scope('datafeeder') as scope:
    feeder = DataFeeder(coord, input_path, hparams)

  # Set up model:
  global_step = tf.Variable(0, name='global_step', trainable=False)
  with tf.variable_scope('model') as scope:
    model = create_model(args.model, hparams)
    model.initialize(feeder.inputs, feeder.input_lengths, feeder.mel_targets, feeder.linear_targets)
    model.add_loss()
    model.add_optimizer(global_step)
    stats = add_stats(model)

  # Bookkeeping:
  step = 0
  time_window = ValueWindow(100)
  loss_window = ValueWindow(100)
  saver = tf.train.Saver(max_to_keep=5, keep_checkpoint_every_n_hours=2)

  # Train!
  with tf.Session() as sess:
    try:
      summary_writer = tf.summary.FileWriter(log_dir, sess.graph)
      run_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE)
      run_metadata  = tf.RunMetadata()
      #プロファイル
      sess.run(tf.global_variables_initializer())
      count = 0
      if args.restore_step:
        # Restore from a checkpoint if the user requested it.
        restore_path = '%s-%d' % (checkpoint_path, args.restore_step)
        saver.restore(sess, restore_path)
        log('Resuming from checkpoint: %s at commit: %s' % (restore_path, commit), slack=True)
      else:
        log('Starting new training run at commit: %s' % commit, slack=True)

      feeder.start_in_session(sess)

      while not coord.should_stop():
        start_time = time.time()
        step, loss, opt = sess.run([global_step, model.loss, model.optimize],
				  options=run_options,
				  run_metadata=run_metadata)
        time_window.append(time.time() - start_time)
        loss_window.append(loss)
        message = 'Step %-7d [%.03f sec/step, loss=%.05f, avg_loss=%.05f]' % (
          step, time_window.average, loss, loss_window.average)
        log(message, slack=(step % args.checkpoint_interval == 0))
        count = count + 1

        step_stats=run_metadata.step_stats
        tl = timeline.Timeline(step_stats)
        ctf = tl.generate_chrome_trace_format(show_memory=False,
                                      show_dataflow=True)
        with open("timeline.json", "w") as f:
           f.write(ctf)

        if loss > 100 or math.isnan(loss):
          log('Loss exploded to %.05f at step %d!' % (loss, step), slack=True)
          raise Exception('Loss Exploded')

        if step % args.summary_interval == 0:
          log('Writing summary at step: %d' % step)
          summary_writer.add_summary(sess.run(stats), step)

        if step % args.checkpoint_interval == 0:
          log('Saving checkpoint to: %s-%d' % (checkpoint_path, step))
          saver.save(sess, checkpoint_path, global_step=step)
          log('Saving audio and alignment...')
          input_seq, spectrogram, alignment = sess.run([
            model.inputs[0], model.linear_outputs[0], model.alignments[0]])
          waveform = audio.inv_spectrogram(spectrogram.T)
          audio.save_wav(waveform, os.path.join(log_dir, 'step-%d-audio.wav' % step))
          plot.plot_alignment(alignment, os.path.join(log_dir, 'step-%d-align.png' % step),
            info='%s, %s, %s, step=%d, loss=%.5f' % (args.model, commit, time_string(), step, loss))
          log('Input: %s' % sequence_to_text(input_seq))

    except Exception as e:
      log('Exiting due to exception: %s' % e, slack=True)
      traceback.print_exc()
      coord.request_stop(e)

```
chrome://tracing/
ここから.jsonを開けます

##ROCmの分析
1step 50~100秒かかっていただけあって.jsonもすごいサイズになってしまっています.
![Screenshot from 2019-09-26 23-21-24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232732/9dd4b46e-7869-4b0e-fd1a-acbd3758f436.png)

これをクロームで開こうとしたらブラウザが固まってしまいました.

####補足
1step目だと時間がかかりすぎるので3stepぐらいだと読み込みが出来ました
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232732/b160df72-4819-4133-597a-4c1625d4ced3.png)

結構unknownが占めていて原因がわからなかったのが残念です.
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232732/207f4461-da31-29f7-af6c-39b963759402.png)


##CUDAの分析
![Screenshot from 2019-09-27 00-15-54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232732/fa104839-011a-6ffb-5464-4b8b7dddac94.png)

1step 10s~18sぐらいでステップが進みました。


![Screenshot from 2019-09-27 01-28-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232732/0a147285-6904-f278-6e89-7d11fe774b10.png)


分析した感じではNatMulが普通に一番時間を消費してしたのでCUDAでは計算ワークが正常に行われていたものと思われます
ROCmについては明らかに実用域では動いてないのでtacotronではCUDAを使うのが無難でしょう.





###参考
http://kikei.github.io/ai/2019/07/08/tensorflow.html