promptttsppで合成音声を試す(Winodows)

初めに

新しくttsのライブラリが出たので触ってみます

論文の中では日本語の音声合成にも触れられていましたが、デモ版では日本語はできないみたいです

環境

  • WIndows 11
  • anaconda
  • RTX 4070 Ti Super

準備

公式のReadMeの通りに進めていきます

conda create -n py38_prompt python=3.8 numpy scipy scikit-learn numba cython pandas tqdm
conda activate py38_prompt
pip install "torch==1.11.0+cu113" "torchvision==0.12.0+cu113" "torchaudio==0.11.0" --extra-index-url https://download.pytorch.org/whl/cu113
pip install -e .

また 以下のhfから事前学習モデルをダウンロードして以下のように配置します

huggingface.co

egs\proposed\bin\conf\demo.yaml の 設定を書き換えます

model_ckpt_path: ./pretrained_model/checkpoint/proposed/last.ckpt
vocoder_ckpt_path: ./pretrained_model/checkpoint/bigvgan_f0_full/last.ckpt
mel_stats_file: ./pretrained_model/checkpoint/pretrained_model_checkpoint_stats.yaml

実行

以下で動かすことできます

python app.py

推論時間は1.7s程度でした

以下の箇所で計測しています

    @torch.no_grad()
    def onclick_synthesis(content_prompt, style_prompt=None, reference_mel=None):
        start_time = time.perf_counter()
        assert style_prompt is not None or reference_mel is not None
        device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
        phonemes = g2p(content_prompt)
        phonemes = [p if p not in [",", "."] else "sil" for p in phonemes]
        phonemes = [p for p in phonemes if p in symbols]
        phoneme_ids = text_to_sequence(" ".join(phonemes))
        phoneme_ids = torch.LongTensor(phoneme_ids)[None, :].to(device)
        if style_prompt is not None:
            dec, log_cf0, vuv = model.infer(
                phoneme_ids,
                style_prompt=style_prompt,
                use_max=True,
                noise_scale=0.5,
                return_f0=True,
            )
        else:
            reference_mel = (reference_mel - mel_stats["mean"]) / mel_stats["std"]
            reference_mel = reference_mel.to(device)
            dec, log_cf0, vuv = model.infer(
                phoneme_ids,
                reference_mel=reference_mel,
                use_max=True,
                noise_scale=0.5,
                return_f0=True,
            )
        modfs = int(1.0 / (10 * 0.001))
        log_cf0 = lowpass_filter(log_cf0, modfs, cutoff=20)
        f0 = log_cf0.exp()
        f0[vuv < 0.5] = 0
        dec = dec * mel_stats["std"] + mel_stats["mean"]
        wav = vocoder(dec, f0).squeeze(1).cpu()
        
        # 終了時間を記録
        end_time = time.perf_counter()
        inference_time = end_time - start_time
        print(f"推論時間: {inference_time:.4f} 秒")
        return wav

F5-TTSで音声合成を試す

初めに

Flow MatchingとDiffusion Transformer(DiT)を基盤にした完全な非自己回帰型テキスト音声合成(TTS)である F5-TTSが公開されています

以下 ライブラリの詳細です( ReadMeより ChatGPTから生成したものです)

構成要素の概要

エンコーダー(Encoder)

エンコーダーは、テキスト入力を音声に変換するための特徴表現を生成する役割を果たします。このシステムでは、ConvNeXTブロックを使用して、テキスト入力を時間的に調整された音声特徴と一致させることができます。この部分は従来のTTSで使われていた複雑な設計(例: Duration Model, Text Encoder, Phoneme Alignment)を排除し、単にテキストに「Filler Tokens」をパディングして音声の長さに合わせるという簡単な手法を取っています。これにより、モデルはテキストと音声のアライメントを簡単に行えるようにしています。

デコーダー(Decoder)

デコーダーは、エンコーダーからの特徴表現を用いて最終的な音声を生成します。このシステムでは、DiTブロック(Diffusion Transformer)がその役割を担います。DiTブロックは、予測されたフローを基に音声を生成するための時間ステップごとのスケーリングや変換を行います。このプロセスでは、時間ステップ ( t \sim U[0,1] ) から始まり、入力データを次々と処理していく「拡散プロセス」が適用されます。

