02 - 神经网络的数据表示
1. 基本概念
张量(tensor):输入网络的数据存储对象
张量运算: 层的组成要素
梯度下降: 可以让网络从训练样本中进行学习
1.1 张量的概念
1.1.1 标量(0 Dimension)
仅包含一个数字的张量叫作标量。在numpy中,一个float32 或 float64 的数字就是一个标量张量。
使用ndim 属性查看张量的维度。
Python 3.8.1 (tags/v3.8.1:1b293b6, Dec 18 2019, 23:11:46) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> x = np.array(12)
>>> x
array(12)
>>> x.ndim
0
1.1.2 向量(1 Dimension)
数字组成的数组叫向量或一维张量。一维张量只有一个轴。
>>> x = np.array([12, 3, 6, 14, 7])
>>> x
array([12, 3, 6, 14, 7])
>>> x.ndim
1
1.1.3 矩阵(2 Dimension)
向量组成的数组叫作矩阵或二维张量。矩阵有两个轴, 行和列。
>>> x = np.array([[5, 78, 2, 34, 0],[6, 79, 3, 35, 1],[7, 80, 4, 36, 2]])
>>> x
array([[ 5, 78, 2, 34, 0],
[ 6, 79, 3, 35, 1],
[ 7, 80, 4, 36, 2]])
>>> x.ndim
2
现实生活中例如(samples, features) 组成的2D张量 。
例如:
人口统计数据集, 其中包括每个人的年龄、邮编、和收入。 每个人可以表示为包含3个值的向量
而整个数据集包含100000个人, 因此,可以存储在形状为(100000, 3) 的 2D张量中。
文本文档数据集, 每个文档表示为每个单词在其中出现的次数,每个文档可以被编码为包含20000个值的向量,
整个数据集包含500个文档, 可以存储在形状为(500, 20000)的张量中。
1.1.4 立方体 (3 Dimension)
将多个矩阵组合成一个新的数组,可以得到一个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
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 张量, 时间序列数据, 形状为(samples, timesteps, features)
例如股票价格数据集: 每一分钟,股票的当前价格、前一分钟最高价格和前一分钟的最低价格保存下来。
因此每分钟被编码为3D向量,整个交易日被编码为一个开关为(390, 3)的2D张量中,250 的数据则可以保存
在一个形状为(250, 390, 3)的3D张量中,这里每个样本是一天的股票数据。
将多个3D张量组合成一个数组, 可以创建一个4D张量,以此类推。
4D 张量,图像,形状为(samples, height, width, channels)
5D张量, 视频,形状为(samples, frames, height, width, channels)
1.2 张量的属性
张量有三个关键属性
* 维度(ndim):就是属于几D张量。
* 形状: 表示张量沿每个维度的大小(元素个数),所以是一个整数元组。
例如标量的形状是空,即()
向量的形状只包含一个元素(5,)
矩阵示例形状为3行5列(3, 5)。
立方体的形状为3高(层),3长(行),5宽(列) (3, 3, 5)
* 数据类型(dtype): float32, uint8, float64 , char
查看mnist数据集中张量的属性值
from keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
接下来,我们给出张量 train_images 的轴的个数,即 ndim 属性。
>>> print(train_images.ndim)
3
下面是它的形状。
>>> print(train_images.shape)
(60000, 28, 28)
下面是它的数据类型,即 dtype 属性。
>>> print(train_images.dtype)
uint8
使用Matplolib 显示
digit = train_images[4]
import matplotlib.pyplot as plt
plt.imshow(digit, cmap=plt.cm.binary)
plt.show()
2. 张量运算
所有计算机程序进入CPU运算时都只表示高低电平,运算只有AND,OR,NOR等。
与此类似,深度神经网络学到的所有变化都是张量运算。
2.1 逐元素运算
relu 运算与加法都是逐元素的运算,即该运算独立地应用于张量中的每个元素。
relu 的简单代码实现
def naive_relu(x): assert len(x.shape) == 2 x = x.copy() for i in range(x.shape[0]): for j in range(x.shape[1]): x[i, j] = max(x[i,j], 0) return x
加法运算的简单实现
def naive_add(x, y): assert len(x.shape) == 2 assert x.shape == y.shape x = x.copy() for i in range(x.shape[0]): for j in range(x.shape[1]): x[i, j] += y[i, j] return x
减法与乘法使用相同的方法实现,numpy 将这个都已经封装起来,交给了BLAS(Basic linear algebra subprograms)实现。
可以直接这么用
import numpy as np
z = x + y
z = np.maximum(z, 0)
2.2 广播
如果两个不同形状的张量数据进行加法操作,较小的张量会被广播,以匹配较大的张量的形状。
广播包含以下两步:
(1) 向较小的张量添加轴(叫作广播轴), 使其ndim 与 较大的张量相同
(2) 将较小的张量沿着新轴重复,使其形状与较大的张量相同。
具体例子
假设x是一个2D矩阵,形状为(32, 10), y是一个数组,形状为(10, ), 现在要执行 x + y 操作。
第一步: 给y添加空的第一个轴,这样y的形状变为(1, 10)。
第二步:将 y 沿着新轴重复32次, 这样得到的张量 y 的形状为 (32, 10), 并且 y[i, :] == y 。
现在可以相加, 因为形状相同。
2.3 张量点积
点积运算,也叫张量积,与诸元素运算不相同。是最常见也是最有用的张量运算。
与逐元素的运算不相同,它将输入张量的元素合并在一起。
两个向量之间的点积是一个标量,而且只有元素个数相同的向量之间才能做点积。
import numpy as np z = np.dot(x, y)
数学符号中的 . 表示点积去处
z = x.y
def naive_vector_dot(x, y): assert len(x.shape) == 1 assert len(y.shape) == 1 assert x.shape[o] == y.shape[o] z = 0. for i in range(x.shape[0]): z += x[i] * y[i] return z
一个矩阵x 和 一个向量 y 做点积,返回值是一个向量,其中每个元素是y 和 x 的每一行之间的点积。
def naive_metric_vector_dot(x, y): assert len(x.shape) == 2 assert len(y.shape) == 1 assert x.shape[1] == y.shape[0] z = np.zeros(x.shape[0]) for i in range(x.shape[0]): for j in range(x.shape[1]): z[i] += x[i, j] * y[j] return z
2.4 张量变形
张量变形是指改变张量的行和列,以得到想要的形状。 变形后的张量的元素总个数与初始张量相同。
>>> x = np.array([[0., 1.], [2., 3.], [4., 5.]]) >>> print(x.shape) (3, 2) >>> x = x.reshape((6, 1)) >>> x array([[ 0.], [ 1.], [ 2.], [ 3.], [ 4.], [ 5.]]) >>> x = x.reshape((2, 3)) >>> x array([[ 0., 1., 2.], [ 3., 4., 5.]])
经常遇到的一种特殊的张量变形是转置( transposition)。对矩阵做转置是指将行和列互换,
使 x[i, :] 变为 x[:, i]。
>>> x = np.zeros((300, 20))
>>> x = np.transpose(x)
>>> print(x.shape)
(20, 300)
创建一个形状为 (300, 20) 的零矩阵