2.《动手深度学习》之多层感知机

《动手深度学习》总结

0. 推荐资料

首先感谢在Datawhale的组织下,联合了李沐老师一起举办了本次的学习计划,在本次计划下也记录一下自己的学习过程。
本次学习教程的参考书籍:动手学深度学习
本次学习教程的参考视频:李沐老师b站视频

1. 前言

     本书个人认为需要有线性、高等、概率论的基础,以及掌握一些基础的Pytorch框架知识,至少达到能看懂代码的程度。
     关于线性回归的总结,链接在这:《动手深度学习》之线性回归神经网络
     下面将总结一下《动手深度学习》的第四章内容。

2. 深度学习

多层感知机

     将下面的两张图进行对比,可以看出左边的图是将我们的输入直接映射到输出,然后进行softmax操作,但是这种做法有些许不太合理,即输入的某个特征相比于其他特征较大时,会导致模型输出的增大,这也就是为什么叫“线性”的原因,呈单调性。

     为了克服这种缺点,可以在网络中加入隐藏层,使其能处理更普遍的函数关系模型,如下面右边的图,就是一个简单的多层感知机:这个多层感知机有4个输入,3个输出,隐藏层包含5个隐藏单元。该多层感知机中的层数为2,且这两层都是全连接的。每个输入都会影响隐藏层中的每个神经元,而隐藏层中的每个神经元又会影响输出层中的每个神经元。

在这里插入图片描述

激活函数

为什么要使用激活函数?

  • a. 不使用激活函数,每一层输出都是上层输入的线性函数,无论神经网络有多少层,输出都是输入的线性组合。
  • b. 使用激活函数,能够给神经元引入非线性因素,使得神经网络可以任意逼近任何非线性函数,这样神经网络就可以利用到更多的非线性模中。

什么是激活函数?

​ 激活函数(activation function):通过计算加权和并加上偏置来确定神经元是否应该被激活,它们将输入信号转换为输出的可微运算。

常用的激活函数

  1. ReLU (Rectified linear unit)

     ReLU提供了一种非常简单的非线性变换,使用ReLU的原因是,它求导表现得特别好:要么让参数消失,要么让参数通过(当输入为负时,ReLU函数的导数为0,而当输入为正时,ReLU函数的导数为1)。这使得优化表现得更好,并且ReLU减轻了困扰以往神经网络的梯度消失问题。其定义为:
ReLU ⁡ ( x ) = max ⁡ ( x , 0 ) \operatorname{ReLU}(x) = \max(x, 0) ReLU(x)=max(x,0)
在这里插入图片描述

  1. Sigmoid

     sigmoid函数将输入变换为区间(0, 1)上的输出,sigmoid常用来做二分类,其缺点是计算量大,且反向传播时容易出现梯度消失。其公式为:
sigmoid ⁡ ( x ) = 1 1 + e − x d d x sigmoid ⁡ ( x ) = exp ⁡ ( − x ) ( 1 + exp ⁡ ( − x ) ) 2 = sigmoid ⁡ ( x ) ( 1 − sigmoid ⁡ ( x ) ) . \operatorname{sigmoid}(x) = \frac{1}{1 + e^{-x}} \\ \frac{d}{dx} \operatorname{sigmoid}(x) = \frac{\exp(-x)}{(1 + \exp(-x))^2} = \operatorname{sigmoid}(x)\left(1-\operatorname{sigmoid}(x)\right). sigmoid(x)=1+ex1dxdsigmoid(x)=(1+exp(x))2exp(x)=sigmoid(x)(1sigmoid(x)).
在这里插入图片描述

  1. tanh

     tanh(双曲正切)函数也能将其输入压缩转换到区间(-1,1)上,当输入在0附近时,tanh函数接近线性变换。函数的形状类似于sigmoid函数,不同的是tanh函数关于坐标系原点中心对称。
tanh ⁡ ( x ) = 1 − e − 2 x 1 + e − 2 x d d x tanh ⁡ ( x ) = 1 − tanh ⁡ 2 ( x ) . \operatorname{tanh}(x) = \frac{1 - e^{-2x}}{1 + e^{-2x}} \\ \frac{d}{dx} \operatorname{tanh}(x) = 1 - \operatorname{tanh}^2(x). tanh(x)=1+e2x1e2xdxdtanh(x)=1tanh2(x).
在这里插入图片描述