ボコーダーVocoder

ボコーダーは、最終的に生成された音声スペクトログラムを実際の波形データに変換する部分です。このシステムでは、「ODE Solver」というプロセスを通じて、生成された音声メルスペクトログラムを波形データに変換します。これにより、生成されたメルスペクトログラムを直接人間の耳に聞こえる音声に変換する役割を果たします。

特徴的な部分

Sway Sampling

推論時に適用されるサンプリング戦略で、既存のFlow Matchingベースのモデルにも再トレーニングなしで適用可能です。これにより、効率と性能が大幅に向上します。推論リアルタイムファクター(RTF)は0.15と、従来の拡散ベースのTTSモデルと比較して大幅に改善されています。

ConvNeXT

入力テキストの特徴抽出にはConvNeXTブロックを使用し、これは近年の画像処理モデルで高い性能を示しているアーキテクチャです。このモデルは、テキストと音声の特徴表現を精緻に整列させる役割を果たし、従来のテキストエンコーダーよりも効率的です。

レーニングと推論

レーニングデータ

システムは100K時間の多言語データセットでトレーニングされており、その結果、高い自然性や表現力を持つ音声を生成できます。また、コードスイッチング(異なる言語間での切り替え)や速度制御も可能で、幅広い用途に対応できます。

非自己回帰型TTS

非自己回帰型TTSは、自己回帰型のモデルと異なり、推論時に音声フレームを一度に並列生成するため、速度が速くなるという利点があります。このF5-TTSシステムは、従来の自己回帰型モデルと比べて大幅な速度向上を実現しています。

環境

準備

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

公式のリポジトリだと動かなかったので、以下で修正したものがあります

github.com

uv pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
uv pip install -r requirements.txt

事前学習モデルの配置

以下から各モデルをダウンロードして、画像のように配置します

huggingface.co

実行

以下でttsの推論をすることができます

uv run .\test_infer_single.py

使用する事前学習モデルを変更する場合は、以下の箇所を変更します

exp_name = "E2TTS_Base"  # F5TTS_Base | E2TTS_Base

推論時の参照音声および生成するテキストを変更するには、以下の変更します

ref_audio = "tests/ref_audio/test_en_1_ref_short.wav"
ref_text = "Some call me nature, others call me mother nature."
gen_text = "I don't really care what you call me. I've been a silent spectator, watching species evolve, empires rise and fall. But always remember, I am mighty and enduring. Respect me and I'll nurture you; ignore me and you shall face the consequences."

crcmodのインストールでstream did not contain valid UTF-8のエラー対応

開発環境

詳細

crcmod(==1.7)をインストールする際に以下のエラーが出ました。

error: Failed to prepare distributions
  Caused by: Failed to fetch wheel: crcmod==1.7
  Caused by: Failed to run `C:\Users\name\AppData\Local\uv\cache\builds-v0\.tmpv87Zlw\Scripts\python.exe`
  Caused by: stream did not contain valid UTF-8

以下で解決できます

$Env:PYTHONUTF8 = "1"

arXivAPIを使って気になる論文を探してタイトルとサマリを表示する

初めに

査読前の論文がアップロードされている arXivを気になったものを見ているものの気になるものを全て探すのは大変なので API経由で検索をしていきます

記事の内容のリポジトリは以下で公開しています

github.com

開発環境

詳細

やりたいこと * 気になる特定のトピックの中から最新のものを探す * タイトルおよびSummaryを見る

以下で最新の内容からトピックを探してきます

import urllib.parse
import feedparser

# 検索クエリを定義
query = 'all:"LLM" OR all:"Text to Speech" OR all:"Speech to Text" OR all:"AI Character"'

# クエリをURLエンコード
encoded_query = urllib.parse.quote(query)

# ベースとなるAPIのURL
base_url = 'http://export.arxiv.org/api/query?'

