ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

大模型指令微调入门:从NLP四范式到LoRA实战

大模型指令微调入门:从NLP四范式到LoRA实战

简介:这份PPT面向自然语言处理与大模型微调初学者及需要课堂或组内分享的技术人员,系统梳理NLP四范式演进,并聚焦大语言模型指令微调的基本流程与核心概念。包内仅含1个pptx文件,压缩包约2.65MB,结构紧凑,便于快速浏览和二次整理。内容从传统机器学习、深度学习、预训练加微调到预训练加Prompt四条路线展开,说明指令微调如何弥合下一词预测目标与用户指令执行目标之间的差距,并涉及指令数据集的三要素、手动构建与自动生成两类方法、监督微调步骤及其可控性和计算效率优势。目前已有4262人学习下载,适合用来建立大模型微调的整体认知框架,也可作为课程汇报或入门备课的参考素材。

1. 先搞懂一件事:大模型指令微调到底在调什么

很多人第一次听到“大模型指令微调”,脑子里浮现的画面是几个人对着一个几百亿参数的庞然大物改代码。其实不是这样。你可以把预训练好的大模型想成一个读完了整座图书馆、但从没上过一天班的新人:知识很多,可你跟他说“把这段会议记录整理成三条待办”,他未必照做,甚至可能顺着你的话继续往下编。指令微调(Instruction Tuning)就是给这个新人做岗前培训——拿一批“命令 + 标准答案”的示范给他看,教他听懂人话、按格式交付。它不需要从头训练,也不用海量数据,几百到几千条高质量示范,就能让输出风格明显变得符合期望。自然语言处理和深度学习做了这么多年,真正让普通人敢用大模型的,恰恰是这一步“岗前培训”。这份入门内容面向完全没接触过微调的人,按“是什么、为什么、第一个例子怎么跑”的顺序走一遍。

2. 为什么要学:从 NLP 四范式看清微调站在哪一步

学一个新技术,最怕不知道它从哪来、为什么非它不可。大模型微调不是凭空冒出来的,它是自然语言处理这条技术路线走到第四站之后,必然要补上的一个环节。把前面三站看一遍,你就明白自己现在站在哪、为什么这一步绕不过去。

2.1 四次换挡:NLP 四范式到底在换什么

学术界习惯把自然语言处理的发展分成四个范式,这个分法对新手特别友好,因为它本质上是在讲“人干的活越来越少,模型干的活越来越多”。

第一范式是传统机器学习。你用 tf-idf 把一句话变成一堆词频数字,再喂给朴素贝叶斯之类的算法去分类。这个阶段人的工作量最大:得自己挑特征、自己设计规则,模型只是个算概率的工具。做情感分类,你得先想清楚“出现‘不错’加分、出现‘垃圾’减分”,写一堆规则,效果还很容易被反例打脸。

第二范式进入深度学习。word2vec 把词变成向量,LSTM 负责读序列,特征工程的工作量明显减少——你不用再手工写规则了,模型自己从数据里学。准确率上去了,但对数据量的要求也上去了,而且每个任务基本都要单独训一个模型。

第三范式是预训练 + 微调,BERT 是这一站的代表。先在海量文本上预训练一个“懂语言”的底座,再拿少量标注数据在下游任务上微调。好处很实在:小数据集就能训出好模型,准确度还比第二范式高。代价是模型参数量涨得厉害,而且每个任务都要存一份微调后的模型副本。

第四范式是预训练 + Prompt + 预测。不再改模型参数,而是把任务改写成一句“填空题”或者“指令”,让模型自己补全。训练所需的数据量进一步下降,一个模型能应付很多任务。你现在用各种对话式大模型时敲进去的那句话,本质上就是在做 Prompt。

四步走下来你会发现一个规律:模型越来越大,人给的数据越来越少,但对“模型能不能听懂我要什么”的要求越来越高。指令微调,就是第四范式真正落地时必须做的那道工序。

