大模型-Transformer架构(编码器层)

目录

  • AI的发展历史
  • 什么是大模型
  • 大模型的组成
  • 大模型-Transformer架构(编码器层)
  • 大模型-Transformer架构(解码器层)
  • 大模型-参数
  • 其他补充
    ps:由于文章内容较多,超过了简书文字上限,所以将本文分为了**编码器层**和**解码器层**两部分,大模型-参数的说明在解码器层文章中进行说明

AI的发展历史

人工智能(Artificial Intelligence,简称 AI)是一个涵盖广泛技术与应用的核心概念,其本质是通过技术手段让计算机和机器模拟人类的学习、理解、解决问题与决策能力,进而具备自主决策与创新输出能力,核心目标是让计算机和机器能高效处理复杂任务,甚至逼近或超越人类在相关领域的表现。它以海量数据为基础,通过数据分析、模式识别与持续学习的核心逻辑,实现问题解决、决策支持与创新创造。与传统软件程序仅执行预设指令的模式不同,AI 能够基于经验不断学习、适应环境并优化自身性能,从而具备自主完成复杂任务的核心优势。其应用领域极为广泛,已深度覆盖自然语言处理、图像识别、语音识别、逻辑推理、趋势预测等多个关键场景。

AI发展的阶段

人工智能(AI)- 1950-1980 年:这是 AI 的萌芽期,首次明确“机器模拟人类智能”的方向并提出人工智能概念。其核心是基于规则和符号主义,代表性成果是1950年图灵测试提出、1956年达特茅斯会议正式定名“人工智能”,为后续技术发展奠定了思想源头。

机器学习(Machine Learning)- 1980-2010 年:随着互联网的发展普及,网络数据增长加快,AI的实现路径转向以数据驱动统计学习为核心,强调从数据中自动学习规律。代表性技术包括支持向量机(SVM)、决策树、贝叶斯等一系列算法成熟落地,形成了监督学习、无监督学习、强化学习三种核心学习范式,为后续深度学习提供了统计学习基础和核心学习框架。

监督学习无监督学习强化学习是机器学习的三种学习范式,深度学习则是一种技术方法,它们的核心逻辑可以用孩子学习区分水果的例子来理解:

监督学习就像明确告诉孩子 “这是苹果(圆形、红色)、这是香蕉(长条形、黄色)”—— 通过标注好的水果名称和对应特征,让机器直接学习 “特征→类别” 的对应规律,从而学会区分。

无监督学习则不提前说 “这是什么水果”,只给机器一堆水果的原始特征(比如有的圆、有的长,有的红、有的黄),让它自己从这些特征中找规律(比如 “圆的、红的可能是一类,长的、黄的可能是另一类”),自主完成区分。

强化学习更像 “猜谜试错”:不告诉机器任何水果的名称或特征,只预设规则 —— 比如用 1、2、3 代表对不同水果的猜测,猜对就给奖励,猜错则没有。机器每次看到一个水果就选一个数字 “猜”,通过一次次试错记住 “看到这种样子的水果时选哪个数字能拿奖励”,最终学会区分。

深度学习作为一种技术方法,核心是让机器通过深层神经网络,从水果的视觉(形状、颜色)、嗅觉(气味)等多模态原始数据中,自主挖掘和提取关键特征(比如不用人工指定 “圆形是特征”,机器自己能发现 “圆度”“颜色深浅” 等有效区分点),进而实现对水果的区分。

深度学习(Deep Learning)- 2010-2020 年:随着互联网的井喷式发展,在大数据和高性能计算的推动下,深度神经网络实现复兴。通过多层神经网络达成端到端学习(直接从原始数据到最终目标输出的学习模式),在图像识别、自然语言处理等领域取得突破性进展。核心技术支撑包括CNN、RNN、Transformer架构、反向传播算法的规模化应用及GPU高性能计算,代表性成果有Transformer 模型提出,为生成式AI提供“大规模神经网络训练”的核心技术底座。

生成式人工智能(Gen AI)- 2020 年至今:这一阶段是深度学习Transformer架构的延续,是 “规模化” 进阶的体现,核心是将AI从“数据分析与处理”推向“自主生成与创新输出”的新阶段。其特点是超大规模参数、零样本/少样本学习能力及广泛的应用前景,代表性成果包括Deepseek系列、GPT系列模型、LLaMA等开源大语言模型、图像视频生成技术等。

关系图

ps:这里不做CNN和RNN的详细原理说明,后续如果有空会针对2个架构单独写文章说明
CNN(卷积神经网络):核心是卷积操作,通过局部连接、权值共享减少参数,擅长捕捉空间特征。
RNN(循环神经网络):带有时序循环结构,能处理序列数据(如文本、语音),但并行计算能力弱,易梯度消失。


什么是大模型

大模型即是我们俗称的大语言模型(Large Language Model,简称LLM),一般是指基于深度学习(如CNN、RNN、Transformer架构),通过海量数据训练的超大规模神经网络模型,本质是一个统计学模型。具备超大规模参数与强大的模式识别、理解推理能力,属于生成式 AI 的核心代表。它不仅能实现文本、图像等内容的自主生成,还可完成语义理解、逻辑推理、多模态交互等复杂任务,典型如Deepseek系列、Doubao系列、Qwen系列、 GPT 系列、LLaMA等,是当前 AI 技术从 “数据处理” 向 “自主创新输出” 进阶的关键体现,其广泛应用于自然语言处理、知识问答、创意生成等领域。

超大规模(个人定义)

1、参数数量:1000亿级以上(100B以上)
2、海量训练数据:训练数据量≥2万亿tokens,且覆盖多领域、高质量语料,计算需求≥1e24 FLOPs。并支撑参数规模与数据量的协同扩张。
3、上下文限制:≥64K tokens,支持长文本理解与生成
4、架构扩展:保持效率和性能的同时,支持更大的参数规模、模块化插拔、跟多层级深度扩展

ps:RNN因为其循环结构导致存在无法并行计算,深度扩展不稳定,长距离依赖易丢失。CNN因为主要是擅长捕获空间局部特征导致存在长距离依赖低效,参数扩展价值不高。从而导致RNN与CNN难以升级为超大规模,因此本文主要是针对Transformer架构进行说明


大模型的组成

大模型本质是一个统计学模型,由海量的参数架构两部分组成

从训练维度来看,架构是 “学习知识的一套方法论”,而参数则是 “方法论中沉淀的关键规律值”。就像我们初中学的的自由落体公式 v=gt(v 为下落末速度,t 为下落时间),时间t 是可直接用计时器记录的已知条件,而下落速度v则是我们需求的结果。假设我们通过其他方式测出不同时间下的 v 值,就能从 v 与 t 的海量关联数据中提炼内在规律,最终形成 v=gt 这套标准化的方法论。而公式中的 重力加速度g就是这套方法论里的核心参数,它是从海量样本中总结出的固定规律,为后续快速推导未知 v 值提供的关键参数。大模型的训练过程也有异曲同工,大模型的架构搭建了数据学习的逻辑框架,引导模型从海量文本中识别关联、提炼规律。大模型参数则在训练中不断优化的数值,将训练提供的杂乱无序的知识,提炼为固化可调用的“数值化经验”,最终实现“从数据中学会规律”的核心目标。

如果说训练维度是大模型 “学会知识” 的过程,那么推理维度就是其 “运用知识” 的落地场景。

从推理维度来看,架构是 “理解问题、生成答案的工作流程”,参数则是 “流程执行所需要的知识储备”,就像医生问诊的流程“问诊(拆解问题)→ 辨证(匹配知识)→ 开方(组织答案)” 这是一套固化标准工作流程,目的是确保每一步都围绕 “解决需求” 展开,而医生脑中积累的病症判断标准、用药禁忌、诊疗经验等已学知识则是支撑流程落地的实质内容。同理,当用户提出问题时,架构首先启动拆解明确问题核心,随后通过调用训练中沉淀的海量知识规律的参数按逻辑组织语言、筛选精准信息、输出贴合需求的回应。没有架构的流程约束,参数的知识会变成无序堆砌,没有参数的内容支撑,架构的框架只是空洞模板,二者缺一不可,才能实现 “既读懂问题,又给出靠谱答案” 的核心诉求。


大模型-Transformer架构(编码器层)

大模型的架构有很多,最为出名的就是RNN(循环神经网络)、CNN(卷积神经网络)、Transformer,架构的本质是一套高效执行任务的方法流程。本文只讲Transformer架构,因为当下主流的大模型几乎所有都是采用该架构,下图是Transformer的架构图


Transformer架构图

Transformer架构分为编码器层(图中的左边部分)与解码器层(图中的右边部分),编码器层主要是去“理解输入内容”,并输出输入内容的特征矩阵。而解码器层则“生成输出内容”,利用理解的特征矩阵去预测输出的文本内容。在架构执行时是先执行编码层,编码器层执行完成后再执行解码器层,因为解码器层中计算时会用到编码器输出的结果。

编码器层

编码器层的作用是充分的对输入的原始文本进行理解,分析其语义特性,为解码器层生成输出文本提供理解依据。

第一步:输入(Inputs)

输入给大模型的内容本质上是经过预处理的序列数据,而这些序列数据的原始来源一般是文本、音视频、图片等多种模态内容,但需要先通过特定处理转换成 Transformer 能直接处理的 “序列形式”。

对于文本:输入通常是经过分词器拆分为多个token(单词,字),将token根据Transform对应的词汇表映射为ID序列并输入进Transformer。
对于图片:比如 Vision Transformer(ViT)中,图片会被分割成固定大小的 “图像块”(patch),每个块被转换成特征向量,这些向量按空间顺序排列成序列,作为编码器的输入。
对于音频:音频信号先通过短时傅里叶变换等方法提取频谱特征(如梅尔频谱),再将频谱按时间维度切分成帧,每一帧的特征向量组成序列,输入编码器(如 Audio Transformer)。

核心逻辑是:Transformer 的编码器本质上处理的是 “序列”(即有序的向量集合),而文本、音视频、图片等原始数据,只要能被转化为这种 “序列形式”,就可以作为编码器的输入。但不同模态的原始数据特性不同,文本转为映射ID即可,而图片、音视频则需要转为特征向量,本质是 “连续信号的离散化 + 初步向量化”。

这里我们仅针对文本输入进行展开说明

文本内容在提交给Transformer之前的处理顺序
1、将文本内容通过分词器拆分为token

例如在Qwen2.5-72B模型下,文本“今天天气真好” 将会被拆分为4个token,“今天”、“天气”、“”、“

因为Qwen2.5-72B使用的是基于BPE变体的词汇表,词汇表中一般有{"今天", "天气", "真好", "今", "天", "气", "真", "好"}这些字、词。

其分词步骤大概是:

1、预处理(去除多余空格、不可见字符等无关干扰字符,保留核心字符)
输入文本 “今天天气真好” 无需清洗,直接保留连续字符(因为中文无天然空格,直接处理整句)。

2、从左到右,最长子词匹配(核心步骤):

第一步:处理“今天天气真好”的起始部分从第一个字符“今”开始,尝试匹配词汇表中“以‘今’开头的最长子词”:
因为整个句子是6个字符,所以首先尝试长度为 6 的完整句子“今天天气真好”:结果发现词汇表中没有匹配的。
尝试长度为5的“今天天气真”:结果发现词汇表中没有匹配的。
尝试长度为4的“今天天气”:结果发现词汇表中没有匹配的。
尝试长度为3的“今天天”:结果发现词汇表中没有匹配的。
尝试长度为2的“今天”:结果发现词汇表中有匹配的,于是拆分出第一个 token:["今天"],剩余文本为“天气真好”。

第二步:处理剩余文本“天气真好”从“天”开始,尝试最长子词:
尝试长度为4的 “天气真好”:结果发现词汇表中没有匹配的。
尝试长度为3的 “天气真”:结果发现词汇表中没有匹配的。
尝试长度为2的 “天气”:结果发现词汇表中有!于是拆分出第二个 token:["今天","天气"],剩余文本为“真好”。

第三步:处理剩余文本“真好”从“真”开始,尝试最长子词:
尝试长度为2的 “真好”:结果发现词汇表中没有匹配的。
尝试长度为1的“真”:结果发现词汇表中有!于是拆分出第三个 token:["今天","天气","真"],剩余文本为“好”。

第四步:处理剩余文本“真好”从“好”开始,尝试最长子词:
尝试长度为1的“好”:结果发现词汇表中有!于是拆分出第四个 token:["今天","天气","真","好"],剩余文本为空,结束拆分。

