介绍
功能:
逐元素对数据应用如下函数公式进行激活
G E L U ( x ) = x ∗ Φ ( x ) GELU(x)=x*\Phi(x) GELU(x)=x∗Φ(x)
其中 Φ ( x ) \Phi(x) Φ(x)是标准正态分布的积累分布函数:
Φ ( x ) = ∫ − ∞ x e − t 2 / 2 2 π d t = 1 2 [ 1 + e r f ( x 2 ) ] \Phi(x)=\int^x_{-\infty}\frac{e^{-t^2/2}}{\sqrt{2\pi}}dt=\frac12[1+erf(\frac x{\sqrt2})] Φ(x)=∫−∞x2πe−t2/2dt=21[1+erf(2x)]
其中 e r f ( ⋅ ) erf(·) erf(⋅)可以表示为:
e r f ( x ) = 2 π ∫ 0 x e − t 2 d t erf(x)=\frac2{\sqrt\pi}\int^x_0e^{-t^2}dt erf(x)=π2∫0xe−t2dt
对 G E L U GELU GELU求导,可得到导函数:
G E L U ′ ( x ) = 1 2 ( 1 + e r f ( x 2 ) ) + x 2 π e − x 2 2 GELU'(x)=\frac12(1+erf(\frac x{\sqrt2}))+\frac{x}{\sqrt{2\pi}}e^{-\frac{x^2}{2}} GELU′(x)=21(1+erf(2x))+2πxe−2x2
注:
- 输出数据尺寸与输入数据尺寸相同;
优点
- 相比于ReLU,GELU函数在临近原点时梯度不为零,减少了训练过程中梯度消失的问题;
- 导函数比较光滑,无间断情况,容易做反向传播;
- RELU计算复杂度较低,同时具有良好的性能,常用于大规模训练的任务,例如BERT、GPT等等。
函数图像
下图左侧为GELU激活函数图像,右侧为导函数图像:
代码案例
import torch.nn as nn
import torch
GELU = nn.GELU()
x = torch.rand(10)
value = GELU(x)
print(x)
print(value)
输出
tensor([0.7163, 0.9452, 0.6216, 0.5953, 0.5593, 0.1129, 0.9343, 0.4854, 0.3826,
0.2847])
tensor([0.5466, 0.7823, 0.4555, 0.4311, 0.3982, 0.0615, 0.7708, 0.3331, 0.2483,
0.1742])
注:绘图程序
import numpy as np
import matplotlib.pyplot as plt
from scipy.special import erf
def gelu(x):
return 0.5 * x * (1 + erf(x / np.sqrt(2)))
def gelu_activation(x):
return 0.5 * (1 + erf(x / np.sqrt(2))) + x / np.sqrt(2 * np.pi) * np.exp(-x ** 2 / 2)
# 生成x轴数据
x = np.linspace(-5, 5, 100)
# 计算GeLU函数和其导数
y_gelu = gelu(x)
y_gelu_activation = gelu_activation(x)
# 创建图形和子图
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6))
# 绘制GeLU函数图像
ax1.plot(x, y_gelu, color='blue')
ax1.set_title('GeLU Function')
ax1.set_xlabel('x')
ax1.set_ylabel('GeLU(x)')
ax1.grid(True)
# 绘制GeLU函数导数图像
ax2.plot(x, y_gelu_activation, color='red')
ax2.set_title('GeLU Activation Function')
ax2.set_xlabel('x')
ax2.set_ylabel('GeLU\'(x)')
ax2.grid(True)
# 显示图形
plt.tight_layout()
plt.show()
官方文档
nn.GELU:https://pytorch.org/docs/1.9.1/generated/torch.nn.GELU.html