搞懂Transformer

Transformer之前

在2017年google的论文《Attention is All you need》出来之前,NLP领域的主流技术是RNN(循环神经网络)为代表的序列模型。

RNN能够处理序列数据(如文本,音频),但要真正理解一句话,模型需要记住很早之前的信息。核心问题是 长距离依赖。

LSTM 和 GRU 可以理解为都是基于RNN上的优化,但是依然无法根治问题 :

  • 串行计算的弊端: 必须一个字一个字地按顺序处理,无法并行。要理解第t个词,必须等前t-1个词都算完。这极大限制了训练速度和模型规模。
  • 记忆力”依然有限:虽然比RNN强,但对于段落、篇章级别的长距离依赖(比如一本小说开头埋的伏笔,在500页后揭晓),LSTM依然会“遗忘”。

所以Transformer的一个革命性的观点提出来就是说: 不要再一个字一个字读了,同时看所有的字把。

Transformer一个关键特性就是注意力机制 ,用一句话概括,就是让每个词去看一眼其他词,然后自己决定--- 谁跟我关系最大,我就多关注谁。

  1. 不再依赖“位置顺序”来传递信息:RNN是靠“相邻”逐步传递的,距离越远信息越弱。而注意力机制允许任意两个词直接“对话”,无论它们隔了多远。
  2. 每个词都在“全局语境”中更新自己:一个词的最终表示,不再是“前面所有词的累积”,而是整个句子中所有词信息的加权融合。重要的词(相关性高)贡献大,不重要的词(相关性低)贡献小。
  3. 并行计算成为可能:因为所有词之间的“两两关系”可以同时计算(用矩阵乘法一次性完成),不需要等待前一步的结果。这正好释放了GPU并行计算的潜力。

自注意力机制

讲到这里,我有必要推后一步说清楚:啥叫每个字都看其他词? 啥叫更新自己?

在一个Transformer模型里,计算机不认识“字”,它认识到都是数字,所以我们得先把句子,切成小块,叫做token,本质上就是一个向量。

我们以 “他在银行存钱”这句话来解释:

比如“银行”这个词,在模型内部不是一个汉字,而是一个装满数字的列表

银行 = [0.8, 0.1, 0.3, -0.2, 0.5, ...] (假设有512个数字)

这个列表里的每个数字,可以理解成这个词在某个“潜在维度”上的属性值。但这些数字具体代表什么(比如第3个数字是“金融机构程度”还是“抽象程度”),是模型自己学出来的,我们不直接解释。

什么是“看”

当我们说“词A去看词B”,在数学上其实是在做一件事:

用词A的向量,去和词B的向量,计算一个“相关性分数”。

算出相关性分数之后,每个词要做一件事:根据这些分数,从所有词那里“收集信息”,调整自己的向量。

这里也有个问题:用什么标准来判断两个词是否相关?

比如“银行”和“存”相关,但“银行”和“在”不相关。模型需要一种机制,让每个词能表达“我在找什么”,同时每个词能表达“我是什么”。

Q、K、V就是用来解决这个问题的三套向量。

Q(Query,查询):我在找什么

每个词都会生成一个Q向量,代表它主动发出的查询

比如“银行”的Q可能是“我在找跟金融机构相关的动作或实体”。带着这个Q,它去问所有其他词:“你们谁跟这个相关?”

Q就是词作为“查询者”时的身份。

K(Key,键):我是什么标签

每个词也会生成一个K向量,代表它能被匹配到的标签

比如“存”的K可能是“我是一个动作词”。当“银行”的Q来匹配时,发现这个K和自己要找的东西很匹配,就给出高分。

K就是词作为“被查询者”时的身份标签。

V(Value,值):我能贡献什么

每个词还会生成一个V向量,代表它真正可以贡献出去的内容

比如“存”的V是一段表示“存入、放置”语义的数字向量。当“银行”通过Q和K匹配认定“存”跟自己相关时,它就从“存”的V里取信息。