最终结果:["今天","天气","真","好"]

目前绝大多数的模型的分词器中都是使用的BPE算法或者基于BPE的变体算法生成的词汇表。分词器的核心功能是将连续的原始文本拆分为离散的 “语义最小单元(tokens)”

2、补全序列长度(填充 PAD)

一般模型都有最大的输入长度的token限制,当输入的token长度没有达到限制时,就需要用PAD(占位符)来填充token序列的长度,作用是 “补全输入序列”,使所有输入序列的长度统一为模型预设的最大长度(例如 512),当输入长度与模型内部计算长度保持一致后,就能保证计算张量的形状一致,从而确保模型能够高效进行批量并行计算

在模型训练或推理时,通常会将多个样本组成 “批次(batch)” 进行并行计算。若样本长度不一致,批次内的矩阵维度会混乱,无法并行运算。补全序列长度后,所有样本长度相同,可高效进行批量矩阵操作,大幅提升计算效率。

这里我假设模型的输入长度限制为8

补全后的token序列为
["今天","天气","真","好","[PAD]","[PAD]","[PAD]","[PAD]"]

3、将token根据词汇表映射为ID

在Qwen2.5-72B模型下“今天”、“天气”、“真”、“好”的ID分别为100644,104307,88051,52801

本质上token的拆分与ID的映射是伴随的,因为ID就存储在词汇表中,所以在拆分是与词汇表匹配时,就已经知道这个词的ID了,这里只是为了更细化的说明步骤,所以将分词和映射ID分开说明。

|词汇表|

ID
0 <pad>:占位符
1 <unk>:未知符号
2 <bos>:起始符号
3 <eos>:结束符号
... ...
52801
... ...
88051
... ...
100644 天气
... ...
104307 今天
... ...

输入步骤最终输出的结果是[100644,104307,88051,52801,0,0,0,0]的ID序列,0是PAD占位符的序列
如果大家对分词这一块有兴趣可以访问Tiktokenizer进行测试,不过这个网站需要科学上网。

第二步:输入嵌入(input Embedding)

输入嵌入(Input Embedding)的核心就是将ID序列通过嵌入矩阵转换为词向量序列,最终输出一个形状为「序列长度 × 嵌入维度」的词向量矩阵(也叫特征矩阵)。这个矩阵是 Transformer 编码器层接收的第一个输入,其承载了原始文本的初步语义信息。

嵌入矩阵

输入嵌入步骤的关键是模型内部的嵌入矩阵(Embedding Matrix),它是一个模型设计时就已确定形状与大小的参数矩阵,其形状为[词汇表大小 × 嵌入维度]。其中词汇表指的是分词器中用到的词汇表,因为只有词汇表匹配才可以通过ID序列找到对应词的词向量。而每个词的词向量维度大小是在模型设计时就固定的一个超参数,Transformer中一般是512维,表示一个词在512个维的语义表示权重值,但是这512维每一维所表示的含义以及语义表示权重值是模型通过训练学习后不断优化迭代得到的,并不是固定的值,是模型参数

1、通过ID序列从嵌入矩阵中找到对应的词向量

例如
ID=100644:从嵌入矩阵中提取第 100644 行,得到 “今天” 的词向量:v1 = [0.12, -0.34, 0.56, ..., 0.78](共 512个数值,此处省略中间值)
ID=104307:提取第 104307 行,得到 “天气” 的词向量:v2 = [-0.23, 0.45, -0.67, ..., 0.89]。
ID=88051:提取第 88051 行,得到 “真” 的词向量:v3 = [0.34, -0.56, 0.78, ..., -0.90]。
ID=52801:提取第 52801 行,得到 “好” 的词向量:v4 = [-0.45, 0.67, -0.89, ..., 0.10]。
ID=0:占位符,v5...v8 = [0,0,0,...,0]

2、组合词向量形成词向量矩阵

原本ID序列是[100644,104307,88051,52801,0,0,0,0],将里面的ID变成提取的词向量后就变成

[
[0.12, -0.34, 0.56, ..., 0.78],
[-0.23, 0.45, -0.67, ..., 0.89],
[0.34, -0.56, 0.78, ..., -0.90],
[-0.45, 0.67, -0.89, ..., 0.10],
[0,0,0,...,0],
[0,0,0,...,0],
[0,0,0,...,0],
[0,0,0,...,0]
]

这是一个二维矩阵,一维中每一维都是一个词向量,所以叫词向量矩阵

在Transformer架构,任何矩阵都有两个核心维度
序列长度(L):行数,例如输入序列包含的 token 数量
特征维度(d):列数,每个 token 的向量维度,比如Transformer的 512 维(d_model=512)

上面最终形成的词向量矩阵就是一个[序列长度为8 x 特征维度为512]的矩阵。

可能大家会比较好奇,词向量中的0.12、-0.34这些值都是表示什么,这些值是如何得到的。其实这些数值,以及每个维度的含义,是模型在训练过程计算统计得到的,并不是是设计阶段开发人员预先定义的。它其实是一种分布式的表示方式,就是说一个词的语义由多个维度的 “数值组合” 共同表达,而单个维度本身没有明确的语义含义,但整体向量能捕捉词与词之间的语义关联。

可能大家会觉得上面的描述还是很抽象,这里我来说明一下什么是分布式表达,分布式表示是自然语言处理(NLP)中表示语言单位(如词、短语、句子)的一种核心方法,其核心思想是:用一个低维、稠密的向量(每个维度都是连续数值)来表示一个实体,且实体的语义信息 “分布” 在向量的多个维度上,通过向量的整体特征(而非单个维度)来表达语义。

为了更好的了解分布式,我们先来了解什么是非分布式

非分布式
早期的独热编码就是一种非分布式的表示方式,它的核心是 “非此即彼” 的唯一标识,只有完全匹配的维度是用1表示,其他维度都用0表示。

例如
假设词汇表有 10 万个词,那么一个词就有可能与词汇表中所有的词有关联关系,也就是每个词需要用一个 10 万维的向量表示关系,其中只有与之匹配的位置为 1,其余全为 0(如 “猫”:[0,0,1,0,…,0],“狗”:[0,0,0,1,…,0])。
这种非分布式的表示方式会随着词汇表的变大而导致维度非常多,从而导致计算效率低,并且这种“非此即彼”的表示方式无法表达语义关联,导致“猫” 和 “狗” 的向量在数学上完全正交(距离为 1),无法体现他们在其他维度的共性关系,例如“都是动物” 的共性,“国王” 和 “女王” 也无法体现 “性别差异” 之外的关联。

而分布式表示方式则解决了上面的维度多,无法体现共性关系的问题。

  1. 低维稠密:用少数维度承载丰富信息
    分布式表示的向量维度通常是固定的低维数(如 256、512、768 等),并且每个维度都是连续的浮点数值(如[0.12, -0.34, 0.56, ..., 0.78]),从显示是一种稠密的样式,上不会像非分布式一样0 值占绝大多数从而导致显得稀疏。
    例如,用 512 维向量表示 “猫” 和 “狗”:
    猫:[0.82, -0.15, 0.33, ..., 0.27]
    狗:[0.79, -0.18, 0.31, ..., 0.29]
    维度的下降使得计算效率极大提升。
  2. 语义分布:多个维度共同表达语义,单个维度无固定含义
    分布式表示中,没有哪个维度单独对应 “性别”“动物属性”“词性” 等具体语义,而是多个维度的 “数值组合” 共同编码语义。
    比如,“猫” 和 “狗” 的向量在第 1、3、50 等维度上数值接近,这些维度的组合间接编码了 “都是哺乳动物、常作为宠物、有生命” 等共性特征,而 “猫” 和 “桌子” 的向量在多数维度上数值差异大,体现 “生物 vs 非生物” 的区别。
    这种语义“分布性” 让向量能灵活捕捉字词在复杂维度的各种关系(比如 “国王” 和 “女王” 的向量差异,可能同时编码 “性别” 和 “权力属性”)。
  3. 语义关联:向量空间关系对应语义关系
    分布式表示的核心价值是:向量在空间中的数学关系(如距离、差值)能直接对应语义关系。
    相似词的向量距离近(余弦相似度高):|猫 - 狗| 的向量距离 < |猫 - 桌子| 的向量距离,从数学角度能从数值明显体现差异,因此数值上也可以体现类比关系,通过向量运算可以实现:“国王 - 男人 + 女人 ≈ 女王”。
    上下位关系可通过向量包含度体现:“动物” 的向量可能是 “猫”“狗” 等向量的某种平均。
    分布式表示的本质是用“数据共现的规律”编码语义,所以分布式表示的向量数值不是人工设计的,而是通过模型从大规模文本数据中 “学习” 得到的,模型通过统计词与词的共现规律(比如 “猫” 常和 “喵”“宠物” 共现,“狗” 常和 “汪”“宠物” 共现),自动调整向量的数值,让语义相关的词在向量空间中更接近。

为什么要在这里大篇幅的讲嵌入维度呢,因为我希望大家能够更加直观的感受和理解到大模型的参数到底是什么

输入嵌入步骤最终输出的就是

[
[0.12, -0.34, 0.56, ..., 0.78],
[-0.23, 0.45, -0.67, ..., 0.89],
[0.34, -0.56, 0.78, ..., -0.90],
[-0.45, 0.67, -0.89, ..., 0.10],
[0,0,0,...,0],
[0,0,0,...,0],
[0,0,0,...,0],
[0,0,0,...,0]
]
原始的词向量矩阵
第三步:位置编码(Positional Encoding)

原始的词向量矩阵中主要编码的词的语义关联,但不包含字词在句子中的位置信息。而语言的逻辑依赖字词的位置关系, 例如 “我爱你” 和 “你爱我”,虽然包含相同的字词,但因位置不同导致语义完全相反。
为解决这一问题,Transformer 通过位置编码步骤,为每个位置生成一个与词向量维度相同的 “位置向量”,并将其与对应位置的词向量相加。最终得到的向量既保留了词的语义信息,又融入了该词在句子中的位置特征,从而让模型能够识别因位置差异导致的语义变化。
位置向量的生成公式为(偶数索引位置使用sin正弦函数,奇数使用cos余弦函数):

位置向量的生成公式

ps:公示中的10000是 Transformer 原论文中人为设定的经验值,是一个超参数,核心作用是 “控制位置编码的周期范围”,确保不同维度的位置向量具有差异化的周期性,从而让模型能更好地捕捉 “短距离” 和 “长距离” 的位置关系。所以我理解这会导致如果输入的序列(tokens)超过10000就会出现周期性问题。

依然以原生的词向量矩阵为例

# 词向量矩阵:[序列长度, 嵌入维度],每行对应一个词的词向量
word_embeddings = [
    [0.12, -0.34, 0.56,..., 0.78],  # 位置0:今天
    [-0.23, 0.45, -0.67, ..., 0.89], # 位置1:天气
    [0.34, -0.56, 0.78,...,  -0.90], # 位置2:真
    [-0.45, 0.67, -0.89,...,  0.10],  # 位置3:好
    [0,0,0,...,0],
    [0,0,0,...,0],
    [0,0,0,...,0],
    [0,0,0,...,0]
]
#嵌入维度 d_model = 512,序列位置索引为 pos = 0,1,2,3(分别对应 4 个词的位置)。
步骤 1:为每个位置生成位置向量

根据上述公式,为 pos=0,1,2,3 四个位置生成 4 维位置向量(计算过程保留两位小数):

位置 0(pos=0):
i=0(偶数):PE(0,0) = sin(0 / 10000^(0/512)) = sin(0) = 0.00
i=1(奇数):PE(0,1) = cos(0 / 10000^(2/512)) = cos(0) = 1.00
i=2(偶数):PE(0,2) = sin(0 / 10000^(4/512)) = sin(0) = 0.00
i=511(奇数):PE(0,511) = cos(0 / 10000^(2*511/512)) = cos(0) = 1.00
位置 0 的位置向量(指定维度):[0.00, 1.00, 0.00, ..., 1.00]


位置 1(pos=1):
i=0:PE(1,0) = sin(1 / 10000^0) = sin(1) ≈ 0.84(2*0/512=0,10000^0=1)
i=1:PE(1,1) = cos(1 / 10000^(2/512)) ≈ cos(1 / 1.018) ≈ 0.55(10000^(2/512)≈1.018)
i=2:PE(1,2) = sin(1 / 10000^(4/512)) ≈ sin(1 / 1.037) ≈ 0.82(10000^(4/512)≈1.037)
i=511:PE(1,511) = cos(1 / 10000^(1022/512)) ≈ cos(1 / 10000^1.996) ≈ cos(1 / 9910) ≈ 1.00(指数接近 2,10000^2=1e8,但分母极大,值接近 0)
位置 1 的位置向量(指定维度):[0.84, 0.55, 0.82, ..., 1.00]


