「……我想这个问题还是要分类做。我强烈建议你们去读一下 Watson 的那篇 paper,那篇讲的最重要的一点就是『没有银弹』,不是用一种算法,而是把问题分成多个类别,每一类用一种算法去解决……」
吃过晚饭后,我第一次参与了文因金融问答技术组的当日复盘会。上面的话是我司鲍老师看过一个怪异的标签匹配问题后所提出的建议。
这一切似乎显得那么近,又那么远。不过有一点是肯定的:我通过文因互联的四轮面试了,我将成为一名算法工程师,与大家一起努力前进。
一切还要从头说起。
(一)机会
正是寒冬腊月时,街上、超市里处处张灯结彩,充满了红通通的年味儿。交接完工作,我正在回家过年的火车上,等待列车开动。百无聊赖时点开了我与学友日常交流的「薅机器学习群」,鲍老师两句刚发的话赫然于眼前:
「我们想招一个前端工程师。有人有兴趣吗?」
「好奇心,进取心,忍不住的动手精神。其实具体以前做过什么不太重要」
这立马激发了我的兴趣:毕竟在知道文因互联之前,我就在微博上关注过 @好东西传送门和鲍老师 @西瓜大丸子汤 ;2016 年,文因互联搬家到呼家楼后,我纯粹出于好奇而报名参加了几次讲座,既了解了知识图谱等自然语言处理技术与金融的结合,也见识到了文因在金融中踏实前进、迅速成长的风格。
正好刚刚辞职了,而我这次辞职正是为了找一份 NLP 或机器学习有关的工作。
我本科的专业是「过程装备与控制工程」,本科时也有打算未来要往算法之类的方向靠。通过与机械行业内的前辈交流,我发现一些当年所担心的事情在传统工业并不比 IT 少,比如深夜加班这类事(如果你想做出点成绩);而且我在大三大四时发现,自己的学习速度与顶尖学神不可同日而语,原先设想同时做两套差异比较大的工作、都做到不错(我还是不太愿意混日子的)、并慢慢转行的想法,恐怕难以实现,随着时间推移,转行成本可能越来越高,说不定那时候这想法就没机会实施了,所以不如趁早转过来。
至于为什么要转 NLP?这问题也没有太多复杂的原因:我好奇心旺盛,NLP 只是早期种下的多颗种子之一(此外还有操作系统、信息管理系统、设计会玩游戏的 AI,还有比如研究数学、物理等),比如我曾经想做一些定制化的爬虫、情感分析系统/助手等。但所有的想法不可能一步到位同时实施,三千弱水我可能都想饮,但胃容量和消化速度就那样,也就只能一瓢一瓢饮了,一口气想都喝完,只能是啥味道都不知道,还可能撑坏了肚子。
所以,不如先选定一个投入进去吧,不然太分散精力,也做不成一件完整点的事。然后我就只是先选定了它当目标,准备沉下去。为什么选它为目标,这个问题没有更深的答案,只是人为设定了界限:我想做,所以选择了它,就这么简单。它是目标,不是手段,所以也没有更多的理由。
既然文因有这个机会,为什么不去试试呢?虽然没什么前端的经验,反正试试看吧。于是我联系了鲍老师,他也很爽快:
「那节后等你回来,来咱们这里聊聊?」
(二)第一次面试
不出意外地,面试挂了;准确说,「面试」过了,但由于我此前没有做过前端任务,因此让我现场做一次 hackthon 模拟一个真实任务,但我并没能在给定时间内完成。
原因也不复杂:(1)想法太多,但缺乏沟通,总想着靠自己一个人写出来——然而其实在 hackthon 一开始,鲍老师就说过,你可以问未来要带你的那个同事;(2)准备缺乏——鲍老师已经在年前给了几个网站,建议我去学几样技术,但我在这期间并没有给出足够精力去折腾前端,仅在面试前不久(主要是年后)才花了一些时间「抱佛脚」。
事后我请教了当时面试我的三位前辈(包括鲍老师在内)。其中一位前辈建议我从初级工程师开始做起,深入掌握前后端各一门语言,打好基础,提高自己的学习能力;另一位前辈认为我可能准备得不充分,对前端工作展示的热情不高,或许要选一个自己确实喜欢的方向,会更专注一点。
还有一位前辈与我年龄相仿,建议我还是要注重兴趣,另外像我做到一半时发现进度不对,其实应该及时沟通想法,不只是埋头做,还建议我去多读些感兴趣的开源代码:「一方面体会思想,另一方面看看工程上的东西。代码呢,是写给人看的,凑巧能被计算机执行而已」
仔细想想,第一位前辈给的建议最踏实有效;第二位前辈指出了思想方向上的问题,他看得很准,无论是从面试中我坦诚透露出的信息,还是 hackthon 没发挥好,都确实从不同侧面透露出我对前端的热情十分有限,有「勉强」的味道;第三位前辈给出的建议则涉及角度最多。
面试文因的前端,没有通过。下一步,我该怎么做呢?
(三)反馈
直到今天我都非常感谢文因那天面试我的三位前辈,毫无保留给出的建议。重新梳理过自己从高考填志愿、本科四年求学生涯、本科毕业后到当时为止的路程,我想看有一点是很对的:这个时候确实不是以前端工程师的身份加入文因的好时候。为什么这么说?
原因也很简单:我现在对与NLP/机器学习直接打交道的工作,念想远远强于对前端工作的念想;在我当时的条件下,我还有一个 Udacity(中译名「优达学城」,以下简称「优达」)机器学习课程的毕业大项目未完成(我选的是 NLP 与机器学习的交叉项目「20 Newsgroups 文档自动分类」),我总觉得自己可能还有机会;这样的情况下,勉强自己强行接受前端工作,与我之前从本科开始勉强接受过的一些工作一样,内在动机都有限,业绩最多也就是差强人意——我还记得第一份工作刚离职时,有一位前辈告诉过我,年轻时过得都不会很容易,但比起三四十岁时要考虑的东西已经少得多,还是不要那过早妥协自己的人生,找点有内在动机的事情做。
梳理后我也很快做了个决定:先把优达的毕业项目完成,然后去找机器学习/NLP相关的工作;如果尝试过多次后仍然无法找到互相满意的职位,那时候再死心,我就按第一位前辈所说的那样,去做一些更基础性的东西补足自己的技能。
没办法,既然希望还没耗尽,谁知道这样的执着是好事还是坏事呢,走着瞧吧。我想。
(四)红旗还能扛多久?
随后就开始了「长征」。从二月面试结束,开始把优达机器学习课的正课收尾完成,然后就开始了文档分类项目的研究。最终完成到与 code reviewer 反复沟通并迭代修正,乃至最终完成课程、取得优达「机器学习纳米学位」,花费了 4 个月之久。
回过头时,停下来想想,这中间刨掉因为完美主义而造成的进度控制问题(比如,因为做不到只为了推进而推进,我会经常停下来深刨、阅读源码,甚至去挖掘最初开创这个概念的论文,即便没有精读,也研究了个大概),或许这样的速度也并不算太慢。这中间最耗时,也最煎熬的,恐怕是这样一个「经典问题」:
红旗还能扛多久?
从北师大对面的咖啡馆,到北邮校内的咖啡馆,到五道口的咖啡馆……每个地方都留下了自我斗争的身影,尽管从外人看来,这只是一个长期泡在咖啡馆自习的年轻人而已。因为进度一拖再拖,追求理解原理然后行动、而非边行动边理解原理,试图通过早期的小试来制订完美的行动计划、而非尽早上足够规模(如全部)的数据来迭代行动……无论从其他角度看,这些做法有什么优点,至少从进度控制上来讲,这些决策都不算好;我给自己定的找工作的截止日期,也一拖再拖。几乎每两三天,最长每周就要自我拷问一次:我的计划可行吗?我能找到机器学习/NLP相关的工作吗?我是不是还是将就着去做前后端开发就好了,不管是不是和机器学习/NLP有关?
但每一次,那个不肯妥协的我,还是能够比妥协的自我多撑一阵。兜兜转转,到了 5 月初,优达推出了「优等生计划报名」,大意是机器学习课程毕业生可以申请成为「导师」,帮助带领新的学习课程的学员,负责答疑等任务。本着「教即是学」的念头,同时希望认识更多志同道合的朋友,同时还抱着「万一真的不行,或许看有没有机会去优达帮助做运营吧」的念头(注:有类似的先例)。虽然很忐忑,我还是厚着脸皮提交了申请……没想到最后通过了申请,通知我有面试;我又紧锣密鼓地抓起了西瓜书、李航书和各种学习资料紧张地复习了一遍,没想到面试比预想中的来得顺;更没想到的是,在面时候,导师团总负责人要我发个人简介并给出样例时,我发现自己的经历实在是黯然失色,原以为这次过不了了……
或许厚脸皮也可以被称为勇气,它终究起了点作用。六月中旬时,导师团负责人突然通知我入选导师,而且马上就要面试学生带班。这真的是又惊又喜,但也是手忙脚乱地,一边给毕业项目做最后的修订,一边张罗起了面试、答疑等工作。
随后是忙忙碌碌面试的七月。面试了四五家公司:有知名大公司委托外包公司招聘偏数据清洗的岗位,笔试面试均顺利通过——这于我而言是有点惊喜的,至少说明我的能力在一定程度上得到了认可,虽然说限于岗位需求,只是部分认可,但也是一种认可了,这对于长期面对各种怀疑的我来说不啻为一剂鸡血;不过我觉得我尝试得还太少,不想过早死心,就又面试了后面几家,比如有试图把自然语言处理用于软件测试的前辈开的创业公司,也有来自某若干知名企业的人联合创办、在硅谷有分部的创业公司等,结果都是差强人意。
就这么到了八月。就在准备动摇的那一阵,优达的第一届毕业生典礼在上海开办了,抱着去寻找可能的机会以及结识同类的念头,我去了上海,同时也见到了我带的几个学员。他们鼓励我:程序猿遍地是,你应该发挥自己的优势;九月十月还有一拨机会,为什么不再试一次呢?
如今看来,真的是非常感激他们。我真的都已经买好了一些前后端包括爬虫的书籍,准备开始强化自己这块的技术了。他们这一席话,让我重新冷静了一下,心又定下来了。随于是八月又报名担任了另一个组织集智俱乐部 PyTorch 深度学习的课程助教,一边强化自己的机器学习理论与技能、一边强化自己的 Python 水平。同时,一边也在招聘网站上关注职位,有一天意外地在拉勾上看到了鲍老师发布的自然语言处理初级工程师招聘需求。我又惊又喜:半年前招聘的岗位和我的胃口一时不匹配,现在这是机会来了么?于是接下来一段时间,我密切关注公众号的动向。果不其然,近期不断更新的入职故事,每一篇都在告诉我:时候到了。于是我很快就联系了鲍老师。鲍老师依然是半年前那样热情:
「你对我们还有兴趣不? 有的话过来再聊聊。」
等的就是这句话。联系好时间后,紧锣密鼓整理了简历和这半年来的经历,在 9 月 13 日敲开了文因互联公司的门:
「你好,我是来面试的。」
(五)守得云开见月明
四轮面试中的面试官虽然与半年前不尽相同,但对待未来的合作者,依然是春风般的感觉;而我也不再是半年前的那个我,能够侃侃而谈独立完成的文本分类项目,同时也想清楚了未来几年内的发展方向等问题。结果自然无须多言,我成功转行成为一名算法工程师。
期间有多少变化?七杂八东,不一而足吧,比如开始写了一些 bash 脚本来总结并简化 Linux 日常、比如从完全不懂云到比较自如地使用云服务器以训练自己需要的模型及上传下载数据、比如现在写代码时比半年前会更有意识地经常做一些总结和抽象……总的来说,上一次的面试让我意识到我确实还有各种不足——那就挽起袖子干吧,遇到问题也不躲开,就想法子跨过去。此外的方面,大概有三四个点吧:
独立完成项目的能力不同了。我能够独立从头完成一个完整的与自然语言处理有关的机器学习项目,从数据预处理、表示建模、分类器训练、测试、调优,从查阅必要的论文到结合一些相应的技术、软件包来完成任务,能够靠自己完成整套流程,这某种意义上证明了自己独立完成业务的能力。同时,为了更好地完成项目、提高自己的技术水平,我真的按前辈的建议去挖某些源代码看了,比如 scikit-learn 的某些软件包、比如 TensorFlow 官方对 Word2Vec 的两种实现版本等,有需要时我还读懂并修改过了 scikit-learn 中部分软件的源代码。而半年前的我,甚至没有一个小小的个人「玩具项目」来表明自己能在前端上能和别人协作好,更不要说能让人相信我能在前端工作方面独当一面。
面试前基础准备量和准备态度和第一次大不相同。上一次是从节前到节后大约一周的时间,但一方面由于过年、更重要的可能是我确实对前端的热情有限、也可能是因为自大,总之每天并没有花足够时间去研究前端相关的内容,比如 JS 的语法、React 等框架的用法我都还没摸过一遍或者至少稍微做个小玩意儿练练手。而这一次,从鲍老师那里得到面试通知后,只有三天时间准备,除了必要的日常生活如吃饭洗澡睡觉等活动,为了节省交通时间,我全天都泡在家里,一方面研究和复习 Python 的一些核心基础库、还有梳理自己做过的项目,一方面如饥似渴地把《Effective Python》的后半本几乎都啃完了,同时在自己电脑上又敲了些代码练习。
面试前心态和第一次也不太一样。上一次我是充满了焦虑,感觉东西好多,无从下手,什么都想看完,但最后什么都没看完一遍。而这一次,我就「咸鱼」一些了,对自己不再抱有不切实际的完美主义期望,而是更加务实了:从接到面试通知时决定把 Python 文档全看一遍,到决定只把《Effective Python》后半本刷完,好好巩固之前掌握的内容,这个决策上的变化基本上就花了不到半天时间。在看完这本书后,我还能根据学到的知识反过来梳理此前优达项目中的不足。
当然,某种意义上说,虽然最开始的焦虑感都是一样的,最后决策结果却不同,与两次面试前对两种技术的掌握基础也不一样或许也有关:JS 我几乎没怎么写过,更别说有什么项目经验(哪怕是出于自己学习和研究的目的写的小项目);而加上这半年, Python 我已经写了至少一年多,还有写过完整的个人项目。某种意义上说,这也算是长期积累与「抱佛脚」之间的差别吧,长期积累让自己更多了点底气,反而更加务实,不至于一把抓瞎。
在进度控制上,这半年踩了一个巨大的坑,即优达学城的机器学习课毕业项目上,我抱有不切实际的完美主义期望、迭代过慢、闷头做太多(但其实理论上也还达不到足够严格的标准),再加上中间突然冒出折腾系统的想法又耽误了两周…导致一个大概最多两个月就能完成的项目,我给活生生拖到了四个月才完成。于是…当时的奖学金就没了(和当时优达对该课程的一个奖励政策有关)。白花花的银子买来的教训,肉疼。这也一定程度上也提醒了我:需要理清任务的核心目标,理清优先级,尽早围绕核心目标(「客户」关心的内容)展开迭代;非核心目标但自己感兴趣的(比如自己的而非「客户」提出的更高要求、比如自己想用什么新的工具完成任务),可以研究,但必须是建立在核心目标推进和迭代没问题的基础上,而不是想到什么地方发散到什么地方去。
有了这个教训,随后在 PyTorch 课程的助教工作中,我就有所改进了:比如先及时实现一些原型,然后提交到 git 上,及时写完报告;在完成一个能通过作业要求的 60 分内容后,再不断迭代以逼近八九十分、或者再尝试自己的各种脑洞。事实证明这样的做法是对的,比如我在 PyTorch 课程中有一个「MNIST 加法机」的作业,最开始我冒出了两个脑洞,一个是直接用传统的 CNN 完成,另一个则是有带点迁移学习的味道,但当时我对迁移学习还知之甚少,于是我果断先用 CNN 写了一个版本实现出来,然后把该版本优化到 96% 的准确率,最后才尝试迁移学习的脑洞。虽然在作业提交截止日期前我最终没能写出那个迁移学习的版本,但并不影响我在这个作业上拿了高分:因为我已经完成了「客户」(老师)对任务的基本要求。
(六)没有终点的「长征」
不知道其他人会不会觉得,也就半年的历程,至于用「长征」这个词嘛?会不会有些夸张?对此,有一句用滥了的词:「如人饮水,冷暖自知。」
但我也清楚,这不是终点。这段路途的价值可能并不在落在文因的这个「终点」或者「里程碑」,也在这个过程中所面对的来自朋友的、家人的、乃至自己的怀疑,还有在这个过程中来自朋友的支持和理解(包括但不限于岗位推荐、吃吃喝喝、支持我对理想的坚持等等),也是面对这些怀疑的过程、和朋友共处的过程,造就了现在的我。多了几分对自己的肯定、多了几分韧性,更习惯了一些质疑,也对「守得云开见月明」有了更深的体会了。
到现在为止我仍然不是一个完人,我想我到人生的终点时也不会是。但人的一生就是成长的一生,如果没有了那些「怀疑」作为对手,或许成长的意义也会少了几分;或许更重要的,不是一开始是否是完美,或者「结果」是否完美(结果,所有人都要回归黄土),而是在「怀疑」与「信任」的拉扯中,找到属于自己的演化路径。或许回首往事时,只有这些看似不经意的一个个细节积累而成的演化路径,才是我们人生真实存在过的、值得对酒笑谈的一点下酒菜吧。
P.S. 如果你对成为一名算法工程师也有向往,如果你也打算为这一份念想做点什么,欢迎你加入我们,可以投递简历到 ceo@memect.co 除此之外,文因还会不定期举办开放日活动,关注文因学堂公众号可以了解最新活动资讯,也欢迎你来交流。
加入文因学堂金融极客交流群
如果你是喜爱科技的金融从业人员,我们诚挚邀请你加入【文因学堂金融极客群】,参与文因学堂核心粉丝的交流圈。添加小助手微信号 wenyinai42,附上姓名、所属机构、部门及职位,审核后会邀请您入群。
发表回复