8B のオープンウェイトモデルは、レンタルした 24 GB の GPU 1 枚で、自分のデータを使って QLoRA でファインチューニングできます。よくある 1 回の学習なら費用は $1 未満です。難しい問題はその前にあります。そもそもファインチューニングが正しい解決策なのか(事実を扱うなら、たいていは検索のほうが有利です)、そして他人が所有するマシンの上でデータをどう非公開に保つかです。
このガイドではその両方を扱い、続いてモデルサイズ別に必要な VRAM、現在のツール、動く学習スクリプト、費用の計算例、学習結果の提供方法を説明します。内容はすべて 2026 年 9 月に確認したもので、出典は最後にあります。
ファインチューニングか、RAG か、プロンプトの改善か
ファインチューニングはモデルの振る舞いを変えます。事実を教える方法としては向いていません。Ovadia らは知識の注入について両者を比べ、RAG は教師なしファインチューニングを「一貫して上回る」こと、しかも「学習中に触れた既存の知識でも、まったく新しい知識でも」そうであることを示しました。彼らのまとめはこうです。LLM はファインチューニングで新しい事実を覚えるのが苦手です。
ですから、何かを借りる前にこの判断の流れをたどってください。
ファインチューニングする正当な理由には、次のようなものがあります。
- 厳密な出力形式。 毎回のプロンプトに 1 ページ分の指示を書かなくても、呼び出しのたびに自社のスキーマどおりに項目を抽出させる。
- 文体と口調。 自社のチームらしいサポートの返信や、決まった構成のレポート。
- 小さなモデルに任せる特定のタスク。 1 つの仕事なら、調整した 8B モデルで大きな汎用モデルを置き換えられます。安いハードウェアで提供するときに効いてきます。
- プロンプトの短縮。 重みに学習させた振る舞いは、リクエストのたびに繰り返す必要がありません。
LoRA と QLoRA
フルファインチューニングはすべての重みを更新するので、GPU はモデルに加えて、すべての重みの勾配とオプティマイザーの状態を保持しなければなりません。LoRA はベースモデルを固定し、層の横に置いた小さな低ランク行列を学習します。元の論文では、GPT-3 175B を Adam でフルファインチューニングする場合と比べて、学習するパラメーターが 1 万分の 1、GPU メモリが 3 分の 1 になったと報告されています。
QLoRA はさらに進めて、固定したベースモデルを 4 ビットの NF4 精度で読み込み、アダプターだけを 16 ビットで学習します。Dettmers らはこれを使って、65B のモデルを 48 GB の GPU 1 枚でファインチューニングし、しかも「16 ビットのフルファインチューニングと同等のタスク性能を保って」いました。この論文で追加された 3 つの仕組みは、今もツールで使われています。NF4 データ型、量子化定数の二重量子化、そしてメモリの急増を吸収するページングオプティマイザーです。
どちらでも、結果はアダプターです。いくつかのテンソルが入ったフォルダーで、変更していないベースモデルの上に適用します。別に持っておくことも、重みに統合することもできます。画像モデルでも同じ手法を使います。Stable Diffusion の LoRAなら、レンタルした 24 GB のカード 1 枚で、$10 を大きく下回る費用で学習できます。
必要な VRAM
Unsloth は、ファインチューニングに必要な最小 VRAM をモデルサイズ別の表で公開しています。以下は同社のメモリ最適化を使った場合の数字です。素の Hugging Face での学習ではもっと必要になり、シーケンスが長くなったりバッチが大きくなったりすれば、どの行も数字が上がります。
| モデルサイズ | QLoRA(4 ビット) | LoRA(16 ビット) | QLoRA が余裕で収まるレンタル GPU |
|---|---|---|---|
| 3B | 3.5 GB | 8 GB | 12 GB 以上ならどれでも |
| 8B | 6 GB | 22 GB | RTX 3090 / 4090(24 GB) |
| 14B | 8.5 GB | 33 GB | RTX 3090 / 4090(24 GB) |
| 32B | 26 GB | 76 GB | 48 GB のカード(RTX A6000、A40、L40S) |
| 70B | 41 GB | 164 GB | 80 GB のカード(A100、H100) |
私の基本は、RTX 4090 で 8B か 14B のモデルです。2,048 トークンのシーケンスと妥当なバッチサイズの余裕を残せる、最も安いレンタル GPU で、この範囲のモデルなら学習後の提供も簡単です。提供に使う GPU の VRAM からベースモデルを選ぶなら、GPU の VRAM に収まる AI モデルをご覧ください。
ツールを選ぶ:TRL、Unsloth、Axolotl
3 つともオープンソースで、どれも LoRA と QLoRA に対応しています。
| ツール | 使い方 | 強み | 注意点 |
|---|---|---|---|
| Hugging Face TRL + PEFT | Python(SFTTrainer) | 基準となる実装。同じ API で DPO や GRPO なども使える | 同じ学習でも Unsloth よりメモリを多く使う |
| Unsloth | Python、または Unsloth Studio の Web UI | 2 倍速く VRAM を 70% 削減とうたう。GGUF に直接エクスポートできる | Studio UI は AGPL-3.0(コアは Apache 2.0) |
| Axolotl | YAML ファイル 1 つ、axolotl train config.yml | マルチ GPU(FSDP、DeepSpeed)、豊富なレシピ | Python 3.11 以上と PyTorch 2.11 以上が必要 |
2026 年 9 月時点で TRL はバージョン 1.14、PEFT は 0.21 です。Unsloth には Python 3.11〜3.13 と、CUDA Compute Capability 7.0 以上の NVIDIA GPU(V100、T4、RTX 20 シリーズ以降)が必要です。Axolotl は Python 3.12 と PyTorch 2.12.1 を推奨しています。
すべての行を理解したいなら TRL、VRAM が足りないか GGUF へのエクスポートを 1 回の呼び出しで済ませたいなら Unsloth、設定を変えて何度も学習したり複数の GPU に移ったりするなら Axolotl です。以下のスクリプトでは TRL を使います。すべての要素が見える最短の方法だからです。
データを準備する
TRL の SFTTrainer は、チャット API のリクエストと同じ形の会話を読み込みます。train.jsonl に 1 行 1 つの JSON オブジェクトを書きます。
{"messages": [{"role": "system", "content": "Extract the invoice fields as JSON."}, {"role": "user", "content": "Invoice 4471 from Norden AB, due 12 March, total 1,250 EUR"}, {"role": "assistant", "content": "{\"invoice_id\": \"4471\", \"supplier\": \"Norden AB\", \"due\": \"2026-03-12\", \"total\": 1250, \"currency\": \"EUR\"}"}]}
実際的なルールです。
- 量より質。 一貫していて正しい例が数百〜数千件あれば、ノイズの多い数万件に勝ります。データの間違いは、お金を払って教え込む振る舞いになります。
- 本番に合わせる。 アプリケーションが実際に送るシステムプロンプトと入力形式を使ってください。
- 5〜10% を取り分けておく。 モデルに一度も学習させない例を残し、ベースモデルと調整後のモデルを並べて比べるのに使います。
- 不要なものは取り除く。 名前、メールアドレス、口座番号、ID が形式の学習に役立つことはまずありません。データが自分のコンピューターを出る前に、それらしいプレースホルダーに置き換えます。
最後のルールは、レンタルするマシンだけの話ではありません。Carlini らは GPT-2 から、名前、電話番号、メールアドレスを含む数百の学習データを原文のまま抽出しました。中には学習データの 1 文書にしか出てこないものもありました。ファインチューニングしたモデルは、学習した内容を後でそれを使う誰にでも繰り返すことがあります。
レンタルしたマシンでデータを非公開に保つ
GPU マーケットプレイスでは、コンピューターの所有者は他人です。Vast.ai ははっきりこう書いています。「クライアントは非特権の Docker コンテナで隔離され、自分のデータにしかアクセスできません」、そして「プロバイダーのセキュリティには大きなばらつきがあります」。この隔離はほかの借り手からあなたを守ります。物理的にアクセスでき、ホストの root 権限を持つ人からは守りません。
非公開のデータを扱うなら、次のようにします。
- 審査済みのデータセンターのホストを選ぶ。 Vast.ai の Secure Cloud のプロバイダーは「ISO 27001 認証を持ち、Tier 3/4 のデータセンター基準を満たす、審査済みのデータセンター」で、Vast は機密性の高い作業にはこちらを勧めています。RunPod の Secure Cloud は T3/T4 のデータセンターで動いており、Community Cloud は個人のプロバイダーにつながります。データセンターの区分は 1 時間あたりの料金が高くなりますが、ここでは払う価値があります。
- アップロードするのはクリーニング済みのデータセットだけにし、 SSH(
rsync -avPまたはscp)で送ります。途中で公開バケットや共有リンクに置かないでください。 - ログは手元にとどめる。 TRL 1.14 では
report_toのデフォルトが"none"なので、自分で有効にしない限り実験管理ツールには何も送られません。非公開データで学習したアダプターでpush_to_hubを呼ばないでください。 - 結果を取り出してから、インスタンスを削除する。 アダプターと評価結果をダウンロードし、トークンを使ったなら Hugging Face からログアウトし(
hf auth logout)、インスタンスとボリュームを削除します。Vast.ai では、ストレージは停止ではなく削除するまで課金され、保持され続けます。
コンテナ内でファイルを消しても、ホストのディスクが消去される保証はありません。本当の防御はステップ 1 と 2 です。誰がハードウェアを持つかを選び、その相手に送るものを最小限にすることです。詳しくは公開 GPU ノードでデータセットを守る方法をご覧ください。社内のポリシーが第三者のハードウェアを一切認めないなら、同じスクリプトを自前の 24 GB のカードで実行できます。
学習する:TRL による QLoRA スクリプト
RTX 3090 か 4090 を載せたレンタルの Linux マシンで次を実行します。
python -m venv venv && source venv/bin/activate
pip install torch trl peft bitsandbytes datasets
続いて train.py です。TRL の PEFT ドキュメントにある QLoRA のパターンに沿っています。Qwen3-8B は Apache 2.0 でアクセス制限がないので、Hugging Face のトークンは不要です。
import torch
from datasets import load_dataset
from peft import LoraConfig
from transformers import BitsAndBytesConfig
from trl import SFTConfig, SFTTrainer
dataset = load_dataset("json", data_files="train.jsonl", split="train")
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True,
)
peft_config = LoraConfig(
r=16,
lora_alpha=32,
lora_dropout=0.05,
target_modules="all-linear",
task_type="CAUSAL_LM",
)
args = SFTConfig(
output_dir="out",
num_train_epochs=3,
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
learning_rate=2e-4,
lr_scheduler_type="cosine",
warmup_steps=20,
max_length=2048,
bf16=True,
logging_steps=10,
save_strategy="epoch",
model_init_kwargs={"dtype": torch.bfloat16},
)
trainer = SFTTrainer(
model="Qwen/Qwen3-8B",
args=args,
train_dataset=dataset,
quantization_config=bnb_config,
peft_config=peft_config,
)
trainer.train()
trainer.save_model("out/adapter")
重要な設定は次のとおりです。
learning_rate=2e-4。 TRL のドキュメントは、QLoRA では通常のファインチューニングの約 10 倍の学習率を勧めています。学習損失が下がるのに評価損失が上がるなら過学習です。エポック数を減らしてください。r=16、target_modules="all-linear"。 すべての線形層にアダプターを付けます。Unsloth のベンチマークと同じ構成です。形式や文体ならランク 16 で十分で、難しいタスクでは上げます。max_length=2048。 これより長い例は切り捨てられます。データのトークン長を確認してください。上限を長くするとそのぶん VRAM が必要です。- 実効バッチサイズ 16(4 × 勾配累積 4 ステップ)。メモリが足りなければ、
per_device_train_batch_sizeを下げ、その分だけ累積ステップを上げて積を保ちます。
マシンを止める前に、取り分けておいた例をベースモデルと調整後のモデルの両方に通して比べてください。お金をかけた意味があったかどうかがわかるのは、このテストだけです。
費用
学習時間は、総トークン数 ÷ スループットです。ホスティング会社の GigaGPU は、RTX 4090 での Llama 3.1 8B の QLoRA 学習で毎秒約 3,500 トークンという実測値を公開しています。Qwen3-8B でも同程度と仮定すると、次のようになります。
小規模な学習: 2,000 件 × 600 トークン × 3 エポック = 360 万トークン。3,600,000 ÷ 3,500 = 1,029 秒、約 17 分です。
| 作業 | 時間 |
|---|---|
| 環境のセットアップ | 10 分 |
| Qwen3-8B(重み 16.4 GB)のダウンロードとデータのアップロード | 10 分 |
| 学習 | 17 分 |
| 取り分けたデータでベースモデルと調整後モデルを比較 | 15 分 |
| 統合、エクスポート、ダウンロード、インスタンスの削除 | 15 分 |
| 合計 | 67 分(1.12 時間) |
- Vast.ai の RTX 4090($0.31/時):1.12 × $0.31 = $0.35
- RunPod の RTX 4090(料金ページの定価 $0.74/時):1.12 × $0.74 = $0.83
大規模な学習: 20,000 件 × 1,000 トークン × 2 エポック = 4,000 万トークン ÷ 3,500 = 11,429 秒、約 3.2 時間です。同じような付帯作業に 50 分かかるとして合計 4.0 時間、Vast.ai で $1.24、RunPod で $2.97 です。
32B のモデルなら、2026 年 9 月時点で RunPod の 48 GB のカードは $0.49/時(A40)、$0.53/時(RTX A6000)、$1.09/時(L40S)です。これらのカードでの 32B の QLoRA のスループットは公開された数字が見当たらないので、50 ステップだけ実行してログから 1 ステップの時間を読み取り、長い学習を始める前に同じ掛け算をしてください。
料金は、RunPod の料金ページと、Vast.ai については getdeploying.com のトラッカーから取った 2026 年 9 月の数字です。Secure やデータセンターの区分は、コミュニティの最安の提示価格より高くなります。全体像は GPU レンタル料金比較にまとめています。
学習結果を提供する
方法は 2 つあります。アダプターを別に持つか、モデルに統合するかです。
vLLM でアダプターを別に持つ。 vLLM はベースモデルと一緒に LoRA アダプターを読み込み、OpenAI 互換サーバー上でそれぞれを 1 つのモデル名として公開します。
vllm serve Qwen/Qwen3-8B --enable-lora --lora-modules invoices=./out/adapter
クライアントは "model": "invoices" を送ります。複数のアダプターが、1 枚の GPU 上の 1 つのベースモデルを共有できます。
統合して Ollama で動かす。 アダプターをフル精度の重みに統合し、llama.cpp で GGUF に変換して量子化し、インポートします。
import torch
from peft import AutoPeftModelForCausalLM
from transformers import AutoTokenizer
model = AutoPeftModelForCausalLM.from_pretrained("out/adapter", dtype=torch.bfloat16)
model.merge_and_unload().save_pretrained("merged")
AutoTokenizer.from_pretrained("Qwen/Qwen3-8B").save_pretrained("merged")
python llama.cpp/convert_hf_to_gguf.py merged --outfile invoices-bf16.gguf --outtype bf16
./llama.cpp/build/bin/llama-quantize invoices-bf16.gguf invoices-Q4_K_M.gguf Q4_K_M
echo "FROM ./invoices-Q4_K_M.gguf" > Modelfile
ollama create invoices -f Modelfile
Unsloth なら統合と GGUF へのエクスポートが 1 回の呼び出しで済みます(model.save_pretrained_gguf("dir", tokenizer, quantization_method="q4_k_m"))。ドキュメントには、エクスポート後に回答がおかしくなる一番多い原因はチャットテンプレートの間違いだという注意があります。学習に使ったテンプレートで提供してください。Ollama、vLLM、TGI の使い分けは RTX 4090 での推論ベンチマークで扱っています。
GPUFlow の出番
GPUFlow では学習はできません。貸し出すのはプロバイダーの GPU 上の OpenAI 互換 API で、シェルも SSH もファイルへのアクセスもありません。ファインチューニングしたモデルを提供することもできません。借り手はモデルをアップロードできず、使えるのは各プロバイダーが(たいていは Ollama で)インストールしたモデル、たとえば qwen2.5:7b や llama3.1:8b です。
役に立つのは、これらすべての前の段階です。既存のオープンモデルに良いプロンプトを与えるだけで用が足りるかを、数セントで確かめられます。判断フローの中で一番安い結末です。その確認にはテスト用のデータを使い、このガイドで扱っている非公開のデータは使わないでください。レンタル中、プロンプトと回答はプロバイダーのマシンを平文で通ります。使い方は API クイックスタートに、既存のツールとの接続はアプリでキーを使う方法にあります。
出典
すべて 2026 年 9 月に確認しました。
- 論文:Hu et al., LoRA、Dettmers et al., QLoRA、Ovadia et al., Fine-Tuning or Retrieval?、Carlini et al., Extracting Training Data from Large Language Models
- Hugging Face TRL:SFT Trainer、PEFT との統合と QLoRA
- Unsloth:要件と VRAM の表、ベンチマーク、GGUF への保存、GitHub
- GitHub の Axolotl
- モデル:Qwen3-8B のモデルカード
- 学習スループット:GigaGPU、RTX 4090 でのファインチューニング
- ホストとセキュリティ:Vast.ai のセキュリティ FAQ、Vast.ai の料金、RunPod の Pod の概要
- 料金:RunPod の料金、getdeploying.com(Vast.ai、RTX 4090)
- 提供:vLLM の LoRA アダプター、llama.cpp の quantize、Ollama へのインポート
- GPUFlow:API クイックスタート