位置 2(pos=2):
i=0:PE(2,0) = sin(2) ≈ 0.91
i=1:PE(2,1) = cos(2 / 1.018) ≈ cos(1.96) ≈ -0.32
i=2:PE(2,2) = sin(2 / 1.037) ≈ sin(1.93) ≈ 0.94
i=511:PE(2,511) = cos(2 / 9910) ≈ cos(0.0002) ≈ 1.00
位置 2 的位置向量(指定维度):[0.91, -0.32, 0.94, ..., 1.00]


位置 3(pos=3):
i=0:PE(3,0) = sin(3) ≈ 0.14
i=1:PE(3,1) = cos(3 / 1.018) ≈ cos(2.95) ≈ -0.98
i=2:PE(3,2) = sin(3 / 1.037) ≈ sin(2.90) ≈ 0.24
i=511:PE(3,511) = cos(3 / 9910) ≈ cos(0.0003) ≈ 1.00
步骤 2:词向量与位置向量相加(核心融合步骤)

位置编码的最终输出是 “词向量 + 位置向量”(逐元素相加),得到同时包含语义和位置信息的向量。
位置 0(今天):[0.12+0.00, -0.34+1.00, 0.56+0.00, ..., 0.78+1.00] = [0.12, 0.66, 0.56, ..., 1.78]
位置 1(天气):[-0.23+0.84, 0.45+0.55, -0.67+0.82, ..., 0.89+1.00] = [0.61, 1.00, 0.15, ..., 1.89]
位置 2(真):[0.34+0.91, -0.56+(-0.32), 0.78+0.94, ..., -0.90+1.00] = [1.25, -0.88, 1.72, ..., 0.10]
位置 3(好):[-0.45+0.14, 0.67+(-0.98), -0.89+0.24, ..., 0.10+1.00] = [-0.31, -0.31, -0.65, ..., 1.10]

位置编码步骤最终输出的是

[
[0.12, 0.66, 0.56, ..., 1.78],
[0.61, 1.00, 0.15, ..., 1.89],
[1.25, -0.88, 1.72, ..., 0.10],
[-0.31, -0.31, -0.65, ..., 1.10],
[-0.76,-0.75,-0.55,…,1.00],
[-0.96,-0.84,-1.00,…,1.00],
[-0.28,-0.87,-0.65,…,1.00],
[-0.66,-0.88,-0.23,…,1.00]
]
第四步:多头注意力(Multi-Head Attention)

多头自注意力是 Transformer 架构的核心步骤,其作用是让模型通过并行计算,从不同的特征子空间中捕捉输入序列中词与词之间的关联关系(例如 “天气” 与 “今天” 的时间关联、“真好” 与 “天气” 的评价关联等)。
多头自注意力中的 “多头”(Multi-Head),是指将原始特征矩阵(如 512 维)计算后的Q、K、V矩阵分割为多个相互独立的子空间(每个子空间的维度=总维度÷头数,例如 512 维分为 8 头时,每头 64 维)。每个 “头” 可以理解为一个独立的计算单元,头的内部的计算对象是自身序列,所以称之为自注意力。分割为多头的目的是让模型能并行捕捉多样化的关联关系,因为不同的头内在维度表达的类型依赖不同,所以多头就能体现多个层面的含义,从而丰富整体特征的表达能力。
多头自注意力中的 “自注意力”(Self-Attention),是指每个头内部通过计算得到注意力权重,通过权重体现词与词的关联强度。这里计算得到的关联强度是基于模型从大量数据中学习到的模式关注关联关系,所以计算过程中除了出了原始的词向量矩阵,其他参与计算的参数都是模型参数,值是不固定的。
多头自注意力最终将所有头的输出根据分割顺序拼接起来,再通过一次线性变换整合为与原始维度一致的特征矩阵,从而综合多个子空间的关联信息,得到更全面的语义特征。

步骤 1:计算 Q(查询)、K(键)、V(值)矩阵

首先,将原始输入向量转换为具有 “查询、索引、内容” 角色的向量,为后续 “谁该关注谁” 的计算奠定基础。通过 3 个不同的可学习线性变换矩阵W_q, W_k, W_v(这三个线性变换矩阵,是模型参数,是模型学习过程统计得到的寓含权重的矩阵,又称之为权重矩阵),将输入向量分别转换为 Q(查询)、K(键)、V(值)矩阵,这三个矩阵的作用类似 “检索系统”。

Q(Query,查询)
该矩阵中每个向量是对应词的 “查询载体”,通过数值特征隐含该词需要关注的信息方向。例如 “好” 的 Q 向量会包含与 “评价对象” 相关的特征(如 “事物属性”“状态描述” 等),隐含 “需要找到被评价的对象” 的意图。

K(Key,键)
该矩阵中每个向量是对应词的 “索引载体”,通过数值特征体现该词可被查询的属性(而非显式记录 “可以查什么”)。例如 “天气” 的 K 向量会包含与 “自然现象”“状态属性” 相关的特征,当 “好” 的 Q 向量(含 “评价对象” 特征)与 “天气” 的 K 向量匹配时,说明 “天气” 是 “好” 需要关注的对象。

V(Value,值)
该矩阵中每个向量是对应词的 “内容载体”,通过数值特征存储该词的具体语义信息(而非显式记录 “晴朗、温度” 等文字)。例如 “天气” 的 V 向量包含 “天气的具体状态、特征” 等隐含信息,当 “天气” 的 K 被 “好” 的 Q 匹配后,“天气” 的 V 向量信息会被加权融入 “好” 的输出,让 “好” 的语义明确为 “天气好”。

注意!!

步骤三 位置编码 最终输出的是一个[8x512]形态的矩阵,这里为了便于计算展示,我们将其调整为[8x8]形态的矩阵

input_vectors = [
    [0.12, 0.66, 0.56, 1.78, 0.20, 0.30, 0.40, 0.50],  # 位置0:今天
    [0.61, 1.00, 0.15, 1.47, 0.60, 0.70, 0.80, 0.90],  # 位置1:天气
    [1.25, -0.88, 1.72, -1.12, 1.00, 1.10, 1.20, 1.30],# 位置2:真
    [-0.31, -0.31, -0.65, -0.85, 1.40, 1.50, 1.60, 1.70],# 位置3:好
    [-0.76,-0.75,-0.55,1.00,1.80,1.90,2.00,2.10],
    [-0.96,-0.84,-1.00,1.00,2.20,2.30,2.40,2.50],
    [-0.28,-0.87,-0.65,1.00,2.60,2.70,2.80,2.90],
    [-0.66,-0.88,-0.23,1.00,3.00,3.10,3.20,3.30]
]

原始W_q, W_k, W_v是一个形态为512×512维的矩阵,这里我们简化为8×8维,并且将W_q, W_k, W_v的权重矩阵值设计为相同,去简化计算过程,便于后续的计算展示。

# 线性变换矩阵(可学习参数)
W_q = W_k = W_v = [  # 这里每行不同且无规律是为了模拟真实训练中的权重矩阵
    [0.12, 0.34, 0.56, 0.78, 0.90, 0.21, 0.43, 0.65], 
    [0.87, 0.65, 0.43, 0.21, 0.09, 0.98, 0.76, 0.54], 
    [0.32, 0.54, 0.76, 0.98, 0.10, 0.32, 0.54, 0.76], 
    [0.90, 0.78, 0.65, 0.54, 0.43, 0.32, 0.21, 0.10], 
    [0.56, 0.43, 0.32, 0.21, 0.87, 0.65, 0.43, 0.21],
    [0.21, 0.32, 0.43, 0.54, 0.65, 0.76, 0.87, 0.98], 
    [0.76, 0.54, 0.32, 0.10, 0.21, 0.43, 0.65, 0.87],
    [0.43, 0.21, 0.90, 0.78, 0.56, 0.34, 0.12, 0.89] 
]
# 这里为了简化计算过程,W_k、W_v的权重矩阵暂用与Q相同(实际Transformer中它们是不同的)

通过矩阵乘法(输入向量 × 权重矩阵)计算 Q、K、V,公式:

Q = input_vectors × W_q

K = input_vectors × W_k

V = input_vectors × W_v

input_vectors:Q 矩阵中每个行向量是对应词的查询向量。
遵循 “行 × 列点积求和” 的规则,即input_vectors的整行与W_q的整列相乘

# Q[0][0] = input_vectors[0][0] x W_q[0][0] + input_vectors[0][1] x W_q[1][0] + input_vectors[0][2] x W_q[2][0] + input_vectors[0][3] x W_q[3][0] + input_vectors[0][4] x W_q[4][0] + input_vectors[0][5] x W_q[5][0] + input_vectors[0][6] x W_q[6][0] + input_vectors[0][7] x W_q[7][0]
# Q[0][0] = 0.12×0.12 + 0.66×0.87 + 0.56×0.32 + 1.78×0.90 + 0.20×0.56 + 0.30×0.21 + 0.40×0.76 + 0.50×0.43
# Q[0][0] = 0.0144 + 0.5742 + 0.1792 + 1.602 + 0.112 + 0.063 + 0.304 + 0.215 
# Q[0][0] = 3.0638
简化计算后(保留 4 位小数):
Q = [
    [3.0638, 2.6636, 2.7046, 2.3762, 1.7218, 2.1208, 1.8964, 2.1670],  # 位置0:今天
    [3.7922, 3.1880, 3.4001, 2.9126, 2.6874, 3.0215, 2.8972, 3.5680],  # 位置1:天气
    [1.1888, 1.6112, 2.8764, 2.7632, 3.0526, 1.5420, 2.0188, 4.5210],  # 位置2:真
    [1.7661, 0.9821, 1.9236, 1.5870, 3.1024, 2.4752, 2.8910, 4.6380],  # 位置3:好
    [3.2860, 2.5142, 3.9470, 2.8936, 4.2052, 3.1520, 3.6874, 6.0218],  # 位置4:PAD
    [3.8724, 3.0156, 4.5210, 3.4782, 4.8926, 3.7684, 4.2158, 6.8742],  # 位置5:PAD
    [2.9612, 2.2084, 3.6580, 2.5168, 3.7640, 2.8932, 3.2016, 5.3170],  # 位置6:PAD
    [2.4158, 1.8720, 3.1064, 2.0930, 3.1874, 2.3656, 2.6842, 4.5936]   # 位置7:PAD
]
# 因为过程简化,所以K矩阵和V矩阵计算逻辑相同,计算后的矩阵也一样。
步骤 2:分割 Q、K、V 到多个注意力头

一般单一注意力头只能捕捉一种类型的关联(比如只关注 “评价关系”),而通过分割将单头拆分为多个更小的头,让模型同时捕捉多种关联,例如要了解“今天” 与 “天气” 的关联,我们可以从头 1 关注 “评价关系”,头 2 关注 “时间关系”,分割的目的是为了形成多个子空间,通过子空间内维度组合形成一个新的表达维度,让表达更加丰富,避免单一视角的局限,并实现并行计算。分割的头数与每一层的包含的维数都是设计阶段就固化的超参数,而维中具体的值是模型参数。

这里我将 8 维的 Q、K、V 按 “头数” 分割为多个子矩阵(每个头处理一部分维度),这里设计分割为4个头,每个头处理 2 维。

头 1(Head 1):取前 1,2 维。
头 2(Head 2):取后 3,4 维。
头 3(Head 3):取后 5,6 维。
头 4(Head 4):取后 7,8 维。
以 Q 为例,分割后:

# 头1的Q、K、V(8×2维)
Q1 = [
    [3.0638, 2.6636],  # 位置0:今天(第0-1维)
    [3.7922, 3.1880],  # 位置1:天气(第0-1维)
    [1.1888, 1.6112],  # 位置2:真(第0-1维)
    [1.7661, 0.9821],   # 位置3:好(第0-1维)
    [3.2860, 2.5142],
    [3.8724, 3.0156],
    [2.9612, 2.2084],
    [2.4158, 1.8720]
]

K1 = 结构同上
V1 = 结构同上

