【波士顿,剑桥市,MIT人工智能实验室】
2016年1月12日,凌晨2点17分
陆星衍按下回车键,屏幕上的代码开始运行。实验室里只有他一个人,其他博士生要么早就回去睡觉了,要么今晚根本没来。白色的LED灯管发出均匀而冷冽的光,照在银灰色的机箱阵列上,那些机器正在嗡嗡低鸣,为他的神经网络训练提供算力。
窗外的波士顿冬夜漆黑如墨,只有远处查尔斯河对岸的哈佛校园还亮着几点灯光。实验室位于MIT斯塔塔中心的三楼,巨大的玻璃窗外能看到校园里光秃秃的树木和积着薄雪的小径。
陆星衍盯着屏幕上滚动的日志:
Epoch 100/1000
Training Loss: 0.437
Validation Loss: 0.598
梯度范数: 0.003
梯度范数太小了。小到几乎可以忽略不计。
他靠在椅背上,闭上眼睛,右手拇指和食指按在鼻梁两侧。这是他从高中就有的习惯,思考难题时会这样做。
梯度消失。深度神经网络训练中最经典也最恼人的问题之一。网络层数太深,反向传播时梯度信息逐层衰减,传到最前面的层时已经近乎为零,导致前面的参数几乎无法更新。
他试过几种方法:批归一化、残差连接、梯度裁剪。都有改善,但都不够彻底。模型在训练集上表现尚可,但在验证集上很快就过拟合了。
他睁开眼睛,从桌上拿起一叠草稿纸。最上面那张已经写满了公式:链式法则的展开,激活函数的导数,权重矩阵的更新规则。
他在空白处写道:“如果是清辞,会用动量优化。”
这不是随意想到的。是高三那年,他们一起准备信息学竞赛时,沈清辞解决过一个类似的问题:递归搜索时,在深层分支中容易迷失方向,找不到最优解。沈清辞当时提出了一个方法:给搜索过程加上“动量”,让它不会在某个局部停滞太久,而是能够跳出陷阱,继续探索。
“就像滑雪,”沈清辞当时解释说,“如果你在某个小坑里停住了,就永远出不来。但如果你有足够的速度,就能冲过去。”
陆星衍记得自己当时的回答:“动量在物理中是惯性,在算法中是历史信息的积累。”
“对!就是这个意思!”
那是2012年的冬天,云城一中的计算机教室里,暖气片发出咝咝的声音,窗外在下小雪。他们挤在一台电脑前,沈清辞的手指在键盘上快速敲击,陆星衍在旁边看着他写代码,偶尔提出修改建议。
四年了。
陆星衍放下笔,看向窗外。波士顿的雪比云城大得多,也更冷。但他记忆里最清晰的,还是云城那种湿冷的冬天,和计算机教室里那台老旧的暖气片。
他重新看向屏幕。动量优化。他试过了,Adam优化器本身就包含动量概念。但也许可以调整参数?或者尝试Nesterov加速梯度?
他打开另一个终端窗口,开始修改代码。手指在键盘上敲击的速度很快——这是他在华清四年训练出来的速度,也是……当年和沈清辞一起写代码时养成的节奏。
他们曾经比赛谁打字更快。沈清辞总是赢,因为他手指更长,而且有种天生的节奏感。但陆星衍的逻辑更严谨,bug更少。
“我们是完美组合,”沈清辞有一次说,“我负责速度,你负责正确性。”
陆星衍当时没说什么,但心里同意。
完美的组合。
但已经四年没有组合了。
【旧金山湾区,斯坦福大学格林图书馆】
2016年1月12日,晚上11点03分
沈清辞盯着屏幕上的递归函数,眉头紧锁。图书馆的这个角落很安静,只有他一个人,还有几排布满灰尘的旧书——这里存放的是1990年代以前的计算科学文献,几乎没人来看。
窗外是斯坦福的夜晚。加州冬天温和得多,没有雪,只有偶尔的细雨。路灯在湿漉漉的路面上投下黄色的光晕。
屏幕上的代码看起来很简单:
```python
def fibonacci(n):
if n