找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

5405

积分

0

好友

716

主题
发表于 2 小时前 | 查看: 3| 回复: 0

GELU 是深度学习、神经网络、激活函数、Transformer 和大语言模型中非常常见的一个术语。它用来描述一种比 ReLU 更平滑的非线性激活函数。换句话说,GELU 函数是在回答这样一个问题:神经元计算出一个线性得分后,应该怎样以更柔和的方式决定这个信号通过多少?

如果说 ReLU 函数像一个“硬开关”:正数通过、负数截断;那么 GELU 更像一个“软门控”:输入越大,越倾向于通过;输入越小,越倾向于抑制,但不是简单粗暴地一刀切。因此,GELU 常用于 Transformer、BERT、GPT 类模型、前馈神经网络模块和现代深度学习模型,是理解大模型中激活函数选择的重要概念。

一、基本概念:什么是 GELU 函数

GELU 是 Gaussian Error Linear Unit 的缩写,通常可译为高斯误差线性单元。它是一种激活函数,用于把神经元的线性输入转换成非线性输出。

一个神经元通常先计算:

z = w · x + b

然后通过激活函数得到输出:

a = GELU(z)

其中:

  • x 表示输入向量
  • w 表示权重向量
  • b 表示偏置
  • z 表示线性输入
  • a 表示经过 GELU 激活后的输出

GELU 的常见定义为:

GELU(x) = x * Φ(x)

其中:

  • x 表示输入
  • Φ(x) 表示标准正态分布的累积分布函数
  • xΦ(x) 表示把输入 x 乘以一个与 x 大小相关的平滑门控系数

从通俗角度看,GELU 可以理解为:输入越大,越应该保留;输入越小,越应该抑制;中间区域则平滑过渡。

这与 ReLU 的硬截断不同。ReLU 是:

ReLU(x) = max(0, x)

也就是:

  • x > 0 时,直接输出 x
  • x ≤ 0 时,直接输出 0

而 GELU 不是简单地把负数全部变成 0,而是根据输入大小进行柔和调整。

二、为什么需要 GELU 函数

GELU 之所以重要,是因为现代 深度学习 模型需要既有非线性表达能力,又有较平滑的训练性质。

ReLU 函数简单高效,但它有明显的硬折点:

ReLU(x) = max(0, x)

这意味着:

  • 正数完全通过
  • 非正数直接归零
  • 在 0 附近存在明显折断

这种设计简单有效,但有时过于粗糙。

GELU 的思路更柔和:不是简单判断输入是否大于 0,而是根据输入大小决定信号通过的程度。

例如:

  • 较大的正数大部分保留
  • 接近 0 的数部分保留
  • 较小的负数大多被抑制
  • 轻微负数可能仍保留少量信息

从通俗角度看:

  • ReLU:大于 0 就开,小于等于 0 就关
  • GELU:根据输入大小,柔和决定开多少

这使 GELU 在许多 Transformer 模型中表现良好。

现代大语言模型中,前馈网络模块通常包含:

线性层 → 激活函数 → 线性层

其中激活函数常常使用 GELU 或其变体。

因此,GELU 是理解 Transformer 内部非线性变换的重要组成部分。

三、GELU 的核心公式

GELU 的理论定义为:

GELU(x) = x * Φ(x)

其中,Φ(x) 是标准正态分布的累积分布函数:

Φ(x) = P(X ≤ x),其中 X ~ 𝒩(0,1)

其中:

  • X 表示服从标准正态分布的随机变量
  • 𝒩(0,1) 表示均值为 0、方差为 1 的正态分布
  • Φ(x) 表示随机变量 X 小于或等于 x 的概率

因此,GELU 可以理解为:

GELU(x) = x * P(X ≤ x)

从通俗角度看:GELU 用一个概率值 Φ(x) 作为门控系数,决定输入 x 应该保留多少。

x 很大时:

  • Φ(x) 接近 1
  • GELU(x) 接近 x

