DLAI-大模型微调笔记-全-

DLAI 大模型微调笔记(全)

001:介绍 🧠

在本节课中,我们将要学习大型语言模型微调的基本概念。我们将了解什么是微调,它为何重要,以及它如何帮助你将通用的大型语言模型应用于你自己的数据和特定任务。


当我和不同的团队交流时,经常听到一个问题:如何让大型语言模型在我们自己的数据或任务上发挥作用?

你可能已经知道如何通过提示来使用大型语言模型。

本课程将讨论另一个至关重要的工具:微调。微调是指获取一个开源的大型语言模型,并在你自己的数据上对其进行进一步的训练。使用提示时,你可以让模型执行诸如提取关键词或进行情感分类等任务。

如果你进行微调,那么你可以让模型更稳定、更一致地执行你期望的操作。我发现,通过微调可以调整模型的语言风格,例如使其回答更乐于助人、更有礼貌,或者更简洁。仅通过提示来实现这一点有时颇具挑战性,而微调被证明是调整模型语气的有效方法。

如今,人们已经见识了ChatGPT等流行大模型在广泛主题上的强大问答能力。然而,许多个人和公司希望拥有能够处理其私有和专有数据的同类界面。

实现这一目标的方法之一就是用你自己的数据来训练一个大模型。当然,从头训练一个基础模型需要海量数据(可能达到数千亿甚至上万亿词)以及巨大的GPU计算资源。

但通过微调,你可以利用一个已经预训练好的模型,并仅基于你自己的数据对其进行进一步训练。

所以,在本课程中,你将学习:

  • 什么是微调。
  • 微调在何时可能对你的应用有帮助。
  • 微调在整个模型训练流程中处于什么位置。
  • 它与提示工程或检索增强生成等技术有何不同,以及这些技术如何与微调结合使用。

你将深入探究一种特定的微调变体——指令微调,它教导一个大模型遵循指令。最后,你将亲身体验微调你自己大模型的完整步骤:准备数据、训练模型,并在代码中进行评估。

本课程专为熟悉Python的学习者设计。要完全理解所有代码,最好具备一些深度学习的基础知识,例如了解训练过程、神经网络的基本概念以及训练集/测试集划分。

我们要感谢Lamini团队和Wei Neena在设计方面所做的卓越工作,以及DeepLearning.AI的Tommy Nelson和Jeff Lord。大约一小时后,通过这个简短的课程,你将能更深入地理解如何通过对现有大模型进行微调,来构建属于你自己的、适配特定数据的语言模型。


本节课总结:我们一起学习了大型语言模型微调的核心价值。我们了解到,微调是一种高效的方法,能够让我们在预训练模型的基础上,利用自有数据对其进行定制化训练,从而使其更稳定地执行特定任务、适应特定风格,并处理私有领域知识。这为将通用大模型转化为专属工具提供了关键路径。

002:为什么要微调? 🤔

在本节课中,我们将要学习大模型微调的核心概念、目的及其与提示工程的区别。我们将通过比喻和实例来理解微调如何将一个通用模型转变为特定领域的专家,并探讨其在实际应用中的优势。

概述

微调是将通用的大型语言模型(如GPT-3)专门化,以适应特定任务(如聊天机器人或代码助手)的过程。本节将解释微调的原理、好处,并将其与更常见的提示工程方法进行比较。

什么是微调? 🎯

上一节我们介绍了课程主题,本节中我们来看看微调的具体定义。

微调是将通用模型(例如GPT-3)专门化到特定应用(如聊天机器人ChatGPT)的过程。或者,将GPT-4变成一个专门的GitHub Copilot代码自动完成工具。

一个恰当的比喻是:通用模型就像你的全科医生(PCP),每年进行一次全面检查。而一个经过微调或专门化的模型,则像心脏病专家或皮肤科医生,拥有特殊专长,可以更深入地治疗特定问题。

那么,微调实际上对模型做了什么?

  • 学习更多数据:它使模型能够处理比提示所能容纳的更多的数据,从而从数据中学习,而不仅仅是接收指令。
  • 实现专业化:通过这个学习过程,模型能够从“全科医生”升级为像“皮肤科医生”一样的专家。

例如,当输入“皮肤刺激、红肿、瘙痒”等症状时:

  • 基础模型(通用的)可能会说:“这可能是痤疮。”
  • 基于皮肤病学数据微调的模型可能会给出更清晰、更具体的诊断。

微调的核心优势 ✨

除了学习新信息,微调还能带来以下关键优势:

以下是微调带来的主要好处:

  1. 引导更一致的输出:微调可以帮助模型获得更一致的行为或输出。

    • 示例:当问基础模型“你的名字是什么?”时,它可能会回答“你姓什么?”,因为它看到了太多不同问题的调查数据,甚至不知道应该回答这个问题。而一个微调的模型会明确回答:“我叫莎伦。”
  2. 减少幻觉:微调可以帮助模型减少“幻觉”,即模型编造事实的问题。

    • 示例:一个未经微调的模型可能会说“我的名字是鲍勃”,而这与训练数据(例如关于“莎伦”的数据)完全不符。

  1. 定制化模型:微调使您能够根据特定的用例定制模型。微调过程与模型早期的训练方法非常相似。

微调 vs. 提示工程 ⚖️

现在,让我们将微调与你可能更熟悉的提示工程进行比较。提示工程是在查询中编辑指令以改变模型输出结果的方法,在过去十年中广泛应用于搜索引擎和大型语言模型。

以下是提示工程的主要特点:

  • 优点
    • 无需数据即可开始与模型交互。
    • 前期成本较低,每次调用模型的费用不高。
    • 无需太多技术知识,只需知道如何组织文本指令。
    • 现在可以通过检索增强生成(RAG)等技术有选择地将更多数据连接到提示中。
  • 缺点
    • 如果数据量很大,可能无法全部放入提示中。
    • 模型容易忘记长上下文中的信息。
    • 存在幻觉问题,难以纠正模型已学到的不正确信息。
    • 使用RAG时,可能错过正确数据或引入错误数据,导致错误输出。

相比之下,微调提供了不同的价值主张:

  • 优点
    • 可以容纳几乎无限量的数据。
    • 模型可以从数据中学习新信息。
    • 可以纠正模型先前学到的不正确信息,或加入其未了解的最新信息。
    • 事后(推理阶段)成本较低,尤其在使用较小的微调模型处理高吞吐量或大负载时非常重要。
    • 同样可以与检索增强生成(RAG)结合使用,连接更多数据。
  • 缺点
    • 需要更多、更高质量的数据才能开始。
    • 存在前期计算成本,并非免费。
    • 通常需要一些技术知识来处理和准备数据。
    • 用户不能仅仅是一个“会发短信的人”。

总结对比

  • 提示工程非常适合通用用例、不同的副项目和快速原型设计。
  • 微调则更适合企业或特定领域用例,并用于生产环境。

