粗读《Python 深度学习》(1)

粗读《Python 深度学习》(1)

  • 第二章
    • 2.1 初始神经网络
    • 2.2 神经网络的数据表示
      • 2.2.1 标量(0D 张量)
      • 2.2.2 向量(1D 张量)
      • 2.2.3 矩阵(2D 张量)
      • 2.2.4 3D 张量与更高维张量
      • 2.2.5 关键属性
      • 2.2.6 在 Numpy 中操作张量
      • 2.2.7 数据批量的概念
      • 2.2.8 现实世界中的数据张量
    • 2.3 神经网络的“齿轮”:张量运算
      • 2.3.1 逐元素运算
      • 2.3.2 广播
      • 2.3.3 张量点积
      • 2.3.4 张量变形
      • 2.3.5 张量运算的几何解释
      • 2.3.6 深度学习的几何解释
    • 2.4 神经网络的“引擎”:基于梯度的优化
      • 2.4.2 张量运算的导数:梯度
      • 2.4.3 随机梯度下降
      • 2.4.4 链式求导:反向传播算法
    • 2.5 回顾第一个例子

第二章

2.1 初始神经网络

此处以手写数字图像分类为例,使用 MNIST 数据集,包含 60 000 张训练图像和 10 000 张测试图像,图像大小为 28*28。

1、加载 Keras 中的 MNIST 数据集

from keras.datasets import mnist

(train_images, train_labels), (test_images, test_labels) = mnist.load_data()

训练集 包括:6万张存储在变量train_images中的图像样本(大小为(60000, 28, 28))和6万个存储在变量train_labels中的样本标签(大小为(60000,))。
测试集 包括:1万张存储在变量test_images中的图像样本(大小为(10000, 28, 28))和6万个存储在变量test_labels中的样本标签(大小为(10000, ))。

2、网络架构

神经网络的核心组件是 层(layer),它是一种数据处理模块,你可以将它看成数据过滤器。进去一些数据,出来的数据变得更加有用。具体来说,层从输入数据中提取 表示——我们期望这种表示有助于解决手头的问题。
个人理解:通过改变数据的表达形式,使得混杂在一起的数据分离,易于区分。同时,通过层层变化,使得抽象的内容变得简单清晰,方便电脑理解识别。)

from keras import models
from keras import layers

network = models.Sequential()
network.add(layers.Dense(512, activation='relu', input_shape=(28 * 28,)))
network.add(layers.Dense(10, activation='softmax'))

上述代码中的网络包含 2 个 Dense 层,它们是 密集连接(也叫 全连接)的神经层。第二层(也是最后一层)是一个 10 路 softmax 层,它将返回一个由 10 个概率值(总和为 1)组成的数组。每个概率值表示当前数字图像属于 10 个数字类别中某一个的概率。

3、编译步骤

network.compile(optimizer='rmsprop',
                loss='categorical_crossentropy',
                metrics=['accuracy'])

编译(compile) 包括三个重要参数:损失函数(loss function)优化器(optimizer)指标(metric)
此处选用多分类交叉熵损失函数和RMSprop优化器(可添加动量),以变量accuracy中存储的精确度为指标。

4、准备图像数据

train_images = train_images.reshape((60000, 28 * 28))
train_images = train_images.astype('float32') / 255

test_images = test_images.reshape((10000, 28 * 28))
test_images = test_images.astype('float32') / 255

在开始训练之前,要对数据进行 预处理,将其变换为网络要求的形状,并缩放到所有值都在 [0, 1] 区间。

因为数据将输入到大小512的全连接层中,所以需要将二维图像变换为一维数列,同时对数据 标准化。原始数据为unit 8数组,为确保标准化后的数据精度,此处将数据存储在float 32数组中。

5、准备标签

from keras.utils import to_categorical

train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)

6、训练

最后调用网络中的fit()方法,拟合(fit) 模型。

