Zenn
Closed9

エンドツーエンド音声処理ツールキット「ESPnet」を試す

kun432kun432

ちゃんとやったことが一度もないのであらためて。とりあえず盛りだくさん。

公式サイト

https://espnet.github.io/espnet/

ESPnet: エンドツーエンド音声処理ツールキット

ESPnetは、エンドツーエンドの音声認識、テキスト読み上げ、音声翻訳、音声強調、話者分離、音声言語理解などを網羅するエンドツーエンド音声処理ツールキットです。
ESPnetは、深層学習エンジンとして pytorch を使用し、Kaldi 方式のデータ処理、特徴抽出/フォーマット、レシピに則って、様々な音声処理実験のための完全なセットアップを提供します。

主な特徴

Kaldiスタイルの完全なレシピ

  • 多数の ASR レシピに対応(WSJ、Switchboard、CHiME-4/5、Librispeech、TED、CSJ、AMI、HKUST、Voxforge、REVERB、Gigaspeech など)
  • 同様に多くの TTS レシピに対応(LJSpeech、LibriTTS、M-AILABS など)
  • 多数の ST レシピに対応(Fisher-CallHome Spanish、Libri-trans、IWSLT'18、How2、Must-C、Mboshi-French など)
  • 多数の MT レシピに対応(IWSLT'14、IWSLT'16、上記STレシピなど)
  • 多数の SLU レシピに対応(CATSLU-MAPS、FSC、Grabo、IEMOCAP、JDCINAL、SNIPS、SLURP、SWBD-DA など)
  • 多数の SE/SS レシピに対応(DNS-IS2020、LibriMix、SMS-WSJ、VCTK-noisyreverb、WHAM!、WHAMR!、WSJ-2mix など)
  • 音声変換レシピにも対応(VCC2020ベースライン)
  • 話者ダイアリゼーションレシピにも対応(mini_librispeech、librimix)
  • 歌声合成レシピにも対応(ofuton_p_utagoe_db、opencpop、m4singer など)

ASR: 自動音声認識

  • 複数のASRベンチマークにおいて 最先端の性能 (ハイブリッドDNN/HMMやCTCと比較して同等または優れている)
  • Hybrid CTC/attention に基づくエンドツーエンドASR
    • CTC/attentionのマルチタスク学習による高速かつ高精度な学習
    • 単調なアライメントのデコーディングを強化するCTC/attentionの共同デコーディング
    • エンコーダ:VGG風CNN + BiRNN(LSTM/GRU)、サブサンプリングBiRNN(LSTM/GRU)、Transformer、Conformer、Branchformer、または E-Branchformer
    • デコーダ:RNN(LSTM/GRU)、Transformer、またはS4
  • Attention: Flash Attention、ドット積、位置情報対応Attention、多頭Attentionの変種
  • テキストデータのみで学習されたRNNLM/LSTMLM/TransformerLM/N-gramを組み込むことが可能
  • GPUバッチデコーディング
  • データ拡張
  • Transducer に基づくエンドツーエンドASR
    • アーキテクチャ:
      • RNN、Conformer、Branchformer(変種あり)、1D Conv / TDNNに対応したカスタムエンコーダ
      • ブロック間でパラメータが共有されたデコーダ(RNN、1D Convによるステートレス、MEGA、および RWKVに対応)
      • 利用可能なPre-encoder: VGG2LまたはConv2D
    • 探索アルゴリズム:
    • 特徴:
      • オフラインおよびストリーミング音声認識のための統一インターフェース
      • 各種補助損失を用いたマルチタスク学習:
        • エンコーダ:CTC、補助Transducer、対称KLダイバージェンス
        • デコーダ:ラベルスムージング付きクロスエントロピー
      • 音響モデルおよび/または言語モデルによる転移学習
      • FastEmit正則化手法を用いた学習 [Yu et al., 2021]

    詳細なドキュメントについては、チュートリアルページを参照してください。

  • CTCセグメンテーション
  • Mask-CTCに基づく非自己回帰モデル
  • 絶滅危惧言語の記録支援のためのASR例(詳細は egs/puebla_nahuatl および egs/yoloxochitl_mixtec を参照)
  • EncoderとしてWav2Vec2.0の事前学習モデルを使用(FairSeqからインポート)
  • フロントエンドにおいて、上流モデルを用いた自己教師あり学習表現(S3PRL)を特徴として利用
    • frontends3prl に設定
    • 対応する名前を指定して frontend_conf を設定することで、任意の上流モデルを選択可能
  • 転移学習 :
  • ブロックワイズ同期ビームサーチを用いたストリーミングTransformer/Conformer ASR
  • 長い系列に対して、Longformer に基づくRestricted Self-Attentionをエンコーダとして利用
  • OpenAIの Whisper モデル、広範な弱教師ありマルチタスク学習に基づく堅牢なASR

デモンストレーション

  • ESPnet2を用いたリアルタイムASRデモ Open In Colab
  • Gradio を用いたHugging Face Spaces上のWebデモ。詳細は Web Demo を参照
  • ESPnet2によるストリーミングTransformer ASR Local Demo

TTS: テキスト読み上げ

  • アーキテクチャ
    • Tacotron2
    • Transformer-TTS
    • FastSpeech
    • FastSpeech2
    • Conformer FastSpeech & FastSpeech2
    • VITS
    • JETS
  • 複数話者および多言語拡張
    • 事前学習済み話者埋め込み(例:X-vector)
    • 話者ID埋め込み
    • 言語ID埋め込み
    • グローバルスタイルトークン(GST)埋め込み
    • 上記埋め込みの組み合わせ
  • エンドツーエンド学習
    • エンドツーエンドのテキストからwavへのモデル(例:VITS、JETS など)
    • text2melとvocoderの共同学習
  • 多様な言語に対応
    • 英語 / 日本語 / 中国語 / ドイツ語 / ロシア語 / その他...
  • ニューラルボコーダとの統合
    • Parallel WaveGAN
    • MelGAN
    • Multi-band MelGAN
    • HiFiGAN
    • StyleMelGAN
    • 上記モデルの組み合わせ

デモンストレーション

以下のリポジトリでニューラルボコーダの学習を行ってください:

SE: 音声強調(および分離)

  • 単一話者の音声強調
  • 複数話者の音声分離
  • 時間領域および周波数領域モデルのための統一されたエンコーダ-セパレータ-デコーダ構造
  • 柔軟なASR連携:個別タスクまたはASRフロントエンドとして機能
  • Asteroidから事前学習済みモデルの簡単なインポートが可能
    • Asteroidの事前学習済みモデルと特定の設定の両方に対応

デモンストレーション

  • ESPnet2を用いたインタラクティブなSEデモ Open In Colab
  • ESPnet2を用いたストリーミングSEデモ Open In Colab

ST: 音声翻訳 & MT: 機械翻訳

  • 複数のSTベンチマークにおいて 最先端の性能 (カスケードASRとMTと比較して同等または優れている)
  • TransformerベースのエンドツーエンドST(新機能!)
  • TransformerベースのエンドツーエンドMT(新機能!)

VC: 音声変換

  • Melスペクトログラムを用いたTransformerおよびTacotron2ベースのパラレルVC
  • カスケードASR+TTSに基づくエンドツーエンドVC(Voice Conversion Challenge 2020のベースラインシステム!)

SLU: 音声言語理解

  • アーキテクチャ
    • Transformerベースのエンコーダ
    • Conformerベースのエンコーダ
    • Branchformerベースのエンコーダ
    • E-Branchformerベースのエンコーダ
    • RNNベースのデコーダ
    • Transformerベースのデコーダ
  • ASRとのマルチタスク学習に対応
    • 意図とASRトランスクリプトの両方を予測
  • NLUとのマルチタスク学習に対応
    • 熟慮エンコーダを用いた2段階モデル
  • 事前学習済みASRモデルの利用に対応
    • Hubert
    • Wav2vec2
    • VQ-APC
    • TERA など
  • 事前学習済みNLPモデルの利用に対応
    • BERT
    • MPNet など
  • 多様な言語に対応
    • 英語 / 日本語 / 中国語 / オランダ語 / その他...
  • 前の発話からの文脈利用に対応
  • SEなど他のタスクとのパイプライン方式の利用に対応
  • オーディオとASRトランスクリプトの両方を組み合わせた2段階SLUに対応

デモンストレーション

  • 音声強調モデルと音声言語理解モデルを連携させたノイズのある音声言語理解の実施。 Open In Colab
  • 音響情報と意味情報の両方に着目する2段階SLUの実施。 Open In Colab
  • Hugging Face SpacesにGradioを統合。複数言語に対応したSLUデモは Hugging Face Spaces を参照

SUM: 音声要約

  • 制限付きSelf-Attentionを用いた講義動画向けのエンドツーエンド音声要約レシピ [Sharma et al., 2022]

SVS: 歌声合成

  • Muskitsから統合したフレームワーク
  • アーキテクチャ
    • RNNベースの非自己回帰モデル
    • Xiaoice
    • Tacotron-singing
    • DiffSinger(開発中)
    • VISinger
    • VISinger 2(異なるvocoder-アーキテクチャとのバリエーション)
  • 複数話者および多言語歌声合成に対応
    • 話者ID埋め込み
    • 言語ID埋め込み
  • 多様な言語に対応
    • 日本語 / 英語 / 韓国語 / 中国語
  • ニューラルボコーダとの緊密な統合(TTSと同一)

SSL: 自己教師あり学習

UASR: 教師なしASR (EURO: ESPnet Unsupervised Recognition - オープンソース)

  • アーキテクチャ
    • wav2vec-U(各種自己教師ありモデル付き)
    • wav2vec-U 2.0(開発中)
  • PrefixBeamSearchおよびK2ベースのWFSTデコーディングに対応

S2T: Whisperスタイルの多言語マルチタスク音声認識

  • 公開データを用いたWhisperスタイルのスクラッチからの学習の再現: OWSM
  • 単一モデルで複数タスクに対応
    • 多言語音声認識
    • 任意の言語間の音声翻訳
    • 言語識別
    • 発話単位のタイムスタンプ予測(セグメンテーション)

DNNフレームワーク

  • ChainerおよびPyTorchによる柔軟なネットワークアーキテクチャ
  • kaldiioおよびHDF5サポートによる柔軟なフロントエンド処理
  • Tensorboardベースのモニタリング
  • DeepSpeedに基づく大規模学習

ESPnet2

詳細は ESPnet2 を参照。

  • ESPnet1とは独立(Kaldi/Chainerに依存しない)
  • 学習時のオンザフライな特徴抽出およびテキスト処理
  • DistributedDataParallelおよびDaraParallelに対応
  • 複数ノード学習に対応し、SlurmまたはMPIと統合
  • fairscale によるSharded Trainingをサポート
  • 全コーパスに適用可能なテンプレートレシピ
  • CPUメモリエラーなく任意のサイズのコーパスの学習が可能
  • ESPnet Model Zoo と統合
  • wandb と統合
kun432kun432

インストール

一応ここにあるけど、ちょっと古い気がする。

https://espnet.github.io/espnet/installation.html

各機能ごとのノートブックの内容を見てると、最新で揃ってるという感じでもなくて、バージョンが個別に指定されている。

で、READMEを見ると、PythonバージョンとPyTorchのバージョンの組み合わせがあるので、これを踏まえたほうが良さそう(ちょっとFailedになってるものもあるけど)

自分の環境はUbuntu-22.04+RTX4090。このマトリックスに従って、最新のものを使用するならばPython-3.11+PyTorch-2.4.0という感じが良さそう。

PyTorch-2.4.0のインストール手順を見ると、CUDAは11.8/12.1/12.4という感じ。
https://pytorch.org/get-started/previous-versions/#v240

自分の場合はCUDAのバージョンがいろいろ混在させてやや環境が汚れてた感もあったので、CUDA-12.4.1を入れ直した。

作業ディレクトリ+仮想環境を作成

mkdir espnet-work && cd espnet-work
uv venv -p 3.11.11

PyTorch-2.4.0をパッケージインストール

uv pip install torch==2.4.0 torchvision==0.19.0 torchaudio==2.4.0 --index-url https://download.pytorch.org/whl/cu124

ESPnetをパッケージインストール。espnet_model_zooをあわせてインストールしておくと、学習済みモデルをダウンロードして使える様子。

uv pip install espnet espnet_model_zoo
出力
(snip)
 + espnet==202412
 + espnet-model-zoo==0.1.7
 + espnet-tts-frontend==0.0.3
(snip)

あとは各機能ごとに個別に追加していく感じで。

とりあえず学習は後回しで、一旦推論だけを見ていくつもり。

kun432kun432

ASR

https://espnet.github.io/espnet/notebook/ESPnet2/Demo/ASR/asr_realtime_demo.html

まずは文字起こし。espnet_model_zooをインストールしておくと、以下からモデルをダウンロード・使用することができる。

https://github.com/espnet/espnet_model_zoo/blob/tree/espnet_model_zoo/table.csv

またそれ以外にも

などのモデルも指定できる様子。

とりまノートブックに記載されている日本語モデルを使用させていただいてやってみる。サンプル音声として、自分が開催した勉強会のYouTube動画から冒頭5分程度の音声を抜き出したオーディオファイルを用意した。

https://www.youtube.com/watch?v=Yl2kR6zLRY8

コード

asr.py
import string
import soundfile
from espnet_model_zoo.downloader import ModelDownloader
from espnet2.bin.asr_inference import Speech2Text
import matplotlib.pyplot as plt
import librosa.display

fs = 16000
tag = 'Shinji Watanabe/laborotv_asr_train_asr_conformer2_latest33_raw_char_sp_valid.acc.ave'

audio_file = "voice_lunch_jp_1min.wav"
output_waveform_image = "output_waveform.png"

# モデルのセットアップ
d = ModelDownloader()
speech2text = Speech2Text(
    **d.download_and_unpack(tag),
    device="cuda",
    minlenratio=0.0,
    maxlenratio=0.0,
    ctc_weight=0.3,
    beam_size=10,
    batch_size=0,
    nbest=1
)

def text_normalizer(text):
    """
    入力テキストを正規化する
    ・すべての文字を大文字に変換
    ・句読点などの記号を削除
    ※日本語ではあまり意味がなさそう
    """
    text = text.upper()
    return text.translate(str.maketrans('', '', string.punctuation))

# 音声ファイル読み込み
speech, rate = soundfile.read(audio_file)
assert rate == fs, "サンプリングレートが一致しません"

# ASR推論
nbests = speech2text(speech)
text, *_ = nbests[0]

print(f"Input Speech: {audio_file}")
print(f"ASR hypothesis: \n*****\n{text_normalizer(text)}\n*****")

# 画像生成処理:波形プロットを画像として保存する
plt.figure(figsize=(10, 4))
librosa.display.waveshow(speech, sr=rate, color="blue")
plt.title("Waveform")
plt.xlabel("Time (s)")
plt.ylabel("Amplitude")
plt.savefig(output_waveform_image)
plt.close()
print(f"Waveform image saved to: {output_waveform_image}")

グラフの描画でmatplotlibを追加。あとどうやらFlash attentionも使っているようなので追加しておく。

uv pip install matplotlib
uv pip install flash-attn --no-build-isolation
出力
(snip)
 + matplotlib==3.10.1
(snip)
出力
(snip)
 + flash-attn==2.7.4.post1
(snip)

実行

uv run asr.py
出力
Input Speech: voice_lunch_jp_1min.wav
ASR hypothesis:
*****
ということでありますけれどもまだ来られていない方もいらっしゃるんですけれどもこういったことがありますということで日本に来ていただきましてありがとうございますということで今日はスペシャルゲストの皆さんに来ていただいておりますということでございますけれども今日はストレートになりましたけれども今日はストレートの中でもあるということでございますということでございます
*****
Waveform image saved to: output_waveform.png

サンプルの音声クオリティはあまり良くないのではあるけども、それにしても、発話されていない無駄な繰り返しがあったりして、あまり認識は良くない。モデルを変えるとまた変わるのかも知れない。

上記はファイルからのバッチ処理だが、ストリーミングのサンプルもある

https://espnet.github.io/espnet/notebook/ESPnet2/Demo/ASR/streaming_asr_demo.html

最初、1つ前で使った日本語モデルでそのままやったのだけどエラーになって、どうやらストリーミングはストリーミング専用のモデルを使わないとダメみたい。

日本語だとこのモデルが使えそう。

https://huggingface.co/eml914/streaming_conformer_asr_csj

asr_stream_from_file.py
import sys
import wave
import numpy as np
from espnet_model_zoo.downloader import ModelDownloader
from espnet2.bin.asr_inference_streaming import Speech2TextStreaming

tag = 'eml914/streaming_conformer_asr_csj'
audio_file = "voice_lunch_jp_1min.wav"

# モデルのセットアップ
d=ModelDownloader()
speech2text = Speech2TextStreaming(
    **d.download_and_unpack(tag),
    token_type=None,
    bpemodel=None,
    maxlenratio=0.0,
    minlenratio=0.0,
    beam_size=20,
    ctc_weight=0.5,
    lm_weight=0.0,
    penalty=0.0,
    nbest=1,
    device = "cpu",
    disable_repetition_detection=True,
    decoder_text_length_limit=0,
    encoded_feat_length_limit=0
)


prev_lines = 0
def progress_output(text):
    """
    推論中の進捗を表示する
    ・50文字ごとに改行を挿入
    ・進捗を表示するために、前の行を上書きする
    """
    global prev_lines
    lines=['']
    for i in text:
        if len(lines[-1]) > 50:
            lines.append('')
        lines[-1] += i
    for i,line in enumerate(lines):
        if i == prev_lines:
            sys.stderr.write('\n\r')
        else:
            sys.stderr.write('\r\033[B\033[K')
        sys.stderr.write(line)

    prev_lines = len(lines)
    sys.stderr.flush()


def recognize(wavfile):
    """
    音声ファイルを読み込んで、ASR推論を行う
    """
    with wave.open(wavfile, 'rb') as wavfile:
        ch=wavfile.getnchannels()
        bits=wavfile.getsampwidth()
        rate=wavfile.getframerate()
        nframes=wavfile.getnframes()
        buf = wavfile.readframes(-1)
        data=np.frombuffer(buf, dtype='int16')
    # 32767は16ビットのバイナリ数の上限値であり、intをfloatに変換するための正規化に使用される
    speech = data.astype(np.float16)/32767.0
    sim_chunk_length = 640
    if sim_chunk_length > 0:
        for i in range(len(speech)//sim_chunk_length):
            results = speech2text(speech=speech[i*sim_chunk_length:(i+1)*sim_chunk_length], is_final=False)
            if results is not None and len(results) > 0:
                nbests = [text for text, token, token_int, hyp in results]
                text = nbests[0] if nbests is not None and len(nbests) > 0 else ""
                progress_output(nbests[0])
            else:
                progress_output("")
            
        results = speech2text(speech[(i+1)*sim_chunk_length:len(speech)], is_final=True)
    else:
        results = speech2text(speech, is_final=True)
    nbests = [text for text, token, token_int, hyp in results]
    progress_output(nbests[0])

recognize(audio_file)

実行

uv run asr_stream_from_file.py
出力
ライじゃ始めますちょっとまだ来られてない方はもういらしかるんですけどあおいらなくDP始めましゅ京阪んん
りもいらわられちおっあい日曜日に終わってまいただきましてありがとうございますえーと今日久しぶりにですね
オフラインということでえーっと今日はですねスペシャルなゲストを追ったりしていただいておりますということ
であああいえーと今日はちょっとをちトピックに回りますけれもえーっとこうイストローの使用であるんえーラン
ディンリームさんと後えートヘルスフォーストの終えーっとーマーレドラーラールレダインディーターターである
ーメリックベネストターに来ていただいてわーすということですとに来ていただいてありがと思っ

実際にはストリーミングで出力され、すでに出力されたものも後からの認識で修正されたりした場合は書き換わったりする。こちらも精度的にはちょっとイマイチ感ある。

マイクからのストリーミング。pyaudioを使用している。

uv pip install pyaudio
出力
(snip)
 + pyaudio==0.2.14
(snip)
asr_stream_from_mic.py
import sys
import pyaudio
import numpy as np
from espnet_model_zoo.downloader import ModelDownloader
from espnet2.bin.asr_inference_streaming import Speech2TextStreaming

# マイク入力のパラメータ設定
CHUNK=2048          # 一度に読み込むサンプル数
FORMAT=pyaudio.paInt16  # 16ビット整数で音声を取得
CHANNELS=1          # モノラル入力
RATE=16000         # サンプリングレート
RECORD_SECONDS=10    # 録音時間。この秒数が経過すると処理を終了する

tag = 'eml914/streaming_conformer_asr_csj'

# モデルのセットアップ
d=ModelDownloader()
speech2text = Speech2TextStreaming(
    **d.download_and_unpack(tag),
    token_type=None,
    bpemodel=None,
    maxlenratio=0.0,
    minlenratio=0.0,
    beam_size=20,
    ctc_weight=0.5,
    lm_weight=0.0,
    penalty=0.0,
    nbest=1,
    device = "cpu",
    disable_repetition_detection=True,
    decoder_text_length_limit=0,
    encoded_feat_length_limit=0
)


prev_lines = 0
def progress_output(text):
    """
    推論中の進捗を表示する
    ・50文字ごとに改行を挿入
    ・進捗を表示するために、前の行を上書きする
    """
    global prev_lines
    lines=['']
    for i in text:
        if len(lines[-1]) > 50:
            lines.append('')
        lines[-1] += i
    for i,line in enumerate(lines):
        if i == prev_lines:
            sys.stderr.write('\n\r')
        else:
            sys.stderr.write('\r\033[B\033[K')
        sys.stderr.write(line)

    prev_lines = len(lines)
    sys.stderr.flush()


p=pyaudio.PyAudio()
stream = p.open(format=FORMAT,channels=CHANNELS,rate=RATE,input=True,frames_per_buffer=CHUNK)

print(f"\n{RECORD_SECONDS}秒間録音します。話してください...")
print("=" * 50)

for i in range(0,int(RATE/CHUNK*RECORD_SECONDS)+1):
    data=stream.read(CHUNK)
    data=np.frombuffer(data, dtype='int16')
    # 32767は16ビットのバイナリ数の上限値であり、intをfloatに変換するための正規化に使用される
    data=data.astype(np.float16)/32767.0
    if i==int(RATE/CHUNK*RECORD_SECONDS):
        results = speech2text(speech=data, is_final=True)
        break
    results = speech2text(speech=data, is_final=False)
    if results is not None and len(results) > 0:
        nbests = [text for text, token, token_int, hyp in results]
        text = nbests[0] if nbests is not None and len(nbests) > 0 else ""
        progress_output(nbests[0])
    else:
        progress_output("")
nbests = [text for text, token, token_int, hyp in results]

progress_output(nbests[0])

実行

uv run asr_stream_from_mic.py
出力
10秒間録音します。話してください...
==================================================

ESPネットを使ってマイクからリアルタイム文字起こしをしてみました

今回はきれいに文字起こしできた。

kun432kun432

TTS

https://espnet.github.io/espnet/notebook/ESPnet2/Demo/TTS/tts_realtime_demo.html

環境は前回の続きで。

以下を追加

uv pip install pypinyin gdown

pypinyinは既にあったみたい。

出力
 + gdown==5.2.0

で、parallel_waveganだが、

uv pip install parallel_wavegan
出力
      ModuleNotFoundError: No module named 'pip'

      hint: This usually indicates a problem with the package or the build environment.

Remdisのときもうまくいかなかったのだよな。

もはやuvの意味がない気もするが、まああとりあえず。

uv pip install pip
出力
+ pip==25.0.1
source .venv/bin/activate
git clone https://github.com/kan-bayashi/ParallelWaveGAN && cd ParallelWaveGAN
python setup.py develop
cd ..
deactivate

あとpyopenjtalkが必要だった。

uv pip install pyopenjtalk
出力
 + pyopenjtalk==0.4.0

ESPnet2のTTSでは音声生成の方法が2つある

  • Text2wavモデルを使う
    • テキストからWAVを直接生成するend-to-endモデル
      • VITS
  • Text2melモデル+ボコーダーを組み合わせる
    • Text2melモデルで、テキストからメルスペクトログラム(音の特徴量)を生成
      • Tacotron2
      • Transformer-TTS
      • (Conformer) FastSpeech
      • (Conformer) FastSpeech2
    • ボコーダーで、メルスペクトラムから最終的な音声波形を合成
      • Parallel WaveGAN
      • Multi-band MelGAN
      • HiFiGAN
      • Style MelGAN.

VITSモデル(kan-bayashi/jsut_full_band_vits_prosody)の例

tts.py
from espnet2.bin.tts_inference import Text2Speech
from espnet2.utils.types import str_or_none
import time
import torch
import soundfile as sf

# 言語の指定
lang = 'Japanese'

# モデルの指定
# - モデル名の先頭部分が学習に使用されたコーパスを指す
#
# Text2wavモデル(VITS)
# - Text2wavモデルを使用する場合はボコーダーを'none'にする
#tag = 'kan-bayashi/jsut_full_band_vits_prosody'
#tag = "kan-bayashi/jsut_vits_prosody"
#tag = "kan-bayashi/jsut_full_band_vits_prosody"
#tag = "kan-bayashi/jvs_jvs010_vits_prosody"
#tag = "kan-bayashi/tsukuyomi_full_band_vits_prosody"
#tag = "kan-bayashi/jsut_vits_accent_with_pause"
#tag = "kan-bayashi/jsut_full_band_vits_accent_with_pause"
#
# Text2melモデル
# - Text2melモデルを指定する場合はボコーダーも指定する
#tag = "kan-bayashi/jsut_tacotron2"
#tag = "kan-bayashi/jsut_transformer"
#tag = "kan-bayashi/jsut_fastspeech"
#tag = "kan-bayashi/jsut_fastspeech2"
#tag = "kan-bayashi/jsut_conformer_fastspeech2"
#tag = "kan-bayashi/jsut_conformer_fastspeech2_accent"
#tag = "kan-bayashi/jsut_conformer_fastspeech2_accent_with_pause"
#tag = "kan-bayashi/jsut_tacotron2_prosody"
#tag = "kan-bayashi/jsut_transformer_prosody"
#tag = "kan-bayashi/jsut_conformer_fastspeech2_tacotron2_prosody"
#
# ボコーダー
vocoder_tag = 'none'
#vocoder_tag = "parallel_wavegan/jsut_parallel_wavegan.v1"
#vocoder_tag = "parallel_wavegan/jsut_multi_band_melgan.v2"
#vocoder_tag = "parallel_wavegan/jsut_style_melgan.v1"
#vocoder_tag = "parallel_wavegan/jsut_hifigan.v1"

# モデルのセットアップ
text2speech = Text2Speech.from_pretrained(
    model_tag=str_or_none(tag),
    vocoder_tag=str_or_none(vocoder_tag),
    device="cuda",
    # Tacotron2 と Transformerを使用する場合のみ
    threshold=0.5,
    # Tacotron2を使用する場合のみ
    minlenratio=0.0,
    maxlenratio=10.0,
    use_att_constraint=False,
    backward_window=1,
    forward_window=3,
    # FastSpeech、FastSpeech2、VITSを使用する場合のみ
    speed_control_alpha=1.0,
    # VITSをしようする場合のみ
    noise_scale=0.333,
    noise_scale_dur=0.333,
)

# 音声を生成したいテキストを入力する
print(f"Input your favorite sentence in {lang}.")
x = input()

# 音声生成
with torch.no_grad():
    start = time.time()
    wav = text2speech(x)["wav"]
rtf = (time.time() - start) / (len(wav) / text2speech.fs)
print(f"RTF = {rtf:5f}")

# WAVファイルを出力
output_file = "output.wav"
audio_data = wav.view(-1).cpu().numpy()
sf.write(output_file, audio_data, text2speech.fs)
print(f"Output File: {output_file}")

実行。指定したモデルを初回利用する場合はモデルのダウンロードなどが行われるので少し時間がかかる。

uv run tts.py

発話させたい文章を入力する。

Input your favorite sentence in Japanese.
おはようございます!今日はいいお天気ですね。

ファイルに出力される

出力
RTF = 1.509218
Output File: output.wav

実際に生成されたもの

https://soundcloud.com/kuniaki-shimizu/espnet2-tts-ja-sample-using-kan-bayashijsut_full_band_vits_prosody?si=ea3802afed7a452fbd040a2889dcf9a4&utm_source=clipboard&utm_medium=text&utm_campaign=social_sharing

Text2melモデル+ボコーダーの例。以下を使用。

tts.py
(snip)
tag = "kan-bayashi/jsut_tacotron2"
(snip)
vocoder_tag = "parallel_wavegan/jsut_parallel_wavegan.v1"
(snip)

実行して見るとエラー。

出力
ImportError: cannot import name 'kaiser' from 'scipy.signal' 

どうやらこれと同じような感じ。

https://github.com/kan-bayashi/ParallelWaveGAN/issues/430

自分の環境では1.15.2になっていた

uv pip show scipy
出力
Name: scipy
Version: 1.15.2
(snip)

自分はParallelWaveGAN/parallel_wavegan/layers/pqmf.pyを直接修正した。

ParallelWaveGAN/parallel_wavegan/layers/pqmf.py
(snip)
from scipy.signal import kaiser
(snip)
ParallelWaveGAN/parallel_wavegan/layers/pqmf.py修正
(snip)
from scipy.signal.windows import kaiser
(snip)

再度実行したらエラーなくいけた。入力した文字列は上と同じ。

https://soundcloud.com/kuniaki-shimizu/espnet2-tts-ja-sample-using-kan-bayashijsut_tacotron2-parallel_waveganjsut_parallel_waveganv1?si=83f0e930230a4f839ef905485e0b4328&utm_source=clipboard&utm_medium=text&utm_campaign=social_sharing

モデルを変更したり組み合わせを変えてみたりして試すと良い。

複数スピーカーモデル(1つのモデルに複数の話者音声が含まれている)を使うこともできるが、英語のみのようなので割愛。

kun432kun432

SE

音声強調(Speech Enhancement)。訳的にピンとこないのだが、要は雑音などが入ったオーディオデータから特定の音声を抽出したり、複数話者事に音声を分離したりということなのだと思う。

2つのnotebookがあるが、

https://espnet.github.io/espnet/notebook/ESPnet2/Demo/SE/se_demo.html

https://espnet.github.io/espnet/notebook/ESPnet2/Demo/SE/se_demo_for_waspaa_2021.html

どちらも一番最初の「Single-Channel Enhancement, the CHiME example」でコケる・・・多分なにかしらライブラリ側なりモデルなりが変更されていて動かないのだと思う。

スキップ。

kun432kun432

まとめ

ESPnet、以前からあるもの、というような認識しかしてなくて、きちんと試したことはなかったが、今回一通り試せて、音声関連の様々なタスクを包括的に扱っているフレームワークなのだと認識した。以下などを読むと非常に良く考えられているというのがわかる。

https://qiita.com/kan-bayashi/items/536acaf165344a6d6460

https://qiita.com/kan-bayashi/items/0371e06202641dbfa0ad

ただこれを学ぼうと思うと、

  • 正直、どこからスタートすればいいのかわからない。
  • 用語の説明がほしい。ESPnet1と2の違いとか、あとESPnet-EZとは?とか。
  • ノートブックがあるのは良いが、見た感じ内容が古い

あたり、ドキュメント周りが辛いという印象。

なので、まずは、上に記載したQiitaの記事を読むか、以下のリンクなどを読んで、概要を理解してから始めるのが良さそう(なお、全てESPnetの中の人の執筆によるもの)。こういうのが公式ドキュメント以外に分散してるってのがしんどいな。

https://www.jstage.jst.go.jp/article/jasj/76/12/76_720/_article/-char/ja/

https://kan-bayashi.github.io/asj-espnet2-tutorial/

(余談だけど、このスライドをまず一番最初に見たかった・・・)

とはいえ、自分の引き出しを1つ増やせたので良かったし、こういうフレームワークが用意されていること自体ありがたいことである。今後は学習にもトライしてみたい。

このスクラップは27日前にクローズされました
ログインするとコメントできます