talkbank/callhomeの日本語音声をwav形式で保存する

開発環境

セットアップ

ライブラリをインストールします

uv pip install datasets[audio] soundfile pydub 

実行

以下でデータセットをダウンロードして、wav形式で保存します

from datasets import load_dataset
import soundfile as sf  # wavファイルの保存に使用
from pydub import AudioSegment  # mp3ファイルの保存に使用
import os

# 日本語のデータセットをロード
ds = load_dataset("diarizers-community/callhome", "jpn", split='data')

# 保存先のディレクトリを指定
output_dir = "callhome_japanese_audio"
os.makedirs(output_dir, exist_ok=True)

# 音声データをループして保存
for idx, example in enumerate(ds):
    # 音声データの取得
    audio = example['audio']
    array = audio['array']
    sampling_rate = audio['sampling_rate']

    # ファイル名を作成
    filename_base = f"callhome_jpn_{idx}"

    # wavファイルとして保存
    wav_path = os.path.join(output_dir, f"{filename_base}.wav")
    sf.write(wav_path, array, sampling_rate)
    print(f"Saved WAV file: {wav_path}")

pyannote + whisperで話者ダイアライゼーションを行う

初めに

今回は定番のpyanonoteとwhisperで話者ダイアライゼーションを行ってみます

以下で記事のサンプルリポジトリを公開しています

github.com

過去にはほかのライブラリでも試しているので、ほかにどのようなライブラリがあるのか気になる場合はご覧ください

ayousanz.hatenadiary.jp

ayousanz.hatenadiary.jp

ayousanz.hatenadiary.jp

開発環境

セットアップ

uv でpython 3.9の環境を作ります. pyanonoteが依存している numbaが3.10以上は対応していませんでした

uv venv -p 3.9
source venv/bin/activate

必要なライブラリを入れていきます

uv pip install pyannote.audio

torchをgpu版を入れます

uv pip install torch==2.5.1 torchaudio==2.5.1 --index-url https://download.pytorch.org/whl/cu121 --force-reinstall

mp3のファイルを扱えるように 追加のライブラリを入れます

uv pip install pydub

文字お越しようにwhisperを入れます

uv pip install - U openai-whisper

実行

以下のスクリプトを実行することで話者ダイアライゼーションおよび文字起こしを行うことができます

# 必要なライブラリのインポート
from pyannote.audio import Pipeline
import whisper
import numpy as np
from pydub import AudioSegment

# 話者分離モデルの初期化
pipeline = Pipeline.from_pretrained("pyannote/speaker-diarization-3.1")

# Whisperモデルのロード
model = whisper.load_model("large-v3")

# 音声ファイルを指定
audio_file = "JA_B00000_S00529_W000007.mp3"  # MP3ファイルを指定します

# 話者分離の実行
diarization = pipeline(audio_file)

# MP3ファイルをAudioSegmentで読み込む
audio_segment = AudioSegment.from_file(audio_file, format="mp3")

# 音声ファイルを16kHz、モノラルに変換
audio_segment = audio_segment.set_frame_rate(16000).set_channels(1)

# 話者分離の結果をループ処理
for segment, _, speaker in diarization.itertracks(yield_label=True):
    # 話者ごとの発話区間の音声を切り出し(ミリ秒単位)
    start_ms = int(segment.start * 1000)
    end_ms = int(segment.end * 1000)
    segment_audio = audio_segment[start_ms:end_ms]

    # 音声データをnumpy配列に変換
    waveform = np.array(segment_audio.get_array_of_samples()).astype(np.float32)

    # 音声データを[-1.0, 1.0]の範囲に正規化
    waveform = waveform / np.iinfo(segment_audio.array_type).max

    # Whisperによる文字起こし
    # 音声データをサンプリングレート16kHzに合わせて、テンソルに変換
    result = model.transcribe(waveform,fp16=False)

    # 話者ラベル付きで結果をフォーマットして出力
    for data in result["segments"]:
        start_time = segment.start + data["start"]
        end_time = segment.start + data["end"]
        print(f"{start_time:.2f},{end_time:.2f},{speaker},{data['text']}")

