张量
神经网络使用的数据经常是存储在Numpy数组中,也称为张量。
一般来说,当前所有机器学习系统都使用张量作为基本数据结构。
张量这一概念的核心在于,它是一个数据容器。它包含的数据几乎总是数值数据,因此它是数字的容器。
矩阵是二维张量,张量是矩阵向任意维度的推广,张量的维度通常也叫做轴。
常用的张量数据如下:
-
标量(0D张量):仅包含一个数字的张量。
- 在Numpy中,一个float32或float64的数字就是一个标量张量
- 可以使用ndim属性查看一个Numpy张量的轴的个数
- 标量张量有0个轴,张量轴的个数也叫做阶
-
向量(1D张量):数字组成的数组。
- 一维张量只有一个轴
-
矩阵(2D张量):向量组成的数组。
- 矩阵有2个轴,通常叫做行和列
- 可以将矩阵直观地理解为数字组成的矩形网络
-
3D张量及更高维张量
- 将多个矩阵合成一个新的数组,可以得到一个3D张量
- 可以将它直观地理解为数字组成的立方体
- 将多个3D张量组合成新数组,可以创建4D张量。以此类推可以构建更高维张量。
- 深度学习一般处理0-4D张量,但处理视频数据时可能会遇到5D张量
以上张量的代码示例:
import numpy as np
x = np.array(12)
x.ndim # 标量,即0维张量
x = np.array([2,4,6,8,9]) # 该向量有5个元素,即5D向量,此处的维度表示沿着某个轴上的元素个数
x.ndim # 向量,即1维张量
x = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]) # 矩阵是由向量组成的数组
x.ndim # 矩阵,即2维张量
x = np.array([[[1, 2, 3], [4, 5, 6], [7, 8, 9]],
[[1, 2, 3], [4, 5, 6], [7, 8, 9]],
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]]) # 3D张量是由矩阵组成的数组
x.ndim # 3D张量
张量的三个关键属性:
- 轴的个数(阶):3D张量有3个轴,矩阵有2个轴。
- 形状:是个整数元组,表示张量沿每个轴的维度大小(元素个数)
- 如前面矩阵的形状为(3,3),3D张量的形状为(3,3,3),向量的形状为(5,),标量的形状为空()
- 数据类型:张量中所停含数据的类型,如float32, float64, uint8等
- 注意,在极少数情况下,可能会遇到char张量,但Numpy中不存在字符串张量,张量存储在预先分配的连续内存段中,而字符串长度可变,无法存储。
张量操作
常用的操作是选择张量的特定元素,即张量切片。
以Numpy为例,操作张量的方法如下:
my_slice = train_images[10:100] # 假设train_images为mnist数据集
print(my_slice.shape) # 取出的是原数据集中从第10到第100个元素,不包括第100个元素
# (90, 28, 28)
my_slice = train_images[:, 14:, 14:]
# 选出所有图像右下角14*14像素区域
my_slice = train_images[:, 7:-7, 7:-7]
# 选出图像中心14*14像素区域
通常,深度学习中所有数据张量的第一个轴为样本轴。
深度学习模型不会同时处理整个数据集,而是将数据拆分成小批量,如:
batch = train_images[:128] # 第一个批量
batch = train_images[128:256] # 第二个批量
batch = train_images[128*n:128*(n+1)] # 第n个批量
常用的张量数据如下:
- 向量数据:2D张量,形状为(samples, features),如人口统计数据,文本文档数据集
- 时间序列数据或序列数据:3D张量,形状为(samples, timestamps, features),如股票数据集,推文数据集
- 图像:4D张量,形状为(samples, height, width, channels)或(samples, channels, height, width),如图像数据
- 视频:5D张量,形状为(samples, frames, height, width, channels)或(samples, frames, channels, height, width),如视频数据
张量运算
所有计算机程序最终都转化为二进制输入上的一些二进制运算(AND/OR/NOR等)。
与此类似,深度神经网络学到的变换也都可以简化为数值数据张量上的一些张量运算。
常用的张量运算如下:
- 逐元素运算:relu运算和加法都是逐元素运算。该运算独立地应用于张量中的每个元素,非常适合大规模并行实现。
- 广播:当两个不同维度的张量进行运算时,较小的张量会被广播,以匹配较大的张量形状,然后再进行计算
- 张量点积:点积运算也叫张量积(与张量逐元素乘积不同),应该最广,它将输入张量的元素合并在一起。
- 张量变形:根据需要改变张量的行和列。变形后的张量的元素总个数与初始张量相同
神经网络完全由一系列的张量运算组成,而这些张量运算都只是输入数据的几何变换。
深度学习的内容就是要为复杂的、高度折叠的数据流找到简洁的表示,深度网络的每一层都通过变换使数据展开一点点,许多层堆叠在一起,可以实现非常复杂的解开过程。
基于梯度的优化
经常使用下面的方式对输入数据进行变换:
output = relu(dot(w, input) + b)
其中,w和b都是张量,它们为该层的权重或可训练参数,这些权重包含网络从观察训练数据中学到的信息。
一开始,这些权重矩阵取较小的随机值,这一步叫做随机初始化,运算不会得到有用的表示。
虽然得到的表示没有意义,但这是一个起点,下一步是根据反馈信号逐渐调节这些权重,这个逐渐调节的过程叫做训练,也就是机器学习中的学习。
学习的过程是一个循环:
- 抽取训练样本x和对应目标y组成的数据批量
- 在x上运行网络,即前向传播,得到预测值y_pred
- 计算网络在这批数据上的损失,用于衡量y_pred和y之间的距离
- 在更新网络的所有权重,使网络在这批数据上的损失略微下降
最终得到的网络在训练数据上的损失非常小,即预测值y_pred和预期目标y之间的距离非常小。
网络就学会了将输入映射到正确目标。
第一步看起来非常简单,只是输入/ 输出(I/O)的代码。
第二步和第三步仅仅是一些张量运算的应用。
难点在于第四步:更新网络的权重。考虑网络中某个权重系数,你怎么知道这个系数应该增大还是减小,以及变化多少?
简单的方法是保持其他参数不变,只调节其中一个,观察反馈。但是,当网络中参数成千上万个时,这种方法低效且计算代价巨大。
一种更好的方法是利用网络中所有运算都是可微的这一事实,计算损失相对于网络系数的梯度,然后向梯度的反方向改变系数,从而使损失降低。
关于可微、导数、梯度、随机梯度下降、链式求导(反向传播算法)等基本数学原理,可以参考相关资料。
于是,第四步就可以通过下述流程有效实现:
- 计算损失相对于网络参数的梯度(一次反向传播)
- 将参数沿着梯度的反方向移动一点,从而使这批数据上的损失减少一点
小结
以上就是学习神经网络需要了解的基本数学知识。
它并不高深莫测,只要通过复习和练习,并在实践中进行复盘,很容易理解和掌握。
有了这些知识,就可以开始开心研究深度学习了。
参考资料
《python 深度学习》