Hugging Face のモデルをそのまま学習できる NeMo AutoModel を DGX Spark で動かしてみた

Hugging Face のモデルをそのまま学習できる NeMo AutoModel を DGX Spark で動かしてみた

NeMo AutoModel の位置付けと DGX Spark 対応の現状を整理し、公式コンテナで Qwen3-8B の LoRA と full SFT を 1 台で回しました。full SFT は 77.70 GiB で 6 時間完走し、BF16 の full SFT は 8B クラスまでが目安になりそうです。
2026.09.15

はじめに

こんにちは、クラスメソッド製造ビジネステクノロジー部の森茂です。

NVIDIA の学習ライブラリ NeMo AutoModel が、いつのまにか DGX Spark で普通に使える状態になっていました。以前 NeMo Framework を俯瞰する記事を書いたとき、AutoModel の ARM64 対応は「要検証」のままにしていたのですが、上流には DGX Spark 向けのレシピが揃い、GB10 の実機で CI まで回っています。

https://github.com/NVIDIA-NeMo/Automodel

自分はこれまで、DGX Spark でのファインチューニングに AutoModel を使ってきませんでした。Nemotron 3 Nano の日本語学習では Hugging Face の PEFT と TRL を直接使い、Nemotron 3.5 Lightning を LLM ルーターの判定役に仕立てたときは、cookbook が H100 8 枚前提だったので Megatron-Bridge をクラウドで回しています。1 台の DGX Spark で素直に使える形になったのかを確かめるのが、この記事の動機です。

https://dev.classmethod.jp/articles/dgx-spark-nvidia-nemo-framework-overview-and-index/

上の俯瞰記事(2026-04-21 時点の記事です)で △ にしていた AutoModel の行を、この記事で更新します。

この記事では、NeMo AutoModel の概要と DGX Spark 対応の現状、公式コンテナ 26.08 で Qwen3-8B の LoRA と full SFT を回した最初の収穫を紹介します。DGX Spark を 1 台持っていて、Hugging Face のモデルを手元で学習させたい人に刺さるといいなと思っています。

NeMo AutoModel は Hugging Face のモデルをそのまま学習に回す仕組み

NeMo AutoModel は、NVIDIA が公開している PyTorch ネイティブの学習ライブラリです。公式の説明を借りると「PyTorch DTensor ネイティブの SPMD な学習ライブラリで、Hugging Face のモデルを day-0 でサポートする」ものです。Hugging Face Hub にあるモデルをそのまま from_pretrained で受け取り、SFT、LoRA や QLoRA などの PEFT、知識蒸留、VLM の学習までを同じ枠組みで扱えます。学習した結果も Hugging Face 形式の safetensors で出てくるので、変換を挟まずに vLLM などの推論側へ渡せます。

NeMo と名のつくツールは増え続けているので、位置付けを先に整理しておきます。NeMo Framework の LLM 向けの部分は、役割ごとに独立したリポジトリへ分かれています。

役割 コンポーネント AutoModel との関係
データの準備 NeMo Curator、Data Designer ここで作った JSONL を AutoModel のレシピに渡す
学習・カスタマイズ NeMo AutoModel、Megatron-Bridge 同じ層の 2 本立て。HF 形式なら AutoModel、Megatron 形式なら Megatron-Bridge
強化学習 NeMo RL AutoModel と Megatron-Bridge と vLLM の上に組まれている
評価 NeMo Evaluator 学習後のモデルを OpenAI 互換 API 経由で採点する
配信 NIM、vLLM AutoModel が出した safetensors や LoRA adapter を読む

学習の層には AutoModel と Megatron-Bridge の 2 本があり、ここが一番迷いやすいところです。Megatron-Bridge は Megatron-Core ベースで、チェックポイントを Megatron の形式に変換して扱い、大規模な事前学習や深いカスタマイズに向きます。AutoModel は Hugging Face 互換のチェックポイントをそのまま扱う側で、1 GPU の LoRA から複数ノードの学習まで同じレシピの形式で書けます。自分の理解では、Hugging Face にある重みから始めて Hugging Face の形式で終わりたいなら AutoModel、Megatron の世界で学習を組みたいなら Megatron-Bridge、という切り分けです。