結果は以下になります

0.03,4.15,SPEAKER_00,物事に対しても、真っ直ぐに取り組めるような姿勢とか、

Wespeaker/wespeaker-voxceleb-resnet34-LMで話者ダイアライゼーションを行う

初めに

wespeakerで話者ダイアライゼーションを行ってみます。

モデルは以下です

huggingface.co

以下に記事の内容のRepositoryを公開しています

github.com

開発環境

セットアップ

まずは uv環境を作成します

uv venv -p 3.11
.venv\Scripts\activate 

次に必要なライブラリを入れていきます

uv pip install git+https://github.com/wenet-e2e/wespeaker.git
uv pip install PyYAML setuptools requests soundfile

torchのgpu版をインストールします

uv pip install torch --index-url https://download.pytorch.org/whl/cu121 --force-reinstall

モデルのダウンロードを行います

huggingface-cliのインストールを行い、ログインを済ませておきます

uv pip install -U "huggingface_hub[cli]"
huggingface-cli login

以下でモデルのダウンロードを行うことができます

huggingface-cli download --repo-type model Wespeaker/wespeaker-voxceleb-resnet34-LM --local-dir ResNet34_download_dir

CLIから実行

デフォルトではwavファイルのみの対応になっているため、mp3等の場合は ffmpeg等で以下のように変換をします

ffmpeg -i JA_B00000_S00529_W000007.mp3 JA_B00000_S00529_W000007.wav

wavに変換ができたら、以下のコマンドを実行します

 wespeaker -p ResNet34_download_dir --task diarization --audio_file .\JA_B00000_S00529_W000007.wav

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

0.000   4.500   0

Pythonのコードで実行

PythonのスクリプトでもCLIのコマンドと同様のことを行ってみます

以下のスクリプトを実行します

import wespeaker

# モデルのパスを指定
model_dir = 'ResNet34_download_dir'
model = wespeaker.load_model_local(model_dir)
# model.set_gpu(0)

# 音声ファイルのパスを指定
audio_file = 'JA_B00000_S00529_W000007.mp3'

# 話者ダイアリゼーションの実行
diarization_result = model.diarize(audio_file)

# 結果の表示
for segment in diarization_result:
    # segmentの内容を確認(デバッグ用)
    print(f"Segment content: {segment}, Type: {type(segment)}")
    start_time = float(segment[1])
    end_time = float(segment[2])
    speaker_label = segment[3]
    print(f"{start_time:.3f}\t{end_time:.3f}\t{speaker_label}")

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

Segment content: ('unk', 0.0, 4.5, 0), Type: <class 'tuple'>
0.000   4.500   0

Segmetの一つ目のデータは、今回必要ないため表示はしないようにしています

備考

以下のモデルのほうが日本語の精度は高いみたいです

huggingface.co

powerset_calibrationを使って話者ダイアライゼーションを行う

初めに

powerset_calibrationを使って音声内の話者ダイアライゼーションを行ってみます。論文によりデータセットには日本語が含まれていないため、日本語の音声に使う場合は自分で学習を行う必要がありそうです

github.com

以下で動かしたリポジトリを公開しています

github.com

開発環境

セットアップ

環境を作っていきます

uv venv -p 3.9
.venv\Scripts\activate

ライブラリをインストールします。リポジトリで pyproject.toml が提供されているので、そのまま使っていきます

uv sync

torchがcpu版になっているので、GPU版をインストールします

uv pip install torch==2.5.1 --index-url https://download.pytorch.org/whl/cu121 --force-reinstall

話者ダイアライゼーションを実行

from pyannote.audio import Pipeline

# プリトレーニング済みモデルのロード
pipeline = Pipeline.from_pretrained("pyannote/speaker-diarization")

# 音声ファイルのパス(ご自身のファイルパスに変更してください)
AUDIO_FILE = "test.mp3"

# ダイアリゼーションの実行
diarization = pipeline(AUDIO_FILE)

# 結果の表示
for turn, _, speaker in diarization.itertracks(yield_label=True):
    print(f"start={turn.start:.1f}s stop={turn.end:.1f}s speaker_{speaker}")