V就是词作为“信息源”时贡献的内容。

可能你想问,为啥我要区分K和V? 好像这两个是一样的? 这里就是Transformer设计的一个精妙之处。

想象你在图书馆找一本关于“人工智能”的书。

  • K(Key) = 书的标签/索引卡。上面写着“人工智能、机器学习、深度学习”。你通过扫描这些标签来判断这本书跟你找的主题是否相关。
  • V(Value) = 书的实际内容。那几百页的文字、知识、观点。

所以 :K是用来判断“相不相关”,V是用来提供“具体是什么”。两者解耦,各司其职。

关键区别:

  • 你判断一本书是否相关,只需要看它的标签(K),不需要把整本书读完。

  • 但当你决定要借这本书之后,你真正拿走的是它的内容(V)

1: 计算注意力权重

用算出来的相关性分数后,经过softmax运算,变成一组加起来等于1的概率

原始分数:  [他:0.15, 在:0.05, 银行:0.50, 存:0.25, 钱:0.05]
Softmax后: [他:0.20, 在:0.05, 银行:0.45, 存:0.25, 钱:0.05]  (假设归一化后)

如果句子有5个词,那么注意力权重就是一个 5×5 的矩阵

银行
0.60 0.05 0.15 0.15 0.05
0.10 0.50 0.20 0.10 0.10
银行 0.20 0.05 0.45 0.25 0.05
0.25 0.05 0.20 0.40 0.10
0.10 0.10 0.10 0.30 0.40
以“银行”这一行为例:
  • 银行 → 银行:0.45(看自己)
    • 权重最大。表示当“银行”要更新自己时,最依赖的信息来自它自己。它保留了自己的核心属性(比如“金融机构”)。
  • 银行 → 存:0.25(看“存”)
    • 权重第二高。因为“银行”和“存”在语义上高度相关(存钱的行为发生在银行)。模型学到了这种关系。
  • 银行 → 他:0.20(看“他”)
    • 权重中等。因为“他”是动作的发出者,模型需要知道“谁在银行存钱”。
  • 银行 → 在:0.05(看“在”)
    • 权重很低。“在”只是一个位置介词,对理解“银行”作为金融机构帮助不大。
  • 银行 → 钱:0.05(看“钱”)
    • 权重也低。虽然“钱”和“存”相关,但“银行”本身已经隐含了这个关系,不需要过度关注。

2、取出每个词的value

第一步在于每个词看了其他所有词的并且计算相关性分数。第二步就是真实地按权重取每个词的value加权求和并计算更新自己的向量了。

这里就是用V向量。

整体流程图;

句子中的每个词
     ↓
生成各自的 Q、K、V
     ↓
【步骤1】每个词的Q 与 所有词的K 做点积 → 原始分数 → Softmax → 注意力权重(5×5矩阵)
     ↓
【步骤2】注意力权重 × 所有词的V → 加权求和 → 每个词的新向量
     ↓
每个词的新向量(还是 512 维,但内容已融合上下文)

位置编码

你现在已经理解了自注意力机制:每个词同时看所有词,计算相关性,更新自己。

但这里有一个致命问题:这个机制本身是不关心顺序的

考虑两个句子:

  • “我爱你”
  • “你爱我”

如果把它们拆成token(我、爱、你),两个句子的词集合完全一样。在纯粹的自注意力机制下,“我”和“你”的关系是对称的,模型分不清到底是谁爱谁。

这意味着: Transformer如果不做任何处理,会把“我爱你”和“你爱我”当成一样的句子。显然不行。

解决方案:给每个词加上位置信息

我们需要一种方式,让模型知道每个词在句子里的位置

做法很简单:给每个词的输入向量,加上一个“位置向量”。

加完之后,每个词的向量里就同时有两部分信息:这个词是什么意思 + 这个词在第几位。这是进入 Encoder 流水线之前必须完成的一步——否则后面所有层都无法区分词序。

多头注意力