2.2 指令微调补上的三块短板

预训练阶段,模型学的目标只有一个:预测下一个词。这个目标很纯粹,也很有用,但它和用户的目标不是一回事。用户想要的是“照我说的做”,模型学的是“接着往下写”。这两件事之间的缝隙,就是指令微调要填的坑。具体来说,它补的是三块短板。

第一块,弥合“预测下一个词”和“按指令办事”之间的差距。你给基座模型一句“请把下面这段话改写成小学生能懂的表达”,它很可能不回你改写结果,而是接着编出“改写后的表达如下……”然后开始胡诌,或者干脆把这句话当成文章开头续写下去。因为它见过的文本里,这类句式后面跟着什么都有。指令数据集做的事情,就是把“这种句式后面应该跟一个合格的回答”这件事,反复示范给模型看。

第二块,让模型行为更可控、更可预测。基座模型的输出空间几乎是无限的,你永远猜不到它下一句会飘到哪。指令本身带有约束力,它把输出限制在你期望的响应特征或者领域知识范围内,相当于给人类留了一个介入模型行为的通道。你做客服机器人,就灌客服话术的指令;你做合同摘要,就灌法律文书的指令。同一套底座,不同的指令集,行为完全不同。

第三块,算力上更划算。指令微调不需要大量重新训练,也不用改模型架构,就能让模型快速适配某个特定领域。这一点对个人和小团队尤其关键——全量微调一个大模型,显卡开销是普通人难以承受的;而指令微调配合高效微调技术,一张消费级显卡就能跑起来。

提示:把这三块短板记住,后面看任何微调方案,你都能快速判断它到底在解决哪一个问题。很多教程一上来就贴代码,跳过这一步,结果读者跑完了也不知道自己在干嘛。

2.3 零基础的第一份知识清单

入门阶段最忌讳一头扎进公式里。下面这几个概念,是你动手之前必须能用自己的话讲清楚的,其余的都可以边做边补。

概念一句话解释入门阶段要不要深挖
预训练在海量文本上让模型学会“语言长什么样”知道存在即可
有监督微调用“输入 + 标准答案”的成对数据继续训练要理解,这是主线
指令数据集每条样本由指令、可选输入、期望输出三部分组成要理解,这是原料
高效微调只训练一小部分参数,冻住大部分要会用,先会用 LoRA
token模型眼里的“字”,一个汉字大约 1~2 个 token知道即可,用来估长度
学习率每次更新参数迈多大步子知道调大调小的后果
过拟合训练集上表现很好,换新题就露馅要能识别

学习顺序上,建议先跑通一个最小例子,再回头补概念。我见过太多人卡在“Transformer 注意力机制还没完全搞懂”这一步,然后就再也没往下走过。其实你先让模型按你的格式回答一句话,那种“它真的听我的了”的反馈,比看十篇原理文章都管用。概念可以在动手过程中一点点补,路走通了,理解自然跟上。

3. 第一个例子怎么跑:从一条指令数据开始

这一章是整篇里最需要你动手的部分。别怕,我们要跑的东西非常小:十几条样本、一个小参数量的开源基座、一次几分钟的训练。目标也不是做出产品,而是让你亲眼看到“微调前”和“微调后”的差别。

3.1 一条训练样本长什么样

指令数据集里的每条样本由三个元素组成,这三个元素的名字你后面会反复见到:

  • instruction:一段自然语言,用来指定任务。比如“为某某写一封感谢信”“以某某为主题写一篇博客”。
  • input:可选的补充信息,为上下文提供额外内容。没有就留空字符串。
  • output:基于指令和输入,期望模型给出的回答。

举个具体例子。instruction 是“把下面的句子改写成更正式的表达”,input 是“这事儿我觉得不太行”,output 就是“我认为此事可行性不足”。三条凑齐,才算一条完整的训练样本。注意 input 是可选的,很多任务不需要额外上下文,那就留空,不要硬凑。