# APIパラメータの設定
params = {
    'search_query': encoded_query,
    'start': 0,            # 取得開始位置
    'max_results': 10,     # 取得する結果の最大数
    'sortBy': 'submittedDate',   # 提出日の新しい順にソート
    'sortOrder': 'descending',
}

# パラメータをURLエンコードしてクエリ文字列を作成
query_string = '&'.join(f'{key}={value}' for key, value in params.items())

# 完全なAPIリクエストURLを構築
url = base_url + query_string

# フィードをパース
feed = feedparser.parse(url)

# 各論文についてタイトルと要約を表示
for entry in feed.entries:
    title = entry.title
    summary = entry.summary.replace('\n', ' ')  # 改行を削除して整形
    print(f'タイトル: {title}')
    print(f'要約: {summary}')
    print('-' * 80)

結果は以下のようになります

タイトル: Justice or Prejudice? Quantifying Biases in LLM-as-a-Judge
要約: LLM-as-a-Judge has been widely utilized as an evaluation method in various benchmarks and served as supervised rewards in model training. However, despite their excellence in many domains, potential issues are under-explored, undermining their reliability and the scope of their utility. Therefore, we identify 12 key potential biases and propose a new automated bias quantification framework-CALM-which systematically quantifies and analyzes each type of bias in LLM-as-a-Judge by using automated and principle-guided modification. Our experiments cover multiple popular language models, and the results indicate that while advanced models have achieved commendable overall performance, significant biases persist in certain specific tasks. Empirical results suggest that there remains room for improvement in the reliability of LLM-as-a-Judge. Moreover, we also discuss the explicit and implicit influence of these biases and give some suggestions for the reliable application of LLM-as-a-Judge. Our work highlights the need for stakeholders to address these issues and remind users to exercise caution in LLM-as-a-Judge applications.
--------------------------------------------------------------------------------
タイトル: Adaptive Inference-Time Compute: LLMs Can Predict if They Can Do Better,
  Even Mid-Generation
要約: Inference-time computation is a powerful paradigm to enhance the performance of large language models (LLMs), with Best-of-N sampling being a widely used technique. However, this method is computationally expensive, requiring both (1) an external reward model and (2) the generation of multiple samples. In this work, we introduce a new generative self-evaluation scheme designed to adaptively reduce the number of generated samples while maintaining or even improving performance. We use a generative reward model formulation, allowing the LLM to predict mid-generation the probability that restarting the generation will yield a better response. These predictions are obtained without an external reward model and can be used to decide whether or not to generate more samples, prune unpromising samples early on, or to pick the best sample. This capability is very inexpensive as it involves generating a single predefined token. Trained using a dataset constructed with real unfiltered LMSYS user prompts, Llama 3.1 8B's win rate against GPT-4 on AlpacaEval increases from 21% to 34% with 16 samples and math performance on GSM8K improves from 84% to 91%. By sampling only when the LLM determines that it is beneficial to do so and adaptively adjusting temperature annealing, we demonstrate that 74% of the improvement from using 16 samples can be achieved with only 1.2 samples on average. We further demonstrate that 50-75% of samples can be pruned early in generation with minimal degradation in performance. Overall, our methods enable more efficient and scalable compute utilization during inference for LLMs. 
--------------------------------------------------------------------------------

Windows(WSL)にSingularityCEをインストールする

はじめに

Singularity は、高パフォーマンスコンピューティング(HPC)環境でのコンテナ実行を可能にするコンテナプラットフォームです。WSL 上で Singularity を利用することで、Linux コンテナを Windows 環境で動作させることができます。

本記事では、WSL(Ubuntu 20.04)上で SingularityCE 4.2.1 をソースからビルドしてインストールする手順になります。

開発環境

インストール方法

必要なパッケージのインストール

まず、Singularity のビルドに必要なパッケージをインストールします。

sudo apt-get update
sudo apt-get install -y \
    build-essential \
    libssl-dev \
    uuid-dev \
    libgpgme-dev \
    squashfs-tools \
    libseccomp-dev \
    wget \
    pkg-config \
    git \
    cryptsetup \
    libglib2.0-dev \
    libfuse-dev \
    libfuse3-dev \
    libjson-c-dev

Go 言語のインストール

