深度学习-吴恩达
@@ -58,6 +58,13 @@ python3-numpy-scipy-matplotlib-pandas√
|
||||
|
||||
> 变更说明
|
||||
> * 经过仔细思考,感觉李宏毅的机器学习+深度学习与吴恩达的机器学习+深度学习,重叠的部分太多,入门阶段进行混合学习代价较大。所以,入门阶段都是以吴恩达的课程为主,编程也是以吴恩达的课程为主。总共包括五个模块,可以适当地学习三到四个模块,然后进行下一阶段。
|
||||
> * 等所有部分完成了,以李宏毅的课程作为基础知识的回顾和强化。
|
||||
|
||||
|
||||
> 学习路径说明
|
||||
> * 视频教程-基础知识构建,以知识的角度,逐渐构建机器学习体系,跟随课程理解。
|
||||
> * 读书整理-机器学习算法,从算法的角度,独立理解算法的原理,深刻理解每个算法的原理。
|
||||
> * 算法实践,从工程的角度,考虑如何设计算法,实现算法,优化算法和进行算法可视化
|
||||
|
||||
|
||||
### 联邦学习系列(三周)
|
||||
@@ -68,7 +75,12 @@ fate
|
||||
### 相关资料说明
|
||||
* 吴恩达的机器学习
|
||||
* 吴恩达的深度学习五套课程
|
||||
* 西瓜书
|
||||
* 李宏毅《机器学习+深度学习》课程
|
||||
* ~~林轩田《机器学习基石》课程~~
|
||||
* 李航《统计学习方法》
|
||||
* 周志华《西瓜书》
|
||||
* 《机器学习实战》
|
||||
* 《Python机器学习》
|
||||
|
||||
### 选择
|
||||
框架选择:
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
> 这里主要以各种算法的理论知识为主进行说明。
|
||||
|
After Width: | Height: | Size: 52 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Convolutional_Neural_Networks/1x1-Conv-1.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Convolutional_Neural_Networks/1x1-Conv-2.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Convolutional_Neural_Networks/AlexNet.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 511 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Convolutional_Neural_Networks/CNN-Example.jpg
Normal file
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 198 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 222 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Convolutional_Neural_Networks/LeNet-5.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Convolutional_Neural_Networks/Max-Pooling.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Convolutional_Neural_Networks/More-Filters.jpg
Normal file
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 424 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 186 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Convolutional_Neural_Networks/Padding.jpg
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Convolutional_Neural_Networks/R-CNN.png
Normal file
|
After Width: | Height: | Size: 264 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Convolutional_Neural_Networks/ResNet-Paper.png
Normal file
|
After Width: | Height: | Size: 223 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Convolutional_Neural_Networks/Siamese.png
Normal file
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 232 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Convolutional_Neural_Networks/Stride.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 126 KiB |
|
After Width: | Height: | Size: 22 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Convolutional_Neural_Networks/VGG.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 412 KiB |
|
After Width: | Height: | Size: 13 KiB |
222
机器学习/吴恩达深度学习/学习笔记/Convolutional_Neural_Networks/卷积神经网络.md
Normal file
@@ -0,0 +1,222 @@
|
||||
<h1 align="center">卷积神经网络</h1>
|
||||
|
||||
## 计算机视觉
|
||||
|
||||
**计算机视觉(Computer Vision)**的高速发展标志着新型应用产生的可能,例如自动驾驶、人脸识别、创造新的艺术风格。人们对于计算机视觉的研究也催生了很多机算机视觉与其他领域的交叉成果。一般的计算机视觉问题包括以下几类:
|
||||
|
||||
* 图片分类(Image Classification);
|
||||
* 目标检测(Object detection);
|
||||
* 神经风格转换(Neural Style Transfer)。
|
||||
|
||||
应用计算机视觉时要面临的一个挑战是数据的输入可能会非常大。例如一张 1000x1000x3 的图片,神经网络输入层的维度将高达三百万,使得网络权重 W 非常庞大。这样会造成两个后果:
|
||||
|
||||
1. 神经网络结构复杂,数据量相对较少,容易出现过拟合;
|
||||
2. 所需内存和计算量巨大。
|
||||
|
||||
因此,一般的神经网络很难处理蕴含着大量数据的图像。解决这一问题的方法就是使用**卷积神经网络(Convolutional Neural Network, CNN)**。
|
||||
|
||||
## 卷积运算
|
||||
|
||||
我们之前提到过,神经网络由浅层到深层,分别可以检测出图片的边缘特征、局部特征(例如眼睛、鼻子等),到最后面的一层就可以根据前面检测的特征来识别整体面部轮廓。这些工作都是依托卷积神经网络来实现的。
|
||||
|
||||
**卷积运算(Convolutional Operation)**是卷积神经网络最基本的组成部分。我们以边缘检测为例,来解释卷积是怎样运算的。
|
||||
|
||||
### 边缘检测
|
||||
|
||||
图片最常做的边缘检测有两类:**垂直边缘(Vertical Edges)检测**和**水平边缘(Horizontal Edges)检测**。
|
||||
|
||||

|
||||
|
||||
图片的边缘检测可以通过与相应滤波器进行卷积来实现。以垂直边缘检测为例,原始图片尺寸为 6x6,中间的矩阵被称作**滤波器(filter)**,尺寸为 3x3,卷积后得到的图片尺寸为 4x4,得到结果如下(数值表示灰度,以左上角和右下角的值为例):
|
||||
|
||||

|
||||
|
||||
可以看到,卷积运算的求解过程是从左到右,由上到下,每次在原始图片矩阵中取与滤波器同等大小的一部分,每一部分中的值与滤波器中的值对应相乘后求和,将结果组成一个矩阵。
|
||||
|
||||
下图对应一个垂直边缘检测的例子:
|
||||
|
||||

|
||||
|
||||
如果将最右边的矩阵当作图像,那么中间一段亮一些的区域对应最左边的图像中间的垂直边缘。
|
||||
|
||||
这里有另一个卷积运算的动态的例子,方便理解:
|
||||
|
||||

|
||||
|
||||
图中的`*`表示卷积运算符号。在计算机中这个符号表示一般的乘法,而在不同的深度学习框架中,卷积操作的 API 定义可能不同:
|
||||
|
||||
* 在 Python 中,卷积用`conv_forward()`表示;
|
||||
* 在 Tensorflow 中,卷积用`tf.nn.conv2d()`表示;
|
||||
* 在 keras 中,卷积用`Conv2D()`表示。
|
||||
|
||||
### 更多边缘检测的例子
|
||||
|
||||
如果将灰度图左右的颜色进行翻转,再与之前的滤波器进行卷积,得到的结果也有区别。实际应用中,这反映了由明变暗和由暗变明的两种渐变方式。可以对输出图片取绝对值操作,以得到同样的结果。
|
||||
|
||||

|
||||
|
||||
垂直边缘检测和水平边缘检测的滤波器如下所示:
|
||||
|
||||

|
||||
|
||||
其他常用的滤波器还有 Sobel 滤波器和 Scharr 滤波器。它们增加了中间行的权重,以提高结果的稳健性。
|
||||
|
||||

|
||||
|
||||
滤波器中的值还可以设置为**参数**,通过模型训练来得到。这样,神经网络使用反向传播算法可以学习到一些低级特征,从而实现对图片所有边缘特征的检测,而不仅限于垂直边缘和水平边缘。
|
||||
|
||||
## 填充
|
||||
|
||||
假设输入图片的大小为 $n \times n$,而滤波器的大小为 $f \times f$,则卷积后的输出图片大小为 $(n-f+1) \times (n-f+1)$。
|
||||
|
||||
这样就有两个问题:
|
||||
|
||||
* 每次卷积运算后,输出图片的尺寸缩小;
|
||||
* 原始图片的角落、边缘区像素点在输出中采用较少,输出图片丢失边缘位置的很多信息。
|
||||
|
||||
为了解决这些问题,可以在进行卷积操作前,对原始图片在边界上进行**填充(Padding)**,以增加矩阵的大小。通常将 0 作为填充值。
|
||||
|
||||

|
||||
|
||||
设每个方向扩展像素点数量为 $p$,则填充后原始图片的大小为 $(n+2p) \times (n+2p)$,滤波器大小保持 $f \times f$不变,则输出图片大小为 $(n+2p-f+1) \times (n+2p-f+1)$。
|
||||
|
||||
因此,在进行卷积运算时,我们有两种选择:
|
||||
|
||||
* **Valid 卷积**:不填充,直接卷积。结果大小为 $(n-f+1) \times (n-f+1)$;
|
||||
* **Same 卷积**:进行填充,并使得卷积后结果大小与输入一致,这样 $p = \frac{f-1}{2}$。
|
||||
|
||||
在计算机视觉领域,$f$通常为奇数。原因包括 Same 卷积中 $p = \frac{f-1}{2}$能得到自然数结果,并且滤波器有一个便于表示其所在位置的中心点。
|
||||
|
||||
## 卷积步长
|
||||
|
||||
卷积过程中,有时需要通过填充来避免信息损失,有时也需要通过设置**步长(Stride)**来压缩一部分信息。
|
||||
|
||||
步长表示滤波器在原始图片的水平方向和垂直方向上每次移动的距离。之前,步长被默认为 1。而如果我们设置步长为 2,则卷积过程如下图所示:
|
||||
|
||||

|
||||
|
||||
设步长为 $s$,填充长度为 $p$,输入图片大小为 $n \times n$,滤波器大小为 $f \times f$,则卷积后图片的尺寸为:
|
||||
|
||||
$$\biggl\lfloor \frac{n+2p-f}{s}+1 \biggr\rfloor \times \biggl\lfloor \frac{n+2p-f}{s}+1 \biggr\rfloor$$
|
||||
|
||||
注意公式中有一个向下取整的符号,用于处理商不为整数的情况。向下取整反映着当取原始矩阵的图示蓝框完全包括在图像内部时,才对它进行运算。
|
||||
|
||||
目前为止我们学习的“卷积”实际上被称为**互相关(cross-correlation)**,而非数学意义上的卷积。真正的卷积操作在做元素乘积求和之前,要将滤波器沿水平和垂直轴翻转(相当于旋转 180 度)。因为这种翻转对一般为水平或垂直对称的滤波器影响不大,按照机器学习的惯例,我们通常不进行翻转操作,在简化代码的同时使神经网络能够正常工作。
|
||||
|
||||
## 高维卷积
|
||||
|
||||
如果我们想要对三通道的 RGB 图片进行卷积运算,那么其对应的滤波器组也同样是三通道的。过程是将每个单通道(R,G,B)与对应的滤波器进行卷积运算求和,然后再将三个通道的和相加,将 27 个乘积的和作为输出图片的一个像素值。
|
||||
|
||||

|
||||
|
||||
不同通道的滤波器可以不相同。例如只检测 R 通道的垂直边缘,G 通道和 B 通道不进行边缘检测,则 G 通道和 B 通道的滤波器全部置零。当输入有特定的高、宽和通道数时,滤波器可以有不同的高和宽,但通道数必须和输入一致。
|
||||
|
||||
如果想同时检测垂直和水平边缘,或者更多的边缘检测,可以增加更多的滤波器组。例如设置第一个滤波器组实现垂直边缘检测,第二个滤波器组实现水平边缘检测。设输入图片的尺寸为 $n \times n \times n\_c$($n\_c$为通道数),滤波器尺寸为 $f \times f \times n\_c$,则卷积后的输出图片尺寸为 $(n-f+1) \times (n-f+1) \times n'\_c$,$n'\_c$为滤波器组的个数。
|
||||
|
||||

|
||||
|
||||
## 单层卷积网络
|
||||
|
||||

|
||||
|
||||
与之前的卷积过程相比较,卷积神经网络的单层结构多了激活函数和偏移量;而与标准神经网络:
|
||||
|
||||
$$Z^{[l]} = W^{[l]}A^{[l-1]}+b$$
|
||||
$$A^{[l]} = g^{[l]}(Z^{[l]})$$
|
||||
|
||||
相比,滤波器的数值对应着权重 $W^{[l]}$,卷积运算对应着 $W^{[l]}$与 $A^{[l-1]}$的乘积运算,所选的激活函数变为 ReLU。
|
||||
|
||||
对于一个 3x3x3 的滤波器,包括偏移量 $b$在内共有 28 个参数。不论输入的图片有多大,用这一个滤波器来提取特征时,参数始终都是 28 个,固定不变。即**选定滤波器组后,参数的数目与输入图片的尺寸无关**。因此,卷积神经网络的参数相较于标准神经网络来说要少得多。这是 CNN 的优点之一。
|
||||
|
||||
### 符号总结
|
||||
|
||||
设 $l$ 层为卷积层:
|
||||
|
||||
* $f^{[l]}$:**滤波器的高(或宽)**
|
||||
* $p^{[l]}$:**填充长度**
|
||||
* $s^{[l]}$:**步长**
|
||||
* $n^{[l]}\_c$:**滤波器组的数量**
|
||||
|
||||
* **输入维度**:$n^{[l-1]}\_H \times n^{[l-1]}\_W \times n^{[l-1]}\_c$ 。其中 $n^{[l-1]}\_H$表示输入图片的高,$n^{[l-1]}\_W$表示输入图片的宽。之前的示例中输入图片的高和宽都相同,但是实际中也可能不同,因此加上下标予以区分。
|
||||
|
||||
* **输出维度**:$n^{[l]}\_H \times n^{[l]}\_W \times n^{[l]}\_c$ 。其中
|
||||
|
||||
$$n^{[l]}\_H = \biggl\lfloor \frac{n^{[l-1]}\_H+2p^{[l]}-f^{[l]}}{s^{[l]}}+1 \biggr\rfloor$$
|
||||
|
||||
$$n^{[l]}\_W = \biggl\lfloor \frac{n^{[l-1]}\_W+2p^{[l]}-f^{[l]}}{s^{[l]}}+1 \biggr\rfloor$$
|
||||
|
||||
* **每个滤波器组的维度**:$f^{[l]} \times f^{[l]} \times n^{[l-1]}\_c$ 。其中$n^{[l-1]}\_c$ 为输入图片通道数(也称深度)。
|
||||
* **权重维度**:$f^{[l]} \times f^{[l]} \times n^{[l-1]}\_c \times n^{[l]}\_c$
|
||||
* **偏置维度**:$1 \times 1 \times 1 \times n^{[l]}\_c$
|
||||
|
||||
由于深度学习的相关文献并未对卷积标示法达成一致,因此不同的资料关于高度、宽度和通道数的顺序可能不同。有些作者会将通道数放在首位,需要根据标示自行分辨。
|
||||
|
||||
## 简单卷积网络示例
|
||||
|
||||
一个简单的 CNN 模型如下图所示:
|
||||
|
||||

|
||||
|
||||
其中,$a^{[3]}$的维度为 7x7x40,将 1960 个特征平滑展开成 1960 个单元的一列,然后连接最后一级的输出层。输出层可以是一个神经元,即二元分类(logistic);也可以是多个神经元,即多元分类(softmax)。最后得到预测输出 $\hat y$。
|
||||
|
||||
随着神经网络计算深度不断加深,图片的高度和宽度 $n^{[l]}\_H $、$n^{[l]}\_W$一般逐渐减小,而 $n^{[l]}\_c$在增加。
|
||||
|
||||
一个典型的卷积神经网络通常包含有三种层:**卷积层(Convolution layer)**、**池化层(Pooling layer)**、**全连接层(Fully Connected layer)**。仅用卷积层也有可能构建出很好的神经网络,但大部分神经网络还是会添加池化层和全连接层,它们更容易设计。
|
||||
|
||||
## 池化层
|
||||
|
||||
**池化层**的作用是缩减模型的大小,提高计算速度,同时减小噪声提高所提取特征的稳健性。
|
||||
|
||||
采用较多的一种池化过程叫做**最大池化(Max Pooling)**。将输入拆分成不同的区域,输出的每个元素都是对应区域中元素的最大值,如下图所示:
|
||||
|
||||

|
||||
|
||||
池化过程类似于卷积过程,上图所示的池化过程中相当于使用了一个大小 $f=2$的滤波器,且池化步长 $s=2$。卷积过程中的几个计算大小的公式也都适用于池化过程。如果有多个通道,那么就对每个通道分别执行计算过程。
|
||||
|
||||
对最大池化的一种直观解释是,元素值较大可能意味着池化过程之前的卷积过程提取到了某些特定的特征,池化过程中的最大化操作使得只要在一个区域内提取到某个特征,它都会保留在最大池化的输出中。但是,没有足够的证据证明这种直观解释的正确性,而最大池化被使用的主要原因是它在很多实验中的效果都很好。
|
||||
|
||||
另一种池化过程是**平均池化(Average Pooling)**,就是从取某个区域的最大值改为求这个区域的平均值:
|
||||
|
||||

|
||||
|
||||
池化过程的特点之一是,它有一组超参数,但是并**没有参数需要学习**。池化过程的超参数包括滤波器的大小 $f$、步长 $s$,以及选用最大池化还是平均池化。而填充 $p$则很少用到。
|
||||
|
||||
池化过程的输入维度为:
|
||||
|
||||
$$n\_H \times n\_W \times n\_c$$
|
||||
|
||||
输出维度为:
|
||||
|
||||
$$\biggl\lfloor \frac{n\_H-f}{s}+1 \biggr\rfloor \times \biggl\lfloor \frac{n\_W-f}{s}+1 \biggr\rfloor \times n\_c$$
|
||||
|
||||
## 卷积神经网络示例
|
||||
|
||||

