🚀 「未来のAI: DeepSeek-R1-Distill-Qwen-1.5Bの最先端ファインチューニング完全ガイド」

# LLMのファインチューニング: DeepSeek-R1-Distill-Qwen-1.5Bの詳細ガイド
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3917980/95469b01-366b-aa7b-2291-d70c1d22f17c.png)


LLM（大規模言語モデル）のファインチューニングにより、特定のタスクでのパフォーマンスを大幅に向上させることができます。本ガイドでは、Google Colab、Hugging Faceの`transformers`、`datasets`、および8ビット量子化をサポートする`bitsandbytes`を使用して、DeepSeek-R1-Distill-Qwen-1.5Bモデルをファインチューニングする方法を説明します。また、`wandb`を使用して実験を追跡します。

---
## **ステップ1: 環境のセットアップ**
まず、必要なライブラリをインストールします:
```python
!pip install transformers datasets sympy wandb
!pip install --no-cache-dir bitsandbytes
```

これらのライブラリは、モデルのロード、データセットの処理、効率的なファインチューニング、および実験の追跡に必要です。

---
## **ステップ2: モデルとトークナイザーのセットアップ**
DeepSeek-R1-Distill-Qwen-1.5Bモデルとトークナイザーをロードします:
```python
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM

model_name = "deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B"

# トークナイザーをロード
tokenizer = AutoTokenizer.from_pretrained(model_name)

# モデルをロードし、GPUに移動
model = AutoModelForCausalLM.from_pretrained(model_name).to("cuda")

print("モデルがGPUにロードされました。")
```

---
## **ステップ3: WandBを使用した実験トラッキングのセットアップ**
まず、Weights & Biases（WandB）にログインします:
```python
!wandb login
```

プロジェクトを初期化します:
```python
import wandb
wandb.init(
    project="My_LLM",
    config={
        "learning_rate": 5e-5,
        "architecture": "DeepSeek-R1-Distill-Qwen-1.5B",
        "dataset": "dataset.jsonl",
        "epochs": 2,
    }
)
```

---
## **ステップ4: データセットの準備**
### **Google Driveのマウント**
```python
from google.colab import drive
drive.mount('/content/drive')
```
データセットをGoogle Driveに保存しておく必要があります。

### **データセットのロードと分割**
```python
from datasets import load_dataset

dataset = load_dataset("json", data_files={"train": "/content/drive/My Drive/dataset.jsonl"}, split="train")
print(f"データセットがロードされました: {len(dataset)} サンプル")

train_test_split = dataset.train_test_split(test_size=0.2)
train_dataset = train_test_split["train"]
eval_dataset = train_test_split["test"]
```
80%をトレーニング用、20%を評価用に分割します。

### **トークナイゼーション**
```python
def tokenize_function(examples):
    combined_texts = [f"{prompt}\n{completion}" for prompt, completion in zip(examples["prompt"], examples["completion"])]
    tokenized = tokenizer(combined_texts, truncation=True, max_length=512, padding="max_length")
    tokenized["labels"] = tokenized["input_ids"].copy()
    return tokenized

tokenized_train_dataset = train_dataset.map(tokenize_function, batched=True)
tokenized_eval_dataset = eval_dataset.map(tokenize_function, batched=True)
```

---
## **ステップ5: 8ビット量子化によるモデルのロード**
```python
from transformers import BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(load_in_8bit=True)
model = AutoModelForCausalLM.from_pretrained(model_name, quantization_config=quantization_config, device_map="auto")
print("モデルが8ビット量子化でGPUにロードされました。")
```

---
## **ステップ6: LoRAによるファインチューニングの設定**
```python
from peft import get_peft_model, LoraConfig, TaskType

lora_config = LoraConfig(
    r=8, lora_alpha=16, lora_dropout=0.05, task_type=TaskType.CAUSAL_LM
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
```

---
## **ステップ7: トレーニングの設定**
```python
from transformers import TrainingArguments, Trainer

training_args = TrainingArguments(
    output_dir="./deepseek_finetuned",
    num_train_epochs=50,
    per_device_train_batch_size=2,
    gradient_accumulation_steps=16,
    fp16=True,
    logging_steps=10,
    save_steps=100,
    evaluation_strategy="steps",
    eval_steps=10,
    learning_rate=3e-5,
    logging_dir="./logs",
    report_to="wandb",
    run_name="DeepSeek_FineTuning_Experiment",
)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_train_dataset,
    eval_dataset=tokenized_eval_dataset,
)

trainer.train()
```