既存の Go の削除(必要な場合)

sudo rm -rf /usr/local/go

最新の Go のダウンロードとインストール

# 最新の Go 1.21.1 をダウンロード
wget https://go.dev/dl/go1.21.1.linux-amd64.tar.gz

# /usr/local に展開
sudo tar -C /usr/local -xzf go1.21.1.linux-amd64.tar.gz

# ダウンロードしたアーカイブを削除
rm go1.21.1.linux-amd64.tar.gz

環境変数を設定します

echo 'export GOPATH=${HOME}/go' >> ~/.bashrc
echo 'export PATH=/usr/local/go/bin:${PATH}:${GOPATH}/bin' >> ~/.bashrc
source ~/.bashrc

ここでインストールしたgoのversionを確認します

go version

以下の出力ができてきます

go version go1.21.1 linux/amd64

Singularity のソースコードのダウンロード

リポジトリからクローンします

git clone https://github.com/sylabs/singularity.git
cd singularity

configの設定を使って処理を実行します

./mconfig

ビルドをしてインストールをします

make -C builddir
sudo make -C builddir install

以下でインストール後の確認ができます

singularity --version

以下のような出力がされてたら成功です

singularity-ce version 4.2.1

エラー対応

  1. glib-2.0 headers are required to build conmon.

以下で追加のライブラリを入れます

sudo apt-get install libglib2.0-dev

参考サイト

zenn.dev

uvでrequirements.txtからインストールをする

参考

(この記事はとても参考になっています)

zenn.dev

開発環境

内容

requirements.txt を使って ライブラリをインストールするときのメモ

pythonのversionの固定

以下で 特定のversionをインストールします

uv python install 3.9.20 

以下で使用するversionを固定します

uv venv -p 3.9.20

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

以下で インストールをすることができます

uv pip sync requirements.txt

また以下をすることによってライブラリの依存を pyproject.toml に記載してくれます

uv add -r requirements.txt

fish-speechのFine-tuningを独自データで行う

初めに

fish-speech v1.4がリリースされたので、改めて触ってみます。

前回 CLIで推論を行う記事を書いたので、今回は つくよみちゃん会話AI育成計画(会話テキストデータセット配布) を使って学習を進めていきます

ayousanz.hatenadiary.jp

環境

docker環境の作成

まずは fish-speechをcloneします。

https://github.com/fishaudio/fish-speech.git

docker環境が準備されているので、docker環境をビルドして立ち上げます。

docker-compose -f docker-compose.dev.yml up -d

ビルドしたdocker環境には以下のコマンドで入ることができます

docker exec -it fish-speech /bin/bash

音声データセットの準備

今回は つくよみちゃんデータセットを使うので、データセットをダウンロードしてきます。

次に 以下のようなフォルダ構成を作成します

/exp/
├── data-raw/
│   ├── tsukuyomi-chan/

この中に音声ファイルを入れます。

ノーマライゼーション処理

はじめに 音声のノーマライゼーションを行います

fap loudness-norm data-raw data --clean

fapコマンドがない場合は、以下でインストールをします

pip install fish-audio-preprocess

(docker環境内でほかのライブラリと依存関係が一致しない場合は、docker外で別環境を作成してそちらでインストールを行うとうまく動きました。)

この処理が終わると /data に処理後の音声が保存されます。

ファイルによってはうまく処理がされない場合があるので、以下の修正を行ったverを作成しました。

  • ファイルのI/O処理のチャンク対応
  • 音声のクリッピングの際に音声の長さの考慮

github.com

必要に応じてこちらをcloseして以下でインストールを行い処理をします。

pip install -e .

文字お越しファイルの作成

/data の音声から それぞれの音声ファイルに対する .lab ファイルを作成します。

以下のコードで つくよみちゃんの文字起こしのテキストファイルと音声ファイルを使って labファイルを作成します。

import re
import os
import argparse

