同为工程师,搞算法的凭什么工资比你高?
算法工程师到底有什么特别之处?这个岗位真的比普通工程师高一等吗?同为工程师,算法工程师为啥工资高几倍?从普通工程师转为算法工程师,会有多困难?算法真的那么难搞吗?
不知道各位程序员朋友平时有没有想过这些问题,不知道各位是怎么看待这些问题的,如果你心里对算法工程师也有着各种疑惑,你一定不能错过今天的文章,本文的作者从两个角度来解答了这些疑问。
在他看来:算法工程师首先要是个工程师,但是,算法工程师又不只是工程师。
是不是听上去有些绕,但是又仿佛很有道理?先别忙着下结论,看完内容再评论。
上篇:论算法工程师首先是个工程师
引子
最近校招面试到吐,算法岗位有点太热了,简直心力憔悴。我们的面试分两个部分,先是做一两道编码题,然后才是考察机器学习的知识。很多同学不理解,在网上 diss 我们,说什么机器学习基本没有问。这种情况,一般是代码做的太烂了,面试官都没有兴趣去了解机器学习部分。
机器学习算法岗位,很容易让大家有个误解,认为平时工作就是推推公式,调调参数。鉴于此,本文借用下我们团队最近的一个重要项目:深度学习在搜索、推荐中的应用,来描述下平时我们是怎么干活的,看完之后,大家应该很容易理解为何我们要求有编码能力。
其实,我们的编码题真的很简单,不用刷题也能做出来,看看其他公司出的题,已经有点类似面试造原子弹,进来卖茶叶蛋的蜜汁感觉。当然,他们有资本,可以通过这种方式选到很聪明的候选人。
回到正题,我们从去年年底开始探索深度学习在搜索、推荐中的应用,包括排序和召回。以前我们常常用和工程同学合作,对系统的理解,比如推荐引擎、搜索引擎来表达编码能力的重要性,可能对于应届生来讲,有点模糊。这次的项目经历可能更好一些。
先总结下指导思想
这大半年,我们踩了很多坑,特别是痴迷论文中的各种 fancy 结构,寄希望于换换模型拿到收益。最终都纷纷被打脸,反而是回归到开始,从使用更多的样本数据,改善样本清洗、构造的逻辑,谨慎选择经典的模型结构,对优化算法保持敬畏等等,拿到了不错的收益。先来几点务虚的鸡汤,大概有以下几点:
- 对比传统模型,深度学习更需要大量的数据去学习,样本数据的增加能明显的改善模型的结果。
- 在初期,请忘记 paper 里面各式各样的奇技淫巧。
- 一套有效的方案,其效果是多和少的问题,不是有和无的问题。
- 好好调参,比乱试各种论文 idea 有效。
- 深度学习真的可以自称调参炼丹师,所以比别人试的更快,是炼丹师的核心竞争力。
- Embedding 太神奇,请把主要精力花在这里,深度模型对 id 的理解可以震惊到你。
- 关心你的模型的计算效率,最终还是要上线的,绕不过去的性能问题。
训练中的工程能力篇,就是各种踩坑各种填坑
样本规模的问题
一开始,我们把现有基线的特征数据喂到了深度模型中,试过 dnn、dfm、lstm 等等,发现效果比 lr 还差。当时为了快速尝试,将所有的数据 load 到了内存,限制了数据规模,而且有部分数据预处理的工作也是在 python 中处理,导致计算在 cpu 和 gpu 之间频繁切换,gpu 利用率抖动很厉害。基于 tf 提供的性能工具,做了点分析后,判断是特征预处理这部分移太耗时了。另外,模型的参数很大,但是样本数不够,急需增加样本量。我们用 spark 将样本数据构造成 tfrecord 的格式,整个构建过程对比原来基于 hive sql,再从 hdfs 拉到本地,快了近 10 倍,而且能用的样本数据量大了很多,发现模型效果好了很多。
embedding id 量级过大的问题
深度学习是在图像、语音等场景起家,经常在 nlp 的论文中,将几十万的 word 做 embedding 称为大规模。工业界做 user 和 item embedding 的同学应该笑了。userid 和 itemid 非常容易过百万、千万的量级,导致生成 embedding lookup oom。可以参考我上篇文章:https://zhuanlan.zhihu.com/p/39774203。
有些公司会选择对 id 进行 hash,再做 embedding,比如 tf 的官网就建议这样:https://www.tensorflow.org/guide/feature_columns#hashed_column。也有些会选择 simhash 来替换直接 hash。我们目前能做百万级别的原始 id,后续如果需要加大量级,更倾向于只对样本特别稀疏的 id 做 hash 或根据 id 的 metadata 做重编码来做。
Wide 模型带来的稀疏模型训练问题
大部分的 wide & deep 代码实现,其实用的 tensor 都是 dense 的。tf 基于 PS 做的模型训练,当你的特征规模在亿级别时,网络通信是个灾难,加上 grpc 的垃圾性能,网卡利用率上不去,训练的时间大部分都耗在通信上了。
但如果花点心思看看 tf 的源码,解决方法其实很简单,采用一些 sparse 的 op 就行。比如用 sparse_gather,就能解决网络传输的问题。但这个不是彻底的解决方案,tf 在计算的时候又会把 sparse 的 tensor 转成 dense 做。继续看看源码,会发现 tf 自身实现的 embedding_lookup_sparse。换个角度来理解,天然就能支持 sparse 的 wide 模型训练。把 sparse 的 wide 模型理解成 embedding size 为 1 的情况,上层接个 pooling 做 sum,就是我们要的 wide 的 output 结果,方案很优雅。
分布式下训练速度不能随着 batch size 增加变快
这个问题,单纯看性能分析还不好发现。还是去看下 TF 的代码实现,其实是 TF 默认有个 dimension 压缩的优化带来的。TF 为了节省存储,会对一个 batch 内的相同的 feature 做 hash 压缩,这里会有个 distinct 的操作,在 batch size 大的时候,性能损耗很明显。改下参数,就可以取消该操作,不好的地方是浪费点内存。
还有两个核心问题:TF 不支持 sparse 模型和分布式下 work 的 checkpoint 问题,这里不展开了。
线上性能篇
真实线上场景与 batch size 的训练的差异
真实排序的时候,一个用户过来,需要精排的候选集可能有几千。而我们在训练的时候,基于 batchsize 方式组织的 predict 代码。会将用户侧的 feature 复制几千次,变成一个矩阵输入到模型中。如果给 tf 自己做,这里就会有几千次的 embedding lookup,非常的耗时。如果我们选择在请求的一开始,就把用户侧的 lookup 做掉,然后去做点内存复制,就能大大减少 rt。
另外一个耗时大头是 attention,这个解决方案也很多,比如用查表近似就可以。
还有一些是模型实现的细节不好导致性能很差,比如 DCN 的 cross 实现,一个简单的交换律能带来巨大的性能提升,参考:https://zhuanlan.zhihu.com/p/43364598
扯淡开始
上面很多工作,都是算法工程师和工程同学一起深入到代码细节中去扣出来的,特别是算法工程师要给出可能的问题点。做性能 profile,工程的同学比我们在行,但是模型中可能的性能问题,我们比他们了解的多。当然也有很多同学 diss,上面这些都是工程没有做好啊,工程好了不需要关心。但是,真正的突破必然是打破现有的体系,需要你冲锋陷阵的时候自己不能上,别人凭什么听你的,跟你干。大概率就是在后面维护点边缘业务了。
难道机器学习理论不重要吗
当然不是,这篇已经写得太长了,只讲两个点。
信念的来源:这个其实是很重要的,一个项目,搞个一年半载的,中间没有什么明确的产出,老板要 kpi,旁边的同事刷刷的出效果,靠什么支持你去坚持继续填坑,只有对理论认知的信念。假设总是很美好,现实数据很残酷,左脸打完打右脸,啪啪啪的响。怎么一步步的接近真实,解决问题,靠的还是对理论的理解,特别是结合业务的理论理解。
工程和理论的关系就有点像,理论起到是指路者的作用,而工程是你前进道路上披荆斩棘的利刃。没有理论就没有方向,没有编码能力,就只能当个吃瓜群众,二者缺一不可。
最后,总结下:算法工程师首先是个工程师。
PS:Don’t panic!Make your hands dirty!编码没有那么难。
算法工程师首先要是个工程师,不知道看过作者的这篇文章,读者有没有对这句话有更深刻的理解?希望你没有被绕晕,因为接下来,作者又要谈到他的下一个观点了。下篇:算法工程师又不只是工程师
继上篇文章着重描述了工程能力的重要性,对于理论部分提的很少,但不代表它不重要。
谈的是提升理论素养
理论深似海,那是人类顶级的头脑的战场。
大多数算法工程师,当讲和理论相关时,大多是看了点论文、读点经典教科书,能水下 paper 已经是很高端了。不能称这些是做理论,对那些真正从事理论工作的同学太不尊重了,称为提升理论素养更合适。
理论素养不直接等价于业绩产出
很少人会觉得理论素养不重要,但提升理论素养的投入和产出之间不是线性关系。导致在工业界,经常争论对理论素养需求程度。比如知乎上的这个问题:有没有必要把机器学习算法自己实现一遍?(地址:https://www.zhihu.com/question/36768514)有 5k+ 的关注,100 多个回答,可见热度。
双方观点其实都挺有道理,但大家特别容易手里拿个锤子,看什么都是钉子。
现实中不存在一头扎在理论学习或者工程实现,就万事大吉。在二者中来来回回穿梭,试探边界在何处才是常态。
就像生活的常态是 chaos,就像熵一样一直增长,是自然规律。维持有序的状态需要付出了额外的成本。就像 IBM 大型电脑之父佛瑞德·布魯克斯说的:
No Silver Bullet我们的 CEO 也说过,他是一个现实的理想主义,美好的理想就像有序的状态一样需要消耗巨大的资源,而我们的资源永远是有限的,要学着带着镣铐跳舞。
争论的背后:ROI
我们所有人,都太追求效率了,俗话说:
一分钱一分货,十分钱两分货边际效用无处不在,当投入过了一个坎,ROI 就会剧烈下滑,线性增长的 ROI 就像泡沫一样美丽。
工业界的同学,ROI 的思维已经是生存的本能,但面对理论时,有时成也 ROI,败也 ROI,正如李沐在一篇帖子中说:
在工业界呆过再去读 phd 可以少走很多弯路,也会发现很多学术界的 idea 就是个笑话。但同样的问题是,习惯了很 solid 的工作,反而有时候思路打不开,不敢尝试思路新奇的点子。我 phd 期间比较后悔的是好几个地方隐约有点想法,但太专注一些跟工业界经历很像的想法,结果后面看到别人在这些地方做出了世界级的工作。我们和大神的距离太遥远,也很少能接触世界级的工作。更恰当的例子是公司的短期 KPI 和长期 KPI 的矛盾。短期的 KPI 虽然回报高,但就像下游低端产业,由于门槛低,很容易会变成红海,要发展就需要升级产业,向上游、高端的方向去,获得更大的利益分配权。
再退一步讲,浪费一些时间、精力在不能明显看到 ROI 的事情,其实也没什么,反正它也会被浪费在别的地方。意大利物理学家卡洛•罗韦利在《七堂极简物理课》中提到:
少年时代的爱因斯坦曾度过一年无所事事的时光。很可惜,现在很多青少年的父母经常会忘记这样一个道理:一个没有 " 浪费 " 过时间的人终将一事无成。务实一点,提高理论素养的好处还是很多的
除了以前常说的理论是指路明灯外,还有很多其他好处。
有助于系统化知识点
工作期间,见过不少干的好但是说不清楚的,在晋升上吃亏。有些同学性格内向,不善表达。改善表达可能比较难,但可以扬长避短,从写东西入手,写东西的前提是心里有货。好的理论素养,能高屋建瓴将工作经验、知识点系统化,更利于他人理解。
比如这篇《从 FM 推演各深度 CTR 预估模型》:
https://yq.aliyun.com/articles/614262?spm=a2c4e.11163080.searchblog.119.48912ec1Avric7
这篇文章清晰的指出:在 wide&deep 的基本框架下,上述论文都是在尝试不同的策略去把输入向量用一个 Embedding 层接入到 Dense 网络中。里面的每一篇论文我都看过,扪心自问,能不能写出类似的文章,遗憾的是不行。
解放思想,见识是阻碍我们发展的最大障碍
我司的图像做了有一段时间,一直是单机跑模型,有时候一跑要一两周,不少公司和我们类似。一直也没有觉得有什么问题,很少去想是不是要搞分布式 GPU 计算平台。以前的业务,上分布式大部分是因为数据规模很大。工程组也很犹豫要不要做,我们自己心里也没有个定论,拖了一两年。直到看了这篇文章:
https://arxiv.org/pdf/1706.02677.pdf
这才开拓了视野,马上就下了决心动手干。
他山之石可以攻玉
Scott Berkun 在《Myths of innovation》提出:一个新的 idea 背后,能找到多个已经存在的 idea。
最近把 Jared Diamond 的书重看了一遍,从《第三种黑猩猩》到《枪炮、病菌与钢铁》到《大崩坏–人类社会的明天》,作者兼具演化生物学、生理学、生物地理学等学科,取众家之长,融会贯通,形成独特的观点,写成如此优秀的作品。
深度学习在图像和 NLP 领域大放异彩,涌现出很多建设性的工作,又有多少能应用在工作中呢?
取上者得中,这一场 idea 的盛宴,不容错过。
满足好奇心
深度学习的理论发展远跟不上应用的发展,但一个个漂亮的结果背后,总是忍不住好奇它背后是为什么。
比如图像中的 milestone 模型 resnet,没有细看论文,一直认为是解决了 gradient vanishing/exploding 问题,而作者在原论文中:
https://arxiv.org/pdf/1512.03385.pdf
明确指出这个问题已经被 BN 和良好的 initialization 解决,resnet 解决了网络层数增加后 degradation 的问题,具体是什么问题,作者并没有深入。
后续这篇论文:
https://arxiv.org/pdf/1702.08591v2.pdf
更详细的描述了这个问题,并指出可以用 LL,不需要 residual 的结构,也能训练 deep 模型。
更上一层楼
现实世界中,很多问题需要都不需要太懂理论就能解决的不错。
这个背后的力量是抽象带来的,抽象做的好了,能让你不用懂其原理,也能发挥它的功效。就像我们每天用的手机,里面有量子力学的原理在发挥作用,但没有几个人懂量子力学。
随着各种工具越做越好,越来越多的细节被屏蔽,这个情况会越来越普遍,但随之带来是更多的应用可能性。就像今天的码农大多不懂编译器,也不会汇编,但 IT 业却前所未有的繁荣。
这几年在公司,还是做出了点业绩,但水平如何,如人饮水冷暖自知。比如 58 同城上麻利电工不一定懂电路原理,懂了电路原理也不能增加每小时的薪水,和我们何其相像。
居安思危,认清自身所处的产业环节,尽力向上游发展,而理论素养是其中一把钥匙。
提升理论素养,悟性低就多动手
深度学习大多数论文偏应用,对理论背景和数学知识要求不高,但就如此,理解他们也不是一帆风顺,可见纯理论工作之难。
最近被 BERT 刷爆朋友圈,发现对 transformer 的理解还不够。重新回去看下这篇文章:
https://arxiv.org/pdf/1706.03762.pdf
用 pytorch 动手实现了一把,发现了几个以前没有注意的问题:
论文里自称可以并行,但 decoder 部分怎么并行呢,下一步的 output 总要依赖上一步吧?然而作者是直接把 ground-truth 放入。self-attention 的理解是错的 KQV 让代码都简洁了。
果然资质平庸,还是需要动一遍手才能理解更多,叹悟性之差。过程中,花了不少时间在处理 Tensor 的 shape 变换上了,算是一种浪费吧。
再一次,没有银弹
并不是把每个算法都自己实现一遍,就能做出更好的成绩的,也不存在把公式推一边,能找到解决问题的灵丹妙药。
大多数我们并不是没有时间,反而是觉得自己在浪费时间,而不肯投入。然而浪费是常态,据说碳基生物的能量利用率不到 20%。再比如,公司里失败的项目远大于成功的。
最难的部分是不知道怎么准确定义问题。一百分的努力中,若有一二十分最终有收益,算很了不起了,没有银弹,只能先把量堆起来,量变引起质变。
道理易懂,行动不易
PRML 还停留在第 5 章,ESL 买了后在书架上积灰,电脑下面还垫着 MLAPP(颈椎是好了一点)。看论文的速度慢,数量也不多。但其间看了好多杂书,其中还有几本网文,比如大圣传,美其名曰帮弟弟考察行情。
头顶的发际线在告诉我,韶关易逝。现在我常想,20 岁的我在干嘛,估计以后还是会常想 30 岁的我在干嘛呢。
如果觉得自己明天起来就能变成意志力超人,那这 30 年算是白活了。虽然很多事情不及预期,但也收获了不少,就是这样,不完美、挣扎、痛苦,构成了生命的组成。只希望未来的时光,能牢记初心,切勿自甘堕落。
送一句话给自己:切勿做井底之蛙,坐井观天,固步自封。
原文链接:
https://zhuanlan.zhihu.com/p/44315278
https://zhuanlan.zhihu.com/p/48249123