深度学习的实用层面
1. 训练,验证,测试集
深度学习是一个典型的迭代过程,迭代的效率很关键,创建高质量的训练数据集,验证集和测试集有助于提高循环效率。
-
三者区别:
训练集(train set) —— 用于模型拟合的数据样本。
验证集(development set)—— 是模型训练过程中单独留出的样本集,用于调整模型的超参数以及对模型的能力进行初步评估。通常用来在模型迭代训练时,用以验证当前模型泛化能力(准确率,召回率等),以决定是否停止继续训练。
测试集(test set) —— 用来评估模最终模型的泛化能力。但不能作为调参、选择特征等算法相关的选择的依据。 -
切分标准:
小数据量时代,常见做法是三七分,70%验证集,30%测试集;也可以 60%训练,20%验证和20%测试集来划分。大数据时代,数据量可能是百万级别,验证集和测试集占总量的比例会趋于变得更小。 -
数据来源:
最好要确保 验证集 和 测试集 的数据来自同一分布,因为要用验证集来评估不同的模型,如果验证集和测试集来自同一个分布就会表现很好。
2. 偏差,方差
关键数据:
训练集误差、验证集误差(基于人眼辨别错误率 ≈ 0情况下)
如果人眼辨别的错误率(贝叶斯误差,最优误差)非常高,比如15%。那么上面第二种分类器(训练误差15%,验证误差16%),15%的错误率对训练集来说也是非常合理的,偏差不高,方差也非常低。
解决方案:(TODO)
解决高方差:获得更多的训练样本;尝试减少特征的数量;尝试增加正则化程度 λ λ λ。
解决高偏差:尝试获得更多的特征;尝试增加多项式特征;尝试减少正则化程度 λ λ λ。
3. 机器学习基础
4. 正则化
正则化有助于防止过拟合,降低方差。
范数 (norm) 几种范数的简单介绍、对于L1和L2正则化的不同解释
-
L1 范数: ∥ X ∥ 1 = ∑ i = 1 n ∣ x i ∣ \|X\|_{1}=\sum_{i=1}^{n}\left|x_{i}\right| ∥X∥1=∑i=1n∣xi∣ 表示非零元素的绝对值之和;
-
L2 范数: ∥ X ∥ 2 = ∑ i = 1 n x i 2 \|X\|_{2}=\sqrt{\sum_{i=1}^{n} x_{i}^{2}} ∥X∥2=∑i=1nxi2 表示元素的平方和再开方。
-
矩阵的L2范数叫做:弗罗贝尼乌斯范数,所有元素的平方和 ∥ W ∥ F 2 \|W\|_{F}^{2} ∥W∥F2
加上正则化的损失函数:
L
1
正
则
化
:
J
(
ω
,
b
)
=
1
m
∑
i
=
1
m
L
(
y
^
(
i
)
,
y
(
i
)
)
+
λ
2
m
∥
ω
∥
1
L
2
正
则
化
:
J
(
ω
,
b
)
=
1
m
∑
i
=
1
m
L
(
y
^
(
i
)
,
y
(
i
)
)
+
λ
2
m
∥
ω
∥
2
2
\begin{aligned} \mathrm{L}1正则化: J(\omega,b)=\frac{1}{m} \sum_{i=1}^{m} \mathcal{L}\left(\hat{y}^{(i)},y^{(i)}\right)+\frac{\lambda}{2 m}\|\omega\|_{1} \\ \mathrm{L}2正则化: J(\omega,b)=\frac{1}{m} \sum_{i=1}^{m} \mathcal{L}\left(\hat{y}^{(i)},y^{(i)}\right)+\frac{\lambda}{2 m}\|\omega\|_{2}^{2} \end{aligned}
L1正则化:J(ω,b)=m1i=1∑mL(y^(i),y(i))+2mλ∥ω∥1L2正则化:J(ω,b)=m1i=1∑mL(y^(i),y(i))+2mλ∥ω∥22
L1正则化 & L2正则化的特征:
- L1 正则,权重 w \mathrm{w} w 最终变得稀疏,多数变成 0;
- L2 正则,使得权重衰减。
对于在神经网络W矩阵中进行参数更新操作: W [ l ] : = ( 1 − α λ m ) ∗ W [ l ] − α ( 梯度 ) W^{[l]}:=\left(1-\frac{\alpha \lambda}{m}\right) * W^{[l]}-\alpha(\text { 梯度 }) W[l]:=(1−mαλ)∗W[l]−α( 梯度 ),权重不但减少了,还乘以了小于1的系数进行衰减。
5. 为什么正则化预防过拟合
J
(
ω
,
b
)
=
1
m
∑
i
=
1
m
L
(
y
^
(
i
)
,
y
(
i
)
)
+
λ
2
m
∥
ω
∥
2
2
J(\omega,b)=\frac{1}{m} \sum_{i=1}^{m} \mathcal{L}\left(\hat{y}^{(i)},y^{(i)}\right)+\frac{\lambda}{2 m}\|\omega\|_{2}^{2}
J(ω,b)=m1i=1∑mL(y^(i),y(i))+2mλ∥ω∥22
当
λ
\lambda
λ 设置的很大的时候,最终
W
W
W 会变得很接近于 0,神经网络中的很多单元的作用变得很小,整个网络越来越接近逻辑回归。
λ 增大时,整个神经网络会计算离线性函数近的值,这个线性函数非常简单,不是复杂的高度非线性函数,不会发生过拟合。
L2 正则化是训练深度学习模型时最常用的一种方法。
6. dropout(随机失活)正则化
以上是一个样本的过程,其他样本也是同样的过程。
实施 dropout 举例: 最常用的方法——inverted dropout (反向随机失活),用一个三层网络举例,注意:下面的a3和d3对应网络中所有的神经单元,实际实现过程中需要一层一层来实现。
- 定义向量
d
,
d
3
d,d3
d,d3 表示一个三层的 dropout 向量。它是一个概率矩阵,对应每个样本和每个隐藏单元。
d
3
=
d3=
d3= np. random. rand (a3. shape
[
0
]
[0]
[0] , a3. shape
[
1
]
)
[1])
[1])。
定义 keep-prob(表示保留某个隐藏单元的概率) ,概率为 1 - keep_prob 的元素对应为 0 ,概率为 keep_prob 的元素对应为 1 ; - 获取激活函数 a 3 a3 a3, a 3 = n p . m u l t i p l y ( a 3 , d 3 ) a3=\mathrm{np}. \mathrm{multiply}(\mathrm{a} 3,\mathrm{~d} 3) a3=np.multiply(a3, d3),使得 d 3 d3 d3 中为 0 的元素把 a 3 a3 a3 对应元素归零;
- 向外扩展 a 3 a3 a3, a 3 a3 a3 /= keep_prob。
反向随机失活 (inverted dropout) 方法通过除以 keep-prob,确保 a [ 3 ] a^{[3]} a[3] 的输出期望值不会被改变。原因如下:虽然dropout忽略了某些隐藏层神经元,例如系数是0.8,则保留80%的神经元,则神经元输出A整体期望也为原来的80%。但是inverted dropout的放缩操作,即对A除以80%。一缩一放过程,相当于输出期望没有改变。
7. 理解 dropout
- 其功能类似于 L2 正则化;
- 对于参数集多的层,可以使用较低的 keep-prob 值(不同的层,可以使用不同的值),缺点是:需要交叉验证更多的参数;
注意:
-
dropout 一大缺点就是:代价函数不再被明确定义,每次迭代,都会随机移除一些节点,想检查梯度下降的性能,实际上是很难进行复查的。
-
在实际操作中,可以先关闭dropout,将keep-prob 设置为 1,确保 J 函数单调递减, 然后再尝试使用dropout。
8. 其他正则化
- 数据扩增,假如是图片数据,扩增数据代价高,我们可以:
水平翻转;随意剪裁旋转放大(这种方式扩增数据,进而正则化数据集,减少过拟合成本很低)
对于数字识别图片,我们可以进行旋转,扭曲来扩增数据集
- early stopping
在验证集误差变坏的时候,提早停止训练
early stopping 缺点:不能同时处理 过拟合 和 代价函数不够小 的问题
- 提早停止,可能代价函数 J 不够小
- 不提早结束,可能会过拟合
如果不使用 early stopping ,使用 L2 正则化的话,这样训练时间可能很长,参数搜索空间大,计算代价很高。
early stopping 优点:只运行一次梯度下降,可以找出 w 的较小值,中间值,较大值,无需尝试 L2 正则化超参数 λ \lambda λ的很多值。
9. 归一化输入
归一化输入,可以加速训练。它一般需要两个以下步骤:
- 零均值化(所有的数据减去均值)
- 归一化方差 (所有数据除以方差)
注意:
μ
,
σ
2
\mu,\sigma^{2}
μ,σ2 是由训练集得到,然后用于其他所有数据集。
10. 梯度消失 / 梯度爆炸
在非常深的神经网络中,权重只要不等于 1,激活函数将会呈指数级递增或者递减,导致训练难度上升,尤其是梯度与 L 相差指数级,梯度下降算法的步长会非常非常小,学习时间很长。
11. 神经网络权重初始化
上面讲到了梯度消失/爆炸,如何缓解这个问题?
为了预防
z
z
z 的值 过大或过小,
n
n
n 越大时,你希望
w
i
w_i
wi 越小,因为
z
z
z是
w
i
w_i
wi
x
i
x_i
xi的和,合理的方法是
w
i
=
1
/
n
,
n
w_{i}=1 / n,\mathrm{n}
wi=1/n,n 是输入特征数量。
w
[
l
]
=
n
p
w^{[l]}=n p
w[l]=np.random.randn
(
(
( shape
)
∗
n
p
.
sqrt
(
1
n
[
l
−
1
]
)
,
n
[
l
−
1
]
) * np.\operatorname{sqrt} \left(\frac{1}{n^{[l-1]}}\right),n^{[l-1]}
)∗np.sqrt(n[l−1]1),n[l−1] 是给第
l
l
l 层输入的特征数量。
- 如果使用 ReLu激活函数 (最常用),则 ∗ n p . s q r t ( 2 n [ l − 1 ] ) * np.sqrt\left(\frac{2}{ n^{[l-1]}}\right) ∗np.sqrt(n[l−1]2),称为Xavier初始化
- 如果使用 tanh 激活函数,则 ∗ 1 n [ l − 1 ] * \sqrt{\frac{1}{n^{[l-1]}}} ∗n[l−1]1,或者 ∗ 2 n [ l − 1 ] + n [ l ] * \sqrt{\frac{2}{n^{[l-1]}+n^{[l]}}} ∗n[l−1]+n[l]2
这样设置的权重矩阵既不会增长过快,也不会太快下降到 0,从而训练出一个权重或梯度不会增长或消失过快的深度网络,这也是一个加快训练速度的技巧
12. 梯度的数值逼近
在反向传播时,有个测试叫做梯度检验。即计算误差时,我们需要使用双边误差,不使用单边误差,因为前者更准确。
f
′
(
θ
)
=
f
(
θ
+
ε
)
−
f
(
θ
−
ε
)
2
ε
\left.f^{\prime}( \theta\right)=\frac{f(\theta+\varepsilon)-f(\theta-\varepsilon)}{2 \varepsilon}
f′(θ)=2εf(θ+ε)−f(θ−ε)
13. 梯度检验
梯度检验帮助我们发现反向传播中的 bug。
将所有 W W W矩阵转换成向量之后,做连接运算,得到一个巨型向量 θ \theta θ,该向量表示为参数 θ \theta θ,代价函数 J J J是所有 W W W和 b b b的函数,现在你得到了一个 θ \theta θ的代价函数 J J J(即 J ( θ ) J(\theta) J(θ))。
接着,同样可以把
d
W
[
1
]
dW^{[1]}
dW[1]和
d
b
[
1
]
db^{[1]}
db[1]……
d
W
[
l
]
dW^{[l]}
dW[l]和
d
b
[
l
]
db^{[l]}
db[l]转换成一个新的向量,用它们来初始化大向量
d
θ
d\theta
dθ,并且它与
θ
\theta
θ具有相同维度。
14. 梯度检验的注意事项
- 不要在训练中使用梯度检验,它只用于调试;
- 如果算法的梯度检验失败,要检查所有项,检查每一项,并试着找出bug;
- 如果使用了正则化,计算梯度的时候也要包括正则项;
- 梯度检验不能与dropout 同时使用,可以关闭dropout,进行梯度检验,检验正确了,再打开dropout。