x 很小时:

  • Φ(x) 接近 0
  • GELU(x) 接近 0

x 接近 0 时:

  • Φ(x) 接近 0.5
  • GELU(x) 大约保留一半趋势

所以,GELU 不是简单地“负数归零、正数放行”,而是用概率方式对输入进行平滑调节。

这也是 GELU 名称中包含 Gaussian 的原因:它与高斯分布,也就是正态分布有关。

四、GELU 的近似公式

由于标准正态分布的累积分布函数 Φ(x) 计算起来相对复杂,实际工程中常使用近似公式。

常见近似形式为:

GELU(x) ≈ 0.5x (1 + tanh(√(2/π) (x + 0.044715x^3)))

其中:

  • tanh 表示双曲正切函数
  • π 表示圆周率
  • 0.044715 是近似公式中的常数

这个公式虽然看起来复杂,但它的作用很简单:用一个更方便计算的平滑函数近似原始 GELU。

还有一种更简单的近似形式:

GELU(x) ≈ x * σ(1.702x)

其中:

  • σ 表示 Sigmoid 函数
  • σ(1.702x) 近似模拟 Φ(x)

从通俗角度看:

  • 原始 GELUx × 正态分布累计概率
  • 近似 GELU:用 tanh 或 Sigmoid 近似这个概率门控

在深度学习框架中,用户通常不需要手写这些公式。

例如,在 PyTorch 中可以直接使用:

torch.nn.GELU()

框架会在内部处理具体计算方式。

五、如何直观理解 GELU

GELU 最核心的直觉是:让输入根据自身大小,以平滑概率方式决定通过程度。

可以把 GELU 看成一种“软门控”函数:

  • 输入很大 → 门几乎全开 → 基本保留
  • 输入接近 0 → 门半开半关 → 部分保留
  • 输入很小 → 门几乎关闭 → 基本抑制

这与 ReLU 的差别很明显。

ReLU 是硬门控:

  • x > 0:通过
  • x ≤ 0:关闭

GELU 是软门控:

  • x 越大,通过比例越高
  • x 越小,通过比例越低

例如,从直觉上看:

  • x = 2 时,GELU(x) 接近 2
  • x = 0 时,GELU(x) = 0
  • x = -2 时,GELU(x) 接近 0,但不是通过硬规则截断

此外,GELU 在轻微负数区域可能输出小的负值。
这说明它不像 ReLU 那样把所有负数都强制变成 0,而是允许部分负向信息以较弱形式存在。

从通俗角度看:GELU 比 ReLU 更柔和,也更连续地控制信息流。

这有助于模型在训练过程中获得更平滑的梯度变化。

六、GELU 与 ReLU 的区别

GELU 和 ReLU 都是隐藏层常用激活函数,但它们的行为不同。

1、ReLU 是硬截断

ReLU 定义为:

ReLU(x) = max(0, x)

它的特点是:

  • 正数直接通过
  • 负数全部变为 0
  • 计算简单
  • 可能出现死亡 ReLU 问题

从通俗角度看:ReLU 是一个简单明确的开关。

2、GELU 是平滑门控

GELU 定义为:

GELU(x) = x * Φ(x)

它的特点是:

  • 正数大多通过
  • 负数大多被抑制
  • 过渡更加平滑
  • 不像 ReLU 那样简单一刀切

从通俗角度看:GELU 是一个根据输入强弱逐渐开合的软开关。

3、训练表现上的差异

ReLU 的优势是简单、高效、广泛适用。

GELU 的优势是平滑、柔和,并且在 Transformer 等模型中常有较好表现。

可以简单理解为:

  • ReLU:适合许多传统深度网络,尤其是 CNN 和普通 MLP
  • GELU:常见于 Transformer、BERT、GPT 等现代架构

不过,GELU 并不总是绝对优于 ReLU。
在不同任务、模型规模、数据条件和训练设置下,二者表现可能不同。

