DeepLearning でアニメキャラのボイロを作った話 【モデル作成編 その1】

はじめに

データ収集編のつづきです。
次は用意したデータを用いて音声合成を行う Deep Learning モデルを作成する作業になります。 今回使用したモデルは Nvidia の Tacotron2 + Waveglow です。
このモデルは、例えば JSUT のデータをダウンロードしてデータの前処理をして Readme に従いモデルを作るだけで十分良いものができるのでパッと音声合成を試してみたい人にもオススメです。
(残念ながら他の手法を試したことがないので比較とかはできません。例えば、Mozilla が作ってたりもしてるようです。。今のデファクトスタンダードはどれなんでしょうか。)

音声合成モデル概要

Tacotron2 + Waveglow による音声合成の流れはこんな感じです。

f:id:tosaka-m:20200306205512p:plain:w400
音声合成モデル概要図

この図にある Tacotron2 と Waveglow の部分を用意したデータを使って学習することで音声合成モデルを作ります。 ここでモデル作成に必要なデータは図の テキストデータ波形データ です。

今回私が組んだモデルはちょっと変えてこんな感じにしてます。

f:id:tosaka-m:20200306205559p:plain:w500
音声合成モデル概要図その2

違うのは F0 カテゴリデータを入力に与えたのと、Denoising を追加したくらいです。
前処理ではテキストを MeCab, Jaconv でカタカナ直したあとローマ字に直すことをしました (juliusのマッピングを使用しました が一般的なやり方とかは知らないです。誰か教えてください。)

Tacotron2, WaveGlow, Denoising, F0 カテゴリデータ の部分を順にコメントしていきます。

Tacotron2

Tacotron2 については解説記事を書いてくださっている方がいましたので、こちら をご覧ください。(ありがたい...)
Tacotron2 がやることは、「テキスト → MelSpectrogram」 の変換です。Mel Spectrogram が何かについてはこの記事とか参考になりますかね。

Tacotron2 の学習自体はだいたいはもとのコードそのままで実行しております。
学習時の初期値には Nvidia の公開しているモデル を使用して Fine tuning しました。
他にも細かいハイパーパラメータの設定とかありますが、細かい上に特に違いとかも出なかった気がするので省略します。

余談ですが、Tacotron2 の学習にはどれくらいデータが必要なのか? とういう問いの一つの答えとして、学習データ量と精度の関係性について結果を載せているこの論文のプロジェクトページ が参考になるかなと思います。
モデル自体は Nvidia の Tacotron2 でなく Waveglow でも使っていないですが、類似モデルの話ではあるので Tacotron2 + Waveglow でもそこまで変わらないのではと思っております。

私が使用したデータは計1時間くらい(ただしノイズ多め)ですが、印象としてはここの Data requirements of the baseline Tacotron の 1 shard (24min) ~ 3 shard (72min ちょい) くらいの結果に近そうかなと勝手に思っています。
ここのプロジェクトページの結果をみると、そこそこのモデルなら30分くらいあれば良さそうですし、質を求めるなら 10 時間分くらいは欲しくなりますね...データの足りなさはより良いモデルを使ったり色々工夫したりで埋められる部分はあるかと思いますが。

WaveGlow

Waveglow は音声特徴量から波形データを生成するモデルです。このようなモデルは Vocoder と呼ばれ、 他に有名なものとしては、WaveNet とか World とかがあります。私は詳しくないですが、他にも色々あるようです。
NEUTORINO は 製作者 Tweet を拝見する限り NFS ライクなモデルを使っているっぽいんですかね?

こちらも学習時の初期値には Nvidia の公開しているモデル を使用して Fine tuning しました。

色々試した訳ことがある訳ではないのであれなんですが、Waveglow は自分のデータで学習させてみると iteration が増えるにつれノイズが乗るようになったり、ノイズが乗っていない iteration のモデルを使っても多少音質が劣化してしまったりと結構微妙かなと思ったり思わなかったりしています。
学習がちょっと難しいかもしれません。一応学習なしよりはよくなります。
時間が無限にあれば他の Vocoder も色々試して聴き比べてみたいです。

