CoolFace
Modelpublic

infodeliverailab/qwen3-omni-jp-vllm

sourceHugging Faceupdated 2mo agoView on Hugging Face
0likes
Model Card

Qwen3-Omni-30B-A3B 日本語 ASR + 話者分離 (vLLM サーバ版)

Qwen3-Omni-30B-A3B-Instruct をそのままの重みで日本語音声書き起こしに使う「レシピ」。 モデル重みは Qwen 公式そのまま (Qwen/Qwen3-Omni-30B-A3B-Instruct) を使い、 本レポは セットアップ + サーバ実装 だけを配布します。

  • —base: Qwen/Qwen3-Omni-30B-A3B-Instruct
  • —runtime: vLLM (fused MoE kernel + PagedAttention + CUDA graph)
  • —測定環境: NVIDIA A100 80GB, bf16
  • —速度実測: 30 秒の電話音声を 約 4 秒 で完全書き起こし (標準 transformers 実装比 約 6 倍)
  • —実効計算は 3B クラス: 総パラメータは 30B だが MoE (top-k=8 / 128 experts) なので、 1 トークンあたり実際に走る expert は 8 個 = 推論時にアクティブになるパラメータは約 3B。 30B 全体をロードするだけの VRAM は要るが、演算量は 3B の dense モデルと同等水準。

性能

Qwen3-Omni-30B-A3B-Instruct そのままの重みで:

  1. 1.電話音声 (mulaw 8kHz、証券会社の営業電話) — 話者ラベル [spk_0][spk_1] を正しく振り分け、 固有名詞 (顧客名、会社名、支店名) や数値 (銘柄コード等) までほぼ正確に起こす。 Whisper + pyannote などの従来型 (ASR + diarization を別段でつなぐ) パイプラインを圧倒する精度。 これは Qwen3-Omni がマルチモーダル LLM として音響 + 言語文脈を一体で扱える強みで、 固有名詞・数字・話者切替の判定が全て言語モデル側の推論として動くため。
  2. 2.話者分離 — 追加学習なし。1 パスで「誰が」「何を」を出力。話者数が可変でも自動対応。
  3. 3.企業名 / 商品名 / 銘柄コード — 日本語 LLM の中でも最上位の認識精度。
  4. 4.現代の潮流: 音響エンジン + LM のカスケードは (数年前まで最強だった) Whisper 系が代表格だが、 マルチモーダル LLM (Qwen3-Omni、Gemini 2 系、GPT-4o 音声系など) が 精度・柔軟性ともに世代交代 している状況。本レポはその実運用サンプル。

なぜ transformers そのままだと遅いのか

Qwen3-Omni は Mixture-of-Experts (MoE) モデルで、内部の各層に 128 個の「専門家 (expert)」 FFN があり、トークンごとに router がその中から動的に 8 個選んで使う。 標準の transformers ライブラリでの計算は、この一連の処理を大量の小さなカーネルに分けて実行する:

router で 8 個を選ぶ → 選ばれた expert に token を振り分ける → 各 expert ごとに FFN 計算
→ 重み α を掛ける → 結果を全部足し合わせる

これを バッチサイズ 1 (通常の推論) で回すと、GPU への「命令発行」オーバーヘッドが積み重なり、 実際の計算より待ち時間の方が支配的になる。48 層 × 30 個以上のカーネル起動が毎トークンで 走るので、GPU がほぼ「待機」の状態になってしまう。

vLLM が何をしているか

vLLM の MoE 実装は、上の一連の処理を 1 つの融合カーネル にまとめてある:

router → top-K → dispatch → expert FFN 群 → weighted sum   ← 全部これを 1 発の GPU カーネルで

加えて:

  • —PagedAttention — KV cache を効率よく管理
  • —CUDA Graph capture — カーネル起動オーバーヘッドを事実上ゼロに
  • —FlashAttention 内蔵
  • —thinker-only mode — 音声合成用の Talker/Code2Wav は読み込まない

これで A100 80GB 上、111 秒の音声 (200 トークン生成) を 2.1 秒 (95 tok/s) で処理。 transformers 標準の同条件が 14 秒 (14.4 tok/s) なので 約 6.5 倍。

ファイル構成

qwen3-omni-jp-vllm/
├── README.md                (このファイル)
├── setup.sh                 (venv + 依存 install + モデル DL、1 発で deploy)
├── server.py                (FastAPI + vLLM のブラウザ UI サーバ、port 8080)
└── example_transcribe.py    (サーバ無しで 1 音声を書き起こす CLI)

使い方

準備 (1 回だけ)

必要なもの: NVIDIA GPU (VRAM 70GB 以上、A100 80GB を推奨)、Python 3.10 以上、 インターネット接続 (モデル約 65GB を Hugging Face からダウンロード)。

