Jetson NanoでTacotron2(音声合成)を動かす
Jetson nanoでTacotron2を動かしてみます。Tacotron2の詳細は記事をご覧ください。
なお本記事は2019年11月末時点のものです。ツールのバージョンアップ等により、この手順で動かなくなることもありうるので、あらかじめご容赦ください。
先に結果を報告します。
- Jetson NanoでTacotron2+WaveGlowが動きました。
- 実行にかかる時間は約3分ちょいでした(そのうちモデル読み込み時間が約2分)。nvpmodeはmax(10W 4コア)、クロックも最大設定です(gpu 921.6MHz)。
- NVIDIA実装の英語のままです。
- メモリはぎりぎりで、Tacotron2、WaveGlowの片方でほぼ一杯。Nanoは4GBのメモリがありますが、常時約1.6GBはシステムが占有しており、残りだと精一杯のようです。今回、Docker Containerで動かしましたが、ホストOS側でSwap設定が必須です。
- インターネットブラウザ等、他のアプリは全て落として動かさないと、メモリSwapでえらく時間がかかります(下手すると数10分以上)。
- 高速化の余地はだいぶありそうですが、専門的知識、経験が無いと難しいかも。
興味がある方は以下の手順で試してみてください。環境構築するのに1,2時間かかります。docker containerを使うのでSDカードは容量に余裕があるもの(64GB以上)を推奨します。だいたいcontainerで5GB~6GBくらい消費します。
あと、Jetson NanoはHDMI経由で音を出します。HDMIに接続されているディスプレイにスピーカがついているか事前に確認が必要です。
なお、Jetsonを持ってないけど試してみたい方はこちら。Google Colaboratoryで試しています。
akifukka.hatenablog.com
1.JETPACK4.2.2の準備
本記事ではDocker Containerを使います。Containerを使うにはJETPACK4.2.2以降が必要です。JETPACK4.2.2のセットアップは次を参考にしてください。
メモリSwapもJETCARDをインストールすると自動的に設定してくれます。
2.DeepStream-l4t Containerの作成、起動
Tacotron2をContainerで動かします。まずはl4t-base Container(r32.2.1)を作成、起動します。
sudo xhost +si:localuser:root
sudo docker run --runtime nvidia --network host -it -e DISPLAY=$DISPLAY -v /tmp/.X11-unix/:/tmp/.X11-unix --device /dev/snd:/dev/snd nvcr.io/nvidia/l4t-base:r32.2.1
4.環境構築
Containerの端末で次を実行します。
- update
apt-get update
- PIP3
wget https://bootstrap.pypa.io/get-pip.py
python3 get-pip.py
- git
apt-get install git
- apex pip3でlibblas.so.3 errorが出るのを回避
apt-get install libatlas3-base
- コンパイラ
apt-get install -y --no-install-recommends make g++
- python3の開発ツール
apt-get install python3.6-dev
- pytorch1.0 少し時間がかかります。
wget https://nvidia.box.com/shared/static/2ls48wc6h0kp1e58fjk21zast96lpt70.whl -O torch-1.0.0a0+bb15580-cp36-cp36m-linux_aarch64.whl
pip3 install numpy torch-1.0.0a0+bb15580-cp36-cp36m-linux_aarch64.whl
- scipy
apt-get install python3-scipy
なお、python2,3自体は最初からcontainerにインストールされています。
5.Tacotron2関係のインストール
(1)tacotron2
git clone https://github.com/NVIDIA/tacotron2.git
(2)submodule(waveglowなど)導入
waveglowを最新版にしないと後でdenoiserが無いというエラーが出るので、--remote --mergeで最新版に更新しています。
以降はtacotron2フォルダで作業します。
cd tacotron2
git submodule init
git submodule update --remote --merge
(3)Apexインストール
git clone https://github.com/NVIDIA/apex
cd apex
pip3 install -v --no-cache-dir ./
(4)matplotlib
apt-get install python3-matplotlib=2.1.1-2ubuntu3
地域を聞かれるのでAsia-Tokyoを選択します。
(5)tensorflowインストール
apt-get install libhdf5-serial-dev hdf5-tools libhdf5-dev zlib1g-dev zip libjpeg8-dev python3-h5py
pip3 install -U future==0.17.1 mock==3.0.5 keras_preprocessing==1.0.5 keras_applications==1.0.6 enum34 futures testresources setuptools protobuf
pip3 install --extra-index-url https://developer.download.nvidia.com/compute/redist/jp/v42 tensorflow-gpu==1.13.1+nv19.3
pip3 install tensorboardX==1.1tensorboardX==1.1 unidecode==1.0.22 pillow inflect==0.2.5
(6)librosaインストール
librosaのインストールは次のホームページに助けられました。Thanks!
ア. llvmliteのインストール
apt-get install llvm-7
cd /usr/bin
ln -s llvm-config-7 llvm-config
cd /tacotron2
pip3 install llvmlite
apt-get install libblas-dev liblapack-dev libatlas-base-dev gfortran
イ.cython
pip3 install cython
ウ.pip3アップグレード
pip3 install --upgrade pip
エ.librosaのインストール 時間がかかります
pip3 install librosa==0.6.0
6.学習済みモデルのダウンロード
(1)WaveGlow
wget https://api.ngc.nvidia.com/v2/models/nvidia/waveglow_ljs_256channels/versions/3/files/waveglow_256channels_ljs_v3.pt
(2)Tacotron2
wget --load-cookies /tmp/cookies.txt "https://docs.google.com/uc?id=1c5ZTuT7J08wLUoVZ2KkUs_VdZuJ86ZqA&export=download&confirm=$(wget --quiet --save-cookies /tmp/cookies.txt --keep-session-cookies --no-check-certificate 'https://docs.google.com/uc?id=1c5ZTuT7J08wLUoVZ2KkUs_VdZuJ86ZqA&export=download&id=FILEID' -O- | sed -rn 's/.*confirm=([0-9A-Za-z_]+).*/\1\n/p')&id=FILEID" -O tacotron2_statedict.pt && rm -rf /tmp/cookies.tx
7.Pythonからサウンド出力するためのライブラリ
apt-get install libasound-dev
apt-get install portaudio19-dev python-all-dev
pip3 install pyaudio
8.動かしてみる
①inference.pyとして以下をtactron2フォルダに置く。viエディタで 'i’ でインサートモードにしてコピペすれば複製できます。
②他のソフト、Chrome等を全て終了させます。終了させないとメモリが足りなくなって時間がものすごくかかったりします。
③実行します。
python3 inference.py
④warningがたくさん出ますが気にしないで、高速化設定のJetson Nanoで3分半ほど待つとmel spectrogramの画面が表示されます。画面をx印をクリックして終了させると音声が出ます。日本語風はあまり聞き取れませんが・・・。
・waveglow is really awesome!
・こんにちわ、今日もいい天気ですね!
exitを入力するとcontainerを終了させることができます。
import matplotlib
import matplotlib.pylab as plt
import sys
sys.path.append('waveglow/')
import numpy as np
import torch
import pyaudio
import gc
import time
from hparams import create_hparams
from model import Tacotron2
from layers import TacotronSTFT, STFT
from audio_processing import griffin_lim
from train import load_model
from text import text_to_sequence
from denoiser import Denoiser
def plot_data(data, figsize=(16, 4)):
fig, axes = plt.subplots(1, len(data), figsize=figsize)
for i in range(len(data)):
axes[i].imshow(data[i], aspect='auto', origin='bottom',
interpolation='none')
torch.cuda.synchronize()
time0 = time.time()
hparams = create_hparams()
hparams.sampling_rate = 22050
checkpoint_path = "tacotron2_statedict.pt"
model = load_model(hparams)
model.load_state_dict(torch.load(checkpoint_path)['state_dict'])
_ = model.cuda().eval().half()
torch.cuda.synchronize()
time1 = time.time()
print('Tacotron2 load',time1 - time0)
text = "Waveglow is really awesome!"
sequence = np.array(text_to_sequence(text, ['english_cleaners']))[None, :]
sequence = torch.autograd.Variable(
torch.from_numpy(sequence)).cuda().long()
mel_outputs, mel_outputs_postnet, _, alignments = model.inference(sequence)
text2 = "kon nichiwa!,kyou moiitenkidesue ne!"
sequence2 = np.array(text_to_sequence(text2, ['english_cleaners']))[None, :]
sequence2 = torch.autograd.Variable(
torch.from_numpy(sequence2)).cuda().long()
mel_outputs2, _, _, _ = model.inference(sequence2)
torch.cuda.synchronize()
time2 = time.time()
print('Tacotron2 infer ',time2 - time1)
del model
gc.collect()
torch.cuda.synchronize()
time3 = time.time()
waveglow_path = 'waveglow_256channels_ljs_v3.pt'
waveglow = torch.load(waveglow_path)['model']
waveglow.cuda().eval().half()
for k in waveglow.convinv:
k.float()
denoiser = Denoiser(waveglow)
torch.cuda.synchronize()
time4 = time.time()
print('waveglow init ',time4 - time3)
with torch.no_grad():
audio = waveglow.infer(mel_outputs_postnet, sigma=0.666)
audio2 = waveglow.infer(mel_outputs2, sigma=0.666)
torch.cuda.synchronize()
time5 = time.time()
print('waveglow infer ',time5 - time4)
np.save('audio',audio[0].data.cpu().numpy())
np.save('audio2',audio2[0].data.cpu().numpy())
list_audio = []
for i in audio[0].data.cpu().numpy():
list_audio.append(i)
list_audio.append(i)
audio1_2 = np.array(list_audio)
list_audio2 = []
for i in audio2[0].data.cpu().numpy():
list_audio2.append(i)
list_audio2.append(i)
audio2_2 = np.array(list_audio2)
p = pyaudio.PyAudio()
stream = p.open(format = pyaudio.paFloat32,
channels = 1,
rate = 44100,
output = True,
frames_per_buffer = 1024)
plot_data((mel_outputs.float().data.cpu().numpy()[0],
mel_outputs_postnet.float().data.cpu().numpy()[0],
alignments.float().data.cpu().numpy()[0].T))
plt.show()
print("play")
stream.write(audio1_2.astype(np.float32).tostring())
stream.write(audio2_2.astype(np.float32).tostring())
stream.close()
9.containerの再実行
・CONTAINER_IDを取得します。
sudo docker ps -a
・実行させます。-iを忘れずに。
sudo docker start -i CONTAINER_ID
・なお、CONTAINER_IDをわかりやすい名前に変えることもできます。
sudo docker rename CONTAINER_ID 変更後のCONTAINER_ID
10.まとめ
Jetson NanoでTacotron2音声合成を試してみました。かろうじて動きましたが、リアルタイムとは行きませんでした。
一応、2行分で、time関数で処理時間を計測した結果は次の通り。
tacotron2 6.5s、waveglow 20.6s
実際はモデル読み込みに2分38秒、その他ソフト初期化等で30秒弱といったところです。高速化チューニングで処理時間(モデル読み込み、ソフト初期化を除く)を数分の一程度に短縮できる可能性はあると思いますが、それでもまだまだですね。
といっても、Jetsonザビエルあたりだとリアルタイムに動くかも知れません。ハードウェアの高速化を待った方がよさそうですね。
日本語化も課題ですが、ちょっと簡単にはいかなさそうなので、次どうするかは未定です。