跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
PythonAI算法

利用大模型构造数据集并微调模型实战

详细介绍如何利用大语言模型自动化构建垂直领域数据集,并结合 PEFT 技术对 Phi-3 等开源模型进行低成本微调。内容涵盖从原始文本到 Alpaca 格式的数据转换流程、LangChain 链式调用实现、训练参数配置及推理部署步骤。文章重点解决了数据集生成中的 Prompt 设计、数据清洗、LoRA 微调参数调优以及推理性能优化等关键问题,旨在帮助开发者在有限算力下快速构建专属大模型应用。

漫步发布于 2025/2/6更新于 2026/8/2164 浏览
利用大模型构造数据集并微调模型实战

一、前言

目前大模型的微调方法有很多,且大多可以在消费级显卡上进行,开发者完全可以在本地环境中微调自己的大模型。然而在实际操作中,我们常面临一个核心问题:数据集的构建。网络上虽然有许多开源数据集,但往往难以直接满足特定业务场景的需求。我们更希望使用某本书、某个作者的作品、内部聊天记录或特定角色的对话来微调模型。

用于微调的高质量数据通常是成千上万的问答对(Instruction-Input-Output)。如果完全依靠人工搜集和标注,将耗费大量时间成本。本文将介绍一种高效的方式:利用大语言模型自动生成高质量数据集,并使用该数据集对大模型进行微调。

二、构造数据集

2.1 目的与格式

微调数据集通常采用问答对形式,例如 Alpaca 数据集的标准结构如下:

{
  "instruction": "保持健康的三个提示。",
  "input": "",
  "output": "以下是保持健康的三个提示:\n\n1. 保持身体活动。每天做适当的身体运动..."
}

但在实际场景中,我们拥有的原始数据往往是一大段非结构化的文本,例如书籍内容或文档片段:

小时候,那时我还只有6岁,看到一本描写原始森林壮观景象的书,名叫真实的故事。书里有一幅很精彩的插画,画的是一条大蟒蛇正在吞食一只动物...

我们的目标是将这种大段文本转换为标准的 Alpaca 格式。过去这只能依赖人工,现在我们可以借助大模型的能力,通过 Prompt 工程让模型根据上下文提取对话和问答内容。

2.2 Prompt 设计

在系统提示词中,我们需要明确指示模型根据上下文提取问答对。示例如下:

QA_PAIRS_SYSTEM_PROMPT = """
<Context></Context> 标记中是一段文本,请学习和分析它,并整理学习成果:
- 提出问题并给出每个问题的答案。
- 答案需详细完整,尽可能保留原文描述。
- 答案可以包含普通文字、链接、代码、表格等 Markdown 元素。
- 最多提出 30 个问题。
"""

为了便于程序解析,我们需要规定严格的输出格式(JSON 数组):

QA_PAIRS_HUMAN_PROMPT = """
请按以下格式整理学习成果:
<Context>
{text}
</Context>
[
  {{"question": "问题 1", "answer": "答案 1"}},
  {{"question": "问题 2", "answer": "答案 2"}}
]
------
我们开始吧!
"""

2.3 处理文档

首先导入必要的模块,包括文件加载、文本分割及 LangChain 组件:

import json
from typing import List
from tqdm import tqdm
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import JsonOutputParser
from langchain_openai import AzureChatOpenAI
from langchain_community.document_loaders import UnstructuredFileLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter

我们需要将长文档切分为适合模型处理的片段:

def split_document(filepath):
    loader = UnstructuredFileLoader(filepath)
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=2048,
        chunk_overlap=128
    )
    documents = loader.load_and_split(text_splitter)
    return documents

2.4 构建 Chain

构建生成数据集的 Chain,包含 Prompt、LLM 和 Output Parser 三部分。

2.4.1 Prompt 整合
prompt = ChatPromptTemplate.from_messages([
    ("system", QA_PAIRS_SYSTEM_PROMPT),
    ("human", QA_PAIRS_HUMAN_PROMPT)
])
2.4.2 LLM 配置

建议选择长上下文能力强于待微调模型的基座。此处以 Azure OpenAI 为例:

llm = AzureChatOpenAI(
    azure_endpoint=endpoint,
    deployment_name=deployment_name,
    openai_api_key=api_key,
    openai_api_version="2024-02-01",
)
2.4.3 结果解析

