购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

1.4 深度学习基础与框架

20世纪90年代以来,随着信息技术和大数据技术的发展,算力和数据量有大幅度的提升,人工智能技术获得进一步优化,人工神经网络主导的深度学习领域也得到了极大的突破。基于深度神经网络技术的发展,人工智能才逐渐步入快速发展期。本节将介绍几年来越来越火热的深度学习的基础和常见的框架。

1.4.1 深度学习基本原理

深度神经网络、激活函数、损失函数、梯度下降和反向传播是深度学习的基本元素。深度神经网络是深度学习算法的核心;激活函数的引入,使得神经网络能够抓取特征的非线性关系;损失函数表现了预测和实际数据的差异;梯度下降算法通过计算可微函数的梯度并沿梯度的相反方向移动,直到搜索损失函数局部或者全局最小值;反向传播是一种机制,通过这种机制,可以反复调整影响神经网络输出的组件,以降低损失函数。

1.深度神经网络

深度学习(Deep Learning)是机器学习的分支,是一种以神经网络为模型,基于对数据进行表征学习的算法。和许多传统机器学习算法相比,深度学习的模型有更强的学习能力,可以通过更大量的数据来提升性能。接下来将介绍什么是神经网络、常见的深度学习算法,以及几种常见的神经网络模型变形。神经网络,也称为人工神经网络(Artificial Neural Networks),它是深度学习算法的核心。其名称和结构是受人类大脑的启发,模仿了生物神经元信号相互传递的方式。最经典的人工神经网络称为深度前馈网络,指的是由输入层和输出层之间的多层非线性映射组成多层感知器,以完成复杂的函数逼近。一般来讲,神经网络会包含两个主要部分:线性变换函数和非线性变换函数。给定输入 x ∈R D ,神经网络预测输出 y ∈R K ,其中 D 是输入的维度, K 是输出的维度。神经网络的数学模型可以用以下函数表示:

f θ ( x )= σ ( L ) ( W ( L ) σ ( L -1) ( W ( L -1) σ (2) ( W (2) σ (1) ( W (1) x ))))

其中 L 是隐藏层数, θ ={ W (1) , W (2) ,…, W ( L ) }是要学习的参数, σ ={ σ (1) , σ (2) ,…, σ ( L ) }是非线性激活函数,例如Tanh、Sigmoid和ReLU等,如图1-6所示。

● 图1-6 包含两个隐藏层的神经网络

可以看出,第 l 层的第 i 个神经元将第 l -1层的神经元的输出作为输入,经过加权相加和非线性激活函数,然后输出并作为第 l +1层的神经元的输入。其中, 是第 l -1层的第 j 个神经元和第 l 层的第 i 个神经元的连接:

因此,也可以用矩阵形式表示,即:

2.激活函数

非线性激活函数,也叫作激活函数,它将神经元的输入映射到一个非线性输出。引入激活函数是为了增加神经网络模型的非线性,所以激活函数对于人工神经网络模型去学习非常复杂和非线性的函数来说,具有十分重要的作用。如果不用激活函数,每一层输出都是上层输入的线性函数,则无论神经网络有多少层,本质上输入的只是线性组合。如果使用激活函数,则原则上神经网络可以任意逼近任何非线性函数,这样神经网络就可以应用到众多的非线性模型中。常见的激活函数包括Sigmoid函数、双曲正切函数Tanh、修正线性单元ReLU函数和Softmax函数等。

(1)Sigmoid函数

Sigmoid函数也叫作Logistic激活函数,如图1-7a所示,它将实数值压缩进0到1的区间内,该函数将较大的负数转换为趋近于0,将较大的正数转换为趋近于1。可以将它应用在预测概率的输出层中。Sigmoid函数的导数为

f′ ( x )= f ( x )[1 -f ( x )]

● 图1-7 非线性激活函数

a)Sigmoid函数 b)Tanh函数 c)ReLU函数 d)LeakyReLU函数 e)ELU函数 f)GeLU函数

Sigmoid函数的优点在于它可导,并且值域在0~1,使得神经元的输出标准化。然而,它也有几个缺点:第一,它的输出不是以零为中心的,这会导致参数更新时只能朝一个方向更新,从而影响收敛速度;第二,与其他非线性激活函数相比,以e为底的指数函数和它的导数计算成本高;第三,它可能导致梯度消失(Gradient Vanishing)和梯度爆炸(Gradient Exploding)。Sigmoid函数的基本形式如下:

(2)Tanh函数

Tanh函数也叫作双曲正切函数(Hyperbolic Tangent Activation Function),如图1-7b所示,与Sigmoid函数类似,但Tanh函数将全实数域映射至-1到1的区间内。Tanh函数的特点是:它的输出值以0为中心,解决了Sigmoid函数输出值只为正,梯度只向一个方向更新的问题。依然存在Sigmoid中梯度消失和爆炸的问题以及指数运算量大的问题。Tanh函数的基本形式如下:

(3)ReLU函数

ReLU函数也叫作修正线性单元(Rectified Linear Unit),它是目前最常应用的激活函数。如图1-7c所示,可以看出, x ≥0时梯度为1;而在 x <0的情况下,梯度为0。该函数的优点是:第一,收敛速度快,并且在正数区域(即 x ≥0),可以对抗梯度消失问题;第二,计算成本低,导数更加好求;第三,使网格具有稀疏性。而它的缺点也包括:第一,它的输出也不以0为中心,因此只存在正向梯度;第二,可能出现神经元“坏死”(Dead Neurons)现象。举个例子:由于ReLU在 x <0时梯度为0,这样就导致负的梯度在这个ReLU被置0,而且这个神经元有可能保持非激活状态。这样,参数无法得到更新,网络无法学习。

为了避免ReLU函数在负数区域的梯度消失问题,人们也提出了一些新的类似ReLU的函数,比如渗漏型整流线性单元LeakyReLU函数(如图1-7d所示)、指数线性单元ELU函数(如图1-7e所示)、高斯误差线性单元GeLU函数(如图1-7f所示)。

3.损失函数

监督学习本质上是给定一系列训练样本( x i , y i ),尝试学习 f x y 的映射关系,使得给定一个 x ,即便它没有在训练样本中出现,也能够输出 ,尽量与真实的 y 接近。损失函数主要用来估量模型的输出 与真实值 y 之间的差距,定义了模型优化的方向。

如上式所示,模型的优化主要是最小化经验风险和结构风险,前面的均值函数为经验风险, L y i , f ( x i , θ ))为损失函数,损失函数是经验风险函数的核心部分,后面的项为结构风险,也称作正则项, Ω ( θ )用来衡量模型的复杂度。接下来将介绍几个常用到的损失函数。

(1)均方差损失函数

均方差(Mean Squared Error,MSE)损失函数是机器学习、深度学习中回归任务最常用的一种损失函数,也称为L2损失函数(L2 Loss Function)。其基本形式如下:

(2)平均绝对误差损失函数

平均绝对误差(Mean Absolute Error,MAE)损失函数是另一类常用的损失函数,也称为L1损失函数。其基本形式如下:

(3)Huber损失函数

Huber损失函数是一种将MSE与MAE结合起来的损失函数,也称作Smooth Mean Absolute Error损失函数。它取了两者优点,在误差接近0时使用MSE,误差较大时使用MAE,降低了异常点的影响,使训练更加鲁棒。其基本形式如下:

其中, δ 是Huber损失函数的一个超参数, δ 的值是MSE与MAE连接的位置。

(4)交叉熵损失函数

交叉熵(Cross Entropy)损失函数常常用于分类问题。在二分类中,通常使用Sigmoid函数将模型的输出映射到(0,1)区间内。 表示在给定输入 x i 的情况下,模型判断为正类的概率。其基本形式如下,也叫作Binary Cross Entropy。

在多分类的任务中,将 y i 表示成一个one-hot向量,其中, y i , c =1当且仅当该样本属于类 c 。通常,模型的最后一层使用Softmax函数将输出的向量的每个维度的输出范围限定在(0,1)内,同时所有维度的输出和为1。其基本形式如下,也叫作Categorical Cross Entropy。

4.梯度下降和反向传播

