
【夏休みの自由研究リレー】Amazon Transcribeとfaster-whisperの日本語音声文字起こし精度を比較してみた
はじめに
こんにちは、大阪オフィスのよなみねです。
当記事は、クラスメソッドの有志による 『夏休みの自由研究リレー』 第18回目のエントリ です。
このブログリレーの企画は、普段からクラウドやAIを追いかけているメンバーによって、「やってみた」だけではなく「作ってみた」や「調査/研究してみた」もアウトプットしてみようという企画です!
新たな知見になることは勿論、アイデアを自社やコミュニティの発展に寄与できればと考えておりますので、お付き合いいただけますと幸いです!
最近、会議や会話の音声録音をAIのデータソースとして利用したいなあ。
と思うことがよくあります。
日本語音声の文字起こしツールはたくさんありますが、安い、早い、精度よいものを使いたくなるのが人間です。
なおかつ、私は普段からAWSを使うことが多いのでAWS上で動くとなおよいです。
そんな私の要望に応えられそうなツールをKiroと壁打ちしていました。
その中でAmazon Transcribeとfaster-whisperが私の中では有力候補となりました。
そこで、日本語音声の文字起こしをする場合、どちらが精度いいのか気になったので比較してみました!
日本語文字起こしの精度評価は評価基準をKiroと相談しつつ、最終的な確認は人間(私)がおこないました。
前置き
ブログとして使えるような会議録音がなかったので、この記事では代わりに弊社のYoutubeチャンネルから座談会形式で会話している動画を録音した音声で検証を行いました。
固有名詞や数字など、普段の会議でも出てくるような言葉が出てくるので、ちょうど良い題材かと思います。
動画は19分程度で、Youtubeなので音声もある程度聞き取りやすいです。
そのため、一般的な会議と比較すると少しいい条件での検証かなと思います。
あくまでも上記の条件での検証結果であることはご理解ください
先に結論
正直、全てにおいてこれが一番。というものはありませんでした。
それぞれいいところ、気になるところがありました。
文字起こしのミスには傾向があり、
Amazon Transcribeは欠落と固有名詞の認識ミスが多く、faster-whisperは数字・英単語の認識ミスが多いという結果でした。
固有名詞はlarge-v3が最も精度がよかったです。
話者分離はAmazon Transcrebeがもっともミスが少なかったです。
処理時間はlarge-v3-turbo GPUが最も短く1分7.584秒でした。
約19分の音声を約1分で処理できるのは驚異的ですね。
Amazon Transcribeは2分33.640秒で、large-v3 GPUの2分27.239秒とほぼ同じでした。
概算料金はlarge-v3-turbo GPUが$0.022047で最も安く、Amazon Transcribeは$0.114200でした。
ただし、faster-whisperはEC2で動かしています。
$0.022047というのは単純に文字起こしに要した時間を料金に換算しているだけです。
Amazon Transcribeはインスタンスが不要で好きなタイミングで必要な時間だけ実行できることも考えると、単純な比較は難しいかなと思います。
検証内容
検証内容としては同じ音声を5つの構成で文字起こしします。
faster-whisperは異なるモデルを異なるプロセッサで動かして、合計4構成検証しました。
| 構成 | 実行先 |
|---|---|
| Amazon Transcribe | ap-northeast-1 |
| faster-whisper large-v3 CPU | c8i.4xlarge |
| faster-whisper large-v3 GPU | g6.xlarge |
| faster-whisper large-v3-turbo CPU | c8i.4xlarge |
| faster-whisper large-v3-turbo GPU | g6.xlarge |
faster-whisper自体に話者分離機能はないようなので、pyannoteのCommunity-1というpythonの音声処理ライブラリを組み合わせます。
評価は3つの手順で進めます。
- 私が動画を見て正解文を書き起こす
- Kiroへ正解文と5つの構成の出力を渡して差分の候補を挙げてもらう
- Kiroが出した候補と正解文を私が見比べる
精度を定量的に測るのはむずかしいですが、とりあえずKiroと相談しながら、これは人間が見て間違いと判断するだろうというものを項目ごとに分類しました。
あわせて処理時間と概算料金(ap-northeast-1)も計測します。
実行環境
faster-whisperの実行環境は次のとおりです。
Amazon Transcribeはマネージドサービスのため対象外です。
CPU構成
- インスタンス: c8i.4xlarge
- OS: Amazon Linux 2023(カーネル 6.18.39-79.141.amzn2023.x86_64)
- CPU: Intel Xeon 6975P-C、16 vCPU
- Python: 3.12.13
- uv: 0.11.21
GPU構成
- インスタンス: g6.xlarge
- AMI: ami-02661579dcd8efe92(Deep Learning Base OSS Nvidia Driver GPU AMI (Amazon Linux 2023) 20260807)
- GPU: NVIDIA L4(23,034 MiB)、ドライバー 595.91.07
- CUDA: 12.8(cuBLAS 12.8.4.1、cuDNN 9.10.2)
- Python: 3.12.13
- uv: 0.11.21
Kiroと評価方法を決める
評価方法はKiroと話し合って決めました。
各構成の出力と正解文(人間の文字起こし)をKiroへ渡します。
両者を比較して、Kiroには次の候補を抽出してもらいます。
| 分類 | 確認する内容 |
|---|---|
| 誤認識 | 発話と異なる文字列へ置き換わった箇所 |
| 欠落 | 発話が文字起こしへ含まれなかった箇所 |
| 追加 | 音声にない文字列が加わった箇所 |
| 固有名詞 | 人名や製品名を誤った候補 |
| 数字・英単語 | 数字や英単語を誤った候補 |
| 話者割り当て間違い | 発話者と話者ラベルが一致しない候補 |
固有名詞と数字・英単語は、誤認識や欠落と一部重複して数えています。
Kiroの判定だけだと不安なので、Kiroが間違いだと判断した箇所は自分で文字起こししたものと比較して確認しました。
Macのボイスメモで検証音声を準備する
動画をMacで再生し、その音をボイスメモで録音しました。
正解文は私が動画を見て書き起こしました。
この作業が一番辛かったです...
文字起こしの出力と同じ粒度で比べるために「えっと」や「ま、」といったフィラーも残しています。
作成した正解文の冒頭を抜粋します。
話者は3人で、Aさん、Bさん、Cさんとしています。
A
こんにちは。クラスメソッドYouTubeチャンネルです。
今日なんですけれども、クラスメソッドといえばブログの会社ということで、
クラスメソッドのオウンドメディアであるDevelopersIOのブログの方でですね、
今年特に読まれたブログということで、えっと、5つ私の方でピックアップを
しましたので、今日ご出演いただいてるお2人と一緒にですね、ま、ピックアップ
したブログっていうところを、感想とかその辺ディスカッションしていければな
っていう風に思っておりますので今日よろしくお願いいたします。
B
お願いします。
C
よろしくお願いします。
A
1つ目が、えっと要件定義をする時に意識していることをまとめてみた要件例を
添えてということで、のんピさんが執筆されたブログですね。
B
横のバーの小ささがハンパない
全文は約8,000文字です。
録音した音声を変換して計測したところ、音声時間は19分1.696秒でした。
Amazon Transcribeで文字起こしと話者分離を実行
文字起こしする音声をS3へ配置しておきます。
LanguageCodeにja-JPを指定してバッチ処理を開始します。
話者分離にはShowSpeakerLabels=trueとMaxSpeakerLabels=3を指定します。
処理後のJSONから文字列と話者ラベルを取り出します。
構築手順は比較に必要な範囲だけ載せていきます。
Pythonの環境と依存関係はuvで管理しています。
依存関係はpyproject.tomlで固定します。
今回の検証ではAmazon Transcribeとfaster-whisperを同じプロジェクトで動かしています。
[project]
requires-python = "==3.12.*"
dependencies = [
"boto3==1.43.68",
"faster-whisper==1.2.1",
"pyannote==4.0.7",
]
環境を作成します。
uv sync --all-groups --locked --python 3.12
ジョブの開始からJSONの整形までを、1つのPythonスクリプト(run_amazon_transcribe.py)にまとめました。
次はその一部を抜粋したものです。
# ジョブを開始する
client = boto3.client("transcribe", region_name="ap-northeast-1")
client.start_transcription_job(
TranscriptionJobName=job_name,
LanguageCode="ja-JP",
MediaFormat="wav",
Media={"MediaFileUri": media_s3_uri},
Settings={
# 話者分離を有効にする
"ShowSpeakerLabels": True,
# 今回は話者3人なので3を指定する
"MaxSpeakerLabels": speaker_count,
},
)
# 完了を待ってTranscriptFileUriからJSONを取得する
response = client.get_transcription_job(TranscriptionJobName=job_name)
job = response["TranscriptionJob"]
status = job["TranscriptionJobStatus"]
if status == "COMPLETED":
uri = job["Transcript"]["TranscriptFileUri"]
# results.itemsを1件ずつ処理して話者付きテキストへ整形する
# 話者が変わるまで同じセグメントへ連結する
for index, raw_item in enumerate(items):
content, confidence = _alternative(raw_item, index)
# 句読点は時刻を持たないので直前のセグメントへ足す
if raw_item.get("type") == "punctuation":
if current_contents:
current_contents.append(content)
continue
speaker = raw_item.get("speaker_label")
if not isinstance(speaker, str):
# itemに話者がない場合はspeaker_labels.segmentsの時刻から引く
speaker = speaker_by_times.get((str(start_raw), str(end_raw)))
# 話者が切り替わったらセグメントを確定する
if current_speaker is not None and speaker != current_speaker:
finish_segment()
current_contents.append(content)
話者が変わるまで文字を連結してセグメントを作るため、同じ話者が続く発話はひとつのセグメントにまとまります。
ジョブの呼び出しは手元の端末から実行します。
uv run --no-project --python 3.12 \
--with boto3==1.43.68 --with 'botocore[crt]' \
python run_amazon_transcribe.py \
--experiment experiment-full.json \
--media-s3-uri s3://<YOUR_BUCKET>/data/input-16khz-mono.wav \
--job-name roundtable-full-amazon-transcribe-20260811 \
--output results/transcribe-full/amazon-transcribe-full.json \
--raw-output results/transcribe-full/amazon-transcribe-full-raw.json \
--price-per-minute-usd 0.006 \
--poll-interval-seconds 5 \
--timeout-seconds 1200
出力は次のとおりです。
ジョブ状態: COMPLETED
処理時間: 153.640秒
話者数: 3
処理時間はジョブ開始から話者付きテキストの整形までの合計時間を測りました。
話者ラベルはspk_0からspk_2の3つが付きました。
指定したMaxSpeakerLabelsの3と一致しますね。
話者付きテキストの冒頭を抜粋します。
次のような形式で文字起こしされています。
[00:01.080-00:56.930] spk_0
こんにちは、クラスメソッドYouTubeチャンネルです。今日なんですけれども、クラスメソッドと言えば、ブログの会社ということで、クラスメソッドのWundメディアであるデベロッパーズIOのブログの方でですね、今年特に読まれたブログ、ということで、えっとー5つ、私の方でピックアップをしましたので、
(以下略)
[00:57.689-00:59.889] spk_1
横のバーの小ささがあ、
[00:59.930-01:11.919] spk_0
そうそうそうそうそうそう、あのクラスリゾートのブログって、横にあのナビゲーションバーみたいなものがあって、インデックスが貼られているような形で、それぞれまー飛んでいけるっていうのはあるんですけども、これの行がなんか改めて見たらすごいっす
[01:12.000-01:15.599] spk_2
ね。元。へえ。
faster-whisperとpyannoteで文字起こしと話者分離を実行
faster-whisperではlarge-v3とlarge-v3-turboというモデルを試します。
話者分離を担当するpyannoteのモデル(Community-1)は既定でCPUを使うため、GPU構成ではパイプラインをGPUへ移します。
話者数が3人と分かっているため、num_speakers=3を指定します。
Python環境と依存関係はuvで管理します。
Amazon Transcribeと同じプロジェクトで、pyproject.tomlの依存関係も共通です。
| パッケージ | バージョン |
|---|---|
| faster-whisper | 1.2.1 |
| pyannote | 4.0.7 |
| torch | 2.13.0 |
モデルの読み込みから文字起こし、話者分離、単語と話者区間の結合までを、1つのPythonスクリプトにまとめました。
次はその一部を抜粋したものです。
# モデルの読み込み。
# 計測区間の外で実行する
whisper_model = WhisperModel(
configuration.model,
# cpu または cuda
device=configuration.device,
# int8 または float16
compute_type=configuration.compute_type or "default",
download_root=str(model_cache_dir / "faster-whisper"),
)
diarization_pipeline = Pipeline.from_pretrained(
"pyannote/speaker-diarization-community-1",
token=hf_token,
cache_dir=model_cache_dir / "pyannote",
)
if configuration.device == "cuda":
# Community-1は既定でCPUを使うのでGPUへ移す
diarization_pipeline.to(torch.device("cuda"))
# 文字起こしと話者分離の実行。
# この区間だけ時間を測る
with ProcessingTimer() as timer:
raw_segments, info = whisper_model.transcribe(
str(audio_path),
language="ja",
beam_size=5,
# 話者を割り当てるため単語ごとの時刻を取る
word_timestamps=True,
vad_filter=False,
)
words = extract_whisper_words(list(raw_segments))
# load_pcm_waveformはPCM WAVを読み込んで波形の辞書へ変換する
# TorchCodecの内蔵デコーダーを使わないための処理
diarization_audio = load_pcm_waveform(audio_path)
diarization_output = diarization_pipeline(
diarization_audio,
# 話者数が分かっているので3を指定する
num_speakers=speaker_count,
)
# exclusive_speaker_diarizationを使う。
# 話者が重なった区間を排他的に扱えるため
turns = extract_diarization_turns(
diarization_output.exclusive_speaker_diarization
)
segments = assign_speakers(words, turns)
def _speaker_for_word(word, turns):
"""単語ごとに重複時間が最大の話者区間へ割り当てる。
"""
overlaps = [
max(
0.0,
min(word.end_seconds, turn.end_seconds)
- max(word.start_seconds, turn.start_seconds),
)
for turn in turns
]
maximum_overlap = max(overlaps)
if maximum_overlap > 0:
return turns[overlaps.index(maximum_overlap)].speaker
# どの区間とも重ならない単語は中点が最も近い区間へ寄せる
midpoint = (word.start_seconds + word.end_seconds) / 2
return min(
turns,
key=lambda turn: min(
abs(midpoint - turn.start_seconds),
abs(midpoint - turn.end_seconds),
),
).speaker
割り当てた話者が変わるまで単語を連結してセグメントにします。
Amazon Transcribeの整形と同じ考え方ですね。
このルールのため、話者境界の単語1つが別の話者へ吸収されることがあります。
実行コマンドと出力を構成ごとに記載していきます。
Community-1の利用にはHugging Faceトークンが必要なので、あらかじめ環境変数へ設定しておきます。
export HF_TOKEN="<YOUR_HF_TOKEN>"
large-v3をCPUで実行します。
uv run python run_faster_whisper.py \
--experiment experiment-full.json \
--configuration-id fw-large-v3-cpu \
--output results/full/fw-large-v3-cpu-full.json \
--raw-output results/full/fw-large-v3-cpu-full-raw.json \
--hourly-price-usd 0.94376 \
--model-cache-dir models \
--instance-type c8i.4xlarge
出力は次のとおりです。
構成: faster-whisper large-v3 CPU
処理時間: 1112.162秒
検出言語: ja
話者数: 3
large-v3をGPUで実行します。
GPU構成ではfaster-whisperとpyannoteがCUDAのライブラリを呼び出すため、そのライブラリが置かれているディレクトリをPATHとLD_LIBRARY_PATHへ追加しておきます。
export PATH="/usr/local/cuda-12.8/bin:$HOME/.local/bin:$PATH"
export LD_LIBRARY_PATH="/usr/local/cuda-12.8/targets/x86_64-linux/lib:/usr/local/cuda-12.8/lib:${LD_LIBRARY_PATH:-}"
uv run python run_faster_whisper.py \
--experiment experiment-full.json \
--configuration-id fw-large-v3-gpu \
--output results/full/fw-large-v3-gpu-full.json \
--raw-output results/full/fw-large-v3-gpu-full-raw.json \
--hourly-price-usd 1.1672 \
--model-cache-dir models \
--instance-type g6.xlarge \
--gpu "NVIDIA L4"
出力は次のとおりです。
構成: faster-whisper large-v3 GPU
処理時間: 147.239秒
検出言語: ja
話者数: 3
large-v3-turboをCPUで実行します。
uv run python run_faster_whisper.py \
--experiment experiment-full.json \
--configuration-id fw-large-v3-turbo-cpu \
--output results/full/fw-large-v3-turbo-cpu-full.json \
--raw-output results/full/fw-large-v3-turbo-cpu-full-raw.json \
--hourly-price-usd 0.94376 \
--model-cache-dir models \
--instance-type c8i.4xlarge
出力は次のとおりです。
構成: faster-whisper large-v3-turbo CPU
処理時間: 654.488秒
検出言語: ja
話者数: 3
large-v3-turboをGPUで実行します。
uv run python run_faster_whisper.py \
--experiment experiment-full.json \
--configuration-id fw-large-v3-turbo-gpu \
--output results/full/fw-large-v3-turbo-gpu-full.json \
--raw-output results/full/fw-large-v3-turbo-gpu-full-raw.json \
--hourly-price-usd 1.1672 \
--model-cache-dir models \
--instance-type g6.xlarge \
--gpu "NVIDIA L4"
出力は次のとおりです。
構成: faster-whisper large-v3-turbo GPU
処理時間: 67.584秒
検出言語: ja
話者数: 3
4構成すべてで検出言語はjaでした。
話者数も3で一致しました。
large-v3 CPUの話者付きテキストを冒頭から抜粋します。
faster-whisperとpyannote.audioの結果では、時刻ごとにSPEAKER_00のような話者ラベルを付けました。
[00:01.220-00:57.920] SPEAKER_00
こんにちはクラスメソッドYouTubeチャンネルです今日なんですけれども(略)かなり丁寧にアウトプットしてくれたという結構文章量としても多いブログですよね横
[00:57.920-00:59.620] SPEAKER_02
のバーの小ささがそうそう
[00:59.620-01:58.660] SPEAKER_00
そうそうクラスメソッドのブログって横にナビゲーションバーみたいなものがあって(略)そのシステムを作るという立場の方はブログなんじゃないかなっていうふうに思ってます自
[01:58.660-02:21.620] SPEAKER_01
分はもうこれ見たときなんかのんぴーさんが考えてることがめっちゃ(略)
Kiroに誤り候補を探してもらう
Kiroへ正解文と5つの構成の結果を渡しました。
分類は前述の表をそのまま使います。
候補ごとに時刻と分類を付けてもらい、正解文と出力の該当箇所を並べてもらいます。
Amazon Transcribe
Amazon Transcribeで挙がった候補は次の件数です。
| 分類 | 候補件数 |
|---|---|
| 誤認識 | 31 |
| 欠落 | 9 |
| 追加 | 2 |
| 固有名詞 | 16 |
| 数字・英単語 | 3 |
| 話者割り当て間違い | 28 |
それぞれの分類は候補件数が重複しているものがあります。
たとえば「クラスメソッド→クラスリゾート」は誤認識1件であり、同時に固有名詞1件としても数えます。
そのため6分類の件数を単純に合計しても、候補の総数にはなりません。
また、人名や製品名がカナ表記になった箇所は候補へ含めていません。
音声だけでは漢字や英字を確定できないためです。
「タカヤマさん」や「ギットハブ」は誤りとして数えていません。
Amazon Transcribeの候補から、固有名詞の代表例を抜粋します。
| 正解 | 出力 | 時刻 |
|---|---|---|
| オウンドメディア | Wundメディア | 00:01.080-00:56.930 |
| クラスメソッド | クラスリゾート | 00:59.930-01:11.919 |
| NotebookLM | ノートブックイレブン | 06:41.500-08:32.450 |
| Claude Code | クロードコート | 13:42.130-14:29.429 |
| Obsidian | オブリアン | 15:37.140-16:19.119 |
| 大前さん | 大村さん | 17:11.609-17:34.369 |
NotebookLMは1回目だけ「ノートブックLM」と正しく出力されました。
2回目以降は3回とも違う文字列です。
Claude Codeも揺れました。
「クロードコード」と正しく出た箇所と、「クロードコート」「クロウドコード」になった箇所があります。
固有名詞以外の誤認識から、代表例を抜粋します。
| 正解 | 出力 | 時刻 |
|---|---|---|
| 言語化されてる | ゲームされてる | 01:58.110-02:18.990 |
| 可用性 | 多様性 | 02:43.210-03:12.619 |
| 生成AI | 精製AI | 03:12.699-03:46.940 |
| プロンプトエンジニアリング | プロトエンジニアリング | 05:13.183-05:38.360 |
| ログ見に行って | その5人に行って | 16:59.030-17:10.060 |
欠落の代表例も挙げます。
| 正解 | 出力 | 時刻 |
|---|---|---|
| 非機能要件 | 機能要件 | 02:43.210-03:12.619 |
| Claude Codeを徹底解説 | コードを徹底解説 | 11:52.155-13:23.005 |
| 1番基礎のところ | 一番なところ | 14:40.969-14:47.320 |
発話がまるごと出力されなかった候補も2件あります。
9分51秒付近の「業務で使ったりします?」と、16分21秒付近の「大前さんどういう風に使われてるとかありますか」です。
数字の誤りは見つかりませんでした。
「3分の1」「5つ」「10のこと」「2025年」「5月」「6月」はすべて正解と一致します。
話者割り当ての候補28件は、大半がセグメント境界のずれです。
話者が切り替わる箇所で、直前または直後の短い発話が別の話者ラベルへ吸収されています。
例えば以下のような形です。
[00:59.930-01:11.919] spk_0
(略)これの行がなんか改めて見たらすごいっす
[01:12.000-01:15.599] spk_2
ね。元。へえ。
spk_0の「すごいっす」に続く「ね」がspk_2へ入りました。
正解では同じ話者の発話です。
冒頭のあいさつでも起きています。
話者Bの「お願いします」と話者Cの「よろしくお願いします」が、話者Aのセグメントへまとめられていました。
faster-whisper + pyannote
faster-whisperは同じ音声を4構成で試してみました。
抽出した文字起こし候補と、話者割り当て間違いの参考値は次のとおりです。
| 分類 | large-v3 CPU | large-v3 GPU | large-v3-turbo CPU | large-v3-turbo GPU |
|---|---|---|---|---|
| 誤認識 | 35 | 31 | 41 | 32 |
| 欠落 | 3 | 4 | 3 | 4 |
| 追加 | 1 | 3 | 5 | 2 |
| 固有名詞 | 10 | 7 | 11 | 11 |
| 数字・英単語 | 12 | 10 | 15 | 17 |
| 話者割り当て間違い | 40 | 37 | 36 | 34 |
固有名詞と数字・英単語は、誤認識・欠落・追加と一部重複して数えています。
プロセッサの差で出力が変わった例
同じモデルでもプロセッサの差で出力が変わることがありました。
compute_typeという演算精度の設定を、CPUではint8、GPUではfloat16にしています。
float16はCPUでは最適化されておらず、指定しても内部でfloat32へ変換されるため、CPU側はint8を選びましたが、この違いが影響しているのかもしれません。
今回はより実際のユースケースに近づけるためにこういった設定にしました。
以下にlarge-v3の2構成を並べます。
| 正解 | large-v3 CPU | large-v3 GPU |
|---|---|---|
| DevelopersIO | デベロッパー・ザ・イオー | デベロッパー材料 |
| プロンプトエンジニアリング | プロントエンジニアリング | プロンプトエンジニアリング |
| カーソルに入れて | 関数に入れて | 感想に入れて |
| アイコン | 愛の手 | 愛情 |
| いい、使ってます | 言い伝わってます | いい使ってます |
large-v3 GPUだけ「プロンプトエンジニアリング」を正しく出力しました。
CPUのint8は「プロント」になりました。
音声にない文字列が追加された例
large-v3-turbo GPUの末尾には、音声にない文字列が入りました。
それでは皆さんどうもありがとうございました失礼しまーすご視聴ありがとうございました
正解文の末尾は「失礼します」です。
「ご視聴ありがとうございました」は誰も発話していません。
large-v3 GPUにも音声にない固有名詞が出ました。
Google系のドキュメント機に連携ができるKiehl'sじゃないですか
正解は「Google系のドキュメントに連携ができるじゃないですか」です。
「Kiehl's」は実在する化粧品ブランドの名前です。
単語内で話者ラベルが分かれた例
本検証では、faster-whisperが出力した単語ごとの時刻情報へ、pyannote Community-1が検出した話者区間を重ねて話者ラベルを付けました。
単語単位の時刻と話者境界がずれると、1つの語が複数の話者ラベルへ分かれることがありました。
例として、large-v3 CPUの出力から2箇所を抜粋します。
[10:36.160-10:36.480] SPEAKER_02 小
[10:36.480-10:37.000] SPEAKER_00 説です
[10:37.000-10:37.240] SPEAKER_02 よ、
[10:37.240-11:16.760] SPEAKER_00 これ。これはですね。(以下略)
正解は話者Bの「小説ですよ、もうこれ。
」に続けて話者Aが話し始める箇所です。
「小説」という1つの単語が「小」と「説」に分かれ、別の話者へ割り当てられました。
[05:39.700-05:47.360] SPEAKER_01 (略)ぜひクロードコードのスキル使って
[05:47.360-05:48.220] SPEAKER_00 作
[05:48.220-05:50.080] SPEAKER_01 図するときにアシストしてくれるそれ
[05:50.080-05:51.540] SPEAKER_00 見たなーも
[05:51.540-05:58.180] SPEAKER_01 あるので(以下略)
正解は話者Cの「作図するときにアシストしてくれる」に、話者Aが「あ、それ見たな」と割り込む箇所です。
「作図」の「作」だけが話者Cの発話の途中で話者Aへ割り当てられ、直後の話者Aの発話末尾には話者Cの次のセリフの一部(「も」)が吸収されました。
境界は必ず発話の先頭や末尾とは限りません。
1つの単語の内部で話者が入れ替わることもあります。
5構成の候補件数と誤り方を比較する
分類別の件数を5構成で比較します。
分類ごとに最も精度が良かった構成の数値を太文字にしています。
| 分類 | Amazon Transcribe | large-v3 CPU | large-v3 GPU | large-v3-turbo CPU | large-v3-turbo GPU |
|---|---|---|---|---|---|
| 誤認識 | 31 | 35 | 31 | 41 | 32 |
| 欠落 | 9 | 3 | 4 | 3 | 4 |
| 追加 | 2 | 1 | 3 | 5 | 2 |
| 固有名詞 | 16 | 10 | 7 | 11 | 11 |
| 数字・英単語 | 3 | 12 | 10 | 15 | 17 |
| 話者割り当て間違い | 28 | 40 | 37 | 36 | 34 |
固有名詞と数字・英単語は、誤認識・欠落・追加と一部重複して数えています。
話者割り当て間違いは、正解文と音声、出力内容を照合した参考値です。
誤認識、欠落、追加を合計すると、Amazon Transcribeは42件でした。
faster-whisperはlarge-v3 CPUが39件、large-v3 GPUが38件、large-v3-turbo CPUが49件、large-v3-turbo GPUが38件です。
今回の音声では、ミス候補件数の合計に大きな差はありませんでした。
一方で、誤り方には傾向があります。
Amazon Transcribeの欠落は9件で、faster-whisperの3〜4件より多くなりました。
固有名詞候補もAmazon Transcribeが16件で、faster-whisperの7〜11件より多い結果です。
数字・英単語の候補はAmazon Transcribeが3件で、faster-whisperは10〜17件でした。
参考として、固有名詞の結果を構成ごとに並べます。
| 正解 | Amazon Transcribe | large-v3 CPU | large-v3 GPU | large-v3-turbo CPU | large-v3-turbo GPU |
|---|---|---|---|---|---|
| DevelopersIO | デベロッパーズIO | デベロッパー・ザ・イオー | デベロッパー材料 | デベロッパー内容 | デベロッパーズIo |
| のんピさん | のんぷさん | のんぴーさん | のんぴーさん | DOMPさん | ノンピさん |
| クラスメソッド側 | クラスの外側 | クラシマスット側 | クラシマスット側 | クラスマスター側 | クラスマスット側 |
| draw.io | ドロア | ドローIO | ドローIO | ドローア用 | ドローア用 |
| 非機能要件 | 機能要件 | 機能要件 | 機能要件 | 機能要件 | 機能要件 |
| 有料コンテンツ | 有料コンテ | 有料級 | 有料級 | 有料級 | 有料級 |
| Obsidian | オブリアン | Obsidian | Obsidian | オブシビア | オブシビアン |
| トーチさん | さん | 恒一さん | 康二さん | 小西さん | 欠落 |
「非機能要件」は5つの構成すべてで「機能要件」になりました。
「非」が落ちる誤りだけは全構成で共通です。
正解かどうかは音で判定します。
表記がカナか英字かは問いません。
「デベロッパーズIO」は正解、「デベロッパー材料」は誤りとして扱います。
DevelopersIOは5つの構成すべてが違う文字列になりました。
音を捉えたのはAmazon Transcribeとlarge-v3-turbo GPUの2構成です。
残る3構成は別の語へ置き換わりました。
draw.ioはモデルで傾向が分かれました。
large-v3の2構成は「ドローIO」です。
large-v3-turboの2構成は「ドローア用」です。
同じ分かれ方は「これの行が」でも起きました。
large-v3の2構成とAmazon Transcribeは「行」です。
large-v3-turboの2構成は「業」になりました。
Obsidianはlarge-v3の2構成だけ英字で正しく出力しました。
ブログ執筆者について名前を出す会話がありましたが、名前はどの構成でも当てられませんでした。
Amazon Transcribeは名字が落ちて「さん」だけが残り、large-v3-turbo GPUは名字ごと出力されませんでした。
残る3構成はそれぞれ違う名字を出しています。
この箇所は人間が音声を聞いて正解を確認しましたが、かすかに聞き取りづらい箇所でもあったので仕方ないかなと思います。
NotebookLMは同じ音声の中で表記が変わりました。
前半と後半で表記が変わる構成があり、後半に崩れる例もあります。
| 構成 | 前半 | 後半 |
|---|---|---|
| Amazon Transcribe | ノートブックLM | ノートブックエM |
| large-v3 CPU | ノートブックLM | ノートブックエレメント |
| large-v3 GPU | ノートブックLM | notebook.lm |
| large-v3-turbo CPU | ノートブックLM | ノートブックLM |
| large-v3-turbo GPU | ノートブック11 | ノートブックエレム |
large-v3-turbo CPUだけ最後まで「ノートブックLM」を維持しました。
5つの構成のうち唯一です。
ここまでに挙げた8語の正解数をまとめます。
| 構成 | 8語中の正解数 | 正解した語 |
|---|---|---|
| Amazon Transcribe | 1 | DevelopersIO |
| large-v3 CPU | 3 | のんピさん、draw.io、Obsidian |
| large-v3 GPU | 3 | のんピさん、draw.io、Obsidian |
| large-v3-turbo CPU | 0 | ― |
| large-v3-turbo GPU | 2 | DevelopersIO、のんピさん |
この8語は構成間で差が出た語です。
全体の結果ではありません。
以下の言葉は5つの構成すべてが正しく認識できました。
「AWS」「CDK」「GitHub」「MCP」「高山さん」「横田」「2025年」「3分の1」
話者ラベルと正解文の対応は次のとおりです。
| 正解文 | Amazon Transcribe | faster-whisperの4構成 |
|---|---|---|
| 話者A | spk_0 | SPEAKER_00 |
| 話者B | spk_1 | SPEAKER_02 |
| 話者C | spk_2 | SPEAKER_01 |
3人の対応は5つの構成すべてで一貫していました。
精度・処理時間・料金を比較する
精度は何に重きを置くかによって変わります。
例えば、固有名詞や欠落の精度ではfaster-whisper v3がもっとも精度が良い結果となりました。
一方で話者の割り当てや数字・英単語の文字起こしではTranscribeが高精度でした。
また、早さという点においてはfaster-whisper large-v3-turboが圧倒的に早かったです。
概算料金
概算料金は検証時点の料金表と実際の課金対象時間から計算します。
音声時間は19分1.696秒です。
結果は次のとおりです。
| 構成 | 処理時間 | 概算料金 |
|---|---|---|
| Amazon Transcribe | 2分33.640秒 | $0.114200 |
| faster-whisper large-v3 CPU | 18分32.162秒 | $0.291779 |
| faster-whisper large-v3 GPU | 2分27.239秒 | $0.047985 |
| faster-whisper large-v3-turbo CPU | 10分54.488秒 | $0.171712 |
| faster-whisper large-v3-turbo GPU | 1分7.584秒 | $0.022047 |
処理時間が最も短いのはlarge-v3-turbo GPUで、1分7.584秒でした。
Amazon Transcribeは2分33.640秒で2番目です。
CPUのlarge-v3は18分32.162秒かかって、音声の再生時間に近い時間がかかりました。
概算料金が最も安いのはlarge-v3-turbo GPUで、$0.022047でした。
Amazon Transcribeは$0.114200で、large-v3 GPUの$0.047985より高い結果です。
入力音声は1141.696秒です。
1秒単位へ切り上げると1142秒になります。
Amazon Transcribeの課金対象は入力音声時間です。
処理時間は課金へ影響しません。
EC2で動かす4構成とは課金の基準が違います。
逆にfaster-whisperの構成はある程度決め打ちでEC2を用意しているので、利用用途に応じて料金の変動はあります。
実行は各構成1回で、処理時間の差に再現性があるとは断定できません。
感想
今回は約19分の音声1本で5つの構成を比べました。
今回の結果を踏まえた個人的な感想です。
どれか1つの構成に精度が偏るかと思っていましたが、構成によって得意不得があることがわかりました。
また、プロセッサに関しては制限がなければGPUを使うのが良いと思います。
CPUは処理時間が長く、結果的に料金も高くなります。
精度もGPUと大差なかったので、あえてCPUを選択する必要はないかなと思います。
また、faster-whisperを動かすためのインフラやコードを準備するのはそれなりに時間がかかりました。
Kiroと伴走しながら作りましたが、思ったよりも時間がかかってしまいました。
文字起こし環境を準備、運用することを考えると、お金が許せばAWSマネージドなAmazon Transcribeが良いと思いました。
一方で長時間の音声を頻繁に文字起こしするようなケースではAmazon Transcribeの料金は見過ごせないと思います。
そういった場合はイベント駆動でEC2インスタンスやECSを起動するといった仕組みを作った方がお財布に優しいと思います。
精度に関して言えば、固有名詞の誤りは、辞書を渡せば改善する余地があると思いました。
Amazon Transcribeにはカスタム語彙、faster-whisperにはinitial_promptがあります。
また、一度文字起こししたデータをLLMに渡して整形、修正するといった方法も考えられます。
時間のある時に試してみたいと思います。
以上、『夏休みの自由研究リレー』第18回のエントリ『Amazon Transcribeとfaster-whisperの日本語音声文字起こし精度を比較してみた』でした!
次回はキタガワさんの夏休み自由研究ですの予定です!
お楽しみに!!






