大模型微调实战手册:从零打造你的专属AI专家

6 阅读22分钟

用一张游戏显卡,让通用模型学会你的独门绝技

你有没有这样的经历:向AI问一个你行业里的常识问题,它给出的答案听起来头头是道,却完全不对路?你让它模仿你公司的客服口吻,结果它开口就是一股机器人味儿?

这不能怪AI。通用大模型就像一个读了万卷书的大学生——知识面很广,但没在你这个行业上过一天班。想让AI真正成为你的得力干将,你需要一项关键技术:监督微调(Supervised Fine-Tuning,SFT)

这篇文章会从零开始,把SFT是什么、怎么做、怎么省钱、怎么避坑,从头到尾讲一遍。全文约1.2万字,建议收藏后慢慢看。


1 为什么模型需要“再教育”?

1.1 大模型的三段式成长

今天的主流大模型(比如GPT-4、Qwen、Llama)都要经历三个阶段才能变得好用。你可以把它想象成一个员工的成长过程:

  • 预训练(Pre-training)

    :模型被喂了互联网上几乎所有的文本——维基百科、新闻、论文、论坛……总量几十个TB。它的任务很简单:猜下一个词。这个阶段结束后的模型叫Base Model。它知识丰富,但完全不会“听指令”。你问它“今天天气怎么样”,它可能把“天气”这个词后面所有可能的续写都生成一遍。

  • 监督微调(SFT)

    :我们给模型看大量的“指令→回答”例子,比如:
    指令:把“我很好”翻译成英文 → 回答:I am fine.
    模型通过这些例子学会了:别人给我一个任务,我就要按要求输出。这个阶段结束后的模型叫Instruct Model。你现在用的ChatGPT、通义千问都属于这一类。

  • 偏好对齐(RLHF/DPO)

    :教模型什么该说、什么不该说,让它更安全、更有帮助、更诚实。

你平时说的“微调”,99%指的是第二个阶段——监督微调。

1.2 为什么不能只靠“写提示词”?

有人会问:我多写几个提示词,让模型学会不行吗?
可以,但效果有限。 提示工程和微调的区别,就像“看说明书”和“真正学会开车”。

对比项

提示工程

监督微调

需要数据量

几条示例

几百到几千条

模型理解深度

临时记忆(在上下文窗口内)

永久记忆(写进模型参数)

格式稳定性

不稳定,换个说法可能崩

稳定,模型真正记住了规则

成本

需要一点算力(但可控)

适用场景

简单任务、快速验证

生产环境、稳定输出

一个真实案例:你想让模型输出固定的JSON格式 {"code":200,"data":...}。用提示工程,今天写“请输出JSON,格式为...”,模型照做了;明天换个问法,它可能给你 {status:"ok"}。但如果你用微调,给它几百条正确格式的样本,它就能牢牢记住这个格式。

1.3 什么情况下应该微调?

先用提示工程试,如果出现以下情况,再考虑微调:

  • 模型能力确实不够

    :你换了好几种提示写法,甚至给了几个示例(few-shot),模型还是经常出错。

  • 格式要求很严格

    :比如需要输出固定的XML结构、特定的JSON字段,提示工程总是“偶尔翻车”。

  • 降低成本

    :你现在用GPT-4每月花好几千,但你的任务其实不难。这时候可以微调一个小模型(比如7B参数的Qwen),部署在自己服务器上,成本能降90%以上。


2 起跑线怎么选:Base模型还是Instruct模型?

这是初学者最容易踩的坑。你下载模型时,会发现同一个名字通常有两个版本:

  • Qwen/Qwen2-7B-Base —— Base版

  • Qwen/Qwen2-7B-Instruct —— Instruct版

直接说结论:99%的情况选Instruct版。

维度

Base模型

Instruct模型

是否需要教它“听懂指令”

需要,从头教

不需要,已经会了

需要的数据量

几万条起

几百到两千条就够了

训练后是否还要做对齐

通常需要,否则可能乱说话

不需要,已经对齐过

适合谁

研究人员、特殊格式爱好者

普通开发者、企业应用

只有两种极端情况才考虑Base模型

  1. 你的任务形式极其特殊,Instruct模型自带的对话模板反而碍事(比如你在做一个全新的交互范式)。

  2. 你有海量高质量数据(5万条以上)且预算充足,打算从头训练一个完全定制化的模型。

