1. 数据集划分
对于一个需要解决的问题的样本数据,在建立模型的过程中,数据会被划分为以下几个部分:
- 训练集(train set):用训练集对算法或模型进行训练过程;
- 验证集(development set):利用验证集(又称为简单交叉验证集,hold-out cross validation set)进行交叉验证,选择出最好的模型;
- 测试集(test set):最后利用测试集对模型进行测试,获取模型运行的无偏估计(对学习方法进行评估)。
在小数据量的时代,如 100、1000、10000 的数据量大小,可以将数据集按照以下比例进行划分:
- 无验证集的情况:70% / 30%;
- 有验证集的情况:60% / 20% / 20%;
而大数据时代,验证集和测试集所占的比重会趋向于变得更小。
- 100 万数据量:98% / 1% / 1%;
- 超百万数据量:99.5% / 0.25% / 0.25%(或者99.5% / 0.4% / 0.1%)
验证集的目的是为了验证不同的算法哪种更加有效,所以验证集只要足够大到能够验证大约 2-10 种算法哪种更好;测试集的主要目的是评估模型的效果,是对最终所选定的神经网络系统做出无偏估计,如在单个分类器中,往往在百万级别的数据中,我们选择其中 1000 条数据足以评估单个模型的效果。
建议验证集要和训练集来自于同一个分布(数据来源一致),可以加速神经网络的集成,也可以更有效地衡量算法的偏差和方差,从而更高效地选择合适方法来优化算法
如果不需要用无偏估计来评估模型的性能,可以不需要测试集。只要在训练集上训练,尝试不同的模型框架,在验证集上评估这些模型,然后迭代并选出适用的模型。因为验证集中已经涵盖测试集数据,其不再提供无偏性能评估
2. 偏差和方差
泛化误差可分解为偏差、方差与噪声之和:
- 偏差:度量了学习算法的期望预测与真实结果的偏离程度,即刻画了学习算法本身的拟合能力;
- 方差:度量了同样大小的训练集的变动所导致的学习性能的变化,即刻画了数据扰动所造成的影响;
- 噪声:表达了在当前任务上任何学习算法所能够达到的期望泛化误差的下界,即刻画了学习问题本身的难度。
泛化性能是由学习算法的能力、数据的充分性以及学习任务本身的难度所共同决定的。给定学习任务,为了取得好的泛化性能,则需要使偏差较小,即能够充分拟合数据,并且使方差较小,即使得数据扰动产生的影响小。
- 在欠拟合(underfitting)的情况下,或高偏差(high bias)的情况,即不能很好地对数据进行分类。
- 当模型设置的太复杂时,训练集中的一些噪声没有被排除,使得模型出现过拟合(overfitting)的情况,在验证集上出现高方差(high variance)的现象。
当训练出一个模型以后,如果:
- 训练集的错误率较小,而验证集的错误率却较大,说明模型存在较大方差,可能出现了过拟合;
- 训练集和验证集的错误率都较大,且两者相当,说明模型存在较大偏差,可能出现了欠拟合;
- 训练集错误率较大,且验证集的错误率远较训练集大,说明方差和偏差都较大,模型很差;
- 训练集和验证集的错误率都较小,且两者的相差也较小,说明方差和偏差都较小,这个模型效果比较好。
- 最优误差通常也称为“贝叶斯误差”,是理论上的误差下界
如果存在高偏差:
- 扩大网络规模,增加神经网络的隐藏层个数、神经元个数
- 训练时间延长
- 选择其它更复杂的NN模型等
如果存在高方差:
- 增加训练样本数据
- 进行正则化Regularization
- 选择其他更复杂的NN模型
4. 正则化(Regularization)
L2正则化,使用了欧几里德法线,被称为向量参数w的L2范数- 通常w是一个高维参数矢量,几乎涵盖所有参数,已经可以表达高偏差问题,所以参数很大程度上由w决定,
- b只是众多参数中的一个,改变b值对整体模型影响较小,所以通常省略不计。如果加了参数b,也没太大影响
深度学习模型中,L2正则化也叫权重衰减,可以预防过拟合,表达式为:
- 该矩阵范数被称为弗罗贝尼乌斯范数(Frobenius Norm),计算所有元素平方和再开方,所以神经网络中的正则化项被称为弗罗贝尼乌斯范数矩阵
- 正则化因子设置的足够大的情况下,为了使成本函数最小化,权重矩阵 W 就会被设置为接近于 0 的值,直观上相当于消除了很多神经元的影响,那么大的神经网络就会变成一个较小的网络。当然,实际上隐藏层的神经元依然存在,但是其影响减弱了,便不会导致过拟合。
- 在权值变小之下,输入样本 X 随机的变化不会对神经网络模造成过大的影响,神经网络受局部噪音的影响的可能性变小。这就是正则化能够降低模型方差的原因
L1正则化,称为参数向量w的L1范数,无论分母是m还是2m,它都是一个比例常量
- L1正则化,w最终会是稀疏的,也就是说w向量中有很多0,虽然L1正则化使模型变得稀疏,却没有降低太多存储内存
- 实际上L1 regularization在解决high variance方面比L2 regularization并不更具优势。而且,L1的在微分求导方面比较复杂
5. dropout正则化
Dropout是指在深度学习网络的训练过程中,对于每层的神经元,按照一定的概率将其暂时从网络中丢弃。即每次训练时,每一层都有部分神经元不工作,起到简化复杂网络模型的效果,从而避免发生过拟合
Inverted dropout(反向随机失活):假设对于第l层神经元,设定保留神经元比例概率keep_prob=0.8,即该层有20%的神经元停止工作。dl为dropout向量,设置dl为随机vector,其中80%的元素为1,20%的元素为0keep_prob = 0.8 # 设置神经元保留概率 dl = np.random.rand(al.shape[0], al.shape[1]) < keep_prob al = np.multiply(al, dl) al /= keep_prob
scale up: al /= keep_prob
是因为a[l]中的一部分元素失活(相当于被归零),为了在下一层计算时不影响Z[l+1]=W[l+1]a[l]+b[l+1]=的期望值,因此除以一个keep_prob
。
对于m个样本,单次迭代训练时,随机删除掉隐藏层一定数量的神经元;然后,在删除后的剩下的神经元上正向和反向更新权重w和常数项b;接着,下一次迭代中,再恢复之前删除的神经元,重新随机删除一定数量的神经元,进行正向和反向更新w和b。不断重复上述过程,直至迭代训练完成
使用dropout需要注意:
- 不同隐藏层的dropout系数keep_prob可以不同。
- 一般来说,神经元较少的层,
keep_prob
设的大一些如0.8-1,而神经元多的层则会设置比较小的keep_prob
- 越容易出现overfitting的隐藏层,其keep_prob就设置的相对小一些
- 实际应用中,不建议对输入层进行dropout
- 如果担心某些层比其它层更容易发生过拟合,可以把某些层的keep-prob值设置得比其它层更低,缺点是为了使用交叉验证,要搜索更多的超级参数
- 加入了 dropout 后,每次丢掉一定数量的隐藏层神经元,相当于在不同的神经网络上进行训练,这样就减少了神经元之间的依赖性,即每个神经元不能依赖于某几个其他的神经元(指层与层之间相连接的神经元),使神经网络更加能学习到与其他神经元之间的更加健壮的特征
- dropout 的一大缺点是成本函数无法被明确定义。因为每次迭代都会随机消除一些神经元结点的影响,因此无法确保成本函数单调递减。因此,使用 dropout 时,先将
keep_prob
全部设置为 1.0 后运行代码,确保 J(w,b)函数单调递减,再打开 dropout。 - 在测试阶段不要使用 dropout,因为那样会使得预测结果变得随机
6. 其他正则化方法
机器学习训练模型有两个目标:一是优化cost function,尽量减小J;二是防止过拟合。这两个目标彼此对立的,即减小J的同时可能会造成过拟合,反之亦然。二者之间的关系称为正交化orthogonalization
- 数据扩增(Data Augmentation):通过图片的一些变换(翻转,局部放大后切割等),得到更多的训练集和验证集。
- 早停止法(Early Stopping):通过减少迭代训练次数来防止过拟合,将训练集和验证集进行梯度下降时的成本变化曲线画在同一个坐标轴内,当训练集误差降低但验证集误差升高,两者开始发生较大偏差时及时停止迭代,并返回具有最小验证集误差的连接权和阈值,以避免过拟合。这种方法的缺点是无法同时达成偏差和方差的最优。
7. 标准输入
假若输入特征分布极不平衡,训练集得到的权重在数量级上有很大差别,导致梯度下降时,为避免代价函数发生震荡,只能选择很小的学习因子,进行标准归一化使得器代价函数分布较为平滑,不会出现极陡峭的梯度,学习因子也可以选的大一些便于训练,保证了代价函数的单调下降
原因:对输入进行标准化操作,是为了让所有输入归一化在同样的尺度上,方便进行梯度下降算法时能够更快更准确地找到全局最优解
方式:
8.梯度消失和梯度爆炸(Vanishing / Exploding gradients)
训练一个层数非常多的神经网络时,计算得到的梯度可能非常小或非常大,甚至是指数级别的减小或增大,导致输出呈指数型减小或增大,成为梯度消失和梯度爆炸
利用 Xavier initialization初始化缓解梯度消失和爆炸:
#tanh, Xavier initialization w[l] = np.random.randn(n[l],n[l-1])*np.sqrt(1/n[l-1]) #relu, He Initialization w[l] = np.random.randn(n[l],n[l-1])*np.sqrt(2/n[l-1]) #other w[l] = np.random.randn(n[l],n[l-1])*np.sqrt(2/(n[l-1] + n[l]))
9. 梯度检验
注意事项:
- 只在调试时使用梯度检验,训练中不使用;否则训练梯度下降时每次都要检验,速度太慢
- 如果算法的梯度检验失败,要检查所有项,并试着找出 bug,即确定哪个 dθapprox[i] 与 dθ 的值相差比较大
- 进行梯度检验时,当成本函数包含正则项时,也需要带上正则项进行检验
- 梯度检验不能与随机失活(dropout) 一起使用。因为每次迭代过程中,dropout 会随机消除隐藏层单元的不同子集,难以计算 dropout 在梯度下降上的成本函数 J。建议关闭 dropout,用梯度检验进行双重检查,确定在没有 dropout 的情况下算法正确,然后打开 dropout;