介绍
GELU(Gaussian Error Linear Unit,高斯误差线性单元), 是一种非线性激活函数。由Dan Hendrycks和Kevin Gimpel于2016年提出。
它是深度学习模型中广泛使用的激活机制之一,尤其在Transformer架构(如BERT、GPT系列)中扮演关键角色。GELU的设计灵感来源于高斯分布的累积分布函数(CDF),旨在 解决传统激活函数(如ReLU)的一些局限性,例如“死亡ReLU”问题(负输入被完全抑制,导致梯度为零)和非平滑性,从而提升模型的训练稳定性和性能。
一句话解释:是一种平滑的 ReLU 变体,现在在 Transformer / BERT 等模型里几乎是默认激活函数。
核心思想
ReLU
ReLU 的工作方式可以被看作一个“硬门控 (hard gate)”:当输入 x>0 时,门是开的(输出 x);当 x≤0 时,门是关的(输出 0)。
GELU
GELU 的核心思想则更为精妙,它采用了一个“随机门控 (stochastic gate)”。一个神经元的输出值 x 将乘以一个在 [0, 1] 之间的值,这个值是 随机生成的,但其概率分布取决于输入 x 本身。
具体来说,GELU 使用标准正态分布的累积分布函数 (CDF) ,用 \Phi(x) 表示,来作为这个门控的概率值。
如果输入
x越大,\Phi(x) 就越接近1,意味着这个输入有很大概率被“保留”。如果输入
x越小(越负),\Phi(x) 就越接近0,意味着这个输入有很大概率被“置零”。
这种方式将神经元的激活与它的数值分布联系起来,实现了一种数据驱动的、非线性的门控机制。
公式
GELU(Gaussian Error Linear Units)可以理解为:
“带一点随机性、平滑版的 ReLU”。
常用 近似公式(有上面可知,有随机数,所以用近似公式,代码里一般用这个):
\text{GELU}(x) = x \cdot \Phi(x)
其中:
x 是输入(标量或张量元素)
\Phi(x) 是 标准正态分布的 CDF,常用近似:
\Phi(x) \approx 0.5 \left(1 + \tanh\left[\sqrt{\frac{2}{\pi}} \left(x + 0.044715 * x^3\right)\right]\right)
提示:这个近似公式在 PyTorch 和 TensorFlow 等主流框架中被广泛采用。
完整公式
\text{GELU}(x) \approx 0.5 * x * \left(1 + \tanh\left[\sqrt{\frac{2}{\pi}} \left(x + 0.044715 * x^3\right)\right]\right)
直观理解
- 对每个输入 (x),以某种概率把它“关掉”或“减弱”,这个概率跟 (x) 的大小有关
- 比 ReLU 更平滑,不是硬切 0,而是连续变化
GELU vs. ReLU (视觉对比)

绘制图像代码:
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
gelu = nn.GELU()
relu = nn.ReLU()
x = torch.linspace(-3, 3, 100)
print("x.shape:", x.shape)
print("x:\n", x)
y_gelu = gelu(x)
y_relu = relu(x)
plt.figure(figsize=(8, 3))
for i, (y, label) in enumerate(zip([y_gelu, y_relu], ["GELU", "ReLU"]), 1):
plt.subplot(1, 2,i)
plt.plot(x, y)
plt.title(f"{label} activation function")
plt.xlabel("x")
plt.ylabel(f"{label}(x)")
plt.grid(True)
plt.tight_layout()
plt.show()
绘制图像
为了直观地比较GELU函数与ReLU函数,将它们并排绘制出来
gelu = GELU()
relu = nn.ReLU()
x = torch.linspace(-3, 3, 100)
print("x.shape:", x.shape)
print("x:\n", x)
y_gelu = gelu(x)
y_relu = relu(x)
plt.figure(figsize=(8, 3))
for i, (y, label) in enumerate(zip([y_gelu, y_relu], ["GELU", "ReLU"]), 1):
plt.subplot(1, 2,i)
plt.plot(x, y)
plt.title(f"{label} activation function")
plt.xlabel("x")
plt.ylabel(f"{label}(x)")
plt.grid(True)
plt.tight_layout()
plt.show()
ReLU
在 原点有一个尖锐的拐点:
在 x \leq 0 时为一条直线 y=0
在 x>0 时为一条直线 y=x
GELU
当 x 很大时,函数曲线非常接近 y=x
当 x 是很大的负数时,函数曲线非常接近 y=0
在原点附近平滑过渡,并且在负值区域会略低于 x 轴。
和 ReLU 比较优缺点
优点
- 输出更平滑,梯度更连续,训练更稳定
- 在 Transformer、BERT、GPT 等模型中,效果普遍好于 ReLU
- 对不同尺度的输入更“友好”,不容易一下子饱和
缺点
- 计算比 ReLU 稍复杂一点(但在现代硬件上影响不大)
- 形式稍复杂,不像 ReLU 那样一眼就懂
什么时候用 GELU?
- 做 Transformer / 大语言模型 / 注意力模型:优先用 GELU
- 做 CV 里的 ViT、Swin Transformer 等:也常用 GELU
- 普通 CNN、MLP:
- 用 ReLU 完全没问题
- 如果想试试提升一点效果,可以把 ReLU 换成 GELU 做对比
实现
pytorch实现
import torch
import torch.nn as nn
# 使用官方实现的 GELU
activation = nn.GELU()
x = torch.randn(10) # 示例输入
y = activation(x)
print(y)
参考:
https://juejin.cn/post/7562095943442235444
https://blog.csdn.net/u013172930/article/details/153544283