异或神经网络中的死亡RELU问题

192 阅读1分钟

使用带有一个隐藏层的MLP训练简单的异或神经网络,发现当设置不同的随机种子时,模型有时候收敛,有时候并不收敛。

不收敛的代码例子:

import torch
import torch.nn as nn
torch.manual_seed(24)

class XOR(nn.Module):
    def __init__(self):
        super(XOR, self).__init__()
        self.fc1 = nn.Linear(2, 2)
        self.fc2 = nn.Linear(2, 1)

    def forward(self, x):
        x = torch.relu(self.fc1(x))
        x = torch.sigmoid(self.fc2(x))
        return x

def init_weights(m):
    if type(m) == nn.Linear:
        torch.nn.init.kaiming_normal_(m.weight)
        m.bias.data.fill_(0.01)

model = XOR()
model.apply(init_weights)
EPOCH = 10000
criterion = nn.BCELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
inputs = torch.tensor([[0, 0], [0, 1], [1, 0], [1, 1]], dtype=torch.float32)
labels = torch.tensor([[0], [1], [1], [0]], dtype=torch.float32)
for epoch in range(EPOCH):
    optimizer.zero_grad()
    outputs = model(inputs)
    loss = criterion(outputs, labels)
    loss.backward()
    optimizer.step()
    if epoch % 1000 == 0:
        print(f'Epoch [{epoch + 1}/{EPOCH}], Loss: {loss.item()}')

此时运行代码会发现loss居高不下,获取反向传播的梯度情况,发现此时fc1层梯度消失。经过分析,发现这是因为ReLU(Rectified Linear Unit)激活函数引发梯度消失问题,被称为"死亡ReLU"(Dead ReLU)问题。

当ReLU的输入为负时,它会输出零;当输入为正时,输出为原值。因此,如果神经网络中的某些神经元的输出始终为零(即ReLU的输入始终小于零),那么这些神经元的梯度将永远为零,导致它们在反向传播中无法更新,从而“死亡”。