使い方の骨格はシンプルで、YAML のレシピ 1 枚に「どのモデルを、どのデータで、どの並列化で学習するか」を書き、automodel <recipe.yaml> --nproc-per-node N で起動します。モデルの指定は nemo_automodel.NeMoAutoModelForCausalLM.from_pretrained という Hugging Face 互換のクラスで、レシピの中身は普通の PyTorch と Hugging Face の語彙で読めます。分散学習は FSDP2 と DTensor が土台で、モデルの大きさと GPU の枚数に合わせて tensor parallel、context parallel、expert parallel を重ねる設計です。checkpoint は DCP と safetensors の両方に対応し、FP8 の学習や投機デコード用 drafter の学習もレシピの選択肢に入っています。Hugging Face 側にも AutoModel を使ったファインチューニングのドキュメントがあり、MoE モデルでは Transformers v5 比で 3.4〜3.7 倍のスループットが出たという記事を NVIDIA が公開しています。

あえて AutoModel を選ぶ理由

Hugging Face のモデルを LoRA するだけなら、PEFT と TRL を直接使う道も、Unsloth のような軽いツールもあります。自分も Nemotron 3 Nano を日本語で学習したときは PEFT と TRL を直接使いました。それでも今は AutoModel を選ぶ場面が増えていて、理由は 4 つあります。

1 つ目は、入口と出口が Hugging Face 形式のまま閉じることです。学習の入力は Hub のモデル ID かローカルのスナップショット、出力は safetensors か PEFT 形式の adapter で、別の検証では AutoModel が出した adapter を vLLM にそのまま読ませて chat completion が返ってきました。学習と配信の間で形式変換を挟まないので、試行の回数を増やしやすいですね。

2 つ目は、NVIDIA がハードウェアの面倒を見ていることです。DGX Spark の GB10 は compute capability 12.1 で、データセンター向けの Blackwell とは別物です。ここに合わせた bitsandbytes のビルドや、cuDNN が扱えない経路を避けるレシピの指定は、自分で追いかけると地味に時間を取られます。AutoModel では GB10 の実機が CI に入っていて、この手の対応がコンテナとレシピに畳み込まれた状態で届きます。

3 つ目は、1 GPU で書いたレシピがそのまま大きい環境に持っていけることです。LoRA の rank や学習率は YAML の値で、並列化の設定は distributed のブロックで独立しています。手元の 1 台で回して当たりを付けたレシピを、後からクラウドの GPU に持っていくときに書き直しが要りません。

4 つ目は、NeMo の他のツールとつながることです。自分は合成データを Data Designer で作り、Curator で整え、AutoModel で学習して、Evaluator で採点するという流れを組んでいます。それぞれ独立したツールなので個別に差し替えられますが、データの形式や評価の API が揃っているので、パイプラインとして組んだときの継ぎ目が少ないです。

自分が組んでいる流れを図にすると次のようになります。AutoModel は真ん中の学習の箱で、入出力はどちらも Hugging Face の形式です。

一方で、深いカスタマイズが要る学習は Megatron-Bridge の領分ですし、コンテナの中身は 2 か月ごとに更新されるので、レシピの互換性は版ごとに確かめる必要があります。後半で触れるバージョン表示の癖もその一例です。過度な期待は禁物ですが、Hugging Face のモデルを DGX Spark で普通に学習したい、という用途には今のところ一番手間の少ない道かなと思っています。

DGX Spark 対応はリリースノートではなく PR の積み重ねで見える

自分が対応を見落としていた理由は単純で、リリースノートに「DGX Spark 対応」と書かれた行が v0.2.0 の 1 行しかなかったからです。実際の対応は PR とレシピの YAML で積み上がっていて、GitHub の履歴をたどると次のように見えます。

日付 変更 収録
2025-10-14 Discussion #640 で DGX Spark 向け playbook を告知
2025-10-15 PR #645 Qwen3-8B の DGX Spark 向け SFT レシピを追加 v0.2.0 以降
2025-10-19 PR #657 GPT-OSS を DGX Spark の 1 GPU で回す dequantization v0.2.0 以降
2026-02-05 PR #1164 統合メモリ向けの streaming safetensors writer v0.3.0 以降
2026-08-14 PR #3538 DGX Spark 向けレシピを GB10 の実機 CI ランナーへ v0.6.0(NGC 26.08)
2026-08-14 PR #3553 bitsandbytes を SM121 ネイティブでビルド v0.6.0(NGC 26.08)
2026-08-18 PR #3533 単 GPU の DCP ロード修正と Lightning 向け単 GPU LoRA レシピ main のみ
2026-09-02 PR #3766 64GB の RTX Spark 向け学習サポート main のみ

