目录

1.LLM简介

2.结构鸟瞰

3.Transformer

3.1. 词嵌入(Word Embedding)

3.2. 循环神经网络(Recurrent Neural Networks,RNN)

3.3. 可视化神经机器翻译模型(Visualizing A Neural Machine Translation Model)

3.4. 注意力(Attention)

3.5. 自注意力(Self-Attention)

3.6. 多头自注意力机制(Many Heads Self-Attention )

3.7. 残差(Residual)

3.8. 小结

4.Only Decoder Transformer

4.1. 掩码自注意力机制(Masked Self-Attention)

4.2. 注意力头(Attention Heads)

4.3. 分词(Tokenization)

4.4. 词元嵌入和位置嵌入(Token Embedding & Position Embedding)

4.5. LLM基本成型


1.LLM简介

        LLM(Large Language Model)大型语言模型LLM)是一种利用自监督机器学习方法,基于海量文本训练而成的语言模型,专为自然语言处理任务而设计,尤其适用于语言生成

         更多介绍参考维基百科:https://en.wikipedia.org/wiki/Large_language_model

2.结构鸟瞰

        以主流 decoder-only Transformer(GPT/LLaMA/Qwen 系)为例,最核心的结构可以抽象成:

Text → Tokenizer → token ids → Embedding(+Pos) → N×Transformer Block → logits → sampling → next token

Transformer Block 通常是两大子层(外加残差与归一化):

  • Self-Attention 子层:把序列中任意位置的信息按“相关性”混合,形成上下文表示(contextual representation)。

  • MLP/FFN 子层:对每个位置的表示做非线性变换(现代实现多用 SwiGLU/GeLU 等变体,属于工程细节可后看)。

3.Transformer

参考内容:https://jalammar.github.io/illustrated-transformer/?utm_source=chatgpt.com

3.1. 词嵌入(Word Embedding)

参考内容:

https://medium.com/deeper-learning/glossary-of-deep-learning-word-embedding-f90c3cec34ca

        简而言之,神经网络是不认识单词和字符的,计算机只认识数字。词嵌入就是把单词转换成数字(向量),并且在空间中相关的单词距离会更近。

       经典word2vec(单词to向量)嵌入算法

       神经网络一般划分为:输入层隐藏层、和输出层。假设我们有10000个单词和300个神经元,对于每一个单词,都会在所有的神经元中进行传递,因此需要所有神经元的参数集合来确定一个单词,简称分类

        而对于所有单词的神经元参数表示之和,我们称之为嵌入矩阵,则在本场景中嵌入矩阵的规模就是10000×300。当我们想要直到某个单词在计算机中的表示(编码)是什么的时候,我们只需要查询嵌入矩阵表即可。

3.2. 循环神经网络(Recurrent Neural Networks,RNN)

        通俗来讲,RNN(循环神经网络)就是一个“读一句话的翻译员”,每读一个词就更新一次脑内记忆。这份记忆(状态)会带到下一步继续用。

输入:

内部记忆:状态

递推更新:

对于RNN的本身,可以做一个解释就是“我读到第 t 个词时,对前面内容的总结”。

图片来源于:https://www.geeksforgeeks.org/nlp/stacked-rnns-in-nlp/