其他情况,一律用Instruct模型。这就像招员工,你肯定优先选有工作经验的,而不是从零培养。

一个关键提醒:Instruct模型在微调时,必须使用和它训练时一模一样的聊天模板(Chat Template)。比如Qwen用的是ChatML格式,会插入 <|im_start|>user 这样的特殊标记。如果你换了另一种模板,模型就不知道哪里是用户的话、哪里是助手的话,训练效果会一塌糊涂。好在现代框架会自动处理这件事——你只需要在分词器上调用 apply_chat_template 即可。


3 数据:微调的灵魂

如果说模型是发动机,那数据就是燃料。数据质量直接决定微调效果,比模型选择、参数调整都重要。

3.1 数据从哪里来?

公共数据源(适合练手、验证想法):

  • Hugging Face Hub

    :全球最大的数据集仓库,搜一下“medical”“chinese”就能找到很多。用 datasets 库一行代码就能下载。

  • ModelScope

    :阿里旗下的平台,有很多中文高质量数据集,尤其是医疗、金融领域。

私有数据源(这才是你的核心竞争力):

  • 公司内部的聊天记录(客服对话、销售沟通)

  • 历史文档(报告、邮件、会议纪要)

  • 行业数据库(电子病历、交易记录)

私有数据通常很“脏”,需要你做大量清洗:去掉隐私信息、统一格式、修正错别字。一般建议用内部专家标注,或者借助自动化工具(比如Easy Dataset)提高效率。

3.2 数据长什么样?两种主流格式

3.2.1 指令式(适合单轮任务)

源于斯坦福的Alpaca项目,每条数据有三个字段:

{
  "instruction": "将以下英文翻译成中文",
  "input": "Large language models are transforming AI.",
  "output": "大语言模型正在改变人工智能。"
}

如果任务不需要额外输入,input 字段可以留空。训练时,框架会自动把它们拼成类似这样的文本:

指令:将以下英文翻译成中文
输入:Large language models are transforming AI.
回答:大语言模型正在改变人工智能。

3.2.2 对话式(适合多轮聊天)

最常用的是OpenAI格式

{
  "messages": [
    {"role": "system", "content": "你是一个专业的营养师,回答要基于科学证据。"},
    {"role": "user", "content": "我最近下午总是犯困,有什么零食推荐?"},
    {"role": "assistant", "content": "下午犯困常见原因有午餐后血糖波动、脱水等。推荐你试试:1)一小把原味坚果;2)希腊酸奶;3)一个苹果。同时注意多喝水。"},
    {"role": "user", "content": "坚果会不会热量太高?"},
    {"role": "assistant", "content": "确实,坚果热量不低。建议每天一小把(约20克),不要过量。如果你想控热量,黄瓜条、小番茄也是不错的选择。"}
  ]
}

字段说明:

  • system:系统提示,设定模型的“人设”和规则(可选,但强烈建议加上)

  • user:用户的输入

  • assistant:模型的回答

还有一种ShareGPT格式,它用 conversations 列表,每个元素包含 from(human/gpt)和 value。两种格式本质一样,选你顺手的就行。

3.3 一个非常重要的细节:损失掩码

训练时,我们要告诉模型:只学习assistant的回答,不要把用户的提问也背下来

为什么?如果不这样做,模型就会“作弊”——它发现训练数据里每个用户的提问后面都跟着一个固定回答,于是它学会了“看到这个提问,就原样输出那个回答”,而不是真正理解提问内容。这样的模型换一个问法就完全不会了。

在 SFTTrainer 里,你只需要设置 assistant_only_loss=True,它会自动处理。原理是在计算损失(模型预测和正确答案之间的差距)时,把用户提问部分的损失权重设为0,只计算assistant回答部分的损失。

示意(使用ChatML模板):

<|im_start|>user\n今天天气怎么样?<|im_end|>        ← 这部分不计入损失
<|im_start|>assistant\n今天晴,25度。<|im_end|>   ← 这部分计入损失

4 微调方法怎么选?全参数、LoRA、QLoRA

这一节教你省钱。我们先对比三种方法,再说具体怎么选。

4.1 全参数微调(Full Fine-tuning)

做什么:更新模型的每一个参数。比如一个70亿参数的模型,你要更新全部70亿个值。

优点:理论上效果最好,能最大化适配你的任务。