定义 Pydantic 模型以确保输出符合 JSON Schema:

from langchain_core.pydantic_v1 import BaseModel, Field

class QaPair(BaseModel):
    question: str = Field(description='问题内容')
    answer: str = Field(description='问题的回答')

class QaPairs(BaseModel):
    qas: List[QaPair] = Field(description='问答对列表')

parser = JsonOutputParser(pydantic_object=QaPairs)

连接 Chain 并封装为函数:

def create_chain():
    prompt = ChatPromptTemplate.from_messages([
        ("system", QA_PAIRS_SYSTEM_PROMPT),
        ("human", QA_PAIRS_HUMAN_PROMPT)
    ])
    llm = AzureChatOpenAI(
        azure_endpoint=endpoint,
        deployment_name=deployment_name,
        openai_api_key=api_key,
        openai_api_version="2024-02-01",
    )
    parser = JsonOutputParser(pydantic_object=QaPairs)
    chain = prompt | llm | parser
    return chain

主流程执行逻辑:

def main():
    chain = create_chain()
    documents = split_document('The.Little.Prince.txt')
    datas = []
    bar = tqdm(total=len(documents))
    for idx, doc in enumerate(documents):
        bar.update(1)
        try:
            out = chain.invoke({'text': doc.page_content})
            if isinstance(out, dict) and 'qas' in out:
                datas.extend(out['qas'])
        except Exception as e:
            print(f"Error processing doc {idx}: {e}")
    
    with open('dataset.json', 'w', encoding='utf-8') as f:
        json.dump(datas, f, ensure_ascii=False, indent=2)
    print(f"Total pairs generated: {len(datas)}")

if __name__ == '__main__':
    main()

三、微调模型

准备好数据集后,可以使用 PEFT 库进行高效微调。这里以 Hugging Face Transformers 和 LoRA 技术为例。

3.1 加载模型与配置 LoRA

LoRA(Low-Rank Adaptation)通过在旁支网络注入可训练参数,大幅降低显存需求。

from peft import LoraConfig, TaskType, get_peft_model
from transformers import AutoModelForCausalLM, AutoTokenizer

# 配置 LoRA 参数
peft_config = LoraConfig(
    task_type=TaskType.CAUSAL_LM,
    inference_mode=False,
    r=8,              # 低秩矩阵维度
    lora_alpha=32,    # 缩放系数
    lora_dropout=0.1
)

# 加载基座模型
model = AutoModelForCausalLM.from_pretrained(
    "microsoft/Phi-3-mini-4k-instruct",
    trust_remote_code=True,
    device_map="auto"
)
tokenizer = AutoTokenizer.from_pretrained("microsoft/Phi-3-mini-4k-instruct")

# 应用 LoRA
model = get_peft_model(model, peft_config)
model.print_trainable_parameters()

3.2 数据处理与 Tokenization

需要将自定义数据集转换为模型可接受的输入格式。

from datasets import load_dataset

def tokenize_function(example):
    encoded = tokenizer(
        example['question'],
        truncation=True,
        padding='max_length',
        max_length=512
    )
    # 标签设为答案部分
    labels = tokenizer(
        example["answer"],
        truncation=True,
        padding="max_length",
        max_length=512
    )["input_ids"]
    encoded["labels"] = [-100] * len(encoded["input_ids"])  # 默认忽略
    # 仅将答案部分的 token 设为标签
    input_len = len(encoded["input_ids"])
    label_start = input_len - len(labels)
    encoded["labels"][label_start:] = labels
    return encoded

# 加载本地数据集
dataset = load_dataset('json', data_files={'train': 'dataset.json'})
tokenized_dataset = dataset.map(tokenize_function, batched=True)

3.3 训练配置与执行

from transformers import Trainer, TrainingArguments

training_args = TrainingArguments(
    output_dir="outputs",
    learning_rate=2e-4,
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,
    num_train_epochs=3,
    weight_decay=0.01,
    evaluation_strategy="epoch",
    save_strategy="epoch",
    load_best_model_at_end=True,
    fp16=True,
    logging_steps=10
)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_dataset["train"],
    eval_dataset=tokenized_dataset["validation"],
    tokenizer=tokenizer,
)

trainer.train()
model.save_pretrained("outputs")

四、推理部署

微调完成后,需要加载适配器进行推理。LoRA 允许我们在不修改基座权重的情况下切换不同任务。

