机器如何“读懂”语言
“大模型本质上是在玩一个高级的‘文字接龙’概率游戏。” 这个比喻精准地抓住了模型生成文本的核心机制。
让我们听起来感觉,也不是很难啊!
那么这个看似简单的“接龙”游戏,为何直到今天才爆发出如此巨大的能量?
其关键,在于模型如何计算那个“最可能”的概率。
最初的方法,我们叫他统计语言模型,是计算条件概率:
我们用大量文本,暴力地统计“A”词后面出现“B”词的频率,基于此做概率预测。
然而这种纯粹基于频率的统计方法,其天花板显而易见,只能处理词语搭配的表层规律,无法真正理解语言的含义。
于是,我们在想,在计算概率之前,我们必须先让机器“认识”词。 机器的世界里没有文字,只有数字。
因此,我们的第一步,就是必须为人类语言中的每一个词,创造一个独一无二的、机器能够理解的数字身份。这场“编码”之旅,就此开始。
为“词汇”注入“意义”
朴素尝试:独热编码
我们有非常多的词,怎么用数字表示每个词,同时还能看出与其他词的区别?
“独热编码”的想法是,用一个长长的向量表示,其向量长度即词表长度。
比如中文有7万词,向量就有7万个位置,先全部填上0。每个词都对应其中一个位置。
比如,“苹果”,我们可以定义它的向量在第50个位置为1,其余全是0。
独热编码示例
-
词典 : {"我": 0, "爱": 1, "北京": 2, "天安门": 3}
-
向量维度: 4
-
"我" ->
[1, 0, 0, 0] -
"爱" ->
[0, 1, 0, 0] -
"北京" ->
[0, 0, 1, 0] -
"天安门" ->
[0, 0, 0, 1]
独热编码图片示例
图:独热编码 图片来源:blog.csdn.net/weixin_4566…
好,这样确实,是能表示出所有的词。 但有俩个致命缺陷
- 维度灾难:这也太臃肿了吧?向量不仅维度巨大,而且极其稀疏(几乎所有空间都被0占绝),造成了极大的存储和计算浪费。
- 语义鸿沟:词与词之前没有任何关联!如果采用余弦相似度计算向量间的相似度,可以明显的发现任意两者向量的相似度结果都为 0,即任意二者都不相关。所以在机器眼里,“苹果”和“香蕉”之间的关系,与“苹果”和“飞船”之间的关系,没有任何区别
语义革命:稠密向量
我们需要一种全新的表示方法。它不再是高维、稀疏、非0即1的,而是低维、稠密的。
这意味着向量的每一维度都是一个有意义的实数,比如用一个512维的向量来表示一个词,这512个位置上,都有数字。
这种向量我们叫稠密向量。
这种将词语从高维稀疏空间(就是我们之前所说的onehot向量)到低维稠密空间的技术,就是大名鼎鼎的“词嵌入” ,word embedding, 如果你了解过transformer,一定有所耳闻。
所以这个概念,并不仅仅是transformer拥有的,而是所有产出稠密向量的模型拥有的。
模型所产出的稠密向量,我们通常也直接称为“词嵌入”或“词向量”
它的核心思想,源于语言学的一句名言:“一个词的意义,由它周围的词来定义”。我们不再孤立地看待一个词,而是通过它的上下文来学习它的语义。
本节,我们就将讨论如何对词进行词嵌入,即将独热编码变成稠密向量。
Word2Vec
Word2Vec是产出稠密向量的鼻祖模型。
Word2Vec并非直接去“定义”每个词的向量,而是设计了一个巧妙的“借口任务”来“逼迫”模型学出我们想要的东西。
我们定义一下输入,在word2vec前,词向量单词只是“独热向量”。
假设,我们有vocab_size 个词, 即每个词形状是[vocab_size] ;
用独热向量的话,整个词表的形状就为[vocab_size,vocab_size];
而我们想要的输出是,“稠密向量”,想让每个词的形状为 [embedding_dim]。比如说, 我们可以把这个维度设为512等。(这比上面举的vocab_size是7万的例子,好多了)
那我们训练出的矩阵长啥样呢?
其维度是[vocab_size, embedding_dim];
embedding_dim远小于vocab_size。
我们怎么达成目的呢?
Word2Vec分为两个模型,去产生这些向量。
- 完型填空,让模型基于上下文猜中间的词汇
- 看词猜伙伴,让模型基于中间词猜它周围的上下文
CBOW
“完形填空”。 模型看到上下文(例如 “今天天气__”),任务是预测中间的那个词(“很好”)。
具体做法是,先传入多个词,每个词都是1×vocab_size 的维度,使vocab_size×embedding_dim矩阵与他们分别相乘,这样有很多个1×embedding_dim向量。
然后我们相加或取平均,聚合这些除了中间词的向量,最终变成一个向量!
这个向量,就代表了中间词的上下文的含义。
接着去和矩阵embedding_dim×vocab_size 做矩阵乘法
变回一个1×vocab_size向量。
这一步可以理解为,基于聚合向量维度蕴含的信息,反过来查词表,查出中间位置对应的词。
即“今天天气”本来是两个词,我们聚合成一个词,然后聚合的词看作“中间词“,如果聚合的词就表示”很好“的话,我们预测就理想了。
这个1×vocab_size向量有vocab_size个位置,在每个位置上的数我们使用softmax映射为概率,其可以看作那个位置上的词的概率。
我们要让中心词,”很好”,概率最高 。
抱着这个目的 ”反向传播、梯度下降”,调整vocab_size×embedding_dim矩阵, 逼迫模型理解词,对每个词得到恰当的vocab_size。
skip-gram
“看词猜伙伴”。 模型看到一个中心词(“天气”),任务是预测它周围可能出现的上下文词(“今天”、“很好”)。
具体做法是,传入一个词,“天气” 1×vocab_size维度, 我们使用vocab_size×embedding_dim矩阵进行矩阵乘法,得到1×embedding_dim的词向量。
接着,我们借助embedding_dim×vocab_size的权重矩阵,仍然是矩阵乘法,得到1×vocab_size的词向量 。
我们根据这个向量使用softmax,要让真实的上下文所在位置概率大,可能有多个位置(今天、很好,有俩个位置) 他们都需要是高概率的。
基于这个任务,通过反向传播调整vocab_size×embedding_dim矩阵 , 逼迫模型理解词,对每个词得到恰当的vocab_size
我们的核心都是那个初始的vocab_size×embedding_dim的矩阵
当模型为了完成预测任务而不断优化这个矩阵时,这个矩阵本身就成了一个副产品——一个蕴含了丰富语义信息的词向量库
这个矩阵,就蕴含着”词向量“的信息!
每一行,都是一个词的词向量
那些经常在相似上下文中出现的词(如“国王”和“女王”),为了让模型的预测更准确,它们的词向量在空间中被自然而然地“推”到了一起。
图:Word2Vec实现 图片来源:《百面大模型》
值得注意的一点是,我们训练出来的是静态词嵌入。
初始的独热向量算作一个词表的话, word2vec算出来的,也算一个词表。
词表都是静态的! 训练好就不变了。
那现在,模型能理解句子了吗?
我们把我们训练好的词表,这个词向量, 拼在一起,不就是句子的向量吗?
答案是:还远远不够。静态的词嵌入解决了“词”的问题,却留下了“句子”的挑战:
- 一词多义:不同的句子,有一词多义的问题。"苹果手机"和”好吃的苹果“,俩个苹果的向量,是一样的。但我们知道他们含义并不一样
- 语序的丢失: “我打你”和“你打我”,仅仅是词向量的简单集合,完全无法区分其天差地别的含义。模型还没有“时序”的概念。
如何让模型像人类一样,顺序地阅读,并结合上下文来理解一个词在句子中真正的、动态的含义呢?这正是我们要探索的下一个里程碑——循环神经网络(RNN)
处理“序列”的首次尝试 - 循环神经网络(RNN)
RNN模型,正解决了word2Vec出现的两个问题
首先,先讲清楚RNN的工作机制
模型的有很多layer,每层layer,接受的是当前时间步的输入x,和上一层layer残留的信息, 这个信息是上一个时间步x,经过上一层layer的隐藏层转换后,得到的信息。
所以核心是利用隐藏层理解信息, 利用“层层传入”的动作传递信息。
图:RNN机制 图片来源:https://www.geeksforgeeks.org/machine-learning/introduction-to-recurrent-neural-network/
那这个RNN是怎么用的?用来训练词向量吗?
并不是,我们是在之前word2vec训练的静态词向量的基础上,使用RNN进行强化的。
这点很重要,对于得到词向量,RNN不是Word2Vec的代替!而是在其基础上的强化!
回顾我们的工作机制,现在我们套用句子,进行举例
解决语序
“我打你”
其中“我”为第一个x, 经过隐藏层一(后面缩略为h),将模型对“我”的理解传入第二个layer, 第二个layer传入的x是“打”,此时,模型基于h1,即“我”的理解,去理解“打”,然后经过h2,就是
模型理解的”打“,但是包含”我“的信息。
那么最后一个,输出的”你“的向量,同理,包含着”我“和”打“的信息。
我们可以看到,处理信息的过程是从左往右依次处理,最后一个词能接受到的信息最多。
那么不同的语序,”你打我“传入进去,得到的词向量就天差地别。
”你打我“中的”你“,
没有任何前文信息,只有模型纯粹的对”你“的理解,而刚才”我打你“中的”你“,是包含”我打“的信息的。
解决多义
同理,”吃苹果“ 和”买苹果手机“。
这俩个”苹果“也因前文不同而输出的向量不同。
这就解决了不同句子相同词,词义不同的问题。
当然,这又引发出一个问题 ,目前rnn只是看前文啊,那”苹果派“和”苹果手机“,这俩个词的“苹果”的向量,输出的应该是一样的?
所以真正解决多义,还需要双向的隐藏层信息。
双向RNN
人类是如何理解“苹果派”里的“苹果”是食物的?
因为我们的眼睛不仅看到了“苹果”,还向后扫了一眼,看到了“派”。我们的理解是基于完整的、双向的上下文。
标准RNN,我们称之为单向RNN ,它的视野是受限的,就像一个只能用余光看左边,却永远不能回头或向右看的人。
为了解决这个“只能看前文”的致命缺陷,科学家们提出了一个非常直观且优雅的改进方案:**双向循环神经网络。
它的思想极其简单:既然一个从左到右的RNN不够,那我们再加一个从右到左的RNN不就行了?
当要计算句子中任何一个词(比如“苹果”)的最终表示时,模型会做一个简单的动作:将这个词在正向RNN中的隐藏状态和在反向RNN中的隐藏状态拼接在一起。
通过拼接前后文信息,双向RNN极大地提升了模型在局部上下文中理解多义词的能力。
可以说,对于“苹果派”这类短语级别的多义性问题,它给出了一个近乎完美的答案。但是,如果决定一个词义的关键信息,出现在距离它非常遥远的地方呢?
这引出了RNN一个更深层次的困境。
图:双向RNN 图片来源: [Denny’s Blog](https://dennybritz.com/) https://dennybritz.com/posts/wildml/recurrent-neural-networks-tutorial-part-1/
RNN的问题
如果句子很长的话,第一层h1的信息,在一次次传播中,可能早都丢失了...
具体解释一下, 每一层,接收到的来自前文的信息,只有一个隐藏层,就是上一个layer的隐藏层。
只是说上一个layer的隐藏层还有上上一层的信息,然后上上一层的隐藏层有上上上...
这就像一个“方言传话”游戏:每个人听上一个人的话,然后用自己家的方言传给下一个人。人越多,第一个人的话可能传到最后一个人不知道剩什么了。
翻译到RNN架构里,就是信息每经过一个时间步的处理(一个人的转述),都会不可避免地发生损耗和变形。当句子足够长(游戏队列足够长),传到末尾的信息可能早已面目全非。
这种现象在学术上被称为梯度消失。
造成这个现象的原因, 就是第一层的信息,只是隐含地在h里面, 而不是显性传递。 总而言之,引出的RNN问题就是,长序列信息的丢失。
LSTM
为了对抗这种记忆衰减,天才的设计LSTM(长短期记忆网络)诞生了。
它不是靠上层隐藏层输入传递前文信息,而是将前文信息当作知识, 始终挂载在传递信息的过程中,不被隐藏层处理。
可以这样想象,这个知识就放在传送带上,会被每一个流水线的工人(即每一层layer)看到,处理。
工人会使用三个门控机制选择对知识的增、删,以及选择该从当前的知识库里读取什么信息。
图: LSTM 图片来源: colah's blog https://colah.github.io/posts/2015-08-Understanding-LSTMs/
但只是缓解了梯度消失的问题 RNN和LSTM仍然没解决的问题是:
- 句子很长时,长序列信息的丢失(只不过LSTM比RNN稍微好一丢丢)
- 处理时一个一个处理,虽然其处理序列的时间复杂度为线性的O(n),这在算法上是高效的,但其无法并行化的本质。gpu的每个格子都能计算,而串行处理,只能让一个格子工作,其他格子干等着,极大浪费了资源。
曙光初现 - 注意力机制(Attention)的诞生
至此,我们看到了一幅清晰的图景:从RNN到双向RNN,再到LSTM,研究者们用惊人的才智,将“循环记忆”这条路走到了极致。
然而,两条沉重的枷锁依然牢牢地束缚着序列模型的发展:
-
记忆的枷锁:无论门控机制多么精妙,依靠单一“记忆通道”来传递长距离依赖,终究是一个摇摇欲坠的方案。仍然存在着记忆不精准,以及长序列记忆丢失的问题。
-
效率的枷锁:固有的串行计算模式,使其在并行计算的时代,如同“单核CPU”面对“超级计算机”,速度成了无法逾越的鸿沟。
整个领域都在期待一场范式革命。人们不禁开始思考一个颠覆性的问题:
我们真的需要“循环”吗?有没有一种方法,可以彻底抛弃这种“一个接一个”的处理方式,让模型在计算任何一个词时,都能“一眼”就看到全局,直接、并行地捕捉任意两个词之间的依赖关系?
这石破天惊的一问,正是Attention机制将要给出的答案。 它,将是下一篇文章的主角。
理论的理解,只有在实践中才能得到最终的升华。
为了让您能亲手触摸到我们文中所探讨的每一个概念——从“词向量的语序灾难”,到RNN如何力挽狂澜,再到亲手打开RNN的“黑箱”——我为您准备了一份配套的、逐行注释的Jupyter Notebook。
您将在15分钟内,亲眼见证问题的发生、奇迹的出现、以及魔法的揭秘。
所有代码和未来的更新,都已在我的开源项目【LLM基础锻造厂】中发布。欢迎您Star、Fork,并与我们一同踏上这段激动人心的锻造之旅。