転機は 2026 年 8 月 14 日の 2 件です。GB10 の実機が CI ランナーに入り、Qwen3-8B の SFT、GPT-OSS-20B の LoRA、Llama-3.3-70B の QLoRA の 3 本が GB10 実機の CI 対象になりました。同じ日に bitsandbytes を SM121 向けにネイティブビルドする変更が入っています。この 2 件は v0.6.0 のリリースブランチに cherry-pick され、v0.6.0 は 8 月 26 日に公開、対応する NGC のタグが 26.08 です。

v0.6.0 に入っている DGX Spark 向けレシピは 4 本です。Qwen3-8B の SQuAD SFT、GPT-OSS-20B の単 GPU LoRA、Llama-3.3-70B の QLoRA、そして Nemotron 3 Nano 30B-A3B の単 GPU LoRA です。最後の 1 本は ep_size 1 で書かれていて、自分が以前「cookbook は H100 8 枚前提」と判断して避けた MoE の LoRA が、1 台向けのレシピとして公式に存在していました。

導入経路は 3 つあるがコンテナ一択でよい

DGX Spark で AutoModel を動かす経路は、NGC のコンテナ、pip の wheel、build.nvidia.com の playbook の 3 つがあります。手元で確認した範囲を並べると次のとおりです。

経路 中身の鮮度 arm64 での実績 備考
NGC nemo-automodel:26.08 2026-08-26、r0.6.0 ブランチ この記事で確認。multi-arch で linux/arm64 あり 圧縮約 13GB、展開後 29.4GB
pip nemo-automodel 0.6.0(PyPI) 未確認 wheel は純 Python。TE や bitsandbytes の aarch64 ビルドは別
build.nvidia.com playbook 2026-03-04、26.02 を指定 フォーラムで 70B QLoRA が "Killed" になった報告あり 手順は同じ構造。タグだけ 3 世代古い

playbook は「Fine-tune with NeMo」として公開されていて、手順自体は今回と同じく docker run でコンテナに入ってレシピを叩く形です。ただ指定しているタグが 26.02 のままで、GB10 の CI や bitsandbytes の SM121 ビルドが入る前の版です。pip の wheel は py3-none-any で中身は純 Python なので、AutoModel 本体よりも Transformer Engine や bitsandbytes を aarch64 でどう揃えるかが本題になります。今回はそこに踏み込まず、コンテナだけを使いました。

個人的には、DGX Spark で使うならコンテナ一択でいいと思っています。NGC のイメージは linux/arm64 のマニフェストを持っていて docker pull するだけで揃いますし、レシピも /opt/Automodel/examples/ に同梱されています。

公式 Spark レシピを LoRA 化して Qwen3-8B を短走させる

コンテナに同梱されている Spark 向けレシピ examples/llm_finetune/qwen/qwen3_8b_squad_spark.yaml は full SFT の設定です。今回は使い方の確認が目的なので、このレシピをベースに LoRA を足し、30 step で止まる短い版を作りました。変更したのは step 数とバッチサイズ、検証と保存の間隔、peftcheckpoint のブロック、データのサンプル数、モデルのパスで、CI 用の ci ブロックは外しました。Spark 向けの肝である attention とロス関数、sequence packing はそのまま残しています。

qwen3-8b-squad-spark-lora.yaml(抜粋。説明のコメントを追記)
step_scheduler:
  global_batch_size: 2 # 公式は 64
  local_batch_size: 1 # 公式は 2
  ckpt_every_steps: 30
  val_every_steps: 30
  num_epochs: 1
  max_steps: 30

model:
  _target_: nemo_automodel.NeMoAutoModelForCausalLM.from_pretrained
  pretrained_model_name_or_path: /workspace/models/Qwen3-8B # 取得済みの重みを読み取り専用でマウント
  # Keep packed training on the HF FlashAttention path for GB10. TE's packed THD
  # backward requests ragged LSE, which cuDNN does not support on SM12x GPUs.
  force_hf: true
  attn_implementation: flash_attention_2

peft:
  _target_: nemo_automodel.components._peft.lora.PeftConfig
  target_modules: '*_proj'
  dim: 8
  alpha: 32
  use_triton: false

checkpoint:
  enabled: true
  checkpoint_dir: /workspace/run/checkpoints
  model_save_format: safetensors
  save_consolidated: final

dataset:
  _target_: nemo_automodel.components.datasets.llm.squad.make_squad_dataset
  dataset_name: rajpurkar/squad
  split: train
  limit_dataset_samples: 512

force_hf: trueflash_attention_2 の 2 行は公式レシピにコメント付きで入っている GB10 向けの指定です。Transformer Engine の packed attention が使う backward を GB10 の cuDNN が扱えないため、Hugging Face 側の FlashAttention 2 経路に固定しています。この手の事情がレシピにコメントとして書かれているのは、実機で CI を回している副産物かなと思います。