bash
git clone https://huggingface.co/infodeliverailab/qwen3-omni-jp-vllm
cd qwen3-omni-jp-vllm
bash setup.sh

setup.sh は以下を自動でやります。所要時間は回線速度次第で 10〜30 分程度:

  1. 1.Python の仮想環境を作る (venv)
  2. 2.vLLM 等の必要ライブラリを pip install
  3. 3.モデル (Qwen3-Omni-30B-A3B-Instruct、約 65GB) を Qwen3-Omni-30B-A3B-Instruct/ フォルダにダウンロード

ブラウザで音声をアップロードして書き起こす

bash
source venv/bin/activate
python server.py

これで `http://<サーバの IP>:8080/` にブラウザからアクセスできます。 音声ファイル (wav / opus / mp3 / m4a) をドラッグ&ドロップ、または「クリックで選択」で アップロードして「書き起こし実行」を押すだけ。数秒で結果が表示されます。

  • —30 秒の音声で ~4 秒
  • —3 分の音声で ~20-30 秒 (中身の密度による)
  • —話者ごとに [spk_0] [spk_1] タグが自動で入り、色分けされます
  • —履歴 (直近 20 件) は同じページに残ります

長い音声 (5 分以上) を扱う場合は「max_tokens」を大きめ (1500-2000) にしてください。

コマンドラインで 1 ファイルだけ書き起こす

サーバを立てず、単発で結果を見たい場合:

bash
source venv/bin/activate
python example_transcribe.py --audio your.wav

結果が標準出力に出ます。出力例:

[spk_0] お電話ありがとうございます。◯◯証券△△店の宮沢でございます。
[spk_1] すいません、稲見です。お世話になります。
[spk_0] お世話になります。佐藤さんは?
...

モデルフォルダの場所を変えたい

デフォルトはこのレポと同じ場所 (./Qwen3-Omni-30B-A3B-Instruct/) に置きます。別の場所 (容量の大きいディスクなど) に置きたい場合:

bash
# setup 時
MODEL_DIR=/mnt/big-disk/qwen3-omni bash setup.sh

# サーバ起動時
MODEL_DIR=/mnt/big-disk/qwen3-omni python server.py

# CLI
python example_transcribe.py --audio your.wav --model_dir /mnt/big-disk/qwen3-omni

トラブルシューティング

  • —モデル DL が途中で止まる — 再度 bash setup.sh を実行するとレジューム
  • —VRAM 不足エラー (OOM) — A100 80GB / H100 が推奨、A6000 48GB 以下だと厳しい
  • —`Engine core initialization failed` — 既に別の vLLM プロセスが VRAM を掴んでいる可能性。 nvidia-smi で確認、必要なら pkill -9 -f "python.*server" してから再起動
  • —UI で "書き起こしが途中で切れる" — max_tokens を大きくして再実行 (デフォルト 800)
  • —初回リクエストが遅い — vLLM は最初の 1 回で CUDA graph を capture するため。2 回目以降は本来の速度が出ます

統計的に不要な expert を事前排除する余地 (実験的知見)

このモデルの routing 分布を calibration データ (電話 3 件 + YT 3 件で複数音声を通し、 decode 側 token 全体で softmax 分布を平均) で測ると、多くの層で「router がどの expert を選ぶかがほぼ均等」であることが分かった。具体的には、48 層のうち下記 27 層は router の候補集合を「層平均 softmax の上位 64 個」に絞ってしまっても 書き起こし品質が baseline とほぼ変わらない:

  • —T1 (KL(token_softmax || layer_mean) < 0.16、7 層): layers 7, 16, 18, 19, 30, 31, 43
  • —T2 (KL < 0.19、20 層): layers 6, 8, 9, 12, 13, 14, 15, 17, 20, 21, 24, 26, 27, 28, 29, 32, 33, 44, 45, 46

これら 27 層について router に「上位 64 個以外は選ぶな」という mask を掛けた 6 音声比較実験でも、話者ラベル / 固有名詞 / 数値まで含めて baseline と実質同等の 出力が得られた。残り 64 個の expert は実質的に不要であり、この 27 層に関しては 128 → 64 の dense 化 (KRAFTON MoE-to-dense の block-concat trick) の余地がある。

一方、T1+T2+T3 (kl < 0.22、38 層) に拡げると YT モノローグ音声で数字ズレ (「PER 9.29 → PR 9.29」など) が出始めるため、現状の安全域は T1+T2 の 27 層まで。

現在の vLLM 実装では weight-level の削減までは行っていない (mask だけでは router を通る点は同じで、速度改善には dense concat が必要)。この統計的知見は、 将来モデル自体を smaller dense に置き換える形で更なる速度改善を狙う場合の 根拠になる (別途研究中)。

ライセンス

  • —モデル重み: Qwen 公式ライセンス に従います
  • —本レポの setup.sh / server.py / example_transcribe.py: Apache-2.0