理解深度学习须要熟悉一些简单的数学概念:Tensors(张量)、Tensor operations 张量操做、differentiation微分、gradient descent 梯度降低等等。python
“Hello World”----MNIST 手写数字识别
#coding:utf8 import keras from keras.datasets import mnist from keras import models from keras import layers from keras.utils import to_categorical # 加载MNIST数据集 (train_images,train_labels),(test_images,test_labels) = mnist.load_data() # 定义网络架构 network = models.Sequential() network.add(layers.Dense(512,activation="relu",input_shape=(28*28,))) network.add(layers.Dense(10,activation="softmax")) # 定义网络优化:优化算法、损失函数以及评价指标 network.compile(optimizer='rmsprop',loss="categorical_crossentropy",metrics=['accuracy']) # 数据预处理:images 缩放到[0,1]之间 train_images = train_images.reshape(60000,28*28) train_images = train_images.astype('float32') / 255 test_images = test_images.reshape(test_images.shape[0],28*28) test_images = test_images.astype('float32') / 255 # 数据预处理:labels:one-hot 编码 train_labels = to_categorical(train_labels) test_labels = to_categorical(test_labels) # 模型训练 network.fit(train_images,train_labels,epochs=5,batch_size=128) # 模型测试 test_loss, test_acc = network.evaluate(test_images,test_labels) print('test accuracy:',test_acc) # test accuracy: 0.9727
由上面的程序,咱们了解了如何构建网络以及如何进行网络训练来识别手写字体算法
神经网络的数据表示
当下几乎全部的机器学习框架都使用tensors张量做为基本的数据结构。Tensor本质上是一个数据容器,大多数为数值型数据,也就是说tensor是存储数字的容器。矩阵是二维的张量,张量是任意维数的矩阵的推广(tensor的一个维度一般称为一个轴axis,而不是dimension)。 ###Scalars(0D tensors)标量--0维张量 只包含一个数字的张量tensor叫作标量scaler(或者0D tensor). 在numpy中,一个float32,或float64类型的数字是一个标量。能够经过tensor的ndim属性查看tensor的维度;张量的维度为0,同时维度也称为秩rank。api
>>> import numpy as np >>> x = np.array(12) >>> x array(12) >>> x.ndim 0
向量(一维张量 1D)
一维数组称为向量,或一维张量。一维张量有一个轴axis;数组
>>> x = np.array([13, 31, 7, 14]) >>> x array([13, 31, 7, 14]) >>> x.ndim 1
上述向量有5个条目,所以称为5维向量。5维向量和5维张量并不相同。5维向量指一个轴5个元素。5维张量有5个轴。网络
矩阵(二维张量 2D)
向量数组为一个矩阵,即二维张量。一个矩阵有二个轴。数据结构
>>> x = np.array([[5, 78, 2, 34, 0], [6, 79, 3, 35, 1], [7, 80, 4, 36, 2]]) >>> x.ndim 2
三维张量以及更高维张量
矩阵数组称为三维张量,能够看作是数字的立方体。架构
>>> 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
3维张量数组造成一个4维张量,以此类推。深度学习中,通常操做0D~4D的张量。框架
核心属性
tensor张量由3个重要的属性:机器学习
- Number of axes轴的个数(秩)。3D tensor有3个轴。能够经过tensor的ndim属性查看轴的个数。
- Shape形状:数字元组,描述张量各个轴上的维度。张量维度为(),向量维度为(5,),2D张量维度(3,5),3D张量维度(3,3,5).
- Data type数据类型(dtype属性):张量中数字的数据类型,如float32,uint8,float64等等。
数据批量data batches
深度学习中数据张量的第一轴(axis 0)一般是样本轴(样本维度)---表示样本量的数目。MNIST数据集中,样本是数字图片。 此外,深度学习处理数据过程当中并不一次性对整个数据集进行处理,一般会将数据集划分红若干个批量batches。好比:MNIST中128的小批量样本:函数
batch = train_images[:128]
生活中遇到的数据张量
- 向量型数据vector data--2维张量 ,形状(samples,features)
- 时间序列数据或序列型数据--3维张量,形状(samples,timesteps, features)
- 图片--4维张量,形状(samples, height, width, channels)或者(samples, channels, height, width)
- 视频--5维张量。形状(samples. frames, height, width, channels) 或者(samples, frames, channels, height, width)
Tensors 操做
全部的计算机程序最终都简化为二进制输入上的二进制操做(AND, OR, NOR 等),同时,深度学习网络中全部的转换也能够简化为数据张量上的张量操做,如 加、乘等。
逐元素操做element-wise operations
relu操做和加法运算是逐元素操做:独立应用于待计算张量中的每一个条目。 好比加法运算的for-loop实现:
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
广播broadcasting
上面实现的naive_add加法运算仅支持两个形状相同的二维张量。若是两个加法运算的张量形状不相同会发生什么?小张量会广播匹配到大张量上。广播由两步组成:
- 小张量会添加axes广播轴,以匹配大张量的ndim轴维度。
- 小张量在新添加的轴方向上重复以匹配大张量的形状。
举例来讲,张量X形状为(32, 10),张量y形状为(10, ).两个张量相加。首先,添加一个新轴到张量y上,形状变成(1, 10);而后,在新轴方向上重复y32次,最终张量Y形状为(32,10),X、Y形状相同,能够进行加法运算。 但实际过程当中并不会建立新的二维张量,影响计算效率。
def naive_add_matrix_and_vector(x, y): assert len(x.shape) == 2 assert len(y.shape) == 1 assert x.shape[1] == y.shape[0] x = x.copy() for i in range(x.shape[0]): for j in range(x.shape[1]): x[i, j] += y[j] return x
张量点积运算 Dot
dot点积操做最经常使用、最有用的张量操做。与逐元素操做相反,点积整合输入张量的全部条目。
def naive_vector_dot(x, y): assert len(x.shape) == 1 assert len(y.shape) == 1 assert x.shape[0] == y.shape[0] z = 0. for i in range(x.shape[0]): z += x[i] * y[i] return z
tensor reshaping
reshape意味着从新排列张量tensor的行和列以知足特定的形状。Reshape以后的tensor与初始tensor包含的系数数目相同。
>>> 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.]])
基于梯度的优化算法
神经网络层对输入进行的数学转换为: $output = relu(dot(W, input) + b)$ 张量$W$和张量$b$ 是网络层的参数,被称为网络层的权重系数或者可训练参数。这些权重系数包含着网络从训练数据中学到的信息。 起始这些权重参数用小的随机数赋值(称为随机初始化)。随后,基于反馈信号逐渐调整权重系数。调整过程称为训练过程。 训练过程一般须要反复进行:
- 得到训练数据X,y的一个batch 批量;
- 前向传播获得批量X上的预测值y_pred;
- 计算当前批量下的损失值:计算y_pred和y之间的差别度;
- 在损失函数减少的方向上更新权重系数。
随机梯度降低
一个可微分函数,理论上可以找到它的最小值:最小值点导数为0,因此须要找到全部导数为0的点,而后相互比较找到最小值。 神经网络中,意味着找到一组权重值,使损失函数最小。 mini-batch SGD能够描述为如下四步:
- 得到训练数据X,y的一个batch 批量;
- 前向传播获得批量X上的预测值y_pred;
- 计算当前批量下的损失值:计算y_pred和y之间的差别度;
- 沿着梯度反方向移动权重系数--例如:$W -= step * gradient$,损失函数也所以减少。 随机是指每一个小批量batch是随机在数据中挑选的。 小批量随机梯度降低的一种极端状况是随机梯度降低算法---所有数据造成一个批量,计算结果更准确,但效率比较低。
小结
- 学习指在训练数据上找到一组权重值使得损失函数最小;
- 学习过程:在小批量数据上计算损失函数对应权重系数的梯度值;以后权重系数沿着梯度的反方向移动;
- 学习过程的可能性是基于神经网络是一系列张量操做,所以可以使用导数的链式法则计算损失函数对应权重系数的梯度值;
- 两个重要的概念:损失函数和优化方法(须要在数据送到网络以前定义);
- 损失函数:在训练过程当中最小化的函数,能够用来评估模型的好坏(越小越好,最小为0);
- 优化方法:计算梯度的具体方法,以后更新权重系数;好比有:RMSProp、SGD、Momentum等等。