💬

DGX Sparkと「nanochat」でゼロから丸一日学習させてLLMを自作してみた

に公開

nanochatとは

OpenAI共同設立者、元テスラディレクターであり。バイブコーディング・コンテキストエンジニアリングといった言葉を生み出したAndrej Karpathy氏が公開したソフトウェアです。

https://github.com/karpathy/nanochat

なんと、ChatGPTのような対話可能なLLMを、規模こそ違えど約100ドルのコストでゼロから4時間で学習させることができるソフトということで話題になりました。

100ドルくらいのコストで、人とある程度対話可能なLLMを開発できるというのは、本当に凄いことで破格なのですが、やはり一回の学習に100ドルかかるのは、個人の趣味だったり、学習用に考えると難しいものがあります。

そこで登場するのがNVIDIA DGX Sparkです。1petaFLOPのAIパフォーマンスと128GBのメモリがあればnanochatを実用的な速度で学習できるかもしれないということで、DGX SparkによるLLMのゼロからの学習を試してみました。

なお、DGX SparkはNVIDIAさんから貸与いただいたものを使用しています。

nanochatの学習結果

結論から言うと、DGX Sparkでほぼ丸一日(21時間)学習させることで、ある程度対話可能なLLMを作ることができました。以下学習したモデルを動かしたところです。

https://www.youtube.com/watch?v=ahV1fB7z9XI

ところどころに変なところはありますが、それなりに対話ができていることが分かると思います。

クラウドを使うと100ドルかかる学習を、電気代のみで実現できます(DGX Spark自体の価格は一旦記憶喪失になって忘れてください)。

nanochatoをゼロから学習させる方法

簡単に再現できるように、学習の方法を書きます。

学習の流れ

nanochatの学習の流れは、リポジトリのspeedrun.shを確認すると以下のようになっていることが分かります。

  • トークナイザの学習(tok_train)
  • 事前学習(base_train)
  • 中間学習(mid_train)
  • 教師ありファインチューニング(chat_sft)

LLM、世の中のほとんどの学習はファインチューニングなのですが、nanochatはトークナイザと事前学習からやっているのがハードコアですね。リポジトリみると、speedrun.shには含まれていませんがオプションで強化学習(chat_rl)もできるようです。

speedrun.shスクリプトは、100ドルのコストでの学習を実現させるために、上記の他にセットアップを含んでいたり、ダウンロードと学習を並行させたりと色々工夫をしています。

ただ、DGX Sparkだとそのまま動かないので、以下変更しました。

  • セットアップをspeedrun.shから切り離して、DGX Spark用のセットアップに改変
  • DGX Sparkで学習できるようにノード数、バッチサイズ、イテレーション数等を調整する
  • 評価を省略

セットアップと事前準備

ここからDGX Spark用のセットアップをしていきいます。

以下記事をもとに、基礎的なセットアップをしていることが前提となります。
https://zenn.dev/karaage0703/articles/985ddbd8fa15d3

上記記事をスキップする場合は、最低限uvを以下コマンドでセットアップしておいてください。

$ curl -LsSf https://astral.sh/uv/install.sh | sh

最初にリポジトリのクローンをします。

$ git clone https://github.com/karpathy/nanochat
$ cd nanochat

uvによるPython環境のセットアップをします。

$ uv venv
$ source .venv/bin/activate
$ uv pip install torch torchvision --index-url https://download.pytorch.org/whl/cu129
$ uv pip install datasets fastapi files-to-prompt uvicorn

環境構築に必要な、Rustのインストールと動作確認をします。

$ curl https://sh.rustup.rs -sSf | sh -s -- -y
$ source $HOME/.cargo/env

# 動作確認
$ rustc -V
$ cargo -V

Rustを使った環境構築をします。

$ uv pip install maturin
$ cd rustbpe
$ uv run --active maturin develop --release
$ cd ..

評価用のファイルを準備します。

