- 数据集
深度学习是基于经验的,即使是经验丰富的专家也很难再项目开始的时候就能够确定最优参数,比如神经网络的层数,每层的单元数,每层的激活函数,学习速率等,一般是先选择一个简单的模型,通过不断的迭代来修改各参数,直到最优解。
法则一:一般在项目中会把数据集分成三份:
训练集(training set):用于模型训练
验证集(developing set/dev set):用于交叉验证
测试集(test set):模型确定后,用来检测模型
规模小的数据量一般按照比例 7/3或者6/2/2来划分数据集
对于大数据,数据量越大,训练集占得比重应该越大,比如对于百万级的数据集,其比例可以是98/1/1,对于更大的数据集,其比例可以增加到99.5/0.25/0.25或99.5/0.4/0.1(因为验证集用来验证各种方法哪个更好,所以其所需数据可以比测试集大一些)。
法则二:验证集和测试集要来自同一分布(dev set and test set come from same distribution)
由于深度学习需要大量的数据,数据的来源可能五花八门,有的可能来自网页抓取甚至人工合成,这就导致了训练集可能跟验证集和测试集来自不同的分布,但是只要保证验证集和测试集来自同一分布,算法就会变得很快,后续课程还会给出更详细的解释
法则三:没有测试集也可以
测试集的作用是对最终模型做出无偏估计(unbias estimate),如果不需要无偏估计也可以没有测试集
2. Bias vs Variance(偏差和方差)
借用一张图来说明
最优误差又被称为贝叶斯误差,这里没有详细讲解
假设基本误差很小,而且训练集和验证集样本来自同一分布,有:
训练集误差小,而验证集误差大,一般方差高,过拟合;
训练集误差大,验证集的误差跟训练集误差相近,一般偏差高,欠拟合;
训练集误差大,验证集误差更大,一般既偏差高又方差高,可能部分欠拟合部分过拟合
对于新建立的模型:
首先查看偏差,如果模型偏差较高,那么可以尝试一个更复杂的网络,比如更多的隐藏层、更多的隐藏单元、用更多的时间来训练模型(或新的神经网络架构,这部分在后面会介绍,加括号的意思是这种方法有时候有用有时候没有,不过值得一试),直至偏差调至可接受范围;
其次查看方差,如果方差较高,那么可以尝试更多的数据、正则化、(新的神经网络架构),直至调整至低偏差和低方差。
Bias-variance tradeoff(偏差与方差权衡)
通常减少偏差很可能增加方差,而减少方差又很可能增加偏差,但是在大数据时代,在神经网络比较大数据量也很大的时候(正则适度的情况下),通常可以做到减少偏差或方差而不影响另一方,这是深度学习对监督学习大有裨益的一个重要原因。
3. 正则化Regularization
1)对于逻辑回归来说:
L2 Regularization:因为其用的是参数的欧几里得范数,欧几里得范数又被称为2-范数,一般更倾向于用L2正则化;
L1 Regularization:采用向量的L1范数|W|,如果用L1正则化,得到的W是稀疏的,也就是向量W
里面会有很多0,有人说这有利于压缩模型,但是实际上并没有降低太多内存,而且正则化的目的并不是压缩模型。
正则化是对参数正则化,可以对W和b正则化,也可以只对W正则化,因为W包含了绝大多数的参数。
lambda被称为正则化参数,在python里面lambda是一个预留字段,所以编程时一般用lambd来命名。
2)对于神经网络来说:
Frobenius norm(弗罗贝尼乌斯范数):表示一个矩阵中所有元素的平方和,与L2算法一样,但是由于统计学的某些原因下标为F,原因有待发掘。
3)为什么L2正则化被称为权重衰减?
应用L2正则化之后,W[l]变成了(1-α*λ/m)W[l],即乘了一个小于1的系数
4)为什么正则化可以防止过拟合?
解释一:如果λ设置的足够大,那么权重矩阵W就会接近于0,那么就相当于消除了隐藏层内多于1个的其他隐藏单元的影响,大大简化了神经网络,可能导致神经网络从过拟合到欠拟合,不过只要调整λ到一个合适的值,可以实现防止过拟合却也不至于欠拟合的刚刚好的状态。
解释二:对于激活函数tanh,λ越大W越小,那么Z就越小(忽略b的影响),实际上Z的取值范围很小,tanh会相对呈线性(上图红色近线性区域),那么整个网络的计算也是近似线性而非非常复杂的高度非线性函数,从而不会发生过拟合。
5)正则化后梯度下降注意事项
梯度下降时若构造成本函数和迭代次数的曲线图,会发现成本函数随迭代次数增加而下降,在正则化后,成本函数加了正则化项,所以在构建学习曲线的时候要用加了正则化项的成本函数,如果用原来的成本函数,则曲线不一定是下降的。
4. Dropout正则化(随机失活)
1)原理:随机删除神经网络单元,虽然做法有点疯狂但是确实有效,具体做法是对神经网络的各个单元,以抛硬币的方式来决定其去留,这样会大大简化神经网络,对简化后的神经网络进行训练。
2)如何实施Dropout正则化?
Inverted dropout(反向随机失活)--目前应用最广泛的dropout正则化方法
keep-prob可以理解为保留概率,即超过这个概率的单元保留,而小于这个概率的单元被移除。不同层的keep-prob也可以不同,一般取决于该层W的维数,W维数越高,代表单元数越多,过拟合的可能性就打,那么就可以多删除一些,keep-prob就要小一些,反之亦然,对于单元很少的隐藏层,比如只有1个或2个单元,基本不会导致过拟合,其keep-drop可以设置为1。输入层的keep-drop一般为1,也可以设置其他值比如0.9,因为一般很少删掉输入层的数据,所以这个值一般不会太小如0.5。不同层用不同的keep-drop值可以使正则化更灵活,但是也带来一个问题,如此多的keep-drop参数,每一个参数都需要用交叉验证来确定,那么工作量将会非常大,还有一种选择就是整个系统统一采用一个keep-drop参数。
a3/=keep-prob; 这一步是反向随机失活的关键,其作用在于保持a3的期望值,因为小于keep-prob的单元被移除了,相当于损失了(1-keep-prob)%的值,若要不影响a3以及后续z4、a4的期望值,那么这里需要修正或弥补a3的损失。
这里介绍的是foreprop,即前向传播的随机失活,对于反向传播的随机失活backprop需要自己推导
向量d或d3,他决定第三层中哪些单元归零(both foreprop and backprop),对每一层以及每一次迭代,既可以用相同的d也可以用不同的d,即可以保持让相同的单元被移除,也可以设置让不同的单元被移除。
测试的时候不需要dropout正则化,按照正常步骤测试即可。
3)为什么dropout正则化会有效果?
第一种理解:Dropout通过每次迭代时,神经网络都会变得比以前小,使用一个更小的神经网络看起来和正则化的效果是一样的。
第二种理解:从单个神经元的角度,神经元的作用是接收输入并生成一些有意义的输出,而通过dropout,神经元会被随机删除,也就是当前神经元不能依赖任一输入神经元,所以不会给任何一个输入加上太多权重,因此单元将通过这种方式积极的传播开,并为其每个输入单元各加适量权重,通过传播所有的权重,dropout将产生压缩权重的平方范数(squared norm of the weight)的效果,这就跟L2 Regularization类似,通过压缩权重,防止过拟合,但L2对不同权重的衰减是不同的,取决于倍增激活函数的大小。
drop-out正则化的作用是预防过拟合,所以除非过拟合,一般不会应用drop-out正则化,而dropout主要应用于计算机视觉,因为在这个领域通常数据量不足够大,且输入层的维度很高,容易存在过拟合的问题。
dropout的一个缺点就是成本函数J不再被明确定义,因为每次迭代都会随机删除一些节点,成本函数的计算变得非常困难,所以绘制成本函数和迭代次数的曲线图就非常困难了,通常的做法是先关掉dropout函数(将keep-drop设置为1),运行代码,确保成本函数是单调递减的,然后在打开dropout函数
5. 其他正则化方法
神经网络中出了L2正则化和drop-out正则化,还有几种方法可以有效防止过拟合
1)扩增数据
如果扩增数据的代价太大或很难完成,可以考虑增加这样的数据,比如对于图像数据来说,水平或其他角度旋转(一般不要上下翻转)、缩放、裁剪、扭曲(对于数字识别可以这样做)等,这样做虽然没有重新收集数据效果好,但是这样既节省花费也能有效预防过拟合,性价比不要太高。
2)Early stopping
在梯度下降中,一般会绘制成本函数和迭代次数的曲线,在early-stopping中需要加上验证集误差Jdev,成本函数应该是单调递减,而验证集误差一般是先下降后上升,一旦验证集误差开始上升,就可以停止梯度下降,选择验证集误差最小的点,既可以认为是最优解。
优点:只运行一次梯度下降,就能找到合适的参数。
缺点:机器学习的步骤中,其中之一是选择一个算法来优化代价函数J(成本函数),如梯度下降、momentum、RMSprop、Adam等;优化代价函数之后又不想过拟合,这里也有一些工具如L2正则化、数据扩增等。在机器学习中我们已经有很多超参数要选择,要在这么多算法中选出最合适的算法也变得越来越复杂,所以为了能让问题变得简单点,当我们用工具优化代价函数J的时候,只关心w和b,使得J越小越好,只要想办法减小J,其他的不用管;而防止过拟合呢,用另外一套工具来实现。也就是一个时间只做一件事,这种思路被称为正交化。而early-stopping却在同一时间将这两件事做了,使得需要考虑的问题更为复杂,而过早的停止迭代,便停止了降低代价函数J的尝试,可能使得代价函数不够小。
L2正则化优缺点:需要尝试大量不同的正则化参数lamda的值,计算代价较高,训练神经网络的时间更长,但超参数的搜索空间会更易于分解也更容易搜索。
通常来说L2正则化应用更广。
6. normalizing input(归一化输入)
1)归一化输入需要两步:
-1-均值归零(零均值化):x=x-μ(μ是均值)
-2-归一化方差:x=x/δ2 (δ2是均方差,因为x已经被零均值化了)
需要注意的是,对于训练集、验证集以及测试集,都需要用由训练集获得的μ以及δ2进行数据转换。
2)为什么要归一化输入数据?
如果输入数据的特征值取值范围相差较大,会导致对应的参数w也会相差较大,代价函数的轮廓是狭长的椭圆,就必须使用一个比较小的学习比率,来避免J发生震荡,如果梯度下降的起始值在椭圆的长轴一头,那么可能就需要更多次迭代才能找到最小值;均值归一化之后的代价函数的轮廓更接近圆,那么不论从哪个位置开始,都能比较直接的找到最小值,就可以在梯度下降中使用较大的步长,从而更快的找到最小值。总的来说就是特征值取值范围越相似,代价函数就会更圆,就更容易优化。
3)什么时候用?
一般用于特征值取值范围相差较大的时候,这样会显著提高优化速度,但如果特征值取值范围相差不大,进行均值归一化也没什么坏处,所以若没法确定是否该进行均值归一化的时候,那就均值归一化吧。
7. vanishing/exploding gradients梯度消失与梯度爆炸
1)神经网络中,由于权重的叠加效应,激活函数以及梯度都会随着层数的增加而呈指数增长(或降低),当层数较大时,激活函数或梯度就容易出现爆炸或消失的情况。
2)怎么办?
目前虽然没有一个完整的方案可以彻底解决梯度消失或爆炸的情况,但可以通过对权重初始化的优化来改善它,输入层神经单元越多,那么得到的z就越大,为了防止梯度消失或爆炸,可以使其权重除以输入层神经单元n[l-1]的个数(在初始化时),这样新得到的z就不会变化过大。具体的对于不同激活函数,人们研究了其对应的最优值:
8. Gradient Checking梯度检验
1)Numerical approximation of gradients梯度的数值逼近
双边误差(two-sided difference)的值近似导数值(其实导数的定义就是双边误差的极限),所以可以利用这一特性,检查梯度的正确性。
上图函数g是函数f的一阶导数
2)梯度检验
可以通过梯度检验来检查backprop的实施是否正确
梯度检查首先要做的是分别将W[1],b[1],⋯,W[L],b[L]这些矩阵构造成一维向量,然后将这些一维向量组合起来构成一个更大的一维向量θ。这样cost function J(W[1],b[1],⋯,W[L],b[L])就可以表示成J(θ)。
然后将反向传播过程通过梯度下降算法得到的dW[1],db[1],⋯,dW[L],db[L]按照一样的顺序构造成一个一维向量dθ。dθ的维度与θ一致。
接着利用J(θ)对每个θi计算近似梯度,其值与反向传播算法得到的dθi相比较,检查是否一致。例如,对于第i个元素,近似梯度为:
计算完所有θi的近似梯度后,可以计算dθapprox与dθ的欧氏(Euclidean)距离来比较二者的相似度。公式如下:
一般来说,如果欧氏距离越小,例如10−7,甚至更小,则表明dθapprox与dθ越接近,即反向梯度计算是正确的,没有bugs。如果欧氏距离较大,例如10−5,则表明梯度计算可能出现问题,需要再次检查是否有bugs存在。如果欧氏距离很大,例如10−3,甚至更大,则表明dθapprox与dθ差别很大,梯度下降计算过程有bugs,需要仔细检查。
3)梯度检查的使用技巧及注意事项
--不要在训练过程使用梯度检查!!!因为梯度检查计算量大耗时长,所以一般只在debug的时候使用。
--如果梯度检查失败,那么需要检查所有项,并试着找出bug!! 通过比较dθapprox与dθ,找到差异较大的dθ[i],检查其计算导数的过程是否有bug
--如果梯度检查中有正则化项,一定要记得正则化项!! 即如果对成本函数进行了正则化,梯度千万不要忘记正则化项。
--梯度检查不能与dropout同时使用!!
--随机初始化之后进行梯度检查,反复训练网络之后,再重新进行梯度检查(不常用)