这里有个新手常犯的误解:以为指令写得越长越专业越好。恰恰相反,指令应该是你在真实使用时会敲进去的那句话。你平时怎么问,训练数据就怎么写。如果你平时只打“帮我总结一下”,训练集里却全是“请你作为资深文本分析师,对以下内容进行结构化摘要”,那模型学到的风格和你实际用法是错位的。

3.2 把十几条样本拼成模型能读的文本

先把样本写成 Python 里的列表,这是最原始也最清楚的形态。别急着上框架,先看清楚数据长什么样。

# 每条样本三个字段,input 没有内容时留空字符串 samples = [ { "instruction": "把下面的句子改写成更正式的表达", "input": "这事儿我觉得不太行", "output": "我认为此事可行性不足", }, { "instruction": "给这段客服回复补一句安抚性的话", "input": "您的快递我们已经催了三次了", "output": "非常抱歉让您久等,我们已再次联系承运方,今天之内会同步最新进展给您。", }, { "instruction": "把这句话压缩到十个字以内", "input": "由于天气原因,本次航班预计会延误大约两个小时左右", "output": "航班因天气延误约两小时。", }, # 实际动手时建议写到 20 条以上,覆盖 3~4 类任务 ]

这段代码没有任何技术含量,但它是后面所有步骤的地基。真实项目中,这个列表可能来自 JSON 文件、数据库或者别人给你的数据集,结构都是这三个字段。

接下来要把三元组拼成一段文本。拼接方式没有唯一标准,关键是训练时怎么拼,推理时就必须怎么拼,两边必须完全一致。

def build_prompt(example): """把一条样本拼成模型实际看到的字符串""" prompt = f"### 指令:{example['instruction']}\n" if example["input"]: # input 为空时整段省略 prompt += f"### 输入:{example['input']}\n" prompt += "### 回答:" return prompt def build_full_text(example): """完整文本 = 提示部分 + 标准答案 + 结束符""" return build_prompt(example) + example["output"] + tokenizer.eos_token print(build_full_text(samples[0]))

这里有几个细节值得停下来看。第一,### 指令:这类分隔符是人为约定的,用[INST]、<|user|>也可以,只要前后一致。第二,input为空时整行省略,是为了避免模型学会“看到空的输入就发呆”。第三,结尾追加tokenizer.eos_token让模型知道“话说完了”,少了这个符号,模型容易在推理时停不下来,一直往下续写。

3.3 跑通一次最小规模的 LoRA 微调

全量微调一个大模型对新手来说成本太高,我们先上高效微调里最主流的 LoRA。它的核心假设很朴素:模型适配新任务时,权重的变化是“低秩”的,也就是不需要动整个大矩阵,加两个小矩阵近似一下就够。落到操作上,就是冻结原模型,只在若干层旁边挂两个小矩阵,训练时只更新这两个小矩阵。

import torch from transformers import AutoTokenizer, AutoModelForCausalLM, TrainingArguments, Trainer from transformers import DataCollatorForSeq2Seq from datasets import Dataset from peft import LoraConfig, get_peft_model # 1. 加载基座和分词器,路径换成你自己下载好的模型目录 model_dir = "./base-model" tokenizer = AutoTokenizer.from_pretrained(model_dir, trust_remote_code=True) if tokenizer.pad_token is None: tokenizer.pad_token = tokenizer.eos_token model = AutoModelForCausalLM.from_pretrained( model_dir, torch_dtype=torch.float16, device_map="auto" ) # 2. 只给注意力的四个投影层挂 LoRA,其余参数全部冻结 lora_cfg = LoraConfig( r=8, # 低秩矩阵的秩 lora_alpha=16, # 缩放系数 target_modules=["q_proj", "k_proj", "v_proj", "o_proj"], lora_dropout=0.05, bias="none", task_type="CAUSAL_LM", ) model = get_peft_model(model, lora_cfg) model.print_trainable_parameters() # 可训练参数通常不到总量的 1%

