RTX 50 シリーズで動く Whisper ── whisper.cpp フォークと実運用 STT レイヤー
本家 whisper.cpp は Blackwell GPU でクラッシュします。それを修正し、ストリーミング・単語単位のタイムスタンプ・キャンセル・OpenAI 互換の文字起こし API で包みました。
私たちは最新の NVIDIA ハードウェア上で大量の音声認識を回していますが、RTX 50 シリーズのカードを持つ人なら誰もが直面する壁にぶつかりました—— whisper.cpp が起動しないのです。「遅い」のではなく、音声を 1 秒もデコードする前に、CUDA 初期化の途中でプロセスが落ちます。そこでフォークしました。フォークは github.com/openalchemy/whisper.cpp にあります。本記事では、私たちが修正したクラッシュと、その周りに構築した実運用向けの文字起こしレイヤーを紹介します。
Blackwell でのクラッシュ
RTX 50 シリーズ GPU(Blackwell、compute capability sm_120)では、CUDA バックエンドがまだ部分的にしか列挙されていないデバイススロットを報告することがあります。これが起きると ggml_backend_reg_dev_get() が NULL を返します。本家はそのポインタを無条件にデバイスリストへ push してしまい、次にリストを走査する呼び出し元がアサーションに引っかかってプロセスを kill します:
// 本家: 部分列挙された Blackwell(sm_120)スロットが NULL を返し、
// その NULL が保存され、後の GGML_ASSERT(device) でプロセスが落ちる。
ggml_backend_dev_t dev = ggml_backend_reg_dev_get(reg, i);
devices.push_back(dev); // NULL が入る → バックエンド初期化でクラッシュ
// OpenAlchemy フォーク: 空スロットをガードして列挙を続ける。
ggml_backend_dev_t dev = ggml_backend_reg_dev_get(reg, i);
if (!dev) continue; // 部分スロットをスキップ
devices.push_back(dev);修正は小さく外科的です——ggml-backend-reg.cpp と whisper.cpp のバックエンド初期化パスに数個の NULL ガードを入れただけです。これにより CUDA バックエンドはきれいに列挙し、空スロットをスキップし、デコードは最後まで走ります。RTX 5080(16 GB)、ドライバ 591.86、CUDA 13.2 で検証しました。パッチなしではすべての呼び出しが初期化中にアサートし、ありなら文字起こしが普通に動きます。フォークは本家 whisper.cpp v1.8.6 を追従しているので、最新エンジンに加えて、現行 GPU で起動させる唯一のパッチが手に入ります。
「動く」から実用 API へ
Whisper を起動させるのは床であって天井ではありません。フォークしたエンジンの周りに、それを実際にプロダクションで使える文字起こしサービスへと変えるランタイムレイヤーを構築しました——ストリーミング、単語単位のタイミング、OpenAI 互換のレスポンス形状、そしてきれいなキャンセルです。OpenAlchemy の STT ランタイムが素の whisper.cpp に加えるものは次のとおりです:
これらのいくつかは、機能であると同時にバグ修正でもあります。最大のものは language=auto がセグメント 0 件を返していた問題です——言語検出パスとデコードパスが競合し、自動検出リクエストが黙って空の文字起こしを生成していました。これは修正済みで、言語検出はデコードパス上で暗黙に走るようになりました。
返ってくるもの
文字起こしは OpenAI Audio API と同じ verbose_json の形状で返るので、既存のクライアントはそのまま動きます——セグメント、検出された言語、長さ、(要求すれば)単語単位のタイムスタンプ、そして課金用の usage フィールドです:
{
"task": "transcribe",
"language": "ja",
"duration": 12.84,
"text": "...",
"segments": [
{ "id": 0, "start": 0.00, "end": 3.20, "text": "..." }
],
"words": [
{ "word": "こんにちは", "start": 0.00, "end": 0.48 }
],
"usage": { "audio_seconds": 12.84 }
}呼び出しは /v1/audio/transcriptions への標準的な multipart リクエストです(翻訳は /v1/audio/translations):
curl https://api.openalchemy.io/v1/audio/transcriptions \
-H "Authorization: Bearer $OPENALCHEMY_API_KEY" \
-F model=whisper-large-v3 \
-F response_format=verbose_json \
-F "timestamp_granularities[]=word" \
-F file=@meeting.m4aローカルで動かす
Whisper は OpenAlchemy Engine デスクトップアプリ(v0.5.1)に Speech-to-Text ランタイムとして搭載されています。Speech-to-Text の下で Whisper エンジンを選べば、Blackwell の初期化を生き延びるのと同じフォークが、あなた自身の GPU 上で文字起こしを動かします——このビルドこそが、50 シリーズのカードで STT ジョブを処理できる理由です。
パッチはオープンソースです。ガードとバックエンド初期化の変更は github.com/openalchemy/whisper.cpp で読めます。50 シリーズのカードで whisper.cpp がアサートし続けていたなら、その一行の理由——そして修正——がこれです。
正直に言うと、今回のリリースは速度の主張ではなく、安定性と統合の話です。フォークの RTF や精度のベンチマークはまだ公開できる形では持っていないので、数値は出しません。実測値が揃ったら、それは別の記事にします。