機械学習
記事内に商品プロモーションを含む場合があります

Text2SpeechとSpeech2Textを繰り返すとどうなる実験結果を公開

Aru

Text2Speech(テキストから音声)とSpeech2Text(音声からテキスト)を繰り返すと、テキストや音声はどのように変化するのか?これに興味が湧き、実際に試してみました。音声変換技術の性能を評価するための実験として、変化の詳細を紹介します。

はじめに

ESPnet2というライブラリを使うと、テキストの読み上げ(Text to Speech)と、文字起こし(Speech to Text)の両方のタスクをpythonで手軽に行うことができます。

実際に両方試して見て興味が湧きましたので実験してみることにしました。

参考リンク:ESPnet2のリポジトリ

コードについて

今回のコードは、Google Colab用のコードとしてGithubに置いていますので、そちらも参考にしてください。なお、GPUを利用するコードになっていますので注意してください

Google Colab用コード:サンプルコード(Github)

ライブラリのインストール

必要なライブラリをColab環境にインストールします。

ライブラリのインストールのコードは以下になります。Colab環境以外の場合は、先頭の!を除いてコマンドラインで実行してインストールしてください。

!pip install -q espnet pypinyin parallel_wavegan gdown espnet_model_zoo
!pip install -q --no-build-isolation pyopenjtalk

エラーが発生しますが、2023.09.02現在の環境では、無視してOKでした

必要なライブラリを読み込む

必要なライブラリを読み込みます。

今回はText2SpeechSpeech2Textの両方を行うので、それぞれに必要となるライブラリを読み込んでいます。また、Colabで音声ファイルの再生ボタンを埋め込むためのIPythonパッケージもインポートしています。

librosaは、今回は、レート変換の処理に用います。

from espnet_model_zoo.downloader import ModelDownloader
from espnet2.bin.tts_inference import Text2Speech
from espnet2.bin.asr_inference import Speech2Text
from espnet2.utils.types import str_or_none
from IPython.display import display, Audio
import torch
import librosa

Text2Speech処理

オブジェクトの生成

text2speechオブジェクトを生成します。モデルの指定はtagで行っています。また、GPUの利用を設定しています。

# モデル名などの設定(https://github.com/espnet/espnet_model_zoo/blob/master/espnet_model_zoo/table.csv からjvs, justを選択)
tag = 'kan-bayashi/jsut_full_band_vits_prosody'
vocoder_tag = 'none'

text2speech = Text2Speech.from_pretrained(
    model_tag=str_or_none(tag),
    vocoder_tag=str_or_none(vocoder_tag),
    device="cuda",
)

変換用の関数定義

textを受け取ってwavに変換して返す関数を定義しています。戻り値はtorchのtensorです。

def to_wav(text) :
  with torch.no_grad():
      wav = text2speech(text)["wav"]  
  return wav.cpu()

Speech2text処理

オブジェクトの生成

speech2textオブジェクトを生成します。こちらもGPUを利用する設定を行っています。

tag = "kan-bayashi/csj_asr_train_asr_transformer_raw_char_sp_valid.acc.ave"

d = ModelDownloader()
speech2text = Speech2Text(
        **d.download_and_unpack(tag),
        device="cuda"
    )

変換用の関数定義

wavデータ(音声データ)を受け取って、textを返す関数の定義です。

def to_text(wav) :
  nbests = speech2text(speech)
  text, *_ = nbests[0]
  return text

繰り返し処理してみる

コード

ここまでで準備ができたので、15回繰り返してtext→wav→textの変換を行ってみます。

wavデータは41kHzのサンプリングレートなので、librosa.resampleで、speech2textの入力のサンプリングレート16kHzに変換しています。

text = "吾輩は猫である。名前はまだ無い。 どこで生れたかとんと見当がつかぬ。何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。"
num = 15

for i in range(num) :
  wav = to_wav(text)
  wav = wav.view(-1).cpu().numpy()
  print(i, ":" , text)

  display(Audio(wav, rate=text2speech.fs))
  speech = librosa.resample(wav, orig_sr = text2speech.fs, target_sr = 16000)
  text = to_text(speech)

print("last :" , text)

結果

0は入力です。1以降は入力を読み上げて、読み上げた音声を再びテキストに変換するという操作を繰り返して見ました。以下は、変換を続けた場合のテキストになります。


