当前位置: 首页 > 科技观察

特斯拉AI总监:我复现了LeCun 33年前神经网络,和现在区别不大

时间:2023-03-17 18:05:33 科技观察

TeslaAI负责人:我复现了33年前LeCun的神经网络,和现在差别不大,复现了1989年的一篇论文。一是为了好玩,二是想看看过去33年深度学习领域发生了哪些有趣的变化,是什么让Lecun当年卡住了。此外,他设想了2055年的人们将如何看待当今的深度学习研究。1989年,YannLeCun等人发表了一篇名为“BackpropagationAppliedtoHandwrittenZipCodeRecognition”的论文。在我看来,这篇论文具有一定的历史意义,因为据我所知,它是使用反向传播训练的端到端神经网络最早的实际应用。论文链接:http://yann.lecun.com/exdb/publis/pdf/lecun-89e.pdf虽然数据集和神经网络比较小(7291张16x16灰度数字图像,1000个神经元),但这33年后,这篇论文仍然没有过时:它提供了一个数据集,描述了神经网络的架构、损失函数、优化,并给出了训练集和测试集的实验分类错误率。它是如此具有辨识度,可以归类为现代深度学习论文,但它是33年前的。所以我开始复制这篇论文,部分是为了好玩,部分是为了将这个练习作为一个案例研究来深入学习进展的本质。实现我试图尽可能接近论文并在PyTorch中复制每个细节,请参见以下GitHub存储库:Repro链接:https://github.com/karpathy/lecun1989-repro原始网络是在Lisp中实现的,使用Bottou和LeCun在1988年提出的反向传播模拟器SN(后来改名为Lush)。论文是法文的,看不懂。但在句法上,您可以使用高级API指定神经网络,类似于您今天在PyTorch中所做的事情。在当代软件设计中,库设计分为以下三个部分:1)快速(C/CUDA)通用张量库,用于实现对多维张量的基本数学运算;2)一个autograd引擎,用于跟踪之前的计算图并为backwardpass生成操作;3)一个可编写脚本(Python)的深度学习高级API,包括常见的深度学习操作、层、架构、优化器、损失函数等。训练在训练过程中,我们必须对由以下组成的训练集执行23次传递7291个样本和总共167693个样本/标签被呈现给神经网络。原始网络在SUN-4/260工作站(1987年发布)上训练了3天。今天,我可以在我的MacBookAir(M1)CPU上运行这个实现,只需要90秒(大约3000倍的加速)。我的conda设置为使用本机amd64构建而不是Rosetta仿真。如果PyTorch能够支持M1的所有特性(包括GPU和NPU),加速效果可能会更加明显。我也试过纯粹在A100GPU上运行代码,但训练速度较慢,很可能是因为网络太小(4层convnet,最多12个通道,9760个总参数,64KMAC,1K激活),并且SGD一次只使用一个例子。也就是说,如果真的想用现代硬件(A100)和软件基础设施(CUDA、PyTorch)解决这个问题,我们需要将每个示例的SGD换成全批训练,以最大限度地提高GPU利用率。这样做,我们有可能实现额外的约100倍的训练加速。复现1989年的实验结果原论文给出了如下实验结果:eval:splittrain。损失2.5e-3。误差0.14%。未命中:10eval:拆分测试。损失1.8e-2。误差5.00%。未命中:102但在第23次通过后,我的训练脚本repro.py打印出了结果:eval:splittrain。损失4.073383e-03。误差0.62%。未命中:45eval:拆分测试。损失2.838382e-02。误差4.09%。misses:82因此,我只是粗略地复现了论文的结果,数字并不准确。似乎不可能得到与原始论文完全相同的结果,因为原始数据集随着时间的推移已经丢失。因此,我不得不使用更大的MNIST数据集对其进行模拟,取其28x28位数字,使用双线性插值将它们缩小到16x16像素,并从中随机抽取正确数量的训练集和测试集示例而不进行替换。但我敢肯定还有其他原因会导致精确的重现性,例如论文对权重初始化方案的描述有点过于抽象;PDF文件中可能存在一些格式错误(小数点、平方根符号被擦除等)。例如,论文告诉我们权重初始化是从单位“24/F”中提取的,其中F是fan-in,但我猜它实际上是“2.4/sqrt(F)”,其中sqrt有助于保持输出的标准偏差。H1和H2层之间具体的稀疏连接结构也有问题,论文只说是“根据一个scheme选择的,先不列出来”,所以我只好对重叠块做一些合理的猜测稀疏结构。该论文还声称使用tanh非线性,但我担心这实际上可能是“归一化tanh”映射ntanh(1)=1,可能会添加减少的残差连接,这在当时非常流行,以确保tanh的平尾至少有一点梯度。最后,该论文使用了“牛顿法的特殊版本,它使用了Hessian矩阵的正向对角线近似”。但我只使用了SGD,因为它简单得多。此外,“这种算法预计不会导致学习速度的大幅提高,”该论文的作者说。以新的方式尝试是我最喜欢的部分。我们生活在33年后,深度学习已经是一个非常活跃的研究领域。以我们目前对深度学习的理解和这33年积累的研发经验,我们能在原来的结果上提高多少?我的初步结果是:eval:splittrain。损失4.073383e-03。误差0.62%。未命中:45评估:拆分测试。损失2.838382e-02。误差4.09%。类别的简单分类法。但当时,这被建模为目标为-1(对于负类)或+1(对于正类)的均方误差(MSE)回归,并且输出神经元也具有tanh非线性。因此,我删除了输出层上的tanh以获得类logits,并在标准(多类)交叉熵损失函数中交换它们。这种变化极大地增加了训练误差,完全过度拟合了训练集:eval:splittrain。损失9.536698e-06。误差0.00%。未命中:0eval:拆分测试。损失9.536698e-06。误差4.38%。未命中:87我怀疑如果你的输出层有(饱和的)tanh非线性和MSE错误,你必须更加注意权重初始化的细节。其次,根据我的经验,经过微调的SGD可以很好地工作,但当前的Adam优化器(学习率为3e-4)几乎总是一个很好的基线,几乎不需要调整。因此,为了让我更有信心优化不会影响性能,我切换到学习率为3e-4的AdamW,并在训练期间将其降至1e-4。结果如下:eval:splittrain。损失0.000000e+00。误差0.00%。未命中:0eval:拆分测试。损失0.000000e+00。误差3.59%。misses:72这给出了比SGD略有改善的结果。但是,我们还需要记住,默认参数也有一点权重衰减,这有助于防止过度拟合。由于过拟合现象依然严重,接下来我将介绍一种简单的数据增强策略:将输入图像水平或垂直移动1个像素。然而,由于这模拟了一个更大的数据集,我还必须将通道数从23增加到60(我验证了简单地增加原始设置中的通道数并没有显着改善结果):eval:splittrain.loss8.780676e-04。误差1.70%。未命中:123eval:拆分测试。损失8.780676e-04。误差2.19%。misses:43从测试错误可以看出,上面的方法很有帮助!数据增强是对抗过度拟合的一个相当简单、标准的概念,但我在1989年的论文中没有看到它,也许它是稍晚一些的创新?由于过度拟合仍然存在,我从我的工具箱中取出了另一个新工具——Dropout。我在参数数量最多的层(H3)之前添加了0.25的弱dropout。由于dropout将激活设置为零,因此将它与具有[-1,1]范围内活动的tanh一起使用没有多大意义,因此我还用更简单的ReLU激活函数替换了所有非线性。因为dropout会在训练中引入更多噪音,所以我们还必须训练更长时间并进行80次训练。最终结果如下:eval:splittrain。损失2.601336e-03。误差1.47%。未命中:106评估:拆分测试。损失2.601336e-03。误差1.59%。/2007错误!我验证了简单地将原始网络中的tanh换成relu并没有产生实质性的收益,所以这里的大部分改进来自于dropout。总体而言,如果我回到1989年,我会将错误率降低60%(从80个错误减少到30个错误),测试集上的总体错误率仅为1.5%。但这种收获并不是“免费午餐”,因为我们几乎将训练时间增加了两倍(从3天到12天)。但推理时间不会受到影响。剩下的错误如下:走得更远但是,在完成了MSE→Softmax,SGD→AdamW的改造,加入数据增强,dropout,用relu代替tanh之后,我开始逐渐放弃那些容易实现的想法,开始尝试更多的东西(比如重量归一化),但没有得到更好的结果。我还尝试将ViT缩小为与参数和触发器数量大致匹配的“迷你ViT”,但它无法与ConvNet的性能相媲美。当然,在过去的33年里,我们看到了很多其他的创新,但其中很多(例如残差连接、层/批归一化)仅在大型模型中有用,并且主要用于稳定大型模型。模型优化。在这一点上,进一步的收益可能来自增加网络的规模,但这会增加测试时推理的延迟。另一种修改数据以提高性能的方法是增加数据集的大小,尽管这是以美元标签成本为代价的。在这里再次粘贴我们原来的基线:eval:splittrain。损失4.073383e-03。误差0.62%。未命中:45eval:拆分测试。损失2.838382e-02。误差4.09%。misses:82由于整个MNIST现在可用,我们可以将训练集大小扩大7倍(从7291到50000)。仅从添加的数据来看,运行基线训练100次就显示出一些改进:eval:splittrain。损失1.305315e-02。误差2.03%。未命中:60eval:拆分测试。损失1.943992e-02。误差2.74%。misses:54进一步结合现代知识的创新(如上一节所述)将达到最佳性能:eval:splittrain。损失3.238392e-04。误差1.07%。未命中:31eval:拆分测试。损失3.238392e-04。误差1.25%。未命中:24总之,在1989年,简单地扩展数据集将是提高系统性能而不影响推理延迟的有效方法。反思让我们总结一下我们作为2022年的时间旅行者,从1989年的深度学习SOTA技术中学到的东西:首先,33年来宏观层面没有太大变化。我们仍在构建由神经元层组成的可微分神经网络架构,并使用反向传播和随机梯度下降对它们进行端到端优化。一切看起来都很熟悉,除了1989年的网络更小。按照今天的标准,1989年的数据集仍然是一个“婴儿”:训练集只有7291张16x16灰度图像。今天的视觉数据集通常包含来自网络的数亿张高分辨率彩色图像(谷歌拥有JFT-300M,OpenAICLIP在400M图像上进行训练),并且可以扩展到数十亿张。每张图像包含的像素信息增加了1000倍(384*384*3/(16*16)),图像数量增加了10万倍(1e9/1e4),粗略计算,输入的像素数据增加了一亿多倍。当时的神经网络也是一个“婴儿”:它有大约9760个参数、64K个MAC和1K个激活。当前(视觉)神经网络可扩展到数十亿个参数,而自然语言模型可以达到数万亿个参数。那时,SOTA分类器在工作站上训练需要3天,但现在在无风扇笔记本电脑上训练只需90秒(快3000倍),如果切换到全批优化并使用GPU,速度可以提高一百倍以上。事实上,我能够通过微调模型、增强、损失函数和基于现代创新的优化,将错误率降低60%,同时保持数据集和模型测试时间不变。只需扩大数据集即可获得适度的收益。进一步的重大收益可能必须来自更大的模型,这将需要更多的计算和额外的研究和开发,以帮助在不断增加的规模上稳定训练。如果我被传送到1989年,而且我没有更大的计算机,我将无法进一步改进系统。假设这次练习时间保持不变,这对2022年的深度学习意味着什么?来自2055年的时间旅行者会如何看待当前的网络性能?2055年的神经网络在宏观上和2022年的神经网络基本一样,只是规模更大了。我们的数据集和模型今天看起来像个笑话,到2055年两者都将增加约10,000,000倍。一个人可以在一分钟内训练2022个SOTA模型,所有这些都在他们的个人电脑上作为周末娱乐。今天的模型没有优化,只是改变模型的一些细节,损失函数,增强,或者优化器,可以将错误减少一半。我们的数据集太小,通过扩大数据集可以获得适度的收益。如果不扩大计算机基础设施并投资于相应规模的高效培训模型的研发,就不可能取得进一步的成果。但我想表达的最重要的趋势是,随着GPT这样的基础模型的出现,按照某个目标任务(比如数字识别)从头开始训练整个神经网络的设置将变成由于“fine-tuning”。过时了。这些基础模型由少数拥有大量计算资源的机构训练而成。大多数应用程序是通过对网络的一部分进行轻量级微调、快速工程,或者通过数据和模型蒸馏到更小的专用推理网络的可选步骤。实现。我认为这种趋势在未来会非常活跃。让我们假设您根本不想训练神经网络。在2055年,你可以通过说话要求10,000,000倍大小的神经网络大脑来执行一些任务。如果您的要求足够具体,它就会满足您的要求。当然,您也可以自己训练神经网络,但为什么要这样做呢?