Denoising

Tacotro2 で生成した Mel Spectrogram をちょっと綺麗にすることをします。
作業初期であまりデータを作っていなかった時のちょっと悪いモデルだと結構効果がありましたが、データを増やした後 Tacotron2 のみである程度精度が出るようになるとあまり効果はなくなったかもしれません。
こんな感じに変わります。

データが少ない時

  • Denoising 前

  • Denoising 後

データを増やした時

  • Denoising 前

  • Denoising 後

あんまり変わらないですかね?

今回使用した Denoising の方法はこの方の結果を参考にさせていただきました。この方のどこかの解説記事で書かれていたと思いますが、やっていることとしては画像界隈の Image-to-image translation や SuperResolution と似たような感じだと思います。
この Denoising 機構を入れずに Tacotron2 単体で学習できれば理想なのですが、モデルの構造を深くしようとすると GPU メモリーに限界があったりなどどうしようも無い要素があったりします。特に Tacotron2 の学習は FineTuning 無しかつ BatchSize を小さくしすぎる (10 未満とか) と全然うまく学習しないとかあった気がするので (うろ覚え)、あまり Tacotron2 自体はいじらずに置きたかった事情もありました。

試した方法としてはこの2つです。

最初のほうでデータが少ない時は UNet + GAN を使用していましたが、これでかなり結構ノイズが減って 「おおっ」 となりました。
ただ、適切なハイパーパラメータがあまり分からず学習は安定しないことが多かったです。短い音声に適用すると逆に悪くなったりとかもありました。GAN の学習は難しいですね。

暫くしてデータを増やした後は RCAN を使用していました。
RCAN は SuperResolution 関連の論文なのですが、最近の SuperResolution は GAN でやるものとばかり勝手に思っていたので RCAN の論文を見ると L1 loss のみ学習していたのはちょっと驚きました(ので使って見ることにしました)。
GAN のチューニングのめんどくささもなさそうなのでとりあえずやってみたら、多少効果があってそこそこまぁまぁだったので最終版ではこちらにしてます。
どちらが優位かとかは軽く聴き比べたくらいだと一長一短で分からないです。

ちなみに Waveglow 自体にも予測の bias を除くことによる Denoising 機構があり上記サンプルは全てそれも使用しています。
(Waveglow の Denoising はざっくりと述べると bias = 「0 の値の mel spectrogram の Waveglow による予測値」 と定義し、audio のパワースペクトルから bias のパワースペクトル * 0.1 を除く処理です。)

F0 カテゴリデータ

入力に F0 を入れることで生成する音声の高さをコントロールできるようにしました。(あまり綺麗に変わらないですが...)
F0 が何かについては例えば wiki とか。
F0 の入力のために UI をこんな風に作ってます。

f:id:tosaka-m:20200306161229p:plain:w350
F0 入力フォーム

この UI では 5 段階で F0 を変えられるようにし、 Neural Net の入力にも 1 ~ 5 のカテゴリ値を入力として与えております。
普通 F0 は連続値なのですが、F0 の分布を 20% 点区切りの 5 つに分けることでカテゴリ化しています。

f:id:tosaka-m:20200306211834p:plain:w500
F0 カテゴリ化

F0 の値の算出には pyworld の harvest 関数を使用しました。

そもそもどうしてカテゴリ化したかというと、先に UI の構想があり、この UI で音程をコントロールしてみたいなと思ったのでそれを実現するためのモデルを考えた結果です。

F0 の値を組み込む方法はこんな感じにしました。なんでもよかったので、Tacotron2 の Encoder の部分をそのまま流用することで最小限のコードの変更で済ませてます(??)。

f:id:tosaka-m:20200306161427p:plain:w500
F0 値組み込み方法

F0 に関しては色々モデルを試したりとかは全くしてないのですが、 F0 をカテゴリ化せず直接入れた方がより細かい情報を与えられるため良いかもしれないし、 F0 を入れる NN の構造をもっと単純にする (例えば CNN, RNN を入れずに前後の関係性を無視するようにする) ほうが綺麗に音程が変わるかもしれません。

