0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Whisperを「ローカル」と「API」の両方でやる。差がほぼない、すごい。

0
Posted at

この記事の対象読者

  • 音声認識(ASR)をアプリや業務に組み込みたいエンジニア
  • OpenAI Whisperの名前は知っているが、実際に動かしたことがない方
  • APIとローカル実行のどちらを選ぶべきか迷っている方
  • GPU環境(特にWindows + NVIDIA)でWhisperを高速に動かしたい方

この記事で得られること

  • Whisperのアーキテクチャと各モデルサイズの特性を理解できる
  • ローカル環境(openai-whisper / faster-whisper)でのセットアップと実行方法がわかる
  • OpenAI APIを使った文字起こし・翻訳の実装方法がわかる
  • ローカル vs API、自分のユースケースに合った選択基準が明確になる

この記事で扱わないこと

  • Whisperのファインチューニング(fine-tuning)手順の詳細
  • リアルタイムストリーミング文字起こしの実装(Realtime APIは別記事で扱う予定)
  • 話者分離(Speaker Diarization)の詳細実装

1. Whisperとは何者か — 「汎用音声認識」という革命

音声認識(ASR: Automatic Speech Recognition)の世界は長らく「特定ドメイン特化」が常識だった。医療用、コールセンター用、字幕用...それぞれ専用モデルが必要で、ノイズや訛りに弱く、言語を切り替えるだけで別モデルが必要になる。そんな世界に2022年9月、OpenAIが一石を投じた。

Whisperは、Webから収集した68万時間もの多言語・マルチタスク教師ありデータで訓練された、汎用音声認識モデルだ。その後のlarge-v3では訓練データが500万時間超にまで拡大されている。

Whisperの仕組みを「レストラン」に例えよう。音声データが「食材」として厨房に届くと、まずスペクトログラムという「下ごしらえ」が行われる。Encoder(仕込みシェフ)が音声の特徴を抽出し、Decoder(盛り付けシェフ)がテキストとして仕上げる。特殊トークンという「レシピ指示書」によって、同じ厨房で「文字起こし」も「翻訳」も「言語判定」もこなせる — これがWhisperのマルチタスク設計だ。

Whisperは99言語に対応し、英語のクリーンな音声ではWER(単語誤り率)約**2.7%**を達成している。プロの人間の文字起こしが4〜5%程度であることを考えると、ほぼ人間レベルだ。


2. モデルサイズの選び方 — 「レストランの格」で考える

Whisperには5つのモデルサイズがあり、さらに英語専用モデル(.en)とTurboモデルが存在する。レストランに例えると、tiny は立ち食いそば、large-v3 はミシュラン三ツ星、turbo はミシュラン三ツ星のテイクアウト専門店だ。

モデル パラメータ数 必要VRAM 処理速度(対リアルタイム比) 精度 用途
tiny / tiny.en 39M ~1 GB ~32x プロトタイプ、エッジデバイス
base / base.en 74M ~1 GB ~16x やや低 軽量アプリ
small / small.en 244M ~2 GB ~6x バランス型
medium / medium.en 769M ~5 GB ~2x 本格運用
large-v3 1.55B ~10 GB ~1x 最高 最高精度が必要な場面
turbo 809M ~6 GB ~216x large-v3に迫る 速度と精度の最適バランス(推奨)

tiny.enbase.en は英語専用モデルで、英語の認識精度は多言語モデルより高い。ただし small.en 以上ではその差は小さくなる。日本語を扱うなら.enなしの多言語モデルを使うこと。

turboモデルの正体

turboは2024年にリリースされたモデルで、large-v3のエンコーダーをそのまま使いつつ、デコーダー層を最適化して高速化した「いいとこ取り」モデルだ。large-v3と比べて精度の低下はごくわずかで、処理速度は216倍のリアルタイム処理を実現する。60分の音声ファイルを約17秒で文字起こしできる計算になる。...草。


3. ローカル実行 ①:公式 openai-whisper

3.1 環境構築

まずは公式のopenai-whisperパッケージから始めよう。PyTorchが動く環境であれば比較的簡単にセットアップできる。

前提条件:

  • Python 3.8〜3.13
  • FFmpeg(音声デコードに必要)
  • CUDA対応GPU(推奨。CPUでも動くが遅い)
