审视了合成数据如何辅助大型语言模型预训练 (pre-training)后,我们的重点转向微调 (fine-tuning)。这个重要阶段将通用大型语言模型调整为擅长特定任务、更准确地遵循指令,或采纳特定行为,例如一致的角色或风格。合成数据在此处变得特别有价值,使得创建针对性强、多样化的数据集成为可能,这对于有效的微调非常重要。当特定需求的数据有限、收集成本高昂或根本不存在时,尤其如此。本节介绍合成构建此类多样化数据集的方法,以确保您的微调大型语言模型强大且具备能力。
多样化的微调数据集是指涵盖与目标应用相关的广泛输入、场景和预期输出的数据集。若缺乏这种多样性,您的模型可能在与其有限训练数据相似的示例上表现良好,但无法推广到略有不同但仍然有效的用户请求。手动创建这样一个数据集可能是一项艰巨的任务。幸好,我们可以借助大型语言模型自身来生成这些数据。
自我指令:指导大型语言模型生成自己的训练数据
生成指令微调 (fine-tuning)数据的主要技术之一是自我指令。其主要思想是使用一个强大的教师大型语言模型来生成新的指令及其对应的输入和输出,从而为微调学生大型语言模型(甚至可以是与教师模型相同的基本模型)创建一个合成数据集。
自我指令过程通常包含以下几个步骤:
- 种子指令: 您从一小组人工编写的种子指令开始。这些初始示例为大型语言模型提供了所需指令风格、复杂性和所属方面的一个模板和理解。例如,如果您想微调一个大型语言模型以提供创意写作辅助,您的种子指令可能包括像“写一个关于未来城市侦探的短篇故事开头”或“为经典童话提供三个不同的情节转折点”这样的提示。
- 指令生成: 教师大型语言模型会收到一些种子指令的提示,并被要求生成更多本质相似但新颖的指令。提示可能类似于:“这里有一些指令示例。请生成 10 个新的、多样化的指令,它们遵循相似的模式但涵盖不同的主题或任务。”
- 输入/输出生成: 对于每个新生成的指令,大型语言模型(或可能是另一个专业大型语言模型)负责:
- 判断该指令是“输入优先”还是“输出优先”类型。例如,“总结以下文本:”是输入优先,需要提供文本。“写一首关于大海的诗”是输出优先,直接要求创作作品。
- 如果指令需要输入,则生成一个合适的输入实例。
- 为指令生成高质量的输出或回复。
- 过滤和后处理: 生成的指令-输入-输出三元组随后会经过滤,以去除低质量、语法不佳、琐碎或过于相似的示例。这一步对于保持最终数据集的质量和多样性非常重要。可以使用指令长度、与种子指令的ROUGE分数(以确保新颖性),甚至使用另一个大型语言模型作为判断者等启发式方法。
- 迭代: 新验证的指令可以添加回种子池,并且可以重复该过程以持续扩大数据集。
示意生成微调数据的迭代式自我指令流程图。
自我指令的主要优点是其可扩展性。从少数几个初始示例中,您可以生成数千甚至数万个遵循指令的示例。但是,必须仔细关注种子指令的质量,因为大型语言模型会放大其中存在的任何偏见或局限。定期的人工审查和过滤对成功的自我指令流程非常重要。
演化指令:提升指令的复杂性和多样性
尽管自我指令在生成大量指令方面很有效,但这些指令有时可能缺乏细致性或复杂性上的较大变化。演化指令(进化指令)通过使用大型语言模型将现有指令“演化”得更复杂或更多样化来解决这个问题。这项技术旨在创建推动大型语言模型能力边界的微调 (fine-tuning)数据集。
演化指令过程通常按以下方式进行:
- 初始指令池: 从一组现有指令开始。这些指令可以是人工编写的,从现有数据集中获取的,或通过自我指令生成的。
- 指令演化: 从池中选择一条指令,并对大型语言模型应用“演化提示”。此提示要求大型语言模型以特定方式重写或转换所选指令。常见的演化操作包括:
- 增强细节: 为现有指令添加更复杂的限制、详情或步骤。例如,“将这句话翻译成法语”可能演化为“将这段关于量子物理的技术段落翻译成正式法语,确保所有术语准确无误。”
- 具体化: 使抽象指令更具体或添加上下文 (context)细节。“写一个故事”可以演化为“写一个设定在雷雨中废弃维多利亚时代豪宅的恐怖故事,侧重声音。”
- 扩大范围: 拓宽指令的覆盖范围。“什么是 Python?”可以演化为“比较和对比 Python 与 Java,讨论它们的主要用途、性能特点和生态系统。”
- 推理 (inference)任务增强: 增加所需的推理步骤数量。“如果 X 是 5,Y 是 10,那么 X+Y 是多少?”可以演化为一个多步应用题。
- 添加限制: 引入新的局限或要求。“写一首诗”可以变成“写一首关于秋天的俳句,不使用‘叶子’这个词。”
- 过滤和验证: 演化后的指令随后会进行评估。这可以通过另一个大型语言模型(一个“判断”大型语言模型)或启发式规则来完成。目标是确保演化后的指令仍然连贯、可解决、确实更复杂或更多样,而不是微不足道的修改或格式错误的请求。未能通过此质量检查的指令将被丢弃。
- 回复生成: 对于成功演化的指令,大型语言模型会生成相应的高质量回复。
- 数据集扩充: 新的、演化后的指令-回复配对会添加到微调数据集中。演化后的指令也可能被添加回池中,用于进一步的演化轮次。
演化指令方法的流程,其中指令迭代地变得更复杂或更多样。
演化指令有助于创建一个具有更广泛难度范围和认知要求的数据集,这可以使微调模型更有能力处理复杂提示。主要挑战在于设计有效的演化提示和可靠的过滤机制,以确保演化指令的质量和实用性。
增强数据集多样性的其他策略
其他几种策略也可以帮助构建多样化的微调 (fine-tuning)数据集:
- 转述指令和回复: 使用转述模型或提示大型语言模型以多种方式重述现有指令及其对应的回复。这有助于微调模型泛化到相同基本请求的不同措辞。
- 基于模板的大型语言模型填充槽位生成: 为指令或回复定义结构化模板,其中某些部分是占位符。大型语言模型可以填充这些槽位以产生多样内容,从而实现对多样示例的受控生成。例如,一个指令模板“向 [Z] 的受众解释 [Y] 背景下 [X] 的理念”可以由大型语言模型填充各种 X、Y 和 Z 的术语。
- 指令回译: 如第二章所述,对于通用文本扩充,回译也可应用于指令。将一条指令翻译成另一种语言,然后回译回原文。这通常会产生语义相似但句法不同的指令。
- 结合多种生成源: 不要只依赖单一方法。将通过自我指令、演化指令、人工标注及其他技术生成的数据混合,以创建更丰富、更平衡的数据集。
- 负面示例(需谨慎): 尽管主要焦点是正面示例(正确的指令-回复配对),但在某些特定的微调场景,如安全对齐 (alignment)或减少特定不良行为时,提供少量精心制作的负面示例(例如,一个指令与一个明确“不理想”的回复配对,并如此标记 (token))可能是有益的。这是一种更高级的技术,应谨慎使用。
针对质量和多样性进行整理
无论采用何种生成方法,原始合成数据通常都需要仔细整理。
- 关注主题和技能覆盖: 积极规划您希望模型处理的指令类型。您是目标问答、摘要、创意写作、编码,还是它们的组合?确保您的生成过程,特别是种子数据和演化提示,旨在全面覆盖这些领域。
- 自动化过滤: 实施自动化检查,针对:
- 长度和复杂性: 过滤掉过短/过于简单或过长/过于复杂的指令/回复。
- 重复性: 使用 N-gram 重叠或嵌入 (embedding)相似度(例如,使用句子转换器计算指令嵌入之间的余弦相似度)来检测和移除近似重复的示例。
- 毒性和偏见: 使用内容分类器标记 (token)潜在有害或有偏见的生成文本。
- 指令遵循性: 对于某些任务,您可以使用大型语言模型评估生成的回复是否确实遵循了生成的指令。
- 人工审查: 尽管有自动化,人工审查仍然非常重要,尤其是在构建生成流程的初始阶段或对于特别敏感的任务。审查人员可以发现自动化过滤器遗漏的细节,并提供反馈以改进生成过程本身。
- 迭代优化: 构建多样化、高质量的微调 (fine-tuning)数据集很少是一次性过程。持续评估您的微调模型在使用场景验证集上的表现。识别不足之处,并利用这些见解指导进一步的合成数据生成,针对模型表现不佳的领域。
通过慎重应用自我指令和演化指令等方法,并勤勉整理所得数据,您可以构建强大且多样化的微调数据集。这些数据集在使大型语言模型适应广泛的特定任务和预期行为方面发挥重要作用,使其从通用预训练 (pre-training)转变为专业且高度有能力的工具。