
プロンプトだけでカスタマイズできる!?Nemotron 3.5 Transcribeに専門用語リストを渡したら、日本語での認識精度が31%から67%に上がった
こんちには。製造ビジネステクノロジー部の中村(@nokomoro3)です。
2026年10月28日に、NVIDIAから音声認識モデル「Nemotron 3.5 Transcribe」が公開されました。
従来のASRモデルでは、専門用語に対応させたり、句読点の有無を変えたりするには、モデルの外の仕組みや追加の学習が必要でした。
Nemotron 3.5 Transcribeは、音声エンコーダに言語モデルをつないだ構成で、文字起こしのやり方を自然言語の指示(プロンプト)で変更することができます。
たとえば、専門用語のリストを渡す、句読点を外す、話者ごとに分ける、英語に訳すといったことを、指示文を書き換えるだけで1つのモデルで実現することが可能です。
指示は、音声と一緒にユーザーメッセージに入れます。
モデルカードでは、Formatting:やContext terms:のようなラベルを付けて、書き方や用語を指定する形が推奨されています。
以前の記事では、NVIDIA L40Sで日本語対応のASRモデルを比較し、Nemotron 3.5 ASR(0.6B)を専門用語を含む日本語の音声でファインチューニングしました。
本記事では、Nemotron 3.5 TranscribeをL40Sで動かし、プロンプトによる制御が日本語でどこまで効くのかを、これらの記事と同じ音声で確かめました。
あわせて、認識精度を以前の記事の結果と比べています。
結論
- 専門用語リストの効果
- 用語のリストをプロンプトに入れるだけで、専門用語の認識精度が31.5%から66.7%に上昇
- 以前の記事でファインチューニングした0.6Bのモデル(38.9%)を大きく上回り、紛らわしい一般語を専門用語に置き換えてしまう副作用も少ない
- 表記の指示
- 句読点なしの指示ははっきり効いた(650件中649件)
- 数字の表記(算用数字か漢数字か)の指示は、指示どおりの方向に効いたが、650件中410件は2つの指示で同じ出力で、効き方は弱かった
- 音声からの直接翻訳
- BLEUは日本語→英語で22.82、英語→日本語で30.33で、モデルカードの値(23.00、29.73)とほぼ同じだった
- 認識精度(FLEURSの日本語、650件)
- 正規化CERは4.18%で、以前の記事で比べたどのモデル(最良はWhisper large-v3の4.49%)よりも低かった。ただし、FLEURSは学習データに含まれる
- 動作させるための注意点
- モデルカードの手順のままではL40Sで動かず、CUDA 13の互換パッケージの追加、vLLMのMambaバックエンドのTritonへの変更、投機的デコード(MTP)の無効化の3か所を変える必要があった
- MTPを使えなかったため厳密な速度比較はしていないが、平均13.1秒の音声を約0.44秒で処理できた
Nemotron 3.5 Transcribeとは
これまでのASRとの違い
Whisperのような従来のASRモデルでも、出力をある程度調整する方法はありましたが、その多くはモデルの外の仕組みか、追加学習を行う必要がありました。
Nemotron 3.5 Transcribeでは、同じことをプロンプトで調整することが可能になっています。
| やりたいこと | 従来のASRでの方法の例 | Nemotron 3.5 Transcribe |
|---|---|---|
| 専門用語を正しく書かせる | Phrase Boosting、ファインチューニング | プロンプトに用語を並べる |
| フィラーや句読点の扱いを変える | 認識後の後処理 | 指示文で切り替える |
| 誰が話したかを付ける | 話者分離モデルと組み合わせる | 話者タグを付けるよう指示する(単語のタイムスタンプも出せる) |
| 翻訳する | ASRと翻訳モデルを2段で組む | 翻訳するよう指示する |
プロンプトの書き方
指示は、チャット形式のユーザーメッセージに、音声と一緒に入れます。
モデルカードは、文字起こしではシステムプロンプトを空にし、指示をユーザーメッセージに書くよう推奨しています。
モデルカードで例示されている、FLEURSの評価に使ったプロンプトは次のとおりです。
Audio transcription. Language: as spoken, in its standard writing system. Wording: verbatim, including fillers and repetitions. Formatting: punctuation and capitalization; numbers in their standard written form. Output: transcript only.
日本語に訳すと、次のような指示です。
音声の書き起こし。
言語:話されたとおり、その言語の標準的な表記で。
言葉づかい:フィラーや繰り返しも含めて逐語的に。
書式:句読点と大文字小文字を付ける。数字は標準的な書き言葉の形で。
出力:書き起こしのみ。
このように、先頭にAudio transcription.を置き、ラベルを付けて項目ごとに指定するのが、モデルカードの推奨する書き方です。
文字起こしの推奨プロンプトに出てくるラベルは、次の4つです。
| ラベル | 指定する内容 | 値の例 |
|---|---|---|
Language: |
どの言語や表記で書くか | as spoken、as spoken, in its standard writing system |
Wording: |
言葉づかい(フィラーや言い直しを残すか) | verbatim, including fillers and repetitions、omit fillers and accidental repetitions |
Formatting: |
句読点や数字の書き方 | punctuation and capitalization、numbers in their standard written form |
Output: |
何を出力するか | transcript only |
専門用語などを渡すときは、別のラベルを使います。
| ラベル | 出典 | 書き方の例 |
|---|---|---|
Context terms: |
モデルカードの推奨 | Transcribe with punctuation and capitalization. Context terms: <names and terms>. |
Possible terms: |
Hugging Faceのブログの医療の例 | Transcribe this medical discussion in the original language. Possible terms: HbA1c, metformin. Use these terms only when supported by the audio. |
これらはAPIで決まった項目ではなく、自然言語の指示の中での書き方です。
話者タグを付ける指示のように、ラベルを使わずに普通の文で書く推奨プロンプトもあります。
本記事の検証では、このうちFormatting:の値を変えて表記の指示を、Context terms:で専門用語リストを渡して、その効果を確かめています。
モデルの概要
言語モデル部分はMamba-2、Attention、MoEを組み合わせたハイブリッド構成です。
総パラメータは約30Bですが、MoEにより1トークンあたりに使うパラメータ(アクティブパラメータ)は約4Bに抑えられています。
| 項目 | 内容 |
|---|---|
| モデル | nvidia/NVIDIA-Nemotron-3.5-Transcribe-30B-A4B |
| 量子化版 | FP8版、NVFP4版 |
| 対応言語 | 文字起こしは40言語、英語との翻訳は31言語 |
| 入力 | 最長1時間の録音(ストリーミングには非対応) |
| ライセンス | OpenMDW-1.1(商用利用可) |
モデルカードでは、英語のOpen ASR Leaderboardで、オープンウェイトのモデルの中で最も低いWERとされています。
日本語は、文字起こし、英語との双方向の翻訳、複数の話者が話す音声の文字起こし、コードスイッチングのすべてに対応しています。
コードスイッチングは、1つの発話の中で言語が切り替わることで、日本語の会話に英語の文や語句が混ざるような場面を指します。
モデルカードは言語ごとの品質を「Leading」(そのままで最先端かそれに近い)と「Production-ready」(実運用レベル)に分けており、日本語は「Production-ready」です(英語や韓国語は「Leading」)。
検証用コード
検証に使用したスクリプトと集計結果は以下のリポジトリにあります。
以前のASR比較の記事のリポジトリをもとに、Nemotron 3.5 Transcribe用の推論スクリプトなどを追加したものです。
検証の方法
比べる観点
次の4つの観点で確かめました。
| 観点 | 使う音声 | 比べる相手 |
|---|---|---|
| 専門用語リストの効果 | 以前の記事で録音した、専門用語を含む日本語の音声(60文) | 以前の記事でPhrase Boostingとファインチューニングで改良した結果 |
| 表記の指示 | FLEURSの日本語テストセット(650件) | 指示文だけを変えた条件同士の比較 |
| 音声からの直接翻訳 | FLEURSの日本語と英語のテストセット | モデルカードの値 |
| 認識精度 | FLEURSの日本語テストセット | 以前の記事のWhisper large-v3、Parakeetなど |
FLEURSの日本語テストセット(ja_jp test)は、以前の記事と同じく650件、合計約2.4時間(1件平均13.1秒)の読み上げ音声です。
音声ファイルと入力の順序は、以前の記事とまったく同じものを使いました。
モデルとランタイム
モデルは、L40SがサポートされているFP8版(nvidia/NVIDIA-Nemotron-3.5-Transcribe-30B-A4B-FP8)を使いました。
モデルカードの対応表では、L40SはFP8版だけが対象です。
モデルカードによると、FP8版の誤り率はBF16版より相対で平均1.0%高くなります。
モデルカードの評価値はすべてBF16版のものなので、比べるときはこの差を念頭に置いてください。
推論にはvLLM 0.32.0を使い、OpenAI互換のAPIサーバーとして起動したうえで、スクリプトから音声を送りました。
モデルカードの対応表で、L40SのFP8版に対応するランタイムとして挙がっているのは、vLLMとHugging Face Transformersの2つです。このうち、FP8版の手順(インストール、起動コマンド、起動時に確認すべき項目)がモデルカードに書かれているのはvLLMだけだったため、vLLMを選びました。
モデルカードの推奨どおり、temperatureは0、推論モード(thinking)は無効にしています。
学習データとの重なり
モデルカードは、学習データにFLEURSが含まれると明記しています。
同時に公開されたデータセットのGranary v2を確認すると、日本語のFLEURSはtrainの分割だけが入っており、評価に使ったtest分割は含まれていませんでした。
ただし、学習データはGranary v2だけではないため、FLEURSでの精度は、まったく初見の音声に対する精度とは解釈できません。ここは以前の記事で比べたNemotron 3.5 ASR(0.6B)も同じ状況だったため、そのときと同じ扱いにしています。
実行環境の構築
それでは実際に動作させてみます。
インストールと起動は、モデルカードの手順をできるだけそのまま使い、L40Sで動かなかった箇所だけを変えています。
どの変更が必要かは、新しいインスタンスでモデルカードの手順をそのまま実行し、失敗した箇所を1つずつ直して確かめました(記録はリポジトリのverification/official-rerun.mdにあります)。
Brevのインスタンス
実行環境には、以前の記事と同じNVIDIA Brevのl40s-48gb.1x(L40S 1基、VRAM 48GB)を新しく作って使いました。
brev create cm-nakamura-nemotron-transcribe-2 --type l40s-48gb.1x
作成できたら、インスタンスに接続します。
brev shell cm-nakamura-nemotron-transcribe-2
接続先のホスト名が見つからないと言われた場合は、brev refresh で手元のSSHの設定を更新します。
接続したら、GPUとドライバのバージョンを確認しておきます。
nvidia-smi --query-gpu=name,driver_version,memory.total --format=csv
name, driver_version, memory.total [MiB]
NVIDIA L40S, 565.57.01, 46068 MiB
このインスタンスのGPUドライバは565系で、CUDA 12.7までに対応しています。
CUDA 13の互換パッケージを入れる
最初に、CUDA 13のランタイムを使うためのパッケージを入れます。
sudo apt-get install -y cuda-compat-13-0
vLLM 0.32.0が入れるPyTorchはCUDA 13向けのビルド(2.13.0+cu130)で、ドライバ565のままでは動きません[1]。
L40Sのようなデータセンター向けのGPUでは、このforward compatibilityパッケージを使うと、ドライバを入れ替えずにCUDA 13のランタイムを使えます[2]。
入れたライブラリは、後でサーバーを起動するときにLD_LIBRARY_PATHに加えます。
以前のファインチューニングの記事でも、同じドライバ565のままでは動かない問題に遭遇し、そのときはCUDA 12向けのPyTorch(2.11.0+cu129)に固定して避けました。
今回は、モデルとランタイムの節で書いたとおりvLLMを使います。
vLLM 0.32.0はCUDA 13向けのPyTorchを指定しているため、同じ方法は使えず、互換パッケージを入れています。
vLLMとNeMo Speechを入れる
vLLMとNeMo Speechは、モデルカードの手順のとおりに入れます。
git clone https://github.com/NVIDIA-NeMo/Speech.git nemo-speech
cd nemo-speech
uv venv --python 3.13 .venv
UV_PROJECT_ENVIRONMENT=$PWD/.venv uv sync --extra asr --extra vllm --locked --no-install-project
uv pip install --python .venv/bin/python --no-deps -e .
# PyAV decodes compressed audio formats, such as M4A, without a system FFmpeg.
uv pip install --python .venv/bin/python --no-deps av==19.0.2
# vLLM requires OpenCV, which NeMo's dependency settings exclude.
uv pip install --python .venv/bin/python --no-deps opencv-python-headless==5.0.0.93
source .venv/bin/activate
hf download nvidia/NVIDIA-Nemotron-3.5-Transcribe-30B-A4B-FP8 --local-dir ./NVIDIA-Nemotron-3.5-Transcribe-30B-A4B-FP8
NeMo Speechはmainブランチを、モデルは最新版を取得する手順になっています。
今回実行したときのバージョンは次のとおりです。
| 対象 | バージョン |
|---|---|
| NeMo Speech | mainブランチのコミット079e48770098a4cffcf542a4bc974cafc84502a3 |
| vLLM | 0.32.0 |
| モデル(FP8版) | revision 2b6209f89bec0da576d69183bfdabb3b6c05ade2 |
なお、仮想環境は--python 3.13で作りますが、実際の環境はPython 3.12.16になりました。
インストールのログを見ると、uv venvの時点ではPython 3.13.18の環境が作られ、次のuv syncでUsing CPython 3.12.16、Removed virtual environment at: .venvと表示されて、3.12の環境に作り直されています。
NeMo Speechのリポジトリに含まれる.python-version(3.12)に、uv syncが合わせるためです。
動作には影響ありませんでした。
vLLMのサーバーを起動する
モデルカードのFP8版の起動コマンド(RTX PRO 6000向け)に、L40S向けの変更を加えたものが次のコマンドです。
リポジトリのscripts/serve_nemotron_transcribe.shで、変更した箇所には「変更」とコメントを付けています。
それ以外はモデルカードのままです。
export PATH=/usr/local/cuda/bin:$PATHは、FlashInferのJITコンパイルのためにnvccをPATHに置くよう、モデルカードが例として示している行です。
モデルカードはCUDA 13のnvccを求めていますが、今回の構成では、Brevのイメージに入っているCUDA 12.6(/usr/local/cuda)のままで動きました。
起動時のログでは、モデルカードが確認を求めている項目(FP8の音声エンコーダが128層、KVキャッシュがfp8_e4m3)を確認できました。
モデルの重みは31.08GiBで、起動後のVRAMの使用量は約37GBです。
モデルカードの起動コマンドからの変更点
変更した3か所と、その理由は次のとおりです。
| 変更した部分 | 理由 |
|---|---|
変更1:LD_LIBRARY_PATHに/usr/local/cuda-13.0/compatを追加 |
前の手順で入れたforward compatibilityのライブラリを使うため |
変更2:--mamba-backendをflashinferからtritonに変更 |
FlashInferのMamba層用のカーネル(ReplaySSM用)に、Hopper(sm_90)以降のGPUでしか使えない命令が、GPUの世代による分岐なしで書かれている。L40SはAda世代(sm_89)なので、最初のリクエストでコンパイルに失敗する[3] |
変更3:MTPの投機的デコード(--speculative-config)を削除 |
MambaのバックエンドをtritonにしたままMTPを残すと、vLLMが起動時にMamba2 ReplaySSM speculative decoding requires --mamba-backend flashinferというエラーで拒否するため |
MTPは生成を速くするための仕組みなので、これを外した今回の速度は、モデルカードが想定する速度より遅くなっていると考えられます。
検証の実行
ここからは、実際に検証を実行した手順です。
スクリプトは手元で書き、Brevのインスタンスへ転送して実行しました。
以降のコマンドは、Brevのインスタンス上で、検証用リポジトリのディレクトリから実行しています。
Pythonは、以前のASR比較の記事と同じ手順(scripts/setup_brev.sh)で作った評価用の仮想環境を使います。
source work/.venv/bin/activate
音声とプロンプトの送り方
Nemotron 3.5 Transcribeへの指示は、APIの専用のパラメータではなく、チャット形式のユーザーメッセージのテキストとして渡します。
音声も同じユーザーメッセージに、base64でエンコードしたWAVとして入れます。
専門用語リストも、このテキストの中にContext terms:に続けて書くだけです。
検証用のスクリプト(scripts/run_nemotron_transcribe_vllm.py)で、vLLMのサーバーに送るリクエストを組み立てている部分は次のとおりです。
user_promptに指示(専門用語リストを含む)が入り、音声はaudio_urlにbase64で入ります。
システムプロンプトは、モデルカードの推奨どおり空にしています。
このリクエストを、vLLMのOpenAI互換API(/v1/chat/completions)にPOSTしています。
OpenAI互換のAPIなので、OpenAIのPython SDKでも同じ内容を送れます。
スクリプトは、音声のリスト(マニフェスト)を読み、1件ずつこのリクエストを送って、認識結果を正解と並べて保存します。
音声データの準備
FLEURSの日本語と英語のテストセットをHugging Faceからダウンロードし、16kHzのWAVと、音声のパスと正解の文字列を並べたマニフェストを作ります。
英語は、英語の音声→日本語の翻訳を評価するためだけに使います。
for lang in ja_jp en_us; do
python scripts/prepare_fleurs.py --config $lang \
--audio-dir work/fleurs-$lang-test/audio \
--manifest manifests/fleurs-$lang-test.jsonl \
--metadata manifests/fleurs-$lang-test.metadata.json
done
{"manifest": "manifests/fleurs-ja_jp-test.jsonl", "files": 650}
{"manifest": "manifests/fleurs-en_us-test.jsonl", "files": 647}
マニフェストは、1行が1件の音声を表すJSON Linesです(一部の項目と、正解の文字列の途中を省略しています)。
{"sample_id": "ja_jp-test-0632-id-01936", "fleurs_id": 1936, "audio_filepath": "/home/ubuntu/workspace/asr-benchmark/work/fleurs-ja_jp-test/audio/ja_jp-test-0632-id-01936.wav", "duration_sec": 28.2, "reference": "ペリー氏は「テキサスに戻って、今夜のコーカスの結果を見極めし、…」と述べました。"}
専門用語の録音60文も、同じ形式のマニフェスト(data/discovery/discovery_manifest.jsonl)にしています。
{"sample_id": "D001", "audio_filepath": "../../work/recordings/discovery/D001.wav", "duration_sec": 10.579625, "reference": "Nemotron 3.5 ASRを使って日本語音声を認識します。", "target_term": "Nemotron", "role": "discovery"}
サーバーをバックグラウンドで起動する
実行環境の構築で示した起動コマンド(scripts/serve_nemotron_transcribe.sh)を、バックグラウンドで起動します。
nohup bash scripts/serve_nemotron_transcribe.sh > server.log 2>&1 &
起動の完了までは約2分かかりました。
APIが応答すれば、起動は完了しています。
curl -s http://127.0.0.1:8000/v1/models
{"object":"list","data":[{"id":"nvidia/NVIDIA-Nemotron-3.5-Transcribe-30B-A4B-FP8","object":"model", ...
認識精度の測定
モデルとプロンプトの設定は、YAMLファイル(configs/nemotron-3.5-transcribe-fp8-vllm.yaml)に書きました。
プロンプトは、モデルカードがFLEURSの評価に使ったものです。
以前のASR比較の記事と同じrun_matrix.pyから、この設定で650件を1件ずつ認識します。
python scripts/run_matrix.py --matrix configs/matrix-transcribe.yaml \
--only nemotron-3.5-transcribe-fp8-vllm --batch-sizes 1 --repeats 1 \
--output-dir results/accuracy --status-dir results/status-accuracy
run: nemotron-3.5-transcribe-fp8-vllm-bs1-run1
results/accuracy/20261113T020901-nemotron-3.5-transcribe-fp8-vllm-bs1-run1.meta.json
正規化CERは、以前のASR比較の記事と同じ正規化と計算方法(scripts/calculate_cer.py)で、認識が終わった時点で計算されます。
出力されたメタデータの一部は次のとおりです。
{
"model_id": "nemotron-3.5-transcribe-fp8-vllm",
"total_files": 650,
"finish_reason_length": 0,
"empty_hypotheses": 0,
"accuracy": {"normalized_cer": 0.04180960548885077, "files": 650},
"latency": {"mean_sec": 0.4537, "p50_sec": 0.4382, "p95_sec": 0.6493}
}
出力の長さの上限に達した件数(finish_reason_length)と、空の出力(empty_hypotheses)はどちらも0件でした。
プロンプトを変えた実行
この検証の中心は、プロンプトだけを変えて結果を比べることです。
比べる条件は、条件ごとに音声のマニフェストとプロンプトを1つの設定ファイル(configs/prompt-probes.yaml)にまとめました。
条件は次の8つです。
| 条件名 | 観点 | 音声 | プロンプトの内容 |
|---|---|---|---|
terms_verbatim |
専門用語リスト | 録音60文 | 逐語的に書き起こす指示(モデルカードの推奨)。専門用語リストなし |
terms_context |
専門用語リスト | 録音60文 | 文脈ASRの指示(モデルカードの推奨)と、専門用語リスト25語 |
terms_verbatim_context |
専門用語リスト | 録音60文 | terms_verbatimの末尾に、専門用語リストだけを足したもの |
fleurs_numbers_written |
表記の指示 | FLEURSの日本語 | 数字は標準的な書き言葉で(モデルカードがFLEURSの評価に使ったプロンプト) |
fleurs_numbers_spoken |
表記の指示 | FLEURSの日本語 | 数字は読みのとおりに |
fleurs_no_punctuation |
表記の指示 | FLEURSの日本語 | 句読点を付けない |
st_ja_to_en |
音声からの直接翻訳 | FLEURSの日本語 | 英語に翻訳する |
st_en_to_ja |
音声からの直接翻訳 | FLEURSの英語 | 日本語に翻訳する |
設定ファイルの全文です。
専門用語リストは、プロンプトのContext terms:のあとに、カンマ区切りで並べています。
設定ファイルの条件を順に実行するスクリプト(scripts/run_prompt_probe.py)は、リクエストを1件ずつ送り、条件ごとに認識結果をJSON Linesで保存します。
python scripts/run_prompt_probe.py \
--config configs/nemotron-3.5-transcribe-fp8-vllm.yaml \
--probes configs/prompt-probes.yaml \
--output-dir results/probes
probe: terms_verbatim (60 files)
probe: terms_context (60 files)
probe: terms_verbatim_context (60 files)
probe: fleurs_numbers_written (650 files)
probe: fleurs_numbers_spoken (650 files)
probe: fleurs_no_punctuation (650 files)
probe: st_ja_to_en (650 files)
probe: st_en_to_ja (647 files)
採点
保存した認識結果を、観点ごとのスクリプトで採点しました。
専門用語の認識精度は、以前のファインチューニングの記事の評価スクリプトで計算します。
python scripts/evaluate_term_recognition.py \
--sentences data/discovery/discovery_sentences.csv \
--predictions results/probes/terms_context.jsonl \
--details results/probes/terms_context-term-details.csv \
--summary results/probes/terms_context-term-summary.json
{
"sentences": 60,
"target_sentences": 54,
"strict_hits": 36,
"strict_recall": 0.6666666666666666,
"negative_controls": 6,
"controls_with_target_insertion": 0
}
用語を含む54文のうち36文で正しく書けており(66.7%)、対照の6文に用語が入り込んだ文は0件という結果です。
表記の指示は、数字や句読点を含む出力の件数を数えるスクリプトで集計します。
python scripts/analyze_format_probes.py \
results/probes/fleurs_numbers_written.jsonl \
results/probes/fleurs_numbers_spoken.jsonl \
results/probes/fleurs_no_punctuation.jsonl \
--output results/probes/format-summary.json
fleurs_numbers_written {'files': 650, ..., 'outputs_with_digits': 162, 'outputs_with_kanji_numerals': 99, 'outputs_without_punctuation': 0}
fleurs_numbers_spoken {'files': 650, ..., 'outputs_with_digits': 152, 'outputs_with_kanji_numerals': 115, 'outputs_without_punctuation': 0}
fleurs_no_punctuation {'files': 650, ..., 'outputs_with_digits': 72, 'outputs_with_kanji_numerals': 183, 'outputs_without_punctuation': 649}
翻訳は、同じ文の他言語の書き起こしを正解の訳として、sacreBLEUでBLEUとchrFを計算します。
FLEURSでは同じ文に同じfleurs_idが付いているので、これで訳文と正解の訳を対応づけています(scripts/score_translation.py)。
python scripts/score_translation.py --predictions results/probes/st_ja_to_en.jsonl \
--reference-manifest manifests/fleurs-en_us-test.jsonl --target-lang en \
--output results/probes/st_ja_to_en-score.json
python scripts/score_translation.py --predictions results/probes/st_en_to_ja.jsonl \
--reference-manifest manifests/fleurs-ja_jp-test.jsonl --target-lang ja \
--output results/probes/st_en_to_ja-score.json
st_ja_to_en.jsonl: BLEU 22.82 chrF 53.85 (650/650)
st_en_to_ja.jsonl: BLEU 30.33 chrF 37.56 (592/647)
括弧内は、採点できた件数と全体の件数です。
英語の音声のうち55件は、同じfleurs_idの日本語の書き起こしがテストセットになかったため、採点から外れています。
データの準備から採点までは、scripts/brev/run_transcribe_all.shで通して実行できるようにしています。
結果
専門用語リストによる効果
以前のファインチューニングの記事では、NVIDIAの製品名などの専門用語を含む日本語の文を自分で読み上げて録音し、Nemotron 3.5 ASR(0.6B)で認識しました。
今回は、その録音60文(専門用語を含む54文と、用語を含まない対照の6文)を、Nemotron 3.5 Transcribeで認識しました。
比べたのは、設定ファイルの次の3つの条件です(プロンプトの全文は「プロンプトを変えた実行」の節を参照してください)。
| 条件 | 設定ファイルの条件名 | プロンプト |
|---|---|---|
| 専門用語リストなし | terms_verbatim |
逐語的に書き起こす指示 |
| 専門用語リストあり | terms_context |
文脈ASRの指示と、Context terms:に続けて専門用語リスト25語 |
| 専門用語リストなしの指示文+リスト | terms_verbatim_context |
1つ目の指示の末尾に、専門用語リストだけを足したもの |
3つ目は、指示文の書き方と専門用語リストのどちらが効いているのかを切り分けるための条件です。
専門用語リストに並べた25語は、以前の記事でPhrase Boostingに使った用語のリストと同じです[4]。
判定には、以前の記事と同じスクリプト(scripts/evaluate_term_recognition.py)を使いました。
認識結果と用語の両方をUnicodeで正規化(NFKC)して大文字と小文字をそろえ、用語の表記が認識結果の中にそのまま含まれていれば正解としています。
読み方が合っていても、カタカナで書かれた場合(「Triton」が「トリトン」になった場合など)は不正解です。
専門用語の認識精度(用語が正しい表記で含まれていた文の割合)は次のとおりです。
上の3行は、以前の記事の値です。
| 構成 | 専門用語の認識精度 |
|---|---|
| Nemotron 3.5 ASR 0.6B | 9.3% |
| Nemotron 3.5 ASR 0.6B+Phrase Boosting | 最大9.3% |
| Nemotron 3.5 ASR 0.6B+ファインチューニング(100 step) | 38.9% |
| Nemotron 3.5 Transcribe(専門用語リストなし) | 31.5% |
| Nemotron 3.5 Transcribe(専門用語リストあり) | 66.7% |
| Nemotron 3.5 Transcribe(専門用語リストなしの指示文+リスト) | 68.5% |
プロンプトに用語を並べるだけで、ファインチューニングした0.6Bのモデルを大きく上回りました。
専門用語リストなしの指示文に用語のリストだけを足した条件でも68.5%だったので、効いているのは指示文の書き方ではなく、用語のリストのほうです。
専門用語リストで直った例は次のとおりです。
| 正解 | 専門用語リストなし | 専門用語リストあり |
|---|---|---|
| NeMoを使って音声認識モデルを学習します。 | メモを使って音声認識モデルを学習します。 | NeMoを使って音声認識モデルを学習します。 |
| 学習にはNVIDIA NeMo Frameworkを利用しました。 | 学習にはNVIDIAネモフレームワークを利用しました。 | 学習にはNVIDIA NeMoフレームワークを利用しました。 |
専門用語リストを入れると、関係のない文にまで用語を書き込んでしまう心配があります。
対照の6文には、用語と紛らわしい一般語(「会議のメモ」「黄色いカナリア」「ローツェの山頂」など)を入れてありますが、専門用語リストを入れても誤って用語に置き換わった文はありませんでした。
用語を含む文で、別の用語が入り込んだのは1件だけです。
専門用語リストに入れていない「CTC」が、リストにある「CER」に置き換わりました。
正しく書けなかった18件の多くは、専門用語リストを渡してもカタカナで書かれたものでした。
| 正解の用語 | 認識結果 |
|---|---|
| TensorRT | テンソルRT |
| Triton | トリトン |
| NVLink | NVリンク |
| Lhotse | ローツェ |
| FLEURS | フルール |
| SpecAugment | スペックオーギュメント |
読み方として間違ってはいないので、「英字で書く」と明示する指示を足せば改善する可能性がありますが、今回は試していません。
表記の指示
FLEURSの音声で、表記に関する指示を変えたときの出力を比べました。
| 設定ファイルの条件名 | 指示の違い | 句読点のない出力 |
|---|---|---|
fleurs_numbers_written |
numbers in their standard written form | 0件 |
fleurs_numbers_spoken |
numbers as spoken words | 0件 |
fleurs_no_punctuation |
no punctuation | 649件 |
句読点なしの指示ははっきり効き、650件中649件が句読点のない出力(「、」「。」などの句読点を1つも含まない出力)になりました。
数字の表記の指示は、指示どおりの方向に効きましたが、効き方は弱いものでした。
算用数字と漢数字を含む出力の件数は次のとおりです。
| 指示 | 算用数字を含む出力 | 漢数字を含む出力 |
|---|---|---|
| standard written form(標準的な書き言葉で) | 162件 | 99件 |
| as spoken words(読みのとおりに) | 152件 | 115件 |
読みのとおりにと指示すると、算用数字が減って漢数字が増えています。
はっきり変わった例は次のとおりです。
| 指示 | 認識結果 |
|---|---|
| standard written form | ロランドメンドーサはM16ライフルで観光客に発砲しました。 |
| as spoken words | ロランドメンドーサはエム十六ライフルで観光客に発砲しました。 |
ただし、650件中410件は2つの指示で出力がまったく同じで、「80キロメートル」のように、どちらの指示でも算用数字のままの例も多くありました。
日本語で数字の表記を確実にそろえたい場合は、プロンプトだけに頼らず、後処理と組み合わせるのが確実です。
音声からの直接翻訳
従来は、音声を翻訳するには、ASRで文字起こししてから翻訳モデルにかける2段の構成が一般的でした。
Nemotron 3.5 Transcribeは、音声から訳文を直接出力できます。
FLEURSは同じ文を各言語で読み上げているので、日本語の音声に対しては、同じ文の英語の書き起こしを正解の訳として使えます。
これを使って、日本語の音声→英語、英語の音声→日本語の翻訳を評価しました。
プロンプトは、モデルカードの推奨どおりPlease translate the given speech to English.(またはJapanese)です(設定ファイルのst_ja_to_enとst_en_to_ja)。
| 方向 | BLEU | chrF | モデルカードのBLEU(BF16) |
|---|---|---|---|
| 日本語→英語 | 22.82 | 53.85 | 23.00 |
| 英語→日本語 | 30.33 | 37.56 | 29.73 |
BLEUはsacreBLEUで計算し、日本語の訳はMeCabで単語に分けています[5]。
どちらの方向も、モデルカードの値とほぼ同じ水準でした。
訳の例です。
| 入力 | 翻訳結果 |
|---|---|
| (日本語の音声)また、北側に行くなら世界的に有名なマリア像の聖地であるファティマの聖母の聖域(神社)を訪れましょう。 | Also, if you go north, visit the Church of Our Lady in Fatima, a world-famous pilgrimage site of Marian apparitions. |
| (英語の音声)However, due to the slow communication channels, styles in the west could lag behind by 25 to 30 year. | しかし、通信手段が遅かったため、西洋のスタイルは25〜30年ほど遅れをとっていた。 |
| (英語の音声)All nouns, alongside the word Sie for you, always begin with a capital letter, even in the middle of a sentence. | 世界の安全のために尽力するすべての名詞は、文の途中であっても常に大文字で始まります。 |
おおむね自然な訳ですが、3つ目の例では、ドイツ語の「Sie」を説明する部分が「世界の安全のために尽力する」という原文にない語句になっています。
聞き慣れない語を含む音声では、このような誤訳が起こりうるので注意が必要です。
認識精度
FLEURSの日本語650件での正規化CER(句読点や表記の揺れの一部をそろえてから計算した文字誤り率)は次のとおりです。
(Nemotron 3.5 Transcribe以外は、以前の記事の値です。)
| 構成 | 正規化CER |
|---|---|
| Nemotron 3.5 Transcribe(FP8、vLLM) | 4.18% |
| Whisper large-v3 | 4.49% |
| Whisper large-v3-turbo | 4.81% |
| Parakeet TDT 0.6B Japanese | 5.94% |
| Kotoba-Whisper v2.2 | 6.92% |
| ReazonSpeech K2 v2 | 9.40% |
| Nemotron 3.5 ASR 0.6B(Transformers、offline) | 13.31% |
Nemotron 3.5 Transcribeは、比べたモデルの中で最もCERが低くなりました。
モデルカードのBF16版の値(4.42%)とも近い値です[6]。
ただし、学習データとの重なりの節で書いたとおり、FLEURSは学習データに含まれるため、この差をそのまま汎化性能の差とは読めません。
認識結果を見ると、誤りの多くは句読点や括弧の扱い、助詞1文字程度でした。
| 文字列 | |
|---|---|
| 正解 | また、北側に行くなら世界的に有名なマリア像の聖地であるファティマの聖母の聖域(神社)を訪れましょう。 |
| 認識結果 | また、北側に行くなら、世界的に有名なマリア像の聖地であるファティマの聖母の聖域神社を訪れましょう。 |
処理時間(参考)
ほかのモデルとは比べず、参考として、L40S(MTPなし)で1件ずつ処理したときの時間を示します。
1件ごとに、リクエストを送ってから結果が返るまでの時間を測りました。
| 項目 | 値 |
|---|---|
| 音声の長さ(650件の平均) | 13.1秒 |
| 処理時間の中央値 | 0.44秒 |
| 処理時間の95パーセンタイル | 0.65秒 |
音声の長さの約1/30の時間で処理できているので、録音済みのファイルを文字起こしする用途なら、待ち時間が問題になることは少ないと思います。
処理時間の内訳を、生成したトークンの数との関係から見積もると、1件あたり約0.10秒の固定分と、1トークンあたり約8.4ミリ秒の生成時間に分かれました。
1件で平均41.9トークンを生成しているので、処理時間の約8割は、文字を1トークンずつ生成する部分です。
MTPは、この1トークンずつの生成を速くする仕組みなので、MTPを使えるGPUでは、この時間はさらに短くなると考えられます。
なお、Nemotron 3.5 Transcribeはストリーミングに対応していないため、話しながら文字にしたい用途には使えません。
手元のMacでは動くか
Nemotron 3.5 Transcribeは、NVIDIAのローカル推論用ランタイムであるNeMo-Speech.cppでも動かせます。
macOS(Apple Silicon、Metal)向けのビルド済みのバイナリも公開されています。
ただし、量子化したモデルでも、最も小さいもの(コミュニティが公開した2bit相当の版)で本体が13.6GB、音声エンコーダが1.7GBあります。
手元のMac(M4、メモリ16GB)では、GPUに割り当てられるメモリが既定で物理メモリの約2/3なので、全体を載せることはできません。
そのため今回は試していません。
この量子化版を公開しているAtomicChatの説明では、24GBのMacには約15.6GBの版、32GBのMacには約22.6GBの版を勧めています。Macで動かすなら、24GB以上のメモリが目安になりそうです。
まとめ
NVIDIAのNemotron 3.5 TranscribeをL40Sで動かし、プロンプトによる制御が日本語でどこまで効くのかを確かめました。
Nemotron 3.5 Transcribeの一番の特徴は、Formatting:やContext terms:のようなラベルを付けた指示をユーザーメッセージに書くだけで、文字起こしのやり方を変えられることです。
その中でも最も効果が大きかったのは、Context terms:で渡す専門用語リストです。
用語のリストをプロンプトに入れるだけで、専門用語の認識精度は31.5%から66.7%に上がり、以前の記事でファインチューニングした0.6Bのモデル(38.9%)を大きく上回りました。
ファインチューニングでは、用語を含む文を録音して学習データを作る手間がかかります。
用語のリストを書くだけでそれ以上の結果になるので、用語の多い社内会議などの文字起こしでは、最初に試す価値があると思います。
一方で、指示がすべて日本語で効くわけではありません。
句読点なしの指示ははっきり効きましたが、数字の表記の指示は効き方が弱かったので、表記を確実にそろえたい場合は後処理と組み合わせるのが確実です。
翻訳も、指示を変えるだけで音声から直接行えました。
BLEUはモデルカードの値とほぼ同じで、ASRと翻訳モデルを2段で組まなくても、日本語と英語の翻訳を1つのモデルで済ませられます。
認識精度もFLEURSの日本語で最良でした。
FLEURSが学習データに含まれる点は割り引く必要がありますが、録音済みの音声の文字起こしでは、有力な選択肢になりそうです。
ただし、ストリーミングには対応していない点と、L40SのようなAda世代のGPUではMTPを使えない点には注意が必要です。
本記事がご参考になれば幸いです。
参考リンク
- Nemotron 3.5 TranscribeとGranary v2の紹介(Hugging Face Blog)
- nvidia/NVIDIA-Nemotron-3.5-Transcribe-30B-A4B(Hugging Face)
- nvidia/NVIDIA-Nemotron-3.5-Transcribe-30B-A4B-FP8(Hugging Face)
- NVIDIA-NeMo/Speech(GitHub)
- NVIDIA/NeMo-Speech.cpp(GitHub)
- google/fleurs(Hugging Face)
- NVIDIA L40Sで日本語対応ASRモデルを比較してみた
- Nemotron 3.5 ASRを日本語音声でファインチューニングしてみた
ドライバが古いと、PyTorchの初期化時に
RuntimeError: The NVIDIA driver on your system is too old (found version 12070).というエラーになります。 ↩︎forward compatibilityの詳細は、NVIDIAのCUDA Compatibilityのドキュメントを参照してください。 ↩︎
エラーは
ptxas ... checkpointing_ssu ...; error : Instruction 'griddepcontrol' requires .target sm_90 or higherです。起動は成功し、最初のリクエストを送ったときにこのカーネルのコンパイルが走って失敗します。 ↩︎台本の対象語のうちCTCとDGXの2語は、以前の記事のリストに含まれていなかったため、今回も専門用語リストに入れていません。 ↩︎
モデルカードには単語の分け方が書かれていないため、値の比較は参考程度です。また、英語→日本語は、日本語の書き起こしが見つかった592件で計算しています。 ↩︎
モデルカードとは正規化の方法が異なる可能性があるため、0.2ポイント程度の差には意味を持たせていません。 ↩︎