```Batch: CONSOLE OUTPUT
✅ Dataset loaded: 44 samples
Map: 100%
 35/35 [00:00<00:00, 230.76 examples/s]
Map: 100%
 9/9 [00:00<00:00, 131.62 examples/s]
✅ Train dataset: 35 samples
✅ Eval dataset: 9 samples
✅ Model loaded with 8-bit quantization on GPU...
trainable params: 1,572,864 || all params: 1,348,044,800 || trainable%: 0.1167
/usr/local/lib/python3.11/dist-packages/transformers/training_args.py:1575: FutureWarning: `evaluation_strategy` is deprecated and will be removed in version 4.46 of 🤗 Transformers. Use `eval_strategy` instead
  warnings.warn(
🚀 Starting fine-tuning with LoRA (this may take longer)...
 [50/50 03:44, Epoch 25/50]
Step	Training Loss	Validation Loss
10	6.150900	5.066065
20	3.964500	2.904839
30	2.126500	1.420464
40	1.043100	0.748976
50	0.655800	0.601017


Run history:

eval/loss	█▅▂▁▁
eval/runtime	▁▂▂█▄
eval/samples_per_second	█▇▇▁▅
eval/steps_per_second	█▇▇▁▅
train/epoch	▁▁▃▃▅▅▆▆███
train/global_step	▁▁▃▃▅▅▆▆███
train/grad_norm	▇█▆▃▁
train/learning_rate	█▆▅▃▁
train/loss	█▅▃▁▁

Run summary:

eval/loss	0.60102
eval/runtime	0.91
eval/samples_per_second	9.89
eval/steps_per_second	2.198
total_flos	3445974368256000.0
train/epoch	25
train/global_step	50
train/grad_norm	7.78652
train/learning_rate	0
train/loss	0.6558
train_loss	2.78817
train_runtime	232.9563
train_samples_per_second	7.512
train_steps_per_second	0.215

View run DeepSeek_FineTuning_Experiment at: https://wandb.ai/roboken-akash-/DeepSeek_FineTuning/runs/7b8v92nq
View project at: https://wandb.ai/roboken-akash-/DeepSeek_FineTuning
Synced 5 W&B file(s), 0 media file(s), 0 artifact file(s) and 0 other file(s)
Find logs at: ./wandb/run-20250203_054404-7b8v92nq/logs
✅ Training completed successfully!
```
---

### **📊 トレーニング結果の解析**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3917980/f9620f80-6074-6251-c217-e3a5f483f466.png)



| 指標 | 値 |
|--------------------------|----------|
| **総トレーニングステップ** | 50 |
| **完了エポック数** | 25 / 50 |
| **最終トレーニング損失** | **0.6558** |
| **最終バリデーション損失** | **0.6010** |
| **初期トレーニング損失** | 6.1509 |
| **初期バリデーション損失** | 5.0660 |
| **勾配ノルム** | 7.78 |
| **学習率減衰** | あり（最終 LR = 0） |
| **1秒あたりのサンプル数** | 7.51（トレーニング） / 9.89（評価） |
| **1秒あたりのステップ数** | 0.215 |

---

### **📉 損失曲線の分析**
#### ✅ **トレーニング損失の推移**
- **6.15 → 0.6558** という順調な低下。  
- **急激な下降なし** = 安定した学習プロセス。

#### ✅ **バリデーション損失の推移**
- **5.06 → 0.6010** まで減少。  
- **トレーニング損失との差が小さい** ため、**過学習（オーバーフィッティング）の兆候なし**。  
- **学習が進むにつれて一般化性能が向上** したと考えられる。

#### ✅ **勾配ノルム (`7.78`) は適正範囲内**
- **20 以上 → 勾配爆発のリスク** → なし  
- **1 以下 → 学習不足の可能性** → なし  
- **適正な値（7.78）** なので、**安定した学習** ができている。

---

### **🛠 改善点と次のステップ**
🚀 **① エポック数を増やす（50→75 or 100）**  
- **35 サンプルではデータ量が少ないため、追加のエポックでさらなる改善が期待できる**。  
- `num_train_epochs=75` または `100` で試すのも良い。

🚀 **② データの増強（Data Augmentation）**  
- **データセットが 44 サンプルと少ないため、データを増やすことで性能向上が可能**。  
- 例えば：
  - **入力データのノイズ追加**  
  - **同義語置換によるテキスト拡張**  
  - **データ収集を増やす**

🚀 **③ 学習率 (`learning_rate`) の最適化**  
- 学習率が **0 まで減衰してしまった** ため、学習の進行が止まった可能性がある。  
- **低めの初期学習率** (`2e-5` など) で **新しいトレーニングを実施** してみるのも良い。

🚀 **④ モデルの推論をテストする**
- 実際にモデルをテストして、**期待通りの出力が得られるか確認** する。  
- 精度のチェックのため、**未学習のデータで評価** するのが重要。

---

### **🔥 結論：トレーニングは成功！**
✅ **損失値の低下が確認できる**  
✅ **過学習の兆候なし**  
✅ **学習率の調整でさらなる改善が可能**  
✅ **データ量が少ないため、追加の学習が有効**  


















---
## **ステップ8: ファインチューニング済みモデルの保存**
```python
save_path = "/content/drive/My Drive/deepseek_finetuned"
model.save_pretrained(save_path)
tokenizer.save_pretrained(save_path)
print(f"ファインチューニング済みモデルが保存されました: {save_path}")
```

---
## **ステップ9: LoRAをベースモデルと統合**
```python
from peft import PeftModel

base_model = AutoModelForCausalLM.from_pretrained(model_name)
model = PeftModel.from_pretrained(base_model, save_path)
model = model.merge_and_unload()

final_save_path = "/content/drive/My Drive/deepseek_finetuned_full"
model.save_pretrained(final_save_path)
tokenizer.save_pretrained(final_save_path)
print(f"統合されたモデルが保存されました: {final_save_path}")
```

---
## **ステップ10: ファインチューニング済みモデルのロード**
```python
model = AutoModelForCausalLM.from_pretrained(final_save_path)
tokenizer = AutoTokenizer.from_pretrained(final_save_path)
```
モデルがデプロイの準備が整いました。

この手順を使えば、LLMを効率的にファインチューニングできます！


🚀 **次のステップとして、モデルのテストを試してみませんか？** 🔥