DGX Sparkではなく、Jetson Thorを買ってしまった皆様、いかがお過ごしでしょうか。
本記事では、Jetson Thorを使って何ができるのか。を考え、色々試した結果の一部をご紹介できればと思っております。
執筆内容の理想と現実
- ① 様々な推論速度などを検証し、どの程度の性能を出せるのか ← 比較表を見つけたので、大して有益でない
llama.cpp Benchmarks — DGX Spark vs Jetson AGX Thor - ② GB10系を買ったからには、事前学習からのファインチューニングでしょ ← nanoGPT + nanoMoEでの超小規模をモデル作成したが、試したレベルになるので面白くない+商用利用可能なライセンスで公開するためのデータセット集め+学習が間に合わない。
- ③ いやいや、JetsonならフィジカルAIでしょ ← Isaac Simと Isaac LabはThorでは厳しい(非推奨)要望はあるが、無理っぽい回答
Nvidia Thor上安裝失敗 · isaac-sim/IsaacSim · Discussion #220 - ④ 複数モデルを使った映像要約のデモ ← DGX Sparkなら全モデルをローカルで構築できるのにJetson Thorでは不可!?
https://build.nvidia.com/nvidia/video-search-and-summarization/blueprintcard
ぬこぬこさんのイベント
また、LLMを事前学習した人のみ参加できるというイベントがあり、(東京なのでどうせ行けません+イベントに間に合っていません)これはやらなければといけない。という思いもありました。
https://aimeetup.connpass.com/event/367666/
上記のような(さまざまな環境構築との闘い)という経緯を経て、取り急ぎ② nanoGPTを使った小規模モデルの構築の記事となりました。
nanoGPT
https://github.com/karpathy/nanoGPT
GPT2をベースとした小規模モデルを学習・微調整するためのシンプルなリポジトリです。
8台のA100 40GBノード1台を約4日使用することにより、124MBのモデルを作成する事ができます。
※ なお、nanoGPTはすでに過去の遺物となっており、nanochatの使用が推奨されています。
(2025年11月にその事が記載され、自分が見つけた時は書いてありませんでした。。。)
環境構築
学習はコンテナを使用して行いました。
ベースに使用したコンテナ元は下記です。
nvcr.io/nvidia/pytorch:25.08-py3
自分は下記のように設定しました。
wandbの代わりにmlflowやその他の物を使うためportなどを設定(別PCからmlflowを表示したりなど)、また、容量削減のためにキャッシュフォルダを永続化しております。
docker run --gpus all --ipc=host --ulimit memlock=-1 --ulimit stack=67108864 -d \
--name llm_train \
-p 8000:8000 \
-p 8501:8501 \
-p 8888:8888 \
-p 5000:5000 \
-v /home/kevin/.cache:/root/.cache \
-v /home/kevin/LLM:/workspace \
nvcr.io/nvidia/pytorch:25.08-py3
※ -d コマンドを付けないと、exitしたらstopしてしまいます。
また、nameを付けておかないと適当な名前が付けられるので、つけて管理した方がいいでしょう。
dockerになれてないと、こういうところでも時間かけてしまうんですよね。あろうことか、最初はsingularityを導入しようとしておりました。
必要に応じ、追加インストールを実施しております。
pip install sentencepiece transformers datasets mlflow # etc ..
トークナイザーの学習
今回は、高速化、小規模テストで実施するため。
allenai/c4から日本語用のデータを1GBだけ準備しました。
stats = download_huggingface_dataset(
dataset_name="allenai/c4",
subset_name="ja", # 日本語版
output_dir=output_dir,
target_size_gb=target_size_gb,
max_samples=100000
)
ダウンロードしたデータを元に、追加工+トークナイザー処理を実施します。
加工処理としては
- 連続空白、連続改行、前後空白等の除去
- 長さフィルタリング
- 繰り返しパターン検出
というような簡単な前処理を実施しております
(Claude君が一晩で用意してくれました)
python scripts/preprocess_jsonl_data.py \
--input /workspace/llm_train/data/1gb_dataset/data.jsonl.gz \
--output /workspace/llm_train/data/1gb_dataset/processed/data_2.jsonl.gz \
--min-length 100 \
--max-length 100000
=== Preprocessing JSONL Data ===
Input: /workspace/llm_train/data/1gb_dataset/data.jsonl.gz
Output: /workspace/llm_train/data/1gb_dataset/processed/data_2.jsonl.gz
Text column: text
Length range: 100 - 100000 chars
Processing: 100000it [01:26, 1155.78it/s]
=== Processing Statistics ===
Total documents: 100,000
Passed: 96,030
Filtered (length): 3,151
Filtered (repetition): 819
Filtered (empty): 0
Pass rate: 96.0%
小さいデータサイズなので、学習は1分半ほどで済みました。
事前学習
python src/training/train_nanogpt.py \
--config-yaml "$CONFIG_FILE" \
--output-dir "$OUTPUT_DIR" \
--data-file "$PROCESSED_DATA" \
--tokenizer-path "$TOKENIZER_PATH"
- 学習に使用するデータ
- 出力先
- トークナイザーデータ
- 学習の設定(yaml)
などを引数で渡して実行できるようにしてあります
# nanoGPT Small Configuration
# 小さなnanoGPTモデル(約50M-100Mパラメータ)用の設定
# 1GBのデータで軽く試すための設定
# Model configuration
model:
vocab_size: 32000
hidden_size: 512 # n_embd(小さめに設定)
intermediate_size: 2048 # 4 * n_embd
num_hidden_layers: 8 # n_layer(小さめに設定)
num_attention_heads: 8 # n_head
num_key_value_heads: 8
max_position_embeddings: 1024 # block_size
hidden_act: "gelu"
rms_norm_eps: 1e-5
rope_theta: 10000.0
attention_dropout: 0.0
hidden_dropout: 0.0
# Training configuration
training:
micro_batch_size: 4
gradient_accumulation_steps: 16 # 実効バッチサイズ: 64
learning_rate: 1e-4 # NaN問題を回避するため学習率を下げる
min_learning_rate: 1e-5
warmup_steps: 2000 # NaN問題を回避するためwarmupを増やす
lr_scheduler_type: "cosine"
optimizer: "adamw"
weight_decay: 0.1
adam_beta1: 0.9
adam_beta2: 0.95
adam_epsilon: 1e-8
max_grad_norm: 0.5 # NaN問題を回避するため勾配クリッピングを強化
max_steps: 10000 # 小さなデータセット用に短縮
eval_interval: 500
save_interval: 1000
log_interval: 10
dtype: "float32" # NaN問題を回避するため一時的にfloat32を使用(安定後にbfloat16に戻す)
use_flash_attention: false
use_schedule_free: false
# Data configuration
data:
data_dir: "data/1gb_dataset" # デフォルトのデータディレクトリ
processed_dir: "data/1gb_dataset/processed"
max_seq_length: 1024
num_workers: 4
shuffle_buffer_size: 10000
tokenizer_path: "tokenizer/tokenizer.model"
data_file: "data/1gb_dataset/processed/data.jsonl.gz" # JSONL形式のデータファイル
# Output configuration
output_dir: "outputs/nanogpt_small"
experiment_name: "nanogpt_small_pretrain"
今回は、このような形の設定で学習する事にしました。
Nan問題が発生したりで、何度か試行錯誤しております。
学習スタート
Training: 10%|███▊ | 1010/10000 [1:04:10<10:04:54, 4.04s/step, loss=10.0111, ppl=22272.33, lr=5.10e-05]
Step 1010/10000: loss=10.0111, perplexity=22272.33, lr=5.10e-05
GPU utilization: 88.0%
GPU memory: 0.50GB / 122.82GB (0.4%)
Training: 10%|████ | 1020/10000 [1:04:47<9:14:00, 3.70s/step, loss=9.9951, ppl=21919.83, lr=5.15e-05]
Step 1020/10000: loss=9.9951, perplexity=21919.83, lr=5.15e-05
GPU utilization: 87.0%
GPU memory: 0.50GB / 122.82GB (0.4%)
Training: 10%|████ | 1030/10000 [1:05:24<9:15:20, 3.71s/step, loss=9.9929, ppl=21871.17, lr=5.20e-05]
Step 1030/10000: loss=9.9929, perplexity=21871.17, lr=5.20e-05
GPU utilization: 89.0%
GPU memory: 0.50GB / 122.82GB (0.4%)
このように損失lossが下がっていきます。
仮にNanなどになれば、各種設定などにミスが発生している可能性があります。
公開されているモデル等に比べると圧倒的に小さく、使用しているデータ量も極小ですが、軽く数十時間かかります。
問題がなければlossが順調に下がっていることが確認できます。(mlflow)
設定が失敗していれば記録されてなかったり、GPUの使用率なども表示されなくなるので、小さくテストした方がよいかと思われます(戒め)
MoEバージョンも学習を進めてみましたが、これだけでも数日間かかるようなので本記事用には断念しました。
評価
追加で15000まで回してみましたが、当然ながらパラメータ数、データの質・量、学習量などを考えると言語モデルとは到底言えないような性能となっておりました。
instruction用のデータセットすら使っていないので、会話も一切成り立たないような物となります。
また、一度繰り返しに入ると、永遠とおなじ単語が羅列されるような現象が確認できます。
============================================================
Generating with: checkpoint-15000
============================================================
Number of parameters: 42.08M
[1/3] Prompt: こんにちは、
Generated: 日名と金名屋さんの店にてお金もありましたよ。・木名様のご皆様は御御ごお見をおご伺にいただきまして、御おお伺いいたします。おごおごもさせていただきますので、おごおごごおごおのおおごお・お・おご・お・おお・お・お・お・お・お・お・お・お・お・お・【以下略】
[2/3] Prompt: 人工知能とは、
Generated: この中で、それは当然、現実的なことでしょうか? ◆「第26回」第17回 『第19回』第17回(第19回第1回第2回第2回第1回第2話 第2話第1回第2話 第2話:第1話するか第2話におけるテーマと発表が、第1話第2回第1話第2回第2話第2話第1話第2話第2話第1話第2話、【以下略】
[3/3] Prompt: 今日は良い天気です。
Generated: この時間でもちょっといいのですが。 これもまだ行ないと思いますし。 この前にあるような状況なので、この時点ではやはり今朝は9:05〜、8:05〜、8:05〜の3:06〜の頃にはないよ〜とやればいいけどね。 これは夏予定ある分では、これが6:05〜11:05〜18:06〜、8:05〜16:0〜、8:00〜22:0~20:0〜その22:0~16:00〜いっぱいつつんは10:06〜私、【以下略】
nanoGPT FineWeb版
次に、データの質を重視したものに変えてみます。
FineWebから日本語を1GBほどピックアップしたものを学習させ、単純にc4を使用した場合と比較してみました。
と、思いましたが、データ数が少ないのか、性能の違いを感じられるほどは変わらなかったです。
※ 一番初めに試した時は結構いいところ行くんだな。って思ってたのですが、再度初期からセットアップして試したら性能が激減しておりました。(困惑
総評
H100の性能などには圧倒的に及ばないながら、Jeton Thorを使って小さいモデルでも学習ができる事を確認しました。
GPU使用中はファン音?のような物が聞こえますが、デスクトップGPUや3Dプリンターなどよりも圧倒的に音が小さく、同じ部屋にいても睡眠が害されることは無い。という魅力があります。
ただし、1TBという容量では複数の事を試すのが辛く、DGX Sparkを買うのであれば無理をしてでも4TBをGetするべきだと感じました。
※ 容量限界に気づかず処理を実施しフリーズ。再起動してもログイン画面が出てこず、cursorなどで接続不可。困り果てたところ、コマンドラインからのssh接続ができたのでファイル整理し、なんとか正常起動。という事もありました。
容量には気を配りましょう。
NVIDIA公式でもThorよりSparkの方が圧倒的にサポート感があるため、Jetson Thorは物理ハードありきで使うのが前提であるため、上級者向けのデバイスだと言わざるを得ない状況でした。
これまで運よく松尾研コンペなどにも関わってこれましたが、「他人が用意してくれた環境の中で、軽く設定をして学習ポン」では、やはり身につかないと改めて思いました。
自分でコードを見て、理論も勉強して実際にやってみる事の重要性が実感できました。
- どの程度のデータ量が必要になる。
- どの程度の速度で学習ができる。
- どの程度の性能が出せる。
などの感覚を得る事が大事だと思います。
次は、【つくりながら学ぶ!LLM 自作入門】を見ながらMoEモデルなどもやってみたいと思います。
フィジカルAIは、機会があればまた次回に。
追記
コードも公開できればよかったのですが、nanoGPTがすでに非推奨だった点。各種論文の機能を追加させるためにClaudeやGeminiに働かせた結果、本記事の内容としては不要な箇所が多すぎる点や、再現性が確保できる可能性がなかったため、今回は見送らせて頂きました。
改めて、最低限まともなレベルになれば、その際は公開できればと思っております。(望む人はいないでしょうが、、、)