从实践角度看:ReLU 是经典默认选择,GELU 是现代 Transformer 模型中的常见选择。

七、GELU 在 Transformer 中的作用

GELU 在 Transformer 中非常常见,尤其是在前馈网络模块中。

一个 Transformer 层通常包括:

注意力模块 → 前馈网络模块

其中前馈网络模块常见形式为:

FFN(x) = W₂ * f(W₁ * x + b₁) + b₂

其中:

  • x 表示输入表示
  • W₁、W₂ 表示权重矩阵
  • b₁、b₂ 表示偏置
  • f 表示激活函数

在许多 Transformer 模型中,这里的 f 就可以是 GELU。

从通俗角度看,Transformer 中的前馈网络模块会对每个 token 的表示进行非线性加工:

token 表示 → 线性变换 → GELU 激活 → 线性变换 → 更新后的表示

GELU 在这里的作用是:为 token 表示的变换过程引入平滑非线性。

在 BERT、GPT 等模型中,GELU 曾被广泛采用。
后来一些模型也会使用 SwiGLU、GeGLU、SiLU 等变体,但 GELU 仍然是理解 Transformer 激活函数的重要基础。

从通俗角度看:注意力机制负责让 token 之间交换信息,GELU 所在的前馈网络负责对每个 token 的内部表示进行非线性加工。

八、GELU 的优势、局限与使用注意事项

1、GELU 的主要优势

GELU 的主要优势是平滑。
它不像 ReLU 那样在 0 点硬折断,而是通过概率门控方式平滑调整输入。

其次,GELU 对轻微负值更宽容。
它不会简单地把所有负数都截断为 0,而是允许一部分负向信息以较小形式保留。

再次,GELU 在 Transformer 和大语言模型中非常常见。
对于理解现代模型结构,它是一个非常重要的激活函数。

从通俗角度看,GELU 的优势在于:它不是粗暴地关闭信号,而是根据输入强弱柔和地控制信号通过程度。

2、GELU 的主要局限

GELU 也有局限。
首先,它比 ReLU 计算更复杂。
ReLU 只需要一个 max 操作,而 GELU 涉及正态分布函数或近似函数。

其次,GELU 的解释不如 ReLU 直观。
ReLU 的规则非常清楚:负数归零、正数保留;GELU 则需要理解概率门控和平滑近似。

再次,GELU 并不保证在所有任务中都比 ReLU 好。
对于一些简单网络或小规模任务,ReLU 可能已经足够。

此外,在实际工程中,激活函数只是影响模型表现的因素之一。
模型结构、数据规模、学习率、归一化、初始化和优化器同样重要。

3、使用 GELU 时需要注意的问题

使用 GELU 时,可以注意以下几点:

  • Transformer 和语言模型中常见 GELU
  • 普通 MLP 中也可以尝试 GELU
  • 如果追求极致计算效率,ReLU 可能更简单
  • GELU 适合需要平滑非线性的模型
  • 不要认为 GELU 一定优于所有激活函数
  • 不同框架中 GELU 可能支持 exact 或 approximate 模式

从实践角度看,GELU 是现代深度学习中非常重要的激活函数,尤其适合与 Transformer 架构一起理解。

九、Python 示例

下面给出几个简单示例,用来帮助理解 GELU 的计算和使用。

示例 1:使用 PyTorch 计算 GELU

import torch                     # PyTorch 深度学习库
import torch.nn as nn            # 神经网络模块

# 输入张量(5个实数)
x = torch.tensor([-3.0, -1.0, 0.0, 1.0, 3.0])

# GELU(Gaussian Error Linear Unit)激活函数,更平滑的ReLU变体
gelu = nn.GELU()

# 应用 GELU 激活函数
y = gelu(x)

print("输入:", x)
print("GELU 输出:", y)          # 输出近似:负值被平滑映射到接近0,正值近似线性

这个例子可以观察:

  • 较大正数基本保留
  • 0 附近平滑过渡
  • 负数大多被抑制,但不是像 ReLU 那样简单截断