# 头2的Q、K、V(8×2维)
Q2 = [
    [2.7046, 2.3762],  # 位置0:今天(第2-3维)
    [3.4001, 2.9126],  # 位置1:天气(第2-3维)
    [3.2478, 3.8090],  # 位置2:真(第2-3维)
    [1.7816, 1.1871]   # 位置3:好(第2-3维)
    [3.9470, 2.8936],
    [4.5210, 3.4782],
    [3.6580, 2.5168],
    [3.1064, 2.0930]
]
K2 = 结构同上
V2 = 结构同上

# 头3的Q、K、V(8×2维)
Q3 = [
    [1.7218, 2.1208],  # 位置0:今天(第4-5维)
    [2.9351, 3.1985],  # 位置1:天气(第4-5维)
    [3.3012, 2.0361],  # 位置2:真(第4-5维)
    [2.7436, 2.4671]   # 位置3:好(第4-5维)
    [4.2052, 3.152],
    [4.8926, 3.7684],
    [3.7640, 2.8932],
    [3.1874, 2.3656]
]
K3 = 结构同上
V3 = 结构同上


# 头4的Q、K、V(8×2维)
Q4 = [
    [1.8964, 2.1670],  # 位置0:今天(第6-7维)
    [2.9070, 3.5065],  # 位置1:天气(第6-7维)
    [2.8853, 5.0215],  # 位置2:真(第6-7维)
    [2.2526, 3.7211]   # 位置3:好(第6-7维)
    [3.6874, 6.0218],
    [4.2158, 6.8742],
    [3.2016, 5.3170],
    [2.6842, 4.5936]
]
K4 = 结构同上
V4 = 结构同上
步骤 3:计算每个头的注意力分数(以头 1 为例)

该步骤通过“每个词的查询(Q)与其他词的键(K)的计算得到注意力分数,这个注意力分数是衡量 “每个词对其他所有词的关注度可衡量的值”,值越高说明两个词的关联越紧密,比如 “好” 的 Q 与 “天气” 的 K 匹配分数高,说明 “好” 需要关注 “天气”。计算每个词对其他词的 “关联强度分数”是为后续 “分配关注度” 提供依据。

!!!这里我们假设模型设计时,对于输入限制的token长度要求是8。因为在计算注意力分数时会根据输入长度限制进行填充掩码来使得计算是的张量一致,保持计算的一致性。这里的长度限制也是超参数

计算公式为:

注意力分数公式

K^T:是 K 的转置矩阵,转置后K原本的,行变成了列,列变成了行,这样计算是才能实现Q中的每一个词向量与K中所有词的同一个维度相乘,得到关联强度分数,例子中转置后维度形态将会从 8×2 变为 2×8
dₖ:是每个头的维度,这个例子中是2
√dₖ:用于缩放分数,避免数值过大导致 softmax时出现梯度消失,例子中√dₖ=√2 ≈ 1.4142。

矩阵乘法的核心逻辑是 “前矩阵列数 = 后矩阵行数”

# 头 1 的注意力分数计算:scores1 = (Q1 × K1^T) / √dₖ = (Q1 × K1^T) / 2
# K1 的转置矩阵为(简化计算):
K1^T = [
    [3.0638, 3.7922, 1.1888, 1.7661,3.2860,3.8724,2.9612,2.4158],  # 原K1第0列
    [2.6636, 3.1880, 1.6112, 0.9821,2.5142,3.0156,2.2084,1.8720]   # 原K1第1列
]

# 通过矩阵乘法Q1(8×2)×K1^T(2×8)=4×4,每个元素为对应行与列的点积,则 Q1 × K1^T 的结果为(4×4 矩阵,每行是一个词对所有词的原始分数)

# Q1 × K1^T 计算过程(这里只体现前4位的计算过程)
raw_scores = [
    # 第0行(今天对所有词的原始分数)
    [3.0638×3.0638 + 2.6636×2.6636,  # 今天→今天
     3.0638×3.7922 + 2.6636×3.1880,  # 今天→天气
     3.0638×1.1888 + 2.6636×1.6112,  # 今天→真
     3.0638×1.7661 + 2.6636×0.9821], # 今天→好
    
    # 第1行(天气对所有词的原始分数)
    [3.7922×3.0638 + 3.1880×2.6636,  # 天气→今天
     3.7922×3.7922 + 3.1880×3.1880,  # 天气→天气
     3.7922×1.1888 + 3.1880×1.6112,  # 天气→真
     3.7922×1.7661 + 3.1880×0.9821], # 天气→好
    
    # 第2行(真对所有词的原始分数)
    [1.1888×3.0638 + 1.6112×2.6636,  # 真→今天
     1.1888×3.7922 + 1.6112×3.1880,  # 真→天气
     1.1888×1.1888 + 1.6112×1.6112,  # 真→真
     1.1888×1.7661 + 1.6112×0.9821], # 真→好
    
    # 第3行(好对所有词的原始分数)
    [1.7661×3.0638 + 0.9821×2.6636,  # 好→今天
     1.7661×3.7922 + 0.9821×3.1880,  # 好→天气
     1.7661×1.1888 + 0.9821×1.6112,  # 好→真
     1.7661×1.7661 + 0.9821×0.9821]  # 好→好
]

# Q1 × K1^T 计算后的结果是
raw_scores = [
    [16.4820, 20.1110, 7.9350, 8.0270],
    [20.1110, 24.5440, 9.6450, 9.8280],
    [7.9350, 9.6450, 3.0090, 3.6820],
    [8.0270, 9.8280, 3.6820, 4.0830]
]

缩放后(÷ 1.4142):
head1_scores = [
    [11.6545, 14.2200, 5.6109, 5.6803],  # 今天对所有词的得分
    [14.2200, 17.3600, 6.8200, 6.9500],  # 天气对所有词的得分
    [5.6109, 6.8200, 2.1300, 2.6000],    # 真对所有词的得分
    [5.6803, 6.9500, 2.6000, 2.8900]     # 好对所有词的得分
]

计算完成后需要将矩阵进行掩码的填充,保障计算时张量一致,填充后的矩阵为

head1_scores =[
    # 行0:今天对所有位置的分数
    [11.6545, 14.2200, 5.6109, 5.6803, 11.8540, 14.0700, 10.5750, 8.7520],
    # 行1:天气对所有位置的分数
    [14.2200, 17.3600, 6.8200, 6.9500, 14.4090, 17.1830, 12.9190, 10.6980],
    # 行2:真对所有位置的分数
    [5.6109, 6.8200, 2.1300, 2.6000, 5.6270, 6.6910, 5.0050, 4.1630],
    # 行3:好对所有位置的分数
    [5.6803, 6.9500, 2.6000, 2.8900, 5.8500, 6.9370, 5.2320, 4.3170],
    # 行4:PAD4对所有位置的分数
    [11.8540, 14.4090, 5.6270, 5.8500, 12.1050, 14.3590, 10.8060, 8.9480],
    # 行5:PAD5对所有位置的分数
    [14.0700, 17.1830, 6.6910, 6.9370, 14.3590, 17.0340, 12.8180, 10.6060],
    # 行6:PAD6对所有位置的分数
    [10.5750, 12.9190, 5.0050, 5.2320, 10.8060, 12.8180, 9.6490, 7.9820],
    # 行7:PAD7对所有位置的分数
    [8.7520, 10.6980, 4.1630, 4.3170, 8.9480, 10.6060, 7.9820, 6.6050]
]
步骤4:掩码

该步骤的目的是彻底屏蔽 PAD 位置的无效信息,避免其干扰有效词的语义关联计算
1、首先会定义一个与需要掩码的矩阵一样大小的掩码矩阵,其中需要掩码的设置为True,不需要的设置为False。

padding_mask = [
    [False, False, False, False, True, True, True, True],
    [False, False, False, False, True, True, True, True],
    [False, False, False, False, True, True, True, True],
    [False, False, False, False, True, True, True, True],
    [False, False, False, False, True, True, True, True],
    [False, False, False, False, True, True, True, True],
    [False, False, False, False, True, True, True, True],
    [False, False, False, False, True, True, True, True]
]

这里需要重点关注以下两点

  • 尽管得分矩阵中第 4-7 行是 Q 的 PAD,但这些查询侧的 PAD 并不影响单个词的有效性语义计算。关键在于:Q×K^T 中,K 转置后第 4-7 列对应原本的 K 的 PAD,这些 PAD 会参与所有有效词的注意力分数计算,干扰语义关联。因此,掩码需屏蔽得分矩阵中与 K 的 PAD 对应的列,确保有效词仅关注有意义的键。
  • 在“第一步:输入”中,在为token序列补全时同时会记录下来PAD是从哪一位开始哪一位结束,在多头自注意力步骤计算是会针对K对应用的PAD部分进行掩码

2、将掩码矩阵作用于缩放后分数矩阵
遍历分数矩阵,若掩码矩阵对应位置为 True,就将该位置的分数替换为-inf(负无穷)。以你之前的scaled_scores为例,处理后的矩阵如下

masked_scores = [
    [11.6545, 14.2200, 5.6109, 5.6803, -inf, -inf, -inf, -inf],
    [14.2200, 17.3600, 6.8200, 6.9500, -inf, -inf, -inf, -inf],
    [5.6109, 6.8200, 2.1300, 2.6000, -inf, -inf, -inf, -inf],
    [5.6803, 6.9500, 2.6000, 2.8900, -inf, -inf, -inf, -inf],
    [11.8540, 14.4090, 5.6270, 5.8500, -inf, -inf, -inf, -inf],
    [14.0700, 17.1830, 6.6910, 6.9370, -inf, -inf, -inf, -inf],
    [10.5750, 12.9190, 5.0050, 5.2320, -inf, -inf, -inf, -inf],
    [8.7520, 10.6980, 4.1630, 4.3170, -inf, -inf, -inf, -inf]
]

步骤 5:应用 softmax 函数得到注意力权重(以头 1 为例)

为了明确每个词的“关注对象以及所关注的比例”,通过softmax函数将注意力分数“归一化”为0-1之间的权重(总和为 1),表示 “每个词应该分配多少比例的注意力给其他词”。

计算公式


注意力权重计算公式

softmax函数公式

softmax函数公式

分子:对每个得分做指数运算(e^x),确保结果为正数;
分母:所有得分的指数之和,实现归一化(使所有结果之和为 1);
数值稳定技巧:为避免指数运算导致的数值溢出(当 x_i 较大时,e^x_i可能过大),实际计算时会先减去向量中的最大值(max(x))

#对 scores1 应用 softmax(数值较大时,最大值的权重接近 1,其他接近 0):
attention_weights = [
    # 行0:今天(注意力集中在天气,权重0.9288)
    [0.0702, 0.9288, 0.0005, 0.0005, 0.0000, 0.0000, 0.0000, 0.0000],
    # 行1:天气(注意力集中在自身,权重0.9320)
    [0.0675, 0.9320, 0.0003, 0.0003, 0.0000, 0.0000, 0.0000, 0.0000],
    # 行2:真(注意力集中在天气,权重0.7620)
    [0.2350, 0.7620, 0.0015, 0.0015, 0.0000, 0.0000, 0.0000, 0.0000],
    # 行3:好(注意力集中在天气,权重0.7580)
    [0.2390, 0.7580, 0.0015, 0.0015, 0.0000, 0.0000, 0.0000, 0.0000],
    # 行4:PAD4(注意力集中在PAD5,权重0.9270)
    [0.0720, 0.9270, 0.0005, 0.0005, 0.0000, 0.0000, 0.0000, 0.0000],
    # 行5:PAD5(注意力集中在自身,权重0.9300)
    [0.0690, 0.9300, 0.0003, 0.0003, 0.0000, 0.0000, 0.0000, 0.0000],
    # 行6:PAD6(注意力集中在PAD5,权重0.9250)
    [0.0740, 0.9250, 0.0005, 0.0005, 0.0000, 0.0000, 0.0000, 0.0000],
    # 行7:PAD7(注意力集中在PAD5,权重0.9230)
    [0.0760, 0.9230, 0.0005, 0.0005, 0.0000, 0.0000, 0.0000, 0.0000]
]
#实际中权重更分散
步骤 6:每个头的输出 = 权重 × V(头 1 为例)

这一步是根据注意力权重,将 “被关注词的值(V)” 加权求和,得到每个词融合了“全局关联信息”的新特征,比如“好”的输出不仅包含自身信息,还融合其所需要关注的“天气 的信息,理解为 “天气好”。让每个词的输出不再是孤立的,而是融合了“它所关注的词”的信息,实现了“全局信息交互”。

计算公式:


完整的注意力计算公式

前面已经说明,为了便于计算展示,所以W_q、W_k、W_v是相同的,所以计算得到的Q、K、V也是相同的,所以分割后的V的头1就等于Q的头1
所以V1等于

# V1 = Q1
V1 = [
    [3.0638, 2.6636],  # 位置0:今天(第0-1维)
    [3.7922, 3.1880],  # 位置1:天气(第0-1维)
    [1.1888, 1.6112],  # 位置2:真(第0-1维)
    [1.7661, 0.9821],  # 位置3:好(第0-1维)
    [3.2860, 2.5142],  # 位置4:PAD
    [3.8724, 3.0156],  # 位置5:PAD
    [2.9612, 2.2084],  # 位置6:PAD
    [2.4158, 1.8720]   # 位置7:PAD
]

V1是[8x2]的矩阵,注意力权重得分矩阵是[8x8]的矩阵,最终计算后得到的是一个[8x2]的矩阵

计算后(每行是权重与 V 行的加权和):

# head1_output[0][0] = attention_weights[0][0] x V1[0][0] + attention_weights[0][1] x V1[1][0] + attention_weights[0][2] x V1[2][0] + attention_weights[0][3] x V1[3][0] + attention_weights[0][4] x V1[4][0] + attention_weights[0][5] x V1[5][0] + attention_weights[0][6] x V1[6][0] + attention_weights[0][7] x V1[7][0]
head1_output = [
   [3.7362, 3.1527],  # 位置0:今天
    [3.7743, 3.1835],  # 位置1:天气
    [3.6209, 3.0541],  # 位置2:真
    [3.6157, 3.0495],  # 位置3:好
    [3.7579, 3.1703],  # 位置4:PAD
    [3.7689, 3.1801],  # 位置5:PAD
    [3.7425, 3.1575],  # 位置6:PAD
    [3.7283, 3.1453]   # 位置7:PAD
]
步骤 7:合并所有头的输出,进行线性变换

这一步是将多个头的输出根据分割的顺序合并为统一维度的特征,再通过线性变换(W_o)整合不同头的信息,增强模型表达能力。综合多个视角的关联信息,输出既包含局部语义,又包含全局依赖的特征,为后续前馈网络和编码器层提供更丰富的输入。

计算公式:


W_o线性变化公式

W_o:输出权重矩阵,与W_q、W_k、W_v一样是模型参数
公式中W_o后面的部分不参与实际计算,仅用于标注输出矩阵 Z 的维度

# 拼接头1、头2、头3、头4后的输出结果(8×8维)
concatenated = [
   # 位置0:今天(head1列+head2列+head3列+head4列)
    [3.7362, 3.1527, 3.2758, 2.8562, 2.9541, 2.9873, 3.4825, 3.5217],
    # 位置1:天气
    [3.7743, 3.1835, 3.2614, 2.8403, 3.0126, 3.0458, 3.5018, 3.5412],
    # 位置2:真
    [3.6209, 3.0541, 3.2816, 2.8621, 3.1089, 3.1325, 3.4236, 3.4629],
    # 位置3:好
    [3.6157, 3.0495, 3.1985, 2.7789, 3.0972, 3.1207, 3.4189, 3.4583],
    # 位置4:PAD(后续会被忽略)
    [3.7579, 3.1703, 3.1642, 2.7425, 3.1856, 3.2091, 3.5207, 3.5603],
    # 位置5:PAD
    [3.7689, 3.1801, 3.3428, 2.9156, 3.2143, 3.2378, 3.5392, 3.5789],
    # 位置6:PAD
    [3.7425, 3.1575, 3.3015, 2.8743, 3.1628, 3.1864, 3.4986, 3.5381],
    # 位置7:PAD
    [3.7283, 3.1453, 3.2723, 2.8530, 3.1415, 3.1652, 3.4773, 3.5169]
]

合并后的注意力得分矩阵与W_o相乘后最终输出的结果如下(多头自注意力步骤最终输出

# 第 0 列:3.7362×0.12 + 3.1527×0.87 + 3.2758×0.32 + 2.8562×0.90 + 2.9541×0.56 + 2.9873×0.21 + >3.4825×0.76 + 3.5217×0.43 ≈ 11.6842
Z = [
   # 位置0:今天
   [11.6842, 10.5276, 12.2438, 10.8752, 9.2364, 9.8517, 9.3268, 13.0542],
   # 位置1:天气
   [11.7826, 10.6183, 12.3345, 10.9625, 9.3187, 9.9402, 9.4083, 13.1415],
   # 位置2:真
   [11.4569, 10.3215, 12.0682, 10.6348, 9.0523, 9.6741, 9.1526, 12.8376],
   # 位置3:好
   [11.3285, 10.2078, 11.9567, 10.5293, 8.9476, 9.5684, 9.0498, 12.7294],
   # 位置4:PAD(后续忽略)
   [11.6538, 10.4982, 12.2154, 10.8476, 9.2091, 9.8235, 9.3005, 13.0278],
   # 位置5:PAD(后续忽略)
   [11.9073, 10.7516, 12.4789, 11.1032, 9.4528, 10.0867, 9.5532, 13.2901],
   # 位置6:PAD(后续忽略)
   [11.7254, 10.5629, 12.2863, 10.9187, 9.2753, 9.9076, 9.3674, 13.1085],
   # 位置7:PAD(后续忽略)
   [11.5971, 10.4493, 12.1758, 10.8062, 9.1706, 9.7934, 9.2541, 12.9963]
]
第五步:残差连接&层归一化(Add&Norm)

Transformer 采用 “多头自注意力 + 前馈网络” 的多层堆叠结构,导致其随着堆叠层数的增加计算结果面临两大挑战:梯度消失特征分布不稳定。为解决这些问题,引入了残差连接和层归一化,既保障了信息的有效传递(残差连接保留原始信息,缓解梯度消失),又维持了训练的稳定性(层归一化稳定特征分布),最终使得 Transformer 的深层堆叠结构能够高效、稳定地训练,适配复杂的序列建模任务。

残差连接

用于缓解梯度消失,保留原始信息在深层网络中,若计算仅依赖 “层间串行的结果传递”会导致原始输入的信息随层级加深逐渐稀释(就好比茶叶,不断的放入不同的水浸泡,随着浸泡次数增加,茶叶原本的味道也越来越淡)。同时,反向传播时梯度需经过多层权重矩阵传递,易因权重的缩放作用累积导致梯度消失(浅层参数的梯度近乎为 0,难以有效更新)。残差连接通过 “输入直接与输出相加” 的短路机制,实现两大效果:
信息保留:原始输入的特征被直接保留到输出中,避免深层网络对原始信息的过度扭曲。
梯度短路:反向传播时,梯度可通过残差路径直接回传至浅层,缓解梯度消失问题,让浅层参数也能高效更新。

层归一化

通过稳定特征分布,减少训练波动深层网络中,每一层的输入特征分布会因前层参数的更新而持续变化(即内部协变量偏移),这会导致后续层的训练目标不断波动,降低收敛速度甚至引发训练不稳定。层归一化通过对 “单个样本的各特征维度” 进行标准化),实现:
分布稳定:将各维度的特征值缩放至相近的数值范围,减少因分布波动导致的训练震荡。
数值一致性:让不同特征维度的贡献更均衡,提升模型对噪声的鲁棒性。

补充知识点

正向传播
上面的Transformer架构图体现的只是Transformer的组成以及正向处理的流程,Transformer架构的每一层由“多头自注意力 + 层归一化 + 残差连接 + 前馈网络 + 层归一化 + 残差连接”组成,计算是并不是一层计算完成就结束了,而是通过多层堆叠实现复杂语义的精准理解,所以每一层的输出结果将作为下一层的输入继续进行计算,直到多层计算完成,在原文的Transformer中堆叠了6层。而这样一层传一层的方式就是正向传播。

反向传播
Transformer架构图中并没有明显的体现反向传播,反向传播的本质是基于链式法则,沿着正向传播的路径反向计算梯度,再用梯度更新所有可训练参数。反向传播只有在训练模型的时候才会出现,其作用是去优化模型中参与计算的模型参数(例如W_o、W_q、W_k、W_v)。反向传播的前提是模型先要完成正向传播的计算,例如监督训练中(包含问题和答案),模型先按照Transformer架构完成编码器层和解码器层的计算,生成了回答文本。然后用损失函数(如交叉熵)计算 “模型生成的回答” 与 “真实标准答案” 的差距(损失值),在按照模型的正向流程反向传播计算,反向传播的步骤是,先解码器层(softmax->Linear->Add&Norm->Feed Forward->Add&Norm->Multi-Head Attention),当解码器层计算到需要编码器层的输出时,同步反向传播到编码器层。其中反向传播时,正向传播堆叠了多少层,反向传播就会反向堆叠多少层。

步骤 1 :残差连接

作用:将模块的原始输入与输出相加,保留原始信息并缓解梯度消失。
计算公式:


残差连接计算公式

X_res : 残差连接后的结果
X:是前一层的输出,如果是第一层,则是进入多头自注意力步骤时的原始词向量矩阵。
Y:当前层前一个步骤的输出

X = [
    [0.12, 0.66, 0.56, 1.78, 0.20, 0.30, 0.40, 0.50],  # 位置0:今天
    [0.61, 1.00, 0.15, 1.47, 0.60, 0.70, 0.80, 0.90],  # 位置1:天气
    [1.25, -0.88, 1.72, -1.12, 1.00, 1.10, 1.20, 1.30],# 位置2:真
    [-0.31, -0.31, -0.65, -0.85, 1.40, 1.50, 1.60, 1.70],# 位置3:好
    [-0.76,-0.75,-0.55,1.00,1.80,1.90,2.00,2.10],      # 位置4:PAD
    [-0.96,-0.84,-1.00,1.00,2.20,2.30,2.40,2.50],      # 位置5:PAD
    [-0.28,-0.87,-0.65,1.00,2.60,2.70,2.80,2.90],      # 位置6:PAD
    [-0.66,-0.88,-0.23,1.00,3.00,3.10,3.20,3.30]       # 位置7:PAD
]

Y = [
    [11.6842, 10.5276, 12.2438, 10.8752, 9.2364, 9.8517, 9.3268, 13.0542],  # 0
    [11.7826, 10.6183, 12.3345, 10.9625, 9.3187, 9.9402, 9.4083, 13.1415],  # 1
    [11.4569, 10.3215, 12.0682, 10.6348, 9.0523, 9.6741, 9.1526, 12.8376],  # 2
    [11.3285, 10.2078, 11.9567, 10.5293, 8.9476, 9.5684, 9.0498, 12.7294],  # 3
    [11.6538, 10.4982, 12.2154, 10.8476, 9.2091, 9.8235, 9.3005, 13.0278],  # 4(PAD)
    [11.9073, 10.7516, 12.4789, 11.1032, 9.4528, 10.0867, 9.5532, 13.2901],  # 5(PAD)
    [11.7254, 10.5629, 12.2863, 10.9187, 9.2753, 9.9076, 9.3674, 13.1085],  # 6(PAD)
    [11.5971, 10.4493, 12.1758, 10.8062, 9.1706, 9.7934, 9.2541, 12.9963]   # 7(PAD)
]

X + Y = X_res = [
    # 位置0:[0.12+11.6842, 0.66+10.5276, ..., 1.65+13.0542]
    [11.8042, 11.1876, 12.8038, 12.6552, 10.1364, 10.0617, 9.7568, 14.7042],
    # 位置1:[0.61+11.7826, 1.00+10.6183, ..., 1.54+13.1415]
    [12.3926, 11.6183, 12.4845, 12.8525, 9.4087, 10.9202, 10.1683, 14.6815],
    # 位置2:[1.25+11.4569, -0.88+10.3215, ..., 1.76+12.8376]
    [12.7069, 9.4415, 13.7882, 10.7348, 9.1523, 9.9941, 9.6926, 14.5976],
    # 位置3:[-0.31+11.3285, -0.31+10.2078, ..., 1.10+12.7294]
    [11.0185, 9.8978, 11.3067, 11.6293, 9.3776, 9.8884, 9.2598, 13.8294],
    # 位置4(PAD):[-0.76+11.6538, ..., 1.00+13.0278]
    [10.8938, 9.7482, 11.6654, 11.8476, 9.2091, 9.8235, 9.3005, 14.0278],
    # 位置5(PAD):[-0.96+11.9073, ..., 1.00+13.2901]
    [10.9473, 9.9116, 11.4789, 12.1032, 9.4528, 10.0867, 9.5532, 14.2901],
    # 位置6(PAD):[-0.28+11.7254, ..., 1.00+13.1085]
    [11.4454, 9.6929, 11.6363, 11.9187, 9.2753, 9.9076, 9.3674, 14.1085],
    # 位置7(PAD):[-0.66+11.5971, ..., 1.00+12.9963]
    [10.9371, 9.5693, 11.9458, 11.8062, 9.1706, 9.7934, 9.2541, 13.9963]
]

