[Whisper+ESPnet2(VITS)]音声合成システムを作った備忘録


# 概要

以下の2つの構成で、テキストからの音声合成システムを作りました。
1. 収集した音声用データ(一人の音声)を、Whisperを用いて学習用データを作る
2. ESPnet2を用いて学習

今回は2.の部分は以下の記事のまま実行したので、メインで書くのは1.の部分となります。2.の部分は[以下の記事](https://qiita.com/RRR_troisR/items/6288b9bdc6e725aa8440)を参照してください。
ここでは解説しない知識なども載っているので、こちらをまず読むことをお勧めします。

https://qiita.com/RRR_troisR/items/6288b9bdc6e725aa8440

初めての投稿＋初めてのMarkdown記法なので読みにくかったら申し訳ないですが、備忘録＋結果報告として残しておきます。
(2023/06/18 読みやすくするため若干の修正を加えました)
youtubeの音声データを用いているので、問題があれば削除します。
40分程度の雑な作りの学習用データでファインチューニングすればここまで行けるよ！ってイメージで結果だけ見ていただいてもかまいません。


# Whisperとは
[論文](https://cdn.openai.com/papers/whisper.pdf)
[ブログ](https://openai.com/blog/whisper/)

**ブログからの引用**
Whisper is an automatic speech recognition (ASR) system trained on 680,000 hours of multilingual and multitask supervised data collected from the web.
(引用終わり)

Openai社が2022年9月に公開した、音声認識(音声をテキストに書き起こす)システムです。Web から収集された 680,000 時間分の教師付きデータ(!?)を用いていて、恐ろしいほど高い精度で音声に対するテキストを書き起こすことができます。

今回はこれを用いて学習用データを作りました。

# 環境
google colabを用いました。



# 音声データについて
私はYoutubeなどの一般に公開されている音声(原稿がなく、会話に近いような話し方のもの)で音声合成システムを作ってみたいな～と考えていたので、[好きなYoutuber様](https://www.youtube.com/channel/UCaXwP_NONWOKnhdE2egUgFw)の声をデータとして準備したいと考えました。23歳おめでとうございます。

Vtuberが巷で流行っており、いろいろな方がVtuberの声の音声合成システムを作っているのは知っていましたが、男性の声で作っているのはあまり聞かないので、男性のYoutuberを選びました。

Youtube-dlを導入し、いくつかの動画の音声を抽出しました。(Youtube-dlの使い方や概要などは各自で調べていただけたらと思います。)
私は[こちら](https://qiita.com/aki4masaki/items/ea5a00cb6cb303c6f8cd)の記事を参考にしました。

https://qiita.com/aki4masaki/items/ea5a00cb6cb303c6f8cd

ほとんどの動画にはBGMがあり、それを除去するために音源分離の方法をいろいろ調べていたのですが結局[ボーカルリムーバー](https://vocalremover.org/ja/)を用いて除去しました。

途中でめんどくさくなって3動画分でやめました。BGMがもともと小さいorないものを選んだつもりです。
生放送のアーカイブは使いませんでした。
以下は音声を使用させていただいた動画です。

https://www.youtube.com/watch?v=2dRroY_Nv-A
https://youtu.be/A4qdt5WGDwo
https://youtu.be/pg8iddzua5o

以上、合計40分ぐらいの.wav形式,44100Hzのデータを用意しました。

# Whisperを用いた音声の分割とテキスト準備
まずはWhisperを使って、音声データを書き起こしていきます。
事前に用意した.wavファイルをドライブのどこかに入れておいてください。
私は/content/drive/MyDrive/Colab Notebooks/whisというファイルにすべてまとめておきました。
Whisperは文章の始まる時間と終わりの時間も検出してくれるので、それらもまとめて.csvファイルにまとめるコードを作りました。


```python:whisper.ipynb
#ドライブに接続
from google.colab import drive
drive.mount('/content/drive')

# githubからインストール
!pip install git+https://github.com/openai/whisper.git

# whisperのインポート
import whisper

# largeモデルを使用
model = whisper.load_model("large")

# 実行
filename = "保存した.wavファイルの拡張子を除いた部分"
result = model.transcribe(fr"/content/drive/MyDrive/Colab Notebooks/whis/{filename}.wav")
print(result["text"])

# 結果を保存
import pandas as pd
df=pd.DataFrame(result["segments"])[["id", "start", "end", "text"]]
df.to_csv(fr"/content/drive/MyDrive/Colab Notebooks/whis/{filename}.csv")
```

3動画しかないから一つずつ手動で確認しながら作ればいいや～とのノリで作ったので一つずつやってあげてください。(怠惰)

こうしてできたファイルの一部はこのようになっています。

```text
,id,start,end,text
0,0,0.0,11.08,こんにちは松野ですということで今回もツイスでやっていきたいと思いますよろしくお願いします ということで今回から新シリーズと言いますか新しい試みとして
1,1,11.08,15.44,サブアカで triple s を目指そうという企画でございます
2,2,15.44,25.240000000000002,はいえっと試験ってあの結構ハードル高いですよね なかなかハイスカーを取るのは難しいよっていう形でまあ今いろんな方が苦戦していたりとかこの辺
3,3,25.24,35.2,せいいよっていうのがあったりとかみたいな感じでやってる人多いと思うんだけど まあ自分のメインやがいつも動画にしているアカウントはまあそこそこ課金をしていて
4,4,35.2,40.599999999999994,まあそこそこまあ ws ぐらいまでだったら取れるかなぐらいまで 8
5,5,40.599999999999994,52.519999999999996,育ってきたというかまあそんな状態なんだけど無課金の人ってやっぱりプレイするのなかなか難しいだろうなぁ と思って今回はそんな人だっての攻略の手助けになるかもしれなくもない
6,6,52.52,59.96,っていう建前を持ちつつちょっと無課金のサブアカを作ってみたかった っていう気持ちが9割5分
7,7,59.96,68.96000000000001,そっちが本音ですねえということで無課金サブアカ堂的なね 無課金サブアカでえっと試験でトリプル s を取ろうという企画をやっていこうかなと思います
8,8,68.96000000000001,76.08,初めに言っておきますがこれめちゃくちゃ長期企画になると思います だって課金しててもトリプル s 取るまでめちゃくちゃ時間かかるよ
9,9,76.08,83.67999999999999,半年かかったら最初にトリプル s を取るまでに俺はまあめっちゃ課金してたら最初の試験で トリプル s とったみたいな方もねあの
10,10,83.67999999999999,91.16,1年前いたんだけどまあそれぐらいかかってしまうよとということで8今回からね 新シリーズということでやっていこうかなと思います
```
句読点や！？などはありませんが、かなり高い精度で書き起こしができていると思います。ただ固有名詞(ツイステなど)は間違えやすいようです。またしっかり聞き取れていても表記ゆれや「えーっと」が全部8に置き換わっていたり細かいことを言えば文句だらけなのですが今回はこのままいきます。

**余談として**、startとendの時間の基準(Whisper側が決めた1文の区切りの基準)ですが、文章の始めから最後まで律儀に切っている場合もあれば、2文以上をくっつけていたり、連続して話しているのに切っていたりといまいち謎です。アライメントの調整を考えると、無音区間を切り取ってからWhisperを通すべきだったかなと思いましたが実験的にこのままにしています。

次にこれをつかって音声ファイルを分割し、学習用データを作りました。
[この記事](https://qiita.com/RRR_troisR/items/6288b9bdc6e725aa8440)を参照し、以下のようなファイル構造の学習用データを作っていきます。
```
CHARACTER_voice_data
    |
    |ーーー voice_text.txt
    |
    |ーーー voice 
             |
             |ーーー CHARACTER_001.wav
             |ーーー CHARACTER_002.wav
             |ーーー CHARACTER_003.wav
             ...
```
なお、voice_text.txtの中身の一部は以下の通りとします。
```
CHARACTER_001:(CHARACTER_001.wavの内容の文章)
CHARACTER_002:(CHARACTER_002.wavの内容の文章)
CHARACTER_003:(CHARACTER_003.wavの内容の文章)
...
```
:::note warn
警告
元記事ではvoice_text.txtのアンダーバー(_)が抜けているので入れてあげてください。私はここで一日ハマりました。
:::

.csvファイルと音声ファイルから、学習用データを作るコードを以下のように書きました。(pydubを事前にインストールしてください)

```python:
# -*- coding: utf-8 -*-
#ライブラリのインポート
from pydub import AudioSegment
import pandas as pd 
#ディレクトリの作成
!mkdir /content/drive/MyDrive/CHRACTER_voice_data
!mkdir /content/drive/MyDrive/CHRACTER_voice_data/voice
#.wavと.csvの読み込み
filename = "保存した.wavファイルの拡張子を除いた部分"
df = pd.read_csv(fr"/content/drive/MyDrive/Colab Notebooks/whis/{filename}.csv", encoding="utf_8")
sound = AudioSegment.from_file(fr"/content/drive/MyDrive/Colab Notebooks/whis/{filename}.wav", format="wav")
#.csvの中身を逆順に
df = df.iloc[::-1]
df.index = range(len(df))
#実行
for i in range(len(df)):
    start = int(df.iloc[i,2]*1000)
    end = int(df.iloc[i,3]*1000)
    soundcut = sound[start:end]
    #現在のvoice_text.txtの行数を取得
    try:
        counttxt = sum([1 for _ in open(/content/drive/MyDrive/CHARACTER_voice_data/voice_text.txt,encoding="shift-jis")])
    except:
        counttxt = 0
    i_str = str(i+1+int(counttxt))
    i_zero = i_str.zfill(3)
    savename = fr"/content/drive/MyDrive/CHRACTER_voice_data/voice/CHARACTER_{i_zero}.wav"
    soundcut.export(savename, format="wav", bitrate="44.1k")
    text = df.iloc[i,4]
    txtname = f"CHARACTER_{i_zero}:{text}"
    f = open('/content/drive/MyDrive/CHRACTER_voice_data/voice_text.txt', 'a')
    f.write(f'{txtname}\n')
    f.close()
```
startとendの時間をそのまま扱いたく、.csvの中身を逆順にすることで、音声データの後ろから順に切り取っていく形にしました。
```python:
df = df.iloc[::-1]
df.index = range(len(df))
```

こちらも3動画しかないから一つずつ手動で確認しながら作ればいいや～とのノリで作ったので一つずつやってあげてください。(怠惰)
分割したい動画を一つずつ実行を繰り返せば、学習用データができていくようになっていきます。

ここまでやると、MyDrive直下にCHARACTER_voice_dataという学習用データが入っているファイルができており、これで学習できます。お疲れさまでした。

# 学習を行ってみて

できたファイルを用いて、[以下の記事](https://qiita.com/RRR_troisR/items/6288b9bdc6e725aa8440)を参照しながら学習しました。この部分はローカル環境(Quadro P4000をGPUに持つパソコン)を用いて学習しました。
学習は35時間ほどかかりました。

以下に出来上がったシステムで合成した音声を載せておきます。(qiitaだと載せられないのでSoundCloud)

https://on.soundcloud.com/j3MLd

えーって声はテキストで入力していませんが、文の初めにたまに入るようになっています。ただ、これが悪さをして正常によみあげてくれない場合もあるのでおそらく学習用データからは取り除いた方がよいと思います。
学習用データの問題点としては、動画によって声のテンションが違うもので学習をしたので、テンションがたまにおかしくなる現象もあります。学習用データは
また途中で早口になったり、ノイズが強く乗ってしまったり、読み方が違う語があったりなどの問題点があります。これは学習を増やせば解決する可能性があります。

学習時間が長すぎてやり直す予定はありません。読んでいただきありがとうございました。

# 参考文献


https://qiita.com/RRR_troisR/items/6288b9bdc6e725aa8440