一、 本章学习目标
学习神经网络的一些数学基础,主要是线性代数的一些基本知识。当然首先要明确的是,神经网络所涉及到的数学知识远不只是本章所介绍的这一些。神经网络涉及到线性代数、概率与信息论、数值计算等方面的数学基础知识。后续将在《Deep Learning》 一书的阅读笔记中详细介绍,在这边先只介绍最基础的线性代数。
二、神经网络的数据表示
1. 标量:
仅包含一个数字的张量叫做标量(也叫标量张量、零维张量、0D张量)。在Numpy中,一个float32或float64的数字就是一个标量。可以使用ndim属性来查看一个Numpy张量的轴的个数。标量张量有0个轴。张量轴的个数也叫阶。下面是一个Numpy标量。
>>> import numpy as np
>>> x = np.array(12)
>>> x
array(12)
>>> x.ndim
0
2. 向量(1D张量):
数字组成的数组叫做向量,或一维张量(1D张量)。当然,数学上的严格定义要比这个严谨很多,要求是一列有序排列的数字,这里只以编程上的思维来做一个直观的定义。一维张量只有一个轴。下面是Numpy向量。
>>> x = np. array([ 12, 3, 6, 14, 7])
>>> x
array([ 12, 3, 6, 14, 7])
>>> x. ndim
1
3. 矩阵(2D张量):
向量组成的数组叫做矩阵或者二维张量(2D张量)。矩阵有两个轴,分别叫做行和列。下面是Numpy矩阵。
>>> x = np. array([[ 5, 78, 2, 34, 0],
[6, 79, 3, 35, 1],
[7, 80, 4, 36, 2]])
>>> x. ndim
2
4. 3D张量与更高维张量:
一般的,一个数组中的元素分布在若干维度坐标的规则网络中,我们称之为张量。标量、向量、矩阵都属于张量。将多个矩阵组合成一个新的数组,可以得到一个3D张量。下面是一个Numpy的3D张量。
>>> x = np. array([[[ 5, 78, 2, 34, 0],
[6, 79, 3, 35, 1],
[7, 80, 4, 36, 2]],
[[5, 78, 2, 34, 0],
[6, 79, 3, 35, 1],
[7, 80, 4, 36, 2]],
[[5, 78, 2, 34, 0],
[6, 79, 3, 35, 1],
[7, 80, 4, 36, 2]]])
>>> x. ndim 3
将多个3D张量组合成一个数组,可以创建一个4D张量,以此类推。深度学习处理的一般是0D到4D的张量,但处理视频数据时可能会遇到5D张量。
三、张量的关键属性
- 轴的个数(阶)。3D张量有3个轴,矩阵有2个轴。在Numpy中表示为ndim
- 形状。一个整数元组,表示张量沿每个轴的元素个数。如上述矩阵的形状为(3,5)3行5列,上述3D张量的形状表示为(3,3,5),上诉向量形状表示为(5,),而标量的形状为空表示为(),Numpy中形状存在shape属性中。
- 数据类型。在Numpy中用dtype表示。可取值为float32、uint8、float64等。注意,Numpy中不存在字符串张量,因为张量存储在预先分配的连续内存段中,而字符串长度是可变的,无法用这种方式存储。
四、现实世界中的数据张量
-
向量数据: 2D张量,形状为(samples,features) samples:样本,features:特征数据 下同。例如:人口统计数据集,其中包括每个人的年龄、邮编、收入。每个人包含3个值的向量,而整个数据集包含100000个人。因此可以存储在形状为(100000,3)的2D张量中。
-
时间序列数据或序列数据: 3D张量,形状为(samples,timesteps,features) timesteps:每个样本包含的时间长度。当时间或者序列顺序对数据很重要的时候,应该将数据存储在带有时间轴的3D张量中。
-
图像: 4D张量,形状为(samples,height,width,channels)或者(samples,channels,height,width) height:图像高度,width:图像宽度,channels:通道数量
-
视频: 5D张量,形状为(samples,frames,height,width,channels)或者(samples,frames,channels,height,width) frames:每个样本所包含的帧数。视频的每一帧是一张彩色图像。可以保存在形状为(height,width,channels)的3D张量中,没一个视频样本一般都是由很多帧图像组成,可以存在一个形状为(frame,height,width,channels)的4D张量中,所有样本构成的集合就可以用形状为(samples,frame,height,width,channels)的5D张量进行存储。
五、矩阵和张量的运算
1. 逐个元素计算:
单独地将运算作用在每个元素上。比如对两个张量中对应的元素单独做加法运算或者乘法运算。Numpy的乘法和加法支持逐个元素计算
>>> import numpy as np
>>> x = np.array([[1,2,3],
[4,5,6]])
>>> y = x * 2 # x的每个元素乘以2
>>> y
array([[2,3,6],
[8,10,12]])
>>> z = x + y # x和y对应元素相加
>>> z
array([[3,5,9],
[12,15,18]])
>>> m = x * y # x和y对应元素相乘
>>> m
array([[2,6,18],
[32,50,72]])
2. 广播:
上述例子中参与运算的两个张量的形状是相同的。但是并不是只有形状相同的张量才可以做上述运算。我们试着将一个矩阵和一个向量做加法和乘法运算看看输出结果。
>>> x = np.array([[1, 2, 3],
[4, 5, 6]])
>>> y = np.array([1, 2, 3])
>>> z = x + y
>>> z
array([[2 4 6],
[5 7 9]])
>>> m = x * y
>>> m
array([[ 1 4 9],
[ 4 10 18]])
可以发现运算过程是先对y向量进行扩张变为矩阵,扩张后的矩阵的每一行元素和原向量的元素保持一致,再使用扩张后的矩阵和x矩阵进行逐元素运算,这个过程就叫做张量的广播。
3. 矩阵转置:
我们先来看看矩阵转置在numpy中的运算结果。
>>> x = np.array([[1, 2, 3],
[4, 5, 6]])
>>> y = x.T # x的转置
>>> y
array([[1, 4],
[2, 5],
[3, 6]])
数学上我们将矩阵X的转置表示为,由上述的输出结果我们可以得到转置的定义公式为:
即:沿着对角线将x轴的元素和y轴的元素进行镜像对调得到。
4. 张量点积。
点积运算是张量运算中最常见的运算,在numpy和kera中都是用标准的dot运算来实现点积。我们先来看看两个向量之间的运算规则。
>>> x = np.array([1, 2, 3])
>>> y = np.array([1, 2, 3])
>>> z = x.dot(y)
>>> z
14 # z = x0*y0 + x1*y1 + x2*y2
向量的点积运算是对向量所有元素的乘积做求和运算,结果是一个标量。
接下来我们扩展,再来看看矩阵的点积运算。
>>> x = np.array([[1, 2],
[1, 2]])
>>> y = np.array([[3, 4],
[5, 6]])
>>> z = x.dot(y)
>>> z
array([[13, 16],
[13, 16]])
可见,矩阵的点积结果是一个矩阵(z)。矩阵z的每个元素是由x的行和y的列的积求和得到,这个满足向量的计算公式 将上述公式推广到矩阵运算中:
可以通过如下图对点积运算做一个进一步的理解
根据上述公式我们可以得出一些结论和推理公式:
- X矩阵的列数必须和矩阵Y的行数相等
- 如果X的形状是m x n Y的形状是n x p,那么通过点积得到的Z形状就是m x p
- 矩阵的点积运算满足分配律:
- 矩阵的点积运算满足结合律:
- 矩阵的点积运算并不满足交换律
- 矩阵乘积的转置有着简单的形式:
以上结论都可以通过上述公式推导得到,这里就不作具体的推理和证明了。当然要明确的一个问题是:线性代数的知识远不止这里列出来的这些。这里只是列出了在深度学习中最经常用到的一小部分知识,后续有遇到再进行扩展学习吧。
六、资料引用
- 《Deep Learning with Python》
- 《Deep Learning》