print_trainable_parameters()这行一定要留着,它会打印出可训练参数占总参数的比例。如果这个比例高得离谱,八成是你的target_modules写错了,把整个模型都挂上了。

然后是处理标签。这一步是整个流程里最容易被忽略、也最容易出错的地方:指令部分模型要读,但不应该被计入损失。做法是把指令部分的标签设成 -100,损失函数会自动跳过这些位置。

MAX_LEN = 512 def build_feature(example): prompt_ids = tokenizer(build_prompt(example), add_special_tokens=False)["input_ids"] answer_ids = tokenizer( example["output"] + tokenizer.eos_token, add_special_tokens=False )["input_ids"] input_ids = (prompt_ids + answer_ids)[:MAX_LEN] # 指令部分用 -100 屏蔽,只对回答部分计算损失 labels = ([-100] * len(prompt_ids) + answer_ids)[:MAX_LEN] return {"input_ids": input_ids, "labels": labels} ds = Dataset.from_list(samples).map(build_feature, remove_columns=["instruction", "input", "output"]) args = TrainingArguments( output_dir="./lora-out", per_device_train_batch_size=2, # 单卡一次喂几条,显存小就调到 1 gradient_accumulation_steps=4, # 攒 4 步再更新一次,等效批量翻倍 num_train_epochs=3, # 小数据集 3~5 轮通常够 learning_rate=2e-4, # LoRA 常用 1e-4 到 3e-4 logging_steps=5, save_strategy="epoch", fp16=True, report_to="none", ) trainer = Trainer( model=model, args=args, train_dataset=ds, data_collator=DataCollatorForSeq2Seq(tokenizer, padding=True), ) trainer.train() model.save_pretrained("./lora-out/final") # 只保存 LoRA 权重,几十 MB

参数我挑几个最影响结果的说明一下。r是低秩矩阵的秩,取值越大能学到的信息越多,但也越容易在小数据集上过拟合,入门阶段 8 或 16 就够用。lora_alpha是缩放系数,常见做法是取r的两倍。learning_rate明显比全量微调大,因为可训练参数少,步子可以迈得急一些;如果你发现损失剧烈震荡,先把它降到 1e-4。per_device_train_batch_size和gradient_accumulation_steps是可调的,显存不够就调小前者、调大后者,等效批量基本不变。

跑完之后注意看两件事:一是打印出来的可训练参数占比是不是在 1% 以内,二是损失曲线是不是整体向下但逐渐平缓。如果损失一路掉到接近 0,那大概率是数据太少、学过头了。

3.4 怎么判断这次微调到底有没有用

训练跑完不代表成功。最省事的验证办法,是准备五条训练集里没有出现过的指令,用微调前和微调后的模型各跑一遍,然后人眼对比。