示例 2:对比 ReLU 与 GELU

import torch                     # PyTorch 深度学习框架
import torch.nn as nn            # 神经网络模块

# 测试用的输入张量(包含负数、零、正数)
x = torch.tensor([-3.0, -1.0, 0.0, 1.0, 3.0])

# ReLU 激活函数(负值置零,正值不变)
relu = nn.ReLU()
# GELU 激活函数(高斯误差线性单元,平滑的非线性)
gelu = nn.GELU()

print("输入:", x)
print("ReLU 输出:", relu(x))   # 输出:[0, 0, 0, 1, 3]
print("GELU 输出:", gelu(x))   # 负值有较小的非零输出,正值近似线性

这个例子中:

  • ReLU 会把所有负数变成 0
  • GELU 会对输入进行平滑调整
  • GELU 的负数部分通常不是简单清零

从输出可以直观看到:

  • ReLU 更像硬开关
  • GELU 更像软门控

示例 3:在前馈神经网络中使用 GELU

import torch                     # PyTorch框架
import torch.nn as nn            # 神经网络模块

# 定义简单前馈神经网络:输入4维 → GELU激活 → 输出3维(类别logits)
model = nn.Sequential(
    nn.Linear(4, 16),   # 全连接层:4→16
    nn.GELU(),          # GELU激活函数
    nn.Linear(16, 3)    # 输出层:16→3
)

# 生成一批随机输入:5个样本,每个样本4个特征
x = torch.randn(5, 4)

# 前向传播,得到未归一化的类别分数
logits = model(x)

print("输出 logits 形状:", logits.shape)  # torch.Size([5, 3])
print(logits)

这个例子中:

  • nn.Linear(4, 16) 进行线性变换
  • nn.GELU() 引入平滑非线性
  • nn.Linear(16, 3) 输出 3 个类别的 logits

如果用于多分类任务,通常会配合 nn.CrossEntropyLoss()

示例 4:手动实现 GELU 近似公式

import torch                     # PyTorch 张量计算
import math                      # 数学常量(sqrt(2/π))

# GELU 的近似实现(基于 tanh 展开,常用于高效计算)
def gelu_approx(x):
    # 公式:0.5 * x * (1 + tanh(sqrt(2/π) * (x + 0.044715 * x^3)))
    return 0.5 * x * (
        1 + torch.tanh(
            math.sqrt(2 / math.pi) * (x + 0.044715 * x ** 3)
        )
    )

# 测试输入:负数、零、正数
x = torch.tensor([-3.0, -1.0, 0.0, 1.0, 3.0])

# 计算近似 GELU
y = gelu_approx(x)

print("输入:", x)
print("近似 GELU 输出:", y)

这个例子对应近似公式:

GELU(x) ≈ 0.5x (1 + tanh(√(2/π) (x + 0.044715x^3)))

在实际使用中,一般不需要手动写这个函数,直接使用深度学习框架内置的 GELU 即可。

📘 小结

GELU 函数是一种常用于现代深度学习模型的激活函数,定义为 GELU(x)=xΦ(x),其中 Φ(x) 是标准正态分布的累积分布函数。它不像 ReLU 那样把负数简单截断,而是根据输入大小进行平滑门控:输入越大,越倾向于保留;输入越小,越倾向于抑制。GELU 常用于 Transformer、BERT、GPT 等模型中的前馈网络模块。对初学者而言,可以把 GELU 理解为:一种比 ReLU 更柔和的“软开关”激活函数。对于开发者来说,在 云栈社区 交流这些技术细节,往往能获得更多实践上的启发。

GELU函数二维码与拉普拉斯噪声示意图




上一篇:自托管服务器监控实战:用Checkmate搭建免费Uptime监测与硬件状态看板
下一篇:LLM核心技术解析:Agent, Skill, Memory与Harness Engineering如何协同工作
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-5-15 05:51 , Processed in 0.850333 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表