# 微调 LLM

使用 CLORE.AI GPU 上高效的微调技术训练你自己的定制 LLM。

{% hint style="success" %}
所有示例都可以在通过以下方式租用的 GPU 服务器上运行： [CLORE.AI 市场](https://clore.ai/marketplace).
{% endhint %}

## 在 CLORE.AI 上租用

1. 访问 [CLORE.AI 市场](https://clore.ai/marketplace)
2. 按 GPU 类型、VRAM 和价格筛选
3. 选择 **按需** （固定费率）或 **现货** （出价）
4. 配置你的订单：
   * 选择 Docker 镜像
   * 设置端口（SSH 使用 TCP，Web UI 使用 HTTP）
   * 如有需要，添加环境变量
   * 输入启动命令
5. 选择付款方式： **CLORE**, **BTC**，或 **USDT/USDC**
6. 创建订单并等待部署

### 访问你的服务器

* 在以下位置查找连接详情： **我的订单**
* Web 界面：使用 HTTP 端口 URL
* SSH： `ssh -p <port> root@<proxy-address>`

## 什么是 LoRA/QLoRA？

* **LoRA** （低秩适配）——训练小型适配器层，而不是完整模型
* **QLoRA** ——带量化的 LoRA，可进一步减少 VRAM 占用
* 在单张 RTX 3090 上训练 7B 模型
* 在单张 A100 上训练 70B 模型

## 要求

| 模型  | 方法      | 最小 VRAM | 推荐                                                                                                       |
| --- | ------- | ------- | -------------------------------------------------------------------------------------------------------- |
| 7B  | QLoRA   | 12GB    | [RTX 3090](https://clore.ai/rent-3090.html?utm_source=docs\&utm_medium=guide\&utm_campaign=finetune-llm) |
| 13B | QLoRA   | 20GB    | [RTX 4090](https://clore.ai/rent-4090.html?utm_source=docs\&utm_medium=guide\&utm_campaign=finetune-llm) |
| 70B | QLoRA   | 48GB    | A100 80GB                                                                                                |
| 7B  | 完整 LoRA | 24GB    | RTX 4090                                                                                                 |

## 快速部署

**Docker 镜像：**

```
pytorch/pytorch:2.5.1-cuda12.4-cudnn9-devel
```

**端口：**

```
22/tcp
8888/http
6006/http
```

**命令：**

```bash
pip install "transformers>=4.45" "datasets>=2.20" accelerate "peft>=0.14" \
    bitsandbytes "trl>=0.12" wandb jupyterlab && \
jupyter lab --ip=0.0.0.0 --port=8888 --allow-root
```

## 访问你的服务

部署后，找到你的 `http_pub` URL 于 **我的订单**:

1. 前往 **我的订单** 页面
2. 点击你的订单
3. 找到 `http_pub` URL（例如， `abc123.clorecloud.net`)

使用 `https://YOUR_HTTP_PUB_URL` 代替 `localhost` 用于下面示例中。

## 数据集准备

### 聊天格式（推荐）

```json
[
  {
    "messages": [
      {"role": "system", "content": "你是一个乐于助人的助手。"},
      {"role": "user", "content": "什么是 Python？"},
      {"role": "assistant", "content": "Python 是一种编程语言..."}
    ]
  }
]
```

### 指令格式

```json
[
  {
    "instruction": "翻译成法语",
    "input": "你好，你怎么样？",
    "output": "Bonjour, comment allez-vous?"
  }
]
```

### Alpaca 格式

```json
[
  {
    "instruction": "给出三条保持健康的建议。",
    "input": "",
    "output": "1. 吃均衡的饮食..."
  }
]
```

## 支持的现代模型（2025）

| 模型                         | HF ID                                     | 最小 VRAM（QLoRA） |
| -------------------------- | ----------------------------------------- | -------------- |
| Llama 3.1 / 3.3 8B         | `meta-llama/Llama-3.1-8B-Instruct`        | 12GB           |
| Qwen 2.5 7B / 14B          | `Qwen/Qwen2.5-7B-Instruct`                | 12GB / 20GB    |
| DeepSeek-R1-Distill（7B/8B） | `deepseek-ai/DeepSeek-R1-Distill-Qwen-7B` | 12GB           |
| Mistral 7B v0.3            | `mistralai/Mistral-7B-Instruct-v0.3`      | 12GB           |
| Gemma 2 9B                 | `google/gemma-2-9b-it`                    | 14GB           |
| Phi-4 14B                  | `microsoft/phi-4`                         | 20GB           |

## QLoRA 微调脚本

使用 PEFT 0.14+、Flash Attention 2、DoRA 支持以及 Qwen2.5 / DeepSeek-R1 兼容性的现代示例：

```python
import torch
from transformers import (
    AutoModelForCausalLM,
    AutoTokenizer,
    BitsAndBytesConfig,
    TrainingArguments,
)
from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
from datasets import load_dataset
from trl import SFTTrainer, SFTConfig

# === 配置 ===
# 从以下模型中选择一个：Qwen2.5、DeepSeek-R1-Distill、Llama 3.1、Mistral 等。
MODEL_NAME = "Qwen/Qwen2.5-7B-Instruct"
# MODEL_NAME = "deepseek-ai/DeepSeek-R1-Distill-Qwen-7B"
# MODEL_NAME = "meta-llama/Llama-3.1-8B-Instruct"

DATASET = "your_dataset.json"  # 或 HuggingFace 数据集名称
OUTPUT_DIR = "./output"
MAX_SEQ_LENGTH = 4096           # Qwen2.5 支持最高 32K 上下文
USE_DORA = True                 # DoRA 比标准 LoRA 能带来更好的质量
USE_FLASH_ATTN = True           # Flash Attention 2 可节省 VRAM 并加速

# === 使用 4 位量化加载模型 ===
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_use_double_quant=True,
)

model = AutoModelForCausalLM.from_pretrained(
    MODEL_NAME,
    quantization_config=bnb_config,
    device_map="auto",
    trust_remote_code=True,  # Qwen2.5 和 DeepSeek 需要
    # Flash Attention 2：需要 Ampere+ GPU（RTX 30/40、A100）
    attn_implementation="flash_attention_2" if USE_FLASH_ATTN else "eager",
)

tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)
if tokenizer.pad_token is None:
    tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"

# === 配置 LoRA，可选 DoRA ===
# DoRA（权重分解低秩适配）——需要 PEFT >= 0.14
# use_dora=True 将权重分解为幅值 + 方向，以获得更好的质量
lora_config = LoraConfig(
    r=64,                    # 秩（越高 = 容量越大，VRAM 占用越多）
    lora_alpha=16,           # 缩放因子（保持等于 r 或 r 的一半）
    target_modules=[
        "q_proj", "k_proj", "v_proj", "o_proj",  # 注意力层
        "gate_proj", "up_proj", "down_proj",      # MLP 层
    ],
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
    use_dora=USE_DORA,        # DoRA：提升质量（PEFT 0.14+）
    # use_rslora=True,        # 可选：秩稳定 LoRA
)

# 为 QLoRA 训练准备模型
model = prepare_model_for_kbit_training(
    model,
    use_gradient_checkpointing=True,
    gradient_checkpointing_kwargs={"use_reentrant": False},
)
model = get_peft_model(model, lora_config)

# 打印可训练参数摘要
model.print_trainable_parameters()
# 示例输出：可训练参数：42,991,616 || 全部参数：7,284,891,648 || 可训练%：0.59

# === 加载数据集 ===
dataset = load_dataset("json", data_files=DATASET)
# 或使用公共数据集：
# dataset = load_dataset("HuggingFaceH4/ultrachat_200k")

# === 为 Qwen2.5 / ChatML 格式整理数据集 ===
def format_chat_qwen(example):
    """使用 ChatML 模板为 Qwen2.5 格式化。"""
    messages = example.get("messages", [])
    if not messages:
        # 处理 alpaca 风格数据
        text = f"<|im_start|>system\n你是一个乐于助人的助手。<|im_end|>\n"
        text += f"<|im_start|>user\n{example['instruction']}"
        if example.get("input"):
            text += f"\n{example['input']}"
        text += f"<|im_end|>\n<|im_start|>assistant\n{example['output']}<|im_end|>"
    else:
        # 处理 messages 格式（ChatML）
        text = tokenizer.apply_chat_template(
            messages,
            tokenize=False,
            add_generation_prompt=False,
        )
    return {"text": text}

dataset = dataset.map(format_chat_qwen, remove_columns=dataset["train"].column_names)

# === 训练参数（PEFT 0.14+ / TRL 0.12+） ===
training_args = SFTConfig(
    output_dir=OUTPUT_DIR,
    num_train_epochs=3,
    per_device_train_batch_size=2,
    gradient_accumulation_steps=8,         # 有效批大小 = 2 * 8 = 16
    learning_rate=2e-4,
    weight_decay=0.001,
    warmup_ratio=0.03,
    lr_scheduler_type="cosine",
    logging_steps=10,
    save_steps=100,
    save_total_limit=3,
    bf16=True,                             # 现代 GPU（A100、RTX 30/40）使用 bf16
    # fp16=True,                           # 较旧 GPU 使用 fp16
    optim="paged_adamw_8bit",
    max_grad_norm=0.3,
    group_by_length=True,
    report_to="wandb",                     # 或 "tensorboard"
    # SFTConfig 特定：
    max_seq_length=MAX_SEQ_LENGTH,
    dataset_text_field="text",
    packing=True,                          # 打包多个样本以提高效率
)

# === 训练 ===
trainer = SFTTrainer(
    model=model,
    train_dataset=dataset["train"],
    tokenizer=tokenizer,
    args=training_args,
)

trainer.train()

# === 保存 LoRA 适配器 ===
trainer.save_model(f"{OUTPUT_DIR}/final")
tokenizer.save_pretrained(f"{OUTPUT_DIR}/final")
print(f"模型已保存到 {OUTPUT_DIR}/final")
```

## Flash Attention 2

Flash Attention 2 可显著减少 VRAM 使用并加快训练速度。需要 Ampere+ GPU（RTX 3090、RTX 4090、A100）。

```bash
# 安装 Flash Attention 2
pip install flash-attn --no-build-isolation
```

```python
# 在模型加载中启用：
model = AutoModelForCausalLM.from_pretrained(
    MODEL_NAME,
    attn_implementation="flash_attention_2",  # <-- 添加这一项
    torch_dtype=torch.bfloat16,               # FA2 需要 bf16 或 fp16
    device_map="auto",
)
```

| 设置                        | VRAM（7B） | 速度   |
| ------------------------- | -------- | ---- |
| 标准注意力（fp16）               | \~22GB   | 基线   |
| Flash Attention 2（bf16）   | \~16GB   | +30% |
| Flash Attention 2 + QLoRA | \~12GB   | +30% |

## DoRA（权重分解 LoRA）

DoRA（PEFT >= 0.14）会将预训练权重分解为幅值和方向两个分量。它能提升微调质量，尤其是在较小秩时。

```python
from peft import LoraConfig

# 标准 LoRA
lora_config = LoraConfig(r=64, lora_alpha=16, use_dora=False, ...)

# DoRA——相同参数，更好的质量
lora_config = LoraConfig(r=64, lora_alpha=16, use_dora=True, ...)
# 注意：与标准 LoRA 相比，DoRA 会增加约 5-10% 的 VRAM 开销
# 注意：在所有情况下都不一定与量化（4 位/8 位）模型兼容
```

## Qwen2.5 和 DeepSeek-R1-Distill 示例

### Qwen2.5 微调

```python
MODEL_NAME = "Qwen/Qwen2.5-7B-Instruct"
# 对于 14B："Qwen/Qwen2.5-14B-Instruct"（使用 QLoRA 需要 20GB+ VRAM）

model = AutoModelForCausalLM.from_pretrained(
    MODEL_NAME,
    quantization_config=bnb_config,
    device_map="auto",
    trust_remote_code=True,          # Qwen2.5 需要
    attn_implementation="flash_attention_2",
)
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)

# Qwen2.5 使用 ChatML 格式——使用 apply_chat_template
messages = [
    {"role": "system", "content": "你是一个乐于助人的助手。"},
    {"role": "user", "content": "你好！"},
    {"role": "assistant", "content": "你好！我能帮你什么？"},
]
text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=False)
```

### DeepSeek-R1-Distill 微调

DeepSeek-R1-Distill 模型（Qwen-7B、Qwen-14B、Llama-8B、Llama-70B）以推理为重点。对其进行微调，以将其思维链风格适配到你的领域。

```python
# DeepSeek-R1-Distill 变体
MODEL_NAME = "deepseek-ai/DeepSeek-R1-Distill-Qwen-7B"   # 基于 Qwen2.5 的 7B
# MODEL_NAME = "deepseek-ai/DeepSeek-R1-Distill-Llama-8B" # 基于 Llama3 的 8B
# MODEL_NAME = "deepseek-ai/DeepSeek-R1-Distill-Qwen-14B" # 14B（需要 A100）

model = AutoModelForCausalLM.from_pretrained(
    MODEL_NAME,
    quantization_config=bnb_config,
    device_map="auto",
    trust_remote_code=True,
    attn_implementation="flash_attention_2",
)

# DeepSeek-R1 使用 <think>...</think> 标签进行推理
# 在训练数据中保留它，以维持思维链能力
example_format = """<|im_start|>user
求解：15 * 23 等于多少？<|im_end|>
<|im_start|>assistant
<think>
15 * 23 = 15 * 20 + 15 * 3 = 300 + 45 = 345
</think>
答案是 345。<|im_end|>"""

# DeepSeek-R1-Distill（Qwen2.5 基座）的 LoRA 目标模块
lora_config = LoraConfig(
    r=32,
    lora_alpha=16,
    target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
                    "gate_proj", "up_proj", "down_proj"],
    use_dora=True,
    task_type="CAUSAL_LM",
)
```

## 使用 Axolotl（更简单）

Axolotl 使用 YAML 配置简化了微调：

```bash
pip install axolotl

# 创建配置
cat > config.yml << 'EOF'
base_model: mistralai/Mistral-7B-v0.1
model_type: MistralForCausalLM
tokenizer_type: LlamaTokenizer

load_in_4bit: true
adapter: qlora
lora_r: 32
lora_alpha: 16

datasets:
  - path: your_data.json
    type: alpaca

sequence_len: 4096
sample_packing: true

gradient_accumulation_steps: 4
micro_batch_size: 2
num_epochs: 3
learning_rate: 2e-4

output_dir: ./output
EOF

# 训练
accelerate launch -m axolotl.cli.train config.yml
```

## Axolotl 配置示例

### 聊天模型

```yaml
base_model: mistralai/Mistral-7B-Instruct-v0.2
load_in_4bit: true
adapter: qlora

datasets:
  - path: data.json
    type: sharegpt

chat_template: mistral
```

### 代码模型

```yaml
base_model: codellama/CodeLlama-7b-hf
load_in_4bit: true
adapter: qlora

datasets:
  - path: code_data.json
    type: alpaca

sequence_len: 8192  # 代码的更长上下文
```

## 合并 LoRA 权重

训练后，将 LoRA 合并回基础模型：

```python
from peft import PeftModel
from transformers import AutoModelForCausalLM, AutoTokenizer

# 加载基础模型
base_model = AutoModelForCausalLM.from_pretrained(
    "mistralai/Mistral-7B-v0.1",
    torch_dtype=torch.float16,
    device_map="auto",
)

# 加载 LoRA
model = PeftModel.from_pretrained(base_model, "./output/final")

# 合并
merged_model = model.merge_and_unload()

# 保存合并后的模型
merged_model.save_pretrained("./merged_model")
tokenizer.save_pretrained("./merged_model")
```

## 转换为 GGUF

用于 llama.cpp/Ollama：

```bash

# 克隆 llama.cpp
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp

# 转换
python convert.py ../merged_model --outtype f16 --outfile model-f16.gguf

# 量化
./quantize model-f16.gguf model-q4_k_m.gguf q4_k_m
```

## 监控训练

### Weights & Biases

```python
import wandb
wandb.init(project="llm-finetune", name="mistral-7b-lora")
```

### TensorBoard

```python

# 在训练参数中
report_to="tensorboard"
logging_dir="./logs"

# 查看
tensorboard --logdir ./logs --port 6006 --bind_all
```

## 最佳实践

### 超参数

| 参数          | 7B 模型 | 13B 模型 | 70B 模型 |
| ----------- | ----- | ------ | ------ |
| batch\_size | 4     | 2      | 1      |
| grad\_accum | 4     | 8      | 16     |
| lr          | 2e-4  | 1e-4   | 5e-5   |
| lora\_r     | 64    | 32     | 16     |
| epochs      | 3     | 2-3    | 1-2    |

### 数据集大小

* 最少：1,000 个样本
* 良好：10,000+ 个样本
* 质量 > 数量

### 避免过拟合

```python
training_args = TrainingArguments(
    ...
    weight_decay=0.01,
    warmup_ratio=0.03,
    save_total_limit=3,
    load_best_model_at_end=True,
    evaluation_strategy="steps",
    eval_steps=100,
)
```

## 多 GPU 训练

```bash

# 使用 accelerate
accelerate launch --multi_gpu --num_processes 4 train.py

# 使用 DeepSpeed
accelerate launch --use_deepspeed --num_processes 4 train.py
```

DeepSpeed 配置：

```json
{
  "bf16": {"enabled": true},
  "zero_optimization": {
    "stage": 2,
    "offload_optimizer": {"device": "cpu"}
  }
}
```

## 保存与导出

```bash

# 保存 LoRA 适配器
trainer.save_model("./lora_adapter")

# 保存合并后的模型
merged_model.save_pretrained("./full_model")

# 上传到 HuggingFace
huggingface-cli login
merged_model.push_to_hub("username/my-model")
```

## 故障排查

### OOM 错误

* 减小批大小
* 增加梯度累积
* 使用 `gradient_checkpointing=True`
* 减小 lora\_r

### 训练损失没有下降

* 检查数据格式
* 提高学习率
* 检查数据问题

### NaN 损失

* 降低学习率
* 使用 fp32 而不是 fp16
* 检查是否有损坏的数据

## 成本估算

CLORE.AI 市场典型费率（截至 2026 年）：

| GPU       | 每小时费率   | 每日费率    | 4 小时会话  |
| --------- | ------- | ------- | ------- |
| RTX 3060  | \~$0.03 | \~$0.70 | \~$0.12 |
| RTX 3090  | \~$0.06 | \~$1.50 | \~$0.25 |
| RTX 4090  | \~$0.10 | \~$2.30 | \~$0.40 |
| A100 40GB | \~$0.17 | \~$4.00 | \~$0.70 |
| A100 80GB | \~$0.25 | \~$6.00 | \~$1.00 |

*价格因提供商和需求而异。请查看* [*CLORE.AI 市场*](https://clore.ai/marketplace) *当前费率。*

> 📚 另请参阅： [如何在云 GPU 上微调 LLaMA 3 —— 分步指南](https://blog.clore.ai/how-to-fine-tune-llama-3-cloud-gpu/)

**节省费用：**

* 使用 **现货** 适用于灵活工作负载的市场（通常便宜 30-50%）
* 使用 **CLORE** 代币
* 比较不同提供商之间的价格


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.clore.ai/guides/guides_v2-zh/xun-lian/finetune-llm.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