def generate(model, instruction, input_text=""): prompt = build_prompt({"instruction": instruction, "input": input_text}) inputs = tokenizer(prompt, return_tensors="pt").to(model.device) with torch.no_grad(): out = model.generate( **inputs, max_new_tokens=128, do_sample=False, # 关掉随机采样,两次对比才公平 repetition_penalty=1.1, # 轻微抑制复读 ) return tokenizer.decode(out[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True)

do_sample=False是为了让输出确定,不然同一个问题每次答案都不一样,你就没法判断变化来自微调还是来自随机。max_new_tokens控制回答长度上限,入门阶段 128 足够。对比时重点看三件事:模型是不是开始遵守你约定的格式、回答有没有落到正确的任务上、有没有出现明显的复读或者答非所问。

如果三样都没改善,先别怀疑模型,回头检查你的数据格式和推理时的拼接方式是不是一致。这个坑我踩过不止一次,血泪经验。

注意:微调后保存下来的是几十 MB 的 LoRA 权重,不是完整模型。使用时需要把基座和这份权重一起加载,单独拿走那份权重文件是跑不起来的。

4. 数据从哪来:两条构建路线,新手先走哪条

模型、代码、参数都是现成的,真正决定成败的是数据。指令数据集的构建通常只有两条路:一条是从已有标注数据里用模板改写,另一条是让大模型批量生成。两条路没有优劣,只有适不适合你当前的场景。

4.1 路线一:用模板把已有标注数据改写成指令对

你手上如果已经有带标签的数据,这条路线成本最低。思路很直接:找到现成的“文本—标签”对,用模板把它们翻译成“指令—输出”对。

import json # 假设你手里有一批情感标注数据:(句子, 标签),1 表示正面 raw_pairs = [ ("客服响应很快,问题当天就解决了", 1), ("包装破损,里面还有划痕", 0), ("物流慢了点,东西本身不错", 1), ] def to_instruction_rows(pairs): rows = [] for text, label in pairs: rows.append({ "instruction": "判断下面这句话的情感倾向,只回答“正面”或“负面”。", "input": text, "output": "正面" if label == 1 else "负面", }) return rows with open("instruction_data.jsonl", "w", encoding="utf-8") as f: for row in to_instruction_rows(raw_pairs): f.write(json.dumps(row, ensure_ascii=False) + "\n")

这段代码的关键在instruction那一行。模板的设计决定了模型学到的行为:要求“只回答正面或负面”,模型才会学会收敛输出,而不是洋洋洒洒分析一段。如果你的模板写成“请分析这句话的情感”,那模型就会给你写小作文,训练完也别指望它只吐两个词。

同一条数据换个模板就是一条新样本。比如把指令改成“这句话是好评还是差评”,输出改成“好评/差评”。适度地给同一个 input 准备两三种模板,能让模型对指令措辞的轻微变化更鲁棒。但别走极端,一个样本变出二十种说法,意义不大还浪费算力。

这条路的短板也很清楚:受限于你已有的标注数据。数据里只有情感标签,你就造不出摘要任务;类别不够全,模型就学不到没见过的类别。

4.2 路线二:种子指令 + 通用大模型批量生成

手上没有标注数据怎么办?可以反过来:人工写一小批“种子指令”,再用通用大模型服务批量扩写指令、批量生成输出。整个过程分两步,先扩指令,再造答案。

import json, random # 人工写的种子指令,覆盖你想让模型学会的几类任务 seed_instructions = [ "把下面的句子改写成更简洁的表达", "把这段口语化的内容改成书面语", "给这条差评写一句得体的官方回复", ] def expand_instructions(seeds, n_per_seed=5): """让通用大模型基于种子指令改写,产出措辞更多样的指令""" expanded = list(seeds) for seed in seeds: prompt = ( f"请把下面这条任务指令改写成 {n_per_seed} 个意思相同、措辞不同的版本," f"每行一个,不要编号,不要解释。\n原指令:{seed}" ) result = ask_llm(prompt) # ask_llm 是你自己的调用封装 expanded += [line.strip() for line in result.splitlines() if line.strip()] return expanded def build_answer(instruction, input_text): """让通用大模型扮演标注员,产出标准答案""" prompt = f"请严格按照指令作答,只输出答案本身,不要任何解释。\n指令:{instruction}\n输入:{input_text}" return ask_llm(prompt).strip()

ask_llm这里故意留空,因为不同人接入的方式完全不同,你按自己手头能用的服务补上即可。真正需要用心的是那两个 prompt 的措辞:扩写指令时强调“意思相同、措辞不同”,是防止模型给你造出跑偏的新任务;生成答案时强调“只输出答案本身”,是因为模型天然爱解释,不掐住这一点,你的训练数据里会混进大量“好的,以下是……”,微调完模型也会带着这个毛病。

自动生成最大的问题是噪音。模型编出来的答案看着通顺,未必正确。所以一定要有人工抽检环节,哪怕只抽 10%。我一般按任务类型分层抽,每类抽三到五条,看格式、看事实、看有没有答非所问。

4.3 两条路线怎么选:一张表说清楚

对比项模板改写大模型生成
前提条件已有标注数据有可调用的模型服务 + 人工写种子指令
单条成本几乎为零每次生成都有调用开销
数据多样性受限于原数据分布措辞和任务类型都能扩
质量风险模板写错则全错存在编造和格式漂移
适合谁手上有现成标注数据的人从零起步、想快速凑出第一批数据的人

实际操作中,这两条路往往是配合用的:先用模板把已有数据榨一遍,保证基本盘;再用生成的方式补充长尾场景,把覆盖面撑开。入门阶段建议先用模板路线跑通全流程,因为它的结果完全可预期,出了问题容易定位;等整个链路熟了,再引入生成数据。

4.4 五条能立刻用上的数据自查

数据做完不要直接开训,先过一遍下面这几条。

第一,检查三个字段是不是都有。instruction不能为空,output不能为空,input允许为空但要是空字符串而不是 None。第二,检查格式一致性,分隔符、标点、是否带句号,最好统一,别一半带一半不带。第三,抽样看有没有重复样本,同一对指令和输出重复太多次,模型会把它背下来。第四,按任务类型统计条数,别出现某一类占了九成的情况,那样训出来的模型只会干一件事。第五,确认测试用的指令没有混进训练集,串味了你就没法判断效果。

5. 避坑与排查:新手最容易翻车的五个地方

微调这件事,成功的样子都差不多,失败的样子千奇百怪。下面这五个坑是我见过频率最高的,每一个都按“看到什么现象、为什么、怎么办”来说,遇到时可以直接对着排查。

5.1 坑一:损失一路下降,效果反而更差

现象是训练日志里损失很漂亮,从 2 点多掉到 0.3,但你拿新指令去测,模型开始胡言乱语,或者把所有问题都答成同一种格式。

原因基本可以锁定为过拟合。十几条样本训三轮,模型完全可以把这批数据背下来。它学会的不是“照着指令办事”,而是“看到这个问题就吐这个答案”。数据量越小、训练轮数越多,这个现象越明显。

解决办法有三个方向。一是加数据,这是最根本的,几十条样本撑不起一个稳定的行为改变。二是减轮数,把num_train_epochs从 3 降到 1 或 2,边训边测,看哪一轮开始变差就停在哪一轮。三是降容量,把r从 16 降到 8 甚至 4,减小模型“死记硬背”的空间。判断是否过拟合有个笨但有效的办法:留出五条训练集里完全没有的指令,每训完一轮测一次,哪一轮开始答非所问,答案就出来了。

5.2 坑二:显存不够,程序直接崩

现象是刚跑起来就报显存不足,或者训练到一半突然中断,日志里没有任何有效信息。

原因通常不是模型太大,而是几个默认值没调。per_device_train_batch_size默认可能是 8,MAX_LEN设成 2048,再加上没开混合精度,显存瞬间就满了。另外,如果你的基座加载时没指定半精度,光是把权重读进显存就要占掉一倍空间。

解决办法按顺序试:先把per_device_train_batch_size调成 1,再把gradient_accumulation_steps调大来保持等效批量;把MAX_LEN从 2048 降到 512,绝大多数指令样本用不到那么长;确认加载模型时带了半精度参数;还不行就换更小参数量的基座,入门阶段用零点几 B 到一两 B 的模型完全够验证流程。别一上手就挑最大的模型,那是给自己找不痛快。

5.3 坑三:模型学会了复读和套话

现象是微调后模型的回答里频繁出现“好的,以下是……”“希望对你有帮助”这类句子,或者同一个短语反复出现好几遍,停不下来。

原因有两个。一是训练数据本身混进了这些套话,模型照单全收。二是没有正确设置结束符,模型不知道什么时候该停,只能一直续写。第三个可能的原因是推理时没做任何抑制,让模型在低概率区间里打转。

解决办法:先回头清洗数据,把所有“好的”“以下是”“希望对你有帮助”这类模板句删掉,只保留答案本体;确认每条训练样本结尾都加了结束符;推理时打开重复惩罚参数,取值从 1.1 开始试,别调太高,太高会让回答变得僵硬。如果这三步做完还在复读,检查一下推理时的提示拼接和训练时是不是完全一致,拼接方式不同会让模型认不出任务。

5.4 坑四:评测数据串进了训练集

现象是测试结果好得离谱,几乎每条都答得漂亮,但换个真实场景立刻原形毕露,俗称见光死。

原因很简单:你用来测的指令,在训练数据里出现过,哪怕措辞改了两个字,模型也认得出。它不是在答题,是在回忆。

解决办法是划一条硬边界:训练数据准备好之后,先从中切出 10%~20% 单独存成测试文件,之后再也不碰它,所有评测只用这份文件。另外,测试指令的措辞要故意和训练集不一样,训练集里是“改写成正式表达”,测试时就换成“把这句话说得书面一点”。模型如果只能认死一种说法,说明它学得还是太浅。

5.5 坑五:指望微调把知识灌进去

现象是训完之后,模型确实学会了你教的任务格式,但你问它某个领域的具体事实,它照样答错或者编造。

原因是对微调的作用理解偏了。指令微调擅长的是“行为塑造”——让模型知道该用什么格式、什么语气、什么流程来回答。它不擅长往模型里塞新知识,尤其是那种需要精确记忆的细节。想让它记住你们公司产品的具体参数,靠几百条指令样本是记不牢的,还可能被它自信地编出来。

解决办法是分清两件事:要它“会按格式答”,用指令微调;要它“答对具体事实”,应该走检索增强那条路,把资料在推理时喂给它。入门阶段先把行为塑造这条路走通,别把两个目标混在一次训练里,否则两个都做不好。

6. 下一步学什么:一份可以照着走的顺序

流程跑通之后,最容易犯的错是立刻去追最新的论文和最大的模型。我的建议是先把手上的小例子做深一层,再往外扩。下面这个顺序,是我自己踩过一圈之后觉得最省力的走法。

阶段做什么大概花多久判断做完的标准
第一步把样本量从 20 条补到 200 条,覆盖 4~5 类任务两三天每类任务都有几十条,格式统一
第二步固定一份测试集,每轮训练后都跑一次对比半天你能说出哪一轮效果最好
第三步调三个参数:r、learning_rate、轮数两三天知道每个参数往哪调会变好或变差
第四步换一种高效微调思路对比,比如只调偏置项一天能说出两种方式的效果差别
第五步学一点数据质量评估,做分层抽检一周能自己判断一批数据能不能用

第三步里的参数调优,别一次改动三个,那样结果变好变差你都不知道是谁的功劳。一次只动一个,记下来,再动下一个。我习惯在笔记本上写清楚“这次把r从 8 改到 16,损失更低了,但测试集开始出现复读”,这种记录比任何教程都有用。

第四步的意义在于建立参照系。LoRA 属于“加参数”这一类做法,还有“只调偏置项”和“把权重重新参数化”这两类思路,各自的取舍不同。你不必每种都精通,但知道它们存在,以后遇到显存不够或者效果不稳时,就知道还有别的牌可以打。

最后说个习惯。我最开始做微调那阵子,改完参数就直接开跑,跑完只看最后一句输出,觉得还行就收工。后来有一次,同一个配置隔天再跑,结果完全不一样,我花了整整两天才定位到是数据处理里有个字段顺序被改了。从那以后我每次动数据或改配置,都强制走一遍“先存一份原始数据快照、再跑五条固定测试指令、最后对比输出”的流程。多花十分钟,能省掉两天。希望帮到你。

本文还有配套的精品资源,点击获取

返回列表