缺点:极其吃显存。70亿模型,FP16精度下:

  • 模型参数:14 GB

  • 梯度:14 GB

  • 优化器状态(Adam):56 GB(每个参数存两个FP32状态)

  • 激活值:8~16 GB

  • 总计轻松超过100 GB

这还没算临时变量。你需要多张A100/H100这种专业卡,硬件投入十几万起步。

适合谁:大公司、研究所、不差钱且对性能有极致要求的场景。

4.2 LoRA(低秩适应)——目前最主流的方法

核心思想:微调时真正需要改变的信息其实很少,可以“压缩”成两个小矩阵。

数学上:原来的权重矩阵是 W0W0(尺寸 d×kd×k),全参数微调会学到一个变化量 ΔWΔW。LoRA发现 ΔWΔW 可以分解成两个小矩阵的乘积:ΔW≈A×BΔW≈A×B,其中 AA 尺寸 d×rd×r,BB 尺寸 r×kr×k,rr 很小(通常4~32)。

一个直观例子:假设 d=k=4096d=k=4096,原来的 ΔWΔW 有 4096×4096≈16004096×4096≈1600 万个参数。用LoRA且 r=8r=8 时,AA 有 4096×8=327684096×8=32768 个参数,BB 有 8×4096=327688×4096=32768 个参数,加起来只有65536个参数,是原来的 0.4%

训练过程

  • 冻结原始权重 W0W0(不更新,只参与计算)

  • 只训练新增的小矩阵 AA 和 BB

  • 前向计算时:输出 = (W0+A×B)×(W0+A×B)× 输入

优点

  • 显存占用小(因为梯度只对 AA、BB 计算,不需要存 W0W0 的梯度)

  • 训练快

  • 同一个模型可以挂多个不同的LoRA模块,切换任务只需要换 AA 和 BB,不用复制整个模型

工程实现中的两个小技巧

  • 缩放系数 αα

    :为了控制LoRA增量在训练初期的影响力,前向计算时通常写成 W=W0+αrBAW=W0+rαBA。αα 一般设为 rr 的两倍。

  • LoRA Dropout

    :在LoRA层输入上加dropout(比如0.05~0.1),提升泛化能力,减轻小数据集上的过拟合。

实际建议

  • 秩 rr 一般取8、16、32。太小表达力不足,太大收益递减。

  • 通常只对注意力层的 q_proj 和 v_proj 加LoRA,这两个模块对任务语义最敏感。如果想更强,可以再加 k_proj、o_proj 或FFN层。

4.3 QLoRA —— 穷人的法拉利

做什么:先把模型权重压缩成4位(原本是16位或32位),然后在上面挂LoRA。压缩后显存占用降到原来的1/4左右。

三大核心技术

  1. 4-bit NormalFloat(NF4)量化

    :传统4-bit量化在0附近精度不够,因为模型权重服从正态分布,0附近最密集。NF4针对正态分布设计量化格点,在0附近更密集,两端更稀疏,误差更小。

  2. 双重量化(Double Quantization)

    :不仅量化权重,还量化“量化用的缩放因子”,进一步省显存。

  3. 分页优化器(Paged Optimizer)

    :优化器状态不再全塞进显存,而是拆成“页”,用哪页就临时从内存加载哪页,用完就释放。这大大降低了峰值显存。

实际效果:一张24GB的RTX 4090,用QLoRA可以微调300亿参数的模型(比如Qwen-30B),而用普通LoRA最多只能跑130亿左右。

性能损失:几乎没有。论文和大量实践都证明,QLoRA的效果和全参数微调相差在1%以内。

4.4 到底选哪个?一张表搞定

你的情况

推荐方法

理由

只有一张消费级显卡(24GB显存),模型≤7B

LoRA

足够,训练快

只有一张消费级显卡,模型≥13B

QLoRA

唯一可行的方案

有多张A100/H100,追求极致性能

全参数微调

不差钱就上

你是个人开发者,想省时间

QLoRA

省显存、省心

我的建议:无脑上QLoRA。它让你用最低的成本获得接近顶配的效果,而且代码改动极小(只需在加载模型时加一行 load_in_4bit=True)。


5 动手实战:用SFTTrainer微调你的第一个模型

我们以Hugging Face生态的 SFTTrainer 为例。这是目前最简单、最稳定的微调工具。