梯度下降法是目前最常见的神经网络训练算法,它是一种一阶最优化算法,通常也称为最陡下降法。使用梯度下降法找到一个函数的局部极小值,必须向函数上当前点对应梯度(或者是近似梯度)的反方向的规定步长距离点进行迭代搜索。梯度下降法可以分成三类:批梯度下降法(Batch Gradient Descent,BGD)、迷你批梯度下降法(Mini Batch Gradient Descent,MBGD)和随机梯度下降法(Stochastic Gradient Descent,SGD)。批梯度下降法在一次迭代(Epoch)中,计算损失函数会使用所有训练样本。

反向传播算法是目前最主要的能够高效计算梯度的算法。它利用链式法则计算神经网络中各个参数的梯度。接下来推导反向传播算法的过程。

首先,来回顾一下神经网络的前向传导过程。如图1-8所示,记 为第 k 层的第 i 个神经元的输出, 为第 k 层的第 i 个神经元的输入, W k =( )为连接第 k -1层和第 k 层的参数矩阵, σ 为非线性激活函数。于是可以得到以下两个公式:

● 图1-8 神经网络前向传导

反向传播则是从最后一层开始计算,通过链式法则逐层推导梯度。首先,可以根据第 L 层的输出和定义的损失函数 J 得到损失函数 J 相对于 的偏导数 。反向传播算法则是以下循环过程:

1)通过损失函数 J 关于第 k +1层的输出的偏导数,可以计算损失函数 J 关于第 k +1层的输入的偏导数。如果激活函数为Sigmoid,则

2)通过损失函数 J 关于第 k +1层的输入的偏导数,可以计算损失函数 J 关于第 k 层的输出的偏导数。

3)通过损失函数 J 关于第 k 层的输出的偏导数,可以计算损失函数 J 关于连接第 k 层和第 k +1层参数的偏导数。

深度学习的本质是优化问题,而这个优化函数的变量是神经网络的所有参数 θ 。上文介绍的三种梯度下降法:批量梯度下降法(Batch Gradient Decent,BGD)、随机梯度下降法(Stochastic Gradient Decent,SGD)和迷你批量梯度下降法(Mini-Batch Gradient Decent,MBGD)是几个简单优化器。它们各自的缺点也比较明显:对于BGD,它需要对整个数据集计算梯度,所以计算起来非常慢,当遇到很大的数据集时就会非常棘手;对于SGD,它的更新比较频繁,会造成在损失函数上有严重的震荡。为了解决这些问题,很多不同的优化器也陆续被提出,常用的包括Momentum、Nesterov Acceleration、Adagrad、Adadelta、RMSprop和Adam等。

1.4.2 常见的神经网络类型

随着神经网络技术的不断发展和完善,越来越多的模型架构被提出。其中主要用于处理数据卷积神经网络、处理序列任务的循环神经网络是神经网络最基本最常见的网络类型。

1.卷积神经网络

目前,卷积神经网络(Convolutional Neural Networks,CNN)已经广泛应用在了各个领域,特别是在计算机视觉领域。卷积神经网络是一种特殊的神经网络。与普通的神经网络一样包括一个输入层、一个输出层以及多个隐藏层。但是与常规人工神经网络不同的是,卷积神经网络处理的是二维和三维的张量,而不是向量。一个卷积神经网络主要包括4个基本结构:卷积层、激活层、池化层和全连接层。接下来将介绍这些基本构件及相关的数学运算过程。

卷积(Convolution)是数学分析中一种重要的运算。假设定义两个在R上的可积函数 f ( x )和 g ( x ), f ( x )和 g ( x )的卷积( f * g )( t )是其中一个函数翻转,并平移后,与另一个函数的乘积的积分,可以定义为如下公式。

( f * g )( t ) = f ( x ) g ( t-x )d x

离散空间的二维卷积如图1-9所示,其中中间阴影部分称为窗口函数或者卷积的核,也可以叫作过滤器或者滤波器。我们也可将卷积后的图片上的某一个像素理解成该位置附近的像素集合与卷积核(滤波器或过滤器)对应的加权求和。

如图1-10所示,比较经典的卷积核(滤波器或过滤器)包括高斯核(也叫作高斯模糊)和拉普拉斯核等。

● 图1-9 二维卷积示例

● 图1-10 高斯核和拉普拉斯核效果示例