状态叠加:

  • 旧记忆(
  • 新输入(
  • 更新函数

所以所谓“叠加”,就是每一步把当前输入写入一个固定大小的记忆槽 。这非常像 SSM(状态空间模型,State Space Model):一个状态不断被输入驱动演化。

SSM参考:https://blog.csdn.net/m0_62102955/article/details/152311142?spm=1001.2014.3001.5501

3.3. 可视化神经机器翻译模型(Visualizing A Neural Machine Translation Model)

参考内容:https://jalammar.github.io/visualizing-neural-machine-translation-mechanics-of-seq2seq-models-with-attention/

        可视化神经机器翻译模型,也是基于注意力机制的序列到序列模型(seq2seq)。序列到序列模型是一种接收一系列项目(单词、字母、图像特征等)并输出另一系列项目的模型。

        在神经机器翻译中,序列(seq) 是指一系列单词,它们被逐一处理。同样,输出结果也是一系列单词。

        context(上下文)本质上是一个向量,编码器和解码器都是循环神经网络(RNN)

为什么word2vec是单词变向量,而seq2seq一句话就是一个向量?

经典 RNN/LSTM/GRU 编码器的递推形式是:

所以“上下文只有一个向量”是因为:编码器只把最终隐状态 暴露给解码器。它是一个固定维度向量(比如 512 或 1024 维),无论输入句子多长都一样大。

并且严格来说:不能保证context精准包含所有的词,因此会出现信息瓶颈(information bottleneck)。

另外,两者解决的问题不同,学习目标也不同。

word2vec:学习分布式语义,进行词级别的表示粒度。

seq2seq:把输入序列映射到输出序列,进行句子级编码。

因为句子级别表示确实存在瓶颈,于是出现了Attention和后来的Transformer

3.4. 注意力(Attention)

如果说Seq2seq模型(RNN)是只给解码器最终状态:

那么注意力机制就是让编码器输出整条状态序列:

解码器不再只能读最后的状态,而是能按需读取整条状态轨迹,因此显著缓解长序列丢信息的问题。这里指的是所有解码器都能获得全部编码状态

        其次,注意力解码器在输出之前会进行一个额外的步骤,为了专注于当前解码时间步相关的输入部分,解码器会执行以下操作:

  1. 观察它接收到的编码器隐藏状态集合 ——每个编码器隐藏状态 都与输入句子中的某个特定词关联最为密切。
  2. 给每个隐藏状态打分(暂时忽略评分方式)。
  3. 将每个隐藏状态乘以其softmax得分,从而放大得分高的隐藏状态 ,并掩盖得分低的隐藏状态。

        时间步:解码器在生成第t个输出词时的时刻。

        softmax:常用的激活函数,用于拉大数值的区分度。

现在让我们将所有内容整合到下面的可视化图中,看看注意力过程是如何运作的:

Encoding Stage:

假设编码器逐个读词,产生向量(共三个单词累计的向量)

不是“那个词本身”,而是“这个位置的词 + 它在上下文里的含义”的一个向量笔记

所有都会被保存下来,作为解码器随时可查的向量集合。

Attention Decoding Stage:

图中展示了两个解码时间步,分别生成了“I”和“am”。

解码器每一步生成一个词,通常会用到两类信息:

1. 当前状态

2. 上下文

Step 4: 生成“I”

1. 解码器此时有初始状态

  •         这个状态来源于编码器最后的整体信息。

2. 做一件事:给源句每个位置打分(weight,权重)

  •         比如对于分别给权重
  •         图中虚线框中条形块表示“关注强弱”

3. 用这些权重把源句笔记做加权求和,得到

4. 解码器把自己状态信息+源句上下文综合起来,输出下一个词“I”,并更新出新的解码状态

Step 5: 生成“am”

同理:

1. 得到

2. 再次对打权重(和上一个step打分没关系)

3. 得到上下文

4. +可以得出“am”,更新状态为

关键点:

  • 每一步 attention 都可以“重新照源句”,并且照的位置可以变。

  • 所以翻译时能实现类似对齐:生成 “I” 可能主要看源句主语相关位置;生成 “am” 可能主要看谓语相关位置。

当解码器很靠后的时候,会不会“越到后面就少看一些”?

不会。注意力机制下:

  • 编码器输出的整本记事本一直都在,解码任何一步都能访问全部。

  • 解码器在不同步、不同词上,只是“聚光灯权重”不同,而不是把记事本撕掉一页。

另外还要注意一点:

        因为不同语言所包含的信息不同,或许会出现某种语言的一个词,对应另一种语言的多个词,所以一定要看完整的上下文,才能完成精准翻译,也是其精华所在。

3.5. 自注意力(Self-Attention)

The animal didn't cross the street because it was too tired
这只动物没有过马路,因为它太累了。

        这句话中的“它”指的是什么?是指街道还是动物?对人类来说,这是个简单的问题,但对算法来说却并非如此。当模型处理单词“它”时,自注意力机制使其能够将“它”与“动物”联系起来。

        当模型处理每个单词(输入序列中的每个位置)时,自注意力机制使其能够查看输入序列中的其他位置,寻找有助于更好地编码该单词的线索。

第一步:创建向量

        根据编码器的每个输入向量(在本例中为每个词的词嵌入)创建三个向量。对于每个词,我们创建一个查询向量(Query)一个键向量(Key)一个值向量(Value)。这些向量是通过将词嵌入乘以我们在训练过程中训练的三个矩阵而得到的。

        请注意,这些新向量的维度比嵌入向量小。它们的维度为 64,而嵌入向量和编码器输入/输出向量的维度为 512。它们并非必须更小,也并非一定是512和64,这仅仅是一种常见的工程架构选择,目的是使多头注意力机制的计算量(基本)保持恒定。

第二步:计算得分

        假设我们要计算本例中第一个词“Thinking”的自注意力。我们需要将输入句子中的每个词与这个词进行比较并给出得分。这个得分决定了在编码特定位置的词时,应该给予输入句子的其他部分多少关注。

        得分计算方式为:

        设我们要进行查询的单词对应向量为

        则对于任意单词(包括它自己),评分为:

        这里运算是点乘运算

第三步和第四步:归一化

这一步仅仅一个公式:

或者:

        当且仅当时二者相等。所以 div8 其实就是在这个常见配置下的“写死版本”。这么做的核心原因:防止 softmax 饱和,让梯度更稳定。如果点乘结果太大,softmax的输入会出现极端值,导致其几乎无效。

        将结果输入到 softmax 操作中。softmax 操作会将分数归一化,使它们全部为正且总和为1。

        这里我们还要强调一下softmax为什么能做到归一化:对一组

       也就是说,无论输入正负,通过softmax都能变成整数且所有元素之和为1。 

第五步和第六步:计算V向量和Z向量

        将每个值向量乘以softmax得分为将它们相加做准备)。这里的目的是保持我们想要关注的词的值不变,并消除无关词的影响(例如,通过将它们乘以0.001这样的小数)。

        将加权值向量相加。这就产生了该位置(第一个词)自注意力层的输出。

        至此,自注意力机制的计算就完成了。我们可以将得到的向量传递给前馈神经网络。

为了方便理解,我们做两种形象化的比喻:

1. 直观来讲

q向量代表:x向量表示的是什么意思/需要什么信息。

k向量代表:x的关键词(用来快速检索x)。

v向量代表:x可以被引用的内容。

        最后输出 (注意力输出)就是:位置这一段改写后的内容 = 我根据自己的需求,从全局所有笔记里挑选(加权汇总)出来的引用内容。

2.上下文补全

在 Transformer 里,每个位置的表示要回答一个问题:

“这个 token 在当前上下文里到底是什么意思?”

        举例:英文里 “bank” 在不同上下文含义不同。仅靠词向量 xix_ixi​ 很难确定。注意力层让它做一件事:

  • 去看上下文里哪些词能帮我消除歧义(river、money、loan…)

  • 把这些相关位置的语义()按相关性混合进来

 因此就是:     

  “的上下文化表示(contextualized representation)”

它是经过注意力层“阅读上下文后”的版本,所以天然被当作该层的输出。

另外真正的自注意力在计算时,为了加速是以矩阵形式进行的:

3.6. 多头自注意力机制(Many Heads Self-Attention )

        一个嵌入向量矩阵,对应一组K,Q,V,就是自注意力机制。

        那么,一个嵌入向量矩阵,对应多组K,Q,V,就是多头自注意力机制。

        这里我们强调:一般是随机初始化,经过训练后也基本不会相同。

        如果我们重复上述自注意力计算,每次使用不同的权重矩阵,重复八次,最终会得到八个不同的 Z 矩阵。这就给我们带来了一些挑战。前馈层并不期望接收到八个矩阵,它期望的是一个矩阵(每个词对应一个向量)。因此,我们需要一种方法将这八个矩阵合并成一个矩阵。

        我们该如何实现呢?我们将矩阵连接起来,然后乘以一个额外的权重矩阵

3.7. 残差(Residual)

        需要提及编码器架构中的一个细节,即每个编码器中的每个子层(自注意力、ffnn)周围都有一个残差连接,并且之后会进行层归一化步骤。

        图中每个子层(Self-Attention、Feed Forward)后面都有 Add & Normalize

  •         Add:做残差相加
  •         Normalize:做 LayerNorm(让数值稳定)

典型公式:

这里:

  •  :进入自注意力子层之前,每个 token 的向量表示。
  • : 自注意力计算出来的“上下文混合信息”。
  • :残差相加(Add)。
  • : 归一化稳定训练(Normalize)。

        简单比喻一下:

  • 自注意力:给每个词查资料、做引用摘要

  • 残差:把“原句”保留,然后把“引用摘要”贴在旁边当补充

  • LayerNorm:整理排版,避免数值发散

3.8. 小结

        本章节主要以NMT(机器翻译)的视角对Transformer的基本技术做了一个串接,而Transformer是LLM的重要组成部分,对于它的学习我们值得付出一定的时间。通过对Jay Alammar、Jaron Collis的文章进行了翻译理解和拓展,我们对Transformer应该有了一个初步的认识。

        但是这知识开始,我们学到的”教科书”级别的Transformer并非LLM中的Decoder-only Transformer,因此我们还需要做一个过渡,再深入探索。

4.Only Decoder Transformer

参考内容:https://cameronrwolfe.substack.com/p/decoder-only-transformers-the-workhorse

4.1. 掩码自注意力机制(Masked Self-Attention)

        仅解码器(Decoder-only)Transformer使用一种称为掩码(或因果)自注意力机制的自注意力变体。正如第3章所说,普通的注意力机制允许在计算注意力分数时考虑序列中的所有标记,但掩码自注意力机制通过“屏蔽”序列中给定标记之后的标记来修改底层注意力模式。

        通俗点说,当对第个词的嵌入向量做掩码注意力时,在该词后面出现的词()的对应的位置会被直接遮住,使这些位置在 softmax 后的权重变成 0,于是后面词的 K/V 信息不会被当前词拿来用,也就不会影响当前词的输出表示。

        如图,矩阵的第一行代表矩阵的第一列代表。则在注意力得分矩阵中第一行除了的位置全部是被屏蔽的。

        这个屏蔽的具体方法就是在对该矩阵的每一行执行softmax操作之前,我们可以将注意力矩阵对角线以上的元素值全部设置为负无穷大,这样它们的注意力得分均为零。

4.2. 注意力头(Attention Heads)

        我们目前描述的注意力操作使用 softmax 函数对序列中计算出的注意力分数进行归一化。虽然这种方法可以形成有效的概率分布,但也限制了自注意力机制关注序列中多个位置的能力——概率分布很容易被一个词或者几个词所主导

        可以用一个直观例子理解:在归一化前,我们得到一组得分,计算得出后两个的占比几乎为0,这就会让主导。

        直观上来讲,单个注意力是在捕捉关系。多头注意力是为了并行捕捉多种关系,覆盖更多位置,学习稳定的模式。

对于注意力头的相关参数,可表示如下:

存在token的维度为,注意力头数量为,通常取:

就是我们在自注意力机制中介绍的K,Q,V向量的大小。

对于token的维度,我们不能只停留在自注意力词嵌入事实上,token的生成,是LLM中相当重要的阶段之一,我们会在下面继续讲。

4.3. 分词(Tokenization)

        Transformer接收原始文本作为输入。处理文本的第一步是将其分词,即将其转换为一系列离散的词或子词。这些词和子词通常被称为词元(token)。

        这里每个蓝色小方块就是一个 token。注意:token 不一定等于一个完整的英文单词,它可能是:

  • 一个完整词(如 arecool

  • 一个词的一部分(子词),例如LLMs被拆开(图里#s表示“s 这个后缀片段”)

        子词(subword)是一种策略,为了防止此表爆炸和未知词的出现:

  • 世界上新词、拼写变体、专有名词太多,词表会变得极大,训练与部署成本很高。
  • 模型会频繁遇到没见过的词。如果按词切分,这些词无法编码,而子词可以把它拆成更小的已知片段,仍能表达。

        所以现代 LLM 普遍采用 BPE / SentencePiece / WordPiece 这类子词算法:把高频的字符片段合并成 token,让“常见词尽量是一个 token、不常见词可以拆成多个 token”。

        另外,Tokenization的输出不是字符,而是词/子词在词表中的ID

["LLM", "s", "are", "cool", "."]
--------------------------------
[19342, 29, 389, 1234, 13]

        随后模型才会做下一步:把 token ids 查表变成向量(Embedding),进入 Transformer 计算。

        Token的维度其实是指embedding后的维度,Token本身其实是被拆分的句子,是词/子词。

4.4. 词元嵌入和位置嵌入(Token Embedding & Position Embedding)

        还是拿这个举例子,截止到Tokenization,模型到手只有一串数,下一步就是如何把数变成向量。

Token Embedding:

["LLM", "s", "are", "cool", "."]
--------------------------------
[19342, 29, 389, 1234, 13]

模型有一张可学习的Embeding表(向量词典):

规模为:

其中:

  •         是词表的大小(例如 30k、50k、150k…)
  •          是模型隐藏维度(例如 512、768、4096…)

对每个 id 做一次查表:

        id=19342 ——> 向量

        id=29 ——> 向量

        ...

        id=13 ——>向量

把它们堆叠起来,就得到一个矩阵:

token embedding 只表达“这是什么 token”,但还没表达“它在第几个位置”。

Position Embedding:

        自注意力(self-attention)有一个关键性质:它本身不关心顺序。如果你把一堆 token 向量打乱顺序丢进去,注意力层从数学结构上并不会自动知道“谁在前谁在后”。

        位置嵌入/位置编码的目的,是把“顺序”注入模型。

        经典做法是:绝对位置向量相加

        生成每个Token的位置向量

        对于最终输入的内容:

        也就是:嵌入向量+位置向量。

        最终的

      到这里,Token的含义和处理就告一段落了,我们会把处理出来的嵌入向量输入给4.1. 中描述的掩码自注意力网络(Causal Mask,因果遮罩)。在其内部,Position embedding:告诉模型“顺序是什么”,Causal mask:规定信息流“只能从左到右”,即第个位置只能看的内容。

4.5. LLM基本成型

在上文相关知识的学习下,LLM我们基本有眉目了:

1.语句输入,划分为Token(词,子词),对Token进行Embedding,并加入位置Embedding信息

2.输入进堆叠的Decoder,先做归一化稳定数值,然后输入到掩码注意力学习上下文关联

3.做归一化稳定数值,进入前馈神经网络,FFN (前馈神经网络,Forward Feed Networks)的输出同样通过残差加回,并再做归一化。

4.每经过一层,表示都会再次经历“掩码自注意力的上下文检索 + FFN 的局部重组”。

5.通过所有 decoder blocks 之后,我们拿到最终的输出 token 向量(每个位置一个 维向量)。模型再把这些向量通过一个线性映射投影到词表大小,得到每个位置对“下一 token”的打分(logits)。

6.如果是在训练阶段,会对每个位置的 logits 与真实的下一个 token 计算交叉熵损失,从而并行学习“下一 token 预测”;如果是在推理生成阶段,通常只取最后一个位置的 logits,对其做 softmax 得到概率分布,然后用 greedy 或 temperature/top-p/top-k 等策略采样出下一个 token id。

7.最后,把新采样得到的 token id 追加到原序列末尾,重复同样的过程:再次得到新的输出 logits、再采样下一个 token,如此迭代,直到生成 EOS 或达到长度上限。整个过程中,因果掩码保证“当前只能用历史”,而多层 block 负责把“历史信息”逐步加工成能支持下一 token 预测的表征。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