一.训练后可能出现的问题
类似于简单的回归问题,各种神经网络也会存在着欠拟合和过拟合的情况。我们这里不考虑数据集中的噪声和数据量的影响,就考虑使用神经网络的三个步骤。对于一个足够复杂的神经网络,如果出现了欠拟合情况,那必然是没有计算出对应的比较好的解,即第三步选择最好的函数的问题;而过拟合的情况代表着训练集上已经足够好了,解决方法其实很多,我们在后面详细说明。情况如下图所示,这里的所谓的测试集其实是交叉验证集,因为我们需要有标签数据来反馈训练的情况。
二.解决欠拟合
就像上文所说,欠拟合一般都是因为神经网络没有找到一个比较优的解,也就是没有找到损失值最小的点。
1.更高级的优化器
普通的梯度下降容易陷入局部最优解,而且学习率一直不变,调小了前期可能非常慢而后期可能无法收敛;因此我们可以选用更高级的优化器,例如可以自适应学习率和下降方向的Adam优化器,具体的内容在学习笔记(三)中。
2.新的激活函数
我们之前一直使用的是Sigmoid函数
σ
(
x
)
\sigma (x)
σ(x),然而对于一个很深的神经网络,反向传播求梯度的时候使用了链式法则,每次都要对Sigmoid函数求一次导数。然而我们去看Sigmoid函数的导数,为
σ
(
x
)
(
1
−
σ
(
x
)
)
\sigma (x)(1-\sigma (x))
σ(x)(1−σ(x)),它只有在中间端导数是1,越到两端导数值越小,例如在
x
=
2
x=2
x=2的时候导数已经在0.1左右了,从而反向传播的时候梯度直接衰减了十倍。这样下去层数多的话,前面的层几乎完全无法被训练,不是增加轮数或者使用优化器就可以解决的。因此,我们需要使用其他的激活函数,争取保留梯度。
最简单的保留梯度的方法当然是不使用激活函数(或者说激活函数就是
y
=
x
y=x
y=x)。但这样我们看下图最终结果
y
y
y的表达式,如果这里的激活函数
σ
\sigma
σ没有了,那其实可以把这些权重矩阵
W
W
W乘进里面的表达式,最终我们可以得到
y
=
W
′
X
+
b
′
y=W'X+b'
y=W′X+b′,也就是说不管是多少层的神经网络,都相当于是一个一层的神经网络了,只能有线性边界,这显然不行。
那就是说激活函数不能是线性函数了吗?并不是这样。我们继续可以发挥类似于积分的思想,光滑的分界线可能就是由很小很小的一些直线构成,也就是说如果采用分段等思想,让神经网络是多个分段共同决策的结果,加上神经元层数和数量都很多,足够模拟比较精细的光滑曲线。因此,Relu函数也应运而生。
Relu函数显然很好求导(0处就设置成导数是1就好了),也不会出现梯度消失的情况,要不是梯度直接被传过去,要不就是为0,代表着本次训练这个神经元没有意义。使用这个函数另外一个原因是人大脑神经元的激活机制也类似于Relu函数,信号达到一定程度就原样传播,否则就不再传播(如果这个神经元一直不传播,久而久之这个神经元就会退化掉)。另外,如果是分类问题,由于这个函数输出结果不是在0到1之间,无法模拟概率,所以最后一层还是要使用softmax函数或者sigmoid函数,这个是理所当然的。
至于为什么最后的结果不是线性的,就如同上面所说,对于每个数据(假设数据量足够多),都有不同的"死"神经元,对于活神经元构成的神经网络,的确都是线性的;由于每次死神经元不一样,最后的结果就是这些不同的线性结果的累加,从而模拟非线性边界,也就是上文所说的以直代曲。
(当然全连接层目前使用的最多的就是Relu激活函数,效果也确实让人满意,所以解释起来也有底气,毕竟解释只能是方法论,没有严格的推导)
当然后来又发明了很多Relu函数的改进版,比如负数的时候也有一点点斜率,或者这个斜率也是可以学习的,甚至后来不满足于这个二分段函数,而是使用Maxout激活函数,采用多分段函数。当然,思想上和Relu全异曲同工,具体内容老师的视频中讲的很详细了,这里也没什么其他可说的了。
三.解决过拟合
1.早期停止——面向第三步优化
过拟合时,由于训练集效果好,第三步我们挑不出问题来了,一定是到了一个很优的解了,我们不需要再去优化,但是我们可以试图找到一个所谓的不是那么优的解,这个解可能训练集上效果不够好,但是可能在测试集上,就会有更好的结果。下面的这张图经常被用来说明训练轮数与过拟合的情况,可见我们如果在过拟合前就停止,那么就可能得到满意解。具体实现方式可以是,每过一定的轮数就保存一次参数到文件,然后对测试集(交叉验证集)做测试查看结果,然后找到最优的情况,把这些参数作为最后的参数即可。
2.正则化——面向第二步优化
首先我们假设我们的网络是最经常使用的隐藏层Relu+最后一层Sigmoid的全连接网络,我们考虑一下如果所有的参数都乘以2会有什么结果。显然,由于Relu函数的机制,小于0的还是会小于0从而神经元废掉,而没有废掉的部分随着每层乘2,到达sigmoid函数的函数会乘2的神经网络层数次方。如果本来输入是1,得到的结果大概是0.7,即使是仅仅4层,得到的结果就会到0.999以上,当然这会使得我们的损失值降低很多,但是我们想一想,它和最初始的情况有什么不同之处吗?当然并没有,因为这种改变完全不会改变分类的结果。因此,这种情况就会出现这种过拟合的情况。
当然,上面的论述说明了这会导致过拟合,但是不能说明过拟合一定是这样造成的;但是我们依然可以避免这种情况,去看看是否可以缓解过拟合现象。那我们就可以在损失函数上开刀,让参数的值直接影响损失值。
假设未正则化时损失函数是
L
(
θ
)
L(\theta)
L(θ),正则化后损失函数是
L
′
(
θ
)
L'(\theta)
L′(θ),则有
L
′
(
θ
)
=
L
(
θ
)
+
λ
(
∣
∣
θ
∣
∣
k
)
L'(\theta)=L(\theta)+\lambda(||\theta||_k)
L′(θ)=L(θ)+λ(∣∣θ∣∣k),称作Lk正则化,一般使用的较多的是L1正则化和L2正则化,
α
\alpha
α为自己设定的超参数。
我们可以对比一下L1正则化和L2正则化,其实前者就是加上参数的绝对值和,而后者就是加上平方和。
对于未正则化的情况,我们有
w
t
+
1
=
w
t
−
α
∂
L
∂
w
w^{t+1}=w^t-\alpha\frac{\partial L}{\partial w}
wt+1=wt−α∂w∂L L1正则化中,我们有下式,其中
s
i
g
n
sign
sign函数为符号函数。
w
t
+
1
=
w
t
−
α
∂
L
∂
w
−
α
λ
s
i
g
n
(
w
t
)
w^{t+1}=w^t-\alpha\frac{\partial L}{\partial w}-\alpha \lambda sign(w^t)
wt+1=wt−α∂w∂L−αλsign(wt) L2正则化中,我们有
w
t
+
1
=
(
1
−
α
λ
)
w
t
−
α
∂
L
∂
w
w^{t+1}=(1-\alpha \lambda )w^t-\alpha\frac{\partial L}{\partial w}
wt+1=(1−αλ)wt−α∂w∂L 即为L1正则化是每次向0额外走一个确定的数值,而L2正则化是每次向0额外走一定的比例。而神经网络中各个参数一般都比较小,因此L1正则化的影响有时会过大不灵活,从而L2正则化的比例衰减用的更多。
正则化的结果有的时候是有效的,但有的时候没有效果,毕竟不一定是由于这种参数过大导致的过拟合,这时我们就要再使用其他方法。
3.Dropout——面向第一步优化
如果前面两种方法无法解决问题,那么有可能就是这个网络结构本身的问题了。这时候我们当然可以选择整体换一个神经网络架构,但这是后面要讲的,比如CNN,RNN,GNN架构等等,但是这里我们先不考虑这个问题,我们再回到第二节笔记中所提到的低误差高方差的情况。如果我们把多个低误差高方差(独立同分布)的样本组合起来形成整体,那根据统计学知识,这个方差和整体数量成反比,因此我们可以用这个思想指定策略。
Dropout就是其中一种方法,被译为“随机失活”。顾名思义,就是每个批次的训练中,都让除最后一层的神经元后有一定的概率随机失活,当然这个概率可以人为设定。这样每次训练时假设有
M
M
M个神经元,甚至会有
2
M
2^M
2M个可能的训练网络来训练。虽然看起来这需要极长时间的训练,但由于这些网络是共享参数的,参数的数量是固定的,因此训练起来并没有增加时间,就可以增加了训练的神经网络的数量。唯一的缺点就在于,这些所谓的神经网络之间并不是独立同分布,这也造成了我们只能一定程度减少方差,还可能会增大变差,无法得到所谓的绝对低方差和低偏差(当然这也是必然,完美是不可能的)。
Dropout还有一个步骤就是调整训练完的网络的参数。如果失活率为
p
%
p\%
p%,那么最后所有的参数都要乘
(
100
−
p
)
%
(100-p)\%
(100−p)%。例如一个单个神经元构成的神经网络:线性累加器,最后的参数都应该是1,然而如果有50%的失活率,那剩下的50%平均来讲要参数是2(当然这个2是数学期望)才能贴近结果,从而说明了这个道理。当然,对于多层复杂神经网络,这个无法证明,笔者查了一些资料,也没有严谨的证明,但总之,这样做的结果是期望值最好的,那就承认这是好方法就行了。(日常炼丹)