小白必看:从词向量到Transformer,一口气搞懂自然语言NLP技术发展
你有没有好奇过,GPT 这样的 AI 大模型,到底是如何理解我们的提示词,然后一个字一个字蹦出来回答问题的?
让我们暂时忘记那些复杂的技术名词,从一个最简单的游戏开始,一步步搞懂自然语言技术发展的变化,再看Transformer就非常Easy了。
一、猜词游戏
故事的开始,让我们来玩一个猜词游戏。
根据一句话前面的内容,猜出接下来最有可能出现什么。
比如这句话:
轩辕养了一只____。
A、熊猫
B、汽车
C、鹦鹉
D、苹果
你觉得空白的位置应该填什么?
我们可以用排除法,首先苹果和汽车肯定不对,养了一只苹果和养了一只汽车,这狗屁不通。
熊猫也不对,虽然我在四川,但我也不可能去养一只熊猫啊。
剩下就只能是鹦鹉了。
对人来说,这个猜词游戏很简单,但如果让计算机来做这道题呢?
计算机并不知道什么是鹦鹉,它甚至不知道“养了一只”后面通常应该接动物。
它看到的只是一串文字符号。
那么,计算机应该怎么做才能猜对这道题呢?
二、N-gram
最容易想到的方法,就是统计。
我们可以写个程序,让这个程序阅读大量文章,然后让它统计不同词语组合出现过多少次。
假设在这些文章中:
“养了一只猫”出现过一万次;
“养了一只狗”出现过八千次;
“养了一只鹦鹉”出现过两千次;
而“养了一只苹果”、“养了一只汽车”、“养了一只熊猫”一次都没有出现过。
那么,当计算机看到“养了一只”,它就可以根据过去的统计结果判断:
后面出现“猫”“狗”或者“鹦鹉”的概率比较高,出现“苹果”、“汽车”、“熊猫”的概率几乎为零。
再结合给出的选项,它就知道该选C:鹦鹉了。
这就是早期语言模型最基本的思路:
根据前面已经出现的内容,预测下一个词。
这里为了方便表述,我们暂时把模型预测的单位叫作“词”。
更准确的叫法是 Token。
一个 Token 有时是一个完整的词,有时是一个汉字、一个标点,也可能只是一个英文单词的一部分。
常见的词语可以作为完整 Token 保留下来,不常见的词语则被拆成几个更小的部分。
具体怎样拆分,不是这一期的重点。
你只需要先记住:
Token 就是语言模型读取和预测文本时使用的基本单位。
如果预测下一个词时,只参考前面的一个词,这叫二元模型,也就是 Bigram。
比如只看到“一只”,然后统计“一只猫”“一只狗”“一只鹦鹉”分别出现过多少次。
如果参考前面的两个词,比如“养了”“一只”,这就是三元模型,也就是 Trigram。
如果参考更多连续的词,就可以统称为 N-gram。
N 代表模型一次考虑多少个连续的词。
看起来,只要不断增大 N,让模型看到更多前文,预测就应该越来越准确。
但这里很快会出现两个问题。
第一个问题,是组合数量太多。
假设词汇表里有十万个词。
只考虑两个词的组合,并且假设它们都能两两组合,理论上就可能有一百亿种。
如果考虑三个词、四个词,组合数量还会迅速膨胀。
而现实中的句子千变万化。
即使准备了大量文章,也不可能覆盖所有合理的词语组合。
来举个例子。
还是这道猜词题,假如我把选项C从鹦鹉换成虎皮鹦鹉,情况又会变成什么样呢?
人类根据排除法还是一眼能选出C来。
但N-gram模型呢?它可能就选不出来了。
因为训练数据中可能出现过:
养了一只猫。
养了一只狗。
养了一只鹦鹉。
但是从来没有出现过:
养了一只虎皮鹦鹉。
人看到这句话,会觉得完全正常。
可对于只会统计的 N-gram 来说,“养了一只虎皮鹦鹉”是一个从来没有出现过的全新组合。
它并不知道虎皮鹦鹉和鹦鹉之间有什么关系,所以也就选不出来了。
这就引出了第二个问题。
在 N-gram 眼中,每个词都只是一个独立的符号。
“猫”是一个符号,“狗”是一个符号,“鹦鹉”又是另一个符号。
它不知道猫、狗和鹦鹉都属于动物,也不知道鹦鹉和虎皮鹦鹉在含义上非常接近。
所以,它很难把已经统计出来的规律,迁移到没有见过的新句子上。
可人类为什么能做到呢?
因为我们知道词语的含义。
即使从来没有见过“轩辕养了一只虎皮鹦鹉”这句话,我们也知道虎皮鹦鹉是一种鹦鹉,同样可以被人饲养。
三、词向量
所以接下来要解决的问题,就是:如何让计算机知道鹦鹉和虎皮鹦鹉是很类似的东西呢?
或者换句话说,如何把词语的含义交给计算机?
我们可以先人工设计两个特征,每个特征用一个数字,也就是总共用两个数字描述一个词。
第一个数字是“适合作为宠物的程度”,第二个数字是“飞行能力”,都用零到十分表示。
那么,猫可以表示成:
9, 0。
它很适合作为宠物,但基本不会飞。
鹦鹉可以表示成:
8, 9。
它既可以作为宠物,也拥有较强的飞行能力。
虎皮鹦鹉可能是:
8.5, 9。
可以看到,在这个二维空间中,虎皮鹦鹉和鹦鹉的位置非常接近。
汽车则可能是:
0, 0。
既不会飞,也不适合作为宠物。
它和这些动物的距离就比较远。
这样,每个词就不再只是一个孤立的文字符号,而是变成了空间中的一个坐标。
两个词的位置越接近,就说明它们在这些特征上越相似。
我们还可以从坐标轴原点拉出一个带方向的箭头,指向每个词所在的位置。
这一条带方向的线段,就是我们高中数学中学过的向量。
于是,每一个词就可以用这样一组数字,也就是一个向量来表示,这就是词向量。
这样做还有一个重要的好处,我们可以通过数学方法来衡量两个词到底有多相似。
其中一种非常常见的方法叫作余弦相似度。
它不只是看两个点离得有多近,而是比较两个向量的方向有多接近。
通常来说,两个向量的方向越接近,夹角越小,余弦相似度就越高,也就意味着它们在这个高维语义空间中的关系越相似。
你看,我们就这样把“两个词到底像不像”这个非常抽象的问题,变成了一道可以用数学精确计算的问题。
这里我们使用的是2个维度描述一个词,我们可以再增加一个维度,平面上的向量就变成了空间坐标系中的向量了。
而实际上,两个维度、三个维度都远远不够。
即便只是描述一个动物,都还可能需要考虑它是不是哺乳动物、体型有多大、是不是肉食性、生活在什么环境中等等。
更不用说要描述一个通用的词了。需要的维度可能有几十维、几百维,甚至上千维。
虽然我们无法画出,甚至无法想象一个几千维度的超空间是什么样的,但在数学上,它的计算方式依然和前面2维和3维没什么本质的区别。
但毕竟数量这么大,如果这些维度全部由人来设计,不但工作量巨大,也很难覆盖语言中复杂而抽象的关系。
所以真实情况是,我们只需要设计好维度的数量,然后把每个维度的数值交给计算机自己去学习。
计算机会从大量文本中发现:
经常出现在相似上下文中的词,含义通常也比较接近。
例如:
轩辕养了一只鹦鹉。
轩辕养了一只虎皮鹦鹉。
给鹦鹉喂食。
给虎皮鹦鹉喂食。
···
鹦鹉和虎皮鹦鹉经常出现在相似的位置,也经常搭配相似的词。
在训练过程中,它们的向量就会逐渐靠近。
最终,每个词都会变成一组高维数字。
猫、狗和兔子的距离可能比较近。
鹦鹉和虎皮鹦鹉的距离会更近。
汽车则会出现在更远的位置。
这种使用一组连续数字表示词语的方法,就是 Word Embedding,词嵌入。
通过计算机程序的一通操作,我们就把人类语言中的一个词,变成了这样一个高维度的向量。
人类语言中这个词的很多语义关系,就被编码进了这组高维数字中。
单独看其中每一个数字,我们通常很难解释它具体代表什么含义。
但把整组数字看成一个整体,就可以理解成这个词在高维语义空间中的位置。
看到这里不知道大家的感受怎么样,我第一次学习的时候真的有被震撼到,数学不止可以计算日月星辰的运行轨迹,还能来描述人类语言这样抽象的东西,数学真的太美了。
在我看来,词向量的发明甚至比后来的Transformer架构更重要,没有了词向量,自然语言处理还停留在统计数数的阶段。
言归正传,通过把文字变成词向量,模型开始拥有了一定的泛化能力。
即使训练数据中没有完整出现过:
轩辕养了一只虎皮鹦鹉。
模型也可以利用虎皮鹦鹉和鹦鹉之间的语义空间上挨得很近,判断它是一个合理的组合。
不过之前的N-gram它是基于文本字符串统计的方式来预测,根本没有用到词语的语义,所以即便有了词向量,用N-gram还是不行,我们得换新的技术。
而刚好,神经网络最擅长提取抽象的特征来做计算,在图像识别领域已经很好的证明了这一点。
所以很容易想到,我们可以给神经网络看大量文章,让它来学习这里面的语言规律。
和N-gram不同的是,N-gram是单纯的统计数数,而神经网络是通过大量数据的训练,找到一组合适的网络权重和偏移值来拟合语言中的规律。
四、前馈神经网络
我们先用一种最普通的神经网络:前馈神经网络。
前馈神经网络可以理解成一条从输入到输出的单向计算流水线。
数据从输入层进入,经过一个或多个隐藏层的加权求和与非线性变换,最后到达输出层。
回到最开始那个猜词问题。
假设我们想根据前面的三个词,预测下一个词。
输入内容是:
轩辕、养了、一只。
我们先把这三个词分别转换成词向量。
假设每个词向量有三百维。
三个词的向量合在一起,就可以得到一组九百维的输入数据。
这些数字被送进前馈神经网络。
神经网络通过一层层计算,最后为词汇表中的每个词输出一个分数。
例如:
猫的分数是多少;
狗的分数是多少;
鹦鹉的分数是多少;
汽车的分数又是多少。
再通过softmax把这些分数转换成概率,就可以选出最有可能出现的下一个词。
相比N-gram单纯统计词语组合出现的数量,神经网络有一个明显的优势:
它接收的不再是互不相关的文字符号,而是带有语义关系的词向量。
比如模型训练时经常见到:
养了一只鹦鹉。
后来遇到:
养了一只虎皮鹦鹉。
由于“鹦鹉”和“虎皮鹦鹉”的词向量比较接近,它们进入神经网络以后,也会产生比较相似的计算结果。
模型就有机会把在“鹦鹉”上学到的规律,推广到“虎皮鹦鹉”上。
而且,前馈神经网络可以通过隐藏层和非线性变换,学习比简单数数更加复杂的规律。
它可能学会:
“养了一只”后面通常出现宠物;
“飞来了一只”后面通常出现鸟类;
“开来了一辆”后面通常出现汽车。
这些规律不需要人来逐条编写,可以由神经网络在训练过程中自己调整参数学习出来。
到这里,我们已经取得了很大的进步。
N-gram 主要依赖具体词语组合的统计,很难把已经学到的规律泛化到新的组合上。
词向量加上前馈神经网络,则可以根据语义相似性,对没有见过的新组合进行一定程度的泛化。
五、RNN
但刚才这种固定窗口的前馈神经网络,和 N-gram 仍然存在一个共同问题:
那就是它们一次只能看到固定数量的词。
刚才的神经网络,输入层被设计成接收三个词向量。
那它每次就只能参考前面的三个词。
如果想让它参考前面的五个词,就必须重新设计输入层,让它能够接收五个词向量。
无论选择三个、五个还是十个,模型看到的上下文长度始终是固定的。
再次回到之前的猜词游戏,这一次我们把句子变长:
轩辕小时候养过一只虎皮鹦鹉,它有绿色的羽毛,还会模仿人说话。后来轩辕去了外地上学,很多年没有再见到它,但他始终记得小时候养过的那只____。
选项也调整一下:
A、熊猫
B、猫
C、狗
D、虎皮鹦鹉
我相信你还是能一眼选出正确答案:D。因为我们人类的大脑有记忆,第一句话就给出了正确答案。
但无论是N-gram还是刚刚介绍的这种简单的前馈神经网络,它们都无法选出正确答案。
因为它们只能看到前面有限范围的内容。
比如这个前馈神经网络只能查看前面的五个词,那么它只能看到:
记得、小时候、养过、的、那只。
最前面的“虎皮鹦鹉”早已经超出了输入范围。
对这个神经网络来说,“虎皮鹦鹉”就像从来没有出现过一样。
前馈神经网络缓解了泛化问题,却没有解决记忆长度的问题。
那么,问题来了:
有没有什么办法让模型在读取句子的过程中,把前面出现过的重要信息保存下来?
句子有多长,模型就读多长。
而不是提前规定只能查看三个词、五个词或者十个词。
有的,兄弟,有的。
循环神经网络,也就是 RNN,它来了。
RNN 在普通神经网络的基础上,增加了一份可以不断向后传递的信息。
这份信息叫作隐藏状态。
我们可以把隐藏状态理解成模型的记忆。
不过,这份记忆不是我们通常认识的那种记事本。
模型不会在里面直接写下:
“刚才读到了轩辕。”
隐藏状态的本质,仍然是一组数字,它同样是一个向量。
前面我们说了词嵌入可以把词语的语义转换为一个高维向量,这个高维向量里面就包含了语义所对应的信息。
那么同样的,一段文字的信息也可以转换为一组高维向量,在这里就是这个隐藏状态。
单独看其中某个数字,我们依然很难解释它具体代表什么。
但把这些数字组合起来,就形成了模型对“目前为止读过的内容”的压缩表示。
当模型开始读取一句话时,还没有任何前文。
这时可以先准备一组初始隐藏状态。
接下来,模型读取第一个 Token,也就是“轩辕”。
“轩辕”会先被转换成词向量。
RNN 把“轩辕”的词向量和初始隐藏状态放在一起,进行加权求和以及非线性变换,得到一份新的隐藏状态,这是模型记忆的1.0版本。
这份新的隐藏状态,仍然是一组数字。
但它已经融合了当前读到的“轩辕”。
接下来读取“养了”时,模型会同时接收两样东西:
“养了”的词向量,以及刚才处理“轩辕”以后产生的隐藏状态,也就是模型记忆1.0版本。
RNN 再把这两组向量进行计算,得到下一份隐藏状态,形成模型记忆2.0版本。
新的隐藏状态中,既包含当前的“养了”,也保留了前面的“轩辕”所带来的信息。
接着,模型继续读取“一只”、“鹦鹉”。
每读取一个新 Token,RNN 都会用当前 Token 的词向量,更新一次隐藏状态,让这份记忆不断刷新迭代。
所以,隐藏状态并不是对前文的完整复制。
它更像是模型不断更新的一份摘要。
模型会尝试把对后续任务有用的信息保留下来,同时压缩掉大量暂时不重要的细节。
从这个角度看,RNN 的核心计算可以概括成:
用当前 Token 的向量,结合前一时刻的隐藏状态(记忆),生成新的隐藏状态(记忆)。
这份新的隐藏状态,一方面会传给下一个位置,另一方面也可以交给输出层,用来完成当前预测。
我们在结构图中,经常会看到一连串 RNN 单元。
但这些单元实际上使用的是同一套参数。
可以把它理解成同一个神经网络,被连续使用了很多次。
每一次处理句子中的一个 Token。
这和前馈神经网络有一个重要区别。
前馈神经网络如果只能接收三个词,那么第四个词以外的信息就无法进入模型。
RNN 则可以不断读取新的 Token,同时把隐藏状态向后传递。
理论上,无论句子有多长,前面的内容都有机会通过隐藏状态影响后面的结果。
有了隐藏状态以后,RNN 就可以继续完成刚刚的猜词游戏。
当模型依次读取:
轩辕、养了、一只。
最后得到的隐藏状态,就形成了对“轩辕养了一只”这部分内容的压缩表示。
我们可以把这个隐藏状态送入输出层,计算词汇表中每个 Token 出现的概率。
模型可以选择概率最高的“虎皮鹦鹉”,作为下一个 Token。
六、LSTM
RNN 看起来已经摆脱了固定窗口的限制。
那它是不是可以记住任意长度的句子呢?
理论上可以,实际效果却没有这么理想。
我们把刚才的句子扩展得更长一些:
轩辕小时候养过一只虎皮鹦鹉。它有绿色的羽毛,还会模仿人说话。后来轩辕去了外地上学,很多年没有再见到它。但他始终记得小时候养过的那只____。
当模型读到最后的空白时,需要它回忆起很久之前出现过的“虎皮鹦鹉”。
可在普通 RNN 中,“虎皮鹦鹉”这份信息被编码进隐藏状态以后,需要经过后面的每一个 Token,不断向后传递。
每经过一次计算,隐藏状态都会更新一次。
隐藏状态的维度是固定的。
无论句子有十个词还是一百个词,模型都要把前文信息压缩进同样大小的一组向量里。
随着新内容不断进入,旧信息很容易被新信息覆盖。
传递距离越长,最开始的信息就越容易变得模糊。
等模型读到最后时,隐藏状态中和“虎皮鹦鹉”有关的特征,可能已经非常微弱了。
这就是 RNN 的长期依赖问题。
它比较容易记住附近出现的内容,但很难稳定记住几十个 Token,甚至几百个 Token 之前的信息。
更麻烦的是训练。
前面某条信息到底重不重要,要等很多 Token 以后发生预测错误,模型才知道。这个误差再一路反向传回去,经过几十次计算以后,信号很容易变得越来越弱。
结果就是:模型不光容易“忘”,甚至很难学会“这东西原来应该一直记着”。
那我们能不能对 RNN 做一点改造来解决这些问题呢?
原来的隐藏状态继续保留,负责当前的计算。
但是除此之外,我们再增加一条专门传递重要信息的VIP通道。
这条通道尽量少做复杂的修改,让重要的信息可以比较稳定地一路往后传。
比如模型读到:
轩辕小时候养过一只虎皮鹦鹉。
“虎皮鹦鹉”这条信息后面很可能还有用。
那我们希望模型能够把这条信息写进这条VIP通道。
后面又读到:
它有绿色的羽毛。
会模仿人说话。
轩辕后来去了外地上学。
新的信息不断进来,但是之前“养的是虎皮鹦鹉”这条重要信息,可以继续保留。
一直到几十个 Token 以后,遇到了:
他依然记得小时候养过的那只____。
模型再把之前保存的信息拿出来。
这样是不是就能解决 RNN 容易忘记的问题?
想法是好的,但有一个新问题。
如果什么东西都往VIP通道里写,那这VIP通道不就和之前隐藏状态一样,迟早还是会搞乱吗。
所以,想要这个想法能行得通,模型必须学会判断三件事情:
以前记下来的东西,哪些已经没用了,可以忘掉?
现在读到的新东西,哪些值得写进去?
当前进行预测的时候,又应该从里面拿出哪些信息?
为了搞定这三件事情,我们可以再给这条长期记忆的VIP通道增加几个可以控制信息流动的“门”。
第一个是遗忘门。
它的作用是:决定之前保存的每一部分信息,还要留下多少。
模型需要有能力删除过去已经没用的信息。
第二个是输入门。
它的作用是:决定当前这个 Token 带来的新信息,要不要写进长期记忆。让有用的信息多写入一点,而那些无关紧要的信息少写一点,甚至不写。
这样一来,每读取一个新的 Token,模型做的事情就不再只是简单地把隐藏状态全部重算一遍。
还会额外计算:
旧记忆哪些继续留着;
新信息哪些值得加进去。
于是这份长期记忆就可以有选择地不断更新。
最后还有一个问题。
长期记忆里可能存了很多东西。
当前预测并不一定全部需要。
所以,我们再增加一道输出门。
它负责决定:
当前这一刻,长期记忆里的哪些信息应该拿出来使用。
到这里,我们好像已经把普通 RNN 改造得像模像样了。
原来的隐藏状态还在。
但是又增加了一条更稳定的长期记忆通道。
再使用三道门来控制它:
遗忘门,决定旧信息保留多少。
输入门,决定新信息写入多少。
输出门,决定当前拿出多少来用。
看上去非常完美了。
但模型怎么知道什么时候应该记,什么时候应该忘?
难道这些规则需要程序员一条一条写进去吗?
当然不是。
实际上,这三道门背后都是可以训练的门控计算。
模型会根据当前输入和之前的状态,通过一组可以学习的参数,计算出一串0到1之间的数字。
所谓“门打开多少”,本质上就是由这些数字来控制的。
真正让它学会“什么重要”的,是训练。
训练阶段,我们给模型大量完整文本,让它不停地做猜词题。
例如:
轩辕小时候养过一只____。
正确答案是:虎皮鹦鹉。
继续往后:
它有绿色的____。
正确答案是:羽毛。
再一直训练到后面:
他依然记得小时候养过的那只____。
正确答案仍然是:虎皮鹦鹉。
刚开始训练的时候,模型的参数基本是乱的。
它根本不知道“虎皮鹦鹉”这条信息应该保留下来。
它可能读到前面的时候没有保存好。
或者中间某一步,遗忘门一不小心把这部分信息给削弱掉了。
等到了最后来做题的时候:
那只____。
模型预测成了:猫。
但训练数据告诉它:
错了,正确答案是虎皮鹦鹉。
于是就会产生一个预测误差。
然后通过反向传播,调整整个网络里的参数。
这里面也包括遗忘门、输入门和输出门的参数。
如果模型发现:
前面的“虎皮鹦鹉”保存得更好,最后这个词就能预测得更准确,
那么在大量类似训练中,参数就会逐渐往这个方向调整。
慢慢地,当它再次读到:
某个人养了一只某种宠物。
输入门就可能更倾向于把与“宠物是什么”有关的信息写进去。
即便后面隔了很多其他内容,如果这条信息仍然可能有用,遗忘门就会更倾向于把它保留下来。
到了需要再次提到这只宠物的时候,输出门又会把相关信息拿出来。
所以并不是我们提前告诉模型:
“虎皮鹦鹉很重要,记住它。”
而是模型在一次又一次预测错误、修改参数的过程中,自己学会了:
什么样的信息值得长期保存。
等模型训练完成,真正拿来预测的时候,就不再有标准答案告诉它了。
这时我们输入:
轩辕小时候养过一只虎皮鹦鹉……
模型一个 Token 一个 Token 往后读。
读到“虎皮鹦鹉”的时候,已经训练好的输入门会自动计算:
这部分新信息应该写入多少。
接下来继续读后面的内容。
每走一步,遗忘门都会重新决定:
之前的信息哪些继续保留,哪些逐渐淡化。
一直读到:
他依然记得小时候养过的那只……
输出门再决定:
长期状态中的哪些内容,现在应该拿出来参与预测。
之前一路保留下来的“虎皮鹦鹉”相关信息,就会影响当前隐藏状态。
最后再根据隐藏状态计算下一个 Token 的概率。
于是:
“虎皮鹦鹉”的概率就可能变得非常高。
我们刚才做的这套改造,本质上就是:
给 RNN 增加一条长期记忆通道;
然后再让模型自己学习,什么时候该记,什么时候该忘,什么时候该拿出来用。
而这个改造后的 RNN,就是非常经典的:
LSTM,Long Short-Term Memory,长短期记忆网络。
那个长期记忆通道就是LSTM中的 Cell State,细胞状态。
在很长一段时间里,LSTM 都是自然语言处理中的主力模型。
机器翻译、语音识别、文本生成,都大量使用过它。
七、引出Transformer
不过,LSTM 依然有一个重要的问题没有解决。
它必须按照顺序计算。
模型需要先读完“轩辕”,得到隐藏状态以后,才能处理“养了”。
处理完“养了”,才能继续处理“一只”。
前一个 Token 没有计算完成,后一个 Token 就无法开始。
这意味着,一句话中的大量 Token 很难同时进行计算,训练效率提不起来。
当训练数据越来越多,模型越来越大时,LSTM 的顺序计算就会成为一个明显的瓶颈。
除此之外,两个距离很远的 Token 之间,仍然需要经过很长的路径传递信息。
在刚才的故事中,最后的“那只”和最前面的“虎皮鹦鹉”存在直接关系。
但在 LSTM 中,它们之间的信息依然要经过中间所有 Token,一步一步传递。
能不能让最后的“那只”,直接去查看前面的“虎皮鹦鹉”?
能不能让一句话中的每个 Token,都直接寻找和自己最相关的其他 Token?
能不能在理解句子时,同时处理所有 Token,不再沿着一条固定的链条依次等待?
有的兄弟,有的,这就是Transformer,也是当今大语言模型的基础架构。
不过今天的内容已经有点多了,下一期视频我们就来深入理解一下Transformer又是如何运转的。
现在,让我们简单回顾一下今天这期视频中自然语言处理技术的演进过程:
最开始,N-gram 通过统计词语组合,预测下一个词。
但它主要依赖已经统计出来的词语组合,很难理解词语之间的语义关系,对新句子的泛化能力也比较有限。
词向量把词语变成了高维语义空间中的坐标,让模型能够表示鹦鹉和虎皮鹦鹉之间的相似关系。
前馈神经网络进一步利用这些词向量,学习更加复杂的语言规律,也获得了更强的泛化能力。
但前馈神经网络和 N-gram 一样,只能查看固定长度的上下文。
超出输入窗口的信息,对模型来说就像从来没有出现过。
RNN 增加了隐藏状态。
隐藏状态本质上是一组不断更新的向量,用来压缩表示模型到目前为止读过的内容。
它让模型可以按照顺序读取任意长度的句子,并把前面的信息持续传递到后面。
但普通 RNN 很难稳定保存长期信息。
LSTM 又增加了细胞状态和门控机制,让模型可以有选择地保存、删除和读取记忆。
可它仍然无法摆脱顺序计算,很难进行大规模并行计算。
下一期,我们就从这个问题继续向下推导。
一句话中的每个 Token,究竟怎样直接寻找和自己相关的信息?
注意力机制中的 Q、K和 V到底是什么?
没有 RNN 和 LSTM 以后,模型又是怎么知道 Token 的先后顺序?
我们将从注意力机制开始,一步一步搭建出完整的 Transformer。
OK,以上就是今天的全部内容了,内容创作不易,如果觉得有用,别忘了关注支持一波。





