PyTorch torch.nn.Dropout 関数
torch.nn.DropoutPyTorchにおける正則化のためのモジュールです。
入力要素をランダムにゼロにすることで、ニューロン間の共同適応を減らし、過学習を防ぎます。
関数定義
torch.nn.Dropout(p=0.5, inplace=False)
パラメータの説明:
p(float): 各要素がゼロにされる確率。デフォルトは0.5です。inplace(bool): インプレース操作を実行するかどうか。デフォルトはFalseです。
使用例
例1:基本的な使い方
Dropout層を作成して使用する:
実例
import torch
import torch.nn as nn
# Dropout層を作成、ドロップアウト率0.5
dropout = nn.Dropout(p=0.5)
# トレーニングモード(Dropout有効)
dropout.train()
# 入力を作成
input_tensor = torch.ones(1, 10)
print("入力:", input_tensor.squeeze().tolist())
# 順伝播を複数回実行してランダム性を確認
for i in range(3):
output = dropout(input_tensor)
print(f"第{i+1}回目の出力:", output.squeeze().tolist())
import torch.nn as nn
# Dropout層を作成、ドロップアウト率0.5
dropout = nn.Dropout(p=0.5)
# トレーニングモード(Dropout有効)
dropout.train()
# 入力を作成
input_tensor = torch.ones(1, 10)
print("入力:", input_tensor.squeeze().tolist())
# 順伝播を複数回実行してランダム性を確認
for i in range(3):
output = dropout(input_tensor)
print(f"第{i+1}回目の出力:", output.squeeze().tolist())
呼び出しのたびに、ランダムにおよそ半分の要素がゼロになっていることがわかります。
例2:トレーニング vs 評価モード
Dropoutはトレーニング時と評価時で動作が異なります:
実例
import torch
import torch.nn as nn
dropout = nn.Dropout(p=0.5)
# トレーニングモード
dropout.train()
train_output = dropout(torch.ones(4, 10))
print("トレーニングモード - 活性化率:", (train_output != 0).float().mean().item())
# 評価モード
dropout.eval()
eval_output = dropout(torch.ones(4, 10))
print("評価モード - 活性化率:", (eval_output != 0).float().mean().item())
print("評価モード出力:", eval_output[0].tolist())
import torch.nn as nn
dropout = nn.Dropout(p=0.5)
# トレーニングモード
dropout.train()
train_output = dropout(torch.ones(4, 10))
print("トレーニングモード - 活性化率:", (train_output != 0).float().mean().item())
# 評価モード
dropout.eval()
eval_output = dropout(torch.ones(4, 10))
print("評価モード - 活性化率:", (eval_output != 0).float().mean().item())
print("評価モード出力:", eval_output[0].tolist())
評価時はDropoutは機能せず、出力はそのまま維持されます。
例3:ニューラルネットワークでの使用
Dropout付きの典型的な全結合ネットワーク:
実例
import torch
import torch.nn as nn
class DropoutNet(nn.Module):
def __init__(self, input_dim=784, hidden_dim=256, output_dim=10, dropout_rate=0.5):
super(DropoutNet, self).__init__()
self.fc1 = nn.Linear(input_dim, hidden_dim)
self.dropout1 = nn.Dropout(p=dropout_rate)
self.fc2 = nn.Linear(hidden_dim, hidden_dim)
self.dropout2 = nn.Dropout(p=dropout_rate)
self.fc3 = nn.Linear(hidden_dim, output_dim)
self.relu = nn.ReLU()
def forward(self, x):
x = self.relu(self.fc1(x))
x = self.dropout1(x) # 1回目のDropout
x = self.relu(self.fc2(x))
x = self.dropout2(x) # 2回目のDropout
x = self.fc3(x)
return x
model = DropoutNet()
# トレーニングモード
model.train()
input_data = torch.randn(32, 784)
output = model(input_data)
print("トレーニングモード出力形状:", output.shape)
# 評価モード
model.eval()
output = model(input_data)
print("評価モード出力形状:", output.shape)
import torch.nn as nn
class DropoutNet(nn.Module):
def __init__(self, input_dim=784, hidden_dim=256, output_dim=10, dropout_rate=0.5):
super(DropoutNet, self).__init__()
self.fc1 = nn.Linear(input_dim, hidden_dim)
self.dropout1 = nn.Dropout(p=dropout_rate)
self.fc2 = nn.Linear(hidden_dim, hidden_dim)
self.dropout2 = nn.Dropout(p=dropout_rate)
self.fc3 = nn.Linear(hidden_dim, output_dim)
self.relu = nn.ReLU()
def forward(self, x):
x = self.relu(self.fc1(x))
x = self.dropout1(x) # 1回目のDropout
x = self.relu(self.fc2(x))
x = self.dropout2(x) # 2回目のDropout
x = self.fc3(x)
return x
model = DropoutNet()
# トレーニングモード
model.train()
input_data = torch.randn(32, 784)
output = model(input_data)
print("トレーニングモード出力形状:", output.shape)
# 評価モード
model.eval()
output = model(input_data)
print("評価モード出力形状:", output.shape)
例4:CNNでのDropout2dの使用
nn.Dropout2dチャネル単位で特徴マップ全体をドロップします:
実例
import torch
import torch.nn as nn
# Dropout2dはチャネル単位でドロップ
dropout2d = nn.Dropout2d(p=0.5)
# 入力:batch=1、チャネル=4、高さ=4、幅=4
input_tensor = torch.ones(1, 4, 4, 4)
dropout2d.train()
output = dropout2d(input_tensor)
print("Dropout2d 出力形状:", output.shape)
print("非ゼロチャネル数:", (output.sum(dim=(2, 3)) != 0).sum().item())
import torch.nn as nn
# Dropout2dはチャネル単位でドロップ
dropout2d = nn.Dropout2d(p=0.5)
# 入力:batch=1、チャネル=4、高さ=4、幅=4
input_tensor = torch.ones(1, 4, 4, 4)
dropout2d.train()
output = dropout2d(input_tensor)
print("Dropout2d 出力形状:", output.shape)
print("非ゼロチャネル数:", (output.sum(dim=(2, 3)) != 0).sum().item())
例5:異なるドロップアウト率の効果
ドロップアウト率がネットワークに与える影響:
実例
import torch
import torch.nn as nn
for p in [0.1, 0.3, 0.5, 0.7]:
dropout = nn.Dropout(p=p)
dropout.train()
# 複数回実行して平均を取る
total_active = 0
for _ in range(100):
output = dropout(torch.ones(1000))
total_active += (output != 0).float().sum().item()
avg_active = total_active / 100 / 1000
print(f"p={p} - 平均活性化率: {avg_active:.2%} (期待値: {1-p:.2%})")
import torch.nn as nn
for p in [0.1, 0.3, 0.5, 0.7]:
dropout = nn.Dropout(p=p)
dropout.train()
# 複数回実行して平均を取る
total_active = 0
for _ in range(100):
output = dropout(torch.ones(1000))
total_active += (output != 0).float().sum().item()
avg_active = total_active / 100 / 1000
print(f"p={p} - 平均活性化率: {avg_active:.2%} (期待値: {1-p:.2%})")
Dropout タイプの比較
| 種類 | ドロップ方法 | 適用シーン |
|---|---|---|
nn.Dropout |
単一要素をランダムにゼロ化 | 全結合層、特徴ベクトル |
nn.Dropout2d |
チャネル全体をランダムにゼロ化 | 畳み込み層の特徴マップ |
nn.Dropout3d |
3Dチャネル全体をランダムにゼロ化 | 3D畳み込み特徴 |
よくある質問
Q1:Dropoutのドロップアウト率はどのように選びますか?
- 0.1〜0.3:軽い正則化で、大規模データセットに適しています
- 0.4〜0.5:よく使われるデフォルト値
- 0.5以上:強い正則化で、小規模データセットに適しています
Q2:Dropoutはどこに置きますか?
通常は全結合層の後、活性化関数の後に置きます。活性化関数の前に置くこともできます。
Q3:評価時にDropoutを無効にする必要がありますか?
はい、評価時にはmodel.eval()を使用しますmodel.eval()自動的にDropoutが無効になります。
使用シーン
nn.Dropout主な適用シーンは次のとおりです:
- 過学習の防止:ニューロン間の依存を減らす
- モデルアンサンブル:複数のネットワークの効果を近似する
- 全結合層:FC層で最もよく使われる
- 特徴ドロップ:モデルのロバスト性を向上させる
注意:Dropoutはトレーニング時に有効になり、評価時は必ずevalモードに切り替えてください。そうしないと出力が不安定になります。
その他の拡張
PyTorch torch.nn リファレンスマニュアル