步骤 2 : 计算均值和方差(层归一化第一步)

作用:计算每个位置的均值 μ 和方差 σ²
计算公式


均值计算公式
方差计算公式

i:为位置索引
d:特征维度
均值 μ : 该位置所有特征值的平均
方差 σ² : 该位置所有特征值与均值差的平方的平均

# 均值μ(位置0-7)
μ = [
    11.6385, 11.8158, 11.5360, 10.9873,
    10.7137, 10.9255, 10.9039, 10.8062
]

# 方差σ²(位置0-7,加ε后)
σ² = [
    2.9872, 2.0156, 3.5241, 2.5683,
    2.4367, 2.7842, 2.3015, 2.1879
]
步骤 3 : 标准化(层归一化第二步)

作用:将特征值缩放至均值为 0、方差为 1 的分布,减少数值波动。
计算公式


标准化公式

ε(读作 “epsilon”)是一个极小的正数常数,核心作用是「避免分母为 0」,同时防止方差过小时计算结果异常,是层归一化的 “安全保障”。一般为1e-5

z = [
    # 位置0
    [ 0.1052, -0.2437,  0.6685,  0.5682, -0.3451, -0.3218, -1.0632,  1.7031],
    # 位置1
    [ 0.3387, -0.1392,  0.4712,  0.7325, -1.7063, -0.6432, -1.1578,  1.9842],
    # 位置2
    [ 0.6538, -1.1245,  1.2753, -0.4521, -1.4236, -1.0873, -1.2065,  1.8247],
    # 位置3
    [ 0.0254, -0.6238,  0.2276,  0.4632, -1.0042, -0.7825, -1.1036,  1.9863],
    # 位置4(PAD)
    [ 0.0368, -0.6421,  0.1987,  0.6843, -1.0152, -0.7438, -1.0962,  2.0075],
    # 位置5(PAD)
    [ 0.0032, -0.6645,  0.1036,  0.7821, -0.8037, -0.6042, -0.9873,  2.1548],
    # 位置6(PAD)
    [ 0.3625, -0.8137,  0.2468,  0.6872, -1.0523, -0.6984, -1.0327,  2.1036],
    # 位置7(PAD)
    [ 0.0217, -0.8462,  0.6638,  0.6725, -1.0942, -0.7235, -1.0864,  2.0471]
]
步骤 4 : 引入可学习参数调整(层归一化第三步)

作用:通过缩放γ和平移β恢复特征表达能力,避免标准化过度丢失信息。


参数调整公式

γ:给每个特征维度分配 “权重”,放大有用信息、抑制无关信息。让模型自主学习 “哪些特征更重要”,避免标准化过度抹除特征的个性化差异,平衡 “分布稳定” 和 “信息保留”。
β:将标准化后的特征均值平移到更适合模型学习的位置,避免分布扭曲。给标准化增加 “灵活性”,避免 “一刀切” 的均值归零导致的分布失真,让模型能更好地拟合数据的内在规律。
γ和β在模型未进行任何训练的时候初始值是1和0,随着模型的训练γ和β是会发生变化的,并且γ和β的变化仅存在于模型训练的时候,在模型推理阶段是2个固定的值。

这里我们假设当前γ=1,β=0,所以LN_final = z

第六步 :前馈网络层(Feed Forward)

Transformer 中,多头自注意力机制的核心是建模 token 间的上下文依赖关系,通过计算每个 token 与其他所有 token 的注意力权重,捕捉 “谁与谁相关”“谁更重要” 的全局交互信息(例如 “天气” 与 “今天” 的关联),让模型理解句子的整体逻辑连贯性。但仅靠注意力机制不足以完整建模复杂文本。注意力机制的输出本质上是对输入特征的线性组合,难以捕捉单个 token 所向表达的复杂非线性特征(例如 “好” 这个词在 “天气好” 和 “心情好” 中的细微语义差异),简单的说,人说话的不一定完全连贯,说话的前后逻辑和关注的重点也未必一致,所以单纯的靠多头自注意力是无法处理更加复杂多变的情景的。因此Transformer通过前馈网络为每个 token 的特征进行独立的非线性变换与强化,通过 “升维 - 激活 - 降维” 的结构,为每个 token 注入更丰富的非线性特征表达。这种 “逐 token 独立处理” 的特性,与注意力机制的 “全局交互” 形成互补 , 前者负责深化单个 token 的语义细节,后者负责关联不同 token 的上下文关系。

步骤1 : 升维

将特征矩阵的维数扩大,使模型的参数空间和表达容量变大。低维特征难以捕捉复杂语义,升维后能让模型学习更精细的特征组合。
理论上升维是无限的,但考虑到计算成本与效率,梯度的稳定性,以及过于高维数导致的拟合风险,Transformer原始架构中只是将512维升为了2048维,扩大了4倍。
计算公式:Y1 = LN_final・W1 + b1

这里我们也将上一步的特征维度扩大4倍,假设W1、W2与b1、b2如下

# W1(8×32,每行对应输入1个特征维度,每列对应升维后1个维度)
W1 = [
    [0.0082, 0.0031, -0.0057, 0.0029, 0.0073, 0.0018, -0.0042, 0.0065, 0.0038, -0.0021, 0.0059, -0.0078, 0.0012, 0.0049, -0.0033, 0.0061, -0.0027, 0.0053, -0.0069, 0.0024, 0.0071, -0.0045, 0.0036, -0.0019, 0.0056, -0.0072, 0.0028, 0.0041, -0.0039, 0.0068, -0.0023, 0.0050],
    [-0.0074, 0.0043, 0.0026, -0.0061, 0.0035, -0.0058, 0.0017, -0.0049, 0.0063, -0.0028, 0.0047, 0.0032, -0.0065, 0.0021, 0.0054, -0.0038, 0.0067, -0.0024, 0.0045, -0.0063, 0.0031, 0.0052, -0.0041, 0.0029, -0.0066, 0.0037, -0.0051, 0.0018, 0.0048, -0.0032, 0.0060, -0.0025],
    [0.0068, -0.0039, 0.0052, 0.0019, -0.0064, 0.0027, -0.0055, 0.0033, -0.0047, 0.0062, -0.0031, 0.0058, -0.0023, 0.0046, 0.0030, -0.0067, 0.0025, -0.0050, 0.0038, -0.0060, 0.0022, -0.0053, 0.0040, -0.0026, 0.0059, -0.0034, 0.0061, -0.0020, 0.0044, -0.0056, 0.0028, -0.0042],
    [-0.0053, 0.0062, -0.0028, 0.0045, -0.0037, 0.0051, -0.0019, 0.0043, -0.0059, 0.0032, -0.0048, 0.0024, 0.0057, -0.0030, -0.0046, 0.0021, -0.0054, 0.0036, -0.0042, 0.0058, -0.0029, 0.0041, -0.0033, 0.0055, -0.0027, 0.0049, -0.0038, 0.0063, -0.0040, 0.0035, -0.0052, 0.0023],
    [0.0049, -0.0056, 0.0031, -0.0042, 0.0060, -0.0025, 0.0053, -0.0039, 0.0047, -0.0061, 0.0023, -0.0050, 0.0034, -0.0044, 0.0028, 0.0057, -0.0036, 0.0040, -0.0055, 0.0030, -0.0048, 0.0026, 0.0051, -0.0032, 0.0045, -0.0059, 0.0024, -0.0043, 0.0058, -0.0031, 0.0046, -0.0054],
    [-0.0041, 0.0050, -0.0033, 0.0064, -0.0029, 0.0044, -0.0038, 0.0056, -0.0027, 0.0049, -0.0035, 0.0062, -0.0024, 0.0048, -0.0030, 0.0052, -0.0047, 0.0031, -0.0060, 0.0028, 0.0043, -0.0036, 0.0059, -0.0022, 0.0040, -0.0057, 0.0033, -0.0046, 0.0055, -0.0026, 0.0042, -0.0051],
    [0.0037, -0.0048, 0.0029, -0.0053, 0.0032, -0.0065, 0.0021, 0.0045, -0.0039, 0.0060, -0.0025, 0.0049, -0.0034, 0.0056, -0.0028, 0.0041, -0.0058, 0.0030, -0.0044, 0.0053, -0.0027, 0.0040, -0.0037, 0.0052, -0.0023, 0.0047, -0.0035, 0.0061, -0.0042, 0.0038, -0.0050, 0.0024],
    [-0.0032, 0.0045, -0.0026, 0.0057, -0.0030, 0.0048, -0.0029, 0.0063, -0.0034, 0.0051, -0.0022, 0.0044, -0.0038, 0.0059, -0.0024, 0.0043, -0.0055, 0.0031, -0.0046, 0.0058, -0.0021, 0.0049, -0.0033, 0.0062, -0.0020, 0.0041, -0.0036, 0.0054, -0.0040, 0.0039, -0.0047, 0.0028]
]

# b1(32维,初始全0)
b1 = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]


# W2(32×8,每行对应升维后1个维度,每列对应输出1个特征维度)
W2 = [
    [0.0075, -0.0032, 0.0058, 0.0021, -0.0064, 0.0037, -0.0049, 0.0062],
    [-0.0068, 0.0041, -0.0053, 0.0034, 0.0029, -0.0061, 0.0025, -0.0057],
    [0.0059, -0.0047, 0.0038, -0.0051, 0.0063, -0.0028, 0.0043, -0.0036],
    [-0.0052, 0.0060, -0.0031, 0.0048, -0.0039, 0.0055, -0.0023, 0.0045],
    [0.0046, -0.0058, 0.0027, -0.0044, 0.0051, -0.0033, 0.0061, -0.0029],
    [-0.0040, 0.0053, -0.0024, 0.0039, -0.0047, 0.0028, -0.0059, 0.0032],
    [0.0035, -0.0049, 0.0021, -0.0036, 0.0045, -0.0026, 0.0057, -0.0027],
    [-0.0031, 0.0044, -0.0019, 0.0032, -0.0042, 0.0025, -0.0054, 0.0030],
    [0.0028, -0.0041, 0.0017, -0.0029, 0.0039, -0.0024, 0.0051, -0.0026],
    [-0.0026, 0.0038, -0.0015, 0.0027, -0.0037, 0.0023, -0.0048, 0.0028],
    [0.0024, -0.0035, 0.0013, -0.0025, 0.0034, -0.0022, 0.0045, -0.0025],
    [-0.0022, 0.0032, -0.0011, 0.0023, -0.0031, 0.0021, -0.0042, 0.0027],
    [0.0020, -0.0029, 0.0010, -0.0021, 0.0029, -0.0020, 0.0039, -0.0024],
    [-0.0018, 0.0027, -0.0009, 0.0019, -0.0028, 0.0019, -0.0037, 0.0026],
    [0.0017, -0.0025, 0.0008, -0.0018, 0.0026, -0.0018, 0.0035, -0.0023],
    [-0.0016, 0.0023, -0.0007, 0.0017, -0.0025, 0.0017, -0.0033, 0.0025],
    [0.0015, -0.0022, 0.0006, -0.0016, 0.0024, -0.0016, 0.0031, -0.0022],
    [-0.0014, 0.0021, -0.0005, 0.0015, -0.0023, 0.0015, -0.0029, 0.0024],
    [0.0013, -0.0020, 0.0004, -0.0014, 0.0022, -0.0014, 0.0028, -0.0021],
    [-0.0012, 0.0019, -0.0003, 0.0013, -0.0021, 0.0013, -0.0027, 0.0023],
    [0.0011, -0.0018, 0.0002, -0.0012, 0.0020, -0.0012, 0.0026, -0.0020],
    [-0.0010, 0.0017, -0.0001, 0.0011, -0.0019, 0.0011, -0.0025, 0.0022],
    [0.0009, -0.0016, 0.0001, -0.0010, 0.0018, -0.0010, 0.0024, -0.0019],
    [-0.0008, 0.0015, 0.0000, 0.0009, -0.0017, 0.0009, -0.0023, 0.0021],
    [0.0007, -0.0014, -0.0001, -0.0008, 0.0016, -0.0008, 0.0022, -0.0018],
    [-0.0006, 0.0013, -0.0002, 0.0007, -0.0016, 0.0007, -0.0021, 0.0020],
    [0.0005, -0.0012, -0.0003, -0.0006, 0.0015, -0.0006, 0.0020, -0.0017],
    [-0.0004, 0.0011, -0.0004, 0.0005, -0.0015, 0.0005, -0.0019, 0.0019],
    [0.0003, -0.0010, -0.0005, -0.0004, 0.0014, -0.0004, 0.0018, -0.0016],
    [-0.0002, 0.0009, -0.0006, 0.0003, -0.0014, 0.0003, -0.0018, 0.0018],
    [0.0001, -0.0008, -0.0007, -0.0002, 0.0013, -0.0002, 0.0017, -0.0015],
    [-0.0001, 0.0007, -0.0008, 0.0001, -0.0013, 0.0002, -0.0017, 0.0017],
    [0.0000, -0.0006, -0.0009, 0.0000, -0.0012, 0.0001, -0.0016, 0.0016]
]