卷积神经网络中的卷积层(或者叫作卷积模块),就是通过深度学习优化算法训练,比如梯度下降法,学习得到不同的卷积核,这些卷积核可以将图像的特征提取出来,得到更抽象的特征图。所有深度学习框架也提供了现成的2D卷积类可以调用,如下所示,PyTorch中的torch.nn包中提供了名为Conv2d的类,其中必需的参数包括输入特征图的通道数、输出特征图的通道数,以及卷积核的大小,默认步长为1,默认填充为0,默认带有偏差bias。

与其他神经网络一样,在卷积神经网络中,卷积层的输出还需要经过激活层。之前介绍的一些非线性激活函数都可以作为卷积神经网络的激活层,如双曲正切函数或者Sigmoid函数等。这些函数可以增强网络的非线性特性。但是相比其他函数来说,ReLU函数更受青睐,这是因为它可以增强判定函数和整个神经网络的非线性特性,而本身并不会改变卷积层。除此之外,ReLU函数还可以提升神经网络训练收敛的速度,而并不会对模型的泛化准确度造成显著影响。在卷积神经网络中,池化(Pooling)是另一个重要的概念,它实际上是一种非线性形式的降采样。有多种不同形式的非线性池化函数,而其中最大池化(Max Pooling)是最为常见的。它是将输入的图像划分为若干个矩形区域,对每个子区域输出最大值,图1-11表示了核大小为2,步长为2的最大池化。除了最大池化之外,池化层也可以使用其他池化函数,例如平均池化和L2-范数池化等。过去,平均池化的使用曾经较为广泛,但是最近由于最大池化在实践中的表现更好,平均池化已经不太常用。池化层的优点在于增加了网络的感受野,又减小了特征图的大小,对应减少计算量,一定程度上避免了过拟合。

● 图1-11 最大池化示例

最后,在经过几个卷积和最大池化层之后,神经网络中的高级推理通过完全连接层来完成。就和在常规的非卷积人工神经网络中一样,完全连接层中的神经元与前一层中的所有激活有联系。因此,它们的激活可以作为仿射变换来计算,也就是先乘以一个矩阵,然后加上一个偏差(Bias)偏移量(向量加上一个固定的或者学习来的偏差量)。在图像识别任务中,卷积神经网络通过全连接层和Softmax函数将卷积层学习得到的特征图映射成该图片属于某个类别的概率。

2.循环神经网络

在处理序列数据时,往往需要神经网络具有记忆性。例如,当阅读一篇文章时,会根据前面单词的理解来理解每个单词。而不会把所有东西扔掉,重新开始思考。传统的神经网络显然无法做到这一点。循环神经网络(Recurrent Neural Network,RNN)解决了这个问题。如图1-12所示,循环神经网络是一类以序列数据作为输入,具有循环的,允许信息持续存在的递归神经网络。

● 图1-12 循环神经网络

注:该图取自https://colah.github.io/posts/2015-08-Understanding-LSTMs

简单的循环神经网络主要有两种:Elman和Jordan网络。假设 x t 为输入向量的第 t 个元素, h t 为隐藏层向量的第 t 个元素, y t 为输出向量的第 t 个元素, W U b 分别为参数矩阵和参数向量, σ h σ y 为激活函数,则Elman和Jordan网络可以分别表示为如下公式。

● Elman网络:

h t = σ h ( W h x t + U h h t -1 + b h )

y t = σ y ( W y h t + b y )

● Jordan网络:

h t = σ h ( W h x t + U h y t -1 + b h )

y t = σ y ( W y h t + b y )

然而,RNN存在梯度消失的问题。随着序列数据长度的增加,RNN难以获取很久以前的信息。Hochreiter和Schmidhuber于1997年提出了长短期记忆网络(Long Short-Term Memory Network,LSTM)。LSTM在多个序列任务领域得到了广泛的应用。

如图1-13所示(图中的σ表示Sigmoid函数),LSTM的关键是单元状态(Cell State),即图中LSTM单元上方从左贯穿到右的水平线,它像传送带一样,将信息从上一个单元传递到下一个单元,同其他部分只有很少的线性的相互作用。另一方面,LSTM通过“门”(gate)来控制丢弃或者增加信息,从而实现遗忘或记忆的功能。“门”是一种使信息选择性通过的结构,由一个Sigmoid函数(或者tanh函数)和一个点乘操作组成。Sigmoid函数的输出值在0到1的区间,0代表完全丢弃,1代表完全通过。一个LSTM通过三个门保护和控制单元状态,分别是遗忘门(Forget Gate)、输入门(Input Gate)和输出门(Output Gate)。

