株式会社ホコサキ

VRAM 4GBで8Bモデルをファインチューニングする Soup 入門

天京祐輔
天京祐輔
VRAM 4GBで8Bモデルをファインチューニングする Soup 入門

VRAM 4GB のノート GPU で 8B モデルをファインチューニングする、というのはつい最近まで「無理な話」でした。
LoRA を使っても、ベースモデルをまるごと VRAM に乗せようとすれば 12GB 以上は必要というのが相場感でした。
そこに登場したのが Soup というオープンソースの CLI ツールです。

なぜ 4GB で動くのか。
その仕組みを理解してから手を動かすと、設定の意味がずっと腑に落ちやすくなります。

レイヤーストリーミングが「4GB で 8B」を可能にする理由

LoRA ファインチューニングの仕組みを思い出してください。
学習するのは追加した小さなアダプタ層だけで、ベースモデルの 80 億パラメータは 凍結されたまま です。
凍結されているということは、書き込みが一切発生しないということ。
読むだけなら、VRAM に常駐させる必要はないはずです。

Soup はその発想を素直に実装しています。
ベースモデルを CPU の RAM に置いておき、デコーダーレイヤーを 1 枚ずつ VRAM に引き込んで forward/backward を通し、終わったら捨てる。
次のレイヤーを引き込んで、また通して、また捨てる。
これを全レイヤー分繰り返すのがレイヤーストリーミングの動作イメージです。

この方式だと、GPU 上に存在するのは「いま処理中の 1 レイヤー分」と「LoRA アダプタ」だけです。
モデル全体を VRAM に乗せる必要がないので、ピーク VRAM が劇的に下がります。
さらに、ストリームするベースレイヤーを NF4 量子化すると約 4 分の 1 に圧縮できます。
公開情報によると、Llama-3.1-8B を NF4 量子化と組み合わせた場合のピーク VRAM は 3.32 GB とされています。

速度面では当然トレードオフがあります。
レイヤーを毎回 RAM から転送するコストがかかるので、VRAM にモデルを常駐させる通常の学習より遅くなります。
ただ Soup の設計思想は「速度より正確性を先に解く」というものです。

ここが面白いところで、ストリーミングは失敗しても loss が下がり続けることがあります。
上位レイヤーが学習を続けるので、勾配が壊れていても表面上は「学習が進んでいるように見える」状態になりえます。
そのため Soup はリリースごとにストリーミング実行と通常実行のロジットを突き合わせる検証プロトコルを持っています。
作者自身がこのプロトコルで自分のリリースコードのバグを発見したというエピソードが Product Hunt のコメントに残っており、この検証の重要性がよく伝わります。

インストールと動作確認

Soup は PyPI で配布されています。
ファインチューニングに必要な依存関係を含めてインストールするには、以下のコマンドを使います。

pip install "soup-cli[train]"

対応 Python バージョンは 3.10〜3.12 です。
3.13 以降はまだ対応していないので、環境を作るときに注意してください。

インストール後の動作確認はシンプルです。

soup --help

コマンド一覧が表示されれば問題ありません。

依存関係で詰まりやすいのは PyTorch と CUDA のバージョン整合です。
soup-cli が要求する torch のバージョンと、手元の CUDA ドライバが対応しているバージョンがずれていると、インストール自体は通っても実行時にエラーが出ます。
事前に CUDA バージョンを確認して、対応する torch をインストールしておくのが無難です。

もう一点、見落としがちなのが CPU RAM の容量 です。
レイヤーストリーミングはベースモデルを CPU RAM に展開したうえで VRAM に逐次転送する仕組みなので、RAM にモデル全体を収める余裕が必要です。
8B モデルを NF4 量子化した状態でも数 GB 単位の RAM を消費します。
16GB 以上の RAM を推奨します。

YAML 1 ファイルで始める最小構成

Soup の売りのひとつは、バッチサイズ・量子化・学習率といったハイパーパラメータを自動で決めてくれる点です。
「設定項目が多すぎて最初の一歩が踏み出せない」という状況を避けるための設計思想で、その結果として最小 YAML は驚くほど短くなります。

実際に動く最小構成はこのくらいです。

model: meta-llama/Llama-3.1-8B   # 使用するベースモデル
dataset: ./data/train.jsonl       # 学習データのパス(JSONL 形式)
epochs: 3                         # 学習エポック数
output: ./output/my-adapter       # 学習済みアダプタの保存先
lora_rank: 16                     # LoRA のランク(小さいほど軽量・大きいほど表現力が上がる)

これだけです。
量子化の方式・バッチサイズ・学習率は Soup が自動で選択します。

データセットの形式は JSONL です。
1 行が 1 サンプルで、instruction と output のペアを持つ形が基本になります。