微调自有大模型的好处 🏆

在下一节中,我们将讨论微调对隐私的用处。微调自己的大模型能带来以下好处:

以下是微调自有模型的核心优势:

  1. 性能提升
    • 减少幻觉:可以阻止模型在你的专业领域内编造信息。
    • 增强专业性:在特定领域拥有更多专业知识。
    • 提高一致性:使模型输出更加一致可靠,避免输出结果随时间大幅波动。

  1. 改进的调控能力:你可以引导模型以符合公司政策或用例的方式回应。例如,定制模型在无法回答时的回应方式,帮助与它聊天的人保持正轨。

  1. 隐私保护:微调可以在您的虚拟私有云(VPC)或本地进行,这能防止数据泄露到第三方解决方案,是保护敏感数据安全的一种方法。

  1. 成本与控制
    • 成本透明度与降低:如果有很多用户,微调一个较小的模型可以帮助降低每个请求的成本。
    • 更大控制权:您对成本、正常运行时间和延迟等因素有更大的控制权。例如,可以大大减少自动完成等应用的延迟(目标可能低于200毫秒)。
    • 定制化调控:这是一种为模型提供“护栏”的方法,使其能按需拒绝回答或给出定制响应。

实践:观察微调模型的实际效果 💻

最酷的是,你可以在笔记本上亲眼看到一个例子。在课程的不同实验中,你将使用多种技术进行微调。

以下是三个常用的Python库:

  1. PyTorch:由Meta开发,这是你将看到的最低层级的接口。
  2. Hugging Face Transformers:构建在PyTorch之上的优秀高级库,可以非常容易地导入数据集和训练模型。
  3. Llama Library:由课程团队开发的更高级接口,可以用几行代码训练模型。

现在,让我们跳到笔记本中,看看微调模型的实际表现。

我们将比较一个微调模型和一个非微调模型。

首先,我们从Llama库导入BasicModelRunner,它帮助我们运行托管在GPU上的开源模型。

1. 测试非微调模型(Llama 2)

# 实例化非微调模型
non_finetuned = BasicModelRunner("meta-llama/Llama-2-7b-hf")
# 提出问题
prompt = "告诉我如何训练我的狗坐下"
output = non_finetuned(prompt)
print(output)

输出可能类似:“告诉我如何训练我的狗坐下。告诉我如何训练我的狗说话。告诉我如何教我的狗过来...”

这个模型没有被告知或训练来响应指令,它只是在尝试自动完成句子,就像之前“你的名字是什么?”的例子一样。

2. 测试微调模型(Llama 2 Chat)

# 实例化微调模型
finetuned_model = BasicModelRunner("meta-llama/Llama-2-7b-chat-hf")
# 使用指令标签明确告知模型边界
prompt = """[INST] <<SYS>>
你是一个有帮助的助手。
<</SYS>>
告诉我如何训练我的狗坐下。 [/INST]
"""
output = finetuned_model(prompt)
print(output)

输出可能类似:“训练狗狗坐下可以遵循以下步骤:1. 准备零食... 2. 发出‘坐下’的口令... 3. 当它坐下时立即奖励... 4. 重复练习...”

微调后的模型给出了一个分步指南,响应质量显著提高。使用[INST][/INST]等指令标签有助于告诉模型指令的边界,防止其进行无意义的自动完成。

通过对比其他问题(如“你觉得火星怎么样?”、“泰勒·斯威夫特最好的朋友”、“模拟亚马逊送货客服对话”),可以明显看出,经过微调的模型(包括ChatGPT和这个Llama聊天模型)在遵循指令、提供相关信息和进行连贯对话方面,远优于未微调的模型。

总结

本节课中,我们一起学习了:

  • 微调的定义:将通用大模型专门化以适应特定任务的过程。
  • 微调的优势:包括学习更多数据、获得更一致的输出、减少幻觉以及深度定制模型。
  • 微调与提示工程的对比:两者各有适用场景,提示工程适合快速原型和通用任务,而微调更适合需要高性能、一致性和领域专业性的生产级应用。
  • 微调自有模型的好处:涵盖性能提升、隐私保护、成本控制和对模型行为的更好调控。
  • 实践观察:通过代码示例直观对比了微调与非微调模型在响应质量上的巨大差异。

在下一节课中,我们将探讨微调在整个大模型训练流程中所处的位置,了解如何迈出微调的第一步。

003:微调在训练过程中的位置 📍

在本节课中,我们将学习大语言模型(LLM)训练流程中的关键步骤——微调。我们将了解微调在整个流程中的位置,它与预训练的区别,以及微调能完成哪些具体任务。课程最后,我们将通过一个简单的代码示例,直观地对比预训练数据和微调数据的不同。

概述:训练流程全景图

上一节我们介绍了微调的基本概念,本节中我们来看看微调在整个模型训练流程中处于什么位置。

大语言模型的训练通常分为两个主要阶段:预训练微调。微调是在预训练之后进行的步骤。

预训练:构建基础语言能力 🧱

首先,让我们了解微调发生之前的预训练步骤。预训练是模型学习的起点。

预训练开始时,模型是完全随机的。它对世界一无所知,所有的权重都是随机初始化的。此时模型不具备任何语言技能,甚至无法构成有意义的英语单词。

预训练的核心学习目标是 下一个令牌预测。在简化的意义上,可以理解为“下一个词预测”。模型接收一个词(或令牌),其任务是预测序列中的下一个词是什么。

例如,给定输入 “The”,模型需要预测下一个词可能是 “cat”。在训练初期,模型的预测(如 “SD!”)可能与正确目标相去甚远。

模型通过阅读海量的数据语料库来学习,这些数据通常是从整个互联网上抓取的。我们称这些数据为 无标签数据,因为它们并非人工专门为训练任务构建的。

虽然数据是“抓取”的,但通常会经过大量的清洗和处理工作,以确保数据质量对模型预训练有效。模型通过“下一个令牌预测”任务进行自我监督学习,其目标就是根据上文预测下一个词,而不需要人工提供的“标签”。

经过预训练后,模型能够学会预测像 “on” 或 “in” 这样的常见词汇。它从互联网数据中习得了基础的语言知识和模式。这个过程之所以有效且神奇,是因为模型仅仅通过尝试预测下一个词,就消化了整个互联网规模的数据,从而获得了广泛的知识。

预训练数据示例

预训练所使用的数据通常不公开其具体构成,尤其对于许多大公司的闭源模型。但开源社区有出色的努力,例如 Eleuther AI 创建的 Pile 数据集。这个数据集整合了从互联网抓取的多种类型数据。

以下是Pile数据集可能包含的内容示例:

  • 林肯的葛底斯堡演说
  • 胡萝卜蛋糕食谱
  • 从PubMed抓取的医学文本
  • 来自GitHub的代码