上記のコードで実行をします

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

start=0.0s stop=5.0s speaker_SPEAKER_00

nvidia/parakeet-tdt_ctc-0.6b-jaをWindowsで動かす際のAttributeError: module 'signal' has no attribute 'SIGKILL'. Did you mean: 'SIGILL'?の対応

初めに

NVIDIAが公開している日本語音声向けの音声認識モデル nvidia/parakeet-tdt_ctc-0.6b-jaを Windowsで動かす際に以下のエラーが出た多ため、対応方法を記載します

packages\nemo\collections\asr\models\configs\asr_models_config.py", line 27, in <module>
    from nemo.core.config import modelPT as model_cfg
  File "C:\Users\.venv\Lib\site-packages\nemo\core\config\modelPT.py", line 22, in <module>
    from nemo.utils import exp_manager
  File "C:\Users\.venv\Lib\site-packages\nemo\utils\exp_manager.py", line 160, in <module>
    class FaultToleranceParams:
  File "C:\Users\.venv\Lib\site-packages\nemo\utils\exp_manager.py", line 169, in FaultToleranceParams
    rank_termination_signal: signal.Signals = signal.SIGKILL
                                              ^^^^^^^^^^^^^^
AttributeError: module 'signal' has no attribute 'SIGKILL'. Did you mean: 'SIGILL'?

開発環境

原因

このエラーは、PythonのsignalモジュールでSIGKILLシグナルが定義されていないことが原因です。Windows環境では、一部のUnix/Linux固有のシグナルがサポートされておらず、SIGKILLもその一つです。そのため、nemoライブラリがsignal.SIGKILLを使用しようとすると、Windows環境ではAttributeErrorが発生します。

対応方法

.venv\Lib\site-packages\nemo\utils\exp_manager.py にあるファイルの一部を書き換えます

class FaultToleranceParams内のrank_termination_signalを以下のように変更します。

修正前

rank_termination_signal: signal.Signals = signal.SIGKILL

修正後

import os
if os.name == 'nt':
    rank_termination_signal: int = signal.SIGTERM
else:
    rank_termination_signal: signal.Signals = signal.SIGKILL

備考