実行はコンテナを 1 回起動するだけです。モデルの重みは事前に取得したものをマウントし、SQuAD だけをコンテナ内から取得しました。以下は実際に使った run.sh から抜き出した再現用の形で、作業ディレクトリ直下に config/ を置く前提です。

docker run --rm --gpus all --network=host --shm-size=32g \
  --ulimit memlock=-1 --ulimit stack=67108864 \
  --workdir /opt/Automodel \
  -v "$PWD:/workspace/run" \
  -v "$HOME/models/qwen3-8b-b968826d:/workspace/models/Qwen3-8B:ro" \
  -v "$HOME/.cache/huggingface:/root/.cache/huggingface" \
  nvcr.io/nvidia/nemo-automodel:26.08 \
  automodel /workspace/run/config/qwen3-8b-squad-spark-lora.yaml --nproc-per-node 1

結果は次のとおりです。ロードから 30 step、検証、checkpoint 保存までコンテナの中で 90 秒でした。

項目
step 数 30(すべて有限の loss)
学習 loss 7.9741 → 1.9950(この回の 30 step)
検証 loss(64 件) 2.7526
CUDA 最大割り当て 20.78 GiB
1 step の時間(中央値) 1.69 秒
スループット(中央値) 1,069.63 tok/s
コンテナ内の壁時計 90 秒
adapter の大きさ 43,713,952 bytes(rank 8、alpha 32)

loss が下がっているのは SQuAD を 512 件に制限した設定で 30 step だけ回した結果なので、学習の成果としては読まないでください。ここで確かめたかったのは、公式の Spark レシピの経路が 26.08 の arm64 イメージでそのまま通ること、LoRA の adapter が safetensors で出てくること、そしてメモリが 128GB のどのあたりに収まるかの 3 点です。今回の条件では、Qwen3-8B の BF16 LoRA の CUDA 最大割り当ては 20.78 GiB でした。

128GB の統合メモリでどこまで載るかを手元の実績で並べる

今回の 30 step だけでは物足りないので、同じ AutoModel の一つ前のコンテナ(26.06.00)で回した自分の実績も並べておきます。条件が違うので横並びの比較ではなく、あくまで 1 台に載るかどうかの目安として見てください。

モデルと方式 コンテナ 条件 CUDA 最大割り当て
Qwen3-8B BF16 LoRA、30 step 26.08 packing 1024、batch 2 20.78 GiB
Qwen3-8B BF16 LoRA、360 step、720 件 1 epoch 26.06.00 seq 1,024、batch 2、6 分 09 秒 19.16 GiB
Qwen3-14B LoRA、176 step 26.06.00 文脈長 2,048、batch 2 42.85 GiB
Nemotron 3.5 Lightning 30B-A3B BF16 LoRA、10 step 26.06.00 MTP 層を外す、1 step 約 4 秒 63.25 GiB
Qwen3-8B BF16 full SFT、公式レシピ、305 step 完走 26.08 batch 64、packing 1024、約 72.54 秒/step 77.70 GiB

8B の LoRA が 20.78 GiB、14B で 42.85 GiB、30B の MoE でも 63.25 GiB で、表の条件ではどれも 1 台の GB10 に収まりました。一方で 8B の full SFT は公式レシピの設定のまま 77.70 GiB まで使い、1 step が約 72.54 秒でした。

この full SFT は最後まで回しています。SQuAD の 1 epoch にあたる 305 step を 6 時間 11 分で完走し、学習 loss は 7.0378 から 0.0637 まで、検証 loss は 4.4213 から 0.0960 まで下がりました。検証 loss は step 39 以降ほぼ横ばいなので、この後半はレシピの都合で回しているだけです。完了時には checkpoint として、Hugging Face 形式に統合した safetensors が 5 ファイル約 16.4GB、学習再開用の分割済み重みと optimizer の状態を合わせて 62GB が書き出されました。統合した重みはそのまま vLLM に渡せる形です。8B の BF16 full SFT は、1 台の DGX Spark で「載る」だけでなく「6 時間待てば終わる」と言える範囲でした。

では、どのくらいの大きさまで full SFT が現実的なのでしょうか。8B で 77.70 GiB なので、同じ計算を 14B に当てはめると約 136 GiB になり、Linux から見える 121 GiB を超えます。optimizer の状態を CPU 側へ逃がす、8-bit の optimizer を使うといった手はありますが、手元では試していません。公式の playbook も DGX Spark の組み合わせを「8B は full SFT、70B は QLoRA」で示しているので、BF16 の full SFT は 8B クラスまで、それより上は LoRA か QLoRA、というのが今の自分の見立てです。

