はじめに
faster-whisper v1.1.0で対応した最新large-v3-turboモデルが話題ですが、音声のビットレートの違いでどの程度認識精度が変わるのか調査してみました。
文字起こしに利用する動画は、以下の動画を使わせていただきました。
「ひととAIの新たな未来を実現する!パートナーAIシステム [NEC公式]」
https://www.youtube.com/watch?v=OuC8mkjrLu0
この動画には以下の要素が入っており、文字起こしを試すにはちょうど良いと思いました。
- 文章が区切られており、聞き取りやすい
- 複数人の声がある
- 発話中にBGMが流れている
実験準備
サンプリングレートを変換してデータを準備したため、本来そのサンプリングレートで録音するより劣化がある点にご了承ください。実験結果はあくまで参考としてご覧いただければ幸いです。
音声データの準備
- オリジナルの音声を抽出し、まず44.1kHz, 2ch, 16bit(1411kbps)のWAVファイルを用意しました。
- 事前にwhisperの音声認識に対応するサンプリングレート16kHzにしておくため、ffmpegを使い16kHz, 1ch, 16bit(256kbps)のWAVファイルに変換しました。これを実験の「オリジナル音声」と定義します。
- ffmpegを使い、「オリジナル」の音声データを様々なビットレートにしてm4a形式で圧縮しました。これを実験の「圧縮音声」と定義します。
実験では、以下の採点方法に従って点数化し比較を行いました。
採点方法
まず、以下が正しいトランスクリプトです。
情報に恵まれた現代。
広がりゆく可能性。
人は理想の未来を選べるはずだ。
しかし時に、あふれる情報に人は迷う。
挑戦していきたい。
テクノロジーの力で。
誰ひとり取り残さない社会の実現へ。
私たちの生成AIは、あなたに寄り添い、情報を体験へと変えていく。
本日はどのようなご相談でしょうか。
退職金が入ったので、それの資産運用について教えてください。
おめでとうございます。
期間や金利については、どのくらいの期間で運用を考えていますか。
初心者におすすめの運用方法ってありますか。
では、リスクが少なくて始めやすい定期預金や、投資信託についてご説明しましょうか。
誰もがテクノロジーの力を手にできる。
さまざまな場面で新たな可能性を拓いていく。
私たちと一緒に、未来へ。
今回は「いかに正確に文字起こしができるか」に焦点を当てるため、以下の基準で点数を付与します。
- 各文章が正しい表記で文字起こしできていれば5点(ひらがな・カタカナ・漢字・数字)
- 各文章について、本来から異なる文字になっている箇所(漢字の誤変換など)の個数分、5点から減点(最低0点)
- 文字起こしが別々の文章に分断していても、正しい表記であれば減点しない
- 句読点の過不足、位置の違いは減点しない
- 正しい各文章とは別に、余分な文章が出力されているものは減点しない(VADのチューニングは本実験で考慮していないため)
- 各文章の認識結果の中に余分な文字列が出力されていた場合は、文字ごとに-1点
- 同じ意味のひらがな/カタカナと漢字の対応(「ひとり・一人」「さまざま・様々」など)は減点しない
実装
- オリジナル音声、圧縮音声をそのまま入力できるように実装
- 文字起こしされた文章は改行区切りで出力
import numpy as np
import argparse
from datetime import datetime
from pydub import AudioSegment
from faster_whisper import WhisperModel
# Whisperモデルの初期化
model = WhisperModel("large-v3-turbo", device="cuda", compute_type="float32")
def load_audio(file_path, target_sample_rate=16000):
"""
音声ファイルを読み込み、16kHz, 1chのPCMデータに変換する。
WAVまたはM4A形式に対応。
"""
# 音声ファイルを読み込み(pydubを使用)
audio = AudioSegment.from_file(file_path)
# モノラルに変換
if audio.channels > 1:
audio = audio.set_channels(1)
# サンプリングレートを16kHzに変換(本実験では使わない)
if audio.frame_rate != target_sample_rate:
print(f"Converting samplerate: {audio.frame_rate} -> {target_sample_rate}")
audio = audio.set_frame_rate(target_sample_rate)
# PCMデータを取得
pcm_data = np.array(audio.get_array_of_samples()).astype(np.float32) / 32768.0
return pcm_data
def transcribe_audio(file_path):
"""
音声ファイルを文字起こしする。
"""
# 音声ファイルをロードしてPCMデータに変換
pcm_data = load_audio(file_path)
# Whisperモデルで文字起こし
segments, info = model.transcribe(
pcm_data,
language="ja",
vad_filter=False,
beam_size=5,
best_of=5
)
# 結果を表示
transcription = "\n".join([segment.text for segment in segments])
print(transcription)
# 現在の時刻を取得してファイル名を作成
timestamp = datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
output_file = f"./output/transcription_{timestamp}.txt"
# 結果をファイルに保存
with open(output_file, "w", encoding="utf-8") as f:
f.write(transcription)
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('--input', type=str, required=True)
args = parser.parse_args()
transcribe_audio(args.input)
実験結果
音声データはすべて16kHz、16bit、1chに統一しています。
オリジナル音声(WAV, 256kbps, 3.39MB):82/85点
前のモデルにもありましたが、「ご視聴ありがとうございました」という文章が余分に出てきてしまいました。
(小さい音量のBGMに反応し、無理やり文字起こししようとして出てきてしまうような印象です。VADなどの発話検知を適切にチューニングすれば改善すると思われますが、今回の実験では考慮していません)
圧縮音声(m4a, 64kbps, 926KB):82/85点
【音質】耳で聞いた範囲では、あまりオリジナル音声と聞きやすさは変わりません。
圧縮音声(m4a, 32kbps, 446KB):82/85点
【音質】圧縮され、特にさ行など高音が入る文字が耳に刺さるようになってきました。
しかし、採点結果はオリジナル音声と変わりませんでした。
圧縮音声(m4a, 16kbps, 226KB):80/85点
【音質】さすがに圧縮の影響を受け、声がこもっています。ただ、人間が聞く分には聞き取れます。(Zoomで音質が悪い時の音声みたいな感じです)
圧縮音声(m4a, 12kbps, 172KB):80/85点
【音質】声がさらにこもり、「Zoomより悪い」くらいの印象になりました。人間にはまだ聞き取れます。
間違う箇所が変わっただけで点数は変わっていません。
圧縮音声(m4a, 8kbps(下限), 125KB):72/85点
【音質】音質が悪い声が重なっているように聞こえてきます。さすがにギリギリ何を言っているのか聞き取れるレベルです。
実験結果
- 16kbpsを下回るとちょこちょこ特に漢字の間違いが出るようになりましたが、8kbpsを含めても驚いたことに全体としてはかなり正確でした。
- 人間が聞いてわかるほど「明らかに音質が悪い音声」でも、それなりに認識できることが分かりました。
- 認識精度を保ちつつ、少し音質が悪くなっても問題なければ、32kbps付近まで落として音声を保存しても問題ないかもしれません。
さいごに
今回は圧縮音声のビットレートの違いによる文字起こしについて実験してみました。
大量の音声データを効率よく圧縮して保管しておきたい方の参考になればと思います。