5.1 安装环境

pip install torch transformers accelerate peft trl datasets
# 如果你用QLoRA,还需要
pip install bitsandbytes

5.2 完整代码示例

假设你要微调一个医疗问答助手,数据集用的是OpenAI格式的对话数据。

import torch
from datasets import load_dataset
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from trl import SFTTrainer, SFTConfig
from peft import LoraConfig, prepare_model_for_kbit_training
 
# ========== 1. 配置量化(QLoRA)==========
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,                      # 4位加载
    bnb_4bit_quant_type="nf4",             # 使用NF4量化
    bnb_4bit_compute_dtype=torch.bfloat16, # 计算时用bfloat16
)
 
# ========== 2. 加载模型和分词器 ==========
model_id = "Qwen/Qwen2-7B-Instruct"        # 用Instruct版本
model = AutoModelForCausalLM.from_pretrained(
    model_id,
    quantization_config=bnb_config,        # 启用QLoRA量化
    device_map="auto",                     # 自动分配到GPU
    trust_remote_code=True,
)
tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token  # 设置填充token
 
# ========== 3. 准备模型(对QLoRA必需)==========
model = prepare_model_for_kbit_training(model)
 
# ========== 4. 配置LoRA ==========
lora_config = LoraConfig(
    r=16,                     # 秩
    lora_alpha=32,            # 缩放系数,通常设为r的2倍
    target_modules=["q_proj", "v_proj"],   # Qwen的注意力模块名
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM",
)
 
# ========== 5. 加载数据集 ==========
# 假设你的数据集是JSONL格式,每条有"messages"字段
dataset = load_dataset("json", data_files="my_medical_data.jsonl")
 
# ========== 6. 训练参数 ==========
training_args = SFTConfig(
    output_dir="./medical_assistant",
    per_device_train_batch_size=2,          # 根据显存调整,24GB可用2~4
    gradient_accumulation_steps=4,          # 模拟更大的batch(2×4=8)
    learning_rate=2e-5,                     # Instruct模型用较小的学习率
    max_seq_length=2048,                    # 上下文长度
    num_train_epochs=3,                     # 训练3轮
    logging_steps=10,
    save_steps=500,
    save_total_limit=2,                     # 只保留最近2个checkpoint
    bf16=True,                              # 如果GPU支持(RTX 3090/4090支持)
    gradient_checkpointing=True,            # 用时间换显存
    optim="paged_adamw_8bit",               # QLoRA推荐的分页优化器
    # 关键:只训练assistant部分
    assistant_only_loss=True,
)
 
# ========== 7. 创建Trainer并训练 ==========
trainer = SFTTrainer(
    model=model,
    args=training_args,
    train_dataset=dataset,
    tokenizer=tokenizer,
    peft_config=lora_config,
    dataset_text_field=None,                # 因为用的是messages格式
    dataset_kwargs={"add_special_tokens": False, "return_token_type_ids": False},
)
 
trainer.train()
 
# ========== 8. 保存模型 ==========
trainer.save_model("./medical_assistant_final")
tokenizer.save_pretrained("./medical_assistant_final")

5.3 几个关键参数的解释

参数

作用

建议值

learning_rate

学习率

Instruct模型:1e-5

~

5e-5;Base模型:1e-4

~

5e-4

per_device_train_batch_size

每张卡一次处理几个样本

显存允许下越大越好,但一般2~4

gradient_accumulation_steps

累积几步梯度再更新

模拟大batch,比如batch=2、累积4步,等效batch=8

bf16

/

fp16

混合精度

有Ampere及以上显卡(RTX 3090/4090/A100)用bf16,否则用fp16

gradient_checkpointing

是否用梯度检查点

开启能省20%~30%显存,代价是训练慢15%左右

max_seq_length

最大序列长度

一般2048够用,如果有长文档可以调大到4096或8192,但显存会涨

warmup_ratio

预热步数比例

0.03~0.1,让学习率慢慢升上去,避免初期震荡

5.4 训练后的推理

训练完成后,你得到了一个LoRA适配器(很小,几十MB)。使用时要先加载基座模型,再加载适配器:

from peft import PeftModel
 
base_model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen2-7B-Instruct",
    device_map="auto",
    trust_remote_code=True,
)
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2-7B-Instruct")
 
model = PeftModel.from_pretrained(base_model, "./medical_assistant_final")
 