● 图1-13 长短期记忆(LSTM)网络

(1)遗忘门决定将在单元状态中删除哪些信息:

f t = σ ( W f [ h t -1 , x t ]+ b f )

(2)输入门决定将在单元状态中存储哪些新信息:

(3)更新单元状态:

(4)输出门决定(基于目前的单元状态)要输出什么:

o t = σ ( W o [ h t -1 , x t ]+ b o )

h t = o t *tanh( C t )

Gers和Schmidhuber在2000年提出了一种流行的LSTM变体,在传统的LSTM单元中加入了“窥视孔连接(Peephole Connections)”,如图1-14a所示。

● 图1-14 LSTM变体网络结构

a)窥视孔LSTM b)门控循环单元GRU

f t = σ ( W f [ C t -1 , h t -1 , x t ]+ b f )

i t = σ ( W i [ C t -1 , h t -1 , x t ]+ b i )

o t = σ ( W o [ C t , h t -1 , x t ]+ b o )

LSTM的另一个更有名的变体是由Cho等人在2014年提出的门控循环单元(Gated Recurrent Unit,GRU),如图1-14b所示。这种结构将遗忘门和输入门组合成一个“更新门”,还合并了单元格状态和隐藏状态,并进行了一些其他更改。GRU模型比标准LSTM模型更简单,并且越来越受欢迎。

1.4.3 常见的深度学习框架

深度学习是一个复杂的系统工程。对于某些简单的模型,研究人员也可以手动实现一个神经网络模型。如果需要更复杂的模型,或者计算系统的基线用于与其他方法比较其优缺点,那么会发现重新实现一个复杂模型是不切实际的。深度学习框架能帮助我们使用CUDA代码调用GPU资源进行计算,不需要自己构建计算图实现梯度反向传播。标准化的优化器、数据加载器等能帮助研究与开发人员极大地降低工程量。常见的深度学习框架包括TensorFlow、Keras、PyTorch等。

1.TensorFlow

TensorFlow是谷歌基于DistBelief进行研发的第二代人工智能学习系统,其命名来源于本身的运行原理。Tensor(张量)意味着 N 维数组,Flow(流)意味着基于数据流图的计算,TensorFlow为张量从流图的一端流动到另一端的计算过程。TensorFlow是将复杂的数据结构传输至人工智能神经网络中进行分析和处理的系统。通过描述张量如何在神经网络的一系列层和节点中移动的数据流图来实现的,机器学习开发人员无须处理遍历神经网络所需操作的低级细节,而是专注于应用程序的高级逻辑。TensorFlow是深度学习领域前景广阔且发展迅速的新产品,它提供了一个灵活、全面的社区资源、库和工具生态系统,有助于构建和部署机器学习应用程序。

TensorFlow 2是一个端到端的开源机器学习平台,它结合了4个关键能力。

● 在CPU、GPU或TPU上高效执行低级张量操作。

● 计算任意可微表达式的梯度。

● 将计算扩展到许多设备,例如数百个GP U的集群。

● 将程序图导出到外部运行时,例如服务器、浏览器、移动和嵌入式设备。

TensorFlow以文档和培训支持、可扩展的生产和部署选项、多个抽象级别,以及对不同平台(例如Android)的支持而闻名。TensorFlow提供的API不仅是高级的,还允许一些低级的操作,它还支持Python、JavaScript、C++和Java的API。除此之外,还有一些针对C#、Haskell、Julia、R、MATLAB、Scala等的第三方语言绑定包。使用TensorFlow的另一个优势是谷歌提供了张量处理单元或TPU。这些是专用集成电路,专门为了与TensorFlow一起用于机器学习而定制。

2.Keras

Keras是一个Python深度学习框架,可以方便地定义和训练几乎所有类型的深度学习模型。最开始,Keras是为研究人员开发的,其目的在于快速实验。Keras具有以下重要特性:

● 相同的代码可以在CPU或GPU上无缝切换运行。

● 具有对用户友好的API,便于快速开发深度学习模型的原型。

● 内置支持卷积网络(用于计算机视觉)、循环网络(用于序列处理)以及二者的任意组合。