parakeetはnumpyが2.0.0以上だと以下のエラーになるため、1.x.xを使う必要があります

  File "C:\Users\.venv\Lib\site-packages\numpy\__init__.py", line 411, in __getattr__
    raise AttributeError(
AttributeError: `np.sctypes` was removed in the NumPy 2.0 release. Access dtypes explicitly instead.. Did you mean: 'dtypes'?   

reazonspeech-k2-v2を動かす

初めに

reazon-researchが新しい音声認識モデルを公開されていたので触ってみます

以下に動かしたRepositoryを公開しています

github.com

開発環境

セットアップ

動かすための環境を作ります

uv venv -p 3.11
source venv/bin/activate

ライブラリをインストールします

git clone https://github.com/reazon-research/ReazonSpeech
uv pip install ReazonSpeech/pkg/k2-asr

文字お越しの実行

適当な音声ファイルを使って文字お越しを行います。今回は amphion/Emilia-Datasetの一音声を使ってみます

from reazonspeech.k2.asr import load_model, transcribe, audio_from_path

audio = audio_from_path("JA_B00000_S00529_W000007.mp3")
model = load_model()
ret = transcribe(model, audio)
print(ret.text)

S3Tokenizerを動かす

初めに

CosyVoiceの教師あり音声トークナイザーに関するコードが出ていなかったため issue、以下のRepositoryにて再現実装が行われました。こちらを動かしていきます

github.com

以下でライブラリのverを固定したRepositoryを公開しています

github.com

開発環境

セットアップ

uvの環境を作ります

uv venv -p 3.11
.venv\Scripts\activate

必要なライブラリをインストールします

uv pip install -r requirements.txt 
uv pip install torch==2.5.1 --index-url https://download.pytorch.org/whl/cu121 --reinstall-force 
uv pip install onnxruntime soundfile

インストールが終わったら以下のようなライブラリが入っています

cffi==1.17.1
colorama==0.4.6
coloredlogs==15.0.1
einops==0.8.0
filelock==3.13.1
flatbuffers==24.3.25
fsspec==2024.2.0
humanfriendly==10.0
jinja2==3.1.3
markupsafe==2.1.5
mpmath==1.3.0
networkx==3.2.1
numpy==2.2.0
onnx==1.17.0
onnxruntime==1.20.1
packaging==24.2
protobuf==5.29.1
pycparser==2.22
pyreadline3==3.5.4
s3tokenizer==0.0.8
soundfile==0.12.1
sympy==1.13.1
torch==2.5.1+cu121
tqdm==4.67.1
typing-extensions==4.9.0

実行

サンプルの音声が入っているため、こちらを使って動かしていきます

python .\test\test_onnx.py 

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

=========torch=============
mels.size: torch.Size([2, 128, 420]), mels_lens: tensor([420, 411], dtype=torch.int32)
codes.size: torch.Size([2, 210]), codes_lens: tensor([210, 206], dtype=torch.int32)
wav[0]
tensor([ 143,  602,  702,  473, 2530, 2530,  646,  646,  646,  279, 1145,  440,
         279,  279, 2530, 2530, 2530, 2530, 1019,  501,  501,  631,  287,  465,
         465,  478, 3766,  183,  391,  621,   11, 3480, 3480,   16,  402, 1037,
         253,   55,  720,  227,  227,  159,  110,  103,  103,  103,  110,  110,
        2386,   28,  704,  143,  371,  371,  224,  389,  295,  295,  323,  557,
         681,  455,    4,  386,  403,  629, 2989, 2782,  507, 3290,   57,  215,
         626,   55,  342,  375,  596,  502,   12,   39,   90,  344, 1593, 1593,
         170,  471,  170, 2299, 2299,  112,   94,  629,   33,   33,   33,  348,
         348,  199,  137,  715,  750,  119,  490,  357,    4,  648, 1700,  468,
         468,  422,   47,  732,  224,  224,  224, 2691,  389,  174,  174, 1381,
        1381,   74,  100,    6,  584,  363,  225,  214,  197,  621,  209,   59,
         284,   17,  538,  460,   87,  720,  227,  618,  594,  151,  173,  540,
        1923,  361,  361,   96,  355,  223,  341,  297,    1,  137,  123,  662,
           4,  386,  386,  225,  214,  427,  215,  477, 1405, 3108,  122,  122,
         310,  149, 1479,  314,  486,  946, 3945,  202, 3539, 3539, 3539,  568,
         312,  312,  121,  139,  530,  395,  607,  443,  443,  367,  367,   81,
         367,  367,  367,  367,  727,  367,  221,  508,  508,  508, 1145,  691,
         367,  367,  573,  221,  221, 2530])
wav[1]
tensor([ 644,  404,  329,  329, 1145, 1145, 1145, 1145, 1145, 1145, 1145,  221,
         508,  221,  221,    8,  650,   36,  501,  573,  443,  443, 1849,  435,
          19,  293,   27,  468,  468,   27,   27,  468,  247,  179,  184,  580,
        1593, 1593, 3539, 2299,  266,  344,  606, 2330,  401,   90,   95,  716,
           4, 1935,    4,    4,  160,  495, 2989, 2782, 2782, 2782,    7,    7,
          84,  342,  375,  584,  227,  452,  141,  488, 4013,  568,  312,  312,
         314,  312,   17,  595,   52,  465,  465,  483,  483,  173,  173,  628,
         628,   96,  455,  688,  153,  153,  527,  628, 1529,  612,  514,  304,
        2579, 2579,  173,   20, 2579,   20,  562,   15, 2828, 2828,  620,  261,
        3480,  188,   88,   33,   33,   27,   39,   39, 2031,  734,  158,   50,
          50,  661,  309,  704,  143,  371,  371,  224,  563,  563,  563,  277,
         300,  159,  445,  133,  343,  343, 2514,  318,  377,  584,  386,  448,
         366,  427,  562, 2828, 1006, 1006, 2185, 2299,  732,  100,  211,  504,
         100,  457,  570,  349,  349,  523,  523,   84,  342,  482,  704, 2386,
         498,  277,   92, 2185,  579,  579,  579,   41,   41,   41,  406, 1104,
         236,  607,  395,  395,  642,  607,  642,  607,  607,  368,  368, 3158,
         573, 1145,  367,  367, 1145,  367,  636,  367,  367,  367,  607, 1145,
         636, 2189])
=========onnx===============
wav[0]
tensor([ 143,  602,  702,  473, 2530, 2530,  646,  646,  646,  279, 1145,  440,
         279,  279, 2530, 2530, 2530, 2530, 1019,  501,  501,  631,  287,  465,
         465,  478, 3766,  183,  391,  621,   11, 3480, 3480,   16,  402, 1037,
         253,   55,  720,  227,  227,  159,  110,  103,  103,  103,  110,  110,
        2386,   28,  704,  143,  371,  371,  224,  389,  295,  295,  323,  557,
         681,  455,    4,  386,  403,  629, 2989, 2782,  507, 3290,   57,  215,
         626,   55,  342,  375,  596,  502,   12,   39,   90,  344, 1593, 1593,
         170,  471,  170, 2299, 2299,  112,   94,  629,   33,   33,   33,  348,
         348,  199,  137,  715,  750,  119,  490,  357,    4,  648, 1700,  468,
         468,  422,   47,  732,  224,  224,  224, 2691,  389,  174,  174, 1381,
        1381,   74,  100,    6,  584,  363,  225,  214,  197,  621,  209,   59,
         284,   17,  538,  460,   87,  720,  227,  618,  594,  151,  173,  540,
        1923,  361,  361,   96,  355,  223,  341,  297,    1,  137,  123,  662,
           4,  386,  386,  225,  214,  427,  215,  477, 1405, 3108,  122,  122,
         310,  149, 1479,  314,  486,  946, 3945,  202, 3539, 3539, 3539,  568,
         312,  312,  121,  139,  530,  395,  607,  443,  443,  367,  367,   81,
         367,  367,  367,  367,  727,  367,  221,  508,  508,  508, 1145,  691,
         367,  367,  573,  221,  221, 2530])
all equal: True
miss rate: 0.0%
wav[1]
tensor([ 644,  404,  329,  329, 1145, 1145, 1145, 1145, 1145, 1145, 1145,  221,
         508,  221,  221,    8,  650,   36,  501,  573,  443,  443, 1849,  435,
          19,  293,   27,  468,  468,   27,   27,  468,  247,  179,  184,  580,
        1593, 1593, 3539, 2299,  266,  344,  606, 2330,  401,   90,   95,  716,
           4, 1935,    4,    4,  160,  495, 2989, 2782, 2782, 2782,    7,    7,
          84,  342,  375,  584,  227,  452,  141,  488, 4013,  568,  312,  312,
         314,  312,   17,  595,   52,  465,  465,  483,  483,  173,  173,  628,
         628,   96,  455,  688,  153,  153,  527,  628, 1529,  612,  514,  304,
        2579, 2579,  173,   20, 2579,   20,  562,   15, 2828, 2828,  620,  261,
        3480,  188,   88,   33,   33,   27,   39,   39, 2031,  734,  158,   50,
          50,  661,  309,  704,  143,  371,  371,  224,  563,  563,  563,  277,
         300,  159,  445,  133,  343,  343, 2514,  318,  377,  584,  386,  448,
         366,  427,  562, 2828, 1006, 1006, 2185, 2299,  732,  100,  211,  504,
         100,  457,  570,  349,  349,  523,  523,   84,  342,  482,  704, 2386,
         498,  277,   92, 2185,  579,  579,  579,   41,   41,   41,  406, 1104,
         236,  607,  395,  395,  642,  607,  642,  607,  607,  368,  368, 3158,
         573, 1145,  367,  367, 1145,  367, 1145,  367,  367,  367,  367,  367,
         692,  404])
all equal: False
miss rate: 2.427184581756592%