|
||||
|
||||
在计算神经网络的层数时,通常只统计具有权重和参数的层,因此池化层通常和之前的卷积层共同计为一层。
|
||||
|
||||
图中的 FC3 和 FC4 为全连接层,与标准的神经网络结构一致。整个神经网络各层的尺寸与参数如下表所示:
|
||||
|
||||
| Activation shape | Activation Size | #parameters
|
||||
:-: | :-: | :-: | :-:
|
||||
**Input:** | (32, 32, 3) | 3072 | 0
|
||||
**CONV1(f=5, s=1)** | (28, 28, 6) | 4704 | 158
|
||||
**POOL1** | (14, 14, 6) | 1176 | 0
|
||||
**CONV2(f=5, s=1)** | (10, 10, 16) | 1600 | 416
|
||||
**POOL2** | (5, 5, 16) | 400 | 0
|
||||
**FC3** | (120, 1) | 120 | 48120
|
||||
**FC4** | (84, 1) | 84 | 10164
|
||||
**Softmax** | (10, 1) | 10 | 850
|
||||
|
||||
个人推荐[一个直观感受卷积神经网络的网站](http://scs.ryerson.ca/~aharley/vis/conv/)。
|
||||
|
||||
## 使用卷积的原因
|
||||
|
||||
相比标准神经网络,对于大量的输入数据,卷积过程有效地减少了 CNN 的参数数量,原因有以下两点:
|
||||
|
||||
* **参数共享(Parameter sharing)**:特征检测如果适用于图片的某个区域,那么它也可能适用于图片的其他区域。即在卷积过程中,不管输入有多大,一个特征探测器(滤波器)就能对整个输入的某一特征进行探测。
|
||||
* **稀疏连接(Sparsity of connections)**:在每一层中,由于滤波器的尺寸限制,输入和输出之间的连接是稀疏的,每个输出值只取决于输入在局部的一小部分值。
|
||||
|
||||
池化过程则在卷积后很好地聚合了特征,通过降维来减少运算量。
|
||||
|
||||
由于 CNN 参数数量较小,所需的训练样本就相对较少,因此在一定程度上不容易发生过拟合现象。并且 CNN 比较擅长捕捉区域位置偏移。即进行物体检测时,不太受物体在图片中位置的影响,增加检测的准确性和系统的健壮性。
|
||||
199
机器学习/吴恩达深度学习/学习笔记/Convolutional_Neural_Networks/深度卷积网络:实例探究.md
Normal file
@@ -0,0 +1,199 @@
|
||||
<h1 align="center">深度卷积网络:实例探究</h1>
|
||||
|
||||
讲到的经典 CNN 模型包括:
|
||||
|
||||
* LeNet-5
|
||||
* AlexNet
|
||||
* VGG
|
||||
|
||||
此外还有 ResNet(Residual Network,残差网络),以及 Inception Neural Network。
|
||||
|
||||
## 经典卷积网络
|
||||
|
||||
### LeNet-5
|
||||
|
||||

|
||||
|
||||
特点:
|
||||
|
||||
* LeNet-5 针对灰度图像而训练,因此输入图片的通道数为 1。
|
||||
* 该模型总共包含了约 6 万个参数,远少于标准神经网络所需。
|
||||
* 典型的 LeNet-5 结构包含卷积层(CONV layer),池化层(POOL layer)和全连接层(FC layer),排列顺序一般为 CONV layer->POOL layer->CONV layer->POOL layer->FC layer->FC layer->OUTPUT layer。一个或多个卷积层后面跟着一个池化层的模式至今仍十分常用。
|
||||
* 当 LeNet-5模型被提出时,其池化层使用的是平均池化,而且各层激活函数一般选用 Sigmoid 和 tanh。现在,我们可以根据需要,做出改进,使用最大池化并选用 ReLU 作为激活函数。
|
||||
|
||||
相关论文:[LeCun et.al., 1998. Gradient-based learning applied to document recognition](http://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=726791&tag=1)。吴恩达老师建议精读第二段,泛读第三段。
|
||||
|
||||
### AlexNet
|
||||
|
||||

|
||||
|
||||
特点:
|
||||
|
||||
* AlexNet 模型与 LeNet-5 模型类似,但是更复杂,包含约 6000 万个参数。另外,AlexNet 模型使用了 ReLU 函数。
|
||||
* 当用于训练图像和数据集时,AlexNet 能够处理非常相似的基本构造模块,这些模块往往包含大量的隐藏单元或数据。
|
||||
|
||||
相关论文:[Krizhevsky et al.,2012. ImageNet classification with deep convolutional neural networks](http://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks.pdf)。这是一篇易于理解并且影响巨大的论文,计算机视觉群体自此开始重视深度学习。
|
||||
|
||||
### VGG
|
||||
|
||||

|
||||
|
||||
特点:
|
||||
|
||||
* VGG 又称 VGG-16 网络,“16”指网络中包含 16 个卷积层和全连接层。
|
||||
* 超参数较少,只需要专注于构建卷积层。
|
||||
* 结构不复杂且规整,在每一组卷积层进行滤波器翻倍操作。
|
||||
* VGG 需要训练的特征数量巨大,包含多达约 1.38 亿个参数。
|
||||
|
||||
相关论文:[Simonvan & Zisserman 2015. Very deep convolutional networks for large-scale image recognition](https://arxiv.org/pdf/1409.1556.pdf)。
|
||||
|
||||
## 残差网络
|
||||
|
||||
因为存在梯度消失和梯度爆炸问题,网络越深,就越难以训练成功。**残差网络(Residual Networks,简称为 ResNets)**可以有效解决这个问题。
|
||||
|
||||

|
||||
|
||||
上图的结构被称为**残差块(Residual block)**。通过**捷径(Short cut,或者称跳远连接,Skip connections)**可以将 $a^{[l]}$添加到第二个 ReLU 过程中,直接建立 $a^{[l]}$与 $a^{[l+2]}$之间的隔层联系。表达式如下:
|
||||
|
||||
$$z^{[l+1]} = W^{[l+1]}a^{[l]} + b^{[l+1]}$$
|
||||
|
||||
$$a^{[l+1]} = g(z^{[l+1]})$$
|
||||
|
||||
$$z^{[l+2]} = W^{[l+2]}a^{[l+1]} + b^{[l+2]}$$
|
||||
|
||||
$$a^{[l+2]} = g(z^{[l+2]} + a^{[l]})$$
|
||||
|
||||
构建一个残差网络就是将许多残差块堆积在一起,形成一个深度网络。
|
||||
|
||||

|
||||
|
||||
为了便于区分,在 ResNets 的论文[He et al., 2015. Deep residual networks for image recognition](https://arxiv.org/pdf/1512.03385.pdf)中,非残差网络被称为**普通网络(Plain Network)**。将它变为残差网络的方法是加上所有的跳远连接。
|
||||
|
||||
在理论上,随着网络深度的增加,性能应该越来越好。但实际上,对于一个普通网络,随着神经网络层数增加,训练错误会先减少,然后开始增多。但残差网络的训练效果显示,即使网络再深,其在训练集上的表现也会越来越好。
|
||||
|
||||

|
||||
|
||||
残差网络有助于解决梯度消失和梯度爆炸问题,使得在训练更深的网络的同时,又能保证良好的性能。
|
||||
|
||||
### 残差网络有效的原因
|
||||
|
||||
假设有一个大型神经网络,其输入为 $X$,输出为 $a^{[l]}$。给这个神经网络额外增加两层,输出为 $a^{[l+2]}$。将这两层看作一个具有跳远连接的残差块。为了方便说明,假设整个网络中都选用 ReLU 作为激活函数,因此输出的所有激活值都大于等于 0。
|
||||
|
||||

|
||||
|
||||
则有:
|
||||
|
||||
$$
|
||||
\begin{equation}
|
||||
\begin{split}
|
||||
a^{[l+2]} &= g(z^{[l+2]}+a^{[l]})
|
||||
\\\ &= g(W^{[l+2]}a^{[l+1]}+b^{[l+2]}+a^{[l]})
|
||||
\end{split}
|
||||
\end{equation}
|
||||
$$
|
||||
|
||||
当发生梯度消失时,$W^{[l+2]}\approx0$,$b^{[l+2]}\approx0$,则有:
|
||||
|
||||
$$a^{[l+2]} = g(a^{[l]}) = ReLU(a^{[l]}) = a^{[l]}$$
|
||||
|
||||
因此,这两层额外的残差块不会降低网络性能。而如果没有发生梯度消失时,训练得到的非线性关系会使得表现效果进一步提高。
|
||||
|
||||
注意,如果 $a^{[l]}$与 $a^{[l+2]}$的维度不同,需要引入矩阵 $W\_s$与 $a^{[l]}$相乘,使得二者的维度相匹配。参数矩阵 $W\_s$既可以通过模型训练得到,也可以作为固定值,仅使 $a^{[l]}$截断或者补零。
|
||||
|
||||

|
||||
|
||||
上图是论文提供的 CNN 中 ResNet 的一个典型结构。卷积层通常使用 Same 卷积以保持维度相同,而不同类型层之间的连接(例如卷积层和池化层),如果维度不同,则需要引入矩阵 $W\_s$。
|
||||
|
||||
## 1x1 卷积
|
||||
|
||||
1x1 卷积(1x1 convolution,或称为 Network in Network)指滤波器的尺寸为 1。当通道数为 1 时,1x1 卷积意味着卷积操作等同于乘积操作。
|
||||
|
||||

|
||||
|
||||
而当通道数更多时,1x1 卷积的作用实际上类似全连接层的神经网络结构,从而降低(或升高,取决于滤波器组数)数据的维度。
|
||||
|
||||
池化能压缩数据的高度($n\_H$)及宽度($n\_W$),而 1×1 卷积能压缩数据的通道数($n\_C$)。在如下图所示的例子中,用 32 个大小为 1×1×192 的滤波器进行卷积,就能使原先数据包含的 192 个通道压缩为 32 个。
|
||||
|
||||

|
||||
|
||||
虽然论文[Lin et al., 2013. Network in network](https://arxiv.org/pdf/1312.4400.pdf)中关于架构的详细内容并没有得到广泛应用,但是 1x1 卷积的理念十分有影响力,许多神经网络架构(包括 Inception 网络)都受到它的影响。
|
||||
|
||||
## Inception 网络
|
||||
|
||||
在之前的卷积网络中,我们只能选择单一尺寸和类型的滤波器。而 **Inception 网络的作用**即是代替人工来确定卷积层中的滤波器尺寸与类型,或者确定是否需要创建卷积层或池化层。
|
||||
|
||||

|
||||
|
||||
如图,Inception 网络选用不同尺寸的滤波器进行 Same 卷积,并将卷积和池化得到的输出组合拼接起来,最终让网络自己去学习需要的参数和采用的滤波器组合。
|
||||
|
||||
相关论文:[Szegedy et al., 2014, Going Deeper with Convolutions](https://arxiv.org/pdf/1409.4842.pdf)
|
||||
|
||||
### 计算成本问题
|
||||
|
||||
在提升性能的同时,Inception 网络有着较大的计算成本。下图是一个例子:
|
||||
|
||||

|
||||
|
||||
图中有 32 个滤波器,每个滤波器的大小为 5x5x192。输出大小为 28x28x32,所以需要计算 28x28x32 个数字,对于每个数,都要执行 5x5x192 次乘法运算。加法运算次数与乘法运算次数近似相等。因此,可以看作这一层的计算量为 28x28x32x5x5x192 = 1.2亿。
|
||||
|
||||
为了解决计算量大的问题,可以引入 1x1 卷积来减少其计算量。
|
||||
|
||||

|
||||
|
||||
对于同一个例子,我们使用 1x1 卷积把输入数据从 192 个通道减少到 16 个通道,然后对这个较小层运行 5x5 卷积,得到最终输出。这个 1x1 的卷积层通常被称作**瓶颈层(Bottleneck layer)**。
|
||||
|
||||
改进后的计算量为 28x28x192x16 + 28x28x32x5x5x15 = 1.24 千万,减少了约 90%。
|
||||
|
||||
只要合理构建瓶颈层,就可以既显著缩小计算规模,又不会降低网络性能。
|
||||
|
||||
### 完整的 Inception 网络
|
||||
|
||||

|
||||
|
||||
上图是引入 1x1 卷积后的 Inception 模块。值得注意的是,为了将所有的输出组合起来,红色的池化层使用 Same 类型的填充(padding)来池化使得输出的宽高不变,通道数也不变。
|
||||
|
||||
多个 Inception 模块组成一个完整的 Inception 网络(被称为 GoogLeNet,以向 LeNet 致敬),如下图所示:
|
||||
|
||||

|
||||
|
||||
注意黑色椭圆圈出的隐藏层,这些分支都是 Softmax 的输出层,可以用来参与特征的计算及结果预测,起到调整并防止发生过拟合的效果。
|
||||
|
||||
经过研究者们的不断发展,Inception 模型的 V2、V3、V4 以及引入残差网络的版本被提出,这些变体都基于 Inception V1 版本的基础思想上。顺便一提,Inception 模型的名字来自电影《盗梦空间》。
|
||||
|
||||
## 使用开源的实现方案
|
||||
|
||||
很多神经网络复杂细致,并充斥着参数调节的细节问题,因而很难仅通过阅读论文来重现他人的成果。想要搭建一个同样的神经网络,查看开源的实现方案会快很多。
|
||||
|
||||
## 迁移学习
|
||||
|
||||
在“搭建机器学习项目”课程中,[迁移学习](http://kyonhuang.top/Andrew-Ng-Deep-Learning-notes/#/Structuring_Machine_Learning_Projects/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%EF%BC%88ML%EF%BC%89%E7%AD%96%E7%95%A5%EF%BC%882%EF%BC%89?id=%e8%bf%81%e7%a7%bb%e5%ad%a6%e4%b9%a0)已经被提到过。计算机视觉是一个经常用到迁移学习的领域。在搭建计算机视觉的应用时,相比于从头训练权重,下载别人已经训练好的网络结构的权重,用其做**预训练**,然后转换到自己感兴趣的任务上,有助于加速开发。
|
||||
|
||||
对于已训练好的卷积神经网络,可以将所有层都看作是**冻结的**,只需要训练与你的 Softmax 层有关的参数即可。大多数深度学习框架都允许用户指定是否训练特定层的权重。
|
||||
|
||||
而冻结的层由于不需要改变和训练,可以看作一个固定函数。可以将这个固定函数存入硬盘,以便后续使用,而不必每次再使用训练集进行训练了。
|
||||
|
||||
上述的做法适用于你只有一个较小的数据集。如果你有一个更大的数据集,应该冻结更少的层,然后训练后面的层。越多的数据意味着冻结越少的层,训练更多的层。如果有一个极大的数据集,你可以将开源的网络和它的权重整个当作初始化(代替随机初始化),然后训练整个网络。
|
||||
|
||||
## 数据扩增
|
||||
|
||||
计算机视觉领域的应用都需要大量的数据。当数据不够时,**数据扩增(Data Augmentation)**就有帮助。常用的数据扩增包括镜像翻转、随机裁剪、色彩转换。
|
||||
|
||||
其中,色彩转换是对图片的 RGB 通道数值进行随意增加或者减少,改变图片色调。另外,**PCA 颜色增强**指更有针对性地对图片的 RGB 通道进行主成分分析(Principles Components Analysis,PCA),对主要的通道颜色进行增加或减少,可以采用高斯扰动做法来增加有效的样本数量。具体的 PCA 颜色增强做法可以查阅 AlexNet 的相关论文或者开源代码。
|
||||
|
||||
在构建大型神经网络的时候,数据扩增和模型训练可以由两个或多个不同的线程并行来实现。
|
||||
|
||||
## 计算机视觉现状
|
||||
|
||||
通常,学习算法有两种知识来源:
|
||||
|
||||
* 被标记的数据
|
||||
* 手工工程
|
||||
|
||||
**手工工程(Hand-engineering,又称 hacks)**指精心设计的特性、网络体系结构或是系统的其他组件。手工工程是一项非常重要也比较困难的工作。在数据量不多的情况下,手工工程是获得良好表现的最佳方式。正因为数据量不能满足需要,历史上计算机视觉领域更多地依赖于手工工程。近几年数据量急剧增加,因此手工工程量大幅减少。
|
||||
|
||||
另外,在模型研究或者竞赛方面,有一些方法能够有助于提升神经网络模型的性能:
|
||||
|
||||
* 集成(Ensembling):独立地训练几个神经网络,并平均输出它们的输出
|
||||
* Multi-crop at test time:将数据扩增应用到测试集,对结果进行平均
|
||||
|
||||
但是由于这些方法计算和内存成本较大,一般不适用于构建实际的生产项目。
|
||||
@@ -0,0 +1,168 @@
|
||||
<h1 align="center">特殊应用:人脸识别和神经风格转换</h1>
|
||||
|
||||
## 人脸识别
|
||||
|
||||
**人脸验证(Face Verification)**和**人脸识别(Face Recognition)**的区别:
|
||||
|
||||
* 人脸验证:一般指一个一对一问题,只需要验证输入的人脸图像是否与某个已知的身份信息对应;
|
||||
* 人脸识别:一个更为复杂的一对多问题,需要验证输入的人脸图像是否与多个已知身份信息中的某一个匹配。
|
||||
|
||||
一般来说,由于需要匹配的身份信息更多导致错误率增加,人脸识别比人脸验证更难一些。
|
||||
|
||||
### One-Shot 学习
|
||||
|
||||
人脸识别所面临的一个挑战是要求系统只采集某人的一个面部样本,就能快速准确地识别出这个人,即只用一个训练样本来获得准确的预测结果。这被称为**One-Shot 学习**。
|
||||
|
||||
有一种方法是假设数据库中存有 N 个人的身份信息,对于每张输入图像,用 Softmax 输出 N+1 种标签,分别对应每个人以及都不是。然而这种方法的实际效果很差,因为过小的训练集不足以训练出一个稳健的神经网络;并且如果有新的身份信息入库,需要重新训练神经网络,不够灵活。
|
||||
|
||||
因此,我们通过学习一个 Similarity 函数来实现 One-Shot 学习过程。Similarity 函数定义了输入的两幅图像的差异度,其公式如下:
|
||||
|
||||
$$Similarity = d(img1, img2)$$
|
||||
|
||||
可以设置一个超参数 $τ$ 作为阈值,作为判断两幅图片是否为同一个人的依据。
|
||||
|
||||
### Siamese 网络
|
||||
|
||||
实现 Similarity 函数的一种方式是使用**Siamese 网络**,它是一种对两个不同输入运行相同的卷积网络,然后对它们的结果进行比较的神经网络。
|
||||
|
||||

|
||||
|
||||
如上图示例,将图片 $x^{(1)}$、$x^{(2)}$ 分别输入两个相同的卷积网络中,经过全连接层后不再进行 Softmax,而是得到特征向量 $f(x^{(1)})$、$f(x^{(2)})$。这时,Similarity 函数就被定义为两个特征向量之差的 L2 范数:
|
||||
|
||||
$$d(x^{(1)}, x^{(2)}) = ||f(x^{(1)}) - f(x^{(2)})||^2\_2$$
|
||||
|
||||
相关论文:[Taigman et al., 2014, DeepFace closing the gap to human level performance](http://www.cs.wayne.edu/~mdong/taigman_cvpr14.pdf)
|
||||
|
||||
### Triplet 损失
|
||||
|
||||
**Triplet 损失函数**用于训练出合适的参数,以获得高质量的人脸图像编码。“Triplet”一词来源于训练这个神经网络需要大量包含 Anchor(靶目标)、Positive(正例)、Negative(反例)的图片组,其中 Anchor 和 Positive 需要是同一个人的人脸图像。
|
||||
|
||||

|
||||
|
||||
对于这三张图片,应该有:
|
||||
|
||||
$$||f(A) - f(P)||^2\_2 + \alpha \le ||f(A) - f(N)||^2\_2$$
|
||||
|
||||
其中,$\alpha$ 被称为**间隔(margin)**,用于确保 $f()$ 不会总是输出零向量(或者一个恒定的值)。
|
||||
|
||||
Triplet 损失函数的定义:
|
||||
|
||||
$$L(A, P, N) = max(||f(A) - f(P)||^2\_2 - ||f(A) - f(N)||^2\_2 + \alpha, 0)$$
|
||||
|
||||
其中,因为 $||f(A) - f(P)||^2\_2 - ||f(A) - f(N)||^2\_2 + \alpha$ 的值需要小于等于 0,因此取它和 0 的更大值。
|
||||
|
||||
对于大小为 $m$ 的训练集,代价函数为:
|
||||
|
||||
$$J = \sum^m\_{i=1}L(A^{(i)}, P^{(i)}, N^{(i)})$$
|
||||
|
||||
通过梯度下降最小化代价函数。
|
||||
|
||||
在选择训练样本时,随机选择容易使 Anchor 和 Positive 极为接近,而 Anchor 和 Negative 相差较大,以致训练出来的模型容易抓不到关键的区别。因此,最好的做法是人为增加 Anchor 和 Positive 的区别,缩小 Anchor 和 Negative 的区别,促使模型去学习不同人脸之间的关键差异。
|
||||
|
||||
相关论文:[Schroff et al., 2015, FaceNet: A unified embedding for face recognition and clustering](https://arxiv.org/pdf/1503.03832.pdf)
|
||||
|
||||
### 二分类结构
|
||||
|
||||
除了 Triplet 损失函数,二分类结构也可用于学习参数以解决人脸识别问题。其做法是输入一对图片,将两个 Siamese 网络产生的特征向量输入至同一个 Sigmoid 单元,输出 1 则表示是识别为同一人,输出 0 则表示识别为不同的人。
|
||||
|
||||
Sigmoid 单元对应的表达式为:
|
||||
|
||||
$$\hat y = \sigma (\sum^K\_{k=1}w\_k|f(x^{(i)})\_{k} - x^{(j)})\_{k}| + b)$$
|
||||
|
||||
其中,$w\_k$ 和 $b$ 都是通过梯度下降算法迭代训练得到的参数。上述计算表达式也可以用另一种表达式代替:
|
||||
|
||||
$$\hat y = \sigma (\sum^K\_{k=1}w\_k
|
||||
\frac{(f(x^{(i)})\_k - f(x^{(j)})\_k)^2}{f(x^{(i)})\_k + f(x^{(j)})\_k} + b)$$
|
||||
|
||||
其中,$\frac{(f(x^{(i)})\_k - f(x^{(j)})\_k)^2}{f(x^{(i)})\_k + f(x^{(j)})\_k}$ 被称为 $\chi$ 方相似度。
|
||||
|
||||
无论是对于使用 Triplet 损失函数的网络,还是二分类结构,为了减少计算量,可以提前计算好编码输出 $f(x)$ 并保存。这样就不必存储原始图片,并且每次进行人脸识别时只需要计算测试图片的编码输出。
|
||||
|
||||
## 神经风格迁移
|
||||
|
||||
**神经风格迁移(Neural style transfer)**将参考风格图像的风格“迁移”到另外一张内容图像中,生成具有其特色的图像。
|
||||
|
||||

|
||||
|
||||
### 深度卷积网络在学什么?
|
||||
|
||||
想要理解如何实现神经风格转换,首先要理解在输入图像数据后,一个深度卷积网络从中都学到了些什么。我们借助可视化来做到这一点。
|
||||
|
||||

|
||||
|
||||
我们通过遍历所有的训练样本,找出使该层激活函数输出最大的 9 块图像区域。可以看出,浅层的隐藏层通常检测出的是原始图像的边缘、颜色、阴影等简单信息。随着层数的增加,隐藏单元能捕捉的区域更大,学习到的特征也由从边缘到纹理再到具体物体,变得更加复杂。
|
||||
|
||||
相关论文:[Zeiler and Fergus., 2013, Visualizing and understanding convolutional networks](https://arxiv.org/pdf/1311.2901.pdf)
|
||||
|
||||
### 代价函数
|
||||
|
||||
神经风格迁移生成图片 G 的代价函数如下:
|
||||
|
||||
$$J(G) = \alpha \cdot J\_{content}(C, G) + \beta \cdot J\_{style}(S, G)$$
|
||||
|
||||
其中,$\alpha$、$\beta$ 是用于控制相似度比重的超参数。
|
||||
|
||||
神经风格迁移的算法步骤如下:
|
||||
|
||||
1. 随机生成图片 G 的所有像素点;
|
||||
2. 使用梯度下降算法使代价函数最小化,以不断修正 G 的所有像素点。
|
||||
|
||||
相关论文:[Gatys al., 2015. A neural algorithm of artistic style](https://arxiv.org/pdf/1508.06576v2.pdf)
|
||||
|
||||
#### 内容代价函数
|
||||
|
||||
上述代价函数包含一个内容代价部分和风格代价部分。我们先来讨论内容代价函数 $J\_{content}(C, G)$,它表示内容图片 C 和生成图片 G 之间的相似度。
|
||||
|
||||
$J\_{content}(C, G)$ 的计算过程如下:
|
||||
|
||||
* 使用一个预训练好的 CNN(例如 VGG);
|
||||
* 选择一个隐藏层 $l$ 来计算内容代价。$l$ 太小则内容图片和生成图片像素级别相似,$l$ 太大则可能只有具体物体级别的相似。因此,$l$ 一般选一个中间层;
|
||||
* 设 $a^{(C)[l]}$、$a^{(G)[l]}$ 为 C 和 G 在 $l$ 层的激活,则有:
|
||||
|
||||
$$J\_{content}(C, G) = \frac{1}{2}||(a^{(C)[l]} - a^{(G)[l]})||^2$$
|
||||
|
||||
$a^{(C)[l]}$ 和 $a^{(G)[l]}$ 越相似,则 $J\_{content}(C, G)$ 越小。
|
||||
|
||||
#### 风格代价函数
|
||||
|
||||

|
||||
|
||||
每个通道提取图片的特征不同,比如标为红色的通道提取的是图片的垂直纹理特征,标为黄色的通道提取的是图片的橙色背景特征。那么计算这两个通道的相关性,相关性的大小,即表示原始图片既包含了垂直纹理也包含了该橙色背景的可能性大小。通过 CNN,“风格”被定义为同一个隐藏层不同通道之间激活值的相关系数,因其反映了原始图片特征间的相互关系。
|
||||
|
||||
对于风格图像 S,选定网络中的第 $l$ 层,则相关系数以一个 gram 矩阵的形式表示:
|
||||
|
||||
$$G^{\[l](S)}\_{kk'} = \sum^{n^{[l]}\_H}\_{i=1} \sum^{n^{[l]}\_W}\_{j=1} a^{\[l](S)}\_{ijk} a^{\[l](S)}\_{ijk'}$$
|
||||
|
||||
其中,$i$ 和 $j$ 为第 $l$ 层的高度和宽度;$k$ 和 $k'$ 为选定的通道,其范围为 $1$ 到 $n\_C^{[l]}$;$a^{\[l](S)}\_{ijk}$ 为激活。
|
||||
|
||||
同理,对于生成图像 G,有:
|
||||
|
||||
$$G^{\[l](G)}\_{kk'} = \sum^{n^{[l]}\_H}\_{i=1} \sum^{n^{[l]}\_W}\_{j=1} a^{\[l](G)}\_{ijk} a^{\[l](G)}\_{ijk'}$$
|
||||
|
||||
因此,第 $l$ 层的风格代价函数为:
|
||||
|
||||
$$J^{[l]}\_{style}(S, G) = \frac{1}{(2n^{[l]}\_Hn^{[l]}\_Wn^{[l]}\_C)^2} \sum\_k \sum\_{k'}(G^{\[l](S)}\_{kk'} - G^{\[l](G)}\_{kk'})^2$$
|
||||
|
||||
如果对各层都使用风格代价函数,效果会更好。因此有:
|
||||
|
||||
$$J\_{style}(S, G) = \sum\_l \lambda^{[l]} J^{[l]}\_{style}(S, G)$$
|
||||
|
||||
其中,$lambda$ 是用于设置不同层所占权重的超参数。
|
||||
|
||||
### 推广至一维和三维
|
||||
|
||||
之前我们处理的都是二维图片,实际上卷积也可以延伸到一维和三维数据。我们举两个示例来说明。
|
||||
|
||||

|
||||
|
||||
EKG 数据(心电图)是由时间序列对应的每个瞬间的电压组成,是一维数据。一般来说我们会用 RNN(循环神经网络)来处理,不过如果用卷积处理,则有:
|
||||
|
||||
* 输入时间序列维度:14 x 1
|
||||
* 滤波器尺寸:5 x 1,滤波器个数:16
|
||||
* 输出时间序列维度:10 x 16
|
||||
|
||||
而对于三维图片的示例,有
|
||||
|
||||
* 输入 3D 图片维度:14 x 14 x 14 x 1
|
||||
* 滤波器尺寸:5 x 5 x 5 x 1,滤波器个数:16
|
||||
* 输出 3D 图片维度:10 x 10 x 10 x 16
|
||||
145
机器学习/吴恩达深度学习/学习笔记/Convolutional_Neural_Networks/目标检测.md
Normal file
@@ -0,0 +1,145 @@
|
||||
<h1 align="center">目标检测</h1>
|
||||
|
||||
目标检测是计算机视觉领域中一个新兴的应用方向,其任务是对输入图像进行分类的同时,检测图像中是否包含某些目标,并对他们准确定位并标识。
|
||||
|
||||
## 目标定位
|
||||
|
||||
定位分类问题不仅要求判断出图片中物体的种类,还要在图片中标记出它的具体位置,用**边框(Bounding Box,或者称包围盒)**把物体圈起来。一般来说,定位分类问题通常只有一个较大的对象位于图片中间位置;而在目标检测问题中,图片可以含有多个对象,甚至单张图片中会有多个不同分类的对象。
|
||||
|
||||
为了定位图片中汽车的位置,可以让神经网络多输出 4 个数字,标记为 $b\_x$、$b\_y$、$b\_h$、$b\_w$。将图片左上角标记为 (0, 0),右下角标记为 (1, 1),则有:
|
||||
|
||||
* 红色方框的中心点:($b\_x$,$b\_y$)
|
||||
* 边界框的高度:$b\_h$
|
||||
* 边界框的宽度:$b\_w$
|
||||
|
||||
因此,训练集不仅包含对象分类标签,还包含表示边界框的四个数字。定义目标标签 Y 如下:
|
||||
|
||||
$$\left[\begin{matrix}P\_c\\\ b\_x\\\ b\_y\\\ b\_h\\\ b\_w\\\ c\_1\\\ c\_2\\\ c\_3\end{matrix}\right]$$
|
||||
|
||||
则有:
|
||||
|
||||
$$P\_c=1, Y = \left[\begin{matrix}1\\\ b\_x\\\ b\_y\\\ b\_h\\\ b\_w\\\ c\_1\\\ c\_2\\\ c\_3\end{matrix}\right]
|
||||
$$
|
||||
|
||||
其中,$c\_n$表示存在第 $n$个种类的概率;如果 $P\_c=0$,表示没有检测到目标,则输出标签后面的 7 个参数都是无效的,可以忽略(用 ? 来表示)。
|
||||
|
||||
$$P\_c=0, Y = \left[\begin{matrix}0\\\ ?\\\ ?\\\ ?\\\ ?\\\ ?\\\ ?\\\ ?\end{matrix}\right]$$
|
||||
|
||||
损失函数可以表示为 $L(\hat y, y)$,如果使用平方误差形式,对于不同的 $P\_c$有不同的损失函数(注意下标 $i$指标签的第 $i$个值):
|
||||
|
||||
1. $P\_c=1$,即$y\_1=1$:
|
||||
|
||||
$L(\hat y,y)=(\hat y\_1-y\_1)^2+(\hat y\_2-y\_2)^2+\cdots+(\hat y\_8-y\_8)^2$
|
||||
|
||||
2. $P\_c=0$,即$y\_1=0$:
|
||||
|
||||
$L(\hat y,y)=(\hat y\_1-y\_1)^2$
|
||||
|
||||
除了使用平方误差,也可以使用逻辑回归损失函数,类标签 $c\_1,c\_2,c\_3$ 也可以通过 softmax 输出。相比较而言,平方误差已经能够取得比较好的效果。
|
||||
|
||||
## 特征点检测
|
||||
|
||||
神经网络可以像标识目标的中心点位置那样,通过输出图片上的特征点,来实现对目标特征的识别。在标签中,这些特征点以多个二维坐标的形式表示。
|
||||
|
||||
通过检测人脸特征点可以进行情绪分类与判断,或者应用于 AR 领域等等。也可以透过检测姿态特征点来进行人体姿态检测。
|
||||
|
||||
## 目标检测
|
||||
|
||||
想要实现目标检测,可以采用**基于滑动窗口的目标检测(Sliding Windows Detection)**算法。该算法的步骤如下:
|
||||
|
||||
1. 训练集上搜集相应的各种目标图片和非目标图片,样本图片要求尺寸较小,相应目标居于图片中心位置并基本占据整张图片。
|
||||
2. 使用训练集构建 CNN 模型,使得模型有较高的识别率。
|
||||
3. 选择大小适宜的窗口与合适的固定步幅,对测试图片进行从左到右、从上倒下的滑动遍历。每个窗口区域使用已经训练好的 CNN 模型进行识别判断。
|
||||
4. 可以选择更大的窗口,然后重复第三步的操作。
|
||||
|
||||

|
||||
|
||||
滑动窗口目标检测的**优点**是原理简单,且不需要人为选定目标区域;**缺点**是需要人为直观设定滑动窗口的大小和步幅。滑动窗口过小或过大,步幅过大均会降低目标检测的正确率。另外,每次滑动都要进行一次 CNN 网络计算,如果滑动窗口和步幅较小,计算成本往往很大。
|
||||
|
||||
所以,滑动窗口目标检测算法虽然简单,但是性能不佳,效率较低。
|
||||
|
||||
## 基于卷积的滑动窗口实现
|
||||
|
||||
相比从较大图片多次截取,在卷积层上应用滑动窗口目标检测算法可以提高运行速度。所要做的仅是将全连接层换成卷积层,即使用与上一层尺寸一致的滤波器进行卷积运算。
|
||||
|
||||

|
||||
|
||||
如图,对于 16x16x3 的图片,步长为 2,CNN 网络得到的输出层为 2x2x4。其中,2x2 表示共有 4 个窗口结果。对于更复杂的 28x28x3 的图片,得到的输出层为 8x8x4,共 64 个窗口结果。最大池化层的宽高和步长相等。
|
||||
|
||||
运行速度提高的原理:在滑动窗口的过程中,需要重复进行 CNN 正向计算。因此,不需要将输入图片分割成多个子集,分别执行向前传播,而是将它们作为一张图片输入给卷积网络进行一次 CNN 正向计算。这样,公共区域的计算可以共享,以降低运算成本。
|
||||
|
||||
相关论文:[Sermanet et al., 2014. OverFeat: Integrated Recognition, Localization and Detection using Convolutional Networks](https://arxiv.org/pdf/1312.6229.pdf)
|
||||
|
||||
## 边框预测
|
||||
|
||||
在上述算法中,边框的位置可能无法完美覆盖目标,或者大小不合适,或者最准确的边框并非正方形,而是长方形。
|
||||
|
||||
**YOLO(You Only Look Once)算法**可以用于得到更精确的边框。YOLO 算法将原始图片划分为 n×n 网格,并将[目标定位](http://kyonhuang.top/Andrew-Ng-Deep-Learning-notes/#/Convolutional_Neural_Networks/%E7%9B%AE%E6%A0%87%E6%A3%80%E6%B5%8B?id=%e7%9b%ae%e6%a0%87%e5%ae%9a%e4%bd%8d)一节中提到的图像分类和目标定位算法,逐一应用在每个网格中,每个网格都有标签如:
|
||||
|
||||
$$\left[\begin{matrix}P\_c\\\ b\_x\\\ b\_y\\\ b\_h\\\ b\_w\\\ c\_1\\\ c\_2\\\ c\_3\end{matrix}\right]$$
|
||||
|
||||
若某个目标的中点落在某个网格,则该网格负责检测该对象。
|
||||
|
||||

|
||||
|
||||
如上面的示例中,如果将输入的图片划分为 3×3 的网格、需要检测的目标有 3 类,则每一网格部分图片的标签会是一个 8 维的列矩阵,最终输出的就是大小为 3×3×8 的结果。要得到这个结果,就要训练一个输入大小为 100×100×3,输出大小为 3×3×8 的 CNN。在实践中,可能使用更为精细的 19×19 网格,则两个目标的中点在同一个网格的概率更小。
|
||||
|
||||
YOLO 算法的优点:
|
||||
|
||||
1. 和图像分类和目标定位算法类似,显式输出边框坐标和大小,不会受到滑窗分类器的步长大小限制。
|
||||
2. 仍然只进行一次 CNN 正向计算,效率很高,甚至可以达到实时识别。
|
||||
|
||||
如何编码边框 $b\_x$、$b\_y$、$b\_h$、$b\_w$?YOLO 算法设 $b\_x$、$b\_y$、$b\_h$、$b\_w$ 的值是相对于网格长的比例。则 $b\_x$、$b\_y$ 在 0 到 1 之间,而 $b\_h$、$b\_w$ 可以大于 1。当然,也有其他参数化的形式,且效果可能更好。这里只是给出一个通用的表示方法。
|
||||
|
||||
相关论文:[Redmon et al., 2015. You Only Look Once: Unified, Real-Time Object Detection](https://arxiv.org/pdf/1506.02640.pdf)。Ng 认为该论文较难理解。
|
||||
|
||||
## 交互比
|
||||
|
||||
**交互比(IoU, Intersection Over Union)**函数用于评价对象检测算法,它计算预测边框和实际边框交集(I)与并集(U)之比:
|
||||
|
||||
$$IoU = \frac{I}{U}$$
|
||||
|
||||
IoU 的值在 0~1 之间,且越接近 1 表示目标的定位越准确。IoU 大于等于 0.5 时,一般可以认为预测边框是正确的,当然也可以更加严格地要求一个更高的阈值。
|
||||
|
||||
## 非极大值抑制
|
||||
|
||||
YOLO 算法中,可能有很多网格检测到同一目标。**非极大值抑制(Non-max Suppression)**会通过清理检测结果,找到每个目标中点所位于的网格,确保算法对每个目标只检测一次。
|
||||
|
||||
进行非极大值抑制的步骤如下:
|
||||
|
||||
1. 将包含目标中心坐标的可信度 $P\_c$ 小于阈值(例如 0.6)的网格丢弃;
|
||||
2. 选取拥有最大 $P\_c$ 的网格;
|
||||
3. 分别计算该网格和其他所有网格的 IoU,将 IoU 超过预设阈值的网格丢弃;
|
||||
4. 重复第 2~3 步,直到不存在未处理的网格。
|
||||
|
||||
上述步骤适用于单类别目标检测。进行多个类别目标检测时,对于每个类别,应该单独做一次非极大值抑制。
|
||||
|
||||
## Anchor Boxes
|
||||
|
||||
到目前为止,我们讨论的情况都是一个网格只检测一个对象。如果要将算法运用在多目标检测上,需要用到 Anchor Boxes。一个网格的标签中将包含多个 Anchor Box,相当于存在多个用以标识不同目标的边框。
|
||||
|
||||

|
||||
|
||||
在上图示例中,我们希望同时检测人和汽车。因此,每个网格的的标签中含有两个 Anchor Box。输出的标签结果大小从 3×3×8 变为 3×3×16。若两个 $P\_c$ 都大于预设阈值,则说明检测到了两个目标。
|
||||
|
||||
在单目标检测中,图像中的目标被分配给了包含该目标中点的那个网格;引入 Anchor Box 进行多目标检测时,图像中的目标则被分配到了包含该目标中点的那个网格以及具有最高 IoU 值的该网格的 Anchor Box。
|
||||
|
||||
Anchor Boxes 也有局限性,对于同一网格有三个及以上目标,或者两个目标的 Anchor Box 高度重合的情况处理不好。
|
||||
|
||||
Anchor Box 的形状一般通过人工选取。高级一点的方法是用 k-means 将两类对象形状聚类,选择最具代表性的 Anchor Box。
|
||||
|
||||
如果对以上内容不是很理解,在“3.9 YOLO 算法”一节中视频的第 5 分钟,有一个更为直观的示例。
|
||||
|
||||
## R-CNN
|
||||
|
||||
前面介绍的滑动窗口目标检测算法对一些明显没有目标的区域也进行了扫描,这降低了算法的运行效率。为了解决这个问题,**R-CNN(Region CNN,带区域的 CNN)**被提出。通过对输入图片运行**图像分割算法**,在不同的色块上找出**候选区域(Region Proposal)**,就只需要在这些区域上运行分类器。
|
||||
|
||||

|
||||
|
||||
R-CNN 的缺点是运行速度很慢,所以有一系列后续研究工作改进。例如 Fast R-CNN(与基于卷积的滑动窗口实现相似,但得到候选区域的聚类步骤依然很慢)、Faster R-CNN(使用卷积对图片进行分割)。不过大多数时候还是比 YOLO 算法慢。
|
||||
|
||||
相关论文:
|
||||
|
||||
* R-CNN:[Girshik et al., 2013. Rich feature hierarchies for accurate object detection and semantic segmentation](https://arxiv.org/pdf/1311.2524.pdf)
|
||||
* Fast R-CNN:[Girshik, 2015. Fast R-CNN](https://arxiv.org/pdf/1504.08083.pdf)
|
||||
* Faster R-CNN:[Ren et al., 2016. Faster R-CNN: Towards real-time object detection with region proposal networks](https://arxiv.org/pdf/1506.01497v3.pdf)
|
||||
BIN
机器学习/吴恩达深度学习/学习笔记/Improving_Deep_Neural_Networks/BN.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 39 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Improving_Deep_Neural_Networks/RMSProp.png
Normal file
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 106 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 104 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 22 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Improving_Deep_Neural_Networks/saddle.png
Normal file
|
After Width: | Height: | Size: 346 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 114 KiB |
278
机器学习/吴恩达深度学习/学习笔记/Improving_Deep_Neural_Networks/优化算法.md
Normal file
@@ -0,0 +1,278 @@
|
||||
<h1 align="center">优化算法</h1>
|
||||
|
||||
深度学习难以在大数据领域发挥最大效果的一个原因是,在巨大的数据集基础上进行训练速度很慢。而优化算法能够帮助快速训练模型,大大提高效率。
|
||||
|
||||
## batch 梯度下降法
|
||||
|
||||
**batch 梯度下降法**(批梯度下降法,我们之前一直使用的梯度下降法)是最常用的梯度下降形式,即同时处理整个训练集。其在更新参数时使用所有的样本来进行更新。
|
||||
|
||||
对整个训练集进行梯度下降法的时候,我们必须处理整个训练数据集,然后才能进行一步梯度下降,即每一步梯度下降法需要对整个训练集进行一次处理,如果训练数据集很大的时候,处理速度就会比较慢。
|
||||
|
||||
但是如果每次处理训练数据的一部分即进行梯度下降法,则我们的算法速度会执行的更快。而处理的这些一小部分训练子集即称为 **mini-batch**。
|
||||
|
||||
## Mini-Batch 梯度下降法
|
||||
|
||||
**Mini-Batch 梯度下降法**(小批量梯度下降法)每次同时处理单个的 mini-batch,其他与 batch 梯度下降法一致。
|
||||
|
||||
使用 batch 梯度下降法,对整个训练集的一次遍历只能做一个梯度下降;而使用 Mini-Batch 梯度下降法,对整个训练集的一次遍历(称为一个 epoch)能做 mini-batch 个数个梯度下降。之后,可以一直遍历训练集,直到最后收敛到一个合适的精度。
|
||||
|
||||
batch 梯度下降法和 Mini-batch 梯度下降法代价函数的变化趋势如下:
|
||||
|
||||

|
||||
|
||||
### batch 的不同大小(size)带来的影响
|
||||
|
||||
* mini-batch 的大小为 1,即是**随机梯度下降法(stochastic gradient descent)**,每个样本都是独立的 mini-batch;
|
||||
* mini-batch 的大小为 m(数据集大小),即是 batch 梯度下降法;
|
||||
|
||||

|
||||
|
||||
* batch 梯度下降法:
|
||||
* 对所有 m 个训练样本执行一次梯度下降,**每一次迭代时间较长,训练过程慢**;
|
||||
* 相对噪声低一些,幅度也大一些;
|
||||
* 成本函数总是向减小的方向下降。
|
||||
|
||||
* 随机梯度下降法:
|
||||
* 对每一个训练样本执行一次梯度下降,训练速度快,但**丢失了向量化带来的计算加速**;
|
||||
* 有很多噪声,减小学习率可以适当;
|
||||
* 成本函数总体趋势向全局最小值靠近,但永远不会收敛,而是一直在最小值附近波动。
|
||||
|
||||
因此,选择一个`1 < size < m`的合适的大小进行 Mini-batch 梯度下降,可以实现快速学习,也应用了向量化带来的好处,且成本函数的下降处于前两者之间。
|
||||
|
||||
### mini-batch 大小的选择
|
||||
|
||||
* 如果训练样本的大小比较小,如 m ⩽ 2000 时,选择 batch 梯度下降法;
|
||||
* 如果训练样本的大小比较大,选择 Mini-Batch 梯度下降法。为了和计算机的信息存储方式相适应,代码在 mini-batch 大小为 2 的幂次时运行要快一些。典型的大小为 $2^6$、$2^7$、...、$2^9$;
|
||||
* mini-batch 的大小要符合 CPU/GPU 内存。
|
||||
|
||||
mini-batch 的大小也是一个重要的超变量,需要根据经验快速尝试,找到能够最有效地减少成本函数的值。
|
||||
|
||||
### 获得 mini-batch 的步骤
|
||||
|
||||
1. 将数据集打乱;
|
||||
2. 按照既定的大小分割数据集;
|
||||
|
||||
其中打乱数据集的代码:
|
||||
|
||||
```py
|
||||
m = X.shape[1]
|
||||
permutation = list(np.random.permutation(m))
|
||||
shuffled_X = X[:, permutation]
|
||||
shuffled_Y = Y[:, permutation].reshape((1,m))
|
||||
```
|
||||
|
||||
`np.random.permutation`与`np.random.shuffle`有两处不同:
|
||||
|
||||
1. 如果传给`permutation`一个矩阵,它会返回一个洗牌后的矩阵副本;而`shuffle`只是对一个矩阵进行洗牌,没有返回值。
|
||||
2. 如果传入一个整数,它会返回一个洗牌后的`arange`。
|
||||
|
||||
### 符号表示
|
||||
|
||||
* 使用上角小括号 i 表示训练集里的值,$x^{(i)}$ 是第 i 个训练样本;
|
||||
* 使用上角中括号 l 表示神经网络的层数,$z^{[l]}$ 表示神经网络中第 l 层的 z 值;
|
||||
* 现在引入大括号 t 来代表不同的 mini-batch,因此有 $X^{t}$、$Y^{t}$。
|
||||
|
||||
## 指数平均加权
|
||||
|
||||
**指数加权平均(Exponentially Weight Average)**是一种常用的序列数据处理方式,计算公式为:
|
||||
|
||||
$$
|
||||
S\_t =
|
||||
\begin{cases}
|
||||
Y\_1, &t = 1 \\\\
|
||||
\beta S\_{t-1} + (1-\beta)Y_t, &t > 1
|
||||
\end{cases}
|
||||
$$
|
||||
|
||||
其中 $Y\_t$ 为 t 下的实际值,$S\_t$ 为 t 下加权平均后的值,β 为权重值。
|
||||
|
||||
指数加权平均数在统计学中被称为“指数加权移动平均值”。
|
||||
|
||||

|
||||
|
||||
给定一个时间序列,例如伦敦一年每天的气温值,图中蓝色的点代表真实数据。对于一个即时的气温值,取权重值 β 为 0.9,根据求得的值可以得到图中的红色曲线,它反映了气温变化的大致趋势。
|
||||
|
||||
当取权重值 β=0.98 时,可以得到图中更为平滑的绿色曲线。而当取权重值 β=0.5 时,得到图中噪点更多的黄色曲线。**β 越大相当于求取平均利用的天数越多**,曲线自然就会越平滑而且越滞后。
|
||||
|
||||
### 理解指数平均加权
|
||||
|
||||
当 β 为 0.9 时,
|
||||
|
||||
$$v\_{100} = 0.9v\_{99} + 0.1 \theta\_{100}$$
|
||||
|
||||
$$v\_{99} = 0.9v\_{98} + 0.1 \theta\_{99}$$
|
||||
|
||||
$$v\_{98} = 0.9v\_{97} + 0.1 \theta\_{98}$$
|
||||
$$...$$
|
||||
|
||||
展开:
|
||||
|
||||
$$v\_{100} = 0.1 \theta\_{100} + 0.1 \* 0.9 \theta\_{99} + 0.1 \* {(0.9)}^2 \theta\_{98} + ...$$
|
||||
|
||||
其中 θi 指第 i 天的实际数据。所有 θ 前面的系数(不包括 0.1)相加起来为 1 或者接近于 1,这些系数被称作**偏差修正(Bias Correction)**。
|
||||
|
||||
根据函数极限的一条定理:
|
||||
|
||||
$${\lim\_{\beta\to 0}}(1 - \beta)^{\frac{1}{\beta}} = \frac{1}{e} \approx 0.368$$
|
||||
|
||||
当 β 为 0.9 时,可以当作把过去 10 天的气温指数加权平均作为当日的气温,因为 10 天后权重已经下降到了当天的 1/3 左右。同理,当 β 为 0.98 时,可以把过去 50 天的气温指数加权平均作为当日的气温。
|
||||
|
||||
因此,在计算当前时刻的平均值时,只需要前一天的平均值和当前时刻的值。
|
||||
|
||||
$$v\_t = \beta v\_{t-1} + (1 - \beta)\theta_t$$
|
||||
|
||||
考虑到代码,只需要不断更新 v 即可:
|
||||
|
||||
$$v := \beta v + (1 - \beta)\theta_t$$
|
||||
<!--此处应有公式的实现代码-->
|
||||
|
||||
指数平均加权并**不是最精准**的计算平均数的方法,你可以直接计算过去 10 天或 50 天的平均值来得到更好的估计,但缺点是保存数据需要占用更多内存,执行更加复杂,计算成本更加高昂。
|
||||
|
||||
指数加权平均数公式的好处之一在于它只需要一行代码,且占用极少内存,因此**效率极高,且节省成本**。
|
||||
|
||||
### 指数平均加权的偏差修正
|
||||
|
||||
我们通常有
|
||||
|
||||
$$v\_0 = 0$$
|
||||
$$v\_1 = 0.98v\_0 + 0.02\theta\_1$$
|
||||
|
||||
因此,$v\_1$ 仅为第一个数据的 0.02(或者说 1-β),显然不准确。往后递推同理。
|
||||
|
||||
因此,我们修改公式为
|
||||
|
||||
$$v\_t = \frac{\beta v\_{t-1} + (1 - \beta)\theta_t}{{1-\beta^t}}$$
|
||||
|
||||
随着 t 的增大,β 的 t 次方趋近于 0。因此当 t 很大的时候,偏差修正几乎没有作用,但是在前期学习可以帮助更好的预测数据。在实际过程中,一般会忽略前期偏差的影响。
|
||||
|
||||
## 动量梯度下降法
|
||||
|
||||
**动量梯度下降(Gradient Descent with Momentum)**是计算梯度的指数加权平均数,并利用该值来更新参数值。具体过程为:
|
||||
|
||||
for l = 1, .. , L:
|
||||
|
||||
$$v\_{dW^{[l]}} = \beta v\_{dW^{[l]}} + (1 - \beta) dW^{[l]}$$
|
||||
$$v\_{db^{[l]}} = \beta v\_{db^{[l]}} + (1 - \beta) db^{[l]}$$
|
||||
$$W^{[l]} := W^{[l]} - \alpha v\_{dW^{[l]}}$$
|
||||
$$b^{[l]} := b^{[l]} - \alpha v\_{db^{[l]}}$$
|
||||
|
||||
其中,将动量衰减参数 β 设置为 0.9 是超参数的一个常见且效果不错的选择。当 β 被设置为 0 时,显然就成了 batch 梯度下降法。
|
||||
|
||||

|
||||
|
||||
进行一般的梯度下降将会得到图中的蓝色曲线,由于存在上下波动,减缓了梯度下降的速度,因此只能使用一个较小的学习率进行迭代。如果用较大的学习率,结果可能会像紫色曲线一样偏离函数的范围。
|
||||
|
||||
而使用动量梯度下降时,通过累加过去的梯度值来减少抵达最小值路径上的波动,加速了收敛,因此在横轴方向下降得更快,从而得到图中红色的曲线。
|
||||
|
||||
当前后梯度方向一致时,动量梯度下降能够加速学习;而前后梯度方向不一致时,动量梯度下降能够抑制震荡。
|
||||
|
||||
另外,在 10 次迭代之后,移动平均已经不再是一个具有偏差的预测。因此实际在使用梯度下降法或者动量梯度下降法时,不会同时进行偏差修正。
|
||||
|
||||
### 动量梯度下降法的形象解释
|
||||
|
||||
将成本函数想象为一个碗状,从顶部开始运动的小球向下滚,其中 dw,db 想象成球的加速度;而 $v\_{dw}$、$v\_{db}$ 相当于速度。
|
||||
|
||||
小球在向下滚动的过程中,因为加速度的存在速度会变快,但是由于 β 的存在,其值小于 1,可以认为是摩擦力,所以球不会无限加速下去。
|
||||
|
||||
## RMSProp 算法
|
||||
|
||||
**RMSProp(Root Mean Square Propagation,均方根传播)**算法是在对梯度进行指数加权平均的基础上,引入平方和平方根。具体过程为(省略了 l):
|
||||
|
||||
$$s\_{dw} = \beta s\_{dw} + (1 - \beta)(dw)^2$$
|
||||
$$s\_{db} = \beta s\_{db} + (1 - \beta)(db)^2$$
|
||||
$$w := w - \alpha \frac{dw}{\sqrt{s\_{dw} + \epsilon}}$$
|
||||
$$b := b - \alpha \frac{db}{\sqrt{s\_{db} + \epsilon}}$$
|
||||
|
||||
其中,ϵ 是一个实际操作时加上的较小数(例如10^-8),为了防止分母太小而导致的数值不稳定。
|
||||
|
||||
当 dw 或 db 较大时,$(dw)^2$、$(db)^2$会较大,进而 $s\_{dw}$、$s\_{db}$也会较大,最终使得
|
||||
|
||||
$$\frac{dw}{\sqrt{s\_{dw} + \epsilon}}$$
|
||||
|
||||
和
|
||||
|
||||
$$\frac{db}{\sqrt{s\_{db} + \epsilon}}$$
|
||||
|
||||
较小,从而减小某些维度梯度更新波动较大的情况,使下降速度变得更快。
|
||||
|
||||

|
||||
|
||||
RMSProp 有助于减少抵达最小值路径上的摆动,并允许使用一个更大的学习率 α,从而加快算法学习速度。并且,它和 Adam 优化算法已被证明适用于不同的深度学习网络结构。
|
||||
|
||||
注意,β 也是一个超参数。
|
||||
|
||||
## Adam 优化算法
|
||||
|
||||
**Adam 优化算法(Adaptive Moment Estimation,自适应矩估计)**基本上就是将 Momentum 和 RMSProp 算法结合在一起,通常有超越二者单独时的效果。具体过程如下(省略了 l):
|
||||
|
||||
首先进行初始化:
|
||||
|
||||
$$v\_{dW} = 0, s\_{dW} = 0, v\_{db} = 0, s\_{db} = 0$$
|
||||
|
||||
用每一个 mini-batch 计算 dW、db,第 t 次迭代时:
|
||||
|
||||
$$v\_{dW} = \beta\_1 v\_{dW} + (1 - \beta\_1) dW$$
|
||||
$$v\_{db} = \beta\_1 v\_{db} + (1 - \beta\_1) db$$
|
||||
$$s\_{dW} = \beta\_2 s\_{dW} + (1 - \beta\_2) {(dW)}^2$$
|
||||
$$s\_{db} = \beta\_2 s\_{db} + (1 - \beta\_2) {(db)}^2$$
|
||||
|
||||
一般使用 Adam 算法时需要计算偏差修正:
|
||||
|
||||
$$v^{corrected}\_{dW} = \frac{v\_{dW}}{1-{\beta\_1}^t}$$
|
||||
$$v^{corrected}\_{db} = \frac{v\_{db}}{1-{\beta\_1}^t}$$
|
||||
$$s^{corrected}\_{dW} = \frac{s\_{dW}}{1-{\beta\_2}^t}$$
|
||||
$$s^{corrected}\_{db} = \frac{s\_{db}}{1-{\beta\_2}^t}$$
|
||||
|
||||
所以,更新 W、b 时有:
|
||||
|
||||
$$W := W - \alpha \frac{v^{corrected}\_{dW}}{{\sqrt{s^{corrected}\_{dW}} + \epsilon}}$$
|
||||
|
||||
$$b := b - \alpha \frac{v^{corrected}\_{db}}{{\sqrt{s^{corrected}\_{db}} + \epsilon}}$$
|
||||
|
||||
(可以看到 Andrew 在这里 ϵ 没有写到平方根里去,和他在 RMSProp 中写的不太一样。考虑到 ϵ 所起的作用,我感觉影响不大)
|
||||
|
||||
### 超参数的选择
|
||||
|
||||
Adam 优化算法有很多的超参数,其中
|
||||
|
||||
* 学习率 α:需要尝试一系列的值,来寻找比较合适的;
|
||||
* β1:常用的缺省值为 0.9;
|
||||
* β2:Adam 算法的作者建议为 0.999;
|
||||
* ϵ:不重要,不会影响算法表现,Adam 算法的作者建议为 $10^{-8}$;
|
||||
|
||||
β1、β2、ϵ 通常不需要调试。
|
||||
|
||||
## 学习率衰减
|
||||
|
||||
如果设置一个固定的学习率 α,在最小值点附近,由于不同的 batch 中存在一定的噪声,因此不会精确收敛,而是始终在最小值周围一个较大的范围内波动。
|
||||
|
||||
而如果随着时间慢慢减少学习率 α 的大小,在初期 α 较大时,下降的步长较大,能以较快的速度进行梯度下降;而后期逐步减小 α 的值,即减小步长,有助于算法的收敛,更容易接近最优解。
|
||||
|
||||
最常用的学习率衰减方法:
|
||||
|
||||
$$\alpha = \frac{1}{1 + decay\\\_rate \* epoch\\\_num} \* \alpha\_0$$
|
||||
|
||||
其中,`decay_rate`为衰减率(超参数),`epoch_num`为将所有的训练样本完整过一遍的次数。
|
||||
|
||||
* 指数衰减:
|
||||
|
||||
$$\alpha = 0.95^{epoch\\\_num} \* \alpha\_0$$
|
||||
|
||||
* 其他:
|
||||
|
||||
$$\alpha = \frac{k}{\sqrt{epoch\\\_num}} \* \alpha\_0$$
|
||||
|
||||
* 离散下降
|
||||
|
||||
对于较小的模型,也有人会在训练时根据进度手动调小学习率。
|
||||
|
||||
## 局部最优问题
|
||||
|
||||

|
||||
|
||||
**鞍点(saddle)**是函数上的导数为零,但不是轴上局部极值的点。当我们建立一个神经网络时,通常梯度为零的点是上图所示的鞍点,而非局部最小值。减少损失的难度也来自误差曲面中的鞍点,而不是局部最低点。因为在一个具有高维度空间的成本函数中,如果梯度为 0,那么在每个方向,成本函数或是凸函数,或是凹函数。而所有维度均需要是凹函数的概率极小,因此在低维度的局部最优点的情况并不适用于高维度。
|
||||
|
||||
结论:
|
||||
|
||||
* 在训练较大的神经网络、存在大量参数,并且成本函数被定义在较高的维度空间时,困在极差的局部最优中是不大可能的;
|
||||
* 鞍点附近的平稳段会使得学习非常缓慢,而这也是动量梯度下降法、RMSProp 以及 Adam 优化算法能够加速学习的原因,它们能帮助尽早走出平稳段。
|
||||
318
机器学习/吴恩达深度学习/学习笔记/Improving_Deep_Neural_Networks/深度学习的实用层面.md
Normal file
@@ -0,0 +1,318 @@
|
||||
<h1 align="center">深度学习的实用层面</h1>
|
||||
|
||||
## 数据划分:训练 / 验证 / 测试集
|
||||
|
||||
应用深度学习是一个典型的迭代过程。
|
||||
|
||||
对于一个需要解决的问题的样本数据,在建立模型的过程中,数据会被划分为以下几个部分:
|
||||
|
||||
* 训练集(train set):用训练集对算法或模型进行**训练**过程;
|
||||
* 验证集(development set):利用验证集(又称为简单交叉验证集,hold-out cross validation set)进行**交叉验证**,**选择出最好的模型**;
|
||||
* 测试集(test set):最后利用测试集对模型进行测试,**获取模型运行的无偏估计**(对学习方法进行评估)。
|
||||
|
||||
在**小数据量**的时代,如 100、1000、10000 的数据量大小,可以将数据集按照以下比例进行划分:
|
||||
|
||||
* 无验证集的情况:70% / 30%;
|
||||
* 有验证集的情况:60% / 20% / 20%;
|
||||
|
||||
而在如今的**大数据时代**,对于一个问题,我们拥有的数据集的规模可能是百万级别的,所以验证集和测试集所占的比重会趋向于变得更小。
|
||||
|
||||
验证集的目的是为了验证不同的算法哪种更加有效,所以验证集只要足够大到能够验证大约 2-10 种算法哪种更好,而不需要使用 20% 的数据作为验证集。如百万数据中抽取 1 万的数据作为验证集就可以了。
|
||||
|
||||
测试集的主要目的是评估模型的效果,如在单个分类器中,往往在百万级别的数据中,我们选择其中 1000 条数据足以评估单个模型的效果。
|
||||
|
||||
* 100 万数据量:98% / 1% / 1%;
|
||||
* 超百万数据量:99.5% / 0.25% / 0.25%(或者99.5% / 0.4% / 0.1%)
|
||||
|
||||
### 建议
|
||||
|
||||
建议**验证集要和训练集来自于同一个分布**(数据来源一致),可以使得机器学习算法变得更快并获得更好的效果。
|
||||
|
||||
如果不需要用**无偏估计**来评估模型的性能,则可以不需要测试集。
|
||||
|
||||
### 补充:交叉验证(cross validation)
|
||||
|
||||
交叉验证的基本思想是重复地使用数据;把给定的数据进行切分,将切分的数据集组合为训练集与测试集,在此基础上反复地进行训练、测试以及模型选择。
|
||||
|
||||
### 参考资料
|
||||
|
||||
[无偏估计_百度百科](https://baike.baidu.com/item/%E6%97%A0%E5%81%8F%E4%BC%B0%E8%AE%A1/3370664?fr=aladdin)
|
||||
|
||||
## 模型估计:偏差 / 方差
|
||||
|
||||
**“偏差-方差分解”(bias-variance decomposition)**是解释学习算法泛化性能的一种重要工具。
|
||||
|
||||
泛化误差可分解为偏差、方差与噪声之和:
|
||||
|
||||
* **偏差**:度量了学习算法的期望预测与真实结果的偏离程度,即刻画了**学习算法本身的拟合能力**;
|
||||
* **方差**:度量了同样大小的训练集的变动所导致的学习性能的变化,即刻画了**数据扰动所造成的影响**;
|
||||
* **噪声**:表达了在当前任务上任何学习算法所能够达到的期望泛化误差的下界,即刻画了**学习问题本身的难度**。
|
||||
|
||||
偏差-方差分解说明,**泛化性能**是由**学习算法的能力**、**数据的充分性**以及**学习任务本身的难度**所共同决定的。给定学习任务,为了取得好的泛化性能,则需要使偏差较小,即能够充分拟合数据,并且使方差较小,即使得数据扰动产生的影响小。
|
||||
|
||||
<!-- 以上摘自周志华《机器学习》 -->
|
||||
|
||||
在**欠拟合(underfitting)**的情况下,出现**高偏差(high bias)**的情况,即不能很好地对数据进行分类。
|
||||
|
||||
当模型设置的太复杂时,训练集中的一些噪声没有被排除,使得模型出现**过拟合(overfitting)**的情况,在验证集上出现**高方差(high variance)**的现象。
|
||||
|
||||
当训练出一个模型以后,如果:
|
||||
|
||||
* 训练集的错误率较小,而验证集的错误率却较大,说明模型存在较大方差,可能出现了过拟合;
|
||||
* 训练集和开发集的错误率都较大,且两者相当,说明模型存在较大偏差,可能出现了欠拟合;
|
||||
* 训练集错误率较大,且开发集的错误率远较训练集大,说明方差和偏差都较大,模型很差;
|
||||
* 训练集和开发集的错误率都较小,且两者的相差也较小,说明方差和偏差都较小,这个模型效果比较好。
|
||||
|
||||
偏差和方差的权衡问题对于模型来说十分重要。
|
||||
|
||||
最优误差通常也称为“贝叶斯误差”。
|
||||
|
||||
### 应对方法
|
||||
|
||||
存在高偏差:
|
||||
|
||||
* 扩大网络规模,如添加隐藏层或隐藏单元数目;
|
||||
* 寻找合适的网络架构,使用更大的 NN 结构;
|
||||
* 花费更长时间训练。
|
||||
|
||||
存在高方差:
|
||||
|
||||
* 获取更多的数据;
|
||||
* 正则化(regularization);
|
||||
* 寻找更合适的网络结构。
|
||||
|
||||
不断尝试,直到找到低偏差、低方差的框架。
|
||||
|
||||
在深度学习的早期阶段,没有太多方法能做到只减少偏差或方差而不影响到另外一方。而在大数据时代,深度学习对监督式学习大有裨益,使得我们不用像以前一样太过关注如何平衡偏差和方差的权衡问题,通过以上方法可以在不增加某一方的前提下减少另一方的值。
|
||||
|
||||
## 正则化(regularization)
|
||||
|
||||
**正则化**是在成本函数中加入一个正则化项,惩罚模型的复杂度。正则化可以用于解决高方差的问题。
|
||||
|
||||
### Logistic 回归中的正则化
|
||||
|
||||
对于 Logistic 回归,加入 L2 正则化(也称“L2 范数”)的成本函数:
|
||||
|
||||
$$J(w,b) = \frac{1}{m}\sum_{i=1}^mL(\hat{y}^{(i)},y^{(i)})+\frac{\lambda}{2m}{||w||}^2\_2$$
|
||||
|
||||
* L2 正则化:$$\frac{\lambda}{2m}{||w||}^2\_2 = \frac{\lambda}{2m}\sum_{j=1}^{n\_x}w^2\_j = \frac{\lambda}{2m}w^Tw$$
|
||||
* L1 正则化:$$\frac{\lambda}{2m}{||w||}\_1 = \frac{\lambda}{2m}\sum_{j=1}^{n\_x}{|w\_j|}$$
|
||||
|
||||
其中,λ 为**正则化因子**,是**超参数**。
|
||||
|
||||
由于 L1 正则化最后得到 w 向量中将存在大量的 0,使模型变得稀疏化,因此 L2 正则化更加常用。
|
||||
|
||||
**注意**,`lambda`在 Python 中属于保留字,所以在编程的时候,用`lambd`代替这里的正则化因子。
|
||||
|
||||
### 神经网络中的正则化
|
||||
|
||||
对于神经网络,加入正则化的成本函数:
|
||||
|
||||
$$J(w^{[1]}, b^{[1]}, ..., w^{[L]}, b^{[L]}) = \frac{1}{m}\sum\_{i=1}^mL(\hat{y}^{(i)},y^{(i)})+\frac{\lambda}{2m}\sum\_{l=1}^L{{||w^{[l]}||}}^2\_F$$
|
||||
|
||||
因为 w 的大小为 ($n^{[l−1]}$, $n^{[l]}$),因此
|
||||
|
||||
$${{||w^{[l]}||}}^2\_F = \sum^{n^{[l-1]}}\_{i=1}\sum^{n^{[l]}}\_{j=1}(w^{[l]}\_{ij})^2$$
|
||||
|
||||
该矩阵范数被称为**弗罗贝尼乌斯范数(Frobenius Norm)**,所以神经网络中的正则化项被称为弗罗贝尼乌斯范数矩阵。
|
||||
|
||||
#### 权重衰减(Weight decay)
|
||||
|
||||
**在加入正则化项后,梯度变为**(反向传播要按这个计算):
|
||||
|
||||
$$dW^{[l]}= \frac{\partial L}{\partial w^{[l]}} +\frac{\lambda}{m}W^{[l]}$$
|
||||
|
||||
代入梯度更新公式:
|
||||
|
||||
$$W^{[l]} := W^{[l]}-\alpha dW^{[l]}$$
|
||||
|
||||
可得:
|
||||
|
||||
$$W^{[l]} := W^{[l]} - \alpha [\frac{\partial L}{\partial w^{[l]}} + \frac{\lambda}{m}W^{[l]}]$$
|
||||
|
||||
$$= W^{[l]} - \alpha \frac{\lambda}{m}W^{[l]} - \alpha \frac{\partial L}{\partial w^{[l]}}$$
|
||||
|
||||
$$= (1 - \frac{\alpha\lambda}{m})W^{[l]} - \alpha \frac{\partial L}{\partial w^{[l]}}$$
|
||||
|
||||
其中,因为 $1 - \frac{\alpha\lambda}{m}<1$,会给原来的 $W^{[l]}$一个衰减的参数,因此 L2 正则化项也被称为**权重衰减(Weight Decay)**。
|
||||
|
||||
### 正则化可以减小过拟合的原因
|
||||
|
||||
#### 直观解释
|
||||
|
||||
正则化因子设置的足够大的情况下,为了使成本函数最小化,权重矩阵 W 就会被设置为接近于 0 的值,**直观上**相当于消除了很多神经元的影响,那么大的神经网络就会变成一个较小的网络。当然,实际上隐藏层的神经元依然存在,但是其影响减弱了,便不会导致过拟合。
|
||||
|
||||
#### 数学解释
|
||||
|
||||
假设神经元中使用的激活函数为`g(z) = tanh(z)`(sigmoid 同理)。
|
||||
|
||||

|
||||
|
||||
在加入正则化项后,当 λ 增大,导致 $W^{[l]}$减小,$Z^{[l]} = W^{[l]}a^{[l-1]} + b^{[l]}$便会减小。由上图可知,在 z 较小(接近于 0)的区域里,`tanh(z)`函数近似线性,所以每层的函数就近似线性函数,整个网络就成为一个简单的近似线性的网络,因此不会发生过拟合。
|
||||
|
||||
#### 其他解释
|
||||
|
||||
在权值 $w^{[L]}$变小之下,输入样本 X 随机的变化不会对神经网络模造成过大的影响,神经网络受局部噪音的影响的可能性变小。这就是正则化能够降低模型方差的原因。
|
||||
|
||||
## dropout 正则化
|
||||
|
||||
**dropout(随机失活)**是在神经网络的隐藏层为每个神经元结点设置一个随机消除的概率,保留下来的神经元形成一个结点较少、规模较小的网络用于训练。dropout 正则化较多地被使用在**计算机视觉(Computer Vision)**领域。
|
||||
|
||||

|
||||
|
||||
### 反向随机失活(Inverted dropout)
|
||||
|
||||
反向随机失活是实现 dropout 的方法。对第`l`层进行 dropout:
|
||||
|
||||
```py
|
||||
keep_prob = 0.8 # 设置神经元保留概率
|
||||
dl = np.random.rand(al.shape[0], al.shape[1]) < keep_prob
|
||||
al = np.multiply(al, dl)
|
||||
al /= keep_prob
|
||||
```
|
||||
|
||||
最后一步`al /= keep_prob`是因为 $a^{[l]}$中的一部分元素失活(相当于被归零),为了在下一层计算时不影响 $Z^{[l+1]} = W^{[l+1]}a^{[l]} + b^{[l+1]}$的期望值,因此除以一个`keep_prob`。
|
||||
|
||||
**注意**,在**测试阶段不要使用 dropout**,因为那样会使得预测结果变得随机。
|
||||
|
||||
### 理解 dropout
|
||||
|
||||
对于单个神经元,其工作是接收输入并产生一些有意义的输出。但是加入了 dropout 后,输入的特征都存在被随机清除的可能,所以该神经元不会再特别依赖于任何一个输入特征,即不会给任何一个输入特征设置太大的权重。
|
||||
|
||||
因此,通过传播过程,dropout 将产生和 L2 正则化相同的**收缩权重**的效果。
|
||||
|
||||
对于不同的层,设置的`keep_prob`也不同。一般来说,神经元较少的层,会设`keep_prob`为 1.0,而神经元多的层则会设置比较小的`keep_prob`。
|
||||
|
||||
dropout 的一大**缺点**是成本函数无法被明确定义。因为每次迭代都会随机消除一些神经元结点的影响,因此无法确保成本函数单调递减。因此,使用 dropout 时,先将`keep_prob`全部设置为 1.0 后运行代码,确保 $J(w, b)$函数单调递减,再打开 dropout。
|
||||
|
||||
## 其他正则化方法
|
||||
|
||||
* 数据扩增(Data Augmentation):通过图片的一些变换(翻转,局部放大后切割等),得到更多的训练集和验证集。
|
||||
* 早停止法(Early Stopping):将训练集和验证集进行梯度下降时的成本变化曲线画在同一个坐标轴内,当训练集误差降低但验证集误差升高,两者开始发生较大偏差时及时停止迭代,并返回具有最小验证集误差的连接权和阈值,以避免过拟合。这种方法的缺点是无法同时达成偏差和方差的最优。
|
||||
|
||||
## 标准化输入
|
||||
|
||||
使用标准化处理输入 X 能够有效加速收敛。
|
||||
|
||||
### 标准化公式
|
||||
|
||||
$$x = \frac{x - \mu}{\sigma}$$
|
||||
|
||||
其中,
|
||||
|
||||
$$\mu = \frac{1}{m}\sum^m\_{i=1}x^{(i)}$$
|
||||
|
||||
$$\sigma = \sqrt{\frac{1}{m}\sum^m\_{i=1}x^{{(i)}^2}}$$
|
||||
|
||||
(注意,课程上对应内容中的标准化公式疑似有误,将标准差写成了方差,此处进行修正)
|
||||
|
||||
### 使用标准化的原因
|
||||
|
||||

|
||||
|
||||
有图可知,使用标准化前后,成本函数的形状有较大差别。
|
||||
|
||||
在不使用标准化的成本函数中,如果设置一个较小的学习率,可能需要很多次迭代才能到达全局最优解;而如果使用了标准化,那么无论从哪个位置开始迭代,都能以相对较少的迭代次数找到全局最优解。
|
||||
|
||||
## 梯度消失和梯度爆炸
|
||||
|
||||
在梯度函数上出现的以指数级递增或者递减的情况分别称为**梯度爆炸**或者**梯度消失**。
|
||||
|
||||
假定 $g(z) = z, b^{[l]} = 0$,对于目标输出有:
|
||||
|
||||
$$\hat{y} = W^{[L]}W^{[L-1]}...W^{[2]}W^{[1]}X$$
|
||||
|
||||
* 对于 $W^{[l]}$的值大于 1 的情况,激活函数的值将以指数级递增;
|
||||
* 对于 $W^{[l]}$的值小于 1 的情况,激活函数的值将以指数级递减。
|
||||
|
||||
对于导数同理。因此,在计算梯度时,根据不同情况梯度函数会以指数级递增或递减,导致训练导数难度上升,梯度下降算法的步长会变得非常小,需要训练的时间将会非常长。
|
||||
|
||||
### 利用初始化缓解梯度消失和爆炸
|
||||
|
||||
根据
|
||||
|
||||
$$z={w}_1{x}\_1+{w}\_2{x}\_2 + ... + {w}\_n{x}\_n + b$$
|
||||
|
||||
可知,当输入的数量 n 较大时,我们希望每个 wi 的值都小一些,这样它们的和得到的 z 也较小。
|
||||
|
||||
为了得到较小的 wi,设置`Var(wi)=1/n`,这里称为 **Xavier initialization**。
|
||||
|
||||
```py
|
||||
WL = np.random.randn(WL.shape[0], WL.shape[1]) * np.sqrt(1/n)
|
||||
```
|
||||
|
||||
其中 n 是输入的神经元个数,即`WL.shape[1]`。
|
||||
|
||||
这样,激活函数的输入 x 近似设置成均值为 0,标准方差为 1,神经元输出 z 的方差就正则化到 1 了。虽然没有解决梯度消失和爆炸的问题,但其在一定程度上确实减缓了梯度消失和爆炸的速度。
|
||||
|
||||
同理,也有 **He Initialization**。它和 Xavier initialization 唯一的区别是`Var(wi)=2/n`,适用于 **ReLU** 作为激活函数时。
|
||||
|
||||
当激活函数使用 ReLU 时,`Var(wi)=2/n`;当激活函数使用 tanh 时,`Var(wi)=1/n`。
|
||||
|
||||
## 梯度检验(Gradient checking)
|
||||
|
||||
### 梯度的数值逼近
|
||||
|
||||
使用双边误差的方法去逼近导数,精度要高于单边误差。
|
||||
|
||||
* 单边误差:
|
||||
|
||||

|
||||
|
||||
$$f'(\theta) = {\lim\_{\varepsilon\to 0}} = \frac{f(\theta + \varepsilon) - (\theta)}{\varepsilon}$$
|
||||
|
||||
误差:$O(\varepsilon)$
|
||||
|
||||
* 双边误差求导(即导数的定义):
|
||||
|
||||

|
||||
|
||||
$$f'(\theta) = {\lim\_{\varepsilon\to 0}} = \frac{f(\theta + \varepsilon) - (\theta - \varepsilon)}{2\varepsilon}$$
|
||||
|
||||
误差:$O(\varepsilon^2)$
|
||||
|
||||
当 ε 越小时,结果越接近真实的导数,也就是梯度值。可以使用这种方法来判断反向传播进行梯度下降时,是否出现了错误。
|
||||
|
||||
### 梯度检验的实施
|
||||
|
||||
#### 连接参数
|
||||
|
||||
将 $W^{[1]}$,$b^{[1]}$,...,$W^{[L]}$,$b^{[L]}$全部连接出来,成为一个巨型向量 θ。这样,
|
||||
|
||||
$$J(W^{[1]}, b^{[1]}, ..., W^{[L]},b^{[L]}) = J(\theta)$$
|
||||
|
||||
同时,对 $dW^{[1]}$,$db^{[1]}$,...,$dW^{[L]}$,$db^{[L]}$执行同样的操作得到巨型向量 dθ,它和 θ 有同样的维度。
|
||||
|
||||

|
||||
|
||||
现在,我们需要找到 dθ 和代价函数 J 的梯度的关系。
|
||||
|
||||
#### 进行梯度检验
|
||||
|
||||
求得一个梯度逼近值
|
||||
|
||||
$$d\theta_{approx}[i] = \frac{J(\theta\_1, \theta\_2, ..., \theta\_i+\varepsilon, ...) - J(\theta\_1, \theta\_2, ..., \theta\_i-\varepsilon, ...)}{2\varepsilon}$$
|
||||
|
||||
应该
|
||||
|
||||
$$\approx{d\theta[i]} = \frac{\partial J}{\partial \theta_i}$$
|
||||
|
||||
因此,我们用梯度检验值
|
||||
|
||||
$$\frac{{||d\theta\_{approx} - d\theta||}\_2}{{||d\theta\_{approx}||}\_2+{||d\theta||}\_2}$$
|
||||
|
||||
检验反向传播的实施是否正确。其中,
|
||||
|
||||
$${||x||}\_2 = \sum^N\_{i=1}{|x_i|}^2$$
|
||||
|
||||
表示向量 x 的 2-范数(也称“欧几里德范数”)。
|
||||
|
||||
如果梯度检验值和 ε 的值相近,说明神经网络的实施是正确的,否则要去检查代码是否存在 bug。
|
||||
|
||||
### 在神经网络实施梯度检验的实用技巧和注意事项
|
||||
|
||||
1. 不要在训练中使用梯度检验,它只用于调试(debug)。使用完毕关闭梯度检验的功能;
|
||||
2. 如果算法的梯度检验失败,要检查所有项,并试着找出 bug,即确定哪个 dθapprox[i] 与 dθ 的值相差比较大;
|
||||
3. 当成本函数包含正则项时,也需要带上正则项进行检验;
|
||||
4. 梯度检验不能与 dropout 同时使用。因为每次迭代过程中,dropout 会随机消除隐藏层单元的不同子集,难以计算 dropout 在梯度下降上的成本函数 J。建议关闭 dropout,用梯度检验进行双重检查,确定在没有 dropout 的情况下算法正确,然后打开 dropout;
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
<h1 align="center">超参数调试、Batch 正则化和程序框架</h1>
|
||||
|
||||
## 超参数调试处理
|
||||
|
||||
### 重要程度排序
|
||||
|
||||
目前已经讲到过的超参数中,重要程度依次是(仅供参考):
|
||||
|
||||
* **最重要**:
|
||||
* 学习率 α;
|
||||
|
||||
* **其次重要**:
|
||||
* β:动量衰减参数,常设置为 0.9;
|
||||
* #hidden units:各隐藏层神经元个数;
|
||||
* mini-batch 的大小;
|
||||
|
||||
* **再次重要**:
|
||||
* β1,β2,ϵ:Adam 优化算法的超参数,常设为 0.9、0.999、$10^{-8}$;
|
||||
* #layers:神经网络层数;
|
||||
* decay_rate:学习衰减率;
|
||||
|
||||
### 调参技巧
|
||||
|
||||
系统地组织超参调试过程的技巧:
|
||||
|
||||
* **随机选择**点(而非均匀选取),用这些点实验超参数的效果。这样做的原因是我们提前很难知道超参数的重要程度,可以通过选择更多值来进行更多实验;
|
||||
* 由粗糙到精细:聚焦效果不错的点组成的小区域,在其中更密集地取值,以此类推;
|
||||
|
||||
### 选择合适的范围
|
||||
|
||||
* 对于学习率 α,用**对数标尺**而非线性轴更加合理:0.0001、0.001、0.01、0.1 等,然后在这些刻度之间再随机均匀取值;
|
||||
* 对于 β,取 0.9 就相当于在 10 个值中计算平均值,而取 0.999 就相当于在 1000 个值中计算平均值。可以考虑给 1-β 取值,这样就和取学习率类似了。
|
||||
|
||||
上述操作的原因是当 β 接近 1 时,即使 β 只有微小的改变,所得结果的灵敏度会有较大的变化。例如,β 从 0.9 增加到 0.9005 对结果(1/(1-β))几乎没有影响,而 β 从 0.999 到 0.9995 对结果的影响巨大(从 1000 个值中计算平均值变为 2000 个值中计算平均值)。
|
||||
|
||||
### 一些建议
|
||||
|
||||
* 深度学习如今已经应用到许多不同的领域。不同的应用出现相互交融的现象,某个应用领域的超参数设定有可能通用于另一领域。不同应用领域的人也应该更多地阅读其他研究领域的 paper,跨领域地寻找灵感;
|
||||
* 考虑到数据的变化或者服务器的变更等因素,建议每隔几个月至少一次,重新测试或评估超参数,来获得实时的最佳模型;
|
||||
* 根据你所拥有的计算资源来决定你训练模型的方式:
|
||||
* Panda(熊猫方式):在在线广告设置或者在计算机视觉应用领域有大量的数据,但受计算能力所限,同时试验大量模型比较困难。可以采用这种方式:试验一个或一小批模型,初始化,试着让其工作运转,观察它的表现,不断调整参数;
|
||||
* Caviar(鱼子酱方式):拥有足够的计算机去平行试验很多模型,尝试很多不同的超参数,选取效果最好的模型;
|
||||
|
||||
## Batch Normalization
|
||||
|
||||
**批标准化(Batch Normalization,经常简称为 BN)**会使参数搜索问题变得很容易,使神经网络对超参数的选择更加稳定,超参数的范围会更庞大,工作效果也很好,也会使训练更容易。
|
||||
|
||||
之前,我们对输入特征 X 使用了标准化处理。我们也可以用同样的思路处理**隐藏层**的激活值 $a^{[l]}$,以加速 $W^{[l+1]}$和 $b^{[l+1]}$的训练。在**实践**中,经常选择标准化 $Z^{[l]}$:
|
||||
|
||||
$$\mu = \frac{1}{m} \sum\_i z^{(i)}$$
|
||||
$$\sigma^2 = \frac{1}{m} \sum\_i {(z\_i - \mu)}^2$$
|
||||
$$z\_{norm}^{(i)} = \frac{z^{(i)} - \mu}{\sqrt{\sigma^2 + \epsilon}}$$
|
||||
|
||||
其中,m 是单个 mini-batch 所包含的样本个数,ϵ 是为了防止分母为零,通常取 $10^{-8}$。
|
||||
|
||||
这样,我们使得所有的输入 $z^{(i)}$均值为 0,方差为 1。但我们不想让隐藏层单元总是含有平均值 0 和方差 1,也许隐藏层单元有了不同的分布会更有意义。因此,我们计算
|
||||
|
||||
$$\tilde z^{(i)} = \gamma z^{(i)}\_{norm} + \beta$$
|
||||
|
||||
其中,γ 和 β 都是模型的学习参数,所以可以用各种梯度下降算法来更新 γ 和 β 的值,如同更新神经网络的权重一样。
|
||||
|
||||
通过对 γ 和 β 的合理设置,可以让 $\tilde z^{(i)}$的均值和方差为任意值。这样,我们对隐藏层的 $z^{(i)}$进行标准化处理,用得到的 $\tilde z^{(i)}$替代 $z^{(i)}$。
|
||||
|
||||
**设置 γ 和 β 的原因**是,如果各隐藏层的输入均值在靠近 0 的区域,即处于激活函数的线性区域,不利于训练非线性神经网络,从而得到效果较差的模型。因此,需要用 γ 和 β 对标准化后的结果做进一步处理。
|
||||
|
||||
### 将 BN 应用于神经网络
|
||||
|
||||
对于 L 层神经网络,经过 Batch Normalization 的作用,整体流程如下:
|
||||
|
||||

|
||||
|
||||
实际上,Batch Normalization 经常使用在 mini-batch 上,这也是其名称的由来。
|
||||
|
||||
使用 Batch Normalization 时,因为标准化处理中包含减去均值的一步,因此 b 实际上没有起到作用,其数值效果交由 β 来实现。因此,在 Batch Normalization 中,可以省略 b 或者暂时设置为 0。
|
||||
|
||||
在使用梯度下降算法时,分别对 $W^{[l]}$,$β^{[l]}$和 $γ^{[l]}$进行迭代更新。除了传统的梯度下降算法之外,还可以使用之前学过的动量梯度下降、RMSProp 或者 Adam 等优化算法。
|
||||
|
||||
### BN 有效的原因
|
||||
|
||||
Batch Normalization 效果很好的原因有以下两点:
|
||||
|
||||
1. 通过对隐藏层各神经元的输入做类似的标准化处理,提高神经网络训练速度;
|
||||
2. 可以使前面层的权重变化对后面层造成的影响减小,整体网络更加健壮。
|
||||
|
||||
关于第二点,如果实际应用样本和训练样本的数据分布不同(例如,橘猫图片和黑猫图片),我们称发生了“**Covariate Shift**”。这种情况下,一般要对模型进行重新训练。Batch Normalization 的作用就是减小 Covariate Shift 所带来的影响,让模型变得更加健壮,鲁棒性(Robustness)更强。
|
||||
|
||||
即使输入的值改变了,由于 Batch Normalization 的作用,使得均值和方差保持不变(由 γ 和 β 决定),限制了在前层的参数更新对数值分布的影响程度,因此后层的学习变得更容易一些。Batch Normalization 减少了各层 W 和 b 之间的耦合性,让各层更加独立,实现自我训练学习的效果。
|
||||
|
||||
另外,Batch Normalization 也**起到微弱的正则化**(regularization)效果。因为在每个 mini-batch 而非整个数据集上计算均值和方差,只由这一小部分数据估计得出的均值和方差会有一些噪声,因此最终计算出的 $\tilde z^{(i)}$也有一定噪声。类似于 dropout,这种噪声会使得神经元不会再特别依赖于任何一个输入特征。
|
||||
|
||||
因为 Batch Normalization 只有微弱的正则化效果,因此可以和 dropout 一起使用,以获得更强大的正则化效果。通过应用更大的 mini-batch 大小,可以减少噪声,从而减少这种正则化效果。
|
||||
|
||||
最后,不要将 Batch Normalization 作为正则化的手段,而是当作加速学习的方式。正则化只是一种非期望的副作用,Batch Normalization 解决的还是反向传播过程中的梯度问题(梯度消失和爆炸)。
|
||||
|
||||
### 测试时的 Batch Normalization
|
||||
|
||||
Batch Normalization 将数据以 mini-batch 的形式逐一处理,但在测试时,可能需要对每一个样本逐一处理,这样无法得到 μ 和 $σ^2$。
|
||||
|
||||
理论上,我们可以将所有训练集放入最终的神经网络模型中,然后将每个隐藏层计算得到的 $μ^{[l]}$和 $σ^{2[l]}$直接作为测试过程的 μ 和 σ 来使用。但是,实际应用中一般不使用这种方法,而是使用之前学习过的指数加权平均的方法来预测测试过程单个样本的 μ 和 $σ^2$。
|
||||
|
||||
对于第 l 层隐藏层,考虑所有 mini-batch 在该隐藏层下的 $μ^{[l]}$和 $σ^{2[l]}$,然后用指数加权平均的方式来预测得到当前单个样本的 $μ^{[l]}$和 $σ^{2[l]}$。这样就实现了对测试过程单个样本的均值和方差估计。
|
||||
|
||||
## Softmax 回归
|
||||
|
||||
目前为止,介绍的分类例子都是二分类问题:神经网络输出层只有一个神经元,表示预测输出 $\hat y$是正类的概率 P(y = 1|x),$\hat y$ > 0.5 则判断为正类,反之判断为负类。
|
||||
|
||||
对于**多分类问题**,用 C 表示种类个数,则神经网络输出层,也就是第 L 层的单元数量 $n^{[L]} = C$。每个神经元的输出依次对应属于该类的概率,即 $P(y = c|x), c = 0, 1, .., C-1$。有一种 Logistic 回归的一般形式,叫做 **Softmax 回归**,可以处理多分类问题。
|
||||
|
||||
对于 Softmax 回归模型的输出层,即第 L 层,有:
|
||||
|
||||
$$Z^{[L]} = W^{[L]}a^{[L-1]} + b^{[L]}$$
|
||||
|
||||
for i in range(L),有:
|
||||
|
||||
$$a^{[L]}\_i = \frac{e^{Z^{[L]}\_i}}{\sum^C\_{i=1}e^{Z^{[L]}\_i}}$$
|
||||
|
||||
为输出层每个神经元的输出,对应属于该类的概率,满足:
|
||||
|
||||
$$\sum^C\_{i=1}a^{[L]}\_i = 1$$
|
||||
|
||||
一个直观的计算例子如下:
|
||||
|
||||

|
||||
|
||||
### 损失函数和成本函数
|
||||
|
||||
定义**损失函数**为:
|
||||
|
||||
$$L(\hat y, y) = -\sum^C\_{j=1}y\_jlog\hat y\_j$$
|
||||
|
||||
当 i 为样本真实类别,则有:
|
||||
|
||||
$$y\_j = 0, j \ne i$$
|
||||
|
||||
因此,损失函数可以简化为:
|
||||
|
||||
$$L(\hat y, y) = -y\_ilog\hat y\_i = log \hat y\_i$$
|
||||
|
||||
所有 m 个样本的**成本函数**为:
|
||||
|
||||
$$J = \frac{1}{m}\sum^m\_{i=1}L(\hat y, y)$$
|
||||
|
||||
### 梯度下降法
|
||||
|
||||
多分类的 Softmax 回归模型与二分类的 Logistic 回归模型只有输出层上有一点区别。经过不太一样的推导过程,仍有
|
||||
|
||||
$$dZ^{[L]} = A^{[L]} - Y$$
|
||||
|
||||
反向传播过程的其他步骤也和 Logistic 回归的一致。
|
||||
|
||||
### 参考资料
|
||||
|
||||
* [Softmax回归 - Ufldl](http://ufldl.stanford.edu/wiki/index.php/Softmax%E5%9B%9E%E5%BD%92)
|
||||
|
||||
## 深度学习框架
|
||||
|
||||
### 比较著名的框架
|
||||
|
||||
* Caffe / Caffe 2
|
||||
* CNTK
|
||||
* DL4J
|
||||
* Keras
|
||||
* Lasagne
|
||||
* mxnet
|
||||
* PaddlePaddle
|
||||
* TensorFlow
|
||||
* Theano
|
||||
* Torch
|
||||
|
||||
### 选择框架的标准
|
||||
|
||||
* 便于编程:包括神经网络的开发和迭代、配置产品;
|
||||
* 运行速度:特别是训练大型数据集时;
|
||||
* 是否真正开放:不仅需要开源,而且需要良好的管理,能够持续开放所有功能。
|
||||
|
||||
## Tensorflow
|
||||
|
||||
目前最火的深度学习框架大概是 Tensorflow 了。这里简单的介绍一下。
|
||||
|
||||
Tensorflow 框架内可以直接调用梯度下降算法,极大地降低了编程人员的工作量。例如以下代码:
|
||||
|
||||
```py
|
||||
import numpy as np
|
||||
import tensorflow as tf
|
||||
|
||||
cofficients = np.array([[1.],[-10.],[25.]])
|
||||
|
||||
w = tf.Variable(0,dtype=tf.float32)
|
||||
x = tf.placeholder(tf.float32,[3,1])
|
||||
# Tensorflow 重载了加减乘除符号
|
||||
cost = x[0][0]*w**2 + x[1][0]*w + x[2][0]
|
||||
# 改变下面这行代码,可以换用更好的优化算法
|
||||
train = tf.train.GradientDescentOptimizer(0.01).minimize(cost)
|
||||
|
||||
init = tf.global_variables_initializer()
|
||||
session = tf.Session()
|
||||
session.run(init)
|
||||
for i in range(1000):
|
||||
session.run(train, feed_dict=(x:coefficients))
|
||||
print(session.run(w))
|
||||
```
|
||||
|
||||
打印为 4.99999,基本可以认为是我们需要的结果。更改 cofficients 的值可以得到不同的结果 w。
|
||||
|
||||
上述代码中:
|
||||
|
||||
```py
|
||||
session = tf.Session()
|
||||
session.run(init)
|
||||
print(session.run(w))
|
||||
```
|
||||
|
||||
也可以写作:
|
||||
|
||||
```py
|
||||
with tf.Session() as session:
|
||||
session.run(init)
|
||||
print(session.run(w))
|
||||
```
|
||||
|
||||
with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等。
|
||||
|
||||
想了解更多 Tensorflow 有关知识,请参考[官方文档](https://www.tensorflow.org)。
|
||||
@@ -0,0 +1,44 @@
|
||||
# 神经网络简介
|
||||
|
||||
> 必须得明白,吴恩达在通过什么角度,构建神经网络的基础知识。
|
||||
|
||||
|
||||
## 什么是神经网络
|
||||
|
||||

|
||||
|
||||
* 输入层----隐藏层----输出层
|
||||
|
||||
* **向量化** 实现一个神经网络时,如果需要遍历整个训练集,并不需要直接使用 for 循环。采用向量化的方法代替for 循环
|
||||
* **计算过程**
|
||||
* 正向过程(forward pass)或者叫**正向传播步骤(forward propagation step)**
|
||||
* 反向过程(backward pass)或者叫**反向传播步骤(backward propagation step)**。
|
||||
|
||||
## 用神经网络进行监督学习
|
||||
|
||||
### 应用领域
|
||||
|
||||
* 房屋价格预测-ANN普通神经网络,多维度特征
|
||||
* 图像-CNN卷积神经网络,二维像素
|
||||
* 声音-RNN循环神经网络,一维实践序列
|
||||
* 翻译-RNNs循环神经网络
|
||||
|
||||
### 不同的神经网络
|
||||
|
||||

|
||||
|
||||
### 监督学习
|
||||
|
||||
* 结构化数据:数据库中的结构化数据。
|
||||
* 非结构化数据:声音、图像、文本。
|
||||
|
||||
## 深度学习的历史
|
||||
|
||||
### 原因
|
||||
* 更多的数据data
|
||||
* 更高的算力compute
|
||||
* 更复杂的算法algorithm
|
||||
|
||||
### 流程
|
||||
|
||||
idea--code--experiment---back to idea
|
||||
153
机器学习/吴恩达深度学习/学习笔记/Neural_Networks_and_Deep_Learning/01神经网络基础.md
Normal file
@@ -0,0 +1,153 @@
|
||||
# 神经网络基础
|
||||
|
||||
|
||||
|
||||
|
||||
## Logistic 回归
|
||||
|
||||
Logistic 回归是一个用于二分分类的算法。
|
||||
|
||||
Logistic 回归中使用的参数如下:
|
||||
|
||||
* 输入的特征向量:$x \in R^{n\_x}$,其中 ${n\_x}$是特征数量;
|
||||
* 用于训练的标签:$y \in 0,1$
|
||||
* 权重:$w \in R^{n\_x}$
|
||||
* 偏置: $b \in R$
|
||||
* 输出:$\hat{y} = \sigma(w^Tx+b)$
|
||||
* Sigmoid 函数:$$s = \sigma(w^Tx+b) = \sigma(z) = \frac{1}{1+e^{-z}}$$
|
||||
|
||||
为将 $w^Tx+b$ 约束在 [0, 1] 间,引入 Sigmoid 函数。从下图可看出,Sigmoid 函数的值域为 [0, 1]。
|
||||
|
||||

|
||||
|
||||
Logistic 回归可以看作是一个非常小的神经网络。下图是一个典型例子:
|
||||
|
||||

|
||||
|
||||
### 损失函数
|
||||
|
||||
**损失函数(loss function)**用于衡量预测结果与真实值之间的误差。
|
||||
|
||||
最简单的损失函数定义方式为平方差损失:$$L(\hat{y},y) = \frac{1}{2}(\hat{y}-y)^2$$
|
||||
|
||||
但 Logistic 回归中我们并不倾向于使用这样的损失函数,因为之后讨论的优化问题会变成非凸的,最后会得到很多个局部最优解,梯度下降法可能找不到全局最优值。
|
||||
|
||||
一般使用$$L(\hat{y},y) = -(y\log\hat{y})-(1-y)\log(1-\hat{y})$$
|
||||
|
||||
损失函数是在单个训练样本中定义的,它衡量了在**单个**训练样本上的表现。而**代价函数(cost function,或者称作成本函数)**衡量的是在**全体**训练样本上的表现,即衡量参数 w 和 b 的效果。
|
||||
|
||||
$$J(w,b) = \frac{1}{m}\sum_{i=1}^mL(\hat{y}^{(i)},y^{(i)})$$
|
||||
|
||||
## 梯度下降法(Gradient Descent)
|
||||
|
||||
函数的**梯度(gradient)**指出了函数的最陡增长方向。即是说,按梯度的方向走,函数增长得就越快。那么按梯度的负方向走,函数值自然就降低得最快了。
|
||||
|
||||
模型的训练目标即是寻找合适的 w 与 b 以最小化代价函数值。简单起见我们先假设 w 与 b 都是一维实数,那么可以得到如下的 J 关于 w 与 b 的图:
|
||||
|
||||

|
||||
|
||||
可以看到,成本函数 J 是一个**凸函数**,与非凸函数的区别在于其不含有多个局部最低点;选择这样的代价函数就保证了无论我们初始化模型参数如何,都能够寻找到合适的最优解。
|
||||
|
||||
参数 w 的更新公式为:
|
||||
|
||||
$$w := w - \alpha\frac{dJ(w, b)}{dw}$$
|
||||
|
||||
其中 α 表示学习速率,即每次更新的 w 的步伐长度。
|
||||
|
||||
当 w 大于最优解 w′ 时,导数大于 0,那么 w 就会向更小的方向更新。反之当 w 小于最优解 w′ 时,导数小于 0,那么 w 就会向更大的方向更新。迭代直到收敛。
|
||||
|
||||
在成本函数 J(w, b) 中还存在参数 b,因此也有:
|
||||
|
||||
$$b := b - \alpha\frac{dJ(w, b)}{db}$$
|
||||
|
||||
## 计算图(Computation Graph)
|
||||
|
||||
神经网络中的计算即是由多个计算网络输出的前向传播与计算梯度的后向传播构成。所谓的 **反向传播(Back Propagation)** 即是当我们需要计算最终值相对于某个特征变量的导数时,我们需要利用计算图中上一步的结点定义。
|
||||
|
||||
## Logistic 回归中的梯度下降法
|
||||
|
||||
假设输入的特征向量维度为 2,即输入参数共有 x1, w1, x2, w2, b 这五个。可以推导出如下的计算图:
|
||||
|
||||

|
||||
|
||||
首先反向求出 L 对于 a 的导数:
|
||||
|
||||
$$da=\frac{dL(a,y)}{da}=−\frac{y}{a}+\frac{1−y}{1−a}$$
|
||||
|
||||
然后继续反向求出 L 对于 z 的导数:
|
||||
|
||||
$$dz=\frac{dL}{dz}=\frac{dL(a,y)}{dz}=\frac{dL}{da}\frac{da}{dz}=a−y$$
|
||||
|
||||
依此类推求出最终的损失函数相较于原始参数的导数之后,根据如下公式进行参数更新:
|
||||
|
||||
$$w _1:=w _1−\alpha dw _1$$
|
||||
|
||||
$$w _2:=w _2−\alpha dw _2$$
|
||||
|
||||
$$b:=b−\alpha db$$
|
||||
|
||||
接下来我们需要将对于单个用例的损失函数扩展到整个训练集的代价函数:
|
||||
|
||||
$$J(w,b)=\frac{1}{m}\sum^m_{i=1}L(a^{(i)},y^{(i)})$$
|
||||
|
||||
$$a^{(i)}=\hat{y}^{(i)}=\sigma(z^{(i)})=\sigma(w^Tx^{(i)}+b)$$
|
||||
|
||||
我们可以对于某个权重参数 w1,其导数计算为:
|
||||
|
||||
$$\frac{\partial J(w,b)}{\partial{w\_1}}=\frac{1}{m}\sum^m_{i=1}\frac{\partial L(a^{(i)},y^{(i)})}{\partial{w\_1}}$$
|
||||
|
||||
|
||||
完整的 Logistic 回归中某次训练的流程如下,这里仅假设特征向量的维度为 2:
|
||||
|
||||

|
||||
|
||||
然后对 w1、w2、b 进行迭代。
|
||||
|
||||
上述过程在计算时有一个缺点:你需要编写两个 for 循环。第一个 for 循环遍历 m 个样本,而第二个 for 循环遍历所有特征。如果有大量特征,在代码中显式使用 for 循环会使算法很低效。**向量化**可以用于解决显式使用 for 循环的问题。
|
||||
|
||||
## 向量化(Vectorization)
|
||||
|
||||
在 Logistic 回归中,需要计算 $$z=w^Tx+b$$如果是非向量化的循环方式操作,代码可能如下:
|
||||
|
||||
```py
|
||||
z = 0;
|
||||
for i in range(n_x):
|
||||
z += w[i] * x[i]
|
||||
z += b
|
||||
```
|
||||
|
||||
而如果是向量化的操作,代码则会简洁很多,并带来近百倍的性能提升(并行指令):
|
||||
|
||||
```py
|
||||
z = np.dot(w, x) + b
|
||||
```
|
||||
|
||||
不用显式 for 循环,实现 Logistic 回归的梯度下降一次迭代(对应之前蓝色代码的 for 循环部分。这里公式和 NumPy 的代码混杂,注意分辨):
|
||||
|
||||
$$Z=w^TX+b=np.dot(w.T, x) + b$$
|
||||
$$A=\sigma(Z)$$
|
||||
$$dZ=A-Y$$
|
||||
$$dw=\frac{1}{m}XdZ^T$$
|
||||
$$db=\frac{1}{m}np.sum(dZ)$$
|
||||
$$w:=w-\sigma dw$$
|
||||
$$b:=b-\sigma db$$
|
||||
|
||||
正向和反向传播尽管如此,多次迭代的梯度下降依然需要 for 循环。
|
||||
|
||||
## 广播(broadcasting)
|
||||
|
||||
Numpy 的 Universal functions 中要求输入的数组 shape 是一致的。当数组的 shape 不相等的时候,则会使用广播机制,调整数组使得 shape 一样,满足规则,则可以运算,否则就出错。
|
||||
|
||||
四条规则:
|
||||
|
||||
1. 让所有输入数组都向其中 shape 最长的数组看齐,shape 中不足的部分都通过在前面加 1 补齐;
|
||||
2. 输出数组的 shape 是输入数组 shape 的各个轴上的最大值;
|
||||
3. 如果输入数组的某个轴和输出数组的对应轴的长度相同或者其长度为 1 时,这个数组能够用来计算,否则出错;
|
||||
4. 当输入数组的某个轴的长度为 1 时,沿着此轴运算时都用此轴上的第一组值。
|
||||
|
||||
## NumPy 使用技巧
|
||||
|
||||
转置对秩为 1 的数组无效。因此,应该避免使用秩为 1 的数组,用 n * 1 的矩阵代替。例如,用`np.random.randn(5,1)`代替`np.random.randn(5)`。
|
||||
|
||||
如果得到了一个秩为 1 的数组,可以使用`reshape`进行转换。
|
||||
|
||||
135
机器学习/吴恩达深度学习/学习笔记/Neural_Networks_and_Deep_Learning/02浅层神经网络.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# 浅层神经网络
|
||||
|
||||
## 神经网络表示
|
||||
|
||||
* ReLU,recfied linear unit修正线性单元
|
||||
|
||||
竖向堆叠起来的输入特征被称作神经网络的**输入层(the input layer)**。
|
||||
|
||||
神经网络的 **隐藏层(a hidden layer)** 。“隐藏”的含义是 **在训练集中** ,这些中间节点的真正数值是无法看到的。
|
||||
|
||||
**输出层(the output layer)** 负责输出预测值。
|
||||
|
||||

|
||||
|
||||
如图是一个**双层神经网络**,也称作**单隐层神经网络(a single hidden layer neural network)**。当我们计算网络的层数时,通常不考虑输入层,因此图中隐藏层是第一层,输出层是第二层。
|
||||
|
||||
约定俗成的符号表示是:
|
||||
|
||||
* 输入层的激活值为 $a^{[0]}$;
|
||||
* 同样,隐藏层也会产生一些激活值,记作 $a^{[1]}$
|
||||
隐藏层的第一个单元(或者说节点)就记作 $a^{[1]}_1$输出层同理。
|
||||
* 另外,隐藏层和输出层都是带有参数 W 和 b 的。它们都使用上标`[1]`来表示是和第一个隐藏层有关,或者上标`[2]`来表示是和输出层有关。
|
||||
|
||||
## 计算神经网络的输出
|
||||
|
||||

|
||||
|
||||
实际上,神经网络只不过将 Logistic 回归的计算步骤重复很多次。对于隐藏层的第一个节点,有
|
||||
|
||||
$$z _1^{[1]} = (W _1^{[1]})^TX+b _1^{[1]}$$
|
||||
|
||||
$$a _1^{[1]} = \sigma(z _1^{[1]})$$
|
||||
|
||||
我们可以类推得到,对于第一个隐藏层有下列公式:
|
||||
|
||||
$$z^{[1]} = (W^{[1]})^Ta^{[0]}+b^{[1]}$$
|
||||
|
||||
$$a^{[1]} = \sigma(z^{[1]})$$
|
||||
|
||||
其中,$a^{[0]}$可以是一个列向量,也可以将多个列向量堆叠起来得到矩阵。如果是后者的话,得到的 $z^{[1]}$和 $a^{[1]}$也是一个矩阵。
|
||||
|
||||
同理,对于输出层有:
|
||||
|
||||
$$z^{[2]} = (W^{[2]})^Ta^{[1]}+b^{[2]}$$
|
||||
|
||||
$$\hat{y} = a^{[2]} = \sigma(z^{[2]})$$
|
||||
|
||||
值得注意的是层与层之间参数矩阵的规格大小。
|
||||
|
||||
* 输入层和隐藏层之间:${(W^{[1]})}^T$的 shape 为`(4,3)`,前面的 4 是隐藏层神经元的个数,后面的 3 是输入层神经元的个数;$b^{[1]}$的 shape 为`(4,1)`,和隐藏层的神经元个数相同。
|
||||
* 隐藏层和输出层之间:${(W^{[2]})}^T$的 shape 为`(1,4)`,前面的 1 是输出层神经元的个数,后面的 4 是隐藏层神经元的个数;$b^{[2]}$的 shape 为`(1,1)`,和输出层的神经元个数相同。
|
||||
|
||||
## 激活函数
|
||||
|
||||
有一个问题是神经网络的隐藏层和输出单元用什么激活函数。之前我们都是选用 sigmoid 函数,但有时其他函数的效果会好得多。
|
||||
|
||||
可供选用的激活函数有:
|
||||
|
||||
* tanh 函数(the hyperbolic tangent function,双曲正切函数):
|
||||
|
||||
$$a = \frac{e^z - e^{-z}}{e^z + e^{-z}}$$
|
||||
|
||||
效果几乎总比 sigmoid 函数好(除开**二元分类的输出层**,因为我们希望输出的结果介于 0 到 1 之间),因为函数输出介于 -1 和 1 之间,激活函数的平均值就更接近 0,有类似数据中心化的效果。
|
||||
|
||||
然而,tanh 函数存在和 sigmoid 函数一样的缺点:当 z 趋紧无穷大(或无穷小),导数的梯度(即函数的斜率)就趋紧于 0,这使得梯度算法的速度大大减缓。
|
||||
|
||||
* **ReLU 函数(the rectified linear unit,修正线性单元)**:
|
||||
|
||||
$$a=max(0,z)$$
|
||||
|
||||
当 z > 0 时,梯度始终为 1,从而提高神经网络基于梯度算法的运算速度,收敛速度远大于 sigmoid 和 tanh。然而当 z < 0 时,梯度一直为 0,但是实际的运用中,该缺陷的影响不是很大。
|
||||
|
||||
* Leaky ReLU(带泄漏的 ReLU):
|
||||
|
||||
$$a=max(0.01z,z)$$
|
||||
|
||||
Leaky ReLU 保证在 z < 0 的时候,梯度仍然不为 0。理论上来说,Leaky ReLU 有 ReLU 的所有优点,但在实际操作中没有证明总是好于 ReLU,因此不常用。
|
||||
|
||||

|
||||
|
||||
在选择激活函数的时候,如果在不知道该选什么的时候就选择 ReLU,当然也没有固定答案,要依据实际问题在交叉验证集合中进行验证分析。当然,我们可以在不同层选用不同的激活函数。
|
||||
|
||||
### 使用非线性激活函数的原因
|
||||
|
||||
使用线性激活函数和不使用激活函数、直接使用 Logistic 回归没有区别,那么无论神经网络有多少层,输出都是输入的线性组合,与**没有隐藏层**效果相当,就成了最原始的感知器了。
|
||||
|
||||
### 激活函数的导数
|
||||
|
||||
* sigmoid 函数:
|
||||
|
||||
$$g(z) = \frac{1}{1+e^{-z}}$$
|
||||
|
||||
$$g\prime(z)=\frac{dg(z)}{dz} = \frac{1}{1+e^{-z}}(1-\frac{1}{1+e^{-z}})=g(z)(1-g(z))$$
|
||||
|
||||
* tanh 函数:
|
||||
|
||||
$$g(z) = tanh(z) = \frac{e^z - e^{-z}}{e^z + e^{-z}}$$
|
||||
|
||||
$$g\prime(z)=\frac{dg(z)}{dz} = 1-(tanh(z))^2=1-(g(z))^2$$
|
||||
|
||||
## 神经网络的梯度下降法
|
||||
|
||||
### 正向梯度下降
|
||||
|
||||
$$Z^{[1]}={(W^{[1]})}^TX+b^{[1]}$$
|
||||
|
||||
$$A^{[1]}=g^{[1]}(Z^{[1]})$$
|
||||
|
||||
$$Z^{[2]}={(W^{[2]})}^TA^{[1]}+b^{[2]}$$
|
||||
|
||||
$$A^{[2]}=g^{[2]}(Z^{[2]})=\sigma(Z^{[2]})$$
|
||||
|
||||
### 反向梯度下降
|
||||
|
||||
神经网络反向梯度下降公式(左)和其代码向量化(右):
|
||||
|
||||

|
||||
|
||||
## 随机初始化
|
||||
|
||||
如果在初始时将两个隐藏神经元的参数设置为相同的大小,那么两个隐藏神经元对输出单元的影响也是相同的,通过反向梯度下降去进行计算的时候,会得到同样的梯度大小,所以在经过多次迭代后,两个隐藏层单位仍然是对称的。无论设置多少个隐藏单元,其最终的影响都是相同的,那么多个隐藏神经元就没有了意义。
|
||||
|
||||
在初始化的时候,W 参数要进行随机初始化,不可以设置为 0。而 b 因为不存在对称性的问题,可以设置为 0。
|
||||
|
||||
以 2 个输入,2 个隐藏神经元为例:
|
||||
|
||||
```py
|
||||
W = np.random.rand(2,2)* 0.01
|
||||
b = np.zeros((2,1))
|
||||
```
|
||||
|
||||
这里将 W 的值乘以 0.01(或者其他的常数值)的原因是为了使得权重 W 初始化为较小的值,这是因为使用 sigmoid 函数或者 tanh 函数作为激活函数时,W 比较小,则 Z=WX+b 所得的值趋近于 0,梯度较大,能够提高算法的更新速度。而如果 W 设置的太大的话,得到的梯度较小,训练过程因此会变得很慢。
|
||||
|
||||
ReLU 和 Leaky ReLU 作为激活函数时不存在这种问题,因为在大于 0 的时候,梯度均为 1。
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
<h1 align="center">深层神经网络</h1>
|
||||
|
||||
## 深层网络中的前向和反向传播
|
||||
|
||||
### 前向传播
|
||||
|
||||
**输入**:$a^{[l−1]}$
|
||||
|
||||
**输出**:$a^{[l]}$,cache($z^{[l]}$)
|
||||
|
||||
**公式**:
|
||||
|
||||
$$Z^{[l]}=W^{[l]}\cdot a^{[l-1]}+b^{[l]}$$
|
||||
|
||||
$$a^{[l]}=g^{[l]}(Z^{[l]})$$
|
||||
|
||||
### 反向传播
|
||||
|
||||
**输入**:$da^{[l]}$
|
||||
|
||||
**输出**:$da^{[l-1]}$,$dW^{[l]}$,$db^{[l]}$
|
||||
|
||||
**公式**:
|
||||
|
||||
$$dZ^{[l]}=da^{[l]}*g^{[l]}{'}(Z^{[l]})$$
|
||||
|
||||
$$dW^{[l]}=dZ^{[l]}\cdot a^{[l-1]}$$
|
||||
|
||||
$$db^{[l]}=dZ^{[l]}$$
|
||||
|
||||
$$da^{[l-1]}=W^{[l]T}\cdot dZ^{[l]}$$
|
||||
|
||||
### 搭建深层神经网络块
|
||||
|
||||

|
||||
|
||||
神经网络的一步训练(一个梯度下降循环),包含了从 $a^{[0]}$(即 x)经过一系列正向传播计算得到 $\hat y$ (即 $a^{[l]}$)。然后再计算 $da^{[l]}$,开始实现反向传播,用**链式法则**得到所有的导数项,W 和 b 也会在每一层被更新。
|
||||
|
||||
在代码实现时,可以将正向传播过程中计算出来的 z 值缓存下来,待到反向传播计算时使用。
|
||||
|
||||
补充一张从 [Hinton、LeCun 和 Bengio 写的深度学习综述](https://www.cs.toronto.edu/~hinton/absps/NatureDeepReview.pdf)中摘下来的图,有助于理解整个过程:
|
||||
|
||||

|
||||
|
||||
## 矩阵的维度
|
||||
|
||||
$$W^{[l]}: (n^{[l]}, n^{[l-1]})$$
|
||||
|
||||
$$b^{[l]}: (n^{[l]}, 1)$$
|
||||
|
||||
$$dW^{[l]}: (n^{[l]}, n^{[l-1]})$$
|
||||
|
||||
$$db^{[l]}: (n^{[l]}, 1)$$
|
||||
|
||||
对于 Z、a,向量化之前有:
|
||||
|
||||
$$Z^{[l]}, a^{[l]}: (n^{[l]}, 1)$$
|
||||
|
||||
而在向量化之后,则有:
|
||||
|
||||
$$Z^{[l]}, A^{[l]}: (n^{[l]}, m)$$
|
||||
|
||||
在计算反向传播时,dZ、dA 的维度和 Z、A 是一样的。
|
||||
|
||||
## 使用深层表示的原因
|
||||
|
||||
对于人脸识别,神经网络的第一层从原始图片中提取人脸的轮廓和边缘,每个神经元学习到不同边缘的信息;网络的第二层将第一层学得的边缘信息组合起来,形成人脸的一些局部的特征,例如眼睛、嘴巴等;后面的几层逐步将上一层的特征组合起来,形成人脸的模样。随着神经网络层数的增加,特征也从原来的边缘逐步扩展为人脸的整体,由整体到局部,由简单到复杂。层数越多,那么模型学习的效果也就越精确。
|
||||
|
||||
同样的,对于语音识别,第一层神经网络可以学习到语言发音的一些音调,后面更深层次的网络可以检测到基本的音素,再到单词信息,逐渐加深可以学到短语、句子。
|
||||
|
||||
通过例子可以看到,随着神经网络的深度加深,模型能学习到更加复杂的问题,功能也更加强大。
|
||||
|
||||
## 参数和超参数
|
||||
|
||||
**参数**即是我们在过程中想要模型学习到的信息(**模型自己能计算出来的**),例如 $W^{[l]}$,$b^{[l]}$。而**超参数(hyper parameters)**即为控制参数的输出值的一些网络信息(**需要人经验判断**)。超参数的改变会导致最终得到的参数 $W^{[l]}$,$b^{[l]}$ 的改变。
|
||||
|
||||
典型的超参数有:
|
||||
|
||||
* 学习速率:α
|
||||
* 迭代次数:N
|
||||
* 隐藏层的层数:L
|
||||
* 每一层的神经元个数:$n^{[1]}$,$n^{[2]}$,...
|
||||
* 激活函数 g(z) 的选择
|
||||
|
||||
当开发新应用时,预先很难准确知道超参数的最优值应该是什么。因此,通常需要尝试很多不同的值。应用深度学习领域是一个很大程度基于经验的过程。
|
||||
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 374 KiB |
|
After Width: | Height: | Size: 187 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 204 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 53 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 106 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Sequence_Models/Attention-Model.png
Normal file
|
After Width: | Height: | Size: 223 KiB |
|
After Width: | Height: | Size: 80 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Sequence_Models/BRNN.png
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Sequence_Models/Beam-search.png
Normal file
|
After Width: | Height: | Size: 235 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Sequence_Models/Bleu-score-on-unigram.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Sequence_Models/CBOW.png
Normal file
|
After Width: | Height: | Size: 86 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Sequence_Models/CTC-for-speech-recognition.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Sequence_Models/Computing-attention.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Sequence_Models/DRNN.png
Normal file
|
After Width: | Height: | Size: 134 KiB |
|
After Width: | Height: | Size: 77 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Sequence_Models/Embedding-matrix.png
Normal file
|
After Width: | Height: | Size: 255 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Sequence_Models/Equalization.png
Normal file
|
After Width: | Height: | Size: 162 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Sequence_Models/Error-analysis-process.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 118 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Sequence_Models/Examples-of-Sequence-Model.png
Normal file
|
After Width: | Height: | Size: 289 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Sequence_Models/Image-captioning.png
Normal file
|
After Width: | Height: | Size: 236 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Sequence_Models/LSTM.png
Normal file
|
After Width: | Height: | Size: 158 KiB |
BIN
机器学习/吴恩达深度学习/学习笔记/Sequence_Models/Neural-language-model.png
Normal file
|
After Width: | Height: | Size: 276 KiB |