“仿真器是啥?”
“编译器是啥?”
“计算机体系结构是啥?”
一入职华为,懵懵懂懂的我刚见导师,他就对我发出“夺命三连问”,而当时的我对这些“灵魂拷问”竟然一概不知,我很是羞愧,暗暗下决心一定要在程序员这条路上干出点成绩。
当时不好受的滋味还依稀记得,如今一转眼,我做这行快10年了,从一个小白成长为了一名架构师。与当初的“一问三不知”不同,我已经享受软件编码和设计的过程。
在深夜,抛弃没用的面子入职不久,我便被安排去海外研究所协同攻关,对于还是小白的我来讲简直是天上掉馅饼的幸福,想到要去见识海外的风土人情,面对完全不熟悉的海外同事,心中又激动又忐忑。
我的任务是开发华为NPU芯片的软件仿真器,就是用软件模拟硬件的执行行为,从而帮助芯片未来更好地在商用场景中应用。有一次软件仿真器出现了问题,我绞尽脑汁调试很久,始终没能定位出是什么原因。正当束手无策之际,我看到了心中的大神——海外专家就坐在不远处,瞬间燃起了希望的火花,但是内心又开始了纠结:向他求助?可我们之前从未打过交道,冒然求助有些唐突;比起被拒绝,我更担心他觉得我的问题太过幼稚,真的好怕被他看不起啊!
经过无比激烈的内心斗争,我决定还是抛弃“面子”,我说服自己在解决问题上,面子完全没用,技术问题不分大小,是可以开放讨论的,只要有所收获,即使一时被看扁也无所谓啦。
就这样,我鼓起勇气慢慢走到专家身边,向他说明了我的来意,结果专家非常欢迎我,还很耐心地把自己的经验跟我分享:“要先想清楚,你怀疑的问题在什么输入情况下会反映出什么不一样的现象,如果不是你预期的应该怎么办。”听完这句话,我醍醐灌顶,遇到问题应首先思考如何固定验证环境的变化,不断缩小怀疑范围,从而逐步定位出问题。而我总是一上来就一通拳脚乱打乱踢,确实失了策略……按照专家的思路,我重新构建了验证环境,顺利地定位了问题。
后来不久,在一次项目中碰到了一个内存不够用的问题,兄弟们攻关了一个星期也没有进展。当时我脑子里一下子闪过当初专家跟我说的话,我便把专家的“先固定验证环境的变化”的经验分享给大家,并做了一个内存验证实验,很快就定位到了问题出自内存变量复用,再针对性地提供解决方案就顺利解决了。兄弟们都连连点头,站在巨人的肩膀上,果然可以事半功倍啊!
我觉得搞研发跟做学问一样,需要多学多问,“三人行必有我师焉”。华为公司有良好的团队分享氛围,也储备了很多的博士、外研专家。我有幸和他们一起合作了好几个项目,有了第一次,我也不再害怕了,一有空我就主动去跟他们喝喝咖啡,交流交流心得,每次都受益匪浅,获得成长。
硕士文凭的“博导”做学问除了多学多问,还要肯钻研。在我跟博士团队共同做项目的经历中,我就观察到很多博士们不仅有自己的想法,还很有钻研的劲头,令我印象最深刻的就是我和博士团队一起合作的人体算法性能优化项目。
现今人脸识别技术在市场上得到了较为普遍的商用,而应用于人体识别的算法技术在商用上并不成熟。有个团队已经做出了一套人体识别算法,很厉害,不过也遇到了一个难题:人体识别商用的一个重要前提是GPU支持16路摄像头同时进行实时计算,但团队现在的能力只能达到2路。
当时我们在做HEARS平台,可以提供框架,拥有任务并发的能力,因此算法开发组的兄弟希望我们可以帮忙搞定。这对HEARS来讲是个巨大的挑战,但也是证明框架有效性的机会,这是件非常有意义的事。于是我决定接下这个难题,拉上懂硬件、懂算法的博士和骨干,信心满满地组建了创新人体算法性能优化的团队。当时部门的主管老胡还开玩笑说“你手上带了一大票的博士,都快成‘博导’了!”虽然我是硕士文凭,但我丝毫不慌,还暗自高兴,因为每个成员都是我的法宝,都是项目达成的保障!
人体识别技术是我们未曾涉足的领域,对其相关的知识理解得并不深入,刚开始凭借对架构和代码的熟悉,进展还算顺利,很快实现了2路到4路,然后便有些后劲不足,一直找不到优化点。时间一长大家信心都被耗没了,一度陷入了自我怀疑,甚至有人打起了退堂鼓:
“是不是我们的能力不够?”
“优化到4路是不是已经到头了?”
“做到4路也差不多了吧!”
……
察觉到了团队士气低落,面对疑虑,我对大家说“性能优化需要过程累积,现在遇到瓶颈,没事,后面肯定上得去!我们集思广益,有什么想法大胆说出来。”这时一位博士同事站了出来,想试试在算法上优化。
这个想法一提出来,瞬间我心里像有一束光照进来一样,过去这段时间,我们时时刻刻想的都是在框架上、代码上的优化,已经到达瓶颈,也许算法上会是突破口!说干就干,经过多轮集中讨论,我们与算法团队一起制定了GPU kernel实现优化、多实例流水并行、算法瘦身等优化策略,并让那位博士成员深度参与到算法优化的研究中,我对他说“尽人事、听天命,无论结果如何,我们都要尽全力而为!”就这样在相互打气的过程中,我们坚定了冲击16路的决心。
接下来我带着团队专研算法简化,通过各种方式学习算法原理,剖析算法流程,分析编程技巧,阅读相关paper……大家像回归海洋的鱼儿一样又找回了状态。随着紧凑的学习和专研的深入,我们逐步进入了AI的世界,一个新的领域,我们也越来越多的熟悉和掌握了业界领先的优化技巧。
在持续不断的分析调优中,我们的算法做了很多精简,框架提高了并发度和重排定义,通过这样的方式一步步达到了16路标准,实现了业界的领先,而人体识别算法在安平解决方案中也得到了商用。那位敢提想法的博士也成为了团队中最懂算法的人。
性能优化要慢慢积累,不像软件架构先想好后落实。它是经过持续不断地分析、贡献idea,汇聚出来的。我相信三根筷子折不断,正是大家集思广益,互相补充,项目中遇到的很多问题才能迎刃而解,从中也让我得到了很多收获。
痛苦的淬炼:架构如同搭积木十年来,我参与了不少项目,在参与的许多技术项目中,HARES LiteTask让我改变最大。这是一套底层的多核、异构调度系统的编程框架,它的目标是简化并行编程的复杂度。如果把硬件比作“工人”,程序比作要造的“房子”,我们都知道用5人一起造一个房子会比一个人造房子更快,但如何分配5个人的工作,先一起打地基然后一起一层层累,还是每个人并行造房子的一部分,不同的策略导致最终的速度是不同的。而且1000个人造房子和5个人造房子的策略也会不同。如何让每个工人都不空闲,是否有相对统一的策略可以用于1000人和5个人的工作分配上,这些策略就是HARES LiteTask希望提供的,方便用户规划分配这些“工人”。同时,它还承载了多个产品线的差异化需求,不仅要会“造房子”,还要会“造火箭”,这就更难了,“造火箭”的策略可能与“造房子”的策略完全不同。当时的我们就被缠在了这类泛化问题上:
“为什么我们不用自研或开源系统,要用你们的系统?”
“你这代码太复杂,架构不清晰,代码质量太差了……”
“就不该接这么多的需求啊!”
外部交付压力大,产品质量要保证,团队氛围剑拔弩张。那段时间,我顶着产品线的无情吐槽、内部的诸多质疑,非常苦恼,感觉自己掉进了一个黑洞,天旋地转,压力很大……
这样的困境也引发了我的反思:架构就像搭积木,只有一开始想好怎么搭,下面才会搭得顺畅,没那么多坑。优秀的架构师,最初便能设想出需要多少积木来构建,避过难替换、无法复用的积木,划分、切割出标准的积木完成拼接,实现最终的性能。要达到这个水平,对经验和领域扎根程度是有很高的要求。我若能在早期做好需求评估、架构设计,如今也不会这么狼狈。于是我想到了重构。
重构后的HARES LiteTask,不仅实现了业务系统的性能提升,得到了客户的认可,还增强了后续的可维护性。重构过程是艰辛痛苦的,但给我触动最大的,倒不是具体重构过程的点点滴滴,而是思想和意识上的转变,经过这一次重构,我仿佛经历了一次淬炼,从此深刻理解了如何做好一个架构师,也为以后自己的架构工作点亮了一盏灯。
在代码可信中“打怪升级”我觉得工作就像游戏里的打怪升级,你会不断遇到新的项目、新的难题,需要不断的消灭这些“怪物”,不断经验积累,从而遇到更高级的“boss”。经历过HARES LiteTask项目的我,在MindSpore项目中遭遇了更大的“boss”——GE重构。
MindSpore是华为自研全场景AI计算框架,2019年8月对外发布后,带着支持全场景、实现AI无处不在的使命,MindSpore走上开源之路。我所负责的GE(GraphEngine图编译引擎)可以理解为一个网络适配层,它的作用是发挥自研硬件(昇腾芯片)的计算能力,提升AI框架的竞争力。众所周知,AI的应用五花八门,各种神经网络的结构变化多端,要能够支持不同创新系统网络结构的接入运行,框架要具备更高的泛化能力。
虽然我们的框架尽可能发挥了自研硬件的性能,但在代码实现时还是遇到了大量的泛化问题、网络不兼容问题,如原有系统的定制性太强,网络联调成本太高等,这些问题就像是一个个“小怪”对我们张牙舞爪。因此我们一致决定通过框架本身一次性解决泛化难题,那就需要对原有版本的几十万行代码进行重构,这与我上次HARES LiteTask重构的工作量完全不是同一量级。但是经历过上一次,我深刻明白,势在必行,重构的大战又要开始了。
当时是2019年10月,重构时间窗仅有3个月。为了能按时完成攻关,大部队要一起到南研所与业务的兄弟们联合设计,在此之前我带着几个兄弟作为先遣部队提前冲到了“前线”。前期工作量是最大的,原版本的代码耦合很高,牵一发而动全身,不敢随便修改任何一行代码,所以我们几个就把原来没看过的代码都拉出来一寸一寸review讨论,找出设计逻辑和合理改法,以便大部队到来后可以顺利地往下进行。大部队到后,南研所附近的酒店便被我们一举“占领”。我们交流开发滚动进行,一个月改了几万行代码,可以说是昏天暗地,披星戴月。
这次重构,我教训最大的就是下面这个小故事了,GE架构作为通用的硬件优化层,需要支持多种类型的AI神经网络。架构设计阶段,我们基于“约定俗成”的做法,做了一些前提“假设”,而在实际的AI神经网络中,我们的“假设”被推翻了。比如基于“常规操作”,我们认为AI神经网络的图结构中的layout排布是连续的,结果发现一张图中前后两个算子并不一致,竟然还有这种“反常规操作”。再比如,我们的转换算子可以支持多种格式,然而这其中一些数据类型硬件上却并不支持,导致无法正常运行,这也是一开始没考虑到的。这种种“假设”造成的问题搞得我们很被动,不得不后期拼命填坑。这个血泪教训也给我上了生动的一课——架构设计不能心存任何假设。我想起,在华为常说要有“空杯”心态,重构也应如此,不假设,不自以为是。
在南研,过的是两点一线的生活,庞大又沉重的重构让我有时候怀疑人生,有个周末我领着大家出去走走,当我们来到秦淮河畔的大报恩寺琉璃宝塔脚下,看到这座九层八面、通体琉璃、独步古今的高塔时,我脑海中浮现出了当年的匠人们全神贯注、一寸寸精雕细琢的画面,他们耗时近20年,用心铸造了这个超出当时时代工艺一大截的建筑奇迹,不禁心生敬佩。我不也是在用一行行代码,搭建一个个工程么,我要向这些工匠学习,沉下心来雕琢代码。这么脆弱的琉璃材料,用于筑塔必定也经历过无数次的尝试、失败,代码重构的艰难又算得了什么。给自己做了一番自我激励,放松了一下神经,回来继续领着大家接着啃重构中难啃的硬骨头。最终我们赶在1月份完成了代码重构,支持了MindSpore开源和昇腾芯片商用进度要求,把这个大boss拿下了!
后来项目成功收官,我内心的喜悦不止于此,经历这一系列的“升级打怪”,我更加深刻体会到了人们常说的十年磨一剑,凝聚十年心力,打磨一把非同一般的利剑。做研究、开发软件系统也该如此。
从小白到如今,我的这把“剑”已经磨炼了十年,还未达到我心中优秀架构师的境界和标准,但我会为之继续学习、专研,磨好我的剑,搭好我的积木。