>>> network.fit(train_images, train_labels, epochs=5, batch_size=128)
Epoch 1/5
60000/60000 [=============================] - 9s - loss: 0.2524 - acc: 0.9273 
Epoch 2/5
51328/60000 [=======================>.....] - ETA: 1s - loss: 0.1035 - acc: 0.9692

训练过程中显示了两个数字:一个是网络在训练数据上的 损失(loss),另一个是网络在训练数据上的 精度(acc)。本例中,训练集精度可以达到0.989(98.9%),预测集精度只有 97.8%,这是由于 过拟合(overfit) 造成的。
(就像做题,同样的考点,盯着几种题型多刷几遍,准确率就上去了,换一个题型考法,准确率就会低一些。)

2.2 神经网络的数据表示

前面例子使用的数据存储在多维Numpy数组中,也叫 张量(tensor)。张量是矩阵向任意维度的推广[注意,张量的 维度(dimension) 通常叫作 轴(axis)]。

2.2.1 标量(0D 张量)

仅包含一个数字的张量叫作 标量(scalar,也叫标量张量、零维张量、0D 张量)。在 Numpy中,一个float32float64的数字就是一个标量张量(或标量数组)。可以用ndim 属性 来查看一个 Numpy 张量的轴的个数。标量张量有 0 个轴(ndim == 0)。张量轴的个数也叫作 阶(rank)

>>> import numpy as np
>>> x = np.array(12)
>>> x
array(12)
>>> x.ndim
0

2.2.2 向量(1D 张量)

数字组成的数组叫作 向量(vector)一维张量(1D 张量)。一维张量只有一个轴。

>>> x = np.array([12, 3, 6, 14, 7])
>>> x
array([12, 3, 6, 14, 7])
>>> x.ndim
1

2.2.3 矩阵(2D 张量)

向量组成的数组叫作 矩阵(matrix)二维张量(2D 张量)。矩阵有 2 个轴(通常叫作行和列)。

>>> x = np.array([[5, 78, 2, 34, 0],
                  [6, 79, 3, 35, 1],
                  [7, 80, 4, 36, 2]])
>>> x.ndim
2

第一个轴(0 轴)上的元素叫作 行(row),第二个轴(1 轴)上的元素叫作 列(column)
(0轴方向是由5指向7,1轴方向是由5指向0。行元素为 [5, 78, 2, 34, 0])。

2.2.4 3D 张量与更高维张量

3D 张量由多个2D 张量沿第三个轴(2 轴深度)堆叠形成,可以想象成一个立方体。

>>> x = np.array([[[5, 78, 2, 34, 0], 
                   [6, 79, 3, 35, 1], 
                   [7, 80, 436, 2]], 
                  [[5, 78, 2, 34, 0], 
                   [6, 79, 3, 35, 1], 
                   [7, 80, 436, 2]], 
                  [[5, 78, 2, 34, 0], 
                   [6, 79, 3, 35, 1], 
                   [7, 80, 436, 2]]])

2.2.5 关键属性

张量是由三个关键 属性 来定义的:轴的个数形状数据类型

利用 Matplotlib 库(Python 标准科学套件的一部分)来显示这个 3D 张量中的第 4 个数字:

digit = train_images[4]

import matplotlib.pyplot as plt
plt.imshow(digit, cmap=plt.cm.binary)
plt.show()

2.2.6 在 Numpy 中操作张量

在前面的例子中,使用语法train_images[i]来选择沿着第一个轴的特定数字。选
择张量的特定元素叫作 张量切片(tensor slicing)。下面代码在所有图像的右下角选出 14 像素×14 像素的区域:

my_slice = train_images[:, 14:, 14:]

大概是这样:
粗读《Python 深度学习》(1)_第1张图片

2.2.7 数据批量的概念

通常来说,深度学习中所有数据张量的第一个轴(0 轴,因为索引从 0 开始)都是 样本轴(samples axis,有时也叫 样本维度)。

此外,深度学习模型不会同时处理整个数据集,而是将数据拆分成小批量。之前的例子的批量大小batch_size=128。对于这种批量张量,第一个轴(0 轴)叫作 批量轴(batch axis)或 批量维度(batch dimension)