また、副次的な効果として精度も多少向上しました。
今回使用したデータは同じようなテキストでも声の高さ(キャラクターのテンション)が全然違うことが多々あります。 そのため、テキストだけでは音声の高さが判別できないので、高さ情報もいれてあげないと適切な予測ができない恐れがあります。(高いデータと低いデータで平均する過剰なスムージングがかかってしまう気がします。) そのため、F0 を入力に入れることで高い声を生成すればいいか、低い声を生成すればいいかある程度判断がつくようになったのが良い影響を与えたと思っております。

おわりに

使ったモデルと構造に関してはだいたい以上です。
まだ他に試したこととかもあるので次回は効果のあった手法とかなかった方法とか、あとは今後やりたいこととかをまとめたいと思います。

DeepLearning でアニメキャラのボイロを作った話 【データ収集編 その2】

はじめに

前回の記事のつづきです

データセット作成流れ

3. 対象キャラクターが話しているところのみ切り取り

手作業でやるなら Audacity で音声を聞きつついらないところを切り取るだけです。 初めは手作業でやっていたのですが、非常に時間がかかる上にしんどい...

という訳で、こちらでも Deep Learning の力を借りて作業をちょっと楽にしました。 具体的には、0.01 sec 間隔でその区間に対象キャラクターが話しているかどうかを判別するモデルを Neural Network で作ります。
モデルの全体像はこんな感じ。

f:id:tosaka-m:20200227191310p:plain
モデル全体像
Spectrogram の箇所は波形データを STFT (short time fourier transform) で変換して絶対値を取ったものです。

Neural Network 部分は CNN + BidirectionalLSTM で割と適当に組んでいます。
こんな感じ。

f:id:tosaka-m:20200227191343p:plain:w200
Neural Network 構造

STFT は librosa の関数を hop_length = 256, n_fft = 512 の設定で使用。
Neural Network の Layer 数や次元は CNN, LSTM それぞれ 1~2 層, 64 ~ 256 次元の範囲でいくつかのモデルを作成して 最終的には全モデルの平均による簡単な Ensemble を取っています。
このモデルはチューニングや Ensemble をしない段階でも割と使えそうな感覚だったので、あまり精度を詰めたりとかはしてないです。

このモデルが出来たら、モデルが予測する「対象キャラクターが話している確率」が一定以下の箇所を除去します。
閾値は対象キャラクターが話しているところを消さないように低めに設定します。(例えば今回は予測確率が 0.15 以下の箇所を除去しました。)
モデルが取り逃がす箇所があるので残りは手作業で除きました。

このモデルを入れることで、手で切り取るべきところの 2/3 以上は自動でなくなるのでかなり楽になりました。
まぁこのモデルを作る時間を作業にあてたほうが早く終わったとは思いますし、モデルも完全自動とまでは行っていない不十分な感じではありますが、精神衛生が保たれたことと今後も作業が楽になりうるという非常に大きなメリットがあるのでやってよかったです。

だいたい 1 話分ちょっとくらいを自分でラベルづけして、残りにモデルを適用といった感じでやりましたが、これくらいのデータでの学習で十分使えるものが出来ました。
学習させたデータに出てこないキャラクターがほぼ除去できない点がうまく行かなかったので、除去できなかったキャラクターのデータを適宜学習データに追加してモデルを良くしていったりもしています。

いらない箇所を全て除いた後は、この後行う音声合成モデルの学習時にデータが長すぎると面倒なので 1 ~ 10 秒範囲くらいで音声をキリのいいところで分割をしていきます。これは音声の大きさから切るべき箇所を判断するスクリプトを組んで行いました。

4. 音声に対応するテキストを作成

私はなぜか原作の書き起こしテキストをもっていた(???)ので、それと音声を聴き比べつつデータを作りました。(もともとチャットボット的なのを作りたくてテキストは作ってました。)

テキストがなければ作った音声データを何かしらの音声認識にかければ多分すぐ作れるんじゃないでしょうか?やってないのでわかりません。
フリーの音声認識ソフトとしては Julius とかがあります。

おわりに