上面我们讲清楚了单头自注意力:每个词生成 Q、K、V,算一遍注意力,更新自己的向量。

但只用一个注意力头,有一个明显局限:

一句话里,词与词之间的关系不止一种。

还是以他在银行存钱为例:

  • 银行需要关注存——这是动作关系
  • 存需要关注钱——这是对象关系
  • 他需要关注存——这是主谓关系

单头注意力的问题: 一组Q、K、V只能学到一种“平均”的关系模式。它会把所有关系混在一起,无法同时捕捉多种不同类型的关联。

解决方案:多组Q、K、V并行计算

多头注意力的想法很简单:同时用多组不同的Q、K、V,每组独立计算一次注意力。 每组叫做一个“头”(Head)。常见的头数是8、12、16等。

假设每个词的向量维度是 512(这是 d_model)。

多头注意力不会用 512 维做一次大注意力,而是:

  1. 把 512 维切成 8 份(假设 8 个头),每份 64 维(这是 d_k
  2. 每个头独立做一遍 Q/K/V 注意力,各看各的
  3. 8 个头的结果拼回来,再通过一个线性层融合

用图来理解:

输入向量 (512维)
     ↓
切成 8 个头,每个头 64 维
     ↓
┌─────────┬─────────┬─────────┬─ ... ─┬─────────┐
│  头1    │  头2    │  头3    │         │  头8    │
│ 独立算  │ 独立算  │ 独立算  │         │ 独立算  │
│ 注意力  │ 注意力  │ 注意力  │         │ 注意力  │
└─────────┴─────────┴─────────┴─ ... ─┴─────────┘
     ↓
拼接成 512 维 → 线性变换 → 输出

每个头在学什么?

我们不需要人工指定头1看语法、头2看语义——这是模型自己学出来的。但训练完成后,研究者确实观察到不同头会偏向不同模式,比如:

头(举例) 可能关注的关系
头1 相邻词、语法结构(如在和银行)
头2 语义搭配(如银行和存)
头3 远距离指代(如他和后面的动作)

关键点: 8 个头并行计算,最后合并。计算量增加了,但 GPU 很擅长这种并行,所以实际训练仍然高效。

和单头注意力的公式关系

单头注意力:

Attention(Q, K, V) = softmax(QK^T / √d_k) · V

多头注意力:

MultiHead(Q, K, V) = Concat(head_1, head_2, ..., head_h) · W^O

其中 head_i = Attention(Q·W_i^Q, K·W_i^K, V·W_i^V)
  1. 多个头 = 多种看词视角同时工作
  2. 每个头维度更小(512 → 8×64),分开算再合并
  3. 输出还是和输入一样长(512 维),可以传给下一层

回到银行这个词:经过 8 个头之后,它的新向量里同时包含了跟存的关系跟他的关系跟钱的关系等信息——比单头更丰富。

在 Encoder 的一层里,多头注意力就是子层 ①:所有词交流完毕,输出还是 [词数, 512] 的形状,交给下一个子层。

前馈网络 FFN

注意力机制做完之后,每个词都从其他词收集了信息,更新了自己的向量。

但更新完的向量,还只是其他词信息的加权混合。接下来还需要一步:让每个词独立地对这份混合信息做加工,提取更深的特征。

这就是 FFN(前馈网络) 的用处。

但在讲 FFN 之前,得先把一个前置知识说清楚:全连接层

全连接层:神经网络最基础的构件

全连接层是在 Transformer 之前就有的,神经网络里最基础的构件之一。Transformer 借用了这个已有概念,作为自己架构的一个组件。

它的任务很简单:把输入的数字列表,转换成另一个长度的数字列表。

假设输入有 3 个数字 [x1, x2, x3],输出想要 2 个数字 [y1, y2]

全连接层会做这样两件事:

  1. 每个输出都等于所有输入的加权和(各自乘一个权重,再加起来)
  2. 每个输出有自己独立的一套权重

Q:为啥要转换列表长度?

因为复杂问题里,512 维的运算空间往往不够。要先升维到更高维的计算空间,才有足够余地展开、组合和推演;推演完再降维回 512。

在 Transformer 里,每个词是一个向量,长度是 512(这个数字叫 d_model)。注意力机制的输出要求每个词的向量还是 512 维,所以 FFN 在运算过程中需要把 512 变成 2048,再变回 512。

Q:全连接层如何做到转换长度?

本质上是矩阵乘法

全连接层在数学上就是:

输出向量 = 输入向量 × 权重矩阵 + 偏置

输入是 512 维、输出想变成 2048 维,就乘一个 512 × 2048 的权重矩阵;从 2048 降回 512,就再乘一个 2048 × 512 的矩阵。长度变不变,取决于权重矩阵的形状。

Q:全连接层能做什么?

  • 线性变换、特征组合
  • 把输入各维度按权重重新混合
  • 放大、缩小、筛选、组合信息

FFN 的结构:两层全连接 + 一个激活函数

Transformer里的前馈网络,就是两个全连接层叠起来,中间夹一层激活函数

全连接层1(升维)→ 激活函数 → 全连接层2(降维)

用刚才的数字来表达:

输入 x (512维)
     ↓
全连接层1:512 → 2048      ← 升维,展开思考空间
     ↓
ReLU / GELU 激活            ← 引入非线性
     ↓
全连接层2:2048 → 512       ← 降维,压回标准长度
     ↓
输出 (512维)

写成公式就是:

FFN(x) = 全连接层2( 激活( 全连接层1(x) ) )

为什么中间要加激活函数?

全连接层本身是线性变换。如果两层全连接之间不加激活函数,两层可以合并成一层,深度就没有意义。

激活函数(如 ReLU、GELU)的作用 :

  • 引入非线性
  • ReLU 会把负数变成 0,相当于关掉不相关的特征

    关于 ReLU 为什么把负数变 0、以及它如何让深度网络变得可行,详见附录。

从全局看 FFN 和 ReLU 的作用

上面提到,FFN 的作用是让神经网络更深,那它是怎么做到的?

关键在于非线性 + 升维。

一、非线性让特征可以组合 如果没有 ReLU,两层线性变换实际上是合并成一层:

W₂·(W₁·x + b₁) + b₂ = (W₂·W₁)·x + (W₂·b₁ + b₂)

二、 ReLU

  • ReLU 在中间插了一道“弯折”(负数变0),让两层无法合并。非线性使网络具备了“组合”能力: 第一层提取的中间特征,可以被第二层以更灵活的方式重组。
  • ReLU 的筛选让特征更“纯净”
  • ReLU 把负数变成0。负值在神经网络里通常表示“相反特征”或“不相关”。

如果不变成0,正负信号会相互抵消,信息丢失。ReLU 之后,只有正向激活的特征继续传递,负向的被关掉。每一层都在做一次“提纯”——去掉不相关的,保留有用的。

三、升维给了特征“展开空间” FFN 先把维度从512放大到2048。为什么要放大? 想象你要分析一个人的性格(512个原始特征)。如果只给你512个“中间特征”的空间,你可能只能做简单的线性组合。但如果给你2048个空间,你可以:

  • 让不同的神经元关注不同的特征组合
  • 有的神经元专门检测“动词+名词”模式
  • 有的神经元专门检测“主语+位置”模式 升维 = 给模型更多“神经元”去学习不同类型的特征组合。

残差连接 + 层归一化

每个子层(多头注意力、FFN)算完之后,都要过同一套基础设施:残差连接层归一化

它们不直接参与理解语义,但决定了 Transformer 能不能训得深、训得稳

残差连接 (Add)

前面的多头注意力是让每个词交互信息,前馈网络是让每个词独立加工信息。但是这里有两个问题

第一个问题: Transformer 是一层层叠起来的,每一层都会对信息做变换,经过多层变换之后,最初输入的信息(如银行),有可能已经被变换成很浅的语义了。 极端的例子是,某一层输出全变成了0,传到后面,信息全都丢失了。

残差连接就是解决这个问题的,让信息有一条直达通道,绕开每层的变换。

公式也很简单: 输出 = 输入 + 对这一层输入做的变换

输入 x ──────────────────────┐
   |                          |
   |──→ 变换(注意力/前馈)──→ F(x)
   |                          |
   └────────── + ─────────────┘
                  ↓
              输出 = x + F(x)
  1. 保留原始信息:注意力可能漏掉一些东西,残差保证原来的银行不会完全消失
  2. 梯度更好传:网络很深时,纯堆叠层会导致训练困难;加了短路通道,梯度能直接往回传
  3. 学增量更容易:子层只需要学要在原来基础上改什么,而不是从零重写整个向量

层归一化 (Norm)

残差连接解决了“信息是否还在”的问题。第二个问题是:信息的尺度会变化。

向量里的数字如果忽大忽小,训练很容易发散。层归一化(Layer Normalization,简称 LayerNorm)就是在每个词自己的向量内部做标准化。

把一串数字调整到均值 0、方差 1 附近,再乘以一个可学习的缩放、加上可学习的偏移,让模型自己决定最终尺度。

LayerNorm(x) = γ · (x - mean) / std + β  # γ和 β 是模型学出来的参数 

残差连接和层归一化合在一起,叫做 Add & Norm。在 Encoder 的每一层里要用两次——多头注意力后面一次,FFN 后面一次。它不负责理解语义,但保证整条流水线叠很多层之后仍然训得动、信息传得下去。

Add & Norm

在 Transformer 的架构图和论文里, 经常看到 Add & Norm  都是一起写的,因为这两者解决的问题是互补的

  • Add(残差连接) 确保原始信息能直接传过去,不被层层变换稀释
  • Norm(层归一化) 确保相加后的数值尺度稳定,不会太大或太小

残差连接把原始信息和变换后的信息加在一起,数值范围会变大。层归一化跟在后面,正好把数值拉回稳定范围,让下一层的输入是“干净”的。

为什么顺序是 Add 先、Norm 后?

这是原始 Transformer 论文的顺序(Post-Norm):

输出 = LayerNorm(x + F(x))

1. 先做残差相加(Add)
    
2. 再做层归一化(Norm)

原因是相加后的数值可能过大,立刻做归一化把它拉回稳定范围,再传给下一层。

补充:  后来的模型(如 GPT、BERT、LLaMA)发现先归一化、再做变换(Pre-Norm)训练更稳定,就改成了 输出 = x + F(LayerNorm(x))

Encoder

讲到这里,我们已经搞清楚了很多基础的组件,是时候引入Encoder了。

Encoder 在 Transformer 的作用就是 : 读进一整句输入,让每个词都带着 懂上下文 的向量表示

我们之前学到的拼在一起,就是Encoder的一个层

一层Encoder = 多头注意力 + 残差+层归一化 + 前馈网络 + 残差+层归一化

Encoder = N个这样的层堆叠在一起。

原始 Transformer 的 Encoder 默认 6 层(现在的大模型层数更多,几十层、上百层都有)。

每一层在干什么?

层数(大致趋势) 可能学到的东西
浅层(1–2层) 局部搭配、相邻词关系、基本语法
中层(3–4层) 短语结构、语义组合
深层(5–6层+) 更抽象的语义、远距离依赖、篇章级信息

Decoder

Decoder 的作用

如果说 Encoder 的任务是“读懂”输入,那 Decoder 的任务就是“生成”输出。

在翻译任务中:

  • Encoder 读中文“他在银行存钱” → 输出一组语境化向量
  • Decoder 拿着这组向量 → 逐个生成英文单词 “He” → “deposits” → “money” → “in” → “the” → “bank”

Decoder 其实和Encoder很像,也是由 N 个层堆叠而成的(原始 Transformer 默认也是 6 层)。 只是多了两个: 第一个多头注意力加上了掩码 和 交叉注意力

一层 Decoder = 
   Masked 多头注意力  + 残差+层归一化 ——>
   + 交叉注意力(Cross Attention) + 残差+层归一化 
   + 前馈网络  FFN   + 残差+层归一化

掩码

还是拿翻译来为例,Encoder负责理解的时候,它本来就可以同时看所有词:

但在 Decoder 里,翻译是从左到右一个一个进行的

  • 生成第 1 个词时,不能看到第 2、3、4… 个词(因为它们还没生成)
  • 生成第 2 个词时,只能看到第 1 个词和自己

Masked 注意力就是用来实现这个限制的:

在计算注意力权重时,把“未来词”的权重设为 -∞(经过 Softmax 后变成 0)。这样当前词就只能“看到”它自己和它左边的词,看不到右边的“未来词”。

交叉注意力

交叉注意力做的事情:Decoder 的每个词,去看 Encoder 输出的所有向量。

为什么需要它?

Masked 注意力解决的是 Decoder 内部的问题——生成时不能偷看未来。

但翻译还有另一个问题:Decoder 在生成英文时,得知道中文原句在说什么

Encoder 已经把他在银行存钱读完了,输出了 5 个带上下文的向量。Decoder 生成 "bank" 的时候,不能光靠已经生成的 "He deposits money in the",还得回头查一下:中文里的银行在哪、什么意思。

交叉注意力就是 Encoder 和 Decoder 之间的桥梁。

和自注意力有什么不同?

前面讲的自注意力(包括 Masked 注意力),Q、K、V 都来自同一侧

类型 Q 从哪来 K、V 从哪来 在干什么
Encoder 自注意力 Encoder 的词 Encoder 的词 输入句内部互相看
Decoder Masked 自注意力 Decoder 已生成的词 Decoder 已生成的词 输出句内部互相看(不能看未来)
交叉注意力 Decoder 的词 Encoder 的输出 输出句去查输入句

关键区别就一句话:

自注意力是自己看自己人;交叉注意力是输出这边去问输入那边。

交叉注意力中的Q、K、V

交叉注意力中的 K 和 V 是来自 Encoder 的

  • Query(Q):来自 Decoder(当前正在生成的词)
  • Key(K)和 Value(V):来自 Encoder(源语言的语境化向量)

这样,Decoder 在生成每个目标词时,都可以动态地从源语言中抓取最相关的信息。

例子: 翻译“他在银行存钱” → “He deposits money in the bank”

Decoder 生成 交叉注意力主要关注 Encoder 的哪个词
“He” 关注“他”
“deposits” 关注“存”
“money” 关注“钱”
“bank” 关注“银行”

和 Masked 自注意力怎么配合?

在 Decoder 的每一层里,三个子层按顺序执行:

① Masked 自注意力   →  看自己已经生成了什么(不能看未来)
        ↓ Add & Norm
② 交叉注意力        →  去 Encoder 输出里查输入句说了什么
        ↓ Add & Norm
③ 前馈网络 FFN      →  关起门来深度加工
        ↓ Add & Norm

可以这么理解分工:

  • Masked 自注意力:输出句内部的连贯 ("deposits""money" 的搭配)
  • 交叉注意力:输入和输出的对齐(银行和 "bank" 的对应)

Transformer 为什么成功

讲到这里,我们已经把 Transformer 的每一个组件都拆开看过了。现在可以回过头来回答一个问题:为什么是 Transformer?它到底赢在哪里?

相比之前的 RNN/LSTM,Transformer 的成功可以归结为四个核心优势。

1. 并行计算:训练速度快了一个数量级

RNN 必须一个字一个字地按顺序处理:要理解第 t 个词,必须等前 t-1 个词都算完。这不仅慢,而且无法充分利用 GPU 的并行能力。

Transformer 的注意力机制让所有词同时参与计算。一次矩阵乘法,就能算出所有词之间的注意力权重。训练时间从几周缩短到几天甚至几小时。这是 Transformer 能“做大”的前提——没有并行,就没有大模型。

2. 长距离依赖:信息不再衰减

RNN 传递信息像“传话游戏”:每传一个人,信息都可能被扭曲或丢失。传到最后,开头的信息已经面目全非。LSTM 虽然缓解了这个问题,但依然有上限。

Transformer 里,任意两个词之间都可以直接建立关联。无论隔了多远,一个词“看”另一个词的计算成本是一样的。

模型可以理解段落级别的逻辑、文章开头的伏笔、甚至跨篇章的指代。这对机器翻译、文本摘要、问答系统等任务至关重要。

3. 可堆叠:深度不再是瓶颈

RNN 堆叠多层时,梯度消失问题会急剧恶化,一般只能堆 2-4 层。

Transformer 通过残差连接给梯度开了一条“高速公路”,让信息可以无损地穿过几十层甚至上百层。层归一化则保证每一层的数值尺度稳定,训练不会“跑偏”。

原始 Transformer 用了 6 层,BERT 用了 12 或 24 层,GPT-3 用了 96 层。深度带来了更强的表达能力,每一层都在逐级抽象——从词法到句法到语义。

4. 通用性强:一个架构打天下

RNN/LSTM 时代,不同任务需要设计不同的网络结构:机器翻译用 Encoder-Decoder,文本分类用单向 RNN,序列标注用双向 RNN……

Transformer 用一个架构统一了几乎所有 NLP 任务:

  • Encoder-only(如 BERT):适合理解类任务(分类、标注、相似度)
  • Decoder-only(如 GPT):适合生成类任务(对话、续写、代码生成)
  • Encoder-Decoder(如原始 Transformer):适合序列转换任务(翻译、摘要)

而且,Transformer 不仅限于 NLP。它已经被成功应用到计算机视觉(ViT)、语音处理、蛋白质结构预测(AlphaFold)等领域。

附录:ReLU 激活函数

关于为什么要有激活函数,激活函数为啥可以给全连接层做变化,我们得先从全连接层的变换来讲。

假设你有两层全连接层:

第一层: y1 = x * W1 + b1 第二层: y2 = y1 * W2 + b2

合并起来 :`y2 = (x * W1 + b1) * W2 + b2 = x * (W1 * W2) + (b1 * W2 + b2) ``

实际上还是一层

ReLU 就是拿来打破线性的 ,最简单的ReLu公式只有一行: ReLU(x) = max(0, x)

  • 输入正数 → 原样输出
  • 输入负数 → 变成 0

你可能会问, 为什么是变成0?

因为 0 是“乘法意义上的中性元”。 当一个神经元输出 0 时:

  • 它传给下一层的信号是 0,对后续计算零影响
  • 反向传播时梯度也是 0,不参与本次更新 如果把负数变成其他值(比如 -0.1 或 0.001),这个神经元依然在“发言”,会干扰其他神经元的判断。

具体例子

假设前馈网络的第一层,有一个神经元专门检测“动词”特征。 输入“银行”这个词时,这个神经元的输出可能是:

  • 如果“银行”有动词属性 → 正数(比如 2.5)
  • 如果“银行”没有动词属性 → 负数(比如 -1.2) ReLU后:
  • 正数 2.5 → 保留 2.5
  • 负数 -1.2 → 变成 0

效果: 当“银行”没有动词属性时,这个神经元完全沉默,不往后传递信息。

所以,ReLU的作用有两个:

  1. 加入弯折(引入非线性)→ 让多层全连接真的有深度
  2. 减少噪音(特征筛选)→ 让不相关的神经元闭嘴

ReLU 还有两个额外的好处:

好处 说明
计算快 只需要比较 max(0, x),没有指数运算(Sigmoid 需要算 e^x)
缓解梯度消失 正数区域导数恒为 1,梯度可以原样通过,不会衰减