PyTorch torch.nn.GELU 関数
torch.nn.GELUこれは PyTorch のガウス誤差線形ユニット(Gaussian Error Linear Unit)活性化関数です。
これは Transformer アーキテクチャのデフォルトの活性化関数であり、ReLU と比較してより良い性能と滑らかな勾配を持ちます。
関数定義
torch.nn.GELU(approximate='none')
パラメータの説明:
approximate(str): 近似アルゴリズム。任意指定'none'、'tanh'。デフォルトは'none'。
数学的原理
GELU の数学的公式:
GELU(x) = x * Φ(x)
ここで、Φ(x) は標準正規分布の累積分布関数(CDF)です。
tanh 近似を使用する場合:
GELU(x) ≈ 0.5x * (1 + tanh(√(2/π) * (x + 0.044715 * x³)))
使用例
例 1: 基本的な使い方
GELU 活性化を作成して使用する:
実例
import torch
import torch.nn as nn
# 创建 GELU 激活层
gelu = nn.GELU()
# 测试输入
x = torch.tensor([-2.0, -1.0, 0.0, 1.0, 2.0])
# 前向传播
output = gelu(x)
print("输入:", x.tolist())
print("输出:", output.tolist())
print("n观察:负值有轻微激活(非零),正值保持增长")
import torch.nn as nn
# 创建 GELU 激活层
gelu = nn.GELU()
# 测试输入
x = torch.tensor([-2.0, -1.0, 0.0, 1.0, 2.0])
# 前向传播
output = gelu(x)
print("输入:", x.tolist())
print("输出:", output.tolist())
print("n观察:负值有轻微激活(非零),正值保持增长")
例 2: 異なる活性化関数の比較
GELU、ReLU、Sigmoid の比較:
実例
import torch
import torch.nn as nn
x = torch.linspace(-4, 4, 21)
# 不同激活函数
gelu = nn.GELU()
relu = nn.ReLU()
sigmoid = nn.Sigmoid()
tanh = nn.Tanh()
print("x GELU ReLU Sigmoid Tanh")
print("-" * 50)
for i in range(0, 21, 3):
xi = x[i:i+3]
print(f"{xi[0]:6.2f} {gelu(xi)[0]:8.4f} {relu(xi)[0]:8.4f} {sigmoid(xi)[0]:8.4f} {tanh(xi)[0]:8.4f}")
import torch.nn as nn
x = torch.linspace(-4, 4, 21)
# 不同激活函数
gelu = nn.GELU()
relu = nn.ReLU()
sigmoid = nn.Sigmoid()
tanh = nn.Tanh()
print("x GELU ReLU Sigmoid Tanh")
print("-" * 50)
for i in range(0, 21, 3):
xi = x[i:i+3]
print(f"{xi[0]:6.2f} {gelu(xi)[0]:8.4f} {relu(xi)[0]:8.4f} {sigmoid(xi)[0]:8.4f} {tanh(xi)[0]:8.4f}")
例 3: Transformer での使用
典型的な Transformer FFN 層:
h2 class="example">実例
import torch
import torch.nn as nn
class FeedForward(nn.Module):
def __init__(self, d_model, dim_feedforward=2048, dropout=0.1):
super(FeedForward, self).__init__()
self.linear1 = nn.Linear(d_model, dim_feedforward)
self.dropout = nn.Dropout(dropout)
self.activation = nn.GELU()
self.linear2 = nn.Linear(dim_feedforward, d_model)
def forward(self, x):
x = self.linear1(x)
x = self.activation(x)
x = self.dropout(x)
x = self.linear2(x)
return x
# 测试 FFN
ffn = FeedForward(d_model=512, dim_feedforward=2048)
x = torch.randn(32, 100, 512) # (batch, seq, d_model)
output = ffn(x)
print("输入形状:", x.shape)
print("输出形状:", output.shape)
import torch.nn as nn
class FeedForward(nn.Module):
def __init__(self, d_model, dim_feedforward=2048, dropout=0.1):
super(FeedForward, self).__init__()
self.linear1 = nn.Linear(d_model, dim_feedforward)
self.dropout = nn.Dropout(dropout)
self.activation = nn.GELU()
self.linear2 = nn.Linear(dim_feedforward, d_model)
def forward(self, x):
x = self.linear1(x)
x = self.activation(x)
x = self.dropout(x)
x = self.linear2(x)
return x
# 测试 FFN
ffn = FeedForward(d_model=512, dim_feedforward=2048)
x = torch.randn(32, 100, 512) # (batch, seq, d_model)
output = ffn(x)
print("输入形状:", x.shape)
print("输出形状:", output.shape)
例 4: tanh 近似の使用
tanh 近似を使用して計算を高速化する:
実例
import torch
import torch.nn as nn
# 精确版本
gelu_exact = nn.GELU(approximate='none')
# tanh 近似版本
gelu_approx = nn.GELU(approximate='tanh')
x = torch.randn(1000)
output_exact = gelu_exact(x)
output_approx = gelu_approx(x)
# 计算差异
diff = (output_exact - output_approx).abs().max().item()
print(f"最大差异: {diff:.8f}")
# 性能比較
import time
for _ in range(100):
_ = gelu_exact(x)
start = time.time()
for _ in range(1000):
_ = gelu_exact(x)
time_exact = time.time() - start
start = time.time()
for _ in range(1000):
_ = gelu_approx(x)
time_approx = time.time() - start
print(f"精确版本时间: {time_exact:.4f}s")
print(f"近似版本时间: {time_approx:.4f}s")
import torch.nn as nn
# 精确版本
gelu_exact = nn.GELU(approximate='none')
# tanh 近似版本
gelu_approx = nn.GELU(approximate='tanh')
x = torch.randn(1000)
output_exact = gelu_exact(x)
output_approx = gelu_approx(x)
# 计算差异
diff = (output_exact - output_approx).abs().max().item()
print(f"最大差异: {diff:.8f}")
# 性能比較
import time
for _ in range(100):
_ = gelu_exact(x)
start = time.time()
for _ in range(1000):
_ = gelu_exact(x)
time_exact = time.time() - start
start = time.time()
for _ in range(1000):
_ = gelu_approx(x)
time_approx = time.time() - start
print(f"精确版本时间: {time_exact:.4f}s")
print(f"近似版本时间: {time_approx:.4f}s")
活性化関数の比較
| 活性化関数 | 特徴 | 適用シーン |
|---|---|---|
nn.GELU |
滑らか、非ゼロの負値、Transformer デフォルト | Transformer、BERT、GPT |
nn.ReLU |
単純、スパースな活性化、デッドニューロン | CNN、汎用ディープラーニング |
nn.SiLU |
滑らか、セルフゲーティング | MobileNet、EfficientNet |
よくある質問
Q1: GELU は ReLU と比べてどのような利点がありますか?
- 負の値もわずかに活性化し、情報が失われない
- 勾配がより滑らかで、訓練に役立つ
- Transformer での性能がより良い
Q2: いつ近似バージョンを使用しますか?
推論速度が求められ、精度の要求が厳しくない場合、tanh 近似の方が高速です。
Q3: GELU は出力層に使用できますか?
通常は出力層には使用されません。分類タスクでは Softmax、回帰タスクでは恒等関数を使用します。
使用シーン
nn.GELU主な適用シーンは次のとおりです:
- Transformer アーキテクチャ: BERT、GPT などのモデル
- ディープニューラルネットワーク: 滑らかな活性化が必要な場合
- 事前学習モデル: 現代の NLP モデル
ヒント:GELU は現在の NLP 分野で最もよく使われる活性化関数であり、Transformer の標準装備です。
その他の拡張
PyTorch torch.nn リファレンスマニュアル