# b2(8维,初始全0)
b2 = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]

升维后为

# Y1[0][0] = LN_final[0][0] x W1[0][0] + LN_final[0][1] x W1[1][0] + LN_final[0][2] x W1[2][0] + LN_final[0][3] x W1[3][0] + LN_final[0][4] x W1[4][0] + LN_final[0][5] x W1[5][0] + LN_final[0][6] x W1[6][0] + LN_final[0][7] x W1[7][0] + b1[0]
Y1 = [
    # 位置0(8×32)
    [0.0021, 0.0035, -0.0018, 0.0042, 0.0009, -0.0027, 0.0015, 0.0038, -0.0012, 0.0029, 0.0011, -0.0034, 0.0008, 0.0025, -0.0019, 0.0032, -0.0014, 0.0023, -0.0031, 0.0017, 0.0036, -0.0022, 0.0020, -0.0010, 0.0028, -0.0037, 0.0013, 0.0026, -0.0024, 0.0039, -0.0016, 0.0022],
    # 位置1(8×32)
    [0.0025, 0.0039, -0.0021, 0.0047, 0.0012, -0.0031, 0.0018, 0.0043, -0.0015, 0.0033, 0.0014, -0.0038, 0.0010, 0.0029, -0.0022, 0.0036, -0.0017, 0.0026, -0.0035, 0.0020, 0.0041, -0.0025, 0.0023, -0.0012, 0.0032, -0.0041, 0.0016, 0.0030, -0.0027, 0.0044, -0.0019, 0.0025],
    # 位置2(8×32)
    [0.0019, 0.0031, -0.0016, 0.0038, 0.0007, -0.0023, 0.0013, 0.0034, -0.0010, 0.0026, 0.0009, -0.0030, 0.0006, 0.0022, -0.0017, 0.0028, -0.0012, 0.0020, -0.0027, 0.0015, 0.0032, -0.0019, 0.0018, -0.0009, 0.0025, -0.0033, 0.0011, 0.0023, -0.0021, 0.0035, -0.0014, 0.0019],
    # 位置3(8×32)
    [0.0022, 0.0036, -0.0019, 0.0043, 0.0010, -0.0028, 0.0016, 0.0039, -0.0013, 0.0030, 0.0012, -0.0035, 0.0009, 0.0026, -0.0020, 0.0033, -0.0015, 0.0024, -0.0032, 0.0018, 0.0037, -0.0023, 0.0021, -0.0011, 0.0029, -0.0038, 0.0014, 0.0027, -0.0025, 0.0040, -0.0017, 0.0023],
    # 位置4(PAD,8×32)
    [0.0023, 0.0037, -0.0020, 0.0044, 0.0011, -0.0029, 0.0017, 0.0040, -0.0014, 0.0031, 0.0013, -0.0036, 0.0010, 0.0027, -0.0021, 0.0034, -0.0016, 0.0025, -0.0033, 0.0019, 0.0038, -0.0024, 0.0022, -0.0012, 0.0030, -0.0039, 0.0015, 0.0028, -0.0026, 0.0041, -0.0018, 0.0024],
    # 位置5(PAD,8×32)
    [0.0024, 0.0038, -0.0021, 0.0045, 0.0011, -0.0030, 0.0017, 0.0041, -0.0014, 0.0032, 0.0013, -0.0037, 0.0010, 0.0028, -0.0021, 0.0035, -0.0016, 0.0025, -0.0033, 0.0019, 0.0039, -0.0024, 0.0022, -0.0012, 0.0031, -0.0040, 0.0015, 0.0028, -0.0026, 0.0042, -0.0018, 0.0024],
    # 位置6(PAD,8×32)
    [0.0026, 0.0040, -0.0022, 0.0048, 0.0013, -0.0032, 0.0019, 0.0044, -0.0016, 0.0034, 0.0015, -0.0039, 0.0011, 0.0030, -0.0023, 0.0037, -0.0018, 0.0027, -0.0036, 0.0021, 0.0042, -0.0026, 0.0024, -0.0013, 0.0033, -0.0042, 0.0017, 0.0031, -0.0028, 0.0045, -0.0020, 0.0026],
    # 位置7(PAD,8×32)
    [0.0022, 0.0036, -0.0019, 0.0043, 0.0010, -0.0028, 0.0016, 0.0039, -0.0013, 0.0030, 0.0012, -0.0035, 0.0009, 0.0026, -0.0020, 0.0033, -0.0015, 0.0024, -0.0032, 0.0018, 0.0037, -0.0023, 0.0021, -0.0011, 0.0029, -0.0038, 0.0014, 0.0027, -0.0025, 0.0040, -0.0017, 0.0023]
]
步骤2 : 非线性激活

注意力机制的核心是通过线性变化带来线性加权,因此通过引入激活函数的非线性变换,打破 “线性变换的局限性”,让模型能拟合复杂的非线性语义关系。
Transformer中使用的激活函数是ReLU,但该函数存在 “死亡梯度”的情况,即输入为负时梯度为 0,导致参数永久不更新。所以在目前主流的大模型中很少有使用ReLU函数,而是采用的GELU函数,GELU 比 ReLU 更平滑,能较好避免 ReLU 的 “死亡梯度” 问题,公式为 GELU (x) = 0.5x・[1 + erf (x/√2)],对正值和接近 0 的负值都有响应。因此这一步中我将采用GELU函数来进行计算

ReLU函数公式

x 为函数输入,max(0, x)表示取 “0” 和 “x” 中的较大值。输入大于 0 时,输出等于输入,输入小于等于 0 时,输出为 0。
GELU函数公式

x:函数输入
erf(*):高斯误差函数(Gaussian error function),是统计学中的一个标准函数,积分结果范围为 [-1, 1])
erf函数公式

√2:默认的归一化因子,使输入 x 适配 erf 函数的分布特性。

根据公式计算后的结果为

Y2 = [
    # 位置0(8×32)
    [0.0011, 0.0018, -0.0009, 0.0022, 0.0005, -0.0014, 0.0008, 0.0020, -0.0006, 0.0015, 0.0006, -0.0018, 0.0004, 0.0013, -0.0010, 0.0017, -0.0007, 0.0012, -0.0016, 0.0009, 0.0019, -0.0011, 0.0010, -0.0005, 0.0014, -0.0019, 0.0007, 0.0013, -0.0012, 0.0020, -0.0008, 0.0011],
    # 位置1(8×32)
    [0.0013, 0.0020, -0.0011, 0.0024, 0.0006, -0.0016, 0.0009, 0.0022, -0.0008, 0.0017, 0.0007, -0.0020, 0.0005, 0.0015, -0.0011, 0.0019, -0.0009, 0.0013, -0.0018, 0.0010, 0.0021, -0.0013, 0.0012, -0.0006, 0.0016, -0.0021, 0.0008, 0.0015, -0.0014, 0.0022, -0.0010, 0.0013],
    # 位置2(8×32)
    [0.0010, 0.0016, -0.0008, 0.0020, 0.0004, -0.0012, 0.0007, 0.0017, -0.0005, 0.0013, 0.0005, -0.0015, 0.0003, 0.0011, -0.0009, 0.0014, -0.0006, 0.0010, -0.0014, 0.0008, 0.0016, -0.0010, 0.0009, -0.0004, 0.0013, -0.0017, 0.0006, 0.0012, -0.0011, 0.0018, -0.0007, 0.0010],
    # 位置3(8×32)
    [0.0011, 0.0018, -0.0010, 0.0022, 0.0005, -0.0014, 0.0008, 0.0020, -0.0007, 0.0015, 0.0006, -0.0018, 0.0004, 0.0013, -0.0010, 0.0017, -0.0008, 0.0012, -0.0016, 0.0009, 0.0019, -0.0012, 0.0011, -0.0005, 0.0015, -0.0019, 0.0007, 0.0014, -0.0013, 0.0020, -0.0009, 0.0012],
    # 位置4(PAD,8×32)
    [0.0012, 0.0019, -0.0010, 0.0023, 0.0006, -0.0015, 0.0009, 0.0021, -0.0007, 0.0016, 0.0007, -0.0019, 0.0005, 0.0014, -0.0011, 0.0017, -0.0008, 0.0013, -0.0017, 0.0010, 0.0020, -0.0012, 0.0011, -0.0006, 0.0015, -0.0020, 0.0008, 0.0014, -0.0013, 0.0021, -0.0009, 0.0012],
    # 位置5(PAD,8×32)
    [0.0012, 0.0019, -0.0011, 0.0023, 0.0006, -0.0015, 0.0009, 0.0021, -0.0007, 0.0016, 0.0007, -0.0019, 0.0005, 0.0014, -0.0011, 0.0018, -0.0008, 0.0013, -0.0017, 0.0010, 0.0020, -0.0012, 0.0011, -0.0006, 0.0016, -0.0020, 0.0008, 0.0014, -0.0013, 0.0021, -0.0009, 0.0012],
    # 位置6(PAD,8×32)
    [0.0013, 0.0020, -0.0011, 0.0024, 0.0007, -0.0016, 0.0010, 0.0022, -0.0008, 0.0017, 0.0008, -0.0020, 0.0006, 0.0015, -0.0012, 0.0019, -0.0009, 0.0014, -0.0018, 0.0011, 0.0021, -0.0013, 0.0012, -0.0007, 0.0017, -0.0021, 0.0009, 0.0016, -0.0014, 0.0023, -0.0010, 0.0013],
    # 位置7(PAD,8×32)
    [0.0011, 0.0018, -0.0010, 0.0022, 0.0005, -0.0014, 0.0008, 0.0020, -0.0007, 0.0015, 0.0006, -0.0018, 0.0004, 0.0013, -0.0010, 0.0017, -0.0008, 0.0012, -0.0016, 0.0009, 0.0019, -0.0012, 0.0011, -0.0005, 0.0015, -0.0019, 0.0007, 0.0014, -0.0013, 0.0020, -0.0009, 0.0012]
]
步骤3 : 模拟失活(训练阶段)

该步骤只有在训练时才会有,因为训练时会模拟 “特征缺失”的情况,迫使模型学习更鲁棒的特征,随机将部分特征值置 0(默认失活率为10%),防止模型过度依赖某几个特征,避免过拟合。推理时关闭该阶段,保留全部特征。
鲁棒性:核心是提高抗干扰能力,判断事务不依赖单一的条件,例如识别苹果,不单一的通过红色去识别。为了增加鲁棒性,会随机屏蔽部分特征,让判断的方式变得很多。

这里我随机将Y2中的数据置为0,用于体现该步骤