# FFmpegのインストール(Windows)
winget install Gyan.FFmpeg

# FFmpegのインストール(Ubuntu / WSL)
sudo apt update && sudo apt install ffmpeg

# Whisperのインストール
pip install openai-whisper

Windows環境でFFmpegへのパスが通っていないと FileNotFoundError で落ちる。ffmpeg -version で確認してからWhisperを実行すること。

3.2 CLIでの実行

最もシンプルな使い方はコマンドラインだ。

# 基本的な文字起こし(turboモデル使用)
whisper audio.mp3 --model turbo

# 日本語を明示指定(精度向上)
whisper audio.mp3 --model turbo --language ja

# 日本語音声を英語に翻訳
whisper audio.mp3 --model turbo --language ja --task translate

# SRT字幕ファイルとして出力
whisper audio.mp3 --model turbo --language ja --output_format srt

出力形式は txt / vtt / srt / tsv / json から選べる。動画の字幕を作りたいなら srtvtt が便利だ。

3.3 Pythonからの実行

import whisper

# モデルのロード(初回はダウンロードが走る)
model = whisper.load_model("turbo")

# 文字起こし
result = model.transcribe("audio.mp3", language="ja")
print(result["text"])

# セグメント単位でタイムスタンプ付きテキストを取得
for segment in result["segments"]:
    start = segment["start"]
    end = segment["end"]
    text = segment["text"]
    print(f"[{start:.2f}s -> {end:.2f}s] {text}")

3.4 言語検出

Whisperは音声から自動で言語を判定できる。30秒のチャンクからメルスペクトログラムを生成し、各言語の確率を返す。

import whisper

model = whisper.load_model("turbo")
audio = whisper.load_audio("audio.mp3")
audio = whisper.pad_or_trim(audio)

mel = whisper.log_mel_spectrogram(audio, n_mels=model.dims.n_mels).to(model.device)
_, probs = model.detect_language(mel)

print(f"検出言語: {max(probs, key=probs.get)}")
# 上位5言語の確率を表示
top5 = sorted(probs.items(), key=lambda x: x[1], reverse=True)[:5]
for lang, prob in top5:
    print(f"  {lang}: {prob:.4f}")

4. ローカル実行 ②:faster-whisper — 本番環境の本命

公式のopenai-whisperは手軽だが、本番運用を考えるならfaster-whisperを強く推奨する。CTranslate2という高速推論エンジン上にWhisperを再実装したもので、同精度で最大4倍高速・メモリ使用量も大幅削減を実現する。

レストランの例えで言うと、同じレシピ(Whisperの重み)を使いながら、調理器具(推論エンジン)を最新の業務用に入れ替えたようなものだ。

4.1 faster-whisperのインストール

pip install faster-whisper

faster-whisperの最新版はCUDA 12 + cuDNN 9を要求する。CUDA 11環境では pip install ctranslate2==3.24.0 でダウングレードが必要。CUDAcuDNNのバージョン不一致は「あるある」トラブルなので要注意。

4.2 基本的な使い方

from faster_whisper import WhisperModel

# GPU + FP16で実行(最も高速)
model = WhisperModel("large-v3", device="cuda", compute_type="float16")

# INT8量子化(VRAMを節約、速度もほぼ変わらない)
# model = WhisperModel("large-v3", device="cuda", compute_type="int8")

# CPUで実行する場合
# model = WhisperModel("large-v3", device="cpu", compute_type="int8")

segments, info = model.transcribe("audio.mp3", language="ja")

print(f"検出言語: {info.language} (確率: {info.language_probability:.2f})")

for segment in segments:
    print(f"[{segment.start:.2f}s -> {segment.end:.2f}s] {segment.text}")

4.3 パフォーマンス比較(13分の音声ファイル)

実装 GPU処理時間 GPU VRAM CPU処理時間
openai-whisper (large-v2) 4分30秒 11.3 GB 10分超
faster-whisper (large-v2, FP16) 54秒 4.7 GB
faster-whisper (large-v2, INT8) 3.1 GB 2分44秒

VRAMが11.3 GB → 4.7 GBに削減。これは8GB VRAMのGPUでもlarge-v3が動くことを意味する。(;゚д゚)ポカーン

4.4 faster-whisperの主な派生ツール

