NVIDIA Nemotron 3 DiarizationをRTX 3060で試す:導入手順と日本語2話者の検証結果

社内の検証マシン(GeForce RTX 3060 VRAM 12 GiB)で、NVIDIA Nemotron 3 Diarizationのインストールと日本語音声の動作テストを行いました。
CUDA推論が動作し、交互に登場する2人の声に同じ話者ラベルを付け続けることを確認できました。
一方、低遅延のストリーミング処理では一部の発話区間が短く検出され、強く重ねた音声では2人が同時に話している区間を検出できませんでした。本稿では、公式仕様、導入に使ったコマンド、テスト音声の作り方、実測結果を整理します。
Nemotron 3 Diarizationは何をするモデルか
話者ダイアライゼーションは、音声の中で「いつ、どの話者が話したか」を推定する処理です。Nemotron 3 Diarizationは、その区間に匿名の話者ラベルを付けます。発言内容を文章にするには、別途ASR(音声認識)と組み合わせます。話者の実名を特定したり、声を別々の音声ファイルに分離したりする処理も、今回の出力には含みません。出典:NVIDIAの公式解説記事。
| 公式情報 | 内容 |
|---|---|
| 公開日 | 2026年9月23日 |
| モデルID | nvidia/Nemotron-3-Diarization |
| 規模 | 約1億パラメータ(100M) |
| 話者数・処理方式 | 最大8話者、録音ファイル処理とストリーミングに対応 |
| 入力・出力 | 16 kHz・モノラル音声。話者ごとの活動確率を、話者ラベルと開始・終了時刻に変換できる |
| ライセンス表記 | OpenMDW License Agreement 1.1 |
仕様とライセンス表記はNVIDIA公式モデルカードを参照しました。最大8話者は製品の対応範囲であり、今回実際に確認したのは2話者です。
公式モデルカードにはNeMoとTransformersを使う方法が案内されています。DQNでは、独立したPython仮想環境にTransformersを入れ、ローカル保存したSafetensors形式の重みを読み込む構成を採用しました。
今回使用した環境
| 項目 | 検証時の構成 |
|---|---|
| 検証機 | DQN |
| OS | Ubuntu 24.04.4 LTS |
| GPU | NVIDIA GeForce RTX 3060、VRAM 12,288 MiB(12 GiB) |
| NVIDIAドライバー | 580.173.02 |
| Python | 3.12.3 |
| PyTorch / CUDAランタイム | 2.11.0+cu128 / 12.8 |
| Transformers | 5.18.0.dev0 |
| 推論精度 | FP32 |
| モデルの保存容量 | 約379 MiB |
| Python仮想環境の容量 | 約7.3 GiB(CUDA関連ライブラリを含む) |
Transformersとモデルは、後から同じ版を確認できるようコミット/revisionを固定しました。その他のPythonパッケージの版も、検証記録の packages.txt に保存しています。
Transformers commit: c320b44962f99e47440cd07e3ed42a3d85023b2a
Model revision: f667ed73aee57d40cc39428eb768b4fd87a0a29e
インストール方法とコマンド
1. 前提ツールとGPUを確認する
以下はUbuntuでの導入例です。Python 3.12、venv、Git、NVIDIAドライバーが使えることを確認します。DQNでは既存のGPUドライバーを使いました。新しい環境で不足している場合のOSパッケージ準備例は次のとおりです。
sudo apt-get update
sudo apt-get install -y python3.12-venv git libsndfile1 ffmpeg
nvidia-smi
2. 独立したPython環境を作る
公式モデルカードはTransformersのソースからの導入を案内しています。今回の検証では開発版の更新による差を避けるため、動作確認に使ったコミットを指定しました。以下は検証環境のセットアップ記録に基づくコマンドです。
mkdir -p ~/projects/nemotron3-diarization
cd ~/projects/nemotron3-diarization
python3.12 -m venv .venv
.venv/bin/python -m pip install uv
.venv/bin/uv pip install --python .venv/bin/python \
'torch==2.11.0+cu128' \
--index-url https://download.pytorch.org/whl/cu128
.venv/bin/uv pip install --python .venv/bin/python \
'git+https://github.com/huggingface/transformers.git@c320b44962f99e47440cd07e3ed42a3d85023b2a' \
numpy scipy soundfile librosa accelerate
このコマンドではPyTorchとTransformersを固定しています。依存パッケージすべてを固定したロックファイルではないため、将来の実行では依存関係に差が出る可能性があります。
3. モデルをダウンロードする
.venv/bin/hf download nvidia/Nemotron-3-Diarization \
--revision f667ed73aee57d40cc39428eb768b4fd87a0a29e \
--local-dir model \
--include config.json processor_config.json model.safetensors \
README.md explainability.md diarization_evaluation.md
.venv/bin/python -c "import torch; print(torch.__version__, torch.version.cuda); assert torch.cuda.is_available(); print(torch.cuda.get_device_name(0))"
最後のコマンドでCUDAが利用できることを確認します。モデル取得後は、保存した model/ を使って推論できます。
4. WAVファイルを処理する最小実行例
次のコードを作業フォルダの diarize_minimal.py として保存します。今回の検証スクリプトから入出力に必要な処理を抜き出して整理した例です。ステレオ音声はモノラル化し、必要に応じて16 kHzに変換します。GPUとFP32を明示し、話者番号・開始時刻・終了時刻をJSONで表示します。
from pathlib import Path
from math import gcd
import json
import sys
import soundfile as sf
import torch
from scipy.signal import resample_poly
from transformers import AutoModelForAudioFrameClassification, AutoProcessor
if not torch.cuda.is_available():
raise RuntimeError("CUDA GPU is required")
model_dir = Path(__file__).resolve().parent / "model"
processor = AutoProcessor.from_pretrained(model_dir, local_files_only=True)
model = AutoModelForAudioFrameClassification.from_pretrained(
model_dir, local_files_only=True, dtype=torch.float32
).to("cuda").eval()
audio, rate = sf.read(sys.argv[1], dtype="float32", always_2d=True)
audio = audio.mean(axis=1)
target_rate = processor.feature_extractor.sampling_rate
if rate != target_rate:
divisor = gcd(rate, target_rate)
audio = resample_poly(audio, target_rate // divisor, rate // divisor)
features = processor(audio, sampling_rate=target_rate).to(
model.device, dtype=model.dtype
)
with torch.inference_mode():
scores = model(**features).logits
segments = processor.extract_speaker_dict(scores, features.attention_mask)[0]
result = [
{"speaker": int(s["Speaker"]), "start": float(s["Start"]), "end": float(s["End"])}
for s in segments
]
print(json.dumps(result, ensure_ascii=False, indent=2))
.venv/bin/python diarize_minimal.py /path/to/meeting.wav
この最小例は録音ファイルの入出力確認用です。後述の処理時間は、別の計測用スクリプトでウォームアップとCUDA同期を行って測った値です。長時間音声のチャンク処理やストリーミングAPIは、使用コミットのTransformers公式ドキュメントを参照してください。
テスト対象:公開の日本語音声2本
Google FLEURSの日本語データ ja_jp、dev から、同じ文章を異なる2人が読んだ録音を選びました。データセットの文IDは1526です。男女の表記はデータセットのメタデータに基づきます。出典:Google FLEURS。
| 検証用ラベル | 元の音声ファイル | 長さ | メタデータ |
|---|---|---|---|
| A | 6390238109064655574.wav | 10.20秒 | MALE |
| B | 17467746604232614534.wav | 11.88秒 | FEMALE |
読み上げ文は「冬に北極や南極を訪れると、太陽が地平線から昇らない『極夜』を体験することができます。」です。
音声はGoogle FLEURS(CC BY 4.0)に基づき利用しました。加工内容は、同じ録音の反復、無音の挿入、連結または重ね合わせ、クリッピングを避ける全体ゲイン調整、PCM16への変換です。帰属表示と加工内容は samples/ATTRIBUTION.txt に保存しました。CC BY 4.0。
使用したデータセットrevisionは 70bb2e84b976b7e960aa89f1c648e09c59f894dd。取得元URL、音声ファイルのSHA-256、配置時刻は samples/manifest.json に記録しています。
| テスト音声 | 組み立て方 | 全体の長さ |
|---|---|---|
japanese_alternating.wav | A→B→A→B。元録音の間に0.7秒の無音を挿入 | 47.26秒 |
japanese_overlap.wav | 同じ順序で、隣り合う元録音の配置窓を2秒ずつ重ねる | 39.16秒 |
japanese_overlap_strong.wav | 同じ順序で、配置窓を6秒ずつ重ねる | 27.16秒 |
各音声には先頭と末尾にも0.5秒の無音を置いています。同じ2録音を2回ずつ使った人工的なテストであり、自然な会話の録音ではありません。また、元録音そのものに無音があるため、「録音を6秒重ねた」と「実際の発声が6秒重なった」は同じ意味ではありません。A/Bのラベルや文章はモデルには渡していません。
検証時の実行方法
DQNには、試験音声を組み立てる prepare_samples.py と、計測・結果保存を行う run_diarization.py を用意しました。これらは今回作成した検証用スクリプトで、Nemotronの標準CLIではありません。既存スクリプトを使った再確認は、作業フォルダで次のように実行できます。
cd ~/projects/nemotron3-diarization
# 保存済みサンプルを録音ファイルとして処理
.venv/bin/python run_diarization.py \
samples/japanese_alternating.wav samples/japanese_overlap.wav \
--mode offline --output results/recheck/offline
# 同じ交互発話音声をチャンクに分けて処理
.venv/bin/python run_diarization.py samples/japanese_alternating.wav \
--mode streaming --output results/recheck/streaming
# 強く重ねた音声を処理
.venv/bin/python run_diarization.py samples/japanese_overlap_strong.wav \
--mode offline --output results/recheck/overlap_strong
スクリプトは話者区間をJSON・CSV・RTTMで保存し、モデル版、処理時間、GPUメモリの観測値も記録します。ストリーミングは保存済みファイルをチャンクに分割して順番に処理する試験で、マイクを使ったリアルタイム通話の試験ではありません。
交互発話と2秒重ね合わせの計測では、既存のLLMサービスOrnithを一時停止してGPUを空け、終了後に復帰させました。6秒重ね合わせの追加確認はOrnith復帰後に行っており、同じGPU負荷条件ではありません。上記の個別実行コマンドはサービスを停止しないため、利用時はGPUの空き容量を確認します。
結果:2話者の追跡はできたが、同時発話には課題
| 入力・方式 | 音声長 | 処理時間 | 検出ラベル数 | 観察結果 |
|---|---|---|---|---|
| 交互発話・録音ファイル処理 | 47.26秒 | 0.166秒 | 2 | A→0、B→1を再登場後も維持 |
| 交互発話・ストリーミング | 47.26秒 | 1.290秒 | 2 | ラベルは維持。最初のBの検出区間が短い |
| 2秒重ね合わせ・録音ファイル処理 | 39.16秒 | 0.062秒 | 2 | 2話者は追跡。実発声の重なりの評価としては不十分 |
| 6秒重ね合わせ・録音ファイル処理 | 27.16秒 | 0.122秒 | 2 | 2ラベルは出力。同時に2話者を検出した区間は0秒 |
処理時間は各条件1回の簡易測定です。 ファイルの読み込み・デコード、モデル読み込み、ウォームアップを除き、特徴抽出、GPU計算、区間への後処理を含みます。計測の前後でCUDAを同期しています。平均値やばらつきは測っていません。
交互発話の録音ファイル処理では、モデル読み込みに約0.47秒、3秒音声によるウォームアップに約0.32秒かかりました。これらに加えて、Python起動とライブラリimportの時間も必要です。47.26秒の音声を約0.166秒で処理したという値を、そのままアプリ起動から完了までの時間として扱うことはできません。
交互発話では、再登場した声に同じラベルを維持
交互発話サンプルの録音ファイル処理で得られた区間は次のとおりです。元録音の配置時刻と照合すると、Aは speaker_0、Bは speaker_1 になり、同じ録音が再登場した後も対応が保たれていました。
| 開始 | 終了 | 出力ラベル | 元音声との対応 |
|---|---|---|---|
| 2.28秒 | 8.20秒 | speaker_0 | A |
| 14.03秒 | 19.37秒 | speaker_1 | B |
| 19.87秒 | 22.45秒 | speaker_1 | Bの続き |
| 25.76秒 | 31.68秒 | speaker_0 | Aの再登場 |
| 37.50秒 | 42.85秒 | speaker_1 | Bの再登場 |
| 43.35秒 | 45.94秒 | speaker_1 | Bの続き |
録音内の間によって1回の読み上げが複数区間に分かれるため、6区間の出力は6人の話者を意味しません。また、録音ファイルの配置窓のすべてで発声しているわけではありません。
ストリーミングでは最初のBの検出が短くなった
今回使用した low_latency の公式入力バッファ待ち時間は1.04秒です。ほかに very_low_latency(0.64秒)、ultra_low_latency(0.32秒)が案内されていますが、この2設定は今回試していません。これらは音声をためる時間であり、計算時間を含む全体の応答遅延ではありません。出典:Transformers公式ドキュメント。
表の1.290秒は、47.26秒分のファイルを実時間に合わせて待たずに流したときの計算時間です。47秒の会話が1秒で終わるという意味ではありません。
最初のBの発話に対応する検出区間の合計は、録音ファイル処理で7.92秒、ストリーミングで4.67秒となり、約3.25秒短くなりました。これは2つの処理方式の出力比較であり、手動アノテーションとの比較から求めた誤り時間ではありません。
強い重なりでは同時発話区間を検出できなかった
元録音の配置窓を6秒ずつ重ねた条件では、出力に2つの話者ラベルは現れましたが、2つが同時に活動すると判定された区間は0秒でした。この入力と実行設定では、重なりを含む発話を十分に捉えられなかったと考えられます。
ただし、正確な同時発話の開始・終了時刻は手作業で付与していません。また、この条件は単独話者だけの窓が不足するため、再登場時のラベル一致を調べる簡易判定は採点不能(passed: null)です。ラベルが2つ出たことだけをもって、同時発話の識別成功とは評価していません。
GPUメモリと実行ログ
Ornithを停止した交互発話などの計測では、GPU全体の使用量の最大観測値は567〜571 MiB(約0.56 GiB)でした。約0.2秒間隔の監視なので、瞬間的なピークをすべて捉えた値ではありません。PyTorchが報告した最大確保テンソル容量は約403〜409 MiBで、CUDAコンテキストなどを含むGPU全体の値とは定義が異なります。
6秒重ね合わせの追加確認では、Ornith稼働中のGPU全体使用量は10,575 MiBでした。音声推論側のPyTorch確保分は約400 MiBであり、10,575 MiBをこの音声モデル単体の必要VRAMと解釈することはできません。
開発版Transformersのimport時には、画像処理側の image_like_kwargs のdocstringに関する [ERROR] 表示が記録されました。今回の音声推論は完了し、結果ファイルも出力されています。診断表示を含むログを保存しており、導入時にこの表示が出た場合は、その後の例外や結果出力も合わせて確認する必要があります。
今回の検証で分かったことと、残る確認事項
RTX 3060 12 GiBと独立したPython環境で、Nemotron 3 Diarizationの導入、GPU推論、話者ラベル付き時刻の出力まで確認できました。日本語2話者が交互に現れる短い音声では、声とラベルの対応が保たれています。
一方、試験は同じ2録音を反復した短い人工音声に限られます。DER(話者ダイアライゼーション誤り率)や「日本語正解率」は算出していません。今回の値から、自然な会議、似た声、雑音、遠いマイク、8人の会話、長時間録音での精度を判断することはできません。
会議録や話者付き文字起こしに組み込む次の段階では、実際の利用環境の録音に発話区間の正解ラベルを付け、同時発話と短い相づちを含めて評価したいところです。ASRと組み合わせた場合も、言葉の認識精度と話者の割り当て精度をそれぞれ確認する必要があります。
参照した公式資料と検証記録
NVIDIA公式モデルカード / 検証で固定したrevisionのモデルカード / NVIDIA公式解説記事 / Transformers公式ドキュメント(使用コミット) / Google FLEURS。いずれも2026年9月24日確認。
実測結果の根拠は、検証フォルダ内の results/summary_offline.json、results/summary_streaming.json、results/overlap_strong/summary_offline.json です。音声の出典と構成は samples/manifest.json、環境の版は packages.txt と transformers-direct-url.json に保存しています。記事作成時にDQN上の結果JSONと手元のコピーのSHA-256が一致することも確認しました。