$ export NANOCHAT_BASE_DIR="$HOME/.cache/nanochat"
$ mkdir -p $NANOCHAT_BASE_DIR
$ EVAL_BUNDLE_URL=https://karpathy-public.s3.us-west-2.amazonaws.com/eval_bundle.zip
$ curl -L -o eval_bundle.zip $EVAL_BUNDLE_URL
$ unzip -q eval_bundle.zip
$ rm eval_bundle.zip
$ mv eval_bundle $NANOCHAT_BASE_DIR
$ curl -L -o $NANOCHAT_BASE_DIR/identity_conversations.jsonl https://karpathy-public.s3.us-west-2.amazonaws.com/identity_conversations.jsonl

これでセットアップは完了です。

nanochatの学習

speedrun.shをベースに改変した以下ファイルをspeedrun_spark.shという名前で作成して、nanochat以下に保存します。

NUM_ITERATIONSを変えると学習時間が変わります。今回は1000にしましたが、自分の環境だとこれで21時間くらい学習にかかりました。

#!/usr/bin/env bash
# speedrun_total_min.sh — 全体時間のみ(開始→終了の差)
set -euo pipefail

# ===== ユーザー設定(そのまま) =====
DEPTH=20
DEVICE_BATCH_SIZE=16
#NUM_ITERATIONS=1
NUM_ITERATIONS=1000
CACHE_DIR="$HOME/.cache/nanochat"
# ===================================

# --- 実行環境・OOM対策(任意、元のまま) ---
export PYTORCH_ALLOC_CONF="expandable_segments:True,max_split_size_mb:256"
export TORCHDYNAMO_DISABLE=1
export TORCHINDUCTOR_DISABLE=1

# ---- 計測開始 ----
T0=$(date +%s)

# ===== 実行コマンド =====
python -m nanochat.dataset -n 240

python -m scripts.tok_train --max_chars=2000000000
#python -m scripts.tok_eval

python -m scripts.base_train --depth="${DEPTH}" --device_batch_size="${DEVICE_BATCH_SIZE}" --num_iterations="${NUM_ITERATIONS}"
#python -m scripts.base_loss
#python -m scripts.base_eval

python -m scripts.mid_train --device_batch_size="${DEVICE_BATCH_SIZE}" --num_iterations="${NUM_ITERATIONS}"
#python -m scripts.chat_eval -i mid

python -m scripts.chat_sft --device_batch_size="${DEVICE_BATCH_SIZE}" --num_iterations="${NUM_ITERATIONS}"
#python -m scripts.chat_eval -i sft

# python -m nanochat.report generate

# ---- 計測終了&表示 ----
T1=$(date +%s)
ELAPSED=$((T1 - T0))
printf "\n== SUMMARY ==\nTotal elapsed: %d s (%02d:%02d:%02d)\n" \
  "$ELAPSED" "$((ELAPSED/3600))" "$(((ELAPSED%3600)/60))" "$((ELAPSED%60))"

echo "✅ 完了:Web UI →  python -m scripts.chat_web"

以下コマンドで学習を実行します。

$ bash speedrun_spark.sh

学習が始まります

DGX Dashboardで確認すると、メモリとCPUをほぼフルに使っていることが分かります

この状態だと、DGX Sparkがかなり熱くなっています。

学習曲線は以下の通りです。

動作確認

学習が終わったら、以下コマンドを実行しましょう。

$ python -m scripts.chat_web

DGX Spark上であれば、ブラウザで以下にアクセスします。

0.0.0.0:8000

他のPCからリモートログインしている場合は、0.0.0.0の代わりにDGX SparkのIPアドレスを入れてください。

アクセスすると、nanochatのチャット画面が開きます。NUM_ITERATIONS=1000で学習すると、冒頭の動画のように学習したLLMと対話ができます。

なおNUM_ITERATIONS=100くらいの学習だと、以下のように全く会話になりません。

まとめ

nanochatをDGX Spark上でゼロから学習してみました。自分でゼロから学習させたLLMが、ローカルでサクサク賢く動くのは結構感動ものです。何より、手元で動いているという手触り感がよいですね。

nanochatは、ソフトはシンプルで分かりやすい上、スクリプトは様々な工夫がされている奥が深く面白い勉強になるリポジトリです。DGX Sparkだと、LLM開発を何度でも試行錯誤できるので、学習にうってつけだと思います。

みなさんも、DGX Sparkでnanochatを学習させてLLMをゼロから開発してみましょう!

Discussion