江寒在这个F网络中,实现了一种新的训练策略,也就是迷你批次训练法。
简单地说,就是每次在18万个训练数据中,随机抽取若干条数据,组成一个小包,作为训练的样本。
然后,若干个小包组成一个完整的批次,训练若干个批次后,训练过程就宣告结束。
显而易见,相较于一次训练全部数据,这样做既节省了资源,又能提高训练速度。
这里涉及到3个超参数:每个小包的数据条数n,每批次包含的小包数量m,以及训练的总批次s。
神经网络里,每个神经元的偏置和权重,都是在训练中获得的,称作参数。
而学习速率、隐藏层神经元的数量,隐藏层的层数,权重初始化方案的选择、激活函数的选择、损失函数的选择……
这些都是超参数,必须在神经网络训练之前指定。
但由于缺乏理论指导,没有人知道这些超参数,到底如何选取才是最合理的。
所以在实践中,往往先根据经验,暂时预设一个差不多的,然后在训练的过程中,根据反馈结果,慢慢进行调整。
打造神经网络的过程中,最困难的就是超参数的选择,这往往意味着巨大的工作量。
每次调整超参数,都要重新训练一次神经网络,才能知道这次调整是否成功。
更麻烦的是,超参数之间并不是相互独立的,经常会调整了某一个,就会影响到另一个。
极端情况下,就会像多米诺骨牌一样,一个影响一个,最后导致全盘重来。
在原来的世界,机器学习算法工程师们经常为此挠破了头皮。
所以他们又自嘲或者被戏称为“调参狗”……
这个问题的解决,往往取决于网络设计者的经验。
一名合格的调参狗……咳,算法工程师,往往能凭经验和直觉,大体确定超参数的取值范围,然后根据实际情况逐步优化,直到取得近似最优解。
江寒当然算不上经验丰富,但前世玩神经网络的时候,也接触过不少讨论超参数选择的文章。
以权重初始化举例,就有不少可行的方案:初始化为0值、随机初始化、Xavier初始化、HE方法等。
其中,Xavier初始化又包含许多种做法。
比如将权重w的随机初始化区间,设为正负sqrt(6/(n0+n1))之间。
其中,n0是上一层神经元的个数,n1是本层神经元的个数。
这是一个经验公式,很多时候都很好用,江寒还记得这个公式。
其他超参数的选择,激活函数的选择、损失函数的选择……也有诸多可用的方法、方案。
除了一些前世接触过的方法,江寒自己也有过许多奇思妙想,琢磨出来不少乱七八糟的超参数选择方案。
这次做F模板,索性将它们全都编写成函数,塞到了模板代码中,用以备选。
除此之外,还要解决过拟合问题。
过拟合是机器学习的一道难关,一旦发生这种现象,就会导致训练好的模型,在训练集上表现优秀,而在陌生数据集上表现欠佳。
这是无论如何都要避免的。
要想避免过拟合,通常的做法有:扩大学习规模、降低网络规模、对权重参数规范化,以及非常激进的Dropout方法等。
扩大学习规模,就是尽可能收集更多数据,进行训练。
Kaggle的这场比赛中,官方提供了足足20万条训练数据,这意味着不怎么需要在这方面下功夫了。
如果提供的训练数据较少,那么往往就需要人为扩展训练数据。
比如:将图像略微旋转、平移、翻转、缩放、加入噪点像素……
降低网络规模,的确可以减轻过拟合,但同时也削弱了学习能力,所以一般不作为优先选项。
权重正规化也叫正则化(regurization),就是在未规范化的代价函数上,附加一个权重绝对值的和,使得网络倾向于学习少量的、重要度较高的权重。
这一办法,江寒在这个模板中,也作为备选项加以实现了。
至于Dropout方法,做法是按照给定的概率P,随机删除全连接网络中部分隐藏神经元,以达到简化网络,降低过拟合的效果。
虽然挺简单,但江寒并不准备现在就用出来。
这至少也价值一篇三区以上的论文,用在这种小比赛中,未免有些浪费。
江寒将自己知道的、能想到的方法、方案,全都罗列出来,编制成函数,放进了模板代码中。
然后将代码复制了130份,稍作修改,让它们分别使用不同的超参数设定策略。
这样,就出炉了130种候选的训练方案。
江寒将这些方案连同训练数据包,一起上传到了自己放在车库中的服务器和五台工作站中,然后指挥它们开足马力,同步进行训练。
如果光靠笔记本电脑,这130份代码一个一个训练过去,怕不得两、三个月之后,才能轮一遍?
现在就简单了,大约明天晚上,这130多份方案,就能得到初步的训练结果。
到时候根据反馈,从中选择一个表现最好的,全力训练就可以了。