faster-whisperのエコシステムは豊富だ。

ツール 特徴
whisper-ctranslate2 openai-whisperと互換のCLIクライアント
WhisperX faster-whisper + 話者分離(pyannote)+ 単語レベルタイムスタンプ
whisper-standalone-win Windows/Linux/macOS向けスタンドアロン実行ファイル
whisper-diarize faster-whisper + NVIDIA NeMoによる話者分離

WhisperXは内部でfaster-whisperを呼んでいるため、CUDA/cuDNNの要件は同じだ。話者分離が必要なら最初からWhisperXを検討しよう。


5. OpenAI API での文字起こし — クラウドの手軽さ

「GPUを用意するのは面倒」「とにかく手軽に使いたい」なら、OpenAI APIが最適解だ。レストランに行かずUber Eatsで注文するようなものだと思えばいい。

5.1 利用可能なモデル(2026年3月時点)

モデル 料金(/分) 特徴
whisper-1 $0.006 Whisper V2ベース。安定の実績
gpt-4o-transcribe $0.006 GPT-4oベース。whisper-1より高精度
gpt-4o-mini-transcribe $0.003 コスト重視ならこれ。半額
gpt-4o-transcribe-diarize $0.006 話者分離付き文字起こし

2025年3月にGPT-4oベースの新モデルが追加された。whisper-1より低いエラー率を達成しており、特別な理由がなければ新モデルの使用を推奨する。

5.2 環境準備

pip install openai

APIキーは以下で取得する:

環境変数に設定しておこう。

# Linux / macOS / WSL
export OPENAI_API_KEY="sk-xxxxxxxxxxxxxxxx"

# Windows PowerShell
$env:OPENAI_API_KEY = "sk-xxxxxxxxxxxxxxxx"

5.3 基本的な文字起こし

from openai import OpenAI

client = OpenAI()  # 環境変数 OPENAI_API_KEY を自動で読む

# シンプルな文字起こし
with open("audio.mp3", "rb") as audio_file:
    transcript = client.audio.transcriptions.create(
        model="whisper-1",
        file=audio_file,
        response_format="text"
    )

print(transcript)

5.4 タイムスタンプ付き文字起こし

from openai import OpenAI

client = OpenAI()

with open("audio.mp3", "rb") as audio_file:
    transcript = client.audio.transcriptions.create(
        model="whisper-1",
        file=audio_file,
        response_format="verbose_json",
        timestamp_granularities=["word", "segment"]
    )

# セグメント単位
for seg in transcript.segments:
    print(f"[{seg['start']:.1f}s - {seg['end']:.1f}s] {seg['text']}")

# 単語単位
for word in transcript.words:
    print(f"  {word['word']} ({word['start']:.2f}s)")

5.5 翻訳(他言語 → 英語)

from openai import OpenAI

client = OpenAI()

# 日本語音声を英語テキストに翻訳
with open("japanese_audio.mp3", "rb") as audio_file:
    translation = client.audio.translations.create(
        model="whisper-1",
        file=audio_file
    )

print(translation.text)

翻訳エンドポイント(/v1/audio/translations)は現在 whisper-1のみ対応。出力は英語のみ。日本語→フランス語のような翻訳はできない。

5.6 SRT字幕ファイルの生成

from openai import OpenAI

client = OpenAI()

with open("video_audio.mp3", "rb") as audio_file:
    transcript = client.audio.transcriptions.create(
        model="whisper-1",
        file=audio_file,
        response_format="srt",
        language="ja"
    )

# SRTファイルとして保存
with open("subtitles.srt", "w", encoding="utf-8") as f:
    f.write(transcript)

5.7 プロンプトによる精度向上テクニック

Whisper APIでは prompt パラメータでモデルの出力を誘導できる。これは直前のセグメントのコンテキストをモデルに伝える仕組みだ。

from openai import OpenAI

client = OpenAI()

# 専門用語が多い場合、プロンプトに含めると認識精度が上がる
with open("tech_meeting.mp3", "rb") as audio_file:
    transcript = client.audio.transcriptions.create(
        model="whisper-1",
        file=audio_file,
        language="ja",
        prompt="CUDA、PyTorch、RTX 5090、VRAM、Transformerについての技術ミーティング"
    )