这是一组经过精心策划的数据集,旨在为模型注入多样化的知识。

预训练步骤的计算成本非常高,耗时且昂贵。因为模型需要处理海量数据,从完全随机状态进化到理解文本、食谱甚至编写代码。

微调:从通用模型到专用工具 🔧

上一节我们介绍了预训练如何得到一个基础模型,本节中我们来看看如何通过微调让它变得更有用。

预训练得到的基础模型虽然知识丰富,但可能无法直接满足特定需求。例如,当被问及“印度的首都是什么?”时,模型可能知道答案。但如果以聊天机器人的方式交互,直接问“墨西哥的首都是什么?”,基础模型可能无法给出连贯、有用的回复。

微调 正是将通用基础模型转化为专用工具的关键步骤之一。它是在预训练之后进行的一个步骤。

微调与预训练的核心区别在于 数据数据量

  • 数据性质:预训练使用海量、无结构的原始数据。微调则使用更少、但更有组织、更结构化的数据。这些数据可以是从特定来源抓取并整理的,也可以是完全由人工构建的。
  • 数据量:微调所需的数据量远少于预训练。因为它是建立在已经具备丰富知识和基础语言技能的基础模型之上,只是将其能力“提升到一个新的水平”。

微调的训练目标与预训练相同,仍然是 下一个令牌预测。我们所做的改变是数据本身,使其更具条理性,从而让模型在输出时能更一致地模仿这种结构。

微调能做什么? 🎯

那么,微调具体能实现哪些目标呢?我们可以将其主要分为两大类:

1. 行为改变
改变模型的交互或响应方式。例如,让模型更好地适应聊天对话界面,而不是以调查问卷的形式回应。这能使模型反应更一致、更聚焦,也可能在内容审核等方面表现更好。本质上,这是在梳理和强化模型的特定能力。

2. 知识注入
为模型注入新的、基础预训练模型中没有的特定领域知识。这可能意味着:

  • 学习特定主题的深入知识。
  • 纠正模型中已有的、过时或不正确的信息。
  • 注入最新的信息。

在实际应用中,通常会同时进行行为改变和知识注入。

微调的任务类型 📝

微调的任务主要围绕处理文本展开。我喜欢将其分为两个对比鲜明的类别:

1. 文本提取(阅读类任务)
输入文本,得到更少、更精炼的文本输出。

  • 示例:提取关键词、根据内容将对话路由到不同的处理模块(如不同的API或智能体)。

2. 文本生成(写作类任务)
输入文本,得到更多、更丰富的文本输出。

  • 示例:聊天对话、撰写邮件、编写代码。

理解你的任务属于哪种类型,是微调成功的一个明显标志。清晰的任务定义意味着你知道什么是“好的输出”。当你明确知道模型在编写代码或路由对话方面如何能做得更好时,你就能更有效地微调模型来优化这项任务。

给初学者的微调步骤建议 🚀

如果你是第一次尝试微调,我推荐遵循以下步骤:

以下是开始微调的推荐步骤:

  1. 通过提示工程确定任务:使用像 ChatGPT 这样的大型语言模型,通过设计提示词来探索并确定一个你想让模型做得更好的具体任务。
  2. 收集输入-输出数据对:为选定的任务,收集一些“输入文本”和对应的“输出文本”示例。一个很好的起点是收集大约 1000 对这样的数据。
  3. 确保数据质量:这些输入-输出对应比基础模型直接生成的“还可以”的结果要更好。在你能持续产生高质量数据对之前,确保你已经拥有了这些数据。
  4. 在小模型上尝试微调:使用你收集的数据,在一个相对较小的语言模型上进行微调。这可以帮助你感受性能的提升,是初次尝试的理想选择。

代码实践:对比预训练与微调数据 💻

现在,让我们通过代码来探索用于预训练和微调的数据集有何不同。我们将使用 Hugging Face 的 datasets 库。

首先,我们导入必要的库并加载一个预训练数据集(以 Pile 数据集为例)。由于数据集很大,我们使用流式加载。

from datasets import load_dataset

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-llm-ft/img/b46c7ab563229c69723d79f17ee24102_35.png)

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-llm-ft/img/b46c7ab563229c69723d79f17ee24102_37.png)

# 加载预训练数据集 Pile,使用流式模式
pretrain_dataset = load_dataset("monology/pile-uncopyrighted", split="train", streaming=True)

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-llm-ft/img/b46c7ab563229c69723d79f17ee24102_39.png)

# 查看前几个数据样本
for i, example in enumerate(pretrain_dataset):
    if i < 5:
        print(example["text"][:200])  # 打印前200个字符
        print("---")
    else:
        break

输出内容可能看起来像是从网页或代码库中直接抓取的原始文本,结构松散,内容多样。

接下来,我们查看一个用于微调的数据集。这里我们使用一个假设的、结构化的公司问答对数据集(例如 lamini_docs.json)。

import json

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-llm-ft/img/b46c7ab563229c69723d79f17ee24102_45.png)

# 加载微调数据集
with open("lamini_docs.json", "r") as f:
    finetune_data = json.load(f)

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-llm-ft/img/b46c7ab563229c69723d79f17ee24102_47.png)

# 查看数据结构
print("示例问答对:")
print(f"问题:{finetune_data[0]['question']}")
print(f"答案:{finetune_data[0]['answer']}")
print("---")

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-llm-ft/img/b46c7ab563229c69723d79f17ee24102_49.png)

# 一种简单的数据准备方法:将问题和答案连接起来
simple_prompt = f"{finetune_data[0]['question']} {finetune_data[0]['answer']}"
print("串联后的文本:")
print(simple_prompt)

微调数据通常是结构化的,例如清晰的问答对,围绕特定主题(如某公司的产品文档)。

为了帮助模型更好地理解任务,我们通常使用提示模板来格式化数据,这类似于高级的提示工程。

# 使用提示模板格式化数据
prompt_template = """### 问题:
{question}

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-llm-ft/img/b46c7ab563229c69723d79f17ee24102_57.png)

### 答案:
{answer}
"""

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-llm-ft/img/b46c7ab563229c69723d79f17ee24102_59.png)

formatted_prompt = prompt_template.format(question=finetune_data[0]['question'], answer=finetune_data[0]['answer'])
print("使用模板格式化后的文本:")
print(formatted_prompt)

使用模板可以更清晰地将输入(问题)和输出(答案)分开,这不仅有助于模型学习,也便于后续的评估。

存储这些微调数据的常见格式是 JSON Lines(.jsonl) 文件,即每行都是一个独立的 JSON 对象。

# 将格式化后的数据写入 JSON Lines 文件
formatted_data = []
for item in finetune_data:
    formatted_item = {
        "text": prompt_template.format(question=item['question'], answer=item['answer'])
    }
    formatted_data.append(formatted_item)

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-llm-ft/img/b46c7ab563229c69723d79f17ee24102_67.png)

