20210209 -
0. 引言
本次写这篇文章是因为最近在训练的过程中,遇到了这个问题,而遇到这个问题其实也挺奇葩。因为之前的时候,也遇到过,但是那时候没有这样想,没有往这个方向想也是因为现象不同。因此也因为这个问题让我反思。
首先来说一下具体现象。
今天在进行调试神经网络的时候,简单修改了层数和神经元个数,一开始没当回事,但是在重新测试的时候,却发现性能大不如从前,最后损失值稳定在了一个值。
这个问题很简单,没什么大不了的,但是如果是以前的话,我就会觉得,肯定是这个数据不太好(因为之前遇到过这种情况,跟别人论文中得到的效果差不多),但是这次的这个数据相对来说比较简单,而且我确信,之前的时候是肯定能达到非常好的效果的。
我感觉,前面的现象是落入了局部最优点(数据都是一样的,没有经过随机化)。而以前的时候可能不会这么想,那么这就让我反思自己,是不是我之前的时候也遇到了这种问题呢?(当然,那种跟别人的效果差不多的除外)。
总的来说,在最近的实验中发现,我明明能够达到比较好的效果,有时候修改了一些内容,有时候没有修改内容,结果性能相差很大。如果不是因为看到了有非常好的效果存在,我可能都想不到这个问题。这让我反过来思考这个问题。
其实之前的时候,也看到过过很多文章或者书籍提到,局部最优解的问题,或者说训练过程中遇到的问题,但是平时可能很少遇到,光看理论自然就没啥用。特别是,平时如果是仅仅学习网上的文章,跟着实验一下,但是这种实验一般效果都非常好,就导致无法意识到这些问题。
所以这篇文章就来记录一下,当然,文章的主题应该更具体,面更大一点,那就是,当神经网络的性能不好怎么办。
1. 怎么寻找问题
这里的问题就是,如果是发现了这种情况,应该怎么办。目前来看,根据以前看过的一些书籍也好,文章也好,是无法从别的地方能够体现出来是不是陷入了局部最优点的,这一点很像之前的之后学习核函数的时候看的内容,你也不知道哪一种是最好的,你只能一个一个尝试。
所以这篇文章自然也给不出万能的解决方案,也只能是给出一些提示。
那么既然讨论到了这个地方,就首先来看看平时使用神经网络的过程。
1.1 使用神经网络的过程
这里主要分析分类过程,对于回归或者预测过程来说,是相似的。
- 处理输入数据,归一化数据,归一化数据是为了能够让神经元更好的拟合,有些激活函数的输出范围是0-1或者-1-1.
- 处理输出数据,输出数据主要是将标签数据配合神经网络的输出,二分类只需要一个输出元就可以了,多分类最后一层的激活函数需要softmax来处理;一般都需要将输出标签输出为类别的个数。
- 训练过程,在定义好相关的损失函数之后,就需要利用训练过程来逐步优化损失函数,训练过程就是逐步调整神经元的权值,求到一个优化解。
- 测试过程,训练完成之后,就是通过测试数据来当前的模型
实际上,在上面的步骤中,训练过程是最重要的;将整个过程定义为一个优化问题,那么也就是要找到最好的权值,这个权值能够得到比较好的分类效果。
1.2 训练过程
在神经网络的训练过程中,目标就是找到全局最优解,当然有时候最优解可能也不是最好的,可能这个时候已经过拟合了[1];这里暂时不考虑这种情况。先来说,全局最优解。
在神经网络代码的编写过程中,例如使用keras库,都需要指定优化器,也可以不指定,他会默认选择一个。优化器的作用就是,帮助训练过程时进行神经元的权值调整。那么这个时候,可能遇到的问题就是局部最优解。
到达了局部最优解的时候,神经网络的损失函数就不再下降了。这里仅仅介绍了局部最优解的问题,实际上,还有两个问题[2]。在训练过程中,优化问题存在3个重点问题,或者说挑战:
- 局部最优解
- 平缓区域,又称为鞍点
- 高维数据
而这三个挑战,在训练过程上导致的结果也有3个:
- 可行解质量不行,也就是获得了一个局部最优解
- 训练时间非常长,由于优化方法一般都是采用了递归计算的方式,那么只能逐步到达优化解
- 训练失败,损失函数不再下降,到达了平缓区域,无法继续下降。
1.3 寻找问题
前面已经列出了使用神经网络的大致过程,而比较重要的就是训练过程,当数据都已经预处理完成了。(归一化是必须的)
那么如此来说,训练过程中有哪些步骤可以选择?不仅仅是训练过程的优化器,还有整个神经网络的设计过程,这里不考虑神经元个数和层数的问题,而是考虑其他的内容,这里简单列举几个部分:
1)神经元的初始权值,在有些书籍中已经指出,神经元权值的初始化很重要,有时候也是导致局部最优解的原因
2)优化器,有些优化器就是为了解决局部最优解而提出的
3)激活函数,这个是我以前测试的时候发现的。
目前来说,我能想到的问题就是这些,其他的肯定还有,但是个人能力有限。
2. 问题的解决
前面列举了一些关键的问题,包括训练过程中可能遇到的几个问题,这里暂时不考虑训练时间长的问题。那么重点也就是局部最优解和平缓区域的问题。但是这种问题,怎么说呢,从理论上来进行思考,有点难。平时的时候,主要还是通过调参,调整各个部分的数据,来实现更好的效果。这里这不可能将所有的为解决方案都找到,所以这里作为后续学习过程中记录低点。当前来看,我能想到的一个办法,就是权值初始化,另外一个就是优化器的选择,不过,这个优化器之间他们虽然各有优点,但是怎么样从数据的角度得到指示,让我知道这个优化器不好呢?!
当然前面也说到,这种不是很好做到,就像是核函数的角度一样,你无法知道哪个是最好的,只能逐个试。但是我觉得,应该也有人做过相关的研究,能够有一些经验性的结论。
2.1 权值初始化
这部分可以作为后续可以选择的方案。
2.2 优化器的选择
实验过程中,直接使用了默认的优化器,即没有指定具体的参数,这个时候最高效果只有88%;而更换了SGD之后,可以达到99%,当然即使是这样,也并不能说明这种方法在任何情况下都会有效果。
model.compile(
loss = 'categorical_crossentropy',
optimizer = SGD(),
#optimizer = Adam(learning_rate=0.01),
metrics = [
tf.keras.metrics.Precision(),
tf.keras.metrics.Recall(),
tf.keras.metrics.categorical_accuracy
]
)
参考
[1]Understanding Local Minima in Neural-Network Training [2]Why Training a Neural Network Is Hard