败者合死胜合优——我的ASC16纪行

ASC16已经落幕半个月了。趁着老师催交赛后总结材料之际,我也顺便写一点东西,算是对这场比赛有个感性的记录。去年还兴致勃勃写了几篇,今年偷懒,就全部弄到一篇好了。

按惯例,学校每年超算队招新都是一月初的事情。我一月初就主动联系了叶老师,表示我今年想回来继续打比赛。不用说,我今年肯定也是继续做改代码那道题。之前已经看到消息说我们要做DNN的优化,我这个没有接触过神经网络的就随手搜了一下一些基本的材料,当时就有一种奇怪的感觉。1月16日叶老师拿到代码让我先看。那天早上我还在图书馆里复习偏微分方程,拿出平板下载代码打开一看,直接没忍住在图书馆里爆出了一句『卧槽』——这份代码的计算主体是BLAS的sgemm,而且用的是MKL。回去上服务器上做profiling,果然如此——99+%的时间用在cblas_sgemm这个函数上。
我简单解释一下我的『卧槽』。sgemm是BLAS Level 3函数,用来做单精度一般矩阵(即不考虑其是否有任何特殊性质)乘法。BLAS Level 3的函数都是矩阵-矩阵操作,经过了多年的优化,*gemm系列的矩阵乘法函数更是经典中的经典,无论是学习还是测试都以之作为一个标杆,基本上可以将硬件的计算性能完全发挥出来。原始程序直接调用了Intel MKL这个数学库,这意味着在Intel平台上几乎没有谁家的sgemm能跑得比它快。而且,*gemm函数一般都自带了多线程。总结起来就是,99%的计算时间被一个高度优化过的、已经是多线程并行的函数给占了,那我优化个毛线啊?!
然而事情还是要做,而且我似乎还可以先喘一口气,因为我要先帮忙处理了新队员招募的事情。其他几位去年的队员都还没回来,我顺带先看了一下另外两道题。今年另外一道题,国家第一海洋研究所出的海浪波数值模拟程序,看起来不算长,而且看赛会的意思似乎还想让我们把这题改上GPU,这就有点微妙了。我简单弄了一下,看了一下相应的论文,发现这份代码大概也就是那种写出来能用的公式翻译结果,有些地方的问题太明显而且太致命,甚至反映出写代码的人没有受过基本的算法训练。因此可以预测,这题也是要动筋骨改代码的了。
超算队招新从去年开始都是对比赛做一个简介以后让候选者在实验室内部一个用PC搭建的小集群上面做上机测试,给两个星期或者更多的时间,然后再回来做一个实验报告。我觉得这个方法挺好的。寒假的时候我就负责给他们答疑,以及维护小集群。
我也看了一下DNN相关的一些知识,愈发感到头痛。DNN的数学形式写出来,计算大头就是矩阵乘法,如果有什么可以压缩计算量的地方,这十多年来我觉得应该早就有研究者提出来了。要是真让我捡到漏,我才不在意比赛,按叶总的说法,那是价值连城的发现啊。而且,浪潮最恶劣的一点就是他强调不能改数学算法,任何改动必须证明和原来的等价性。我知道浪潮在14年干过什么『好事』,所以去年也好今年也好我都非常小心,从来不做一星半点越轨的事情。寒假里并没有什么头绪,只好先改了上MIC的版本作为保底的。
2月16号回实验室报道,完成新队员的选拔。今年和去年一样,也是一队A Team一队B Team,不过今年两队人里都有一个大四的。分工和去年有些不同,老司机带了一个大二的继续搞系统,我带了两个大二的写代码,应用组就是两个大三和两个大四的撑着。
初赛阶段由于只考虑单节点内做并行,而且不允许改bunchSize(minibatch的大小),DNN的训练又是一个迭代的过程,所以在保证数学等价的情况下只能在一次迭代内做并行,而且矩阵规模不大,推不到机器峰值,在Xeon Phi上这个问题会更明显一点。我用很大规模的矩阵去做了一个测试,由于有AVX2指令集的加持,双路E5-2670v3的单精度峰值可以到1.6T左右,实测MKL sgemm能到1.5T。Xeon Phi 31S1P在offload模式下的MKL sgemm也是1.5T左右,所以比起纯CPU来已经没有什么优势了。我最后通过重新设计了CPU内的并行方法,使得程序在纯CPU模式下的速度从原来的比纯offload模式下的速度要慢一倍到还要快一点点。相反,海浪波那道题,他们改了不少地方,包括有定位算法和负载均衡调度算法,以及部分IO算法,改得比我们还多。
初赛改代码的时候我就觉得DNN真是一个玄学,因为有两三次我写错了一些地方,但是最后训练出来的结果都能达到准确性的要求。所以每次找到前面的bug,我都后背一阵发凉。别的程序员问我到底哪里做错了,我经常要问我是哪里做对了,是不是真的做对了,真是虚得不行。
3月2日交了初赛报告,心里忐忑了一个星期,还好,还是顺利进入了决赛。
决赛比起初赛,多了一个HPL(今年初赛没有HPL而是测HPCG),一个ABINIT和一个神秘应用。DNN这边新发了一个测试算例,但是这个算例很有问题:它给的初始解太好了,导致无论训练多少,都在那个局部最优解附近;然而,一旦我将编译选项从-O1提升到-O2,马上会跳出局部最优范围,将训练正确率降到非常低。所以,这个算例在我看来没有任何意义,除了数据量大一点。而且考虑到float的数值精度问题,我就有一种不祥的预感了。
3月18号和叶老师去华科开决赛发布会,感觉今年的气氛有点不正常,往年的发布会都很大规模,今年似乎稍微冷清了一些。从发布会上来的消息,海浪波初赛我们是做得最好的,上交的DNN初赛做得最好,而且尝试了『多个方面的优化』。我加了华科负责DNN这题的同学的微信,大家稍微交流一下。决赛的DNN规则又有变化了,而且我感觉是很自相矛盾的:一方面,浪潮坚持要求我们证明改动前后的数学等价,不能改算法;另一方面,bunchSize、learnRate都可以调,也可以做momentium和weight decay,这些在初赛的时候都是不能动的。但是后面这些一动,在数学上就是根本不等价的,不能保证收敛到同一个局部最优解上。发布会的时候我们问了浪潮的负责人这个问题,他也是语焉不详。这个时候我又有一种不祥的预感。
为了保证所谓的『数学等价』,我们依旧是在一个迭代内做并行,将一个bunch内的samples拆分给各个节点来做计算,然后每个bunch之间都需要同步更新。这样做有很高的网络通信代价,但是我们没有想到别的『可靠』的方法。另外,这意味着我们需要通过推大bunchSize的方法来保证速度。决赛用的平台是天河二号,每个节点有三张MIC卡,这个我们也要全部用起来。所以有些很基础很繁琐的工作还是要做,我就教给其中一个学弟去做了,另一个学弟突然遇到了课业上的坑没有办法。叶老师差点就打算让我去写快速矩阵乘法了,后来终归是作罢。但是另一方面,MPI的东西我们倒是玩了不少,特别是在天河二号上用了一些方法重新实现MPI_Allreduce来提升速度。
到我回过头来去看那个学弟的工作的时候,他带给我一个惊喜同时也是一个忧虑:为了掩盖从MIC上传输数据出来和跨节点通信的时间,他写了超过四层的流水线,用了一堆信号量来控制状态转移。这样的好处是,比起只有一层或者两层的话,速度差不多可以翻倍。坏处是,我根本看不明白、遑论改得动他的代码。后者意味着我没有办法帮他Debug和调优。更令我感到眼前一黑的是,这位兄弟初生牛犊不怕虎,改的代码几乎是一步到位的,一次过上了所有的流水线,而不是一个版本加一条流水线一样加上去。我真不知道他是怎么写出来的,居然能跑,居然还暂时没有发现错误。我没有及时和他沟通来了解进度,导致这种情况,是我今年比赛的一个重大失误。后来我被迫自己重新写了一部分,有一个两层流水线的版本,简单很多,算是多留一手准备。
除了弄DNN,我还要帮忙照看一下应用组,因为今年我是队长。应用组的四个人,一个大四B Team的去了忙论文,另一个大四的在跟着海浪波继续改代码,另外两个大三的被抽调了过去搞ABINIT,因为这货不好对付。去年我在深圳超算实习的时候,测试过另一个量化软件VASP,远没有ABINIT那么复杂,大概是因为是商用软件的缘故。ABINIT的编译都有很多的坑,测试数据又有另外的问题,他们也是弄得焦头烂额。后来把用GPU的版本弄好了,发现有些算例居然还不如纯CPU快。海浪波那边的进度也出了点问题,因为那位大四的同学(外号『宝宝』,因为平时睡得很多)有时候改代码之前没有想清楚,导致有些原本我们以为两三天能改好的东西改了一个星期还没改出来。
系统那边今年对实验室的几台服务器做了功耗监测和记录,用来查应用功耗特征,还算有点收获。另外今年我们一咬牙买了一堆SSD回来,问清楚了系统和IB驱动版本,装好了一个母盘并在出发之前dd好了所有的SSD。
4月17日我们从广州出发前往武汉,带着8张K80上高铁感觉就像是恐怖分子一样。到了武汉发现,当地的15~20度和广州的15~20度完全不是一码事,身边卷过的风明显还带有北方的不羁,所以大家一下车就马上开始拿衣服了。志愿者到站接车,今年没有像去年一样,一出站就拿摄像机一路跟着拍了。到华科的国际学术交流中心放下行李以后,我们马上过去看一下比赛场地。当时我还没认清楚哪边是我们的,一不小心走到旁边的机柜后面去看了一下,
4月18日正式开始装机。去年我们被浪潮的机器坑了一笔,今年还是用同一批机器,所以我们该绕开的坑都绕开了。那10块SSD插上去以后全部能开机联网,IB也没有问题,所以我们两个小时内就把所有的机器该装卡的装卡并且都启动起来进行测试了。去年装K80我折腾了好久,今年简直就跟熟手女工一样,结果被老司机在旁边玩起了“你为什么这么熟练啊”的白学梗,大意了。装机顺利为我们赢得了非常多的测试时间。虽然第一天早上有两个结点出了电源的问题,但还好都及时更换了。上交据说有四台机器出了问题,有一台直接就是突然砰的一声电源爆了,其他几台也是有各种各样的电源问题。到了下午,我就回去继续调DNN的参数了,老司机在场上练车。好几家学校都在比着飙功率,浙大曾经一度飙到4000W,黄老板的卡做起电老虎还真是毫不客气啊。
第二天早上我在宾馆里调程序,不知道场上情况如何。下午到赛场,去找浪潮的人最后确认一些规则,看到各校都已经确定了硬件,开始做功耗测试了。清华的人也非常厉害,几次看到他们贴了299xW的功耗极限,就是没有爆。今年的PDU比往年的灵敏了,1秒超过3000W都不行,不会存在那种几秒内突破3000W来刷Linpack记录的情况。前一晚负责ABINIT的两个队友熬得很晚,精神有点不太好。然而ABINIT的测试安排在周四,所以他们还得撑一下。
4月19日正式开打。我依旧是蹲在宾馆不用到现场。拿到所有的算例,传到我们自己的天河二号账户上开始跑,早上跑出来的前两个结果让我吓了一跳:cross validation的精度达不到要求。我开始逐步fallback,放弃速度,将参数改回去,并且回滚版本,仍旧无效。我回滚的这些版本,全部通过了初赛的两个算例的精确度要求,但面对决赛的算例,依旧无力。我最担心的事情还是发生了。晚上叶老师回来和我一起弄,当晚我和写代码的那位大二的队友,在叶老师房间里弄了差不多一个通宵,依然没有解决。那是我觉得最难熬的一晚上,整个人无比的煎熬。到了第二天,这个问题依旧没有办法解决。而且天河二的网络和IO开始极度不稳定。之前准备比赛的时候我们也时不时被天河二号坑了,但是这次比赛关头被坑,我也毫无办法。原本周四中午12点交结果,我到了赛场才知道被延迟了4个小时,原因未明。我在三楼继续受煎熬,旁边是北航的同学,他们也没有解决精度的问题。而且据了解,并不只有我们两个学校有这些问题。下午又遇上天河二号网络和IO最慢的一段时间,甚至tail一个2M的文本需要30秒,vim打开这个文件需要5分钟。这更加让我生气,因为程序精度不够,我尚且可以咽下去说自己技不如人写得不好,现在天河二号根本跑不动程序,我什么都做不了。叶老师和北航的指导老师一起去找赛会人员要求补时,但无果。最后我交了两个之前跑得很快的结果上去就算了,反正都过不了精确度要求,还不如向香港记者学习一下。
4点交完结果,我下去继续作战,帮他们打最后一个神秘应用。我们此前做过两次模拟练习,所以大家做起来还不算太紧张。但毕竟是到了最后一个下午,精神已经跟不上了,有半个小时频繁出现切算例换程序的浪费时间的举动。后来叶老师拍板,赌一把,跑一个分数最大的算例。于是我们就在那里祈祷了一个小时,最后居然真的能够踩线跑完,真是万幸。
6点,比赛结束,大家开始合影留念和拆机器。我们照例找台湾清华拿了一包乖乖回来。我和华科带队的石宣化老师单独合影留念了,因为我14年做志愿者就是接待他,今年回去华科比赛,也算是机缘巧合。到后来拍大合影的时候,我才发现浙大的老师脸色不对。我猜想他们也是被DNN这道题坑了,但并不知道具体的情况。我那道题沉船了我心如刀割,但依旧是要去准备最后一仗:演讲展示。然而我也撑不住了,当天晚上做到11点半就完全睁不开眼了,只好交给宝宝继续。他和我搭档上去讲,起码还能分担一点。
4月21日早上11点轮到我们去做展示。早上还练了一会儿,在酒店房间里我倒是讲得挺有激情,结果一上场看到评委还是各种紧张忘词,出来以后脸都白了。回到宾馆的房间,我直接就倒下睡觉了,别的什么也不想做。强作轻松吃了个饭,带着一种四大皆空的心态去了下午的颁奖典礼。很意外地,我们第二天的两道题目,ABINIT和神秘应用AbySS都做得很好,后者还是第一,还拿了一个单项奖。而且最后算下来我们的总分还能排到第四。华科今年非常完美,凭借着DNN拿了e Prize甩开其他很多队25分,成功反超并拿了冠军,亚军是上海交大。清华很不幸,今年真的四大皆空了,一个单项奖也没拿到。今年请了Jack Dongarra这位HPC界的泰斗前来颁奖,我厚着脸皮找他要了个签名。ASC14、ASC15都是给正式队员发充好钱的临时卡,ASC16改成了发印好日期的餐票;ASC14、ASC15最后一晚都有围餐,大家可以去互相敬敬酒套套话交流交流,ASC16最后一晚我们仍旧只能拿着印了日期的餐票去吃那顿号称一个人要80块的自助餐。前两年我们比完赛第二天都是和清华、台湾清华一起出去玩,今年台清和清华都是周六就走,所以周五晚上我们和台清去逛了一下武汉的汉街,大家聊了一下。
22日周六,原本打算出去玩玩,但是大家一个个都睡了懒觉,结果最后变成组队去旁边的世界城广场吃吃喝喝,然后想出去的再自己去玩。我之前去武汉玩过了,所以选择回去休息。在酒店大堂遇到清华和上交的同学都准备回去,我找他们负责DNN的同学留下了联系方式,交流一下学习一下。看起来,我们和台清、清华的DNN算法在某些情况下是相同的,和上交、北航的不太一样。所以这事儿就有点蹊跷了,说不清道不明,只好放下不再纠缠。
那天晚上我和叶老师讨论了一下,其实今年我们配集群还是弄得不错的,很平衡,兼顾到GPU和CPU的需要,而且功耗也控制得不错。到最后一天下午他们经常喊老司机去『飙车』或者『把方向盘』,前者的意思是放开CPU的睿频,后者的意思是把CPU主频压回去2.2G甚至更低并且降低风扇转速。如果不看DNN的成绩,我们很可能在前两名。然而去年我用Gridding翻了盘把总分拉回第四名,大概今年这人品得补回去吧。严格意义上来说,DNN其实并不适合拿来做竞赛题,一则是其数学等价要求自相矛盾,二则是这个数学模型本质上是可能存在多解的,在允许改参数的情况下,即使不改算法,也很可能收敛到另外一个局部最优解上。
再说一些后话。后来在网上看到一些消息,也和一些人私下交流了,才知道这次浙大的事情有多严重。现在明面上说的情况就是,浙大的天河二号账户出了问题,他们没有及早检查,发现问题的时候去找赛会却没人响应。一个比较客观的评价是,两边都有事情没做好。但是背后有些情况,就真的不好说了。一句话概括,这事儿已经变成了一个罗生门了。
不死虏手死汉法,败者合死胜合优。

败者合死胜合优——我的ASC16纪行》上有1条评论

  1. 嗯……看了师兄的blog觉得超算比赛好有意思的感觉。不过我刚退ACM的坑,貌似还对 竞赛 这种东西心有余悸。还不知道学长怎么称呼?有没有兴趣私下给小弟指点下人生呢。。?感觉前途一片黑暗ing

发表评论

电子邮件地址不会被公开。 必填项已用*标注