print(transcript.text)

whisper-1はプロンプトの最後の224トークンのみを参照する。長すぎるプロンプトは先頭が無視される。

5.8 25MBを超えるファイルの分割処理

APIのファイルサイズ上限は25MB。それを超える場合はpydubなどで分割する。

from pydub import AudioSegment
from openai import OpenAI
import math

client = OpenAI()

def transcribe_large_file(file_path, chunk_minutes=10):
    """大きな音声ファイルを分割してAPIに送信"""
    audio = AudioSegment.from_file(file_path)
    chunk_ms = chunk_minutes * 60 * 1000
    chunks = math.ceil(len(audio) / chunk_ms)
    
    full_transcript = []
    previous_text = ""
    
    for i in range(chunks):
        start = i * chunk_ms
        end = min((i + 1) * chunk_ms, len(audio))
        chunk = audio[start:end]
        
        # 一時ファイルに書き出し
        chunk_path = f"/tmp/chunk_{i}.mp3"
        chunk.export(chunk_path, format="mp3")
        
        with open(chunk_path, "rb") as f:
            transcript = client.audio.transcriptions.create(
                model="whisper-1",
                file=f,
                language="ja",
                prompt=previous_text[-200:] if previous_text else ""
            )
        
        full_transcript.append(transcript.text)
        previous_text = transcript.text
    
    return "\n".join(full_transcript)

result = transcribe_large_file("long_meeting.mp3")
print(result)

前のチャンクの末尾テキストを次のチャンクの prompt に渡すことで、文脈の断絶を防いでいる。これはOpenAI公式ドキュメントでも推奨されている手法だ。


6. ローカル vs API — どちらを選ぶべきか

ここまでローカル実行とAPI実行の両方を見てきた。では結局どちらが自分のユースケースに合うのか。判断基準を整理しよう。

観点 ローカル実行 OpenAI API
初期コスト GPU必要(既にあれば0円) 不要
ランニングコスト 電気代のみ $0.003〜0.006/分
損益分岐点 ~500時間/月でAPIより安価 少量なら圧倒的に安い
精度 large-v3で最高水準 gpt-4o-transcribeが最高
速度 GPU依存。faster-whisper+turboで爆速 サーバー側GPU。安定
プライバシー データが外に出ない OpenAIに送信される
カスタマイズ 量子化、モデル選択、VAD等自由 パラメータ限定
話者分離 WhisperX等で対応 gpt-4o-transcribe-diarize
セットアップ難易度 中〜高(CUDA環境構築) 低(pip install + API key)

個人的な推奨

ユースケース 推奨
個人プロジェクト・プロトタイプ API(gpt-4o-mini-transcribe、$0.003/分は安い)
業務利用・大量処理 ローカル(faster-whisper + turbo)
機密データの文字起こし ローカル一択
字幕制作・動画編集 ローカル(タイムスタンプの細かい制御が可能)
サーバーレスアプリ API(インフラ不要)

7. よくあるエラーと対処法

エラー 原因 対処法
FileNotFoundError: ffmpeg FFmpegがPATHにない winget install Gyan.FFmpeg 後にターミナル再起動
CUDA out of memory VRAM不足 smaller modelに変更 or faster-whisperのINT8量子化を使用
RuntimeError: CUDA error CUDA/cuDNNバージョン不一致 nvidia-sminvcc --version でバージョン確認
ctranslate2 importエラー CUDA 12 + cuDNN 9が未対応 pip install ctranslate2==3.24.0 でダウングレード
APIで File too large 25MB超のファイル pydubで分割してから送信(上記コード参照)
日本語がおかしい 言語自動判定の誤り language="ja" を明示指定する
「ハルシネーション」が出る 無音区間での幻覚出力 VAD(Voice Activity Detection)を有効化する

Whisperにはハルシネーション問題がある。無音や小さなノイズしかない区間で、存在しない文を生成してしまう現象だ。faster-whisperでは vad_filter=True を指定することでVADによるフィルタリングが可能。API利用時も gpt-4o-transcribe はこの問題が大幅に改善されている。


8. 環境診断スクリプト

自分の環境でWhisperが正常に動くか、一発で確認できるスクリプトを用意した。

"""
Whisper環境診断スクリプト
実行方法: python whisper_diagnosis.py
"""
import sys
import subprocess
import importlib

