Part4.第8-9章:神经网络

第8章:神经网络

激活函数

如果没有激活函数,不论几层的神经网络都是一个线性回归。激活函数的作用是引入非线性
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

交叉熵损失函数

在这里插入图片描述
首先要理解信息量和信息熵
前提结论:一个系统的信息熵是对这个系统平均最小的编码长度。
你真的理解交叉熵损失函数了吗?

反向传播

多分类神经网络的反向传播

梯度消失与梯度爆炸

神经网络的每层权重和偏置的梯度计算。我们利用链式求导,从最终的loss值开始,逐层反向计算梯度值。最终导致前边层的梯度值,是很多导数值的连乘。
很多数的连乘有个问题,就是如果这些数都小于1,导致梯度非常小,几乎消失,让参数无法更新。如果这些数都大于1,比如都为1.5,100个1.5连乘,结果大概是4.1乘10的17次方。导致梯度过大,称为梯度爆炸。不论梯度消失还是梯度爆炸。

手动实现多分类网络

代码建议参考原文:手动实现多分类网络

用Pytorch实现多分类网络

代码建议参考原文:用Pytorch实现多分类网络

第9章:优化神经网络

L1和L2正则化

正则化(Regularization)技术就是通过一些技术手段来限制模型的复杂度,从而改进模型过拟合的问题,让模型有更好的泛化性。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在PyTorch里增加L2正则化

l2_norm = 0.0
for param in model.parameters():
      l2_norm += param.pow(2).sum()
loss = criterion(outputs, labels) + 1e-4 * l2_norm

在PyTorch里增加L2正则化非常简单,就是遍历所有参数,对所有参数进行平方并加和。最终将这个值乘以一个很小的系数,比如上边代码里的1-e4,最终加入到loss中就可以。

指数加权平均

具体案例参考原文便于理解。
指数加权平均改进版如下:
在这里插入图片描述

动量梯度下降(Momentum Gradient Descent)

在接近最优点时会产生震荡,如上图所示,沿纵轴b参数的方向产生了震荡。这样训练下去永远到达不了最优点。
梯度下降还有一个问题,当某一参数有局部最优解时,也就是loss对这个参数的偏导数在某一个很小的局部接近0。这时,传统的梯度下降算法对这个参数的更新就非常慢,停滞不前。
动量梯度下降的做法是每次不用当前每个参数的梯度值来更新参数,而是用梯度值的指数加权平均来更新参数。它可以很好的解决上边说的梯度下降的两个问题。
在这里插入图片描述

RMSProp优化器

RMSProp(Root Mean Square Propagation optimizer)均方根传播优化器,也是在标准梯度下降优化器上进行了改进。
我们在进行深度神经网络的训练时,所有的参数都用同一个学习率。这会导致一个问题,有的参数梯度大,有的参数梯度小。如果你设置的学习率过大,会导致梯度大的参数在最优值附近来回震荡,不能收敛。如果你设置学习率过小,导致梯度小的参数学习停滞不前。
在这里插入图片描述

Adam优化器

Adam(Adaptive Moment Estimation),结合了Momentum优化器和RMSProp优化器的优点,目前已经是深度学习领域默认的优化器。 Adam优化器同时利用动量来给梯度更新增加惯性和震荡阻尼,也利用历史梯度的均方根来自适应调整学习率。
在这里插入图片描述

权重衰减

权重衰减(Weight Decay)是一种在模型训练过程中防止模型过拟合的技术。
权重衰减的思想很简单,就是在训练的每一步用梯度更新参数时,同时缩小参数值。防止参数的绝对值过大。权重衰减的思想和L1、L2正则是类似的,都是减少参数的绝对值。不同的是L1、L2正则是在loss函数里增加额外项实现的。而权重衰减的做法更直接,直接减小参数的绝对值。
在这里插入图片描述
PyTorch里一般在定义优化器时,可以同步设置weight decay。并指定λ的值。

