实践心得:从读论文到复现到为开源贡献代码

摘要: 本文讲述了从在fast.ai库中读论文,到根据论文复制实验并作出改进,并将改进后的开源代码放入fast.ai库中。react

clipboard.png

介绍

去年我发现MOOC网上有大量的Keras和TensorKow教学视频,以后我从零开始学习及参加一些Kaggle比赛,并在二月底得到了fast.ai国际奖学金。去年秋天,当我在全力学习PyTorch时,我在feed中发现了一条关于新论文的推文:“平均权重会产生更普遍的局部优化和更好的泛化。”具体来讲,就是我看到一条如何将其添加到fast.ai库的推文。如今我也参与到这项研究。算法

在一名软件工程师的职业生涯中,我发现学习一门新技术最好的方法是将它应用到具体的项目。因此我认为这不只能够练习提升个人PyTorch能力,还能更好的熟悉fast.ai库,也能提升我阅读和理解深度学习论文的能力。网络

做者发表了使用随机加权平均(SWA)训练VGG16和预激活的Resnet-110模型时得到的改进。对于VGG网络结构,SWA将错误率从6.58%下降到6.28%,相对提升了4.5%,而Resnet模型则更明显,将偏差从4.47%减小到3.85%,相对提升了13.9%。架构

论文

背景并发

随机加权平均(SWA)方法来自于集成。集成是用于提升机器学习模型性能的流行的技术。例如,ensemble算法得到了Nekix奖,由于Netkix过于复杂不适用于实际生产,而在像Kaggle这样的竞争平台上,集成最终性能表现结果能够远超单个模型。机器学习

最简单的方式为,集成能够对不一样初始化的模型的若干副本进行训练,并将对副本的预测平均以获得总体的预测。可是这种方法的缺点是必须承担n个不一样副本的成本。研究人员提出快照集成(Snapshot Ensembles)方法。改方法是对一个模型进行训练,并将模型收敛到几个局部最优势,保存每一个最优势的权重。这样一个单一的训练就能够产生n个不一样的模型,将这些预测平均就能预测出总体。函数

在发表SWA论文以前,做者曾发表过快速几何集成(FGE)方法的论文,改方法改进了快照集成的结果,FGE方法为“局部最优能经过近乎恒定损耗的简单曲线链接起来”也就是说,经过FGE做者可以发现损耗曲面中的曲线具备理想的特性,以及经过这些曲线集成模型。性能

在SWA论文中,做者提供了SWA接近FGE的证据。然而,SWA比FGE的好处是推理成本较低 。FGE须要产生n个模型的预测结果,而对于SWA而言,最终只须要一个模型,所以推断能够更快。单元测试

算法

SWA算法的工做原理相对简单。首先制做你正在训练的模型的副本,以便用于跟踪平均权重。在完成epoch训练后,经过如下公式更新副本的权重:学习

clipboard.png

其中n_models是已经包含在平均值中的模型数量,w_swa表示副本的权重,w表示正在训练的模型的权重。这至关于在每一个epoch训练时期结束时存储模型的运行平均值。这就是该算法的精髓,但论文还介绍了一些细节,首页做者制定了具体的学习率计划,以确保SGD在开始平均模型时就可以找到出最优势。其次,对网络进行预训练以达到开始时就有必定数量的epochs,而不是一开始就追踪平均值。另外,若是使用周期性学习率,那么须要在每一个周期结束时存储平均值,而不是在每一个epoch后。

寻找更普遍的最优势

SWA的算法的工做方式,做者提供了证据,证实与SGD相比,它能使模型达到更普遍的局部最优,从而可以提升模型的泛化能力,由于训练损失和测试数据可能不彻底一致。所以,对训练数据进行更普遍的优化使得模型对测试数据进行优化。

clipboard.png

图三的一部分

由图可得,训练损失(左)和测试错误(右)类似但不彻底相同。例如,最右边的X处于训练损失表面的最佳点,但距离最优测试偏差有必定距离。正是这些差别能更容易的寻找更普遍的最优势,这更可能成为训练和测试损失的最佳点。

做者提出观点:SWA能够找到更普遍的最优势。并在论文Optima Width章节中经过实验给出了证据,将损失做为给定方向上的Optima距离的函数,来比较SGD和SWA可以发现的最优势宽度。做者对10个不一样的方向进行了采样,并测量了用SGD和SWA对CIFAR-10进行训练的Preactivation Resnet的损失,结果以下:

clipboard.png

图4:“测试偏差...做为随机射线上的点函数,起始于CIFAR-100上预激活ResNet-110的SWA(蓝色)和SGD(绿色)解决方案。”