# 对话测试
messages = [
    {"role": "system", "content": "你是一个专业的医疗助手。"},
    {"role": "user", "content": "我头疼两天了,吃了布洛芬也没用,怎么办?"}
]
# 应用聊天模板
text = tokenizer.apply_chat_template(messages, tokenize=False)
inputs = tokenizer(text, return_tensors="pt").to("cuda")
outputs = model.generate(**inputs, max_new_tokens=512)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))

6 分布式训练:当单卡不够用时

如果你要微调更大的模型(比如70B),或者想加速训练,就要用到多卡并行。这一节简单介绍几种主流策略。

6.1 数据并行

做法:每张卡放一个完整的模型副本,每张卡处理不同的数据子集。前向、反向在各卡独立完成,然后AllReduce所有卡的梯度,取平均后再统一更新参数。

优点:实现简单,提升吞吐量。
缺点:每张卡都要存完整模型,显存没有节省。
适合:模型能装进单卡,但想加速训练。

6.2 流水线并行

做法:把模型按层切分,比如前10层放在GPU0,中间10层放GPU1,最后10层放GPU2。数据像流水线一样依次经过各卡。

问题:会有“气泡”——GPU1在等GPU0算完,GPU2在等GPU1。解决方法是用微批次,把一个batch拆成很多小份,让各卡尽量不闲着。

优点:能装下比单卡大得多的模型。
缺点:实现复杂,有气泡开销。

6.3 张量并行

做法:把单层内的矩阵乘法拆到多卡上。比如一个4096×4096的权重矩阵,切成4块1024×4096,每张卡存一块。

优点:细粒度并行,能处理超宽模型。
缺点:通信量大(每次矩阵乘都要同步结果)。

6.4 专家并行

专门针对MoE(混合专家) 模型。MoE模型里有多个“专家”FFN层,彼此独立,可以直接把不同专家分配到不同设备上。

6.5 ZeRO —— 数据并行的“增强版”

ZeRO由微软提出,是当前训练超大模型最常用的技术。它解决了数据并行中“每张卡都存一份完整模型状态”的冗余问题。

ZeRO把模型状态(参数、梯度、优化器状态)分成三档:

阶段

分片内容

显存节省

通信开销

ZeRO-1

仅优化器状态分片

4倍左右

ZeRO-2

优化器状态+梯度分片

8倍左右

ZeRO-3

优化器状态+梯度+参数分片

16倍左右

实际使用:DeepSpeed框架原生支持ZeRO。你只需要写一个 ds_config.json,指定 "zero_optimization": {"stage": 2} 即可。

6.6 我需要分布式训练吗?

模型大小

单卡24GB(QLoRA)

单卡80GB(A100)

是否需要多卡

7B

✅ 能跑

✅ 能跑

不需要

13B

✅ 能跑(QLoRA)

✅ 能跑

不需要

30B

✅ 能跑(QLoRA)

✅ 能跑

不需要

70B

❌ 不够

⚠️ 勉强(QLoRA)

推荐2×A100

130B+

❌ 不可能

❌ 单卡不够

必须多卡

结论:绝大多数个人和小团队用不到分布式训练。QLoRA让你在一张卡上就能搞定30B以下的模型。


7 显存估算:别等跑起来才发现卡不够

7.1 显存都去哪儿了?

微调时显存主要被五样东西吃掉:

  1. 模型参数

    :FP16下,1B参数≈2GB;FP32下≈4GB;INT4下≈0.5GB

  2. 梯度

    :和参数同样大小(因为每个参数都有梯度)

  3. 优化器状态

    :Adam优化器每个参数要存一阶矩和二阶矩,都是FP32,所以是 2×4=82×4=8 字节/参数

  4. 激活值

    :和batch size、序列长度、模型层数成正比。经验公式:激活值≈batch×seq_len×hidden_size×layers×(10∼30)激活值≈batch×seq_len×hidden_size×layers×(10∼30)

  5. 临时缓存

    :CUDA内核、通信缓冲区等

7.2 快速估算表(以7B模型为例)

微调方法

参数+梯度

优化器状态

激活值(估)

总计(约)

全参数(FP16)

14+14=28GB

56GB

8~16GB

92~100GB

LoRA(FP16,r=16)

14GB(冻结) + 0.02GB(LoRA)

~0.16GB

8~16GB