2.2.8 现实世界中的数据张量

常用的张量类型有:

1、向量数据:2D 张量,形状为 (samples, features)。
2、时间序列数据或序列数据:3D 张量,形状为 (samples, timesteps, features)。
3、图像:4D 张量,形状为 (samples, height, width, channels) 或 (samples, channels, height, width)。
4、视频:5D 张量,形状为 (samples, frames, height, width, channels) 或 (samples, frames, channels, height, width)。

2.3 神经网络的“齿轮”:张量运算

2.3.1 逐元素运算

Relu 运算加法 都是逐元素(element-wise)的运算,即该运算独立地应用于张量中的每个元素,也就是说,这些运算非常适合大规模并行实现(向量化实现,这一术语来自于 1970—1990 年间向量处理器超级计算机架构)。
Relu 运算:

def naive_relu(x):
    assert len(x.shape) == 2   #'断言' x是一个2D张量
    
    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

2.3.2 广播

当两个形状不同的张量相加时,如果没有歧义的话,较小的张量会被 广播(broadcast),以匹配较大张量的形状。具体步骤:

(1) 向较小的张量添加轴(叫作广播轴),使其ndim与较大的张量相同。
(2) 将较小的张量沿着新轴重复,使其形状与较大的张量相同。

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

2.3.3 张量点积

张量点积运算和矩阵电机运算类似,用函数np.dot()或者点积运算符.表示。

2.3.4 张量变形

利用方法reshape()可以改变张量的形状。

train_images = train_images.reshape((60000, 28 * 28))

使用方法transpose()对张量进行 转置变换,这个比较复杂,需要添加转置轴的相关参数。

2.3.5 张量运算的几何解释

对于张量运算所操作的张量,其元素可以被解释为某种几何空间内点的坐标。张量运算改变了张量在几何空间中的形状和位置。仿射变换、旋转、缩放等基本的几何操作都可以表示为张量运算。

2.3.6 深度学习的几何解释

神经网络完全由一系列张量运算组成,而这些张量运算都只是输入数据的几何变换。因此,你可以将神经网络解释为高维空间中非常复杂的几何变换,这种变换可以通过许多简单的步骤来实现。

对于三维的情况,下面这个思维图像是很有用的。想象有两张彩纸:一张红色,一张蓝色。将其中一张纸放在另一张上。现在将两张纸一起揉成小球。这个皱巴巴的纸球就是你的 输入数据,每张纸对应于分类问题中的一个 类别神经网络(或者任何机器学习模型)要做的就是找到可以让纸球恢复平整的变换,从而能够再次让两个类别明确可分。 通过深度学习,这一过程可以用三维空间中一系列简单的变换来实现,比如你用手指对纸球做的变换,每次做一个动作。

粗读《Python 深度学习》(1)_第2张图片

2.4 神经网络的“引擎”:基于梯度的优化

在之前的代码中,第一层对输入做了如下操作

output = relu(dot(w, input) + b)

其中,wb都是张量,均为该层的属性。它们被称为该层的 权重(weight)或 可训练参数(trainable parameter),分别对应 kernel 和 bias 属性(卷积核和偏置)。这些权重包含网络从观察训练数据中学到的信息。

一开始,这些权重矩阵取较小的随机值,这一步叫作 随机初始化(random initialization)下一步则是根据反馈信号逐渐调节这些权重。这个逐渐调节的过程叫作 训练,也就是机器学习中的学习。

上述过程发生在一个 训练循环(training loop)内,其具体过程如下:

(1) 抽取训练样本 x 和对应目标 y 组成的数据批量。
(2) 在 x 上运行网络[这一步叫作 前向传播(forward pass)],得到预测值y_pred
(3) 计算网络在这批数据上的损失,用于衡量 y_pred 和 y 之间的距离。
(4) 更新网络的所有权重,使网络在这批数据上的损失略微下降。

2.4.2 张量运算的导数:梯度

梯度(gradient)是张量运算的导数。它是导数这一概念向多元函数导数的推广。多元函数是以张量作为输入的函数。