以上が私が実施したデータ作成作業のだいたいの流れです。どうでもいいところを言葉で説明してプログラムとかは全く載せてもないので、もっと細かいところが知りたい方はコメントやTwitterなどで聞いてください。

Deep Learning で何かやりたいと思った時に一番の障害となるのが、データをどうやって集めたらいいんだ 問題だと思っています。
特に個人でやる場合はかけられるお金やリソースが限られるので、集められる量が限られたり質のいいものが集められなかったり、頑張って集めたはいいがデータが足りないせいで微妙なモデルしかできなかったり...とやっても徒らに時間を浪費するばかりでなかなか成果が出ないという状況になりかねません。
そういう時にオープンデータが利用できれば楽なのですが、やりたいことにマッチするオープンデータもそうそうないですよね。
例えば日本語の音声合成に使えるのオープンデータとしては JSUT があります。(質が高いデータをオープンに提供してくれる方々は本当にすばらしい。)
あと、ちょうど数日前に自動で自然な歌声を生成できる NEUTORINO というソフトが発表されて界隈が非常に盛り上がってますが、このモデルの作成には きりたんの歌声のオープンデータベース が元になっているようで、このように質の良いデータセットがあって初めて素晴らしいアプリケーションができるものだと思っています。(この NEUTORINO でできる曲ほんとすごいですよね。SF の世界にしかないような未来がついに現実になった感覚がありすごく感動しました。)

もっと気軽に利用できるオープンデータがたくさんあれば、もっと気軽に色々な応用に挑戦する人が増えて、音声分野自体更に盛り上がると思うんですけど、日本語のデータに関しては全然量も種類も足りないのが現状な気がするのでもっと沢山出てくるといいなと思っています。

追記 JVS(Japanese versatile speech) という素晴らしいデータセットもあることを知りました。これがあればマルチスピーカーモデルや任意話者モデルにも気軽に挑戦できそうですね。

今回私が作ったモデルも JSUT や JVS のデータをうまく使って (例えば Domain Adaptation とか Transfer Learning とか) 精度があげられたらいいのですが、まだ検証・実験が不十分で実を結んでないので、今後やるとしたらこのあたりをもうちょっと詰めてみるのがいいかなと思ってます。あとは、データの処理がバラバラなので最終的によかった方法でやり直すとかでも精度があがるかも...いや、もうあの作業をするのは...精度上がるのは間違いないと思うんですが...

データ作成についてはここまでで、次回はモデル作成のことをまとめます。

DeepLearning でアニメキャラのボイロを作った話 【データ収集編 その1】

はじめに

前回の記事の続き
今回はデータセットを作る話になります。
よく言われる事で私もそう思っているのですが、高品質の Deep Learning モデルを作るために一番大事ことは いかに多くの綺麗なデータを集めるられるか です。
今回は多くの綺麗なデータを簡単に集められるようなタスクではなかったこともありデータ収集も色々頑張ったので(主に手作業を...)、そのあたりの苦労も含めてまとめたいと思います。

データセット作成流れ

だいたいこんな流れでした。順に述べていきます。

  1. アニメから音声抽出
  2. 音声とBGMの分離
  3. 対象キャラクターが話しているところのみ切り取り
  4. 音声に対応するテキストを作成

1. アニメから音声抽出

これは色んな方法があるかと思いますが、私の作業環境が Mac ということもあり QuickTimeとSoundflowerを使う方法 を使用しました。
ここで紹介されている方法は Mac から出る音声を録音する方法でして、これを使用して映像を Mac で再生した時に流れる音声を録音することで音声データを取り出しました。
この方法で作ったデータを使って個人で楽しむ範囲を越えることをすると著作権的にあれなのでご注意ください。 (前回のサンプル音声も怒られたら消します。)

2. 音声とBGMの分離

アニメの音声は大概 BGM が流れつつセリフが進行していたり、時にはセリフに被さって効果音が鳴っていたりするものです。
BGM は基本ノイズにしかならないため、頑張って BGM を消していきます。

具体的には以下を試してみています。