with open("formatted_finetune_data.jsonl", "w") as f:
    for item in formatted_data:
        f.write(json.dumps(item) + "\n")
print("数据已写入 formatted_finetune_data.jsonl")

这样,你就可以轻松地将数据集上传到云端(如 Hugging Face Hub),并在后续训练中直接调用。

总结 📚

本节课中,我们一起学习了微调在大语言模型训练流程中的关键位置。

我们首先回顾了 预训练 阶段,模型通过海量无标签数据学习基础语言能力。接着,我们深入探讨了 微调 阶段,它利用更少但更结构化的数据,在预训练模型的基础上改变其行为或注入新知识。我们分析了微调的两大目标(行为改变与知识注入)和两种主要任务类型(文本提取与文本生成)。最后,通过代码实践,我们直观对比了非结构化的预训练数据与结构化的微调数据,并学习了如何使用提示模板来准备微调数据。

理解微调在整个流程中的位置及其作用,是有效利用和定制大语言模型的重要基础。

004:指令微调 🧠

在本节课中,我们将学习指令微调。这是一种将基础大语言模型(如 GPT-3)转变为具备聊天或遵循指令能力的模型(如 ChatGPT)的关键技术。我们将了解其概念、数据准备方法,并通过实例对比微调前后的模型表现差异。

什么是指令微调?

上一节我们介绍了微调的基本概念,本节中我们来看看指令微调的具体含义。

指令微调是微调的一种特定类型。其核心目标是教会模型遵循指令,使其行为更像一个聊天机器人。这为用户与模型交互提供了一个更好的界面,正如我们在 ChatGPT 中所见。将 GPT-3 转变为 ChatGPT 正是采用了这种方法,这极大地促进了人工智能在广大人群中的普及和应用。

指令微调的数据集

理解了指令微调的目标后,接下来我们看看如何准备相应的数据。

对于指令微调,您可以使用多种现成的数据集,这些数据集可能来自公开资源或您公司的特定资料。常见的数据来源包括:

  • 常见问题解答
  • 客户支持对话记录
  • 即时通讯消息

本质上,这是一个对话数据集指令-响应数据集。如果您没有现成的数据,也无需担心。您可以通过使用提示模板,将现有数据转换为问答格式或指令遵循格式。

例如,一段“Readme”文档可以被转换为一组问答对。您甚至可以借助另一个大语言模型(如 ChatGPT)来自动完成这种转换。斯坦福大学提出的 Alpaca 技术就采用了这种方法。当然,您也可以使用不同的开源模型管道来实现。

指令微调的优势

数据准备是基础,而指令微调带来的能力提升才是关键。

指令微调最显著的优势之一是它能教会模型新的行为模式。虽然您的微调数据中可能只包含类似“法国的首都是什么?”这样的简单问答对,但模型能够推广这种问答模式。

模型可能没有在微调数据集中见过某些特定问题,但它可以利用在预训练阶段学到的知识来回答。例如,关于代码的问题。这正是 ChatGPT 论文中的发现:经过指令微调的模型可以回答关于代码的问题,尽管其指令微调数据集中并没有专门的代码问答对。这是因为创建高质量的、带标注的代码问答数据集成本很高。

指令微调步骤概述

了解了优势,我们来系统性地看一下指令微调的全过程。

指令微调(以及其他类型的微调)是一个高度迭代的过程,主要包含以下步骤:

  1. 数据准备
  2. 模型训练
  3. 效果评估

评估模型后,通常需要返回数据准备阶段进行改进,然后再次训练和评估,如此循环以提升模型性能。其中,数据准备环节因任务而异,您需要根据具体的微调目标(如指令遵循、聊天等)来调整和构建数据。而训练评估的流程则相对通用。

实战:观察指令微调数据集

理论需要实践验证,现在让我们深入实验室,观察一个实际的指令微调数据集。

您将看到用于指令微调的 Alpaca 数据集,并比较经过指令微调与未经过指令微调的模型表现。

首先导入必要的库,其中关键的是从 datasets 库加载数据集的函数。

from datasets import load_dataset

让我们加载这个指令微调数据集,即指定的 Alpaca 数据集。我们使用流式加载,因为它是一个较大的数据集。

dataset = load_dataset("tatsu-lab/alpaca", split="train", streaming=True)

与海量的预训练语料不同,这个数据集更有条理。它并非纯文本,而更像是问答对。Alpaca 论文的作者设计了两类提示模板,以使模型能处理两种任务:

  • 含输入的指令:例如,指令是“将两个数字相加”,输入是“第一个数字是3,第二个数字是4”。
  • 不含输入的指令:例如,指令是“告诉我一个笑话”。

在数据集中,有些样本的“输入”字段是空或不相关的。这些提示模板会被填充,并在整个数据集中应用。打印一个样本可以看到,它最终被构造成“指令 + 输入 -> 输出”的形式,并以“Response:”开头引导模型的回答。

实战:对比微调前后的模型

看过数据后,我们来直观感受一下指令微调带来的变化。

我们将比较两个模型对同一指令的响应。首先是一个未经指令微调的 LLaMA 2 模型。

指令:告诉我如何训练我的狗坐下。
未经微调模型的输出:模型可能输出无关的文本或无法遵循指令,例如重复指令或开始随机生成。

现在,我们比较经过指令微调的模型对同一指令的响应。
经过微调模型的输出:模型会生成一系列合理的训练步骤,例如:“1. 准备一些狗粮作为奖励。2. 让狗保持站立姿势。3. 清晰地说出‘坐下’口令,同时用手轻轻按压它的臀部…”。

作为参考,ChatGPT 对此指令也会产生一套详细、步骤清晰的回答。需要注意的是,ChatGPT 的参数量(据传约700亿)远大于我们示例中使用的 LLaMA 2 模型(70亿参数)。

实战:在特定领域数据上的测试

通用指令的对比很直观,现在我们测试模型在特定领域知识上的表现。

我们将加载一个较小的、拥有7000万参数且未经指令微调的模型。然后,从一个关于“Lamini”公司的特定数据集中抽取一个问题来测试它。

# 示例问题
question = "Lamini 能否为软件项目生成技术文档或用户手册?"
# 期望答案
expected_answer = "是的,Lamini 可以为软件项目生成技术文档和用户手册。"

未经微调模型的回答:模型可能给出不相关或错误的回答,例如:“我有一个关于以下内容的问题:如何获得正确的文档来工作?我认为您需要使用以下代码…”。这表明模型既不理解该领域知识,也不明白它应该以直接回答问题作为期望行为。

现在,将其与我们已为您微调好的模型(或您将在后续课程中自己微调的模型)进行比较。
经过指令微调模型的回答:模型回答:“是的,Lamini 可以为软件项目生成技术文档和用户手册,它能够…” 这个回答准确得多,遵循了我们所期望的正确行为模式。