Y3 = [
    # 位置0(8×32)
    [0.0011, 0.0018, -0.0009, 0.0000, 0.0005, -0.0014, 0.0008, 0.0020, -0.0006, 0.0015, 0.0006, -0.0018, 0.0004, 0.0013, -0.0010, 0.0017, -0.0007, 0.0012, -0.0016, 0.0009, 0.0019, -0.0011, 0.0010, -0.0005, 0.0014, -0.0019, 0.0007, 0.0000, -0.0012, 0.0020, -0.0008, 0.0011],
    # 位置1(8×32)
    [0.0013, 0.0020, -0.0011, 0.0024, 0.0006, -0.0016, 0.0009, 0.0022, -0.0008, 0.0017, 0.0007, -0.0020, 0.0005, 0.0000, -0.0011, 0.0019, -0.0009, 0.0013, -0.0018, 0.0010, 0.0021, -0.0013, 0.0012, -0.0006, 0.0016, -0.0021, 0.0008, 0.0015, -0.0014, 0.0022, -0.0010, 0.0013],
    # 位置2(8×32)
    [0.0010, 0.0016, -0.0008, 0.0020, 0.0004, -0.0012, 0.0007, 0.0017, -0.0005, 0.0013, 0.0005, -0.0015, 0.0003, 0.0011, -0.0009, 0.0014, -0.0006, 0.0010, -0.0014, 0.0008, 0.0000, -0.0010, 0.0009, -0.0004, 0.0013, -0.0017, 0.0006, 0.0012, -0.0011, 0.0018, -0.0007, 0.0010],
    # 位置3(8×32)
    [0.0011, 0.0018, -0.0010, 0.0022, 0.0005, -0.0014, 0.0008, 0.0020, -0.0007, 0.0015, 0.0006, -0.0018, 0.0004, 0.0013, -0.0010, 0.0017, -0.0008, 0.0012, -0.0016, 0.0009, 0.0019, -0.0012, 0.0011, -0.0005, 0.0000, -0.0019, 0.0007, 0.0014, -0.0013, 0.0020, -0.0009, 0.0012],
    # 位置4(PAD,8×32)
    [0.0012, 0.0019, -0.0010, 0.0023, 0.0006, -0.0015, 0.0009, 0.0021, -0.0007, 0.0016, 0.0007, -0.0019, 0.0005, 0.0014, -0.0011, 0.0017, -0.0008, 0.0013, -0.0017, 0.0010, 0.0020, -0.0012, 0.0011, -0.0006, 0.0015, -0.0020, 0.0008, 0.0014, -0.0013, 0.0000, -0.0009, 0.0012],
    # 位置5(PAD,8×32)
    [0.0012, 0.0019, -0.0011, 0.0023, 0.0006, -0.0015, 0.0009, 0.0021, -0.0007, 0.0016, 0.0007, -0.0019, 0.0005, 0.0014, -0.0011, 0.0018, -0.0008, 0.0013, -0.0017, 0.0010, 0.0020, -0.0012, 0.0011, -0.0006, 0.0016, -0.0020, 0.0000, 0.0014, -0.0013, 0.0021, -0.0009, 0.0012],
    # 位置6(PAD,8×32)
    [0.0013, 0.0020, -0.0011, 0.0024, 0.0007, -0.0016, 0.0010, 0.0022, -0.0008, 0.0017, 0.0008, -0.0020, 0.0006, 0.0015, -0.0012, 0.0019, -0.0009, 0.0014, -0.0018, 0.0011, 0.0021, -0.0013, 0.0012, -0.0007, 0.0017, -0.0021, 0.0009, 0.0016, -0.0014, 0.0023, -0.0010, 0.0000],
    # 位置7(PAD,8×32)
    [0.0011, 0.0018, -0.0010, 0.0022, 0.0005, -0.0014, 0.0008, 0.0020, -0.0007, 0.0015, 0.0006, -0.0018, 0.0004, 0.0013, -0.0010, 0.0017, -0.0008, 0.0012, -0.0016, 0.0009, 0.0000, -0.0012, 0.0011, -0.0005, 0.0015, -0.0019, 0.0007, 0.0014, -0.0013, 0.0020, -0.0009, 0.0012]
]
步骤4 : 降维

升维是为了 “扩大容量”,降维是为了 “兼容流程”,最终在不改变维度的前提下,强化了单个 token 的特征表达。将 升后高维特征映射回原本的维数,恢复与输入一致的维度,适配后续的残差连接。
计算公式:FFN_out = Y3・W2 + b2

FFN_out = [
    # 位置0
    [0.0082, 0.0075, 0.0091, 0.0068, 0.0053, 0.0079, 0.0042, 0.0098],
    # 位置1
    [0.0095, 0.0083, 0.0102, 0.0076, 0.0049, 0.0087, 0.0038, 0.0105],
    # 位置2
    [0.0078, 0.0069, 0.0087, 0.0063, 0.0051, 0.0075, 0.0045, 0.0093],
    # 位置3
    [0.0081, 0.0072, 0.0089, 0.0065, 0.0047, 0.0078, 0.0041, 0.0096],
    # 位置4(PAD)
    [0.0079, 0.0071, 0.0088, 0.0064, 0.0048, 0.0076, 0.0043, 0.0094],
    # 位置5(PAD)
    [0.0083, 0.0074, 0.0092, 0.0067, 0.0050, 0.0080, 0.0040, 0.0099],
    # 位置6(PAD)
    [0.0085, 0.0077, 0.0094, 0.0069, 0.0052, 0.0082, 0.0039, 0.0101],
    # 位置7(PAD)
    [0.0080, 0.0073, 0.0090, 0.0066, 0.0049, 0.0077, 0.0042, 0.0097]
]
第七步 : 残差连接&层归一化(Add&Norm)

该步骤的执行过程与第一次完全一致,执行的目标也相同,均为“保全关键信息 + 稳定特征分布”—— 残差连接负责保留前置层的核心特征不丢失,层归一化负责减少特征差异、让输出标准化,二者协同保障计算结果的稳定性,但因前置步骤的功能不同,具体意义有所差异:
多头自注意力步骤的核心作用是计算 token 之间的关联关系,确认原文中的语义权重。但注意力子层的加权求和可能导致两个问题:一是权重过度均匀(掩盖 token 的原始语义差异),二是权重波动过大(导致特征值范围失控),最终造成输出不稳定。因此,第一次残差连接 & 层归一化的意义是:通过 “注意力子层输出 + 编码器原始输入” 的残差连接,保留原始词向量、位置信息等基础特征,避免原始语义因全局交互计算而丢失,再通过层归一化稳定特征分布,为后续前馈网络提供平稳输入。
前馈网络层的核心作用是在全局语义权重的基础上,强化单个 token 的个体特征,突出核心 token。但前馈网络是“逐 token 独立处理”,缺乏全局交互逻辑,可能导致两个风险:一是个体特征过度强化,掩盖注意力子层建立的全局依赖关系,二是非线性激活和升维 / 降维操作可能导致特征离散、差异变大。因此,第二次残差连接 & 层归一化的意义是:通过“注意力子层的权重输出 + 前馈网络层的输出”的残差连接,增强全局关系,减少全局依赖被个体特征覆盖的可能性,再通过层归一化稳定特征分布,为下一个编码器层提供标准化输入,保障深层模型计算的稳定性。

残差连接的计算结果为

residual = [
   [0.11, 0.21, 0.31, 0.41, 0.51, 0.61, 0.70, 0.81],# 位置0 →  [0.10+0.0082, 0.20+0.0075, 0.30+0.0091, 0.40+0.0068, 0.50+0.0053, 0.60+0.0079, 0.70+0.0042, 0.80+0.0098]
    [0.21, 0.31, 0.41, 0.51, 0.60, 0.71, 0.80, 0.11],# 位置1 → [0.20+0.0095, 0.30+0.0083, 0.40+0.0102, 0.50+0.0076, 0.60+0.0049, 0.70+0.0087, 0.80+0.0038, 0.10+0.0105]
    [0.31, 0.41, 0.51, 0.61, 0.71, 0.81, 0.10, 0.21],# 位置2 → [0.30+0.0078, 0.40+0.0069, 0.50+0.0087, 0.60+0.0063, 0.70+0.0051, 0.80+0.0075, 0.10+0.0045, 0.20+0.0093]
    [0.41, 0.51, 0.61, 0.71, 0.80, 0.11, 0.20, 0.31],# 位置3 → [0.40+0.0081, 0.50+0.0072, 0.60+0.0089, 0.70+0.0065, 0.80+0.0047, 0.10+0.0078, 0.20+0.0041, 0.30+0.0096], 
    [0.51, 0.61, 0.71, 0.81, 0.10, 0.21, 0.30, 0.41],# 位置4 → [0.50+0.0079, 0.60+0.0071, 0.70+0.0088, 0.80+0.0064, 0.10+0.0048, 0.20+0.0076, 0.30+0.0043, 0.40+0.0094]
    [0.61, 0.71, 0.81, 0.11, 0.21, 0.31, 0.40, 0.51],# 位置5 → [0.60+0.0083, 0.70+0.0074, 0.80+0.0092, 0.10+0.0067, 0.20+0.0050, 0.30+0.0080, 0.40+0.0040, 0.50+0.0099]
    [0.71, 0.81, 0.11, 0.21, 0.31, 0.41, 0.50, 0.61], # 位置6 →[0.70+0.0085, 0.80+0.0077, 0.10+0.0094, 0.20+0.0069, 0.30+0.0052, 0.40+0.0082, 0.50+0.0039, 0.60+0.0101]
    [0.81, 0.11, 0.21, 0.31, 0.41, 0.51, 0.60, 0.71]   # 位置7 → [0.80+0.0080, 0.10+0.0073, 0.20+0.0090, 0.30+0.0066, 0.40+0.0049, 0.50+0.0077, 0.60+0.0042, 0.70+0.0097]   
]

层归一化的计算结果为

encoder_final = [
    # 位置0:μ≈0.48,σ≈0.24 → 归一化后
    [-1.54, -1.13, -0.71, -0.29, 0.12, 0.54, 0.96, 1.38],
    # 位置1:μ≈0.48,σ≈0.24 → 归一化后
    [-1.13, -0.71, -0.29, 0.12, 0.54, 0.96, 1.38, -1.54],
    # 位置2:μ≈0.48,σ≈0.24 → 归一化后
    [-0.71, -0.29, 0.12, 0.54, 0.96, 1.38, -1.54, -1.13],
    # 位置3:μ≈0.48,σ≈0.24 → 归一化后
    [-0.29, 0.12, 0.54, 0.96, 1.38, -1.54, -1.13, -0.71],
    # 位置4(PAD):μ≈0.48,σ≈0.24 → 归一化后(后续会被掩码)
    [0.12, 0.54, 0.96, 1.38, -1.54, -1.13, -0.71, -0.29],
    # 位置5(PAD):μ≈0.48,σ≈0.24 → 归一化后
    [0.54, 0.96, 1.38, -1.54, -1.13, -0.71, -0.29, 0.12],
    # 位置6(PAD):μ≈0.48,σ≈0.24 → 归一化后
    [0.96, 1.38, -1.54, -1.13, -0.71, -0.29, 0.12, 0.54],
    # 位置7(PAD):μ≈0.48,σ≈0.24 → 归一化后
    [1.38, -1.54, -1.13, -0.71, -0.29, 0.12, 0.54, 0.96]
]
第八步:多层循环

当前馈网络层之后的Add&Norm执行完成后,Transformer架构中编码器层的一次完整的计算单元就完成了,接下来将会把计算结果作为新的输出,再一次进行相同计算单元的计算,直到满足模型架构设计的层数,在Transformer架构原文中编码器层的堆叠层数为6,这里的6是模型的超参数,意味着“多头自注意力层->残差连接&层归一化->前馈网络层->残差连接&层归一化”要执行6次,除了第一次的输入是原始的词向量矩阵以外,所有的输入都是前一层的输出。
设计多层堆叠计算的意义是让模型能够更加深入的去理解原文的语义,确保理解的准确性。
编码器层的最终输出将会作为解码器层中多头自注意力层中的计算K、V的原始输入特征,参与到解码器层的计算中,协助模型完整内容的生成。

这里我们假定最终进行了6层的计算后,编码其层的最终输入结果如下

output = [
   [-1.54, -1.13, -0.71, -0.29, 0.12, 0.54, 0.96, 1.38],
   [-1.13, -0.71, -0.29, 0.12, 0.54, 0.96, 1.38, -1.54],
   [-0.71, -0.29, 0.12, 0.54, 0.96, 1.38, -1.54, -1.13],
   [-0.29, 0.12, 0.54, 0.96, 1.38, -1.54, -1.13, -0.71],
   [0.12, 0.54, 0.96, 1.38, -1.54, -1.13, -0.71, -0.29],
   [0.54, 0.96, 1.38, -1.54, -1.13, -0.71, -0.29, 0.12],
   [0.96, 1.38, -1.54, -1.13, -0.71, -0.29, 0.12, 0.54],
   [1.38, -1.54, -1.13, -0.71, -0.29, 0.12, 0.54, 0.96]
]
**编码器层最终的输出是一个综合用户输入原文语义的特征矩阵,这个矩阵能体现每个词自身的各个维度以及维度在原文语义的权重得分,以及原文中词与词之间的关联关系**
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容