0 : 吾輩は猫である。名前はまだ無い。 どこで生れたかとんと見当がつかぬ。何でも薄暗いじめじめした所でニャーニャー泣いていた事だけは記憶している。
1 : 我が輩は猫である名前はまだないどこで生まれたかとんと見頭が付かぬ何でも薄暗いじめじめしたところでにゃあにゃあ泣いていたことだけは記憶している
2 : 我が子供がらは猫である名前はまだないどこで生まれたかとんとん頭があの何でも薄ぐらいじめじめしたところで出屋にあー泣いていたことだけは記憶している
3 : 我が子供柄は猫である名前はまだないどこで生まれたかとんと頭があの何でも薄暗いじめじめしたところで出屋に合わないていたことだけは記憶している
4 : 我が子供柄は猫である名前はまだないどこで生まれたか本当頭があの何でも薄暗いじめじめしたところで出会いに合わないでいたことだけは記憶している
5 : 我が子供柄は猫である名前はまだないどこで生まれたか本当頭があの何でも薄暗いじめじめしたところで出会いに合わないでいたことだけは記憶している
6 : 我が子供柄は猫である名前はまだないどこで生まれたか本当頭があの何でも薄暗いじめじめしたところで出会いに合わないでいたことだけは記憶している
7 : 我が子供柄は猫である名前はまだないどこで生まれたか本当頭があの何でも薄暗いじめじめしたところで出会いに合わないでいたことだけは記憶している
8 : 我が子供は猫である名前はまだないどこで生まれたか本当頭があの何でも薄暗いじめじめしたところで出会いに合わないでいたことだけは記憶している
9 : 我が子供は猫である名前はまだないどこで生まれたか本当頭があの何でも薄いじめじめしたところで出会いに合わないでいたことだけは記憶している
10 : 我が子供は猫である名前はまだないどこで生まれたか本当頭があの何でも薄いじめじめしたところで出会いに合わないでいたことだけは記憶している
11 : 我が子供は猫である名前はまだないどこで生まれたか本当頭があの何でも薄いじめじめしたところで出会いに合わないでいたことだけは記憶している
12 : 我が子供は猫である名前はまだないどこで生まれたか本当頭があの何でも薄いじめじめしたところで出会いに合わないでいたことだけは記憶している
13 : 我が子供は猫である名前はまだないどこで生まれたか本当頭があの何でも薄いじめじめしたところで出会いに合わないでいたことだけは記憶している
14 : 我が子供は猫である名前はまだないどこで生まれたか本当頭があの何でも薄いじめじめしたところで出会いに合わないでいたことだけは記憶している
last : 我が子供は猫である名前はまだないどこで生まれたか本当頭があの何でも薄いじめじめしたところで出会いに合わないでいたことだけは記憶している

以下は、実行時の画面のキャプチャです。下記のように、変換されたテキストと音声を再生するボタンが交互に出力されます。

実行画面サンプル
図:実行画面のサンプル

考察

結果ですが、思ったより壊れなかった感じです。また、10回以下でほぼ変化しなくなっている感じです(一部は変化していますが)

とりあえず、1回目の変換で「吾輩」が「我が輩」になって、これを「わがやから」と読んでしまったのが壊れる原因だったようです。

また、にゃぁにゃぁという擬音がうまくテキストに変換できなかったのをずっと引きずってしまったようにも見えます。たまたま、この文章を選んだのですが、擬音が入っていたのはテストとしてはある意味よかったのかもしれません。

とりあえず、思ったより安定している感じです。AI技術が進化してきて、このてもかなり高性能化してきた気がします。

まとめ

いかがでしたか?

交互に繰り返してみるというくだらない実験でしたが、結構面白い結果になったかと思います。

テキスト→音声、音声→テキストが手軽にできるので、これをうまく使って音声で指示、音声で解答するアプリとか簡単に作れそうです。

LLMを間に入れて遊んでみるのも楽しそうです(これも、そのうちトライしたいと思います)。

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

ABOUT ME
ある/Aru
ある/Aru
IT&機械学習エンジニア/ファイナンシャルプランナー(CFP®)
専門分野は並列処理・画像処理・機械学習・ディープラーニング。プログラミング言語はC, C++, Go, Pythonを中心として色々利用。現在は、Kaggle, 競プロなどをしながら悠々自適に活動中
記事URLをコピーしました