個人的に意外だったのは Lightning です。以前の自分は「BF16 の LoRA は統合メモリでは載らない」と判断して 4-bit の QLoRA か H100 を選んでいたのですが、同梱の Nemotron 3 Nano 用レシピにある ep_size 1 と LoRA 対象の絞り込みを下敷きに、Lightning 固有の MTP 層を外せば 63.25 GiB で回りました。この Lightning の走り込みは別の記事で扱う予定なので、ここでは数字だけにとどめます。

26.08 で気をつける点を先に書いておく

使い方は以上なのですが、コンテナの中を見ていて引っかかった点がいくつかあったので、同じことを試す方のために先に書いておきます。

まずバージョンの表示です。NGC のタグは 26.08 で、リリースとしては v0.6.0 に対応するはずなのですが、コンテナ内で nemo_automodel.__version__ を見ると 0.5.0+922e83e42 と出ます。起動時のバナーも「NVIDIA Release 26.06」です。GitHub で追うと、このコミットは v0.6.0 のリリースブランチにあり、タグの 3 コミット手前でビルドされたものでした。差分は LoRA backward の修正 1 件とバージョン番号のバンプ 2 件で、GB10 の CI と bitsandbytes の SM121 ビルドは含まれています。中身は v0.6.0 相当と考えてよさそうですが、バージョン文字列を信じて判断すると混乱します。

次に CUDA です。コンテナは CUDA 13.3 で、手元の DGX Spark のカーネルドライバは 580.159.03 でした。起動時に「CUDA Forward Compatibility mode ENABLED」と出て、この組み合わせでは 30 step が完了しました。ドライバを上げずに新しいコンテナを動かす仕組みで、今回は問題になっていません。

ログの出方にも癖があります。学習の loss と memtps は 1 step ごとに INFO 行で出ますが、これは stderr 側です。stdout にはレシピの内容と進捗バーが出ます。2> で分けてしまうと loss が見えなくなるので、両方を残しておくのが無難です。

checkpoint まわりは 2 点あります。コンテナは root で動くので、checkpoints/ 配下のファイルは root 所有で書かれます。自分は同じイメージで chown をかけてから回収しました。もう 1 点は起動時の警告で、save_consolidated: final を指定すると「v4_compatible=False なので transformers v4 とは互換性がないかもしれない」と出ます。コンテナの transformers は 5 系なので今回はそのまま進めましたが、古い transformers で読む予定があるなら checkpoint.v4_compatible を見ておくとよさそうです。

なお、PR #3533 で追加された Lightning 向けの単 GPU LoRA レシピは main にはありますが、26.08 のイメージには入っていません。同梱の nemotron_nano_v3_singlegpu_lora.yaml をベースに自分で書き足す必要があります。

まとめ

NeMo AutoModel は、DGX Spark 向けの公式レシピと GB10 の実機 CI を持つ状態になっていました。NGC の 26.08 コンテナは linux/arm64 のイメージを持ち、公式の Spark レシピを LoRA 化しただけの YAML で Qwen3-8B の学習が CUDA 最大割り当て 20.78 GiB で回り、同じレシピの full SFT も 77.70 GiB で 305 step を完走しました。以前の俯瞰記事で △ にしていた行は、「8B の LoRA と full SFT が公式コンテナで完走する」まで進めてよさそうです。

一方で、今回確かめたのは LoRA の 30 step と full SFT の完走、それに 1 台に載るメモリの目安までです。学習後のモデルの品質、pip での導入、FP8 は見ていません。コンテナのバージョン表示が r0.6.0 ブランチの途中を指している点は、数字を人に伝えるときに注意が要ります。

Nemotron 3.5 Lightning の単 GPU LoRA は、一つ前のコンテナで学習から vLLM での配信まで一周させてあります。こちらは日本語の Tool Calling を題材にした学習と評価を含めて、別の記事で扱う予定です。

参考リンク


AI白書2026 配布中

クラスメソッドが独自に行なったAI診断調査をもとに、企業のAI活用の現在地を調査レポートとしてまとめました。企業規模別の活用度傾向に加え、規模を超えてAI活用を進める企業に共通する取り組みまで、自社の現在地を捉えるためのヒントにぜひ。

AI白書2026

無料でダウンロードする

この記事をシェアする

DevelopersIO 2026

関連記事