深入浅出PyTorch:从模型到源码
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.3 深度学习基本概念

前面简单回顾了机器学习的基础概念,本节将会更进一步了解深度学习的相关概念。首先需要了解的是,深度学习是一种基于神经网络的机器学习。因此,我们前面学到的机器学习的概念可以和深度学习无缝衔接。另外,由于在神经网络模型的计算过程中,会涉及大量的向量、矩阵和张量计算,下面先来回顾一下相关的线性代数的基础知识。

1.3.1 向量、矩阵和张量及其运算

首先要介绍的是向量的概念。这里把向量定义为一行或者一列数,分别称之为行向量和列向量,如式(1.14)和式(1.15)所示(这里用T代表转置,意思是行列互换)。向量是最基本的一种数据排列方式,组成向量的每个数称为向量的分量,这里用a1a2,…,an来表示,其中的n代表向量分量的数目,即向量的大小。在几何上,向量可以看作n空间中的一个方向,其中向量的每个分量代表向量在某个坐标(比如,当n等于3时可以认为是在空间xyz坐标上)上分量的大小。我们定义向量和实数的乘法为向量的每一个分量乘以该实数得到一个新向量,向量与向量的加减法为向量每个元素一一对应相加减(仅对分量数大小相等的向量有意义)。向量与向量之间一个重要的运算是点积(Dot Product),或者称之为内积(Inner Product),表现为两个相同大小的向量按分量相乘并且求和。我们把向量与自身内积的平方根称之为向量的长度(或模,即前面提到的L2-norm),两个向量的内积等于向量的模长乘以向量之间夹角的余弦,如式(1.16)所示。

向量相当于把数排成一维的一条线,当我们把数排列成一个平面的时候,就有了矩阵的概念。所谓矩阵,就如前面所说,是把数按照矩形的形状排列成一个二维的结构,如式(1.17)所示。这里展示了一个m×n的矩阵a,其中m是矩阵的行数,n是矩阵的列数。和向量一样,我们可以定义矩阵的转置操作,如式(1.18)所示,一个m×n的矩阵a的转置是一个n×m的矩阵。同向量一样,矩阵和实数的乘法得到一个新矩阵,该矩阵的每个元素等于原来的矩阵对应位置的元素乘以该矩阵,矩阵的加减法同样定义为对应元素相加减得到的新矩阵(两个相加减的矩阵行列数必须相等)。矩阵的另一个比较重要的操作称为矩阵乘法,我们定义一个m×n的矩阵c为一个m×k大小的矩阵ak×n的矩阵b的乘积(这里注意矩阵a的列数和矩阵b的行数必须相等,否则乘法无意义)。矩阵c的每个分量定义如式(1.19)所示。我们可以看到,c矩阵的每个元素等于a矩阵对应的行和b矩阵对应的列,按照元素一一对应的乘积的和。如果把a矩阵的行和b矩阵的列分别看作一个向量,则c矩阵的元素的值是这两个向量的内积。矩阵的乘法由于和线性方程的变量替换有关,我们也把矩阵的乘法称为线性变换。这里需要注意的是矩阵的乘法和一般的乘法不同,一般不满足交换律,但是满足结合率,即abbaabc=abc

我们把行和列数目相等的矩阵称为方阵。当一个方阵对角线都为1,剩下的元素都为0时,我们称这个方阵为单位矩阵,如式(1.20)所示。单位矩阵和任意矩阵的乘积(无论是左乘还是右乘)等于该任意矩阵本身的公式(1.21)。我们定义一个(可逆)方阵的逆是和该矩阵乘积为单位矩阵的一个矩阵。需要注意的是,有些方阵不可逆,这个涉及行列式的操作(用det来表示取矩阵的行列式,可以认为是把方阵映射为一个实数的函数),详细内容可以参考线性代数的相关书籍。我们把方阵对角线元素的和称为方阵的迹,用tr函数来表示,如式(1-22)所示。

我们可以把数字的排列进一步推广为张量(Tensor)。作为张量的特例,向量可以看作一维张量,矩阵可以看作二维张量,三维的张量可以看作数字排列成长方体。更高维的张量虽然我们无法想象,但是可以根据前面的例子推理得到。举例来说,我们可以把黑白图片看作一个二维矩阵,其两个维度分别为图片的高h和图片的宽w,而彩色图片由于有RGB(即红绿蓝)三个通道,可以看作一个三维张量,即h×w×c,其中h是图片的高度,w是图片的宽度,c是图片的通道数目(c=3)。一个三维张量可以看成多个二维张量的堆叠,如前面所示的彩色图片可认为是三个单通道图片的堆叠。同理,我们可以把多个三维张量堆叠在一起形成四维的张量。在进行深度学习过程中,我们经常会用到四维张量,增加的一个维数称为迷你批次(mini-batch)的大小,可以认为是每次输入深度学习神经网络的图片的数目。根据四维张量四个维度的排列方式可以分为NCHW和NHWC两种,前一种代表的意思是输入神经网络的张量的大小是迷你批次的大小×通道数目×图片高度×图片宽度,后一种代表的意思是输入神经网络的张量大小是迷你批次的大小×图片高度×图片宽度×通道数目。不同的深度框架可能会采用不同的排列方式,需要根据具体使用的框架来决定具体的维数排列应该是什么。图1.6展示了向量、矩阵、三维张量的元素排列方式,读者可以根据这些元素排列的形状来想象更高维的张量应该是什么样的。向量、矩阵和张量是深度学习的基础,很多深度学习的运算涉及向量和矩阵的加法和乘法。