{"instruction": "社内の有給申請はどこから行いますか?", "output": "社内ポータルの『申請フォーム』から行えます。承認フローは直属の上長→人事部の順です。"}
{"instruction": "プロジェクト管理ツールのログイン URL を教えてください。", "output": "https://pm.example.internal からアクセスできます。初回ログインは社員番号と仮パスワードを使用してください。"}

社内ドメイン適応のシナリオで考えると、データ量よりも 質を優先する ことが重要です。
「正しい instruction と正確な output のペア」を丁寧に作ることが、学習結果に直結します。
数十サンプルから試すことは可能ですが、サンプル数が少ないほど 1 件あたりの品質が結果を左右します。
フォーマットが崩れているサンプルが混入すると学習が安定しないので、事前に目視確認するか簡単なバリデーションスクリプトを通しておくと安心です。

実行と学習ログの読み方

設定ファイルができたら、あとは 1 コマンドです。

soup train config.yaml

実行するとエポックごとに loss の値がログに流れてきます。
基本的な見方は「loss が下がり続けているか」です。
最初のエポックで大きく下がり、2〜3 エポック目にかけて緩やかに収束していくのが健全な推移です。
たとえば 2.5 → 1.8 → 1.4 のように単調に下がっていれば、学習は進んでいます。

注意が必要なのは 過学習の兆候 です。
学習データに対する loss は下がり続けているのに、検証データに対する loss が途中から上昇し始めたら、モデルが学習データを丸暗記し始めているサインです。
エポック数を減らすか、データを増やすかで対処します。

所要時間についてはデータ量・モデル・ストレージ速度に大きく依存するため、具体的な数字を出すのが難しいところです。
レイヤーストリーミングの転送コストがある分、VRAM にモデルを常駐させる通常の学習より時間はかかります。
まず手元にある小さいデータセットで走らせてみて、自分の環境での感覚をつかむのが一番早いです。

loss がまったく下がらないとき、最初に確認すべきポイントが 3 つあります。

  • データ量と品質: サンプル数が極端に少ない、または instruction と output のペアが崩れていないか
  • JSONL のフォーマット: パースエラーが出ていないか、エンコーディングが UTF-8 になっているか
  • エポック数: 1 エポックだけでは変化が見えにくい場合がある。3〜5 エポック試してから判断する

この順番で確認すると、大抵のケースは原因を特定できます。

unsloth・axolotl との設定コスト比較

Soup・unsloth・axolotl はいずれも LoRA ファインチューニングを手軽にするためのツールですが、「最初の 1 回を動かすまでの摩擦」がかなり違います。
優劣の話ではなく、ユースケースに合わせた選択の話として整理します。

axolotl は YAML ベースの設定ファイルを使いますが、最小構成でも数十行規模になります。
データセット形式・トークナイザー設定・LoRA パラメータ・学習率スケジューラなど、明示的に指定すべき項目が多く、慣れるまでに時間がかかります。
その分、マルチ GPU(DeepSpeed ZeRO-2/3、FSDP)や大規模モデルへのスケールアウトに強く、チームで再現性を担保しながら本番運用するには向いています。

unsloth は Python スクリプトベースのアプローチで、ノートブック上でインタラクティブに試しやすいのが特徴です。
速度と VRAM 効率に強みがあり、単一 GPU 環境での学習スループットは高い水準です。
ただし設定をコードとして書くため、チームで共有・バージョン管理するときに「どのスクリプトが正しいか」の管理コストが発生します。

Soup の最小 YAML は前述のとおり 5〜6 行です。
バッチサイズ・量子化・学習率の自動決定により、「設定を間違えて動かない」という状況が起きにくい設計になっています。
設定ファイルが短ければ Git 管理も楽で、チームメンバーへの共有も簡単です。

Soup が向かないケースも正直に書いておきます。
マルチ GPU でのスケールアウトが必要な場合、トレーニングループを細かくカスタマイズしたい場合(カスタム loss 関数・独自のスケジューラなど)は、axolotl か unsloth の方が適しています。
Soup はあくまで「手元の 1 枚の GPU でドメイン適応を素早く試す」という用途に最適化されたツールです。

社内用語や社内文書に特化した小型モデルを自社 GPU で育てたい、クラウド API に依存せずローカルで完結させたい、でも設定の複雑さで挫折したくない、という状況であれば、Soup から始めるのはかなり合理的な選択です。
まず動かして、物足りなくなったら axolotl や unsloth に移行する、というステップアップの仕方も十分ありだと思います。


株式会社ホコサキは、山口県宇部を拠点に Web 制作・業務システム開発・AI 活用支援を手がけています。
ローカル LLM の導入や社内ドメイン適応のファインチューニングについて相談したい場合は、お気軽にご連絡ください。
詳しくは お問い合わせページ からどうぞ。