总结

本节课中,我们一起学习了指令微调的核心内容。

我们明确了指令微调是一种赋予基础大模型聊天和遵循指令能力的关键微调方法。我们探讨了其数据集的来源与构建方式,包括使用现成对话数据和通过模板进行转换。通过实战对比,我们清晰地观察到指令微调如何显著提升模型在遵循指令和领域知识问答上的表现。最后,我们了解到指令微调是一个包含数据准备、训练和评估的迭代过程。下一步,我们将深入探讨如何为模型训练准备数据,包括分词器的使用。

005:准备数据 📊

在本节课中,我们将学习如何为大型语言模型的微调准备数据。我们将探讨数据准备的最佳实践、具体步骤,并通过代码示例展示如何对文本进行标记化、填充和截断处理。


概述

数据准备是微调过程中的关键步骤。高质量、多样化的数据能帮助模型更好地学习特定任务。本节将介绍数据准备的核心原则和具体操作流程。


数据准备的最佳实践

上一节我们介绍了微调的基本概念,本节中我们来看看准备数据时应遵循哪些最佳实践。

以下是数据准备的四个关键原则:

  1. 高质量数据:提供高质量的数据是微调的首要任务。低质量的输入会导致模型产生低质量的输出。
  2. 数据多样性:数据应涵盖用例的多个方面。如果所有输入和输出都相同,模型可能会开始记忆数据,而非学习泛化模式。
  3. 真实数据优先:虽然可以生成数据,但使用真实数据通常更有效。生成的数据可能包含固定模式,用其训练可能无法让模型学习新的表达方式。
  4. 数据量:在大多数机器学习应用中,更多数据通常更好。但由于大模型已经过预训练,拥有海量基础知识,因此对于微调而言,数据质量、多样性和真实性比单纯的数据量更重要。


数据准备的步骤

了解了核心原则后,我们来看看将原始数据转化为模型可接受格式的具体步骤。

以下是数据准备的四个标准步骤:

  1. 收集指令-响应对:首先收集任务相关的问答对或指令-响应对。
  2. 构建提示:将这些对连接起来,或添加统一的提示模板。
  3. 标记化:使用标记器将文本数据转换为数字序列。
  4. 数据集划分:将处理好的数据划分为训练集和测试集。


理解标记化

标记化是准备数据的关键环节。它指的是将文本转换成模型能够理解的数字序列的过程。

标记器基于字符或子词的常见出现频率进行转换。例如,单词“fine-tuning”可能被拆分为多个标记,如 ['fine', '-', 'tuning'],每个标记对应一个唯一的数字ID。

核心概念:每个模型都有其专用的标记器。使用错误的标记器会导致模型混淆,因为相同的数字可能代表不同的文本含义。标记化过程可以表示为以下伪代码:

# 伪代码:标记化过程
token_ids = tokenizer.encode(text="你的文本")
decoded_text = tokenizer.decode(token_ids=token_ids)

动手实践:使用标记器

现在,让我们通过代码来具体看看如何使用标记器。我们将使用Hugging Face库提供的AutoTokenizer类。

首先导入必要的库并加载标记器。AutoTokenizer能根据模型名称自动选择正确的标记器。

from transformers import AutoTokenizer

# 指定模型名称,加载对应的标记器
model_name = "your_model_name_here"
tokenizer = AutoTokenizer.from_pretrained(model_name)

接下来,我们对一段文本进行编码和解码,以验证标记化过程。

# 对单条文本进行标记化
text = "Hi, how are you?"
encoded_text = tokenizer(text)
print("编码后的ID:", encoded_text['input_ids'])

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-llm-ft/img/f3f068b1d071ba200429dfe4484c2710_26.png)

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-llm-ft/img/f3f068b1d071ba200429dfe4484c2710_28.png)

# 将标记ID解码回文本
decoded_text = tokenizer.decode(encoded_text['input_ids'])
print("解码后的文本:", decoded_text)

处理批量文本时,我们需要确保每个序列的长度一致,以便模型处理。

# 对批量文本进行标记化
text_list = ["Hi, how are you?", "I'm fine.", "Yes"]
batch_encoded = tokenizer(text_list)
print("批量编码结果:", batch_encoded)

由于批量中文本长度可能不同,我们需要进行填充截断

# 应用填充和截断
processed_batch = tokenizer(
    text_list,
    padding=True,        # 启用填充
    truncation=True,     # 启用截断
    max_length=10,       # 设置最大长度
    return_tensors="pt"  # 返回PyTorch张量
)
print("处理后的批量数据:", processed_batch)

填充通过在序列末尾添加特定的“填充标记”(如0)使所有序列达到相同长度。截断则通过裁剪序列使其不超过最大长度。可以指定从左侧或右侧截断,这取决于任务需求。


准备完整的数据集

我们将上述步骤整合,创建一个函数来处理整个数据集。

首先,加载包含问答对的数据集,并构建提示。

def prepare_prompt(example):
    """将问答对组合成提示格式。"""
    prompt = f"### Question: {example['question']}\n ### Answer: {example['answer']}"
    return {"prompt": prompt}

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-llm-ft/img/f3f068b1d071ba200429dfe4484c2710_51.png)

# 假设 `dataset` 是加载好的数据集
dataset = dataset.map(prepare_prompt)

然后,定义标记化函数并应用于数据集。

def tokenize_function(examples):
    """对数据集进行标记化。"""
    # 设置最大长度,并进行填充与截断
    tokenized_inputs = tokenizer(
        examples["prompt"],
        truncation=True,
        padding="max_length",
        max_length=512
    )
    return tokenized_inputs

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-llm-ft/img/f3f068b1d071ba200429dfe4484c2710_57.png)

# 应用标记化函数
tokenized_dataset = dataset.map(tokenize_function, batched=True)

最后,将数据集划分为训练集和测试集。

# 划分数据集
split_dataset = tokenized_dataset.train_test_split(test_size=0.1, shuffle=True)
train_dataset = split_dataset["train"]
test_dataset = split_dataset["test"]