图1.6 向量、矩阵和三维向量示意图(每个格子代表一个浮点数)

另外,这里可以补充一点知识,作为前面的向量、矩阵和张量之间关系的进一步说明。实际上,我们可以在向量的基础上添加一个维度,让向量成为矩阵,矩阵上添加一个维度,让矩阵成为(三维)张量。具体地说,假如向量的大小为m,我们可以直接把这个向量转换为m×1或者1×m的矩阵(即增加一个维度,保持元素不变)。同理,如果有一个m×n大小的矩阵,我们可以自由选择增加在某一个维度,使之成为m×n×1或者m×1×n或者1×m×n的三维张量,而保持其中的元素不变。

在深度学习的神经网络的构造过程中,我们经常会碰到各种各样的线性变换,而这些线性变换的过程主要分成两类,一类是对于张量(包括向量和矩阵)的线性变换,另一类是张量的逐点(Point-wise)变换。举一个具体的例子,假如有一个长度为n的向量,需要转换为长度为m的向量,这时可以根据前面的知识,使用一个大小为m×n的矩阵来对其进行变换,因为我们知道,m×n的矩阵乘以n×1的矩阵(亦即长度为n向量),结果能够得到m×1的矩阵(即长度为m向量)。在实践中,神经网络的基本构建可以使用各种层来表示,其中一些重要的层如卷积层(Convolution Layer)和线性层(Linear Layer)可以直接通过线性变换和矩阵乘法来计算,我们将会在后续章节介绍相关内容。关于张量的逐点计算,相对于前面的线性变换的概念比较简单一点,即对输入张量的每一个分量(数字)进行相同的运算,比如都乘以一个数(或者形状相同的张量的对应分量),或者都应用一个(非线性)函数,最后输出一个与输入张量形状相同的新张量,即对于张量应用激活函数(Activation Function)的过程。我们也将在后面章节陆续介绍相关内容。一般来说,在神经网络的构建过程中,都是一系列的线性变换和非线性的激活函数的运算交错进行叠加,最后构造出一个含有很多参数的非线性模型,其中,可训练的参数是线性变换的系数。

1.3.2 张量的存储

在整个深度学习的过程中,由于我们会不断地和张量打交道,这里需要进一步阐述一下张量在内存中的表示和存储方法。假如有一个k维的张量,它的维数为(n1n2,…,nk),由于计算机的内存是连续的地址空间,所以在实际存储过程中存储的是1维的向量,这个向量在内存中的大小为n1×n2×…×nk。实际数值的排列方式可以从两个方向开始(从n1nk或者从nkn1),一般选择从nk这个维度开始,由小到大排列这个向量,即先填满nk的维度,再逐渐填满nk-1,直到n1的维度。假设有1个元素,它在张量中的具体下标是(i1i2,…,ik),那么它在内存中是第i1×(n2×n3×…×nk)+i2×(n3×..nk)+…+ik-1×nk+ik个元素,我们称每个维度位置乘以的系数,即(n2×n3×…×nk),(n3×..nk),…,1为这个维度的步长(Stride)或者系数(Offset)。张量在内存中的排列方式如图1.7所示。我们可以看到,维度序数较小(比如第1或第2个维度)的相邻数字在内存中的间隔比较大,反之,在内存中的间隔比较小。

图1.7 一个2×2×4的张量在内存中数字的排布(下标从0开始)

1.3.3 神经元的概念

神经网络最基础的组成单元可以认为是一个神经元(Neuron),它的结构由数个输入和输出组成。如图1.8所示,一个神经元的输入x是之前神经元输入的线性组合x=∑wiai,其中,wii=1,…,n)为一系列的可训练的参数,称为神经网络的权重。该神经元随之对这个线性组合输出的结果做一个非线性的函数变换fx),输出该函数的变换结果。非线性的函数又称激活函数,其选择有多样性,我们会在激活函数的相关章节提到相关方面的问题。由于非线性函数变换的存在,整个神经元的输出结果是非线性的,这就使得神经元的输出能够模拟不同的函数,构成神经网络的数学基础。在实际应用中,虽然深度学习的神经网络架构多种多样,但最终都能表示为神经元之间相互连接的形式,唯一的区别在于神经元的数目和神经元之间的相互连接方式不同。结合前面讲的向量、矩阵和张量的知识,我们可把神经元的输入和输出排列成矩阵的形式,那么使用神经网络的权重进行线性变换就可以对应成矩阵的乘法,同时激活函数的计算就可以看作一个对于矩阵每个元素的逐点计算。

图1.8 单个神经元结构示意图