4.2试设计一个前馈神经网络来解决XOR问题,要求该前馈神经网络具有两个隐藏神经元和一个输出神经元,并使用ReLU作为激活函数.
import torch
import torch.nn as nn
import torch.optim as optim
import numpy
# 异或门模块由两个全连接层构成
class XORModule(nn.Module):
def __init__(self):
super(XORModule, self).__init__()
self.fc1 = nn.Linear(2, 2)
torch.nn.init.normal_(self.fc1.weight, 0.0, 1.0)
torch.nn.init.constant_(self.fc1.bias, 0.0)
self.fc2 = nn.Linear(2, 1)
torch.nn.init.normal_(self.fc2.weight, 0.0, 1.0)
torch.nn.init.constant_(self.fc2.bias, 0.0)
self.act = torch.relu
def forward(self, inputs):
outputs = self.fc1(inputs)
outputs = self.act(outputs)
outputs = self.fc2(outputs)
outputs = self.act(outputs)
return outputs
# 输入和输出数据
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 = torch.nn.MSELoss() # 用交叉熵损失函数会出现维度错误
optimizer = optim.SGD(net.parameters(), lr=0.1) # 用Adam优化参数选不好会出现计算值超出0-1的范围
# 进行训练
for epoch in range(10000):
out_y = net(input_x1)
loss = loss_function(out_y, real_y1) # 计算损失函数
loss.backward() # 反向传播
optimizer.step() # 参数更新
optimizer.zero_grad() # 对梯度清零,避免造成累加
# 进行测试
input_test = input_x
out_test = net(input_test)
print('输入x', input_test.detach().numpy())
print('预测值y', numpy.around(out_test.detach().numpy()))
输出
输入x [[0. 0.]
[0. 1.]
[1. 0.]
[1. 1.]]
预测值y [[0.]
[1.]
[1.]
[0.]]
进程已结束,退出代码为 0
4.3 试举例说明“死亡ReLU问题”,并提出解决办法。
在反向传播过程中,如果学习率比较大,一个很大的梯度经过ReLU神经元,可能会导致ReLU神经元更新后的偏置和权重是负数,进而导致下一轮正向传播过程中ReLU神经元的输入是负数,输出是0。由于ReLU神经元的输出为0,在后续迭代的反向过程中,该处的梯度一直为0,相关参数不再变化,从而导致ReLU神经元的输入始终是负数,输出始终为0。即为“死亡ReLU问题”
解决方法:
使用Leaky ReLU/PReLU、ELU函数或者Softplus函数替换。
4.7为什么神经网络模型的结构化风险函数中不对偏置b进行正则化。
在神经网络模型的结构化风险函数中加入正则化项,可以避免过拟合,对于偏置b bb进行正则化对于防止过拟合没有什么影响。
4.8为什么用反向传播算法进行参数学习时要采用随机参数初始化的方法而不是直接令W=0,b=0?
反向传播就是要将神经网络的输出误差,一级一级地传播到输入。在计算过程中,计算每一个w 对总的损失函数的影响,即损失函数对每个w 的偏导。根据w 的误差的影响,再乘以步长,就可以更新整个神经网络的权重。当一次反向传播完成之后,网络的参数模型就可以得到更新。更新一轮之后,接着输入下一个样本,算出误差后又可以更新一轮,再输入一个样本,又来更新一轮,通过不断地输入新的样本迭代地更新模型参数,就可以缩小计算值与真实值之间的误差,最终完成神经网络的训练。当直接令w =0,b=0时,会让下一层神经网络中所有神经元进行着相同的计算,具有同样的梯度,同样权重更新。