● 支持任意网络架构:多输入或多输出模型、层共享、模型共享等。

Keras是一个模型级(Model-Level)的库,为开发深度学习模型提供了高层次的构建模块。它不处理张量操作、求微分等低层次的运算。相反,它依赖于一个专门的、高度优化的张量库来完成这些运算,这个张量库就是Keras的后端引擎(Backend Engine)。

最初,Keras将Theano作为首选的后端引擎,又支持了其他一些后端引擎,包括CNTK、MxNet和TensorFlow等。随着越来越多的TensorFlow用户开始使用Keras的简易高级API,越来越多的TensorFlow开发人员将Keras项目纳入TensorFlow中作为一个单独模块,并将其命名为tf.keras。TensorFlow v1.10是第一个在tf.keras中包含一个keras分支的TensorFlow版本。而且它也最终成为Keras的默认计算后端引擎。当前Keras是TensorFlow 2的高级API。Keras与TensorFlow 2一起打包为tensorflow.keras。当开始使用Keras时,只需安装TensorFlow 2,然后使用from tensorflow import keras即可。

3.PyTorch

Pytorch是Torch的Python版本,是由Facebook(现更名为Meta)开源的神经网络框架,专门针对GPU加速的深度神经网络(DNN)编程。Torch是一个经典的对多维矩阵数据进行操作的张量(Tensor)库,在机器学习和其他数学密集型应用中有广泛应用。与Tensorflow的静态计算图不同,PyTorch的计算图是动态的,可以根据计算需要实时改变计算图。

PyTorch由Facebook(现更名为Meta)于2017年在GitHub上开源的。由Facebook的AI研究小组开发,并于2017年用于自然语言处理应用程序。PyTorch借鉴了Chainer和Torch,以简单、易用、灵活、高效的内存使用和动态计算图而闻名。它可以使编码更易于管理并提高处理速度。开发人员通常认为PyTorch比其他框架更“Pythonic”。PyTorch是一个非常灵活的框架,虽然它依赖于图来定义神经网络架构的逻辑,但我们不需要在计算之前定义它。相反,可以以动态方式将组件添加到图中,并且彼此独立。这也为代码的测试和调试阶段带来了优势。与TensorFlow相比,PyTorch凭借其动态图方法,以及调试和测试代码的灵活性,已经获得了大量的支持者。

4.TensorFlow、Keras和PyTorch的比较与使用建议

Keras在小数据集中是首选,它提供了快速原型和扩展的大量后端支持,而TensorFlow提供了不同平台不同语言的广泛支持,尤其是在嵌入式设备部署任务上,TensorFlow仍然是首选。PyTorch具有较强的灵活性和调试能力,可以在最短的数据集训练时间内适应。

目前,在学术界PyTorch已经超越TensorFlow。研究人员考虑的是科研的速度而非性能,即哪一种框架能够让他们更快、更好地实践想法。PyTorch可以替代NumPy,轻松与Python生态系统的其余部分集成。而在TensorFlow中,调试模型需要一个活动会话,并且最终会非常棘手。与TensorFlow的API相比,大多数研究人员更喜欢PyTorch的API。其设计得更好,而TensorFlow则需要进行多次切换。在性能方面,PyTorch建立在支持动态图计算的基础上,其运行速度与TensorFlow并没有拉开明显差距,甚至在一些测试中要快于TensorFlow。在工业界,Tensorflow的地位仍然相当稳固。工业界更注重部署,而TensorFlow的生态更有利于快速部署。以英伟达开发的TensorRT为例子,与PyTorch相比,英伟达官方不仅是支持了TensorFlow,而且发布了很多TensorRT实现的深度模型。除此之外,还给出了不同模型在最常用的嵌入式设备Jetson TX2上的算法测试时间。所以工程人员为了更快速地给出方案、更快速地跑通流程,最好的方式就是在现有的生态基础上,进行算法组合和调优,以满足特定任务。如果采用部署生态尚不成熟的PyTorch,可能遇到TensorRT不支持某些操作的情况。所以目前的部署任务中,TensorFlow要比PyTorch更成熟,值得推荐。 9dOi0fSdimhTKRgOashKqXWpxeVimY8GkhuGCs6euh9scF1iNUA41c6AaGyHxqer

点击中间区域
呼出菜单
上一章
目录
下一章
×