🧠 0からLLM — 目指せDeepSeek
MoEモデルを基礎から構築する完全ガイド — HuggingFace活用・日本語対応 2026年版
🎯 ミッション: 0からLLMを作ってDeepSeekを目指す
なぜ今、自作LLMなのか?
2024〜2026年、オープンソースLLMの世界に革命が起きた。中国のDeepSeekが公開した DeepSeek V3(671B MoEモデル)は、GPT-4oに匹敵する性能を 大幅に少ない計算コストで実現し、MIT相当のライセンスで公開した。
この成果を受けて、日本の大手企業も素早く動いた。
- 楽天AI: DeepSeek V3をベースモデルとしてフォークし、大量の日本語データで追加学習を行った RakutenAI-2.0を開発。日本語・英語・コードの三言語対応を実現。 フルスクラッチではなく「巨人の肩に乗る」戦略で短期間での高品質モデル構築に成功。
- サカナAI: 独自の進化的モデルマージ手法(EvoLLM)を開発。 既存のオープンソースモデルを複数組み合わせ、進化アルゴリズムで最適なマージ比率を探索する アプローチで日本語高性能モデルを構築。少ない計算資源で高品質なモデルを作る革新的手法として注目。
3つのルート
① 完全スクラッチ
PyTorchでTransformerを0から実装。nanoGPTが定番の出発点。最も学習効果が高い。
難易度: ★★★☆☆
② Llamaフォーク
MetaのLlama 3.xをベースに日本語データで追加学習。実用的な日本語LLMを最短で作れる。
難易度: ★★☆☆☆
③ DeepSeekフォーク
DeepSeekをベースにMoE構造を活かした学習。楽天・サカナAIが実証済みのアプローチ。
難易度: ★★★★☆
このページで学べること
- Transformerアーキテクチャの仕組みとLLMの基礎知識
- MoE(Mixture of Experts)の構造と利点
- nanoGPTで125Mモデルを作る具体的な手順
- Llama 3.xにLoRA/QLoRAで日本語ファインチューニングする方法
- DeepSeek V2-Liteをフォークしてカスタムモデルを作る手順
- HuggingFaceの日本語データセット・モデルの選び方
- RTX 3090 1〜2枚で始められる実践的な学習環境の構築法
前提知識
PythonとPyTorchの基礎(テンソル操作、nn.Module)があれば十分です。 線形代数(行列積)の直感的な理解があると理解が深まります。 機械学習の深い知識は不要 — このページを読みながら学べます。
ハードウェア要件の目安
| 規模 | パラメータ数 | 必要VRAM | 推奨GPU | 学習時間目安 |
|---|---|---|---|---|
| 超小規模(実験) | 125M〜1B | 4〜8GB | RTX 3060 / GTX 1080 | 数時間〜1日 |
| 小規模 | 1B〜7B | 16〜24GB | RTX 3090 / RTX 4090 | 2〜7日 |
| 中規模 | 7B〜30B | 40〜80GB | A100 40GB×2〜4 | 1〜4週間 |
| 大規模 | 30B〜70B | 160GB以上 | A100 80GB×4〜8 | 1〜3ヶ月 |
| 超大規模 | 70B〜671B | 1TB以上 | H100×数十〜数百枚 | 数ヶ月 |
📚 LLMの基礎: Transformerアーキテクチャ
Transformerの仕組み
現代のLLMは全てTransformerアーキテクチャをベースにしています。 2017年にGoogleが発表した「Attention is All You Need」論文が起点で、 今もその基本構造は変わっていません。
Self-Attention
文中の各トークンが他の全トークンとの「関連度」を計算するメカニズム。 「猫が魚を食べた」→「食べた」が「猫」と「魚」の両方に注目できる。 Query、Key、Value の3つの行列を用いた内積計算で実現。
FFN(Feed-Forward Network)
各トークンに独立して適用される2層のMLPネットワーク。 Attentionで「どこを見るか」を決めた後、FFNで「何を考えるか」を処理する。 パラメータの大半はここに含まれる(MoEもここを分散化する)。
Layer Normalization
各層の出力を正規化することで学習を安定させる。 現代のLLMはPre-LN(層の前に適用)が主流。 残差接続(Residual Connection)と組み合わせて勾配消失を防ぐ。
GPT系(Decoder-only)が現在の主流
Transformerには Encoder-Decoder(T5, BART)と Decoder-only(GPT, Llama, DeepSeek)の2系統があります。 テキスト生成に特化した Decoder-only が現在の主流です。 Causal Attention(過去のトークンのみ参照)により、自己回帰的にトークンを1つずつ生成します。
トークナイザーの役割
LLMはテキストをそのまま処理できません。テキストをトークン(数値ID)に変換する 「トークナイザー」が必要です。
BPE(Byte Pair Encoding)
頻出する文字ペアを繰り返し結合してサブワード語彙を作る手法。 GPT-2、LlamaのTokenizerで採用。英語に最適化されている。
⚠️ 日本語は英語向けBPEだと1文字ずつ分割されてしまい、 同じ意味を表すのに英語の3〜4倍のトークンが必要になる。
SentencePiece
Googleが開発した言語非依存のサブワードトークナイザー。 スペースなしでも動作するため日本語に向いている。 rinna、ELYZA等の日本語LLMで採用。
✅ 日本語専用のSentencePieceを学習すれば、 「東京」を1〜2トークンで表現できる。
パラメータ数とモデルサイズの関係
| パラメータ数 | fp16サイズ | fp32サイズ | 備考 |
|---|---|---|---|
| 125M | 0.25GB | 0.5GB | nanoGPT規模、実験に最適 |
| 1B | 2GB | 4GB | モバイルデプロイ可能な最小クラス |
| 7B | 14GB | 28GB | Llama 3.1 8B相当。RTX 3090 1枚で推論可能 |
| 13B | 26GB | 52GB | RTX 3090 1枚+オフロードで推論可能 |
| 70B | 140GB | 280GB | A100 80GB×2枚必要 |
| 671B(MoE) | 〜80GB(活性化分のみ) | - | DeepSeek V3。活性化は37B相当 |
※ 推論時のVRAM使用量はKVキャッシュ分が追加で必要。学習時はさらに勾配・オプティマイザ状態で2〜4倍必要。
🔀 MoE(Mixture of Experts)完全解説
MoEとは何か
通常のDenseモデルでは全てのFFN層が毎回活性化されます。 MoEでは1つの大きなFFNの代わりに複数の小さなFFN(Expert)を用意し、 入力に応じて一部のExpertだけを選択・活性化します。 DeepSeek V3では671Bのパラメータを持ちますが、推論時に実際に使うのは約37B相当のみです。
MoEの構成要素
Expert(FFN)
それぞれ独立したFFNネットワーク。 DeepSeek V3では256個のExpertが存在し、 各Expertが特定の知識・タスクに特化するよう学習される。
Router(ゲーティング関数)
各トークンに対して「どのExpertを使うか」を決める小さなネットワーク。 各Expertへのスコアを計算し、Top-K個のExpertを選択する。 Routerの学習が安定しないとExpertの偏りが発生する。
Top-K選択
Routerが全Expertにスコアを付け、上位K個のExpertのみを活性化する仕組み。 DeepSeek V3はTop-8(256個中8個を使用)。 KとExpert総数のバランスがモデル性能を左右する。
Dense vs MoE 比較
| 項目 | Dense モデル | MoE モデル |
|---|---|---|
| アーキテクチャ | 全FFN層が毎回活性化 | 一部のExpertのみ活性化(Top-K) |
| 総パラメータ数 | そのまま全て使用 | 大きいが推論時は一部のみ |
| 推論時の計算量 | パラメータ数に比例 | 活性化パラメータ数に比例(大幅削減) |
| メモリ使用量 | モデル全体のサイズ | モデル全体のサイズ(ロードは全体) |
| 学習の難しさ | 比較的シンプル | Router最適化・負荷分散が難しい |
| 代表モデル | GPT-4, Llama 3.1, Gemma | DeepSeek V3, Mixtral, GPT-4(推定) |
楽天AI・サカナAIがMoEを採用した理由
楽天AI(RakutenAI-2.0): DeepSeek V3(671B MoE)をベースに採用した最大の理由は「推論コストの低さ」。 671Bの総パラメータを持ちながら実際の計算は37B相当なので、 サービス提供時の GPU コストがDense 70B モデルとほぼ同等に抑えられる。 日本語・英語・コードの3言語に特化したデータで追加学習することで、 汎用性を保ちながら日本語性能を大幅向上させた。
サカナAI(EvoLLM): 独自のモデルマージ手法で複数のオープンソースモデルを組み合わせる。 進化的アルゴリズムで最適なマージ比率を探索することで、 フルスクラッチの事前学習なしに高性能な日本語モデルを構築。 必要な計算資源が劇的に少なく、少人数チームでも大企業に対抗できるアプローチ。
MoEの疑似コード(概念理解用)
class MoELayer(nn.Module):
def __init__(self, d_model, n_experts, top_k):
super().__init__()
self.router = nn.Linear(d_model, n_experts) # ゲーティング
self.experts = nn.ModuleList([FFN(d_model) for _ in range(n_experts)])
self.top_k = top_k
def forward(self, x):
# x: (batch, seq_len, d_model)
scores = self.router(x) # 全Expertのスコア計算
weights, indices = scores.topk(self.top_k) # Top-K Expert選択
weights = weights.softmax(dim=-1) # 重みの正規化
output = torch.zeros_like(x)
for i, expert in enumerate(self.experts):
# 各Expertを担当するトークンだけを処理
mask = (indices == i).any(dim=-1)
if mask.any():
output[mask] += weights[mask, i:i+1] * expert(x[mask])
return output🏗️ ルート①: 完全スクラッチで作る
Andrej Karpathy(元OpenAI)が公開した nanoGPTから始めるのが定番です。 700行のPyTorchコードでGPT-2相当のモデルが実装されており、 Transformerの仕組みを実際に手を動かしながら理解できます。
手順
ステップ1: SentencePieceで日本語トークナイザー作成
日本語コーパスを用意し、SentencePieceでBPEモデルを学習します。
pip install sentencepiece
# train_tokenizer.py
import sentencepiece as spm
spm.SentencePieceTrainer.train(
input='japanese_corpus.txt', # 学習テキスト(1行1文推奨)
model_prefix='ja_tokenizer', # 出力ファイル名
vocab_size=32000, # 語彙サイズ(32k〜64kが一般的)
character_coverage=0.9999, # 日本語は0.9999以上推奨
model_type='bpe', # BPEを使用
pad_id=3,
bos_id=1,
eos_id=2,
unk_id=0,
)
# 使用例
sp = spm.SentencePieceProcessor()
sp.load('ja_tokenizer.model')
tokens = sp.encode('東京でラーメンを食べた', out_type=str)
# ['▁東京', 'で', 'ラーメン', 'を', '食べた'] ← 自然な分割ステップ2: HuggingFaceから日本語コーパスを取得
pip install datasets
from datasets import load_dataset
# 日本語Wikipediaを取得(最もクリーンなコーパス)
dataset = load_dataset('wikipedia', '20231101.ja', split='train')
# 約182万記事、約3GB
# より大規模なWebコーパス
dataset = load_dataset('mc4', 'ja', split='train', streaming=True)
# ストリーミングで大容量を扱える
# テキストを1ファイルに保存
with open('corpus.txt', 'w', encoding='utf-8') as f:
for item in dataset:
f.write(item['text'].replace('\n', ' ') + '\n')ステップ3: PyTorchでTransformerを実装(核心部分)
import torch
import torch.nn as nn
import math
class CausalSelfAttention(nn.Module):
def __init__(self, d_model, n_heads, max_len=2048):
super().__init__()
assert d_model % n_heads == 0
self.n_heads = n_heads
self.d_head = d_model // n_heads
self.qkv = nn.Linear(d_model, 3 * d_model, bias=False)
self.proj = nn.Linear(d_model, d_model, bias=False)
# Causal mask(未来のトークンを見ない)
mask = torch.tril(torch.ones(max_len, max_len))
self.register_buffer('mask', mask)
def forward(self, x):
B, T, C = x.shape
q, k, v = self.qkv(x).split(C, dim=2)
q = q.view(B, T, self.n_heads, self.d_head).transpose(1, 2)
k = k.view(B, T, self.n_heads, self.d_head).transpose(1, 2)
v = v.view(B, T, self.n_heads, self.d_head).transpose(1, 2)
scale = 1.0 / math.sqrt(self.d_head)
att = (q @ k.transpose(-2, -1)) * scale
att = att.masked_fill(self.mask[:T, :T] == 0, float('-inf'))
att = att.softmax(dim=-1)
return (att @ v).transpose(1, 2).contiguous().view(B, T, C)
class TransformerBlock(nn.Module):
def __init__(self, d_model, n_heads, ffn_mult=4):
super().__init__()
self.ln1 = nn.LayerNorm(d_model)
self.attn = CausalSelfAttention(d_model, n_heads)
self.ln2 = nn.LayerNorm(d_model)
self.ffn = nn.Sequential(
nn.Linear(d_model, ffn_mult * d_model),
nn.GELU(),
nn.Linear(ffn_mult * d_model, d_model),
)
def forward(self, x):
x = x + self.attn(self.ln1(x)) # Attention + 残差接続
x = x + self.ffn(self.ln2(x)) # FFN + 残差接続
return x
class GPT(nn.Module):
def __init__(self, vocab_size, d_model=768, n_heads=12, n_layers=12, max_len=2048):
super().__init__()
self.tok_emb = nn.Embedding(vocab_size, d_model)
self.pos_emb = nn.Embedding(max_len, d_model)
self.blocks = nn.Sequential(*[TransformerBlock(d_model, n_heads) for _ in range(n_layers)])
self.ln_f = nn.LayerNorm(d_model)
self.head = nn.Linear(d_model, vocab_size, bias=False)
def forward(self, idx):
B, T = idx.shape
pos = torch.arange(T, device=idx.device)
x = self.tok_emb(idx) + self.pos_emb(pos)
x = self.blocks(x)
x = self.ln_f(x)
return self.head(x)
# 125Mパラメータ構成: d_model=768, n_heads=12, n_layers=12
model = GPT(vocab_size=32000, d_model=768, n_heads=12, n_layers=12)ステップ4: 学習ループ(AdamW + cosine schedule)
import torch
from torch.optim.lr_scheduler import CosineAnnealingLR
optimizer = torch.optim.AdamW(model.parameters(), lr=3e-4, weight_decay=0.1)
scheduler = CosineAnnealingLR(optimizer, T_max=10000, eta_min=3e-5)
model.train()
for step in range(max_steps):
# Gradient Accumulation(メモリ節約)
for micro_step in range(grad_accum_steps):
x, y = get_batch() # (B, T) のトークン列
logits = model(x) # (B, T, vocab_size)
loss = F.cross_entropy(logits.view(-1, vocab_size), y.view(-1))
loss = loss / grad_accum_steps
loss.backward()
# 勾配クリッピング(学習安定化)
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
optimizer.step()
scheduler.step()
optimizer.zero_grad()
if step % 100 == 0:
ppl = torch.exp(loss * grad_accum_steps).item()
print(f"step {step}: loss={loss.item()*grad_accum_steps:.4f}, ppl={ppl:.1f}")推奨HuggingFaceデータセット(事前学習用)
| データセット名 | サイズ | ライセンス | 特徴 |
|---|---|---|---|
| mc4 (ja) | 約200GB | ODC-By | 大規模日本語Webコーパス。CCから抽出 |
| wikipedia (ja) | 約3GB | CC BY-SA 4.0 | 日本語Wikipedia全記事 |
| oscar-corpus/OSCAR-2301 (ja) | 約85GB | CC0/利用規約要確認 | CommonCrawlから抽出した多言語コーパス |
| cc100 (ja) | 約84GB | MIT | CommonCrawl 100言語、日本語含む |
学習時間の目安
RTX 3090 (VRAM 24GB) 1枚で 125M モデル、日本語Wikipedia(3GB)を学習する場合: バッチサイズ16、シーケンス長512、10エポックで 約2〜3日。 Google Colab Pro なら無料枠でも1エポック程度は回せる。
🍴 ルート②: Llamaフォークで日本語LLMを作る
MetaのLlama(現在はLlama 3.2まで公開)をベースにする方法は、 完全スクラッチよりはるかに少ない計算資源と時間で 高品質な日本語LLMを作れます。ELYZA, CyberAgent CALM, Rinna等の著名な日本語LLMがこのアプローチを採用。
成功事例
- ELYZA: Llama 2 7Bをベースに日本語特化。2023年に公開、現在も改良継続中
- CyberAgent CALM3-22B: 独自アーキテクチャ+大規模日本語データ。Apache 2.0で商用OK
- Rinna: 日本語GPT-NeoX系列から始まり、Llamaフォーク版も公開
- PLaMo(Preferred Networks): Llamaアーキテクチャベースの日本語特化モデル
LoRA/QLoRAとは
LoRA(Low-Rank Adaptation)
全パラメータを更新せず、低ランク行列ペアを追加して学習する手法。 元のパラメータは固定したまま、追加した小さなアダプタだけを学習。 フルファインチューニングの1/10以下のメモリで学習可能。
QLoRA(Quantized LoRA)
LoRAにモデルの4bit量子化を組み合わせた手法。 ベースモデルをNF4量子化してメモリを大幅削減。 RTX 3090(24GB)1枚で7Bモデルの学習が可能になる画期的な手法。
手順(QLoRAによる日本語ファインチューニング)
ステップ1: 必要なパッケージのインストール
pip install transformers datasets accelerate peft trl bitsandbytes
pip install flash-attn --no-build-isolation # 高速Attention(CUDA対応GPU必須)ステップ2: 4bit量子化でモデルをロード
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
import torch
model_id = "meta-llama/Llama-3.1-8B" # HuggingFaceのモデルID(要Meta申請)
# 4bit量子化の設定
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4", # NormalFloat4が精度と速度のバランス最良
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True, # さらにメモリ節約(推奨)
)
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(
model_id,
quantization_config=bnb_config,
device_map="auto", # 自動でGPU/CPUに配置
)ステップ3: LoRAアダプタを設定
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
# k-bit学習の準備(量子化モデルに必要)
model = prepare_model_for_kbit_training(model)
lora_config = LoraConfig(
r=16, # LoRAのランク(高いほど高精度だがメモリ増加)
lora_alpha=32, # スケールファクタ (通常 r*2)
target_modules=["q_proj", "v_proj", "k_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM",
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# trainable params: 約40M || all params: 8B || trainable%: 0.5%ステップ4: 日本語指示データの準備(Alpaca形式)
from datasets import load_dataset
# 日本語指示データセットをロード
dataset = load_dataset("kunishou/databricks-dolly-15k-ja", split="train")
# Alpaca形式のプロンプトテンプレート
def format_instruction(example):
if example.get("input"):
return f"""### 指示:
{example['instruction']}
### 入力:
{example['input']}
### 回答:
{example['output']}"""
else:
return f"""### 指示:
{example['instruction']}
### 回答:
{example['output']}"""
dataset = dataset.map(lambda x: {'"text": format_instruction(x)})
# ShareGPT形式(マルチターン会話)の場合
# {'conversations": [{'from": "human", "value": "質問"}, {'from": "gpt", "value": "回答"}]}
ステップ5: SFTTrainerで学習実行
from trl import SFTTrainer, SFTConfig
training_args = SFTConfig(
output_dir="./llama3-ja-lora",
num_train_epochs=3,
per_device_train_batch_size=2,
gradient_accumulation_steps=8, # 実効バッチサイズ = 2*8 = 16
learning_rate=2e-4,
lr_scheduler_type="cosine",
warmup_ratio=0.05,
fp16=True, # fp16混合精度学習
logging_steps=10,
save_strategy="epoch",
max_seq_length=2048,
report_to="wandb", # wandbでログ管理(オプション)
)
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=dataset,
dataset_text_field="text",
tokenizer=tokenizer,
)
trainer.train()
trainer.save_model("./llama3-ja-lora-final")(応用)ステップ6: DPOでアラインメント
SFT後にDPO(Direct Preference Optimization)を適用すると、より人間の好みに沿った回答を生成するようになります。
from trl import DPOTrainer, DPOConfig
# DPO用データ形式:
# {'prompt": "質問", "chosen": "良い回答", "rejected": "悪い回答"}
dpo_dataset = load_dataset("your-dpo-dataset")
dpo_config = DPOConfig(
beta=0.1, # KLペナルティ係数
output_dir="./llama3-ja-dpo",
num_train_epochs=1,
per_device_train_batch_size=2,
learning_rate=5e-5,
)
dpo_trainer = DPOTrainer(
model=model,
ref_model=None, # peft使用時はNoneでOK
args=dpo_config,
train_dataset=dpo_dataset,
tokenizer=tokenizer,
)
dpo_trainer.train()🚀 ルート③: DeepSeekフォークでMoEを作る
DeepSeek オープンソースモデル一覧
楽天AI・サカナAIのアプローチ詳細
楽天AI: RakutenAI-2.0
- ・DeepSeek V3(671B MoE)をベースとして選択
- ・日本語・英語・コードの3言語混合データで追加学習
- ・楽天独自の大規模日本語コーパス(ECサイトデータ等)を活用
- ・商用サービス向けに安全性チューニング(RLHF相当)
- ・推論コストをDense 37B相当に抑えつつ671B級の性能
サカナAI: EvoLLM / EvoVLM
- ・複数のOSSモデルを「モデルマージ」で組み合わせ
- ・進化的アルゴリズムで最適なマージ比率を自動探索
- ・事前学習不要 → 劇的に少ない計算コスト
- ・EvoVLM-JP: 視覚言語モデルにも同手法を適用
- ・研究成果としてNeurIPS等に論文発表
DeepSeek V2-Liteフォーク手順
いきなりDeepSeek V3(671B)を触るのは難しいので、 まずDeepSeek-V2-Lite(16B MoE、活性化2.4B)で練習します。 RTX 3090×2枚(VRAM 48GB)があれば学習可能です。
ステップ1: モデルのダウンロード
# HuggingFace CLIでダウンロード(約30GB)
pip install huggingface_hub
huggingface-cli download deepseek-ai/DeepSeek-V2-Lite \
--local-dir ./DeepSeek-V2-Lite \
--local-dir-use-symlinks False
# Pythonで確認
from transformers import AutoTokenizer, AutoModelForCausalLM
tokenizer = AutoTokenizer.from_pretrained("./DeepSeek-V2-Lite")
model = AutoModelForCausalLM.from_pretrained(
"./DeepSeek-V2-Lite",
torch_dtype=torch.bfloat16,
device_map="auto",
trust_remote_code=True # DeepSeekはtrust_remote_code必須
)ステップ2: MoE構造の確認
# モデル構造の確認
print(model.config)
# num_experts_per_tok: 6 ← Top-6 Expert選択
# n_routed_experts: 64 ← 計64個のExpert(うち共有Expert 2個)
# moe_intermediate_size: 1408
# Expert数の確認
for name, module in model.named_modules():
if 'expert' in name.lower():
print(f"{name}: {type(module).__name__}")ステップ3: 日本語データでファインチューニング
MoEモデルのLoRAは通常モデルと同じ手順で可能です。ただしRouterはLoRA対象外にすること。
from peft import LoraConfig, get_peft_model
lora_config = LoraConfig(
r=8,
lora_alpha=16,
# MoEのExpert内のLinear層を対象に(Routerは除外)
target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],
lora_dropout=0.05,
task_type="CAUSAL_LM",
)
model = get_peft_model(model, lora_config)
# DeepSpeed ZeRO-2で2GPU学習
# accelerate launch --num_processes=2 train.pyMoE特有の設定: 負荷分散ロス(Load Balancing Loss)
MoEの学習では特定のExpertに処理が偏る「Expertの崩壊」が起きやすい。 負荷分散ロスを追加することで全Expertが均等に使われるよう制御する。
# DeepSeek-V2の設定ファイル(config.json)
# "aux_loss_alpha": 0.001 ← 負荷分散ロスの係数
# この値が小さすぎると偏りが発生、大きすぎると性能低下
# 学習時のロス確認
# total_loss = ce_loss + aux_loss_alpha * load_balance_loss必要GPUメモリの目安
| モデル | 学習方法 | 必要VRAM | 推奨構成 |
|---|---|---|---|
| DeepSeek-V2-Lite (16B MoE) | QLoRA | 24GB | RTX 3090 ×1 |
| DeepSeek-V2-Lite (16B MoE) | LoRA (bf16) | 40GB | RTX 3090 ×2 |
| DeepSeek-V2 (236B MoE) | QLoRA | 160GB以上 | A100 40GB ×4〜8 |
| DeepSeek-V3 (671B MoE) | LoRA (bf16) | 700GB以上 | H100 80GB ×16以上 |
📦 HuggingFace データセット&モデル カタログ
日本語データセット一覧
| データセット名 | 用途 | サイズ | ライセンス | 説明 |
|---|---|---|---|---|
| mc4 (ja) | 事前学習 | 約200GB | ODC-By | 大規模日本語Webコーパス。CCから抽出 |
| wikipedia (ja) | 事前学習 | 約3GB | CC BY-SA 4.0 | 日本語Wikipedia全記事 |
| oscar-corpus/OSCAR-2301 (ja) | 事前学習 | 約85GB | CC0/利用規約要確認 | CommonCrawlから抽出した多言語コーパス |
| cc100 (ja) | 事前学習 | 約84GB | MIT | CommonCrawl 100言語、日本語含む |
| kunishou/databricks-dolly-15k-ja | 指示チューニング | 約4MB | CC BY-SA 3.0 | dolly-15kの日本語翻訳。Alpaca形式 |
| kunishou/oasst1-89k-ja | 指示チューニング | 約30MB | Apache 2.0 | OpenAssistantの日本語翻訳データ |
| ichikara-instruction (申請必要) | 指示チューニング | 〜 | 独自ライセンス | 高品質な日本語指示データ(研究用) |
| llm-jp/llm-jp-corpus | 事前学習 | 約300GB | ODC-By等 | LLM-jpプロジェクトの日本語コーパス |
転用可能な事前学習済みモデル
| モデル名 | パラメータ | 推論VRAM目安 | ライセンス | 備考 |
|---|---|---|---|---|
| meta-llama/Llama-3.1-8B | 8B | 16GB | Llama 3.1 Community | Meta申請必要。最新Llamaシリーズ |
| meta-llama/Llama-3.2-3B | 3B | 6GB | Llama 3.2 Community | 軽量版。モバイル向け |
| deepseek-ai/DeepSeek-V2-Lite | 16B(MoE) | 40GB | DeepSeek License | MoE入門に最適。活性化は2.4B |
| deepseek-ai/DeepSeek-V3 | 671B(MoE) | 〜700GB | DeepSeek License(MIT相当) | 最強のOSS LLM。フル推論はH100×8必要 |
| rinna/japanese-gpt-neox-3.6b | 3.6B | 8GB | MIT | rinnaの日本語特化モデル |
| elyza/ELYZA-japanese-Llama-2-7b | 7B | 14GB | Llama 2 Community | Llama 2ベースの日本語チューニング済み |
| cyberagent/calm3-22b-chat | 22B | 48GB | Apache 2.0 | CyberAgent CALM3。高品質な日本語モデル |
評価ベンチマーク(日本語)
JGLUE
日本語自然言語理解の総合ベンチマーク。感情分析・含意関係認識・質問応答等6タスク。HuggingFaceで公開。
JCommonsenseQA
日本語常識推論ベンチマーク。英語CommonsenseQAを日本語に翻訳・文化適応。5択形式。
MARC-ja
Amazonレビューの感情分析データセット。日本語、4万件超のレビューにラベル付き。
データセットのダウンロードコマンド
from datasets import load_dataset
# 日本語Wikipedia(推奨: 最初のデータセット)
ds = load_dataset("wikipedia", "20231101.ja", split="train")
print(f"件数: {len(ds)}") # 約182万記事
# 日本語指示データ(Dolly日本語版)
ds = load_dataset("kunishou/databricks-dolly-15k-ja", split="train")
print(f"件数: {len(ds)}") # 15,015件
# OpenAssistant日本語版
ds = load_dataset("kunishou/oasst1-89k-ja", split="train")
# ストリーミングで大容量コーパス(mc4は特に大きい)
ds = load_dataset("mc4", "ja", split="train", streaming=True)
for i, example in enumerate(ds):
if i >= 1000: break # まず1000件で試す
print(example["text"][:100])
# JGLUE評価セット
ds = load_dataset("shunk031/JGLUE", name="MARC-ja", split="validation")💻 学習環境のセットアップ
環境別コスト・性能比較
| 環境 | コスト | 最大VRAM | 学習可能なモデル | 備考 |
|---|---|---|---|---|
| Google Colab Pro | $10/月 | 最大40GB (A100) | 7B LoRA | 手軽だが時間制限あり |
| Google Colab Pro+ | $50/月 | 最大80GB (A100) | 13B LoRA | より長い実行時間 |
| Lambda Labs | $1〜3/時間 | 24〜80GB | 7B フルFT / 70B LoRA | コスパ良好。予約不要 |
| RunPod | $0.2〜2/時間 | 8〜80GB | 用途に応じて | 安価。コミュニティGPU有 |
| Vast.ai | $0.1〜1/時間 | 様々 | 用途に応じて | 最安。安定性は環境依存 |
| 自宅 RTX 3090 | 中古5〜8万円 | 24GB | 7B QLoRA | 長期なら最安。電気代考慮 |
| 自宅 RTX 3090×2 | 中古10〜16万円 | 48GB(NVLink不要) | 13B QLoRA / DeepSeek-V2-Lite | MoE実験に十分 |
Docker環境の構築
# Dockerfile
FROM nvcr.io/nvidia/pytorch:24.01-py3
WORKDIR /workspace
RUN pip install --no-cache-dir \
transformers==4.40.0 \
datasets==2.19.0 \
accelerate==0.29.0 \
peft==0.10.0 \
trl==0.8.6 \
bitsandbytes==0.43.0 \
sentencepiece==0.2.0 \
wandb \
flash-attn --no-build-isolation
# ビルド&実行
# docker build -t llm-train .
# docker run --gpus all -v $(pwd):/workspace -it llm-train bash 分散学習の基礎(DeepSpeed ZeRO)
ZeRO Stage 1
オプティマイザの状態をGPU間で分散。メモリ削減: 〜4倍。通信オーバーヘッド小。
ZeRO Stage 2
オプティマイザ状態+勾配を分散。メモリ削減: 〜8倍。ほとんどのケースでこれを使う。
ZeRO Stage 3
パラメータも分散。メモリ削減: GPU数×。通信コスト高いが大規模モデルに必須。
# accelerate の設定(2GPU、DeepSpeed ZeRO-2)
# accelerate config で対話的に設定するか、以下のYAMLを作成
# ~/.cache/huggingface/accelerate/default_config.yaml
compute_environment: LOCAL_MACHINE
distributed_type: DEEPSPEED
deepspeed_config:
gradient_accumulation_steps: 8
zero_stage: 2
offload_optimizer_device: none
offload_param_device: none
num_processes: 2
mixed_precision: bf16
# 実行
# accelerate launch train.py wandb(Weights & Biases)で学習ログ管理
pip install wandb
wandb login # APIキーを入力
# 学習スクリプト内で
import wandb
wandb.init(project="llm-from-scratch", name="llama3-ja-qlora-v1")
# SFTTrainer の training_args に追加:
# report_to="wandb"
# これだけで自動的にloss/lr/perplexityがダッシュボードに表示される🇯🇵 日本語LLM特有のノウハウ
トークナイザーの日本語対応
方法A: Vocab拡張
英語向けトークナイザー(例: Llama tokenizer)のvocabに日本語サブワードを追加する方法。 既存モデルの重みをそのまま使えるが、追加トークンの埋め込みは新規学習が必要。
tokenizer.add_tokens(new_ja_tokens)
model.resize_token_embeddings(len(tokenizer))方法B: 専用トークナイザー
SentencePieceで日本語コーパスから専用トークナイザーを学習する方法。 日本語の圧縮率が最も高いが、事前学習からやり直す必要がある。 新規に0から学習する場合はこちらを推奨。
日本語の文字種問題
日本語はひらがな・カタカナ・漢字・英数字・記号が混在するという特殊な構造を持ちます。 加えて、半角/全角の違い、旧字体/新字体の混在、環境依存文字なども存在します。
データクリーニングの必須処理:
import unicodedata
import re
def clean_japanese_text(text):
# Unicode正規化(NFKC: 全角英数字→半角、ひらがな/カタカナの正規化)
text = unicodedata.normalize('NFKC', text)
# BOM除去
text = text.replace('\ufeff', '')
# 制御文字除去
text = re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', '', text)
# 連続する空白・改行を正規化
text = re.sub(r'\n{3,}', '\n\n', text)
text = re.sub(r' {2,}', ' ', text)
# URLの除去(オプション)
text = re.sub(r'https?://\S+', '', text)
return text.strip()英語にも対応させる: 多言語データの混合比率
英語と日本語の両方に対応するモデルを作る場合、学習データの混合比率が重要です。 日本語に偏りすぎると英語性能が落ち、英語に偏りすぎると日本語が弱くなります。
日本語特化
日本語 85%
英語 10%
コード 5%
バランス型(推奨)
日本語 50%
英語 40%
コード 10%
多言語型
日本語 30%
英語 50%
その他20%
既存の日本語LLM 性能比較
| モデル名 | パラメータ | 種類 | 日本語性能 | 備考 |
|---|---|---|---|---|
| GPT-4o (OpenAI) | 非公開 | API | ◎ | 最高性能。有料API |
| Claude 3.7 Sonnet (Anthropic) | 非公開 | API | ◎ | 高性能。日本語自然 |
| Gemini 1.5 Pro (Google) | 非公開 | API | ◎ | 長文対応200万トークン |
| DeepSeek V3 | 671B MoE | OSS | ○ | GPT-4o相当。OSS最強 |
| CALM3-22B (CyberAgent) | 22B | OSS | ◎ | Apache 2.0。商用OK |
| ELYZA-japanese-Llama-2-7b | 7B | OSS | ○ | 軽量・実用的 |
| RakutenAI-2.0 (楽天) | 非公開 | API/OSS予定 | ◎ | DeepSeek V3フォーク |
| EvoLLM-JP (Sakana AI) | 〜 | OSS | ◎ | モデルマージ進化的手法 |
🗺️ ロードマップ: 0からDeepSeekまでの道のり
| フェーズ | 期間 | 目標 | 必要スキル | ハードウェア | 予算目安 |
|---|---|---|---|---|---|
| Phase 1 | 1〜2週間 | nanoGPTで125Mモデル作成 | Python, PyTorch, Transformer基礎 | RTX 3060以上 or Colab | 0〜$10 |
| Phase 2 | 2〜4週間 | Llama 3.1 8B LoRAファインチューニング | transformers, peft, trl | RTX 3090 or Colab Pro | 0〜$30 |
| Phase 3 | 1〜2ヶ月 | DeepSeek V2-Liteフォーク | MoE理解, 分散学習基礎 | RTX 3090×2 or Lambda | 1〜5万円 |
| Phase 4 | 3〜6ヶ月 | 独自MoEモデル構築 | Expert設計, Router最適化, DeepSpeed | A100 40GB×4以上 | 10〜50万円 |
| Phase 5 | 6ヶ月〜 | スケールアップ・公開 | 大規模分散学習, HuggingFace公開 | H100クラスタ | 100万円〜 |
Phase 1(1〜2週間): nanoGPTで125Mモデルを作る
目標: Transformerの仕組みをコードで理解する。
やること: Karpathyのnanoリポジトリをクローンし、日本語Wikipediaで学習。
Lossが下がること、テキストが生成されることを確認する。
成功基準: perplexity が 100以下になる。「東京は」に続く文章を生成できる。
Phase 2(2〜4週間): Llama 3.1 8B をLoRAで日本語対応
目標: LoRA/QLoRAの使い方を習得し、実用的な日本語対話モデルを作る。
やること: databricks-dolly-15k-ja と oasst1-ja でSFT、その後DPOでアラインメント。
Ollama でローカル推論を試す。
成功基準: JGLUEのMARC-jaで80%以上の精度。自然な日本語回答を生成できる。
Phase 3(1〜2ヶ月): DeepSeek V2-Liteフォーク・MoEを理解
目標: MoEアーキテクチャを実際に触り、Expert Routingの動作を理解する。
やること: V2-Liteのコードを読解 → QLoRAで日本語チューニング → Expert utilization を可視化。
成功基準: 各Expertの活性化頻度を分析し、特定のタスクで特定のExpertが活性化することを確認。
Phase 4(3〜6ヶ月): 独自MoEモデルの設計・構築
目標: 独自のExpert設計とRouter最適化を行い、特定ドメインに特化したMoEを作る。
やること: Expert数・Top-K・モデルサイズの設計 → DeepSpeedによる分散学習 → Load Balance Lossのチューニング。
成功基準: Dense同パラメータのベースラインより同等以上の性能を、少ない計算コストで達成。
Phase 5(6ヶ月〜): スケールアップとHuggingFace公開
目標: 大規模GPUクラスタで本格的な事前学習を行い、コミュニティへ貢献。
やること: H100クラスタ(Lambda/CoreWeave等)でのフル事前学習 → HuggingFaceで公開 → 論文執筆。
成功基準: JGLUEやlm-eval-harnessで既存の同規模モデルを超える。
今すぐ始めるための最小手順(今日〜明日)
- Google Colabを開く(無料)
!git clone https://github.com/karpathy/nanoGPTを実行- 日本語WikipediaをHuggingFaceからダウンロード
- SentencePieceで日本語トークナイザーを学習(30分)
- Colab無料GPUで学習スタート(まず100ステップでLossが下がることを確認)
- ✅ 完了!あとはステップ数を増やすだけ
🤖 Claudeの総評
「0からLLMを作る」というのは数年前まで大企業か有力研究機関にしか現実的でなかった目標でしたが、 DeepSeek V3の登場とオープンソース化により、個人・小チームでも現実的な目標になりました。
このページで紹介した3つのルートを振り返ると、 「完全スクラッチ→Llamaフォーク→DeepSeekフォーク」の順に難易度が上がり、 必要な計算資源も増えます。しかし逆に「学習効果」という観点では逆順です。 完全スクラッチこそが最もTransformerの仕組みを深く理解できる。
私が特に重要だと考える点は2つです。 1つ目は日本語トークナイザーの設計。 英語向けBPEをそのまま使うと日本語の文を表現するのに英語の3〜4倍のトークンが必要になり、 実質的なコンテキスト長が大幅に短くなります。日本語特化モデルを作るなら SentencePieceによる専用トークナイザーの学習は早期に着手すべきです。
2つ目はMoEのRouter設計の難しさです。 MoEは「少ない計算で大きなモデル性能」という魅力的な特性を持ちますが、 Routerの学習が不安定だったり特定のExpertに処理が偏ったりする「Expert崩壊」が 実際の学習では頻繁に起きます。 Load Balancing Lossの係数チューニングや、DeepSeek V3が採用した「Auxiliary-Loss-Free Load Balancing」 のような工夫が必要です。これを乗り越えた先にこそ、本物のMoEモデルが待っています。
楽天AI・サカナAIの成功事例が示す通り、日本語LLMの分野はまだ空白地帯が多い。 DeepSeekフォークという「巨人の肩に乗る」戦略と、日本語固有のノウハウを組み合わせれば、 中規模チームでも世界水準の日本語LLMを作れる時代が来ています。 このページがその第一歩の助けになれば幸いです。