PyTorch torch.nn.ReLU 関数
torch.nn.ReLUPyTorch で最もよく使われる活性化関数の1つであり、入力テンソルに対して要素ごとに修正線形ユニット(Rectified Linear Unit)演算を実行します。
ReLU は、計算が簡単で収束が速く、勾配消失問題を効果的に軽減できるため、深層学習で最も成功した活性化関数の1つです。
関数定義
torch.nn.ReLU(inplace=False)
パラメータの説明:
inplaceinplace (bool): に設定するとTrue、その場で入力テンソルが直接変更され、メモリが節約されます。デフォルトはFalse。
数学的原理
nn.ReLU実行される計算式は次のとおりです:
f(x) = max(0, x)
つまり、入力の各要素について、値が0より大きい場合はそのままにし、値が0以下の場合は0を出力します。
この単純な非線形変換により、ネットワークは勾配の流れを保ちながら複雑なパターンを学習できます。
使用例
例1: 基本的な使い方
ReLU 活性化層を作成し、入力を活性化します:
例
import torch.nn as nn
# ReLU 活性化層を作成
relu = nn.ReLU()
# 負の値を含む入力テンソルを作成
input_tensor = torch.tensor([[-1.0, 2.0, -3.0], [4.0, -5.0, 6.0]])
# 順伝播
output = relu(input_tensor)
print("入力:n", input_tensor)
print("出力:n", output)
出力結果は次のとおりです:
输入:
tensor([[-1., 2., -3.],
[ 4., -5., 6.]])
输出:
tensor([[0., 2., 0.],
[4., 0., 6.]])
すべての負の値が0に設定され、正の値はそのままであることがわかります。
例2: インプレース操作
inplace パラメータを使用するとメモリを節約できます:
例
import torch.nn as nn
# インプレース操作を有効にした ReLU を作成
relu_inplace = nn.ReLU(inplace=True)
# 入力テンソルを作成
input_tensor = torch.randn(2, 4)
original_id = id(input_tensor)
# インプレースで変更
output = relu_inplace(input_tensor)
# 元のテンソルが変更されたか確認
print("元のテンソルが変更されたか:", id(output) == original_id)
print("入力/出力:n", input_tensor)
出力結果は次のとおりです:
是否修改了原张量: True
输入/输出:
tensor([[0.0000, 0.0000, 1.2345, 0.0000],
[0.5432, 0.0000, 0.0000, 2.3456]])
注意: インプレース操作はメモリを節約できますが、場合によっては勾配計算に影響を与える可能性があります。トレーニングの初期や中間の活性化値を保持する必要がある場合は、デフォルトの
inplace=False。
例3: ニューラルネットワークでの使用
畳み込みニューラルネットワークでは、ReLU は通常、畳み込み層の後に続きます:
例
import torch.nn as nn
# 簡単な畳み込みニューラルネットワークを定義
class SimpleCNN(nn.Module):
def __init__(self):
super(SimpleCNN, self).__init__()
# 畳み込み層: 入力3チャンネル、出力32チャンネル、カーネル3x3
self.conv1 = nn.Conv2d(3, 32, kernel_size=3, padding=1)
# ReLU 活性化
self.relu1 = nn.ReLU()
# 2番目の畳み込み層
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
self.relu2 = nn.ReLU()
# プーリング層
self.pool = nn.MaxPool2d(2, 2)
def forward(self, x):
x = self.conv1(x)
x = self.relu1(x)
x = self.pool(x)
x = self.conv2(x)
x = self.relu2(x)
x = self.pool(x)
return x
# モデルを作成
model = SimpleCNN()
# モデル構造を出力
print("モデル構造:")
print(model)
# 順伝播をテスト
# 3x32x32 のカラー画像をシミュレート
input_image = torch.randn(1, 3, 32, 32)
output = model(input_image)
print("n入力形状:", input_image.shape)
print("出力形状:", output.shape)
出力結果は次のとおりです:
模型结构: SimpleCNN( (conv1): Conv2d(3, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (relu1): ReLU() (conv2): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) (relu2): ReLU() (pool): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False) ) 输入形状: torch.Size([1, 3, 32, 32]) 输出形状: torch.Size([1, 64, 8, 8])
例4: nn.functional.relu を使用
PyTorch には関数型インターフェースも用意されていますtorch.nn.functional.relu:
例
import torch.nn.functional as F
# 関数型インターフェースを使用
input_tensor = torch.randn(1, 5, 5)
# 方法1: 関数型インターフェースを使用
output1 = F.relu(input_tensor)
# 方法2: inplace バージョンの関数を使用
F.relu_(input_tensor)
print("出力:n", output1)
両者の違い:
nn.ReLUモジュールクラスであり、モデル定義で使用でき、パラメータを保持します。F.relu関数型インターフェースであり、forwardメソッドや学習可能なパラメータがない場合によく使用されます。F.relu_インプレースバージョンのアンダースコア関数です。
他の活性化関数との比較
| 活性化関数 | 式 | 特徴 | 適用シーン |
|---|---|---|---|
nn.ReLU |
max(0, x) | 計算が簡単、スパース活性化 | 一般的な深層学習(デフォルトの選択) |
nn.LeakyReLU |
x > 0 ? x : 0.01x | 負の軸にわずかな勾配がある | 「死滅ニューロン」を防ぐ | nn.GELU |
x * Φ(x) | スムーズな近似、Transformer のデフォルト | Transformer、BERT など |
nn.Sigmoid |
1/(1+e^(-x)) | 出力0-1、勾配飽和 | 出力層、二値分類 |
nn.Tanh |
(e^x - e^(-x))/(e^x + e^(-x)) | 出力 -1 から 1、ゼロ中心化 | RNN、LSTM |
よくある質問
Q1: ReLU はなぜ「死滅ニューロン」問題を引き起こすのですか?
入力が継続的に負の場合、ReLU の出力は常に0になり、勾配も0になるため、これらのニューロンは学習できなくなります。
解決方法:
- 使用
nn.LeakyReLU或nn.ELU代替 - より小さな初期学習率を使用する
- バッチ正規化を採用する
Q2: ReLU は出力層に適していますか?
通常は適していません。出力層ではより一般的に使用されるのはSigmoid(分類)または恒等関数(回帰)です。なぜなら ReLU の出力は非有界だからです。
使用シーン
nn.ReLU深層学習で最もよく使われる活性化関数であり、主な適用シーンは次のとおりです:
- 畳み込みニューラルネットワーク: 畳み込み層または全結合層の後に非線形性を導入します。
- 多層パーセプトロン: 隠れ層の活性化関数として使用されます。
- TransformerFFN(Feed-Forward Network)内で活性化関数として使用されます(現在はGELUがより多く使用されていますが)。
- 生成対抗ネットワーク: 生成器の活性化関数として使用されます。
ヒント:特別な要件がない限り、ニューラルネットワークを設計する際、ReLU が隠れ層の活性化関数の第一候補です。
その他の拡張