![](https://github.com/OpenDocCN/dsai-notes-pt1-zh/raw/master/docs/dlai-llm-ft/img/f3f068b1d071ba200429dfe4484c2710_61.png)

print(f"训练集大小: {len(train_dataset)}")
print(f"测试集大小: {len(test_dataset)}")

Hugging Face提供了许多有趣的数据集可供练习,例如关于泰勒·斯威夫特或开源大模型的数据集,你可以下载并尝试用自己的数据微调模型。


总结

本节课中我们一起学习了为大型语言模型微调准备数据的全过程。我们首先明确了高质量、多样化、真实数据优先的原则,然后逐步演练了从收集数据、构建提示、进行标记化(包括填充与截断)到最终划分数据集的完整流程。正确的数据准备是模型能否成功学习特定任务的基础。在接下来的实践中,你将应用这些知识来准备自己的微调数据。

006:训练过程 🚀

在本节课中,我们将逐步完成大语言模型的整个训练过程。你将看到模型如何通过训练,在特定任务上得到改进,最终学会与你进行聊天。我们将从训练的基本原理开始,逐步深入到代码实现,并使用高级库简化流程。

概述

大语言模型的训练过程与其他神经网络训练非常相似。核心步骤包括:输入训练数据、计算预测损失、根据损失更新模型权重,最终使模型学会生成期望的输出。

训练过程原理

上一节我们概述了训练的目标,本节中我们来看看训练过程的具体步骤。

训练过程遵循一个标准循环:

  1. 将训练数据输入模型。
  2. 模型进行预测。
  3. 计算预测结果与标准答案之间的损失
  4. 根据损失反向传播,更新模型权重以减小损失。
  5. 重复此过程,直到模型性能达到要求。

训练过程中涉及许多超参数,以下是几个关键的超参数:

  • 学习率:控制每次权重更新的步长。
  • 学习率调度器:在训练过程中动态调整学习率。
  • 优化器超参数:例如动量、权重衰减等,用于控制优化过程。

代码实现:PyTorch 基础训练循环

理解了原理后,我们来看看如何在代码中实现它。以下是 PyTorch 中一个基础训练循环的代码块。

for epoch in range(num_epochs): # 遍历整个数据集的次数
    for batch in dataloader: # 遍历数据批次
        outputs = model(batch) # 前向传播,获取模型输出
        loss = loss_function(outputs, labels) # 计算损失
        loss.backward() # 反向传播,计算梯度
        optimizer.step() # 更新模型权重
        optimizer.zero_grad() # 清空梯度,为下一批次准备

代码解释:

  • epoch:对整个训练数据集的一次完整遍历。
  • batch:将大量数据分成的小块,分批进行训练以提高效率。
  • 循环内的步骤依次是:前向传播、计算损失、反向传播、优化器更新权重。

使用高级库简化训练

手动编写底层训练循环虽然有助于理解,但在实际项目中,我们常使用高级库来简化流程。接下来,我们将介绍如何使用 Lamini 这样的库,用极少的代码完成模型训练。

Lamini 库提供了一个高级接口,可以仅用几行代码在托管 GPU 上训练模型。

from lamini import Lamini

# 初始化Lamini
llm = Lamini(model_name="pythia-70m")
# 加载数据
llm.load_data_from_jsonlines("data.jsonl")
# 开始训练
llm.train()

通过调用 train() 方法,你将获得一个模型 ID 和一个交互界面,可用于后续的继续训练或推理任务。

实战演练:微调 Pythia-70M 模型

为了让大家能在个人电脑上体验整个过程,本实验将使用参数量较小的 Pythia-70M 模型进行微调。在实际应用中,建议根据任务复杂度选择更大参数的模型。

1. 环境配置与数据准备

首先,我们需要导入必要的库并设置训练配置参数。

import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
from datasets import load_dataset

# 训练配置
config = {
    "model_name": "EleutherAI/pythia-70m",
    "dataset_path": "./lamini_docs.jsonl",
    "use_huggingface_dataset": False,
    "max_steps": 3 # 仅训练3步用于演示
}

数据加载有两种常见方式,以下是具体说明:

  • 从本地 JSON Lines 文件加载。
  • 从 Hugging Face 数据集库加载。

2. 加载模型与分词器

接下来,我们加载预训练模型和对应的分词器,并将模型移动到合适的设备上。

# 加载分词器
tokenizer = AutoTokenizer.from_pretrained(config["model_name"])
# 加载预训练模型
base_model = AutoModelForCausalLM.from_pretrained(config["model_name"])

# 检测并设置设备(GPU/CPU)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
base_model.to(device)

3. 推理函数

在训练前,我们先定义一个推理函数,用于观察模型在微调前后的表现变化。

def generate_text(model, tokenizer, prompt, max_input_tokens=100, max_output_tokens=100):
    # 将输入文本转换为令牌(tokens)
    input_ids = tokenizer.encode(prompt, return_tensors="pt").to(device)
    # 模型生成
    output_ids = model.generate(input_ids, max_length=max_input_tokens+max_output_tokens)
    # 将生成的令牌解码回文本
    generated_text = tokenizer.decode(output_ids[0], skip_special_tokens=True)
    # 去掉输入提示部分,只返回新生成的答案
    answer = generated_text[len(prompt):]
    return answer

让我们用测试问题看看基础模型的表现:

提示:“Lamini 能生成技术文档和用户手册吗?”
基础模型输出:(可能是一些不相关或混乱的文本)
期望答案:“是的,Lamini 可以生成技术文档和用户手册。”

可以看到,基础模型尚未学会正确回答我们的问题,这正是训练需要改进的地方。

4. 配置训练参数并开始训练

现在,我们配置训练参数并使用 Hugging Face 的 Trainer 类开始微调。

from transformers import TrainingArguments, Trainer

# 定义训练参数
training_args = TrainingArguments(
    output_dir="./lamini-finetuned",
    num_train_epochs=1,
    per_device_train_batch_size=1,
    max_steps=config["max_steps"], # 关键参数:最大训练步数
    logging_steps=1,
)

# 创建Trainer实例
trainer = Trainer(
    model=base_model,
    args=training_args,
    train_dataset=tokenized_datasets["train"], # 假设已处理好的训练数据
)

# 开始训练!
trainer.train()

训练开始后,控制台会打印日志,你可以观察 损失值 随着训练步数增加而下降的趋势。

5. 保存与加载微调后的模型

训练完成后,保存模型以便后续使用。

# 保存模型
trainer.save_model("./my_lamini_model")

# 加载微调后的模型
finetuned_model = AutoModelForCausalLM.from_pretrained("./my_lamini_model", local_files_only=True)
finetuned_model.to(device)

6. 评估微调效果

最后,我们再次使用相同的测试问题,查看微调后模型的表现。

# 使用微调后的模型进行推理
new_answer = generate_text(finetuned_model, tokenizer, “Lamini 能生成技术文档和用户手册吗?”)
print(“微调后模型回答:”, new_answer)

结果对比

  • 基础模型:回答混乱或不相关。
  • 微调3步后:可能略有改善,但距离完美答案仍有差距。
  • 充分微调后(例如在整个数据集上训练多轮):输出答案将非常接近“是的,Lamini 可以生成技术文档和用户手册。”

高级话题:内容节制与行为引导

微调不仅可以教会模型回答问题,还可以引导其行为。例如,通过在数据集中加入“让我们继续讨论与 Lamini 相关的问题”这样的样本,可以训练模型在遇到无关问题时,礼貌地将对话引导回主题,实现一定程度的内容节制

云端训练与模型分享

对于更大参数的模型,可以使用 Lamini 等库提供的云端托管 GPU 进行训练,只需几行代码即可提交训练任务。训练完成后,你可以获得一个模型 ID 和 API 密钥,方便进行私有部署或与他人分享你的模型。

总结

本节课中,我们一起学习了大语言模型微调的全过程:

  1. 原理:理解了训练通过计算损失和反向传播来更新模型权重的核心机制。
  2. 代码:从 PyTorch 底层训练循环,到使用 Hugging Face Trainer 的高级实践。
  3. 实战:完成了对 Pythia-70M 模型的加载、配置、微调、保存和评估。
  4. 进阶:了解了通过数据设计实现内容节制,以及利用云端资源训练大模型的方法。

通过微调,你可以让通用的基础模型适应你的特定任务和数据,从而显著提升其在目标领域的表现。

007:评估与迭代 🧪

在本节课中,我们将学习如何评估微调后的大语言模型,并了解迭代改进的重要性。评估生成式模型是一项具有挑战性的任务,我们将探讨多种评估方法,包括人工评估、基准测试和错误分析。

评估的重要性与挑战

模型训练完成后,下一步是进行评估。这一步至关重要,因为人工智能的发展依赖于迭代,评估结果将帮助你持续改进模型。

评估生成式模型非常困难。没有明确的衡量标准,且随着模型性能的快速提升,度量标准本身也难以跟上发展。因此,人工评估往往是最可靠的方式,即让熟悉该领域的专家来评估模型的输出。

一个高质量的测试数据集对于有效利用专家时间极其重要。这意味着数据集需要:

  • 准确:经过检查,确保内容正确。
  • 泛化:涵盖大量不同的测试用例。
  • 独立:确保数据在训练集中未曾出现。

主流评估方法

以下是几种主流的模型评估与比较方法。

ELO 排名比较 🏆

这是一种流行的比较方法,类似于在多模型间进行A/B测试或锦标赛。ELO排名最初用于国际象棋,它能有效区分不同模型的性能优劣。

开放LLM基准测试

一个常见的开放LLM基准测试是LMSys Chatbot Arena。它采用一系列不同的评估方法,将结果平均后对模型进行排名。

这个基准由LMSys组织创建,它整合了多个学术基准:

  • ARC:一套小学水平的问题集。
  • HellaSwag:对常识推理能力的测试。
  • MMLU:涵盖多种小学科目。
  • TruthfulQA:衡量模型复现网络上常见错误信息(谎言)的能力。

这些基准被研究人员广泛使用。模型排名会持续更新,例如在录制本课程时,Llama 2表现优异,而使用Orca方法在Llama上微调的Free Willy模型也取得了良好成绩。

错误分析框架 🔍

分析和评估模型的另一个重要框架是错误分析,即对模型产生的错误进行分类,以理解常见的错误类型。一个关键优势是,在微调之前就可以对基础模型进行错误分析,这有助于理解其工作方式,并确定哪些数据能通过微调带来最大提升。

以下是一些常见的错误类别:

  • 拼写错误:模型输出中存在简单的拼写错误。例如,将“杠杆”误写为“肝脏”。解决方法是在数据集中修正此类样本。
  • 冗长:生成式模型通常倾向于给出冗长的回答。解决方法包括确保训练数据包含简洁的回答示例,或在提示模板中更明确地使用停止标记。
  • 重复:模型输出可能包含大量重复内容。除了使用停止标记,还需确保数据集中包含多样性充足、重复较少的示例。

实践:运行评估

现在,我们将进入实践环节,在测试数据集上运行模型,并尝试几种评估指标。

首先,加载测试数据集并查看一个数据样本。

# 打印一个问题-答案对
print(“问题:“, test_dataset[0][‘question’])
print(“答案:“, test_dataset[0][‘answer’])

接着,加载微调后的模型。我们将从Hugging Face获取之前微调好的模型。

from transformers import AutoModelForCausalLM, AutoTokenizer
model_name = “your-finetuned-model” # 替换为你的模型名称
model = AutoModelForCausalLM.from_pretrained(model_name)
tokenizer = AutoTokenizer.from_pretrained(model_name)

在评估模式下运行模型时,一个重要步骤是调用 model.eval(),以确保禁用Dropout等仅在训练时使用的功能。

model.eval()

然后,可以运行推断函数来生成输出。我们将定义一个简单的评估指标:精确匹配,即比较生成的字符串与标准答案字符串是否完全一致(忽略空白字符)。

def exact_match(prediction, target):
    return prediction.strip() == target.strip()

需要注意的是,对于创造性写作任务,存在许多可能的正确答案,因此“精确匹配”并不是一个高效的指标。它更适用于信息提取或分类性质的任务。

除了精确匹配,还有其他评估方法:

  • 使用另一个LLM进行评分:将输出和答案交给另一个LLM,让其评估相似度。
  • 使用嵌入计算相似度:分别对标准答案和生成答案进行嵌入,然后计算它们在高维空间中的距离(如余弦相似度)。

现在,让我们在整个测试集的一个子集上运行评估。

import pandas as pd
results = []
for i in range(10): # 为了节省时间,只评估前10个样本
    question = test_dataset[i][‘question’]
    target_answer = test_dataset[i][‘answer’]
    predicted_answer = generate_answer(question, model, tokenizer) # 假设的生成函数
    is_exact = exact_match(predicted_answer, target_answer)
    results.append({‘question’: question, ‘target’: target_answer, ‘prediction’: predicted_answer, ‘exact_match’: is_exact})
df = pd.DataFrame(results)
print(f“精确匹配的数量:{df[‘exact_match’].sum()}”)

评估结果可能显示精确匹配数为零,这对于创造性任务并不意外。归根结底,更有效的方法是在精心策划的测试集上进行人工检查。你可以查看生成的数据框,逐一对比预测答案与目标答案的接近程度。

运行学术基准测试

最后,我们可以运行像ARC这样的学术基准测试。这个基准测试主要包含小学科学问题。

# 假设使用evaluate库运行ARC基准
from evaluate import load
arc = load(‘arc’)
# 在模型上运行评估(此处为示意,实际调用需适配)
# scores = arc.compute(model=model, tokenizer=tokenizer)

运行后可能会得到一个分数。但需要强调的是,不应过分关注模型在这些通用基准上的性能。人们用这些基准给模型排名,主要是为了比较通用模型的能力。

然而,微调模型的目的是为特定用例量身定制。因此,评估的重点应始终放在与你的业务目标最终用例相关的任务上。除非你微调模型的目的就是回答小学科学问题,否则ARC等基准的分数对你的实际应用参考价值有限。

课程总结

本节课中,我们一起学习了如何评估微调后的大语言模型。

我们首先了解了评估生成式模型的挑战,认识到人工评估和高质量测试集的重要性。接着,我们探讨了ELO比较和LMSys Chatbot Arena等开放基准测试。然后,我们介绍了错误分析框架,用于在微调前后系统性地识别和改进模型缺陷。

在实践部分,我们学习了加载模型、在评估模式下运行、以及实施简单的评估指标(如精确匹配)。我们还讨论了更高级的评估方法,如使用另一个LLM评分或嵌入相似度计算。最后,我们运行了ARC学术基准,并重点指出:评估的核心必须围绕你的特定任务和业务需求展开,通用基准的分数仅在选择基础模型时有参考意义。

通过持续的评估和基于反馈的迭代,你可以逐步提升模型在真实场景中的表现。

008:建议与实用技巧 🧠💡

在本节课中,我们将学习大模型微调的最后一部分内容,涵盖一些实用的步骤、技巧以及对更先进训练方法的初步了解。我们将从基础任务开始,逐步探讨如何应对更复杂的挑战,并介绍提升训练效率的关键技术。

微调的实际步骤 📋

上一节我们介绍了微调的基本概念,本节中我们来看看具体执行的步骤。遵循一个清晰的流程可以帮助你更高效地完成微调任务。

以下是进行微调时需要遵循的关键步骤:

  1. 明确你的任务:首先需要清晰地定义你希望模型完成的具体任务。
  2. 收集与任务相关的数据:准备包含输入和输出的数据对,并将其构造成模型可接受的格式。
  3. 处理数据不足的情况:如果数据量不够,可以通过生成数据或使用提示模板来创建更多训练样本。
  4. 从小模型开始微调:建议先从一个参数在4亿到10亿之间的小模型开始,以初步了解模型性能。
  5. 调整数据量进行实验:通过改变用于训练的数据量,来观察数据如何影响模型的学习效果。
  6. 评估模型性能:对微调后的模型进行评估,分析其成功与不足之处。
  7. 迭代优化:根据评估结果收集更多数据,以改进模型。
  8. 提升任务复杂度:在基础任务表现良好后,可以尝试让任务变得更复杂。
  9. 增大模型规模:对于更复杂的任务,可以考虑使用参数更多的大模型来提升性能。

理解任务复杂度与模型规模的关系 ⚖️

在了解了基本步骤后,我们需要理解任务本身的性质如何影响我们的策略。你学到了阅读任务和写作任务的区别,其中写作任务(如聊天、写邮件、编写代码)通常更具挑战性。

这是因为写作任务需要模型生成更多的令牌(tokens),对模型能力的要求更高。因此,处理更困难的任务往往需要更大的模型。另一种应对复杂任务的方法是将多个子任务组合起来,要求模型同时或按顺序处理多个步骤,而不是执行单一指令。

计算资源与硬件需求 💻

确定了任务和模型规模后,接下来需要考虑实际的硬件和计算资源。这直接关系到实验能否顺利进行。

基本上,你需要根据实验室条件选择能运行模型的硬件。例如,在CPU上运行7000万参数的模型效果通常不理想,建议从性能更好的配置开始。

以下是一些常见的GPU配置及其能力参考:

  • NVIDIA V100 (16GB内存):可用于对70亿参数模型进行推理,但用于训练时,由于需要存储梯度和优化器状态,通常只能训练约10亿参数的模型。
  • 其他更强大的GPU选项:如果你的任务需要更大的模型,可以考虑内存更大的GPU,例如A100等。

参数高效微调技术预览 🚀

如果你发现现有硬件不足以训练理想的大模型,有一种称为参数高效微调的技术可以帮到你。这套方法能让你在训练模型时更有效地利用参数和计算资源。

其中,我最喜欢的技术是 LoRA

LoRA 代表 低秩适应。它的核心作用是大幅减少需要训练的参数数量。

例如,在对GPT-3这样的大模型进行微调时,研究发现可训练参数量能减少 一万倍,这使得GPU内存需求降低了 3倍。虽然微调精度可能略低于全参数微调,但它是一种到达目标的更高效途径,并且在推理时不会增加延迟。

那么LoRA具体是如何工作的呢?

在数学上,LoRA不对原始预训练权重(图中蓝色部分)进行更新,而是冻结它们。它训练一组新的、低秩的权重矩阵(图中橙色部分),这些矩阵是原始权重矩阵的秩分解近似。

关键点在于:这些新的权重可以独立于预训练权重进行训练,但在推理时,能够将它们合并回主预训练权重中,从而得到一个高效的微调模型。

使用LoRA最让我兴奋的一点是它的任务适应性。这意味着你可以用客户A的数据训练一个LoRA适配器,然后用客户B的数据训练另一个不同的适配器,而基础模型保持不变,实现了灵活的多任务适配。


本节课总结

在本节课中,我们一起学习了微调大模型的完整实用流程:从定义任务、准备数据、从小规模实验开始,到评估与迭代。我们探讨了任务复杂度与所需模型规模的关系,以及对应的硬件考量。最后,我们预览了参数高效微调技术,特别是LoRA的原理与优势,它通过大幅减少可训练参数量,让我们能在有限资源下高效地微调大模型。

009:总结 🎯

在本节课中,我们将一起回顾整个大模型微调的学习历程,总结核心概念、关键步骤以及微调技术在整个机器学习工作流中的位置。


上一节我们介绍了模型评估与部署,本节中我们来对整个微调课程进行总结。

现在你明白什么是微调了,它适合的应用场景,以及为什么它很重要。

现在微调已成为你工具箱中的一个实用工具。你已经经历了从数据准备,到模型训练,再到评估模型的所有不同步骤。


课程核心回顾

以下是本课程涵盖的核心内容要点:

  • 微调的定义:在预训练好的大语言模型基础上,使用特定领域的数据进行额外训练,使其适应新任务的过程。核心公式可表示为:微调后模型 = 预训练模型 + Δ(特定任务数据)
  • 微调的价值:相比于从头训练或仅使用提示词,微调能以更低的计算成本和数据需求,获得在特定任务上性能更优、行为更可控的模型。
  • 完整工作流程:你已学习并实践了微调的标准化流程,主要包括:
    1. 数据准备:收集、清洗、格式化特定任务数据。
    2. 模型训练:选择合适的微调方法(如全参数微调、LoRA等),配置超参数,启动训练。
    3. 模型评估:使用验证集和测试集评估模型性能,确保其达到预期目标。
    4. 模型部署:将训练好的模型集成到应用中进行推理。


总结

本节课中我们一起学习了微调技术的全貌。你不仅理解了微调的基本概念和重要性,还掌握了从数据到可部署模型的完整实践路径。微调是连接通用大模型与具体业务需求的关键桥梁,希望你能够将这门课程中学到的知识,有效地应用到实际项目中去。

posted @ 2026-03-26 08:14  绝不原创的飞龙  阅读(1)  评论(0)    收藏  举报