Press "Enter" to skip to content

我是如何从头写一篇顶级论文的

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

Datawhale干货

 

作者: 重剑无锋@知乎,剑桥大学,编辑:极市平台

 

 

 

原文丨https://zhuanlan.zhihu.com/p/538681254

 

极市导读

 

关于一篇顶会论文是如何产生的这件事—且看作者为你娓娓道来,如何从一形成routine的日常科研生活中挖掘到巧妙的产出。

 

最近完成了一篇很满意的论文,不仅整个过程愉快,回味无穷,而且真正做到了“学术有影响 工业有产出”,可以肯定这篇文章会改变差分隐私(differential privacy;DP)深度学习的范式。

 

因为这次经历实在太过“巧”了 (过程充满巧合 结论极其巧妙)在此和同学们分享一下自己从观察–>构思–>实证–>理论–>大规模实验的完整流程,尽量保持lightweight不涉及过多技术细节,代码放在底部。

 

Automatic Clipping: Differentially Private Deep Learning Made Easier and Strongerarxiv.org/abs/2206.07136

 

https://arxiv.org/abs/2206.07136

 

尤其与paper展现的顺序不同,paper有时会刻意将结论放在开头吸引读者,或者先介绍简化后的定理而将完整的定理放附录,而我想将我的经历按时间顺序写下(也就是流水账) 比如把走过的弯路和研究中突发的状况写出来,以供刚踏上科研之路的同学参考。

 

一、 文献阅读

 

我每天都会读arXivDaily学术速递里所有机器学习和统计的文章标题及简介,大概每天150篇 所以DP的文章基本第一时间就能知道。

 

事情的起源是斯坦福的一篇论文,现在已经录了ICLR:

 

文章写的非常好,总结起来三个主要贡献:

 

 

在NLP任务中,DP模型的accuracy非常高,鼓励了privacy在语言模型的应用 (与之相对的是CV中DP会产生非常大的accuracy恶化 比如cifar10目前DP限制下只有80%accuracy,而不考虑DP可以轻松95%;ImageNet当时最好的DP accuracy不到50%)

 

在语言模型上,模型越大性能会越好。比如GPT2中,从4亿参数到8亿参数性能提升很明显,也取得了很多SOTA(但是在CV和推荐系统中,很多时候更大的模型性能会很差,甚至接近random guess。比如CIFAR10的DP best accuracy此前是由四层CNN得到的,而非ResNet)

 

 

NLP任务中DP模型越大性能越好 [Xuechen et al. 2021]

3. 在多个任务上取得SOTA的超参数是一致的,都是clipping threshold要设置的足够小,并且learning rate需要大一些(此前所有文章都是一个任务调一个clipping threshold 费时费力,并没有出现过像这篇这样一个clipping threshold=0.1 贯穿所有任务表现还这幺好)

 

以上总结是我读完paper瞬间理解的,其中括号内的内容并非来此这篇paper而是以往诸多阅读产生的印象,这有赖于长期的阅读积累和高度的概括能力,才能快速联想和对比出来。

 

事实上很多同学做文章起步难恰恰就在于看一篇文章只能看到一篇文章的内容,无法和整个领域的知识点形成网络产生联想。这一方面由于刚入门的同学阅读量不够,尚未掌握足够的知识点,尤其是长期从老师手中拿课题不自己独立propose的同学容易有这个问题。另一方面则是阅读量随够但没有时时归纳总结,导致信息没有凝聚成知识或者知识没有串联。

 

这里补充下DP deep learning的背景知识,暂且略过DP的定义,不影响阅读:

 

所谓DP deep learning 从算法的角度来说其实就是多做两个额外的步骤:per-sample gradiet clipping和Gaussian noise addition;换句话来说,只要你把gradient按照这两步处理完了(处理后的gradient叫做private gradient)之后该怎幺用优化器怎幺用,SGD/Adam都可以。

 

至于最后算法到底多private就是另一个子领域的问题了,称为privacy accounting theory 此领域相对成熟而且需要极强的理论功底,由于本文专注于optimization 按下不表。

 

g_i 是 一个数据点的梯度(per-sample gradient),R是clipping threshold, sigma是noise multiplier。

其中Clip叫做clipping function 就跟常规的gradient clipping一样,梯度长于R就剪到R,小于R就不动。

 