图中数据提供了证据,代表SWA发现的optima比SGD所发现的更普遍,由于它与SWA最优的距离比增长一样数量的测试错误的距离更大。例如,要达到50%的测试偏差,你必须从距离SGD的最佳距离为30,而SGD为50。

实验

做者进行了大量的实验来验证SWA方法在不一样的数据集和模型架构上的有效性。首先,我将详细描述为了实现该算法作的实验设置,而后讲解一些关键结果。

使用VGG16和预激活的Resnet-110体系结构在CIFAR-10上进行了复制实验。每一个体系结构都有必定的预算,以表示仅使用SGD +动量来训练模型收敛所需的时间数。VGG预算为200,而Resnet则为150。而后,为了测试SWA,模型用SGD +动力培训约75%的预算,而后用SWA进行额外的epochs训练,达到原始预算的一、1.25和1.5倍。对每一个测试训练了三个模型,并报告平均值和标准误差。

除了对CIFAR-10的实验外,做者还对CIFAR-100进行了相似的实验。他们还在ImageNet上测试了预训练模型,使用SWA运行了10个epochs,并发如今预训练的ResNet-50、ResNet152和DenseNet-161的精度提升了。最后,做者经过使用固定学习速率的SWA,成功地从scratch中训练了一个宽的ResNet-28-10。

实现

阅读并理解该论文后,我尝试在fast.ai库中找出哪一个位置添加代码可以使SWA正常工做。该位置已经找到了,由于fast.ai库提供了添加自定义回调的功能。若是我用每一个epoch结束时调用的hook来写回调,那么就能在适当的时间更新权重的运行平均值。这是结束的代码:

82df6b30728983878ba9f2eedc2dd25b1c9bef81

回调采用三个参数:model、swa_model和swa_start。前两个是咱们正在训练的模型,以及咱们将用来存储加权平均的模型副本。swa_start参数是平均开始的时间,由于在论文中,模型老是在开始跟踪平均权重以前,用SGD+动量对必定数量的epochs进行训练。

从这里你能够看到SWA回调如何将算法从文件转换成PyTorch代码。在SWA开始的epoch中,咱们将更新参数的运行平均值,并增长平均值中包含的模型数量。

在SWA模型进行推断前,咱们还须要用包含代码修复batchnorm的运算平均值。batchnorm层一般在训练期间计算这些运行统计数据,但因为模型的权重是做为其余模型的平均值计算的,因此这些运行统计数据对于SWA模型是错误的,所以须要再次单次传递数据让batchnorm层计算正确的运行统计数据。修复代码以下:

标题文字clipboard.png

测试

测试很是重要,可是在机器学习代码中应用单元测试是很困难的,由于有一些不肯定的因素或者测试的状态须要较长时间。为了确保所作工做其实是有效的,我作了两个测试,一个是“功能”测试,它们是较小的代码块,一般运行在比较简单的模型上,旨在回答:“这个功能是否按照个人想法实现了?”例如,一项功能测试代表,在通过几个阶段的训练后,SWA模型实际上等于全部SGD模型参数的平均值:

clipboard.png

这些测试一般在30秒内就能运行完成,因此在编写实现代码遇到问题时能快速提醒我。因为fast.ai库的开发速度很是快,这些测试还能在试图解决master分支合并问题时快速识别问题。

第二个测试为“实验”测试。它的目的是回答:“若是我用本身的实现和fast.ai库从新进行论文中的实验,我是否能观察到与论文相同的结果?”每次我实现一个功能就会运行这个测试,以肯定SWA是否对库作出有用的贡献。实验测试要比功能测试花费的时间长,但能确保一切都按预期运行。

最后我能够复述论文的结果-随机权重平均确实在CIFAR-10上产生了比通常SGD更高的准确性,而且随着训练时期的增长,这种改善一般会增长。正以下表所示,我全部的结果都比原始论文结果更准确。其中一个因素多是数据加强的方式——对于CIFAR-10,经过将每一个图像填充4个像素并随机裁剪进行加强,而且我发现fast.ai默认使用不一样类型的填充(rekection填充)。然而,能够清楚地看到SWA改善超过SGD +momentum的模式。

clipboard.png

原始论文的结果

clipboard.png

个人结果

获取测试代码请点击代码。

结论

我对这个项目的最终结果很是满意,由于我从最前沿的研究论文中复制了一个实验,并为机器学习开源代码作出了本身的第一个贡献。我想鼓励你们下载fast.ai库,并尝试一下SWA吧!

数十款阿里云产品限时折扣中,赶忙点击领劵开始云上实践吧!

本文由阿里云云栖社区组织翻译。

文章原标题《Adding a cutting-edge deep learning training technique to the fast.ai library》

做者:William Horton

译者:奥特曼,审校:袁虎。

原文连接

本文为云栖社区原创内容,未经容许不得转载。

相关文章
相关标签/搜索