文章目录
习题4-2 试设计一个前馈神经网络来解决 XOR 问题,要求该前馈神经网络具有两个隐藏神经元和一个输出神经元,并使用 ReLU 作为激活函数.
分析
XOR输入为2个神经元,输出为一个神经元,此题要求隐藏神经元为2个,故只要两层全连接层即可
- 数据集:输入为两位二进制,共四种情况,输出为一个二进制表示的数,要么为0,要么为1
- 网络模型:用pytorch搭建两层全连接层神经网络
- 训练:计算网络输出,计算损失函数,反向传播,参数更新
- 求权重和偏置
- 测试
代码如下:
import torch.nn as nn
import torch
import torch.optim as optim
# 异或门模块由两个全连接层构成
class XORModule(nn.Module):
def __init__(self):
super(XORModule, self).__init__()
self.fc1 = nn.Linear(2, 2)
self.fc2 = nn.Linear(2, 1)
self.relu = nn.ReLU()
def forward(self, x):
x = x.view(-1, 2)
x = self.relu((self.fc1(x)))
x = self.fc2(x)
return x
# 输入和输出数据
input_x = torch.Tensor([[0, 0], [0, 1], [1, 0], [1, 1]])
input_x1 = input_x.float()
real_y = torch.Tensor([[0], [1], [1], [0]])
real_y1 = real_y.float()
# 设置损失函数和参数优化函数
net = XORModule()
loss_function = nn.MSELoss(reduction='mean') # 用交叉熵损失函数会出现维度错误
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9) # 用Adam优化参数选不好会出现计算值超出0-1的范围
# 进行训练
for epoch in range(10000):
out_y = net(input_x1)
loss = loss_function(out_y, real_y1) # 计算损失函数
optimizer.zero_grad() # 对梯度清零,避免造成累加
loss.backward() # 反向传播
optimizer.step() # 参数更新
# 打印计算的权值和偏置
print('w1 = ', net.fc1.weight.detach().numpy())
print('b1 = ', net.fc1.bias.detach().numpy())
print('w2 = ', net.fc2.weight.detach().numpy())
print('b2 = ', net.fc2.bias.detach().numpy())
input_test = input_x1
out_test = net(input_test)
print('input_x', input_test.detach().numpy())
print('out_y', out_test.detach().numpy())
运行结果:
权重和偏置结果:
测试结果:
习题4-3 试举例说明“死亡ReLU问题”,并提出解决方法.
在反向传播过程中,如果学习率比较大,一个很大的梯度经过ReLU神经元,可能会导致ReLU神经元更新后的偏置和权重是负数,进而导致下一轮正向传播过程中ReLU神经元的输入是负数,输出是0。由于ReLU神经元的输出为0,在后续迭代的反向过程中,该处的梯度一直为0,相关参数不再变化,从而导致ReLU神经元的输入始终是负数,输出始终为0。即为“死亡ReLU问题”.
举例:
解决方法:
- 使用Leaky ReLU/PReLU、ELU函数或者Softplus函数替换
- 使用带泄露的ReLU
- 使用带参数的ReLU
- 使用正则项约束参数
- 使用其他方式训练网络,例如Adam
- 使用L2正则化,或者其他的梯度下降方式如动能、RMS 、Adam等可以避免,但他们可以改变的原理还是因为这些算法使得w在一次更新中变化的缓和了,所以想要尽量避免死亡节点,最好的办法还是学习率不要设置太大。
习题4-7 为什么在神经网络模型的结构化风险函数中不对偏置b进行正则化?
正则化主要是为了防止过拟合,而过拟合一般表现为模型对于输入的微小改变产生了输出的较大差异,这主要是由于有些参数 w 过大的关系,通过对||w|| 进行惩罚,可以缓解这种问题。而如果对||b|| 进行惩罚,其实是没有作用的,因为在对输出结果的贡献中,参数b对于输入的改变是不敏感的,不管输入改变是大还是小,参数b的贡献就只是加个偏置而已。
或者说,模型对于输入的微小改变产生了输出的较大差异,这是因为模型的“曲率”太大,而模型的曲率是由 w 决定的,b 不贡献曲率(对输入进行求导, b 是直接约掉的)。
习题4-8 为什么在用反向传播算法进行参数学习时要采用随机参数初始化的方式而不是直接令 w= 0, 𝒃 = 0?
因为如果参数都设为0,那么第一次计算时,隐层神经元的计算结果都一样,并且在反向传播时参数更新也一样,导致在每两层之间的参数都是一样的,这样相当于隐层只有 1个神经元,隐藏层神经元没有区分性。这种现象称为对称权重现象。
习题4-9 梯度消失问题是否可以通过增加学习率来缓解?
分情况,在深层神经网络的浅层如果使用较大的学习率可能会导致模型跨过全局最优点而进入局部最优点。
但在网络的深层使用较大的学习率则可以保证网络的参数仍然在被更新,以达到更好的学习效果。
梯度消失是指梯度在最后一层往前传的过程中不断减小,最终直至近乎为0。因此,“可以缓解”是因为使用一个较大的学习率与这个较小的导数相乘所得到的的结果就没那么小了。“不可以缓解”是因为这样会导致这个较大的学习率与最开始较大的导数相乘结果十分巨大,导致梯度爆炸。
总结
本次习题作业与上次实验内容有许多共通之处,例如死亡Relu问题,梯度消失、梯度爆炸问题等,同时我对正则化,过拟合及欠拟合的理解也更加深入。对梯度消失问题与学习率的增加之间的关系理解更加明确。