optimizer = optim.SGD(model.parameters(), lr=0.1, weight_decay=1e-4)

在这里插入图片描述

Dropout

在训练阶段,Dropout会按照超参数p的设置,随机禁用一些神经元。被禁用的神经元不接受任何输入也不为下一层的神经元提供输出。Dropout一般应用在隐藏层,不对输入和输出层应用。
注意,每次前向传播禁用的神经元并不相同,每个神经元都有p的概率被禁用。 对于保留的神经元的输出也需要做一些调整,对于未被禁用的神经元的输出需要除以1−p来进行缩放。这样就确保了下一层进行线性计算时,输入加权累加值的期望不变。

Dropout可以理解成每次都在训练一个简化的神经网络,让网络每个神经元都学到通用的特征,而不是过份依赖某几个神经元。
在利用Dropout训练好了一个神经网络了,要利用训练好的神经网络进行预测,也叫做推理阶段。这时,Dropout不起作用,所有神经元都起作用。因为之前在训练时对起作用的神经元做过缩放操作,它保证了推理阶段的数值稳定。
在PyTorch里定义Dropout层很简单,如下代码所示:

# 模型定义(加入 Dropout)
class NeuralNetwork(nn.Module):
    def __init__(self):
        super().__init__()
        self.model = nn.Sequential(
            nn.Linear(28 * 28, 128),
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(128, 128),
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(128, 128),
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(128, 64),
            nn.ReLU(),
            nn.Dropout(0.5),
            nn.Linear(64, 10)
        )

    def forward(self, x):
        return self.model(x)

对代码解释如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
p的值我们一般取0.1-0.5。p值越大,正则化效果越强。 还有一点需要注意,Dropout 在训练阶段与推理阶段的行为是不同的,所以你一定在训练前调用model.train(),推理前调用model.eval()函数。

model.train()
## 在这里训练你的模型。
model.eval()  # eval()会切换到推理模式,禁用dropout
## 在这里利用模型进行预测。

批量归一化(Batch Normalization)

批量归一化(Batch Normalization)是一种在深度学习里常用的技术,它可以让深度神经网络的训练更稳定,收敛更快。
我们对输入的数据进行了归一化,它让不同的特征取值范围都是相似的,但是随着网络的前向传播,网络深处层的输入取值范围又会被逐渐拉大。这让更新这些层的参数变得不稳定。
那我们是否可以对神经网络的每一层的输出(下一层的输入)进行归一化呢?这就是批量归一化的动机。
在这里插入图片描述
因为每个神经元的z值,在进行批量归一化时都要减去这个batch z值的均值,所以就没有必要在计算z值的线性变化里加上偏置项b了,因为不论学到的b是多少,在减去均值后,结果都是一样的。所以如果你对一个线性层后边要加批量归一化,那么这一层就可以不设置偏置项。另外输出层一般不加批量归一化层
在这里插入图片描述
PyTorch里有定义好的BatchNorm的层,我们需要把它添加在线性变化和激活函数之间就可以了。它需要传入线性变化输出的神经元的个数。具体代码如下:

import torch.nn as nn

class NeuralNetwork(nn.Module):
    def __init__(self):
        super().__init__()
        self.model = nn.Sequential(
            nn.Linear(28 * 28, 128, bias=False),
            nn.BatchNorm1d(128),
            nn.ReLU(),

            nn.Linear(128, 128, bias=False),
            nn.BatchNorm1d(128),
            nn.ReLU(),

            nn.Linear(128, 128, bias=False),
            nn.BatchNorm1d(128),
            nn.ReLU(),

            nn.Linear(128, 64, bias=False),
            nn.BatchNorm1d(64),
            nn.ReLU(),

            nn.Linear(64, 10)
        )

    def forward(self, x):
        return self.model(x)

训练时和推理时的Batch Normalization的操作是不一样的。所以也要记得调用model.train()和model.eval()来切换模型的状态。

model.train()
## 在这里训练你的模型。
model.eval()
## 在这里利用模型进行预测。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值