ツール 概要 補足
音きりす 周波数のフィルターとかでBGMを消せる やり方については例えばここ参考
PhonicMind ボーカル抽出のWebサービス たしか20ドルくらい課金しました
Spleeter オープンソースの音声分離ソフト これを早めに知ってたらPhonicMindに課金しなかったよ
自作モデル 自分で作った 詳細は下部

体感ですがクオリティ的にはこんな感じでした。

音きりす < 自作モデル < PhonicMind = Spleeter < Spleeter + 自作モデル

このうち自作モデルの話をもう少し詳しく深掘ります。

2.1. 自作モデルについて

そもそもなぜ自作モデルを作る必要があったかというと、 Spleeter (or PhoiceMind) では BGM は消えるけど効果音が消えてくれない という厄介な問題があったためです。

最初は効果音を消すために Audiacity のノイズ除去機能を使って手作業でやっていました。 特に足音のような音に対しては、他の方法だと全然残ったままですが手でやると結構綺麗に消せます。
Audiacity でやる方法はこんな感じ。(こういうことをずっとやってると心が折れる)

f:id:tosaka-m:20200221164646j:plain:w450
効果音箇所の選択
f:id:tosaka-m:20200221164715j:plain:w450
ノイズ除去手順

暫くこれをやっていて、これはもうやりたくないと思ったので、効果音を消すモデルを自分で作る方向性にシフトしました。(このモデル作る時間のほうが手でやるより時間かかったんじゃないだろうか。)

BGM or 効果音 を消すことに関連する音声界隈の分野・タスクに Audio Source Separation というものがあります。 Audio Source Separation タスクでは例えば、曲のボーカルとその他の音源(ギター、ドラム, ...) の分離をしますが、今回やりたいことも基本的に同じなのでこの分野の方法を使用しました。  

試したものは WaveUNet と UNet の 2 つです。WaveUNet はこれ、 UNet はこの方の方法参考にしてます。

これをやるときは自分の勉強も兼ねていたので、自分でモデルを組んでいましたが WaveUNet の方は最終的にそこまでいい感じにならなかったのでこの方のコードのほぼ丸パクリになっていきました。(signal の スケールを変えてるのが結構いい感じになる)

BGM データには、DSD100 と手持ちのサントラ、 効果音データには、効果音の箇所を自分でアニメの音声の中から探して切り取ったり、効果音を配布しているサイトからダウンロードしたりしてデータを集めました。

自作モデルの結果はデータを用意するのが面倒だったので載せませんが、結果の印象だけ述べておきます。

  • WaveUNet は全体的に薄く残ってしまう。
  • UNet は綺麗に消えるがセリフの末尾まで消してしまう。

みたいな違った問題が出てきたのは興味深かったです。両方に共通する問題として、データセットに入れていない効果音はあまり消せない問題もありました。

最終的には自作モデルだと綺麗にBGMを消せなかったので 「spleeter にかけたものを自作の WaveUNet にかける」という 2段階の方法をとり、spleeter の精度を活かしつつ spleeter の苦手な効果音の除去を自作モデルで補う形にしました。
spleeter には学習機能があるっぽいですが、そういえば使ってないです。もしかしたら spleeter の学習のほうがよかったかもしれません。

私は使ってないのですが以下のようなプロ用の製品もいいんじゃないかと気になってます。お高いです。

2.2. 出来上がったデータセットについて

データを作る作業は結構長い期間ちょっとずつやっていたので色んな方法で作ったデータが混在してカオスになりました。特に効果音を除く作業が辛過ぎて...

データを作るよりプログラミングしてる方が楽しいので、

データを作る → 心が折れる → モデルを作る → 精度が微妙だからデータを増やそう → データを作る → 心が...

の流れを 3 回繰り返して、その度により良いデータ作成方法はないかと検討したので色々試してたり、色々混ざってカオスなことになったり...

だいたい 1~4話:音きりす, 5~7話:Phonicmind, 8話~:Spleeter+自作モデル みたいな感じでやりました。

あとは、どの方法もそうなんですが、全体的にうまく行かないというよりも、うまく行く行かないがはっきり別れる感じなので、この段階でデータの選別をしておくのもいいと思います。