from transformers import AutoModelForCausalLM, AutoTokenizer

model = AutoModelForCausalLM.from_pretrained(
    "microsoft/Phi-3-mini-4k-instruct",
    trust_remote_code=True
)
tokenizer = AutoTokenizer.from_pretrained("microsoft/Phi-3-mini-4k-instruct")

model = model.to("cuda")
model.load_adapter('outputs', adapter_name='lora01')
model.set_adapter("lora01")
model.eval()

inputs = tokenizer("作者小时候看了一本关于什么的书?", return_tensors="pt")
outputs = model.generate(
    input_ids=inputs["input_ids"].to("cuda"), 
    max_new_tokens=100,
    temperature=0.7
)
print(tokenizer.batch_decode(outputs.detach().cpu().numpy(), skip_special_tokens=True)[0])

五、常见问题与优化建议

5.1 数据质量控制

在使用大模型生成数据集时,可能会遇到幻觉或格式错误。建议在生成后进行简单的过滤:

  1. 长度过滤:去除过短或过长的问答对。
  2. 重复检测:计算相似度,去除重复样本。
  3. 人工抽检:随机抽取 5%-10% 的数据进行人工审核。

5.2 训练稳定性

  • 学习率调整:若 Loss 震荡剧烈,可降低学习率;若收敛过慢,可适当提高。
  • 早停机制:监控验证集 Loss,当连续 N 个 epoch 未下降时停止训练,防止过拟合。
  • 混合精度训练:开启 fp16 或 bf16 可显著减少显存占用并加速训练。

5.3 推理性能优化

  • 量化:对于资源受限环境,可使用 INT4 或 INT8 量化模型。
  • 批处理:在推理端支持批量请求,提高吞吐量。
  • 缓存 KV:启用 Key-Value Cache 可减少重复计算。

六、总结

本文详细介绍了如何利用大语言模型自动化构建垂直领域数据集,并结合 PEFT 技术对 Phi-3 等开源模型进行低成本微调。通过这一流程,开发者可以快速构建专属知识库,无需依赖昂贵的 API 服务。未来可进一步探索多模态数据融合及分布式训练方案,以适应更大规模的应用场景。

目录

  1. 一、前言
  2. 二、构造数据集
  3. 2.1 目的与格式
  4. 2.2 Prompt 设计
  5. 2.3 处理文档
  6. 2.4 构建 Chain
  7. 2.4.1 Prompt 整合
  8. 2.4.2 LLM 配置
  9. 2.4.3 结果解析
  10. 三、微调模型
  11. 3.1 加载模型与配置 LoRA
  12. 配置 LoRA 参数
  13. 加载基座模型
  14. 应用 LoRA
  15. 3.2 数据处理与 Tokenization
  16. 加载本地数据集
  17. 3.3 训练配置与执行
  18. 四、推理部署
  19. 五、常见问题与优化建议
  20. 5.1 数据质量控制
  21. 5.2 训练稳定性
  22. 5.3 推理性能优化
  23. 六、总结
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • MySQL 数据库常见数据类型详解与选型建议
  • SQLAlchemy 核心用法与实战案例解析
  • Git 本地仓库初始化、提交与分支管理实战
  • 基于 CLIProxyAPI 和 New API 搭建统一 AI 中转站
  • Flutter jwt_io 鸿蒙适配指南:JWT 加解密与身份验证
  • C++ 四十年演进史:从 C with Classes 到现代标准
  • OpenClaw 安装与飞书机器人接入教程
  • Ubuntu 24.04.3 ROS2 一键安装指南
  • HTML input 类型全解析与实战避坑指南
  • 普通程序员学习大模型(LLM)的学习路线与知识体系
  • HarmonyOS6 RcIcon 组件属性系统与样式定制策略
  • SSM 框架文件上传功能实战:从前端到后端完整流程
  • Codex Multi-Agent 与 Claude Agent Teams 技术对比与选型指南
  • Python 学习后如何找工作及就业方向分析
  • OpenClaw 框架 30+ 真实场景实战解析
  • vscode copilot 的配置文件提示警告
  • 2026 年十大 AI 编程工具推荐
  • Git 与 GitHub 入门指南:版本控制与协作实战
  • 前端程序员转行大模型开发指南
  • Go Web 开发必备理论知识

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • curl 转代码

    解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online