模型评估与选择

     到目前为止,深度学习的“大致”流程已经了解的差不多了:

  • ①是收集数据,并用代码加载
  • ②是定义模型(这部分还未讲解),自己实现一个神经网络模型
  • ③是定义超参数,并训练数据
  • ④是模型评估与选择

     在评估一个模型时,首先要了解两个概念“欠拟合”和“过拟合”。如下面这张图,就很好了反映了何为欠拟合,何为过拟合:

  • 欠拟合:训练集和验证集效果都差。简单理解就是模型未学到东西,就要让人家去考试。
    • 解决方法:增加特征数或增加数据集,增加模型复杂度(如添加网络层数),减小正则化系数。
  • 过拟合:在训练集上效果好,在验证集上效果差。简单理解就是模型在平时小测都表现的很好,期末考试就不行。
    • 解决方法:常见的有数据增强,降低模型复杂度,早停,正则化,Dropout等。

在这里插入图片描述

下面教如何判断是属于哪种情况:

​ 参考链接:欠拟合(Under fitting)和过拟合 (Overfitting) - 一抹烟霞 - 博客园 (cnblogs.com)

  1. 第一种:这种情况loss曲线还是在下降的,因此只需要进行更多更高效的训练即可:

    • 增大batch-size,增加训练epoch,增大learning rate等,也可换一种激活函数或优化器
      在这里插入图片描述
  2. 第二种:这种情况loss曲线已经不再下降,因此必须优化模型:

    1. 增加网络复杂度:增加层数;增加卷积层输出的通道数;增加全连接层的节点数
    2. 完善训练集和测试集的分布情况,若采用随机分割的话,有可能出现训练集上并未出现这个类别,但是测试集上又出现了;使用数据增强
      在这里插入图片描述
  3. 第三种:
    在这里插入图片描述

书本4.5及4.6总结*

     正则化思想就是在原来的损失L(W)上,加上了一个参数 λ \lambda λ,来控制正则化的大小。

     L1正则化: 常被用来进行特征选择,主要原因在于L1正则化会使得较多的参数为0,从而产生稀疏解,我们可以将0对应的特征遗弃,进而用来选择特征。公式如下:

  • w i w_i wi>0,sign( w i w_i wi)=1; w i w_i wi<0,sign( w i w_i wi)=-1
    L = L ( W ) + λ ∑ i = 1 n ∣ ω i ∣ ω i = ω i − η ∂ L ( W ) ∂ w i − η λ s i g n ( w i ) L=L(W)+λ\sum_{i=1}^{n}|\omega_i| \\ \omega_i=\omega_i-\eta\frac{\partial{L(W)}}{\partial{w_i}}-\eta\lambda{sign(w_i)} L=L(W)+λi=1nωiωi=ωiηwiL(W)ηλsign(wi)

     L2正则化: 主要用来防止模型过拟合,直观上理解就是L2正则化是对于大数值的权重向量进行严厉惩罚。鼓励参数是较小值,如果 w w w小于1,那么 w 2 w^2 w2会更小。

  • w i w_i wi<1的时,L2的惩罚项会越来越小,而L1还是会非常大,所以L1会使参数为0,而L2很难。
    L = L ( W ) + λ ∑ i = 1 n w i 2 w i = w i − η ∂ L ( W ) ∂ w i − 2 η λ w i L=L(W)+λ\sum_{i=1}^{n}{w_i}^2 \\ w_i = w_i - \eta\frac{\partial{L(W)}}{\partial{w_i}}-2\eta\lambda{w_i} L=L(W)+λi=1nwi2wi=wiηwiL(W)2ηλwi

     Dropout: 思想是在前向传播的过程中,丢弃某些神经元(实际上是让某个神经元的激活值以一定的概率p停止工作),这样可以使模型泛化性更强,因为它不会太依赖某些局部的特征。Dropout其实使用的会比较多,在训练一个深度神经网络时,通常会出现过拟合以及费时两种问题,dropout的思想就是丢弃某些神经元来达到减小过拟合现象,同时还减少了计算参数。另:通常p=0.5
