在写第一行代码之前,先把训练这个概念彻底厘清
先把训练这个概念说清楚
我们每天都在使用大语言模型,但若被问到"它究竟是怎么训练出来的",多数人会发现自己难以回答。参数、数据、显卡、损失函数——这些词大都听说过,却很难把它们串成一条清晰、连贯的线索。
本系列的目标,就是把这条线索完整地梳理出来。我们不会停留在概念的复述上,而是从零开始,用 Python 亲手实现一个可以运行的迷你 GPT,在你自己的电脑上完成它的训练,并观察它如何从输出无意义的字符,逐步变得能够写出通顺的句子。过程中的每一步代码都会解释清楚,不省略关键环节。
不过,在写下第一行代码之前,需要先把一个最基础的概念彻底厘清,否则后续内容都会失去根基。这个概念是:模型在训练过程中,究竟在学习什么。
语言模型的本质:预测下一个字
如果把各种外在的表现形式都剥离掉,一个语言模型所做的事情可以归结为一件:给定一段文字,预测紧随其后的下一个字最有可能是什么。
这个描述听起来过于简单,但它确实是模型工作的核心。当输入是"今天天气真"时,模型会判断下一个字是"好"的可能性较高,是"狗"的可能性极低。需要注意的是,它输出的并不是一个确定的字,而是对所有候选字的一份概率判断。
那么,一段完整的文章又是如何产生的。答案是反复执行上面这个动作。模型预测出"好"之后,把"好"接在原文之后,得到"今天天气真好",再以这句新的文字作为输入,预测再下一个字,可能是一个逗号;接着继续预测,可能是"我"。如此一个字一个字地接续下去,最终形成一段完整的文字。我们在对话界面中看到文字逐个出现的过程,正是这一连续预测过程的外在呈现。
这里需要补充一个术语。严格来说,模型预测的基本单位并不是"字",而是 tokentokentoken 是模型处理文字的最小单位。模型并不直接面对汉字或字母,而是先把文字切成一个个 token、再为每个 token 编号之后才处理。在本系列采用的字符级方案里,一个 token 恰好是一个字符;真实的大模型则常以词或词根这样的片段作为 token。模型每一步所预测的,正是下一个 token。 。一个 token 可能对应一个完整的汉字,也可能是半个英文单词,或者一个标点符号。为什么要引入 token 这一概念、而不直接以字为单位,第二篇会专门讨论。在本篇中,可以暂且把 token 理解为"字",这不会影响对任何原理的理解。
由此,"模型很智能"这一感受,可以被翻译成一个朴素得多的表述:它能够相当准确地预测下一个 token。
训练:让预测能力逐步形成
接下来的问题是,模型凭什么能够预测得准确。
模型的内部,是大量的数值。少则数百万个,多则数百上千亿个,它们有一个统一的名称——参数ParameterParameters are the millions or billions of numbers stored inside a model. They are exactly what training adjusts: each step nudges them so that the next-token prediction grows a little more accurate. A model said to have seven billion parameters has seven billion such adjustable numbers. Once training is finished they are frozen and saved as the model weights. ,也称权重。为了便于建立直观印象,可以借助一个类比:把模型设想成一台装有大量可调旋钮的仪器,文字从一端输入,这些旋钮按照固定的方式对它进行一系列运算,最终在另一端输出对下一个 token 的预测。需要说明的是,这只是一个帮助理解的类比,后文仍以"参数"作为正式称呼。
旋钮所处的位置不同,运算的结果就不同,模型的预测也随之不同。如果所有参数都处在随机的初始位置,模型的输出就只能是毫无意义的字符。
训练,就是有方向地调整这些参数的过程。更具体地说,它是这样一个不断重复的循环:
取一段真实的文字,例如"今天天气真好"。把其中的"今天天气真"输入模型,让它预测下一个字。假设它给出的预测是"狗",而正确答案是"好"。此时我们获得了一条明确的信息——模型预测错了,并且可以据此计算出误差偏在哪个方向。依据这个方向,把模型内部的每一个参数都微调一点,使得模型下一次遇到类似输入时,对"好"给出的概率略微提高,对"狗"给出的概率略微降低。
随后换下一段文字,重复同样的过程;再换,再重复。当海量的文字以这种方式被处理过成千上万遍之后,所有参数就被逐步调整到了一组良好的取值上——良好到模型对几乎任何一段开头,都能给出相当准确的预测。
这个持续调整参数的过程,就是训练。训练完成后,这组参数的取值被固定下来,保存为一个文件,这个文件就是通常所说的模型权重模型权重模型权重就是训练结束后被固定下来的那一整组参数取值,通常保存为一个文件。它凝结了模型从海量文字中学到的全部规律——换句话说,模型的全部能力都存放在这个文件之中。从网上下载一个开源模型,下载的正是这样一份权重文件,只是体量大得多。 。当人们说某个模型"有七十亿参数"时,指的就是这台仪器上有七十亿个可调的旋钮。
这一过程可以与学习骑自行车作类比。没有人能够仅凭讲解就学会骑车,真正起作用的,是身体在一次次摇晃与偏倒之中,依据"这一次向左偏了"这样的反馈,对维持平衡所需的动作做出细微调整。模型训练在原理上与此一致,区别在于它把这种"产生误差、判断误差的方向、做出微调"的过程,作用在数百万个数值之上,并交由计算机自动、高速地完成。
本系列的安排
到此为止,原理层面的铺垫已经完成。但仅凭文字叙述,"预测下一个字""调整参数"这些说法仍然是抽象的。要把它们真正变得具体,最有效的方式是亲手实现一个模型。
因此,本系列是一份实践教程,而非概念介绍。我们将使用 PyTorch——Python 生态中最主流的深度学习库——从零搭建一个迷你规模的 GPT。它与真正的 GPT 采用完全相同的原理和结构,区别仅在于规模:它足够小,可以在一台普通的笔记本电脑上,于几分钟到十几分钟内完成训练。
整个系列的安排如下:
- 本篇,厘清模型在学什么,并准备好开发环境与训练数据。
- 第二篇,把文字转换为数字。计算机只能处理数字,因此第一道工序是为每一个字符分配编号。
- 第三篇,搭建一个结构最简单的模型,使训练循环首次完整运转。这个模型的能力有限,但"输入数据、计算误差、调整参数"这一完整循环将第一次真正运行起来。
- 第四篇,专门讲解反向传播,也就是"如何依据误差的方向调整参数"这一机制的具体实现。它是整个训练过程的核心。
- 第五篇,讲解注意力机制。它让模型不再只依赖前一个字,而是能够回顾整段上下文,这是 GPT 之所以强大的关键所在。
- 第六篇,把注意力机制、残差连接、层归一化等部件组合起来,构成一个完整的 GPT 结构。
- 第七篇,完整地训练这个迷你 GPT,调整超参数,并观察它生成的文字如何逐轮改善。
- 第八篇,从迷你 GPT 回到现实,说明真正的 ChatGPT 在我们所做的这些工作之外,还经历了哪些关键阶段。
本系列假定读者具备 Python 基础,但不要求读者预先了解神经网络,所需的概念都会在文中适时讲解。如果你希望在某个知识点上做更深入的探究,本博客的 ml-basics 系列提供了更系统的数学推导,可以配合阅读。
准备开发环境
下面开始动手。首先安装所需的工具。建议使用 3.10 及以上版本的 Python,然后安装 PyTorch:
# 建议先创建一个独立的虚拟环境,避免影响系统自带的 Python
python -m venv venv
source venv/bin/activate # Windows 系统使用 venv\Scripts\activate
# 安装 PyTorch,使用 CPU 版本即可
pip install torch
没有独立显卡不会造成任何障碍。本系列的模型规模很小,使用 CPU 训练只需几分钟即可完成。如果你的电脑配有 NVIDIA 显卡,第七篇会说明如何利用它加速训练,但这并非必要条件。
安装完成后,做一次验证:
import torch
print(f"PyTorch 版本:{torch.__version__}")
print(f"是否有可用的 GPU:{torch.cuda.is_available()}")
只要能够正常打印出版本号,开发环境就已就绪。即使 torch.cuda.is_available() 返回 False 也不影响后续内容,如前所述,CPU 已经足够。
准备训练数据
模型需要从文字中学习规律,因此我们必须为它提供一份文字材料。具体使用什么内容并不受限——一部小说、一本书籍、一整部诗集都可以。模型会习得这份材料的语言风格,它最终生成的文字,也会带有相应的特征。
你需要做的是:准备一份纯文本文件,命名为 input.txt,并以 UTF-8 编码保存。建议选用中文语料,例如一部已进入公有领域的小说(《三国演义》《西游记》的全文均可),或者一份唐诗合集。文件大小在数百 KB 到数 MB 之间较为合适——过小则模型难以学到有效规律,过大则会显著拖慢训练速度。
准备好之后,把文件读入程序,并先对它做一次初步的观察:
# 读取训练数据
with open("input.txt", "r", encoding="utf-8") as f:
text = f.read()
print(f"全文共有 {len(text)} 个字符")
print(f"开头的 200 个字符:\n{text[:200]}")
# 统计这份材料中共出现了多少种不同的字符
chars = sorted(set(text))
print(f"不同字符的数量:{len(chars)}")
print(f"字符表的前 50 个:{chars[:50]}")
对这几行代码稍作说明。len(text) 是语料的总规模,也就是模型可供学习的原始材料的总量。set(text) 把文字中的所有字符去重,得到一张"字符表"——这份语料中出现过的全部不同字符的集合。这张表的意义需要特别留意:模型将来能够输出的字符,只可能来自这张表;表中没有出现过的字,模型永远无法写出。
这张表的大小,在下一篇中会成为一个关键的数值,称为词表大小(vocabulary size)。由于汉字数量本身较多,中文语料的字符表通常包含数千项。
当这几行代码能够顺利运行时,训练一个模型的准备工作就迈出了第一步。我们现在掌握了所需的原始材料:一份文字,以及它所包含的字符表。
本篇要点
- 语言模型的本质,是依据前文预测下一个 token;生成长篇文字,就是反复执行这一预测并不断接续。
- 模型内部由大量可调整的数值构成,称为参数或权重;参数取值不同,预测结果就不同,随机的参数只能产生无意义的输出。
- 训练是一个循环:输入真实文字、判断模型预测的误差及其方向、据此微调参数,使预测逐步变得准确。
- 训练完成后,参数取值被固定并保存为文件,即"模型权重"。
- 本系列将使用 PyTorch 从零训练一个可在笔记本电脑上运行的迷你 GPT,其原理与真正的 GPT 完全一致。
- 第一步工作是安装 PyTorch、准备一份纯文本语料,并查看它的规模与字符表。
下一篇
我们目前掌握的是一份文字,而模型只能处理数字,无法直接识别汉字。下一篇要完成的,正是这道转换工序:把文字转换为数字,为每个字符分配编号,整理成模型可以读取的形式,并正式认识第一个关键概念,token。
参考资料
- PyTorch 官方安装指引
- Andrej Karpathy: Let's build GPT(本系列的思路来源)
- 本博客 ml-basics 系列——神经网络与反向传播的系统讲解
版权声明: 如无特别声明,本文版权归 sshipanoo 所有,转载请注明本文链接。
(采用 CC BY-NC-SA 4.0 许可协议进行授权)
本文标题:模型到底在学什么
本文链接:https://www.sshipanoo.com/blog/ai/mini-gpt/01-模型到底在学什么/
本文最后一次更新为 天前,文章中的某些内容可能已过时!