22~30GB

QLoRA(4bit)

3.5GB(4bit) + 0.02GB(LoRA)

~0.16GB

8~16GB

12~20GB

实际中,开启 gradient_checkpointing 可以再减少30%的激活值显存。

7.3 一个在线工具

如果不想手算,推荐这个显存计算器:apxml.com/zh/tools/vr…

输入模型参数量、精度、batch size等,它会给你一个比较准的估算。


8 微调工具生态

除了前面讲的SFTTrainer,还有几个工具你也应该知道。

8.1 DeepSpeed

微软出品,分布式训练的王牌。集成了ZeRO、流水线并行、张量并行等。适合训练超大规模模型。配置稍复杂,但功能强大。

8.2 Accelerate

Hugging Face的轻量级分布式训练接口。只需要在普通训练脚本上加几行装饰器,就能自动适配单卡、多卡、DeepSpeed等后端。对新手很友好。

8.3 PEFT

Hugging Face的参数高效微调库,封装了LoRA、QLoRA、Adapter等多种方法。SFTTrainer底层用的就是它。

8.4 Unsloth

一个专注于“加速”的库。它重写了LoRA/QLoRA的内核,训练速度能提升2~5倍,显存占用也降低不少。支持Llama、Qwen、Mistral等主流模型。个人强烈推荐。

8.5 LLaMA Factory

一个“开箱即用”的微调框架,带图形界面(WebUI)。你不需要写代码,上传数据、点几下按钮就能微调。很适合不想折腾代码的产品经理或研究员。

8.6 TRL

Hugging Face的强化学习库,但也包含了SFTTrainer。如果你未来还想做PPO、DPO等对齐训练,用TRL生态最顺手。


9 避坑指南:我踩过的5个坑

坑1:从Base模型开始,数据不够

很多人觉得“从零开始更自由”,结果只准备了2000条数据就开搞。Base模型没有指令理解能力,2000条根本不够它学会“怎么听指令”。最后模型一塌糊涂。

解法:听我一句劝,用Instruct模型。2000条数据效果就很好了。

坑2:学习率设太大

Instruct模型已经是训练好的,学习率如果设成 1e-4 甚至更高,模型会很快“忘记”怎么聊天。你的数据没学会,原来的能力倒丢光了。

解法:用 2e-5 左右,保守一点可以 1e-5。

坑3:忘了设置assistant_only_loss

如果没有这个设置,模型会同时学习用户的提问和助手的回答。结果就是你问“今天天气如何”,它把你的问题原样背出来,而不是回答天气。

解法:SFTTrainer里设置 assistant_only_loss=True。

坑4:数据集格式和模板不匹配

你的数据是 messages 格式,但tokenizer用的模板是ChatML,这个没问题。但如果你把 messages 直接当成文本传给trainer而不调用 apply_chat_template,模型就看不到 <|im_start|> 这些标记。

解法:要么在预处理时对每条数据调用 tokenizer.apply_chat_template,要么让SFTTrainer自动处理(设置 dataset_kwargs)。

坑5:序列长度设置太小

你的业务数据里可能有很长的对话或文档,但 max_seq_length 只设了512。训练时所有长文本都被截断,模型永远学不到完整的上下文。

解法:统计一下你的数据长度分布,一般设1024或2048就够了。如果确实有超长文本(比如法律合同),可以设4096,但显存会涨。


10 写在最后

微调这件事,听起来高大上,实际上门槛已经很低了。

五年前,你想微调一个BERT都要写几百行代码;三年前,微调GPT需要几十万的专业卡;今天,一个普通开发者用两千块的二手RTX 3090,加上我上面给的不到100行代码,就能让一个70亿参数的模型学会你的业务知识。

最后送你三个建议

  1. 先跑通,再优化

    :第一次微调时,用最小的数据量(比如200条)、最少的训练步数(比如100步),确保整个流程能跑通。再慢慢加数据、调参数。

  2. 数据质量 > 数据数量

    :1000条精心标注、格式统一、覆盖全面的数据,远好于10000条充满噪音的数据。

  3. 不要过度微调

    :如果你的任务只需要模型改个输出格式,也许写个更好的提示词就解决了。微调是工具,不是目的。

希望这篇文章能帮你真正入门大模型微调。如果你在实际操作中遇到问题,欢迎在评论区留言,我会尽量解答。