深入了解神经网络
本章将介绍用于解决实际问题的深度学习架构的不同模块。前一章使用PyTorch的低级操作构建了如网络架构、损失函数和优化器这些模块。本章将介绍用于解决真实问题的神经网络的一些重要组件,以及PyTorch如何通过提供大量高级函数来抽象出复杂度。本章还将介绍用于解决真实问题的算法,如回归、二分类、多类别分类等。
本章将讨论如下主题:
[if !supportLists]· [endif]详解神经网络的不同构成组件;
[if !supportLists]· [endif]探究PyTorch中用于构建深度学习架构的高级功能;
[if !supportLists]· [endif]应用深度学习解决实际的图像分类问题。
3.1 详解神经网络的组成部分
上一章已经介绍了训练深度学习算法需要的几个步骤。
1.构建数据管道。
2.构建网络架构。
3.使用损失函数评估架构。
4.使用优化算法优化网络架构的权重。
上一章中的网络由使用PyTorch数值运算构建的简单线性模型组成。尽管使用数值运算为玩具性质的问题搭建神经架构很简单,但当需要构建解决不同领域的复杂问题时,如计算机视觉和自然语言处理,构建一个架构就迅速变得复杂起来。大多数深度学习框架,如PyTorch、TensorFlow和Apache MXNet,都提供了抽象出很多复杂度的高级功能。这些深度学习框架的高级功能称为层(layer)。它们接收输入数据,进行如同在前面一章看到的各种变换,并输出数据。解决真实问题的深度学习架构通常由1~150个层组成,有时甚至更多。抽象出低层的运算并训练深度学习算法的过程如图3.1所示。
图3.1
3.1.1 层——神经网络的基本组成
在本章的剩余部分,我们会见到各种不同类型的层。首先,先了解其中最重要的一种层:线性层,它就是我们前面讲过的网络层结构。线性层应用了线性变换:
Y=Wx+b
线性层之所以强大,是因为前一章所讲的功能都可以写成单一的代码行,如下所示。
上述代码中的myLayer层,接受大小为10的张量作为输入,并在应用线性变换后输出一个大小为5的张量。下面是一个简单例子的实现:
可以使用属性weights和bias访问层的可训练参数:
线性层在不同的框架中使用的名称有所不同,有的称为dense层,有的称为全连接层(fully connected layer)。用于解决真实问题的深度学习架构通常包含不止一个层。在PyTorch中,可以用多种方式实现。
一个简单的方法是把一层的输出传入给另一层:
每一层都有自己的学习参数,在多个层的架构中,每层都学习出它本层一定的模式,其后的层将基于前一层学习出的模式构建。把线性层简单堆叠在一起是有问题的,因为它们不能学习到简单线性表示以外的新东西。我们通过一个简单的例子看一下,为什么把线性层堆叠在一起的做法并不合理。
假设有具有如下权重的两个线性层:
层权重
Layer13.0
Layer22.0
以上包含两个不同层的架构可以简单表示为带有另一不同层的单层。因此,只是堆叠多个线性层并不能帮助我们的算法学习任何新东西。有时,这可能不太容易理解,我们可以用下面的数学公式对架构进行可视化:
Y = 2(3X1) -2 Linear layers
Y = 6(X1) -1 Linear layers
为解决这一问题,相较于只是专注于线性关系,我们可以使用不同的非线性函数,帮助学习不同的关系。
深度学习中有很多不同的非线性函数。PyTorch以层的形式提供了这些非线性功能,因为可以采用线性层中相同的方式使用它们。
一些流行的非线性函数如下所示:
[if !supportLists]· [endif]sigmoid
[if !supportLists]· [endif]tanh
[if !supportLists]· [endif]ReLU
[if !supportLists]· [endif]Leaky ReLU
3.1.2 非线性激活函数
非线性激活函数是获取输入,并对其应用数学变换从而生成输出的函数。我们在实战中可能遇到数个非线性操作。下面会讲解其中几个常用的非线性激活函数。
1.sigmoid
sigmoid激活函数的数学定义很简单,如下:
简单来说,sigmoid函数以实数作为输入,并以一个0到1之间的数值作为输出。对于一个极大的负值,它返回的值接近于0,而对于一个极大的正值,它返回的值接近于1。图3.2所示为sigmoid函数不同的输出。
图3.2
sigmoid函数曾一度被不同的架构使用,但由于存在一个主要弊端,因此最近已经不太常用了。当sigmoid函数的输出值接近于0或1时,sigmoid函数前一层的梯度接近于0,由于前一层的学习参数的梯度接近于0,使得权重不能经常调整,从而产生了无效神经元。
2.tanh
非线性函数tanh将实数值输出为-1到1之间的值。当tanh的输出极值接近-1和1时,也面临梯度饱和的问题。不过,因为tanh的输出是以0为中心的,所以比sigmoid更受偏爱,如图3.3所示。
图3.3
3.ReLU
近年来ReLU变得很受欢迎,我们几乎可以在任意的现代架构中找到ReLU或其某一变体的身影。它的数学公式很简单:
f(x)=max(0,x)
简单来说,ReLU把所有负值取作0,正值保持不变。可以对ReLU函数进行可视化,如图3.4所示。
图3.4
使用ReLU函数的一些好处和弊端如下。
[if !supportLists]· [endif]有助于优化器更快地找到正确的权重集合。从技术上讲,它使随机梯度下降收敛得更快。
[if !supportLists]· [endif]计算成本低,因为只是判断了阈值,并未计算任何类似于sigmoid或tangent函数计算的内容。
[if !supportLists]· [endif]ReLU有一个缺点,即当一个很大的梯度进行反向传播时,流经的神经元经常会变得无效,这些神经元称为无效神经元,可以通过谨慎选择学习率来控制。我们将在第4章中讨论调整学习率的不同方式时,了解如何选择学习率。
4.Leaky ReLU
Leaky ReLU尝试解决一个问题死角,它不再将饱和度置为0,而是设为一个非常小的数值,如0.001。对某些用例,这一激活函数提供了相较于其他激活函数更优异的性能,但它不是连续的。