1538 字
8 分钟
手把手教你微调 DeepSeek 模型:从数据准备到模型部署完整指南
手把手教你微调 DeepSeek 模型:从数据准备到模型部署完整指南
🎯 开场白:相信很多人都听说过”微调”这个词,但真正动手做过的人不多。原因是啥?门槛太高了呗!又要准备数据、又要调参数、又要租 GPU……听起来就劝退。但其实在 2026 年的今天,微调一个 DeepSeek 模型比你想的要简单得多。今天我就带你走一遍完整流程,保证从零跑到起飞。
一、为什么选 DeepSeek 做微调?
选 DeepSeek 做微调,有这几点好处:
- 模型开源 —— 权重随便下,不用看任何人脸色
- 参数量适中 —— 7B/14B,单卡 24G 显存就能跑
- 中文底子好 —— 微调后特别适合中文垂直场景
- 社区活跃 —— 有问题在 GitHub 上吼一声就有人回
二、环境准备
2.1 硬件要求
| 模型 | 最低显存 | 推荐配置 | 训练方式 |
|---|---|---|---|
| DeepSeek-7B | 16GB | 24GB (RTX 3090) | QLoRA |
| DeepSeek-14B | 24GB | 48GB (A6000) | QLoRA |
| DeepSeek-67B | 48GB | 80GB (A100) | LoRA |
不用怕,后面的示例我用 7B + QLoRA,一张 RTX 3090 就能跑。
2.2 安装依赖
# 创建虚拟环境python -m venv finetune-envsource finetune-env/bin/activate
# 安装核心库pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121pip install transformers datasets accelerate peft bitsandbytes
# 安装 DeepSeek 相关pip install deepseek-llm三、数据准备
这是微调最关键的步骤。数据质量决定了模型微调的上限。
3.1 数据格式
DeepSeek 微调使用的是对话格式:
[ { "instruction": "用 Python 实现一个二分查找算法", "input": "", "output": "```python\ndef binary_search(arr, target):\n left, right = 0, len(arr) - 1\n \n while left <= right:\n mid = (left + right) // 2\n if arr[mid] == target:\n return mid\n elif arr[mid] < target:\n left = mid + 1\n else:\n right = mid - 1\n \n return -1\n```\n\n**算法说明**:\n- 时间复杂度:O(log n)\n- 空间复杂度:O(1)\n- 前提条件:数组必须是有序的" }, { "instruction": "解释什么是 RESTful API", "input": "", "output": "RESTful API(Representational State Transfer)是一种 API 设计规范...(省略 200 字)..." }]3.2 数据增强技巧
我自己用的一个数据增强脚本,能把少量数据变成大量高质量数据:
import jsonimport randomfrom typing import List, Dict
class DataAugmenter: """数据增强器:一条数据变成 N 条"""
def __init__(self, seed_data: List[Dict]): self.data = seed_data
def paraphrase_instruction(self, text: str) -> str: """改写指令(用 LLM 做同义改写)""" templates = [ f"请解释一下:{text}", f"跟我说说 {text} 是怎么回事", f"给我详细讲讲 {text}", f"你能介绍一下 {text} 吗?", f"关于 {text},你知道些什么?" ] return random.choice(templates)
def split_long_output(self, output: str) -> List[str]: """拆分长输出为多个知识点""" sections = output.split("\n\n") return [s.strip() for s in sections if len(s.strip()) > 50]
def augment(self, multiplier: int = 3) -> List[Dict]: """增强数据集""" augmented = [] for item in self.data: augmented.append(item) # 保留原始 for _ in range(multiplier - 1): new_item = { "instruction": self.paraphrase_instruction(item["instruction"]), "input": item["input"], "output": item["output"] } augmented.append(new_item) return augmented
# 使用augmenter = DataAugmenter(raw_data)final_data = augmenter.augment(multiplier=5)print(f"数据量:{len(raw_data)} → {len(final_data)}")四、开始微调
4.1 加载模型和分词器
import torchfrom transformers import ( AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig)from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training
# 4-bit 量化配置(省显存的关键)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( "deepseek-ai/deepseek-llm-7b-chat", quantization_config=bnb_config, device_map="auto", trust_remote_code=True,)
# 加载分词器tokenizer = AutoTokenizer.from_pretrained( "deepseek-ai/deepseek-llm-7b-chat", trust_remote_code=True,)tokenizer.pad_token = tokenizer.eos_token4.2 配置 LoRA
# LoRA 配置——只训练一小部分参数lora_config = LoraConfig( r=16, # LoRA 秩,越大效果越好但也越耗显存 lora_alpha=32, # 缩放参数 target_modules=[ # 要微调的目标模块 "q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj", ], lora_dropout=0.05, # Dropout 防止过拟合 bias="none", task_type="CAUSAL_LM",)
# 应用 LoRAmodel = prepare_model_for_kbit_training(model)model = get_peft_model(model, lora_config)
# 看看有多少参数被训练model.print_trainable_parameters()# 输出: trainable params: 8,388,608 || all params: 6,743,363,584 || trainable%: 0.12%注意看!总共 67 亿参数,我们只训练了 838 万参数,只占 0.12%!这就是 LoRA 的魔力——少花钱、多办事。
4.3 训练
from transformers import TrainingArguments, Trainer
training_args = TrainingArguments( output_dir="./deepseek-finetuned", num_train_epochs=3, per_device_train_batch_size=4, gradient_accumulation_steps=4, warmup_steps=100, learning_rate=2e-4, fp16=True, logging_steps=10, save_strategy="epoch", report_to="none", # 不想看 wandb 可以关掉)
trainer = Trainer( model=model, args=training_args, train_dataset=tokenized_dataset, data_collator=default_data_collator,)
# 开跑!(去泡杯咖啡,半小时后回来)trainer.train()4.4 保存模型
# 保存 LoRA 权重(只有几十 MB)model.save_pretrained("./my-deepseek-lora")tokenizer.save_pretrained("./my-deepseek-lora")
# 如果想把 LoRA 合并到原模型(会变大)from peft import PeftModel
merged_model = PeftModel.from_pretrained(model, "./my-deepseek-lora")merged_model = merged_model.merge_and_unload()merged_model.save_pretrained("./my-deepseek-merged")五、模型评估
训练完了,效果到底怎么样?来跑个测试:
def evaluate_model(model, tokenizer, test_data): """评估微调后的模型""" results = [] for item in test_data: prompt = f"### Instruction:\n{item['instruction']}\n\n### Response:\n" inputs = tokenizer(prompt, return_tensors="pt").to("cuda")
outputs = model.generate( **inputs, max_new_tokens=512, temperature=0.7, do_sample=True, )
response = tokenizer.decode(outputs[0], skip_special_tokens=True) response = response.replace(prompt, "").strip()
results.append({ "instruction": item["instruction"], "expected": item["output"][:100], "actual": response[:100], "match": response[:50] == item["output"][:50] })
return results
# 执行评估eval_results = evaluate_model(model, tokenizer, test_data)accuracy = sum(r["match"] for r in eval_results) / len(eval_results)print(f"准确率: {accuracy:.2%}")六、模型部署
6.1 使用 vLLM 部署
# 安装 vLLMpip install vllm
# 启动推理服务python -m vllm.entrypoints.openai.api_server \ --model ./my-deepseek-merged \ --port 8000 \ --tensor-parallel-size 16.2 调用 API
curl -X POST http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "my-deepseek-merged", "messages": [ {"role": "user", "content": "用 Python 实现冒泡排序"} ] }'6.3 集成到 Hermes
# hermes config.yamlcustom_providers: my-finetuned-deepseek: api_base: http://localhost:8000/v1 model: my-deepseek-merged api_key: "not-needed"然后你就可以在 Hermes 里用微调后的模型了:
hermes config set provider customhermes config set custom_providers.my-finetuned-deepseek.api_base http://localhost:8000/v1hermes config set custom_providers.my-finetuned-deepseek.model my-deepseek-merged七、常见问题
Q1: 显存不够怎么办?
用 QLoRA + 4-bit 量化,7B 模型只需要 8-10GB 显存:
# 用 accelerate 做 CPU offloadaccelerate launch --cpu_offload train.pyQ2: 训练完效果不好?
大概率是数据问题。检查:
- 数据量是否够(至少 500+ 条)
- 数据质量(有没有错别字、格式问题)
- 训练轮数(太多会过拟合,太少学不到)
Q3: 模型回答变得很啰嗦?
调低 repetition_penalty:
outputs = model.generate( **inputs, repetition_penalty=1.1, # 默认 1.0,适当提高)八、总结
微调 DeepSeek 的完整流程其实就 5 步:
准备数据 → 配置 LoRA → 开始训练 → 评估效果 → 部署上线最难的是第一步(数据准备),最花钱的其实没有(一张 3090 就能跑)。比起每个月花几百刀调 API,一次微调,终身受益。
💡 最后提醒:微调不是万能药。如果你的场景是通用编程/问答,直接用原版模型就好。微调最适合的是垂直领域——比如你们公司的代码规范、特定业务逻辑、专有术语体系等。
快去看看你的硬盘上有没有合适的训练数据,动手试试吧!
手把手教你微调 DeepSeek 模型:从数据准备到模型部署完整指南
https://www.oferry.com/posts/a95/