def check(name, condition, detail=""):
    status = "OK" if condition else "NG"
    mark = "" if condition else ""
    print(f"  {mark} {name}: {status} {detail}")
    return condition

print("=" * 60)
print("Whisper 環境診断")
print("=" * 60)

# Python バージョン
py_ver = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
check("Python", sys.version_info >= (3, 8), f"({py_ver})")

# FFmpeg
try:
    result = subprocess.run(["ffmpeg", "-version"], capture_output=True, text=True)
    ffmpeg_ver = result.stdout.split("\n")[0] if result.returncode == 0 else "not found"
    check("FFmpeg", result.returncode == 0, f"({ffmpeg_ver[:50]})")
except FileNotFoundError:
    check("FFmpeg", False, "(コマンドが見つかりません)")

# PyTorch
try:
    import torch
    cuda_available = torch.cuda.is_available()
    check("PyTorch", True, f"({torch.__version__})")
    check("CUDA (PyTorch)", cuda_available,
          f"({torch.version.cuda})" if cuda_available else "(CPU mode)")
    if cuda_available:
        gpu_name = torch.cuda.get_device_name(0)
        vram = torch.cuda.get_device_properties(0).total_mem / (1024**3)
        check("GPU", True, f"({gpu_name}, VRAM: {vram:.1f} GB)")
except ImportError:
    check("PyTorch", False, "(未インストール)")

# openai-whisper
try:
    import whisper
    check("openai-whisper", True, f"(installed)")
except ImportError:
    check("openai-whisper", False, "(pip install openai-whisper)")

# faster-whisper
try:
    import faster_whisper
    check("faster-whisper", True, f"(installed)")
except ImportError:
    check("faster-whisper", False, "(pip install faster-whisper)")

# OpenAI API
try:
    import openai
    check("openai (API client)", True, f"({openai.__version__})")
except ImportError:
    check("openai (API client)", False, "(pip install openai)")

print("=" * 60)

# VRAM別モデル推奨
try:
    import torch
    if torch.cuda.is_available():
        vram = torch.cuda.get_device_properties(0).total_mem / (1024**3)
        print(f"\n推奨モデル(VRAM {vram:.0f} GB の場合):")
        if vram >= 10:
            print("  🥇 large-v3 (FP16)     — 最高精度")
            print("  🥈 turbo (FP16)        — 高速+高精度")
        elif vram >= 6:
            print("  🥇 turbo (FP16)        — 最適バランス")
            print("  🥈 large-v3 (INT8)     — faster-whisper推奨")
        elif vram >= 4:
            print("  🥇 medium (FP16)       — 十分な精度")
            print("  🥈 large-v3 (INT8)     — faster-whisper限定")
        else:
            print("  🥇 small (FP16)        — 軽量で実用的")
            print("  🥈 base (FP16)         — 最軽量")
except:
    pass

9. 学習ロードマップ

Whisperを起点に、音声AIの世界を段階的に探索していこう。

レベル 学ぶべきこと 参考リソース
1 Whisperの基本操作 この記事
2 faster-whisper、INT8/FP16量子化 faster-whisper GitHub
3 話者分離、単語レベルタイムスタンプ WhisperX GitHub
4 ドメイン特化ファインチューニング HuggingFace Blog
5 大規模バッチ処理、コスト最適化 OpenAI Batch API / 自前サーバー構築

まとめ

Whisperを「ローカル」と「API」の両面から触ってみて、改めて音声認識がここまでコモディティ化したことに驚いた。68万時間の訓練データで鍛えられたモデルが、pip install 一発で手に入る。API経由なら数行のコードで99言語の文字起こしが動く。

自分のRTX5090環境ではfaster-whisper + large-v3がVRAM 5GB弱で動いており、1時間の会議音声が1分足らずで文字起こしできている。一方、プロトタイプや小規模利用ならAPI(gpt-4o-mini-transcribeで$0.003/分)が圧倒的に手軽だ。

選択肢があることこそが価値だと思う。自分のユースケースに合わせて、「ローカルの自由度」と「APIの手軽さ」を使い分けていこう。


参考文献


Follow on X

最新のAI・GPU・セキュリティ情報を発信中。フォローお待ちしています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?