2.4.3 随机梯度下降

给定一个可微函数,理论上可以用解析法找到它的最小值,但对于实际的神经网络是无法求解的,因为参数的个数不会少于几千个,而且经常有上千万个。

之前描述的方法叫作 小批量随机梯度下降(mini-batch stochastic gradient descent,又称为 小批量 SGD)。具体是:

(1) 抽取训练样本 x 和对应目标 y 组成的数据批量。
(2) 在 x 上运行网络,得到预测值 y_pred。
(3) 计算网络在这批数据上的损失,用于衡量 y_pred 和 y 之间的距离。
(4) 计算损失相对于网络参数的梯度[一次反向传播(backward pass)]。
(5) 将参数沿着梯度的反方向移动一点,比如 w -= step * gradient,从而使这批数据上的损失减小一点。

小批量 SGD 算法的一个变体是每次迭代时只抽取一个样本和目标,而不是抽取一批数据。这叫作 真 SGD(有别于小批量 SGD)。还有另一种极端,每一次迭代都在所有数据上运行,这叫作 批量 SGD。这样做的话,每次更新都更加准确,但计算代价也高得多。这两个极端之间的有效折中则是选择合理的批量大小。

此外,SGD 还有多种变体,其区别在于计算下一次权重更新时还要考虑上一次权重更新,而不是仅仅考虑当前梯度值,比如 带动量的 SGDAdagradRMSProp 等变体。这些变体被称为 优化方法(optimization method)或 优化器(optimizer)。其中动量的概念尤其值得关注,它在许多变体中都有应用。动量 解决了 SGD 的两个问题:收敛速度局部极小点

粗读《Python 深度学习》(1)_第3张图片

使用 动量 方法可以避免这样的问题,这一方法的灵感来源于物理学。有一种有用的思维图像,就是将优化过程想象成一个小球从损失函数曲线上滚下来。如果小球的动量足够大,那么它不会卡在峡谷里,最终会到达全局最小点。动量方法的实现过程是每一步都移动小球,不仅要考虑当前的斜率值(当前的加速度),还要考虑当前的速度(来自于之前的加速度)。这在实践中的是指,更新参数 w 不仅要考虑 当前的梯度值,还要考虑 上一次的参数更新,其简单实现如下所示。

past_velocity = 0.
momentum = 0.1 
while loss > 0.01:
    w, loss, gradient = get_current_parameters()
    velocity = past_velocity * momentum - learning_rate * gradient
    w = w + momentum * velocity - learning_rate * gradient
    past_velocity = velocity
    update_parameter(w)

2.4.4 链式求导:反向传播算法

根据微积分的知识,可以推导(f(g(x)))' = f'(g(x)) * g'(x),这称为 链式法则(chain rule)。将链式法则应用于神经网络梯度值的计算,得到的算法叫作 反向传播(backpropagation,有时也叫 反式微分,reverse-mode differentiation)。反向传播从最终损失值开始,从最顶层反向作用至最底层,利用链式法则计算每个参数对损失值的贡献大小

2.5 回顾第一个例子

回顾之前的例子,我们会明白:
1、张量的形状
2、权重张量 是层的属性,里面保存了网络所学到的 知识(knowledge)。
3、categorical_crossentropy是损失函数,是用于学习权重张量的反馈
信号
,在训练阶段应使它最小化。
4、减小损失是通过小批量随机梯度下降来实现的,具体在于选择什么样的优化器
5、明白在调用fit时发生了什么:网络开始在训练数据上进行 迭代(每个小 批量包含128 个样本),共迭代 5 次[在所有训练数据上迭代一次叫作一个 轮次(epoch)]。在每次迭代过程中,网络会计算批量损失相对于权重的梯度,并相应地 更新权重。5 轮之后,网络进行了2345 次梯度更新(每轮 469 次,60000/128=468.75),网络损失值将变得足够小,使得网络能够以很高的精度对手写数字进行分类。

你可能感兴趣的:(#,《Python,深度学习》,python)