一、前言
本文主要分为 3 周分别了讲解其中视频讲到的难重点,第一周分为 2 个重要的部分:正则化和梯度检验。笔者将自己在学习过程中的不理解的地方记录下俩,希望能够帮助到各位读者,也希望文章有错漏的地方,还请各位读者海涵指正。
二、第一周——深度学习的使用方法
2.1 模型性能判断方法
还记得在西瓜书的第一章中,周志华老师就讲了可以使用测试集的性能来评估模型的预测性能,同时也说了模型的误差可以被分解为 偏差、方差、噪声这 3 个元素。
假设有训练集误差 E1
和 验证集E2
,那么通常的判断方法有 2 个:
- 高方差:E1低、E2高
- 高偏差:E1高、E2更高
PS:其实这里推荐大家去看吴恩达的机器学习公开课,那里对偏方差的讲解更好一点
那么如何解决因为这 2 个结果带来的影响呢? - 偏差:查看训练集的性能,如果此时偏差高一般选择新的网络
- 方差:查看验证集的性能,如果此时方差偏高可以通过增加训练数据或者正则化来降低
2.2 正则化
2.2.1 正则化基础
上面说到正则化可以降低方差,那么这一节来讲讲正则化。
我们一般会在损失函数中加入正则化项,一般的正则化项有 L1范数
和 L2范数
,其实分别对应的就是曼哈顿距离和欧式距离,读者自行百度就明白这 2 个范数的计算方式和表达方式了
假设我们使用欧式距离来作为正则化,那么损失函数可以就是:
其中,是正则化参数,是矩阵 W 的L2范数,作者这里说不加上 b 的原因是因为 b 的影响很小,可加可不加。
在神经网络中的损失函数中通过包含了第 1 层的到第 l 层的,参数同理,因为损失函数是以矩阵为单位来计算的,那么如果正则化项使用矩阵来表示的话是如下所示:
其中我们称为范数平方,被定义为矩阵中所有元素的平方和。
而矩阵的维度通常是(, ),这里对 n 定义不明的同学请看前面的文章,我们使用弗罗贝尼乌斯范数
来称呼矩阵的范数平方,并用下标著名,关于弗罗贝尼乌斯范数
可在参数小节中查阅
如果我们使用的是L2范数正则化,那么我们可以推导出一个L2正则化后的梯度公式。
首先我们在不加正则化项前提下,计算出的对导数成为,那么增加了正则化项的导数我们表示为,那么有如下式子:
最后有可得到
从上式可以明显看得出,使用了正则化之后的梯度公式比原来多了系数,该系数小于 1,也就是先让矩阵W缩小在去减去梯度,所以L2正则化也叫权重衰减
这里我们知道了如何进行L2正则化,但是从代码上看是怎么进行的呢?因为我们推出的公式无法直接用于代码,下面举个例子说明
比如我们在要计算第 3 层,那么第三层的正则化项是,那么在计算时我们就需要在等式后面加上
我们一般在验证集调试超参
2.2.1 正则化原理
我们可以直观的理解,当设置得足够大的时候,可以将矩阵W 衰减到足够小,假设此时使用的是tanh激活函数
,那么因为W矩阵很小,所以输出Z也很小。由tanh函数
的性质可知,如果输入是数值在很小的时候,相当于线性函数。而此时 Z 很小,那么此时激活函数相当于线性函数,多个线性函数叠加还是线性函数,所以此时模型拟合接近线性函数。
当模型在过拟合和线性函数之间存在一个适当的矩阵W使之拟合程度最为适合,所以这就可以正则化其效果的原理
2.2.2 dropout随机失活
dropout是一种类似正则化的手段,但它并不是通过增加正则项,而是通过其他的方法来使模型达到正则化的效果。
为了说明其步骤,视频中以某个神经网络的第 3 层为例子。
在每一轮的前向计算中,我们对每一层的生成一个随机矩阵,第 3 层我们假设随机生成了一个矩阵
d3 = np.random.rand(a3.shape[0], a3.shape[1])
该矩阵是一个只有 0 和 1 的矩阵,其中矩阵元素为 1 的概率是0.8, 为 0 的概率是 0.2,为超参 keep-porb 控制,那么在这里 keep-porb 等于 0.8
通过 d3 * a3,我们可以消去一些神经网络节点的输出,从而使得网络更加精简,从结论上看,假设为 1 的概率是0.8,那么相乘只有 a3也是原来的0.8倍,即 d3 * a3 可以看做是 0.8a3,为了消除对下一层的影响,我们需要继续使用 a3 /= 0.8(这里是0.8是keep-porb )
下层是z4 = w4 * a3 + b4,为了不影响 z4的期望值,即不想影响该层次的梯度下降,所以需要还原a3的值,不要让第三层加入dropout后影响该层的梯度
那么问题来了,刚刚说的是前向传播如何使用dropout,那么在后向传播dropout又该如何处理,其实是一样,我们只需要使用在前向传播中生成的随机二值矩阵来乘即可,然后再让
笔者在做作业的过程中发现如果按照给的keep-prob训练出来的模型准确率只有70%多,但在调整keep-prob在0.5以下的时候真确率提高到了90%,这可谓让笔者体验到了调参的重要性
要注意的是。在测试时不使用dropout。因为我们不期望输出的结果是随机,如果输出结果不是随机的,那么就不会影响预测。我们在前面 a3 /= 0.8是确保在测试时不执行dropout也能让激活函数的期望输出在不会发生变化,这样就不用在测试阶段添加额外的参数,这段话是视频中给出的,但比较晦涩
这里笔者说一下自己的通俗理解:笔者参考中《理解dropout》的说法,理解的dropout是让模型在训练时摆脱各个神经元之间的依赖性,不让模型的某个神经元只在特定的特征下起作用,这样就可以让每一个神经元都能够在所有的特征下都能起作用。那么这样的话,我们如果训练时加入了dropout,则无法体现出dropout的结果,因为测试时输出的跟训练时输出的一样
2.2.3 其他正则化方法
2.2.3.1 数据扩增
1、将图片水平翻转并加入训练集
2、随意缩放和裁剪图像并加入训练集
2.2.3.2 提前停止
在验证集是画出损失函数的下降图形,横轴是迭代次数,纵轴是损失函数,对训练集和验证集都画出图像,通常验证集是先降后升,我们可以在降到最低点时停止训练,此时获得一组参数W。但提前停止有缺点就是无法进行正交化
,正交化在后面会讲解到
2.3 归一化输入
我们先看看归一化输入的执行过程,我们知道执行过程后比较容易理解归一化的原理及作用
2.3.1 步骤
归一化输入的步骤有 2 个,设我们数据集如下
-
零均值化
第一步是对数据集进行零均值化,设有参数
接着我们对每一个训练数据进行减去该参数,即
其实就相当于移动数据集,使他们的均值为 0 ,也就是如下图
归一化方差
第二部就是归一化方差,设有参数
我们上面已经完成了零均值化,那么可以得到如下
从上式可知,是方差,然后我们让每一个数据都除以,得到:
需要注意,如果用来调整训练数据,那么用相同的 μ 和 σ^2来归一化测试集。当然归一化测试集使用的参数和都是从训练集得来的
2.3.2 原理
在不归一化数据的情况下,如果特征的范围是在[0, 1],而特征在[0, 1000]。那么训练出来的和的数量级就会相差非常远,从而看起来是类似的一个图形,图中的b和w应该分别是和
这样的话,如果我们学习率确定得不对,对模型的训练完全没有好处,比如有可能引起振荡之类的情况。
如果我们归一化数据集后可以得到如下的图像
无论在哪个点,只要我们设置的学习率不太奇怪,我们总能够找到最优点
2.4 梯度
这一节将的是梯度,梯度如果在训练不好的情况下虎发生梯度消失和梯度爆炸,如果不理解这 2 个概念可以参考链接《梯度消失和梯度爆炸》
这里简单说下引起梯度爆炸的 2 个原因
2.4.1 解决方法
初始化权值过大容易引起梯度爆炸,过小会引起梯度消失。
一般的,我们有公式如下:
当n越多时,也就是特征越多时,希望w越小
可以这样初始化,第 i 层一般有 个输入,我们可以用这样来初始化 W矩阵
WL = np.random.randn(shape) *
不同的激活函数有不同的初始化方法,对于tanh就有其他初始化公式 ,比如Xavier初始化
如果是ReLu,设置为 效果更好。此时也叫HE初始化
这2个初始化的作用十分明显,笔者目前上了尚未理解,后面理解了再来讲述
我们这里的随机分布一般使用的是高斯分布
当然了,
2.4.2 梯度检验
梯度检验是为了确保后向传播的计算是正确的,保证我们的参数能够完成优化 。
在讲梯度检验之前,先看看导数的单边公差跟双边公差
- 单边公差,公式如下:
- 双边公差,公式如下:
一般双边公差比单边公差更加接近梯度,在梯度检验时我们使用双边公差
进行梯度检验时,我们需要将矩阵和....和 转换为向量(视频中没有说到 b矩阵也需要转换,但这里必须的理解是需要转换b矩阵的)
那么损失函数将变成
在运算完后我们得到和...和,同样地我们需要将这些都转换为与同维度的向量,因为和的维度是一样的,b矩阵同理。
展开可得:
视频中没有说明如何转换,也没说明的具体公式是什么。举个例子说明一下笔者的理解:即和一起转换成,其余同理
那么对于每一个,我们去计算其双边公差:
所以计算出来的是一个向量。从前面我们已经转换出了,那么我们可以用L2范数的计算方式计算
加入的值小于或等于,那么说明梯度是正确的,加入大于这个数,那么我们应该注意梯度是否有问题,当然这里的笔者理解是一个经验数值,大家可以按照各自的情况进行判断
使用梯度检验时有一些注意事项 :
- 训练时不要使用梯度检验,它只用于调试
- 如果算法的梯度检验失败,检查所有项 ,如果 2 个向量之间值相差太大,要查看哪个 i 值相差最大
- 如果在梯度检验的过程中使用正则化,需要将正则项加入梯度检验中
- 梯度检验和dropout不能同时使用,因为dropuout会使代价函数很难计算,此时我们可以先将Keep-prob设置为1
- 在随机初始化进行梯度检验,再训练网络
2.4.3 转换方法
我们上面说过,需要将参数矩阵W和b转换为一个一维向量,但视频中没有提高如何转换吗,这里笔者从作业中看到转换的代码,如下
def dictionary_to_vector(parameters):
"""
Roll all our parameters dictionary into a single vector satisfying our specific required shape.
"""
keys = []
count = 0
for key in ["W1", "b1", "W2", "b2", "W3", "b3"]:
# flatten parameter
new_vector = np.reshape(parameters[key], (-1,1))
keys = keys + [key]*new_vector.shape[0]
if count == 0:
theta = new_vector
else:
theta = np.concatenate((theta, new_vector), axis=0)
count = count + 1
return theta, keys
可以很明显地看到,只是简单地讲参数展开为一维数据然后拼接起来
2.4.4 第一周作业注意事项
- 关于错误
因为库不兼容的原因,这里的作业画图时会出现错误
c of shape (1, 211) not acceptable as a color sequence for x with size 211, y with size 211
解决方法参考链接《课后作业错误解决》
- 二值化矩阵
在dropout阶段,我们需要生成二值矩阵,可以使用下面的语句来实现,这里的大概意思就是D1中的元素如果小于keep_prob的话为 0 ,否则为 1
np.where(D1 < keep_prob, 0, 1)
- relu导数
在这一周的课后作业中,给的代码使用了下面的语句来作为relu的导数
dZ2 = np.multiply(dA2, np.int64(A2 > 0))
其中 np.int64(A2 > 0) 应该是生成一个A2同纬度的矩阵,但是这个矩阵是A2中大于 0 的书保持不变,其余的数为 0
参考
弗罗贝尼乌斯范数:https://blog.csdn.net/david_jett/article/details/77040087
理解dropout:http://www.pianshen.com/article/4175293217/
梯度消失和梯度爆炸:https://www.cnblogs.com/XDU-Lakers/p/10553239.html
课后作业错误解决:https://www.cnblogs.com/buchiyudemao/p/9028704.html