在这里插入图片描述
在这里插入图片描述

这里推荐一篇我学习时找的文章:深度学习-Dropout详解_深度学习dropout_Tc.小浩的博客-CSDN博客

下面代码展示Dropout:

import torch

def dropout_layer(X, dropout):
    assert 0 <= dropout <= 1
    # Dropout=1表示将所有元素丢弃
    if dropout == 1:
        return torch.zeros_like(X)
    # Dropout=0表示将所有元素保留
    if dropout == 0:
        return X
    mask = (torch.rand(X.shape) > dropout).float()
    # 可以查看哪些被丢弃了
    print("mask:", mask)
    return mask * X / (1.0 - dropout)

# 生成一个2×8大小的矩阵,元素为0~15
X = torch.arange(16, dtype = torch.float32).reshape((2, 8))
print("数据集:",X)
print("Dropout=0的时候", dropout_layer(X, 0.))
print("Dropout=0.5的时候", dropout_layer(X, 0.5))
print("Dropout=1的时候", dropout_layer(X, 1.))

前向传播与反向传播

     前向传播是按顺序(从输入层到输出层)计算和存储神经网络中每层的结果。假设输入样本为 x ∈ R d \mathbf{x}\in \mathbb{R}^d xRd,则:
z = W ( 1 ) x \mathbf{z}= \mathbf{W}^{(1)} \mathbf{x} z=W(1)x
      W ( 1 ) ∈ R h × d \mathbf{W}^{(1)} \in \mathbb{R}^{h \times d} W(1)Rh×d是隐藏层的权重参数 , z 是中间变量。将中间变量 ,z是中间变量。将中间变量 z是中间变量。将中间变量 z ∈ R h \mathbf{z}\in \mathbb{R}^h zRh通过激活函数 ϕ \phi ϕ 后,得到长度为ℎ的隐藏激活向量:
h = ϕ ( z ) . o u t p u t = W ( 2 ) h . \mathbf{h}= \phi (\mathbf{z}). \\ \mathbf{output}= \mathbf{W}^{(2)} \mathbf{h}. h=ϕ(z).output=W(2)h.
     h也是一个中间变量,输出层的参数只有权重 W ( 2 ) ∈ R q × h \mathbf{W}^{(2)} \in \mathbb{R}^{q \times h} W(2)Rq×h,可以得到输出变量output,这时候假设损失函数为l,样本标签为y,计算单个数据样本的损失项:
L = l ( o u t p u t , y ) . L = l(\mathbf{output}, y). L=l(output,y).
     根据L2正则化的定义,给定超参数 λ \lambda λ,正则化项为
s = λ 2 ( ∥ W ( 1 ) ∥ F 2 + ∥ W ( 2 ) ∥ F 2 ) , s = \frac{\lambda}{2} \left(\|\mathbf{W}^{(1)}\|_F^2 + \|\mathbf{W}^{(2)}\|_F^2\right), s=2λ(W(1)F2+W(2)F2),
     最后的目标函数为
J = L + s J = L + s J=L+s
在这里插入图片描述

反向传播计算神经网络参数梯度的方法,该方法根据微积分中的链式规则,按相反的顺序从输出层到输入层遍历网络。第一步:计算目标函数 J = L + s J=L+s J=L+s相对于损失项L和正则项s的梯度:
∂ J ∂ L = 1    and    ∂ J ∂ s = 1. \frac{\partial J}{\partial L} = 1 \; \text{and} \; \frac{\partial J}{\partial s} = 1. LJ=1andsJ=1.
链式法则计算目标函数关于输出层变量o的梯度:
∂ J ∂ o = prod ( ∂ J ∂ L , ∂ L ∂ o ) = ∂ L ∂ o ∈ R q . ∂ s ∂ W ( 1 ) = λ W ( 1 )    and    ∂ s ∂ W ( 2 ) = λ W ( 2 ) . \frac{\partial J}{\partial \mathbf{o}} = \text{prod}\left(\frac{\partial J}{\partial L}, \frac{\partial L}{\partial \mathbf{o}}\right) = \frac{\partial L}{\partial \mathbf{o}} \in \mathbb{R}^q. \\ \frac{\partial s}{\partial \mathbf{W}^{(1)}} = \lambda \mathbf{W}^{(1)} \; \text{and} \; \frac{\partial s}{\partial \mathbf{W}^{(2)}} = \lambda \mathbf{W}^{(2)}. oJ=prod(LJ,oL)=oLRq.W(1)s=λW(1)andW(2)s=λW(2).
     现在计算最接近输出层的模型参数的梯度:
∂ J ∂ W ( 2 ) = prod ( ∂ J ∂ o , ∂ o ∂ W ( 2 ) ) + prod ( ∂ J ∂ s , ∂ s ∂ W ( 2 ) ) = ∂ J ∂ o h ⊤ + λ W ( 2 ) . \frac{\partial J}{\partial \mathbf{W}^{(2)}}= \text{prod}\left(\frac{\partial J}{\partial \mathbf{o}}, \frac{\partial \mathbf{o}}{\partial \mathbf{W}^{(2)}}\right) + \text{prod}\left(\frac{\partial J}{\partial s}, \frac{\partial s}{\partial \mathbf{W}^{(2)}}\right)= \frac{\partial J}{\partial \mathbf{o}} \mathbf{h}^\top + \lambda \mathbf{W}^{(2)}. W(2)J=prod(oJ,W(2)o)+prod(sJ,W(2)s)=oJh+λW(2).
     为了获得关于 W ( 1 ) \mathbf{W}^{(1)} W(1)的梯度,需要继续沿着输出层到隐藏层反向传播
∂ J ∂ h = prod ( ∂ J ∂ o , ∂ o ∂ h ) = W ( 2 ) ⊤ ∂ J ∂ o . \frac{\partial J}{\partial \mathbf{h}} = \text{prod}\left(\frac{\partial J}{\partial \mathbf{o}}, \frac{\partial \mathbf{o}}{\partial \mathbf{h}}\right) = {\mathbf{W}^{(2)}}^\top \frac{\partial J}{\partial \mathbf{o}}. hJ=prod(oJ,ho)=W(2)oJ.
     由于激活函数 ϕ \phi ϕ是按元素计算的,计算中间变量z的梯度 ∂ J / ∂ z ∈ R h \partial J/\partial \mathbf{z} \in \mathbb{R}^h J/zRh 需要使用按元素乘法运算符,用⊙表示:
∂ J ∂ z = prod ( ∂ J ∂ h , ∂ h ∂ z ) = ∂ J ∂ h ⊙ ϕ ′ ( z ) . \frac{\partial J}{\partial \mathbf{z}} = \text{prod}\left(\frac{\partial J}{\partial \mathbf{h}}, \frac{\partial \mathbf{h}}{\partial \mathbf{z}}\right) = \frac{\partial J}{\partial \mathbf{h}} \odot \phi'\left(\mathbf{z}\right). zJ=prod(hJ,zh)=hJϕ(z).
     最后,可以得到最接近输入层的模型参数的梯度 ∂ J / ∂ W ( 1 ) ∈ R h × d \partial J/\partial \mathbf{W}^{(1)} \in \mathbb{R}^{h \times d} J/W(1)Rh×d
∂ J ∂ W ( 1 ) = prod ( ∂ J ∂ z , ∂ z ∂ W ( 1 ) ) + prod ( ∂ J ∂ s , ∂ s ∂ W ( 1 ) ) = ∂ J ∂ z x ⊤ + λ W ( 1 ) . \frac{\partial J}{\partial \mathbf{W}^{(1)}} = \text{prod}\left(\frac{\partial J}{\partial \mathbf{z}}, \frac{\partial \mathbf{z}}{\partial \mathbf{W}^{(1)}}\right) + \text{prod}\left(\frac{\partial J}{\partial s}, \frac{\partial s}{\partial \mathbf{W}^{(1)}}\right) = \frac{\partial J}{\partial \mathbf{z}} \mathbf{x}^\top + \lambda \mathbf{W}^{(1)}. W(1)J=prod(zJ,W(1)z)+prod(sJ,W(1)s)=zJx+λW(1).
     这部分内容尽量结合上面的图去理解会比较好。

3. 总结

     关于《动手深度学习》第四章的学习内容如上,如果写的不正确的地方也欢迎评论指正,另附上学习链接:第四章多层感知机

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力学AI的小曾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值