比如DP版本的SGD就是:

 

目前所有paper全都用的是隐私深度学习开山之作(Abadi, Martin, et al. “Deep learning with differential privacy.”)中的clipping function,也称为Abadi’s clipping

 

但这是完全不必要的,遵循第一性原理 从privacy accounting theory出发。其实clipping function只需要满足Clip(g_i)*g_i的模小于等于R就可以了,也就是说Abadi’s clipping只是一种满足这个条件函数,绝非唯一。

 

二、切入点

 

一篇文章的闪光点很多,但是并非都能为我所用,要结合自身的需求和擅长去判断最大的贡献是什幺。

 

这篇文章前两个贡献其实非常empirical,也很难深挖,而最后一个贡献很有意思。我仔细看了看超参数的ablation study 发现一个原作者没有发现的点:在clipping threshold足够小的时候,其实clipping threshold(也就是clipping norm C,在上面的公式中和R是一个变量)没有作用。

 

纵向来看 C=0.1,0.4,1.6对DP-Adam没什幺区别 [Xuechen et al. 2021]

这引起了我的兴趣,感觉背后一定有什幺原理,于是我手写了他们所用的DP-Adam来看看为什幺,其实这很简单:

 

如果R足够小,clipping其实等价于normalization!简单代入private gradient(1.1)可以将R从clipping的部分和noising的部分分别提出来。

 

而Adam的形式使得R会同时出现在梯度和自适应的步长中,分子分母一抵消,R就没有了,顶会idea就有了!

 

m和v都依赖于梯度,同时用private梯度替换即得到DP-AdamW。

就这幺简单的代换,就证明了我的第一个定理:在DP-AdamW中,足够小的clipping thresholds是互相等价的,无需调参的。

 

毫无疑问,这是一个很简明而且很有趣的观察,但这并没有足够的意义,所以我需要思考这个观察在实际中有什幺用途。

 

其实,这意味着DP训练减少了一个数量级的调参工作:假设学习率和R各调5个值(如上图) 那就要测25种组合才能找到最优超参数,现在只需要调学习率5种可能就好,调参效率提高了数倍,这是对业界来说极有价值的痛点问题。

 

立意足够高,数学足够简明,一个好的想法已经初具雏形。

 

三、简单扩展

 

只对Adam/AdamW成立的话,这个工作的局限性还是太大了。所以我很快扩展到了AdamW和其他adaptive optimizers,比如AdaGrad。事实上,对于所有的adaptive optimizers 都可以证明clipping threshold会被抵消从而不用调参,大大增加了定理的丰富程度。

 

这里面还有一个有趣的小细节,众所周知 Adam with weight decay和AdamW不一样,后者使用的是decoupled weight decay 就这个区别还发了篇ICLR。

 

Adam有两种加weight decay的方式

这个区别在DP优化器中也存在,同样是Adam 用decoupled weight decay的话,缩放R不影响weight decay的大小,但是用普通的weight decay的话,放大R两倍等价于缩小两倍的weight decay。

 

四、另有乾坤

 

聪明的同学可能已经发现了,我一直再强调自适应优化器,为啥不讲讲SGD呢? 答案是在我写完DP自适应优化器的理论后,Google紧接着就放了一篇DP-SGD用在CV的文章,也做了ablation study,但是规律和在Adam上发现的完全不同,给我留下了一个对角的印象。

 

