一、指令微调与数据格式
为什么需要指令微调:预训练模型在大规模无监督数据上训练,能生成流畅、上下文相关的文本,但缺乏明确的任务导向,难以直接响应“翻译、分类、摘要”这类具体指令。指令微调通过在预训练模型上进一步微调,用大量带明确任务指令的标注数据,让模型学会“按用户给出的具体指令生成符合预期的输出”,从而显著提高任务适应性与精确度,可统一处理翻译、问答、文本生成等不同类型任务。
数据格式:指令微调数据通常包含两部分(实践中为三字段):
- 任务指令:用户给定的明确任务描述,自然语言表达,告诉模型做什么;
- 输入:模型需要处理的具体数据(可为空);
- 模型输出:模型根据指令与输入应生成的结果。
我们举个例子:
{ "指令": "将以下句子翻译成英文:你好,今天的天气怎么样?", "输入": "", "输出": "Hello, how is the weather today?" }上面这种「指令 / 输入 / 输出」三字段格式即业界常说的 Alpaca 格式,是开源社区最通用的指令微调数据格式之一。工程上通常把成千上万条这样的对象按行存成 train.jsonl(每行一个 JSON),用 HuggingFace datasets 加载:
fromdatasetsimportload_dataset# 每行一个 {"instruction": ..., "input": ..., "output": ...}ds=load_dataset("json",data_files="train.jsonl",split="train")print(ds[0])# 预期输出:{'instruction': '将以下句子翻译成英文:…', 'input': '', 'output': 'Hello, …'}print(len(ds))# 样本条数训练时再把三字段拼成一条完整文本喂给模型,例如"### Instruction:\n{instruction}\n### Input:\n{input}\n### Response:\n{output}",对拼接后的文本计算损失(通常只对 Response 部分计算损失效果更好)。
数据获取的两条路:
- 人工标注:研究者设计具体任务指令,配合正确输出,构成高质量“指令-响应”对;质量高,但成本高、耗时长。
- 自动生成:借助大规模语料库、现有模型或规则自动生成任务指令与响应(从公共数据集、开放领域对话数据中提取,或用模型自动生成指令集)。可大规模扩展,但质量可能不稳定,需进一步筛选优化。# 二、基于大语言模型构建数据
1、用大语言模型自动生成指令微调数据说明
- 提示词驱动:自动化数据生成通常通过设计适当的提示词引导大语言模型生成特定格式的数据。
- 自我迭代提质:如 Self-Instruct 等技术,把模型生成的数据作为新输入再反馈给模型,让模型在自我训练中不断提高生成质量。
- 灵活可调:可针对数据的主题、风格、语气、难度等细致调整,使数据集更多样、更精准。
2、生成流程与方法:Self-Instruct
Self-Instruct 是一种基于大语言模型的自我反馈生成方法,能通过少量初始数据自动生成大量指令和任务数据,并通过自我迭代优化结果。核心流程四步:初始指令生成 → 任务数据生成 → 反馈与优化 → 自我迭代
我们来实践一下,Self-Instruct 式生成的最小可运行骨架(以 OpenAI 兼容接口为例):
fromopenaiimportOpenAIimportjson,re client=OpenAI()# 需先 export OPENAI_API_KEY=sk-...seed=[# 初始指令:人工撰写,对应图4-3 的“初始指令生成”"将以下句子翻译成英文:你好,今天的天气怎么样?","请判断以下评论的情感倾向:这部电影非常好,剧情紧凑。",]defgen_batch(examples,n=8):"""任务数据生成:少样本提示,让模型批量产出新指令。"""prompt="以下是若干任务指令示例:\n"+"\n".join(f"-{e}"foreinexamples)prompt+=f"\n请仿照以上风格,再生成{n}条互不重复、任务类型多样的新指令,每行一条。"resp=client.chat.completions.create(model="gpt-4o-mini",messages=[{"role":"user","content":prompt}],temperature=0.7,# 适当提温增加多样性)lines=[l.strip("- ").strip()forlinresp.choices[0].message.content.splitlines()ifl.strip()]returnlinesdefdedup(instructions):# 反馈与优化:过滤语义重复/过短项seen,out=set(),[]forinsininstructions:key=re.sub(r"\W","",ins.lower())iflen(ins)>10andkeynotinseen:seen.add(key);out.append(ins)returnout pool=list(seed)forround_inrange(3):# 自我迭代:把上轮结果作为下轮示例new=dedup(gen_batch(pool))pool.extend(new)print(f"round{round_}: pool={len(pool)}")# 预期输出:round 0: pool=11 …withopen("self_instruct.jsonl","w",encoding="utf-8")asf:forinsinpool:f.write(json.dumps({"instruction":ins,"input":""},ensure_ascii=False)+"\n")说明:真实 Self-Instruct 还会对生成的指令做“分类(分类 / 生成 / 其他)→ 生成输入输出 → 过滤低质量”等步骤;上例保留了“初始指令 → 批量生成 → 去重 → 迭代”的主干。
3、优势与缺点
优势:
- 规模化能力:短时间内自动生成大量指令、问答对、对话样本与文本摘要,在数据匮乏领域或新兴任务中迅速填补空缺;
- 多样性与灵活性:依据不同输入指令生成丰富多样的输出,覆盖更广任务变体与情境;
- 减少人工干预:大幅降低人工标注比重,节省人力成本。
缺点:
- 质量不稳定:可能出现语法错误、逻辑不清或信息遗漏;高精度、复杂任务难以完全符合需求;
- 继承模型偏差:训练语料来自互联网海量文本,本身可能带偏见或错误,生成时可能被继承,影响公平性与准确性,需细致的数据审查与后期修正;
- 任务适配性存疑:任务复杂度较高时生成数据无法覆盖任务全部需求,高精度任务仍需人工筛选与调整。
三、实践一下:用 HuggingFace Transformers 在中文 RoBERTa 上做法律领域 DAPT
fromdatasetsimportload_datasetfromtransformersimport(AutoTokenizer,AutoModelForMaskedLM,DataCollatorForLanguageModeling,TrainingArguments,Trainer)BASE="hfl/chinese-roberta-wwm-ext"# 步骤1:通用基座tokenizer=AutoTokenizer.from_pretrained(BASE)model=AutoModelForMaskedLM.from_pretrained(BASE)# 步骤2-3:领域语料(法律条文/判例/医学文献),每条记录为一篇纯文本raw=load_dataset("text",data_files={"train":"data/law_corpus.txt"})["train"]tokenized=raw.map(lambdab:tokenizer(b["text"],return_special_tokens_mask=True),batched=True,remove_columns=["text"],)# 步骤4:MLM 自监督继续预训练;用小学习率防止灾难性遗忘collator=DataCollatorForLanguageModeling(tokenizer=tokenizer,mlm=True,mlm_probability=0.15)args=TrainingArguments(output_dir="out/law-roberta-continued",per_device_train_batch_size=16,learning_rate=2e-5,# 远小于从零预训练(约 1e-3 量级)num_train_epochs=3,weight_decay=0.01,logging_steps=100,save_strategy="epoch",)Trainer(model=model,args=args,train_dataset=tokenized,data_collator=collator).train()model.save_pretrained("out/law-roberta-continued")# 步骤5:换 AutoModelForSequenceClassification 等头,在下游任务上监督微调