はじめに
Kotoba-Whisperは、Asahi UshioとKotoba Technologiesが共同開発した、日本語の音声認識(ASR)に特化した蒸留Whisperモデルのコレクションです。OpenAIのWhisper large-v3をティーチャーモデルとし、ReazonSpeechの大規模な日本語音声データを用いて学習されました。
元のlarge-v3モデルと比べて6.3倍の高速化を実現しつつ、ほぼ同等の低いエラー率を維持しています。
この記事では、Kotoba-Whisperについての概要を説明し、Transformersライブラリを使った具体的な利用方法をコード付きで紹介します。
こちらの記事もおすすめ
Kotoba-Whisperの特徴
- 高速性: large-v3の6.3倍の速度
- 高精度: large-v3と同等の低いエラー率
- 軽量: large-v3の半分以下のパラメータ数
- 日本語に特化したファインチューニング
- Transformersライブラリからシームレスに利用可能
環境のセットアップ
Kotoba-Whisperを使うには、Transformers v4.39以降が必要です。
以下のコマンドで最新バージョンをインストールしましょう。
pip install --upgrade pip
pip install --upgrade transformers accelerate datasets
短い音声の文字起こし
30秒以内の短い音声ファイルは、以下のようにpipelineクラスを使って簡単に文字起こしができます。
import torch
from transformers import pipeline
from datasets import load_dataset, Audio
# モデルの設定
model_id = "kotoba-tech/kotoba-whisper-v1.0"
torch_dtype = torch.float16 if torch.cuda.is_available() else torch.float32
device = "cuda:0" if torch.cuda.is_available() else "cpu"
model_kwargs = {"attn_implementation": "sdpa"} if torch.cuda.is_available() else {}
generate_kwargs = {"language": "japanese", "task": "transcribe"}
# モデルのロード
pipe = pipeline(
"automatic-speech-recognition",
model=model_id,
torch_dtype=torch_dtype,
device=device,
model_kwargs=model_kwargs
)
# サンプル音声を読み込み(16kHzにダウンサンプリング)
dataset = load_dataset("japanese-asr/ja_asr.reazonspeech_test", split="test")
sample = dataset[0]["audio"]
# 推論の実行
result = pipe(sample, generate_kwargs=generate_kwargs)
print(result["text"])
ローカルの音声ファイルを文字起こしする場合は、pipelineを呼び出す際にファイルのパスを渡します。
(音声は16kHzでサンプリングされている必要があります)
result = pipe("audio.mp3", generate_kwargs=generate_kwargs)
セグメントレベルのタイムスタンプが必要な場合は、return_timestamps=True
を指定して"chunks"の出力を返します。
result = pipe(sample, return_timestamps=True, generate_kwargs=generate_kwargs)
print(result["chunks"])
長い音声の文字起こし
逐次処理による方法
30秒以上の長い音声ファイルを文字起こしする場合、デフォルトではOpenAIの逐次処理アルゴリズムが使用されます。
これはスライディングウィンドウを使ってバッファ付き推論を行う方法で、チャンク処理より高精度な結果が得られます。
精度が最優先で、レイテンシはそれほど重要でない場合や、長音声を一括処理する場合に適しています。
pipelineクラスを使った逐次処理の例は以下の通りです。
import torch
from transformers import pipeline
from datasets import load_dataset
# モデルの設定
model_id = "kotoba-tech/kotoba-whisper-v1.0"
torch_dtype = torch.float16 if torch.cuda.is_available() else torch.float32
device = "cuda:0" if torch.cuda.is_available() else "cpu"
model_kwargs = {"attn_implementation": "sdpa"} if torch.cuda.is_available() else {}
generate_kwargs = {"language": "japanese", "task": "transcribe"}
# モデルのロード
pipe = pipeline(
"automatic-speech-recognition",
model=model_id,
torch_dtype=torch_dtype,
device=device,
model_kwargs=model_kwargs
)
# サンプル音声の読み込み(長音声のために複数連結)
dataset = load_dataset("japanese-asr/ja_asr.reazonspeech_test", split="test")
sample = {"array": np.concatenate([i["array"] for i in dataset[:20]["audio"]]), "sampling_rate": dataset[0]['audio']['sampling_rate']}
# 推論の実行
result = pipe(sample, generate_kwargs=generate_kwargs)
print(result["text"])
チャンク処理による方法
一方、単一の長音声ファイルを最速で処理したい場合は、チャンク処理アルゴリズムを使用します。
これは逐次処理の最大9倍の速度で処理できますが、若干精度が落ちるというトレードオフがあります。
チャンク処理を有効にするには、chunk_length_s
パラメータをpipelineに渡します。
distil-large-v3では、25秒のチャンク長が最適です。
また、batch_size
を指定することで、長音声のバッチ処理が可能になります。
import torch
from transformers import pipeline
from datasets import load_dataset
# モデルの設定
model_id = "kotoba-tech/kotoba-whisper-v1.0"
torch_dtype = torch.float16 if torch.cuda.is_available() else torch.float32
device = "cuda:0" if torch.cuda.is_available() else "cpu"
model_kwargs = {"attn_implementation": "sdpa"} if torch.cuda.is_available() else {}
generate_kwargs = {"language": "japanese", "task": "transcribe"}
# モデルのロード
pipe = pipeline(
"automatic-speech-recognition",
model=model_id,
torch_dtype=torch_dtype,
device=device,
model_kwargs=model_kwargs,
chunk_length_s=15,
batch_size=16
)
# サンプル音声の読み込み(長音声のために複数連結)
dataset = load_dataset("japanese-asr/ja_asr.reazonspeech_test", split="test")
sample = {"array": np.concatenate([i["array"] for i in dataset[:20]["audio"]]), "sampling_rate": dataset[0]['audio']['sampling_rate']}
# 推論の実行
result = pipe(sample, generate_kwargs=generate_kwargs)
print(result["text"])
プロンプトを用いた文字起こし
Kotoba-Whisperでは、以下のようにプロンプトを与えることで、文字起こしの内容をある程度コントロールできます。
import re
import torch
from transformers import pipeline
from datasets import load_dataset, Audio
# モデルの設定
model_id = "kotoba-tech/kotoba-whisper-v1.0"
torch_dtype = torch.float16 if torch.cuda.is_available() else torch.float32
device = "cuda:0" if torch.cuda.is_available() else "cpu"
model_kwargs = {"attn_implementation": "sdpa"} if torch.cuda.is_available() else {}
generate_kwargs = {"language": "japanese", "task": "transcribe"}
# モデルのロード
pipe = pipeline(
"automatic-speech-recognition",
model=model_id,
torch_dtype=torch_dtype,
device=device,
model_kwargs=model_kwargs
)
# サンプル音声の読み込み
dataset = load_dataset("japanese-asr/ja_asr.reazonspeech_test", split="test")
# プロンプト無しの場合
text = pipe(dataset[10]["audio"], generate_kwargs=generate_kwargs)['text']
print(text)
# 81歳、力強い走りに変わってきます。
# プロンプト有りの場合: 「81」を「91」に変更
prompt = "91歳"
generate_kwargs['prompt_ids'] = pipe.tokenizer.get_prompt_ids(prompt, return_tensors="pt").to(device)
text = pipe(dataset[10]["audio"], generate_kwargs=generate_kwargs)['text']
# 現在のASRパイプラインはプロンプトを文字起こしの先頭に追加するので、それを削除
text = re.sub(rf"\A\s*{prompt}\s*", "", text)
print(text)
# あっぶったでもスルガさん、91歳、力強い走りに変わってきます。
推論のさらなる高速化と省メモリ化
GPUが対応していれば、Flash Attentionを使うことで、推論速度とVRAM使用量をさらに改善できます。
pip install flash-attn --no-build-isolation
model_kwargs = {"attn_implementation": "flash_attention_2"} if torch.cuda.is_available() else {}
モデルの評価
Kotoba-Whisperの性能評価は、以下のように行えます。
ここでは例としてCommonVoice 8.0の日本語サブセットを使用します。
評価には、データセットの読み込みに🤗 Datasetsを、WERの計算に🤗 Evaluateを使用するので、
事前にインストールしておきます。
pip install --upgrade pip
pip install --upgrade transformers datasets evaluate jiwer
from tqdm import tqdm
import torch
from transformers import pipeline
from datasets import load_dataset, Audio
from evaluate import load
# モデルの設定
model_id = "kotoba-tech/kotoba-whisper-v1.0"
torch_dtype = torch.float16 if torch.cuda.is_available() else torch.float32
device = "cuda:0" if torch.cuda.is_available() else "cpu"
model_kwargs = {"attn_implementation": "sdpa"} if torch.cuda.is_available() else {}
generate_kwargs = {"language": "japanese", "task": "transcribe"}
# データの設定
generate_kwargs = {"language": "japanese", "task": "transcribe"}
dataset_name = "japanese-asr/ja_asr.reazonspeech_test"
audio_column = 'audio'
text_column = 'transcription'
# モデルのロード
pipe = pipeline(
"automatic-speech-recognition",
model=model_id,
torch_dtype=torch_dtype,
device=device,
model_kwargs=model_kwargs,
batch_size=16
)
# データセットの読み込みと16kHzへのリサンプリング
dataset = load_dataset(dataset_name, split="test")
transcriptions = pipe(dataset['audio'])
transcriptions = [i['text'].replace(" ", "") for i in transcriptions]
references = [i.replace(" ", "") for i in dataset['transcription']]
# CERの計算
cer_metric = load("cer")
cer = 100 * cer_metric.compute(predictions=transcriptions, references=references)
print(cer)
JSUT Basic5000などの他のデータセットで評価する場合は、dataset_name
を変更します。
dataset_name = "japanese-asr/ja_asr.jsut_basic5000"
さいごに
以上、Kotoba-Whisperについて詳しく解説しました。
音声認識のタスクで日本語を扱う際には、ぜひ選択肢の一つとして検討してみてください。
高速かつ高精度な音声認識を手軽に実現できるKotoba-Whisperが、
皆さんの機械学習プロジェクトの助けになれば幸いです。
ノートブック
謝辞
- WhisperモデルのOpenAI
- モデル統合の🤗 Transformers
- Distil-Whisperのコードベースを提供してくれたHugging Face 🤗
- ReazonSpeechデータセットのReazon Human Interaction Lab
コメント