5.1 自然语言处理与预训练
1.语言怎么进到模型里:从字到向量
说起来,神经网络其实只会算数。你直接把一句中文丢给它,它当场就束手无策,因为字它压根看不懂。所以文本得先变成数字,模型才有可能拿去算,这一步是怎么做的,我们一层一层来说。
第一步,是把一段话切成一个个小块,这些小块就叫词元(token)。一个词元可能是一个字(比如深、度),可能是一个完整的词(比如学习),也可能是某个词的零件(比如ing这种后缀)。切分的方式并没有唯一答案,具体怎么切得看分词器的脾气,但不管怎么切,切完之后每个词元都会被分配一个整数编号。比方说深度学习这四个字,切完就是四个词元,每个词元都有自己的整数编号。编号具体是几不重要,重要的是同一个词元永远对应同一个编号。
光有个编号还不够用。编号本身只是一张身份牌,编号大不代表意义大,编号小也不代表意义小,你要是直接把编号丢进网络里算,模型只会一脸茫然。所以接下来还得通过一张叫嵌入矩阵的大表,把这个编号查成一个向量,这步把编号变成向量的操作就叫嵌入(embedding)。你不妨把嵌入矩阵想成一本超大的花名册,行号就是编号,每一行正好对应一个词元的初始表示。
词元对应的向量记作 ,下标 表示这是这段话里的第几个词元(比如 是第一个, 是第二个)。这个向量由多少个数排成,叫嵌入维度,记作 ( 就是 这条向量的长度)。这些向量一开始全是随机填的,一团乱糟糟的数字,可在训练过程里,它们会根据词元出现的上下文被模型反复调整,慢慢地就被调教出了意义。
最后的结果是,意义和用法相近的词元,会在向量空间里落到相近的位置。比如猫和狗的向量,会比猫和汽车离得更近。这就好比大学里兴趣相近的人喜欢往同一个社团凑,模型靠的正是这种位置关系,隐约懂得了词跟词之间的亲戚关系。这部分思路最早能追到2013年Mikolov他们做出来的word2vec,那会儿大家就发现拿向量来表示词,是真的能学到东西,后人基本上都是在这套想法上继续往下堆的。
2.上下文:让同一个词有不同的味道
光给每个词元一个写死的向量,其实还远远不够。怎么说呢,因为同一个词在不同句子里,意思可能天差地别。苹果在吃水果的句子里是一种水果,在聊公司的句子里是一家科技公司,你要是拿同一个固定向量去表示它,模型当场就分不清东南西北了。
再举个各行各业的例子。我有个朋友在金融行业做事,他说牛这个词在他们那儿,常常指牛市,行情看涨的意思。可要是换个语境,比如看一场球赛,夸一句某位运动员今天真牛,那纯粹是夸对方厉害。同一个字,味道完全变了,写死的向量哪顶得住。
上下文模型解决的正是这桩事。它会根据一个词周围的所有词元,重新算出这个词在当前这句话里的表示,那个写死的初始向量这时候就丢开了,改用一个被整句话重新泡过一遍的新向量。借助于注意力机制(attention),模型能让一个位置参考到句子里其他位置的词元,哪怕隔得很远的语义关系也能照顾到。注意力里最常用的一种叫缩放点积注意力(scaled dot-product attention),它的计算是
式子里的 、、 分别叫查询矩阵、键矩阵、值矩阵, 是键的维度, 用来度量不同位置之间的相关性,除以 是为了在维度较大时把数值控制住,让训练时的梯度更稳定,最后再经softmax归一化之后乘到 上,就得到了融合了上下文的表示。
你不妨把注意力机制想成上课记笔记的情景。老师在前面讲了一长串,你听到当下这句的时候,会自动回头去翻前面记的几行,把相关的内容串起来理解这一句。经过几层网络这么来回打磨,每个词元的表示就带上了整句话的语境。这种带语境的表示就叫上下文相关的表示,也是现代语言模型能这么懂人话的关键之一。把这套注意力机制彻底玩明白、发扬光大的,是2017年Vaswani他们那篇Transformer的论文,后来的BERT和GPT,基本上都是从这条根上长出来的。
3.预训练在学什么:拿海量文本当自习课
预训练(pre-training)这名字听起来挺唬人,说穿了,就是让模型在堆成山的海量文本上自己学语言规律。这些文本大多没有人工标注,模型全靠自己找规律,挺像你期末前泡图书馆,抱着一摞没人给你讲答案的资料硬啃,啃着啃着就悟了。
常用的预训练目标有两种,思路都很朴实。
一种叫自回归语言模型,玩法是根据前文预测下一个词元。给你看到深度学习很有,让模型预测下一个词元,再用交叉熵损失衡量预测概率与真实词元的差距,据此反向调整参数(预测越偏离真值,梯度推动的修正就越强),一遍遍练下来,模型就摸清了词跟词接在一起的规律。这其实跟你追一部长篇连续剧是一个道理,每一集结尾总留个悬念,你心里已经开始琢磨下一集要怎么演,根据前面埋下的伏笔去猜后面的走向。大名鼎鼎的GPT,走的就是这条路。
另一种叫掩码语言模型,玩法是把句子里某些词元遮挡起来,让模型根据剩下的上下文把它们猜回来。比如把深度学习很有趣里那个学习盖住,让模型还原。这就好比做英语卷子里的完形填空,挖几个空让你填回去,BERT走的就是这条路。
这两种目标都把正确答案的概率转化成了损失,模型为了降低损失,就得去揣摩词和词、句和句之间的统计规律,语言表示就这么一点一点被它学会了。以自回归语言模型为例,模型看到前文 (也就是第 个词元之前的所有词元)之后,要预测第 个词元 出现的概率 。训练时把所有位置的预测取对数再取负号累加,就得到交叉熵损失
这里的 是以 为底的自然对数,前面加负号,是因为概率取对数后是非正的,加个负号把它转成非负的损失,模型要做的就是把这个损失压到尽量小。掩码语言目标的损失形式和它类似,只不过只对那些被遮挡住的位置求和。说到底,预训练就是让模型先上一节超级自习课,把人类攒了多少年的文本材料当题库狠狠刷一遍,刷完之后再去干下游的活儿(翻译、问答、摘要这些),上手就快多了,这才是预训练真正的价值所在。
4.规模和数据:大力出奇迹,也得喂得好
预训练模型的能力,受三个因素一块儿影响:参数量(模型有多大)、训练数据量(喂了多少文本)、计算量(烧了多少算力)。
这些年大家发现一个让人又爱又恨的现象:把这三个规模持续往上堆,确实能换来更强、更聪明的模型,而且好像还没到头,这被戏称为Scaling Law(规模法则)。怎么说呢,大力真的能出奇迹,堆卡、堆数据、堆参数,模型性能就跟着往上窜,效果确实让人惊喜。
可放大之后,数据本身的毛病也会被一起放大。数据质量不高、同样的内容在语料里反复出现,都会直接拖累模型。就好比刷题,你要是整天刷一本满是错题的练习册,刷得越多反而越废,可谓反向努力,连带着判断力也会被带歪。更麻烦的是,模型还可能把语料里夹带的偏见也一并学进去,跟着犯混。所以数据从哪儿来、怎么清洗过滤、用什么任务来评估,每一环都得认真对待,光会堆规模那可不行。
我想起那些顶尖的短跑运动员,天赋大概决定了他们的上限在哪儿,可真正能一次次站上领奖台的,往往是日复一日那些不被看见的训练和饮食细节。预训练这件事也差不多,参数和算力像是天赋,数据质量更像是那些容易被忽略的训练细节,两者都马虎不得。
预训练这块就先聊到这儿。一句话收个尾:先把文本切成词元、再把词元嵌成向量、靠注意力拿到上下文表示、最后在海量文本上自修自习,这四步串起来,就是现代语言模型拿到语言能力的整套流程。
今天就先到这儿,下一章见。
练习
Q1. 为什么词元不能直接用它的整数编号丢进网络,而要先过一层嵌入矩阵?
编号本身只是一张身份牌,编号大不代表语义大,编号小也不代表语义小,直接把编号喂进去,模型会把它当成一个有大小关系的数来算,毫无道理可言。嵌入矩阵是一张大表,行号对应编号,每一行是一条 维向量,查表把编号换成向量后,向量之间才能用余弦相似度等办法比出语义远近,模型也才有调整语义表示的余地。
Q2. 自回归语言模型和掩码语言模型,分别对应GPT和BERT,它们的训练目标有什么不同?
自回归语言模型是根据前文预测下一个词元,比如看到"深度学习很有"预测下一个,用交叉熵损失 衡量,GPT走这条路。掩码语言模型是把句子里某些词元盖住,让模型根据上下文猜回来,像做完形填空,BERT走这条路。两者都把预测概率转成损失让模型去压,从而学到词和词、句和句之间的统计规律。
Q3. 易错点:Scaling Law说"规模越大模型越强",那是不是只要无脑堆参数和数据,模型就一定越来越好?
不是。Scaling Law说的是参数量、数据量、计算量一起按幂律下降损失,前提是这三者要协调放大。Chinchilla就指出过,很多人参数喂太多、数据喂太少,得不偿失,算力最优配比大约是每个参数配20个token。而且数据质量同样关键,垃圾语料、重复内容、夹带的偏见都会被规模一起放大,反而把模型带歪。所以堆规模要配上数据清洗和合理配比,无脑堆只会"反向努力"。