对DP-SGD且R足够小的时候,增大10倍lr等于增大10倍R [https://arxiv.org/abs/2201.12328]

当时我看到这篇文章的时候很兴奋,因为又是一个证明small clipping threshold效果好的论文。

 

在科学界,连续的巧合背后往往有着隐藏的规律。

 

简单的代换一下,发现SGD比Adam还好分析 (1.3)可以近似为:

 

显然,R又可以提出来和学习率 \eta\eta 组合在一起,从理论上证明了Google的观察

 

“Specifically, when the clipping norm is decreased k times, the learning rate should be increased k times to maintain similar accuracy.”

 

很可惜 Google只看到现象,没有上升到理论的高度,这里也有一个巧合,那就是上图他们同时画了两种尺度的ablation study 只有左边的尺度能看出对角线,光看右边是没有结论的…

 

由于没有自适应步长,SGD不像Adam一样无视R而是把R看作学习率的一部分,所以不需要调节 反正学习率要调参。

 

再将SGD的理论扩充到momentum,所有Pytorch支持的优化器全都分析完毕。

 

五、从直觉到严谨

 

一个创新点是有了,但是Abadi’s clipping严格来说只是近似normalization,不能划等号,也就没法确凿的分析收敛性。

 

根据多啦A梦铁人兵团原理,我直接命名normalization为新的clipping function 替代了整个领域用了6年的Abadi clipping,这是我的第二个创新点。

 

经过刚才的证明,新的clipping严格不需要R,所以称之为automatic clipping (AUTO-V; V for vanilla)

 

既然形式上与Abadi’s clipping有不同,那幺accuracy就会有差异,而我的clipping可能有劣势。

 

所以我需要写代码测试我的新方法,而这 只需要改动一行代码 (毕竟只是把 )

 

事实上,DP per-sample gradient clipping这个方向,总共只有三种clipping functions。除了Abadi’s clipping以外的两种都是我提出的:一个是global clipping;还有一个就是这篇automatic clipping,而在先前的工作中,我就已经知道怎幺在各个流行的库中改clipping了。我将修改方法放在文章最后一个appendix。

 

经过我的测试,我发现斯坦福的文章中GPT2在整个训练过程中,所有itertation所有per-sample gradient都是clip过的。也就是说,至少在这一个实验上Abadi’s clipping完全等价于automatic clipping。虽然后来的实验的确有输于SOTA的情况,但这已经说明了我的新方法有足够的价值:一个不需要调整clipping threshold的clipping function 而且有时accuracy也不会牺牲。

 

六、 回归抽象思考

 

斯坦福的文章有两大类语言模型的实验:一类是GPT2为模型的生成型任务;另一类是RoBERTa为模型的分类型任务。虽然在生成任务上automatic clipping和Abadi’s clipping等价 但是分类型任务却总是差几个点的准确率。

 

出于我自己的学术习惯,这个时候我不会去换数据集然后专门挑我们占优的实验发表,更不会增加trick比如做数据增强和魔改模型之类的。我希望在完全公平的比较中,只比较per-sample gradient clipping的前提下,尽可能做出最好的不含水分的效果。

 

事实上,在和合作者讨论中我们发现,纯粹的normalization和Abadi’s clipping比,梯度大小的信息是完全抛弃的。也即是说对于automatic clipping,无论原始的梯度多大 clip后都是R这幺大,而Abadi对于比R小的梯度是保留了大小的信息的。

 

基于这个想法,我们做了一个微小但极其巧妙的改动,称之为AUTO-S clipping (S代表stable)。

 

将R和学习率融合后变成

 

简单一画可以发现,这个小小的 \gamma\gamma (一般设为0.01 其实设成别的正数都行 很稳健)就能保留梯度大小的信息。

 

基于这个算法,还是只改动一行,把斯坦福的代码重跑一遍,六个NLP数据集的SOTA就到手了。

 

在E2E生成任务上,AUTO-S超越了所有其他clipping function,在SST2/MNLI/QNLI/QQP分类任务也是。

七、要做通用算法

 

斯坦福文章的一个局限性是只专注于NLP,又很巧合的是,紧接着Google刷了ImageNet的DP SOTA两个月后,Google子公司DeepMind放出了一篇DP在CV中大放异彩的文章,直接将ImageNet从48%提升到84%!

 

https://arxiv.org/abs/2204.13650

 

在这篇文章中,我第一时间去看优化器和clipping threshold的选择,直到我在附录翻到这张图:

 

DP-SGD在ImageNet上的SOTA也是需要clipping threshold足够小

依然是small clipping threshold效果最好!有了三篇高质量的文章支撑 automatic clipping已经有了很强的动机了,我越发肯定自己的工作会是非常杰出的。

 

巧合的是,DeepMind这篇文章也是纯实验没有理论,这也导致他们差点就领悟出了他们可以从理论上不需要R。事实上他们真的非常接近我的想法了,他们甚至已经发现了R是可以提取出来和学习率融合的 (感兴趣的同学可以看看他们的公式(2)和(3)) 但是Abadi’s clipping的惯性太大了… 即使他们总结出了规律却没有更进一步。

 

DeepMind也发现了small clipping threshold效果最好,但是没有理解为什幺。

受这篇新的工作启发,我开始着手做CV的实验,让我的算法能被所有DP研究者使用,而不是NLP搞一套方法CV搞另一套。

 

好的算法,就是应该通用好用,事实也证明 automatic clipping在CV数据集上同样能取得SOTA。

 

八、理论为骨 实验为翼

 

纵观以上所有的论文,都是SOTA提升显着,工程效果拔满,但是理论完全空白。

 

当我做完所有实验的时候,这份工作的贡献已经超过了一篇顶会的要求:我将经验上small clipping threshold所产生的DP-SGD和DP-Adam的参数影响大大简化;提出了新的clipping function而不牺牲运算效率、隐私性,还不用调参;小小的 \gamma\gamma 修复了Abadi’s clipping和normalization对梯度大小信息的破坏;充足的NLP和CV实验都取得了SOTA的准确率。

 

我还没有满意,一个没有理论支撑的优化器,还是无法为深度学习做出实质贡献。每年顶会提出的新优化器几十个,第二年全都扫进故纸堆,Pytorch官方支持的、业界真正在用的还是那幺几个。

 

为此我和合作者们额外花了两个月做了automatic DP-SGD收敛性分析,过程艰难但最后的证明简化到极致。结论也很简单,将batch size、learning rate、model size、sample size等变量对收敛的影响都定量的表达出来,并且符合所有已知的DP训练行为。

 

特别的,我们证明了DP-SGD虽然收敛的比标准的SGD慢,但是iteration趋于无穷的话,收敛的速度都是一个数量级的,这为隐私计算提供了信心:DP模型收敛,虽迟但到。

 

九、撞车了…

 

终于,写了7个月的文章完稿了,没想到巧合还没停,5月份NeurIPS投稿 6/14内部修改完放arXiv,结果6/27看到微软亚州研究院(MSRA)发表了一篇和我们撞车的文章,提出的clipping和我们的automatic clipping一摸一样:

 

和我们的AUTO-S分毫不差

仔细看了看,连收敛性的证明都差不多,而我们两组人又没有交集,可以说隔着太平洋的巧合诞生了。

 

这里稍微讲一下两篇文章的不同:对方文章稍偏理论,比如额外分析了Abadi DP-SGD的收(我只证了automatic clipping 也就是他们文中的DP-NSGD,可能我也不知道咋整DP-SGD),用的假设也有一些不同;而我们实验做的多一些大一些(十几个数据集)更显式地建立了Abadi’s clipping和normalization的等价关系,比如Theorem 1和2解释为什幺R可以不用调参。

 

既然是同时期的工作,我很开心能有人literally不谋而合,互相能补充共同推动这个算法,让整个社群尽快相信这个结果并从中受益,当然私心来说,也提醒自己下一篇要加速了!

 

十、总结

 

回顾这篇文章的创作历程,从起点来看,基本功一定是前提。而另一个重要的前提是自己心中一直念念不忘调参这个痛点问题,正是久旱,所以读到合适的文章才能逢甘露;至于过程,核心在于将观察数学化理论化的习惯,反倒在这个工作中代码实现能力不是最重要的,我会再写一篇专栏着重讲讲另一个硬核代码工作;最后的收敛性分析,也是靠合作者和自己的不将就,所幸好饭不怕晚,继续前进!

 

P.S. 我的paper没有公布代码 因为别人的codebase写了几万行 我就改一行实在没有发布的必要 比如Facebook的DP代码库Opacus(https://github.com/pytorch/opacus) (version 1.1.3)只需要把https://github.com/pytorch/opacus/blob/main/opacus/optimizers/optimizer.py(https://github.com/pytorch/opacus/blob/main/opacus/optimizers/optimizer.py) 第400行的

 

per\_sample\_clip\_factor = \(self.max\_grad\_norm / \(per\_sample\_norms + 1e-6\)\).clamp\(max=1.0\)

 

改成下面这行就好了

 

per\_sample\_clip\_factor = 1 / \(per\_sample\_norms + 1e-2\)

 

这等价于斯坦门茨的故事:画一条线价值一万美元 :)

 

 

“整理不易, 点 赞 三连 ↓

Be First to Comment

发表回复

您的电子邮箱地址不会被公开。