> For the complete documentation index, see [llms.txt](https://docs.clore.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.clore.ai/guides/guides_v2-zh/xun-lian/finetune-llm.md).

# 微调 LLM

使用高效技术在 Clore.ai GPU 上微调自定义 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 模型

## 需求

| 模型  | 方法      | 最低显存 | 推荐                                                                                                       |
| --- | ------- | ---- | -------------------------------------------------------------------------------------------------------- |
| 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.11.0-cuda12.8-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": "You are a helpful assistant."},
      {"role": "user", "content": "什么是 Python？"},
      {"role": "assistant", "content": "Python 是一种编程语言..."}
    ]
  }
]
```

### 指令格式

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

### 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()
# 示例输出：trainable params: 42,991,616 || all params: 7,284,891,648 || trainable%: 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": "You are a helpful assistant."},
    {"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
* 检查是否有损坏的数据

## 成本估算

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

| 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/)

**节省费用：**

* 使用 **竞价** 可中断工作市场——约三分之一的服务器将现货价格定得低于按需价格（中位数约优惠 13%），其余则与按需价格持平
* 使用 **CLORE** 代币支付
* 比较不同提供商的价格


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

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

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
