admin管理员组

文章数量:1579086

习题4-2 试设计一个前馈神经网络来解决 XOR 问题,要求该前馈神经网络具有两个隐藏神经元和一个输出神经元,并使用 ReLU 作为激活函数.

实现代码:

import torch
import torch.nn as nn
import torch.nn.functional as F
from sklearn.metrics import accuracy_score
import numpy as np
from sklearn.svm import SVC


# XOR问题由两个全连接层构成
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]]).to(torch.float32)
label = torch.Tensor([[0], [1], [1], [0]]).to(torch.float32)
# 设置损失函数和参数优化函数
module = XORModule()
learing_rate = 0.01
epochs = 10000
loss_function = nn.MSELoss(reduction='mean')  # 用交叉熵损失函数会出现维度错误
optimizer = torch.optim.SGD(module.parameters(), lr=learing_rate)  # 用Adam优化参数选不好会出现计算值超出0-1的范围

# 进行训练
for epoch in range(epochs):
    out_y = module(input_x)
    loss = loss_function(out_y, label)  # 计算损失函数
    # print('啦啦啦')
    optimizer.zero_grad()  # 对梯度清零,避免造成累加
    loss.backward()  # 反向传播
    optimizer.step()  # 参数更新

out_test = module(input_x)
print( "前馈神经网络的准确率:{}%".format(accuracy_score(out_test.detach().numpy().astype(np.int64), label.detach().numpy()) * 100))

输出结果:

 准确率有点低,增加隐藏层数再试试

import torch
import torch.nn as nn
import torch.nn.functional as F
from sklearn.metrics import accuracy_score
import numpy as np
from sklearn.svm import SVC


# XOR问题由两个全连接层构成
class XORModule(nn.Module):
    def __init__(self):
        super(XORModule, self).__init__()
        self.fc1 = nn.Linear(2, 50)
        self.fc2 = nn.Linear(50, 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]]).to(torch.float32)
label = torch.Tensor([[0], [1], [1], [0]]).to(torch.float32)
# 设置损失函数和参数优化函数
module = XORModule()
learing_rate = 0.01
epochs = 10000
loss_function = nn.MSELoss(reduction='mean')  # 用交叉熵损失函数会出现维度错误
optimizer = torch.optim.SGD(module.parameters(), lr=learing_rate)  # 用Adam优化参数选不好会出现计算值超出0-1的范围

# 进行训练
for epoch in range(epochs):
    out_y = module(input_x)
    loss = loss_function(out_y, label)  # 计算损失函数
    # print('啦啦啦')
    optimizer.zero_grad()  # 对梯度清零,避免造成累加
    loss.backward()  # 反向传播
    optimizer.step()  # 参数更新

out_test = module(input_x)
print( "前馈神经网络的准确率:{}%".format(accuracy_score(out_test.detach().numpy().astype(np.int64), label.detach().numpy()) * 100))

得到结果:

 这是非常好的结果了


习题4-3 试举例说明“死亡ReLU问题”,并提出解决方法

梯度消失:在神经网络的构建过程中,随着网络层数的增加,理论上网络的拟合能力也应该是越来越好的。但是随着网络变深,参数学习更加困难,容易出现梯度消失问题。由于Sigmoid型函数的饱和性,饱和区的导数更接近于0,误差经过每一层传递都会不断衰减。当网络层数很深时,梯度就会不停衰减,甚至消失,使得整个网络很难训练,这就是所谓的梯度消失问题。

在深度神经网络中,减轻梯度消失问题的方法有很多种,一种简单有效的方式就是使用导数比较大的激活函数,如:ReLU,但ReLu会出现“死亡ReLU”问题。
 

死亡ReLU问题:ReLU激活函数是改善梯度消失问题的一种方法,但是在某些情况下容易出现死亡 ReLU问题,使得网络难以训练。这是由于当x<0时,ReLU函数的输出恒为0。在训练过程中,如果参数在一次不恰当的更新后,某个ReLU神经元在所有训练数据上都不能被激活(即输出为0),那么这个神经元自身参数的梯度永远都会是0,在以后的训练过程中永远都不能被激活。
 

改善方法:

1.我认为最简单的方法是调整学习率。我们知道,ReLU叠加越多层越容易出现神经元活性失效,所以可以简单通过降低学习率的方法来缓解神经元活性失效的问题。甚至可以说这是一种通用且有效的方法。

2.将激活函数更换为Leaky ReLU函数,这个尝试在本周的实验中就已经试过,效果也十分的显著。


习题4-7 为什么在神经网络模型的结构化风险函数中不对偏置b进行正则化?

这个问题对我而言太难,于是查找资料得到如下说法:

对于神经网络正则化,一般只对每一层仿射变换的weights进行正则化惩罚,而不对偏置bias进行正则化。

相比于weight,bias训练准确需要的数据要更少。每个weight指定了两个变量之间的关系。weights训练准确需要在很多种情况下的同时观察两个变量。每个bias只控制一个变量。这意味着不对bias正则化,没有引入很多方差(variance)。同时,对bias进行正则化容易引起欠拟合。

原文:

Before delving into the regularization behavior of different norms, we note that for neural networks, we typically choose to use a parameter norm penalty Ω that penalizes only the weights of the affine transformation at each layer and leaves the biases unregularized. The biases typically require less data to fit accurately than the weights. Each weight specifies how two variables interact. Fitting the weight well requires observing both variables in a variety of conditions. Each bias controls only a single variable. This means that we do not induce too much variance by leaving the biases unregularized.Also,regularizing the bias parameters can introduce a significant amount of underfitting.

总结:

这个偏置 b 对于函数来说只是平移,并且 b 对输入的改变是不敏感的,无论输入变大还是变小,b 对结果的贡献只是一个偏置,因此其对过拟合没有帮助。


习题 4-8 为什么在用反向传播算法进行参数学习时要采用随机参数初始化的方式而不是直接令 w= 0, 𝒃 = 0?

如果 W=0,b=0 ,第一次计算时,隐藏层神经元的计算结果是完全相同的,并且在反向传播时参数更新也一致,导致每两层间的参数都一样,等价于隐藏层只有 1 个神经元,浪费资源,减缓效率。

用之前实验的例子:

二分类准确率维持为50%左右,说明模型没有学到任何内容。训练和验证loss几乎没有怎么下降。 


习题4-9 梯度消失问题是否可以通过增加学习率来缓解?

梯度消失问题是由于激活函数为类似于Sigmoid,其值太大或太小时导数都趋于0,并且在深层网络中,误差反向传播时,传播到前几层时梯度信息也会很小。现在问可否通过增大学习率来增大梯度,以至于梯度信息可以在更新时变大,应该是不行,增大学习率带来的缺陷会比梯度消失问题更加严重,学习率变大时,很容易使得参数直接跳过最优值点,然后梯度方向改变,导致参数优化时无法有效收敛,进而无法得到理想的训练结果。


 总结心得:

这几个问题都与前面的实验有关,所以回答起来会比较有经验,不会的就上网搜资料再自己理解一下,也算是查漏补缺,循序渐进的进步吧。

本文标签: 作业第四章课后NNDL