途中ですが

一旦区切ります。続きはその2で。

私は音声関連の専門家ではなく、このボイロ作成で初めて音声関連のタスクに触れたので、一般的な方法がどれかとかもよくわかっていません。
詳しい方でもっと良い方法を知っているという方がいらっしゃいましたら、ぜひお教えいただければ幸いです。

DeepLearningでアニメキャラのボイロを作った話

はじめに

みなさんは Siri とかカーナビとか音声ガイダンスの声が自分の好きなキャラクターの声だったらなーと思ったことはありますか?ありますよね?私は別に思ったことはありませんが。
あの辺りの音声生成は音声合成と呼ばれる技術が使われていて可愛い系の声だと VOICEROID シリーズ (ゆかりさん、琴葉姉妹) とかが有名ですね。
私もあんな感じのが自分の好きなキャラクターで欲しいなーと思ったので Deep Learning の力を借りてとあるアニメキャラの VOICEROID 作りに挑戦してみました。
闇に葬ろうかとも考えていましたが溜まった知見が失われるのもちょっと勿体無い気がしたのでブログでまとめていこうと思ってます。

出来上がったもの
  • サンプル1 (誰かわかるかな? 発言は適当)

もうちょっとサンプルも載せておきます。

  • サンプル2

  • サンプル3

うまく行かないケースについて説明してもらっています。

  • サンプル4

  • サンプル5


ついでに声の高さの情報を入力に入れることで高さをコントロールできるようにしました。 (厳密に高さが変わる訳ではなく、その高さのデータの分布に生成結果が寄るだけ。)

  • サンプル2 の声を高くした版

  • サンプル2 の声を低くした版


さらに今回は単語単位で声の高さを調節できるようにもしてみました。 こんな感じの UI を作ってまして、手でいじれるようにしています。

  • UI イメージ

    f:id:tosaka-m:20200213210653p:plain
    声の高さを変えるUI

  • 生成音声

  • 声の高さの調整を変えた版

    f:id:tosaka-m:20200213210731p:plain
    声の高さの調整を変えた版

  • 生成音声


まぁ思った通りに変わることはほとんどないのですが、色々試しているといいものが出来たりして調整するのがすごく楽しいです。
全部固定値で入れてもある程度変わってくれますが文が長くなるとイントネーションは残念な感じになります。固定値でなくここも推論させてもいい気がしますが、めんどくさいので手で調整するのが楽しいのでやってません。

あと、こんな感じに音声速度も変えられます。

  • 0.5 倍速

  • 2 倍速

作り方

出来上がるまでの大まかな流れはこんな感じ。細かいことは書ききれないのでまた別記事でまとめていく予定です。

  1. アニメから音声抽出
  2. 声とBGM分離
  3. キャラクターが話しているところのみ切り取り
  4. 音声に対応するテキストを作成
  5. 前処理
  6. Deep Learning モデル学習

データに関しては結構手作業でつくるゴリ押し方法をとってます (一番つらい作業だった...)。 ちゃんと計算はしてないですがだいたい合計 1時間 くらいのデータになりました。

オープンデータと違って出来上がったデータセットはノイズが多いとか発話のテンションがバラバラとかテキストの分布が(音素のバランスが)偏っているとか問題だらけだったのでそこが難しいポイントだった気がします。ただ、テンションがバラバラなのはうまくモデルを作ればいろんなテンションの発言を生成できるということなので、これはメリットかもしれません。

Deep Learning モデルは Nvidia の Tacotron2 + Waveglow をベースに使用しました。 あとは この方の手法 も大変参考にさせていただいてます。

おわりに

クオリティに関しては全体的に少しノイズが乗った感じになっていて自分的にはもうあと一歩足りないくらいかなと思ってます。 ですが、モデルをここまで作って燃え尽きてしまったので (すでに 5, 6 ヶ月は作業してるし...)、何かモチベがない限りはもう更新はしないつもりです。誰かが一緒に開発してくれるとか、面白い論文が出るとか、2期が始まるとか、があれば...全部待ってます!

次回はデータの作り方の細かい方法の話をまとめます。

おまけ