def process_text_file(input_file, output_dir):
    # 出力ディレクトリが存在しない場合は作成
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)

    with open(input_file, 'r', encoding='utf-8') as f:
        lines = f.readlines()

    for line in lines:
        # 空行をスキップ
        if line.strip() == "":
            continue

        match = re.match(r'(VOICEACTRESS100_\d+):(.+)', line.strip())
        if match:
            file_name = match.group(1) + '.lab'
            content = match.group(2).strip()
        else:
            # マッチしない行の場合、ファイル名を生成
            file_name = f'line_{lines.index(line) + 1}.lab'
            content = line.strip()
        
        # .lab ファイルを作成し、内容を書き込む
        with open(os.path.join(output_dir, file_name), 'w', encoding='utf-8') as out_file:
            out_file.write(content)

def main():
    parser = argparse.ArgumentParser(description='Generate .lab files from input text file.')
    parser.add_argument('input_file', help='Path to the input text file')
    parser.add_argument('--output_dir', default='output', help='Path to the output directory (default: output)')

    args = parser.parse_args()

    process_text_file(args.input_file, args.output_dir)

if __name__ == "__main__":
    main()

実行は以下のコマンドで実行することができます。

python generate_lab_files.py input_text.txt --output_dir custom_output

セマンティックトークンのバッチ抽出

VQGANの重みをダウンロードをダウンロードします。

huggingface-cli download fishaudio/fish-speech-1.4 --local-dir checkpoints/fish-speech-1.4

セマンティックトークンを抽出します。

python tools/vqgan/extract_vq.py data \
    --num-workers 1 --batch-size 16 \
    --config-name "firefly_gan_vq" \
    --checkpoint-path "checkpoints/fish-speech-1.4/firefly-gan-vq-fsq-8x1024-21hz-generator.pth"

データセットをprotobufにパック

以下でデータセットからprotobufを生成します。

python tools/llama/build_dataset.py \
    --input "data" \
    --output "data/protos" \
    --text-extension .lab \
    --num-workers 16

LoRAの学習

LLAMAの重みをダウンロードします。

huggingface-cli download fishaudio/fish-speech-1.4 --local-dir checkpoints/fish-speech-1.4

docker環境で学習をする場合、shm_sizeが小さいとエラーになるため docker_compose.dev.yml に以下を追加します。

shm_size: 30gb

追加後は以下にようになります

services:
  fish-speech:
    build: .
    container_name: fish-speech
    shm_size: 30gb

batchサイズやデータの並列処理部分のパラメータは text2semantic_finetune.yaml の 以下で変更することができます。

  num_workers: 2
  batch_size: 4

学習時のステップ数や保存するタイミングは以下のパラメータになります。

  max_steps: 5000
  limit_val_batches: 1000
  val_check_interval: 1000

以下でLoRAの学習を開始することができます。 my_voice_project は任意のプロジェクト名を指定してください。

python fish_speech/train.py --config-name text2semantic_finetune \
    project=my_voice_project \
    +lora@model.model.lora_config=r_8_alpha_16

学習後のLoRAの重みを変換

学習が終わった後に生成されるファイルは .ckpt というファイルになっているため、こちらを .pth に変換する必要があります。

以下のコマンドで重みの変換を行います。

python tools/llama/merge_lora.py \
    --lora-config r_8_alpha_16 \
    --base-weight checkpoints/fish-speech-1.4 \
    --lora-weight results/$project/checkpoints/step_000000010.ckpt \
    --output checkpoints/fish-speech-1.4-yth-lora/

学習後のモデルを使って推論

音声推論をする場合は、CLIとWeb版などいくつか選ぶことができます。

CLIは以下を参考にしてください。

ayousanz.hatenadiary.jp

今回は視覚的にわかりやすいWeb版を立ち上げていきます。

まずは必要なモデルをダウンロードします。

huggingface-cli download fishaudio/fish-speech-1.4 --local-dir checkpoints/fish-speech-1.4

以下でWebUIを立ち上げることができます

python -m tools.webui \
    --llama-checkpoint-path "変換したLoRAの重みを保存したパス" \
    --decoder-checkpoint-path "checkpoints/fish-speech-1.4/firefly-gan-vq-fsq-8x1024-21hz-generator.pth" \
    --decoder-config-name firefly_gan_vq

備考

変更差分は以下にpushしています。

github.com