ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

神经网络复兴二十年:从反向传播到深度学习基石

神经网络复兴二十年:从反向传播到深度学习基石 1. 从寒冬到复兴1986-2006这二十年到底发生了什么如果你在1980年代中期进入这个领域大概率会听到两种截然不同的声音。一种来自刚读完Minsky那本《Perceptrons》的人他们会告诉你单层感知机的局限已经被数学证明这条路走不通另一种来自少数还在坚持的研究者他们手里攥着反向传播的推导草稿觉得事情远没有结束。1986年Rumelhart、Hinton和Williams在《Nature》上发表了那篇关于反向传播的论文这被后来很多人视为神经网络复兴的起点。但如果你真的去翻那个时期的文献会发现复兴不是一夜之间发生的它更像是一群人用将近二十年的时间一点一点把地基重新打牢。这二十年的核心矛盾其实很清晰多层网络有了训练方法但算力、数据和理论工具都跟不上。反向传播解决了“怎么调参数”的问题可它没有解决“为什么这样调能work”的问题。于是整个1986到2006年研究者们实际上在做三件事把反向传播从理论变成可用的工程方法、寻找新的网络结构来突破它的局限、以及在算力不足的条件下尽可能榨出模型的性能。今天你随手就能调用的nn.Linear和nn.Conv2d背后是这二十年里无数次的试错和修正。我之所以想认真梳理这段历史是因为现在很多人学神经网络直接从Transformer或者扩散模型切入跳过了中间这段“手工时代”。结果就是遇到梯度消失、初始化敏感、训练不收敛这些问题时只能靠调参玄学不知道这些坑在二十年前就被系统性地研究过。这篇文章会沿着时间线把1986到2006年间几个关键的技术节点拆开讲清楚包括它们解决了什么问题、留下了什么隐患、以及今天你在写代码时还能用上的那些经验。2. 反向传播的工程化从数学公式到能跑的代码2.1 为什么1986年的反向传播和今天的理解不太一样Rumelhart那篇论文里的反向传播本质上就是链式法则在计算图上的应用。但如果你去看当时的描述会发现他们并没有用“计算图”这个概念而是直接对每一层的权重求偏导。这种写法在数学上没问题但在工程实现上会带来一个麻烦每增加一种新的层类型就要重新推导一遍梯度公式。这就是为什么那个年代的代码库往往只支持全连接层和少数几种激活函数想加个新结构得从头写梯度。今天我们用PyTorch或者JAX框架会自动帮你做反向传播你只需要定义前向过程。这个转变的起点其实是1980年代末到1990年代初的一系列工作研究者们开始意识到可以把网络表示成有向无环图然后对图做反向遍历。这个思路后来演变成了自动微分但在当时它更多是一种工程上的简化手段。我个人的经验是理解这段历史对调试现代框架很有帮助——当你看到loss.backward()报错说某个张量没有梯度时本质上就是计算图里有一条路径断了这和当年手工推导时漏掉某一层的偏导是同一类问题。2.2 梯度消失1986年就埋下的雷反向传播刚出来的时候大家都很兴奋觉得只要层数够多网络就能拟合任何函数。但很快有人发现层数一多靠近输入层的那些参数几乎不更新。这个问题在1991年由Hochreiter正式分析清楚他当时用的词是“梯度消失”指的是反向传播时梯度经过多层链式相乘后指数级衰减。为什么会这样如果你用的是Sigmoid激活函数它的导数最大值只有0.25每经过一层就要乘一个小于0.25的数。假设有10层梯度传到第一层时已经乘了10次量级大概在10的负6次方左右。这个数值小到几乎无法对权重产生有效更新。当时没有ReLU也没有BatchNorm大家能想到的办法无非是减小层数、换激活函数、或者用一些启发式的初始化。但这些都治标不治本直到2006年Hinton提出逐层预训练才算是给深层网络的训练找到了一个可行的路径。提示今天你在用Sigmoid做激活时如果发现深层网络不收敛第一反应应该是换ReLU或者Tanh而不是去调学习率。这个直觉就是从这段历史里来的。2.3 那个年代的训练技巧没有Adam没有BatchNorm怎么让网络收敛1986到2006年间训练一个网络远比现在麻烦。没有自适应学习率没有批量归一化甚至连像样的初始化方法都没有。当时常用的做法是小学习率加动量学习率通常设在0.01到0.1之间动量系数0.9左右。动量的作用是对抗梯度方向的高频震荡让更新更平滑。权重衰减也就是L2正则系数一般在0.0001到0.001之间。这个做法到现在还在用只是现在有了AdamW之后实现方式变了。早停因为没有好的正则化手段大家会盯着验证集损失一旦不再下降就停止训练。这个习惯在今天依然有效尤其是小数据集上。手工特征工程在CNN普及之前很多任务靠的是人工设计特征加全连接网络。这也是为什么那个年代的数据集规模都很小因为特征提取本身就很耗时。我实际复现过那个年代的训练流程最大的感受是初始化太重要了。当时常用的初始化是均匀分布范围大概在正负1除以sqrt(输入维度)左右。这个范围和后来Xavier初始化的思路是一致的只是当时没有理论证明更多是靠经验。如果你现在用PyTorch默认的初始化去训练一个很深的网络效果通常不会太差这其实是站在了这二十年研究的肩膀上。3. 结构创新CNN、RNN和那些被遗忘的尝试3.1 卷积神经网络从福岛邦彦到LeCun的LeNet-5卷积的思想其实比反向传播更早。1980年福岛邦彦提出的Neocognitron已经包含了卷积和池化的雏形但它没有用反向传播训练而是靠无监督的竞争学习。真正把卷积和反向传播结合起来的是LeCun他在1989年提出了用反向传播训练卷积网络并在1998年完善成了LeNet-5。LeNet-5的结构今天看起来很简单两个卷积层、两个池化层、三个全连接层总共大约6万个参数。但它的设计思路影响深远。比如局部感受野的概念指的是每个神经元只连接输入的一个小区域这大幅减少了参数数量。再比如权重共享同一个卷积核在整张图上滑动这进一步降低了参数量同时带来了平移不变性。我在复现LeNet-5时注意到一个细节LeCun当时用的是平均池化不是最大池化。最大池化是后来才流行起来的因为它在很多任务上效果更好。但平均池化在某些场景下依然有用比如需要保留更多背景信息的时候。这个选择没有绝对的对错取决于你的任务需求。3.2 循环神经网络Elman网络和它的梯度难题RNN的早期工作可以追溯到1980年代的Hopfield网络但真正用于序列建模的是Elman在1990年提出的Elman网络。它的结构很简单一个隐藏层隐藏层的输出会反馈到下一时刻的输入。这种结构天然适合处理变长序列但训练起来非常困难因为反向传播要沿着时间展开梯度消失问题比前馈网络更严重。当时有人尝试用“截断反向传播”来缓解这个问题也就是只往回传固定步数比如10步或20步。这个做法在今天依然有用尤其是在处理超长序列时你不可能把整个序列都展开。但截断会丢失长距离依赖所以后来才有了LSTM。LSTM是1997年由Hochreiter和Schmidhuber提出的核心是引入了门控机制和细胞状态。细胞状态像一条传送带梯度可以沿着它几乎无衰减地传递。这个设计非常巧妙直到今天LSTM依然是很多序列任务的首选尤其是在数据量不够大、没法训练Transformer的场景下。3.3 那些没成为主流的网络RBF、SNN和液态网络除了CNN和RNN这二十年里还有很多其他尝试。RBF网络径向基函数网络在1990年代一度很流行它的隐藏层用的是径向基函数输出层是线性的。RBF网络训练速度快因为隐藏层可以用无监督方法初始化但它的泛化能力不如多层感知机所以后来慢慢边缘化了。脉冲神经网络SNN是另一条路线它模拟的是生物神经元的脉冲发放机制。SNN的理论基础在1990年代就已经奠定但因为它需要特殊的硬件支持而且训练算法不成熟所以一直没有大规模应用。最近几年因为神经形态芯片的兴起SNN又重新受到关注但它的训练方法依然是个开放问题。液态神经网络是更晚近的概念但它的思想根源可以追溯到这二十年里对动态系统的研究。它的核心是用微分方程来描述神经元的动态然后通过数值方法求解。这个思路和Neural ODE是一脉相承的只是当时没有自动微分工具实现起来非常困难。4. 理论突破为什么深层网络能训练4.1 通用逼近定理能拟合不代表能训练1989年Hornik等人证明了通用逼近定理一个包含足够多神经元的前馈网络可以以任意精度逼近任何连续函数。这个定理在当时被广泛引用作为神经网络能力的理论保证。但如果你仔细看它的条件会发现它只说了“存在这样一组参数”没有说“你能找到这组参数”。这就是理论和实践的鸿沟。通用逼近定理保证了网络有解但反向传播能不能找到这个解取决于损失函数的形状、初始化、优化算法等一系列因素。1990年代很多研究者花了大量精力去研究损失函数的性质比如有没有局部极小值、鞍点的影响有多大。这些研究后来演变成了非凸优化的理论但在当时更多是靠实验来指导实践。4.2 逐层预训练2006年的关键转折2006年Hinton提出了深度信念网络DBN和逐层预训练的方法。核心思想是先用无监督学习比如RBM逐层初始化网络然后再用反向传播做微调。这个方法在MNIST等数据集上取得了当时最好的效果重新点燃了大家对深层网络的兴趣。逐层预训练为什么有效一个直观的解释是无监督预训练把每一层的参数初始化到了一个比较好的区域使得反向传播不容易陷入差的局部极小值。这个解释后来被一些实验证实但也有人发现随着ReLU、BatchNorm和更好的初始化方法的出现逐层预训练变得不再必要。今天你几乎看不到有人用RBM做预训练了但它的历史意义不可忽视——它证明了深层网络是可以训练的这为后来的深度学习爆发铺平了道路。4.3 从预训练到端到端2006年之后的路线分化2006年之后领域出现了两条路线。一条是以Hinton为代表的“预训练加微调”另一条是以LeCun为代表的“端到端训练”。后者在2012年AlexNet出现后成为主流因为GPU算力的提升让端到端训练变得可行。但预训练的思想并没有消失它只是换了一种形式——今天你在做NLP任务时用的BERT、GPT本质上都是预训练加微调只是预训练的方式从RBM变成了自监督学习。这个演变过程给我的启发是很多技术不是被淘汰了而是被重新包装了。如果你理解RBM预训练的原理再看BERT的Masked Language Model会发现它们都在做同一件事——让网络在无标签数据上先学到一个好的表示然后再用有标签数据微调。只是实现手段不同核心思想是一致的。5. 数据与算力被低估的瓶颈5.1 MNIST为什么能成为二十年的标准测试集MNIST是1998年由LeCun等人整理的包含6万张训练图像和1万张测试图像每张是28x28的灰度手写数字。这个数据集在当时算比较大的但放到今天连一个很小的模型都能轻松达到99%以上的准确率。那为什么它统治了这么多年原因很简单在算力和数据都有限的时代MNIST提供了一个足够难但又不会太难的任务。它的规模适中训练一个模型只需要几分钟到几小时适合快速验证想法。而且它的任务定义清晰评价指标简单方便不同方法之间比较。我在做新模型的原型验证时依然会先用MNIST跑一遍确认没有低级错误再去上更大的数据集。5.2 算力限制如何塑造了那个年代的研究风格1986到2006年间大部分研究者用的是CPU内存以MB计硬盘以GB计。训练一个卷积网络可能需要几天甚至几周。这种限制直接影响了研究风格模型规模小LeNet-5只有6万参数放到今天连一个层都比它大。数据集小MNIST、CIFAR-10是主流ImageNet直到2009年才发布。实验周期长一个想法从提出到验证可能需要几个月所以大家更倾向于做理论分析而不是大规模试错。代码复用率高因为重写一遍太耗时很多人会直接修改已有的代码库这也导致了那个年代的代码风格比较统一。我有时候会想如果当时有GPU深度学习会不会提前十年爆发大概率会。但历史没有如果正是这些限制逼着研究者去思考更本质的问题而不是靠堆算力解决问题。这种思维方式在今天依然有价值尤其是在资源有限的情况下。5.3 GPU的早期应用从图形渲染到通用计算GPU最初是为图形渲染设计的但它的并行计算能力很快被研究者注意到。2000年代初有人开始尝试用GPU加速神经网络训练但当时的编程接口很不友好需要把计算映射到图形API上。直到2007年CUDA发布GPU通用计算才真正变得可行。这个时间点很关键2006年Hinton提出逐层预训练2007年CUDA发布2012年AlexNet用GPU训练夺冠。这三件事连在一起构成了深度学习爆发的完整链条。如果没有GPU逐层预训练可能只是一个小众技巧不会引发后续的连锁反应。所以我在看技术史时会特别关注那些“使能技术”——它们本身可能不是主角但没有它们主角就上不了台。6. 这二十年留下的遗产今天你还在用的那些东西6.1 反向传播、梯度下降和正则化三大基石反向传播、梯度下降和正则化是这二十年里沉淀下来的三大基石。反向传播解决了“怎么算梯度”梯度下降解决了“怎么更新参数”正则化解决了“怎么防止过拟合”。今天你用的Adam、RMSProp都是梯度下降的变体Dropout、Weight Decay都是正则化的变体但核心思想没有变。我在教新人时会让他们先手写一遍反向传播不依赖框架。这个过程很痛苦但能帮你理解框架在背后做了什么。比如当你看到loss.backward()时你知道它是在做链式法则的反向遍历当你看到optimizer.step()时你知道它是在用梯度更新参数。这种理解在调试复杂模型时非常有用。6.2 那些被淘汰的方法RBM、预训练和手工特征RBM预训练、手工特征工程、早停这些方法在今天已经很少用了。但它们被淘汰的原因各不相同。RBM是因为有了更好的初始化方法和正则化手段手工特征是因为CNN能自动学习特征早停则是因为有了更系统的正则化方法比如Dropout和BatchNorm。但淘汰不等于无用。我在处理小数据集时依然会用早停来防止过拟合在特征工程方面虽然CNN能自动学习但理解数据的物理意义依然重要尤其是在科学计算领域。所以我的建议是不要因为一个方法过时了就完全忽略它理解它的适用场景和局限比盲目追新更有价值。6.3 从这二十年里能学到的研究方法论这二十年里研究者们面对的是一个“工具不完善、算力不足、数据有限”的环境。他们的应对方式给了我很多启发先验证想法再优化实现用MNIST快速验证再去上大数据集。理论分析和实验验证并重梯度消失既有理论分析也有实验佐证。关注使能技术GPU、自动微分、大数据集这些不是主角但决定了主角能走多远。保持耐心从反向传播到深度学习爆发中间隔了二十多年。很多想法需要时间才能成熟。我在做自己的项目时会刻意留出时间做原型验证而不是一上来就追求完美。这个习惯就是从这段历史里学来的。先跑通再优化最后才是规模化。这个顺序不能乱乱了就容易在细节里迷失方向。6.4 如果你要复现那个年代的代码需要注意什么如果你真的想复现1986到2006年间的经典模型有几个坑需要提前知道初始化当时的初始化方法比较粗糙你需要自己实现Xavier或He初始化否则深层网络很难训练。激活函数Sigmoid和Tanh是主流但梯度消失严重。建议先用ReLU跑通再换回Sigmoid对比效果。优化器没有Adam你需要自己实现动量SGD。学习率和动量系数需要仔细调。数据预处理当时的预处理很简单通常只是归一化到0到1或者减均值除方差。但这一步对训练影响很大不要跳过。评估指标当时的评价指标比较单一主要是准确率。但你要注意区分训练集和测试集的表现避免过拟合。我复现LeNet-5时用PyTorch大概花了半天时间就跑通了但调到接近论文里的效果花了将近一周。最大的瓶颈是学习率和初始化的配合这两个参数稍微偏一点训练就会发散或者停滞。所以如果你要复现建议先用小学习率加动量跑通再逐步调整。7. 从2006到今天的连接点2006年之后深度学习进入了一个新的阶段。ReLU、BatchNorm、Dropout、Adam这些方法陆续出现GPU算力持续提升ImageNet等大规模数据集发布最终在2012年AlexNet夺冠后引发了爆发。但如果你仔细看这些新方法会发现它们都在解决1986到2006年间遗留的问题ReLU解决梯度消失BatchNorm解决内部协变量偏移Dropout解决过拟合Adam解决学习率选择。所以这二十年不是一段被超越的历史而是一段被继承的历史。今天你写的每一行神经网络代码背后都有这二十年里某个研究者的影子。理解这段历史不是为了怀旧而是为了在遇到问题时知道该往哪个方向找答案。梯度消失、初始化敏感、训练不收敛这些问题在二十年前就被系统研究过答案就在那些泛黄的论文里。
返回列表