AndrejKarpathy是深度学习计算机视觉、生成模型和强化学习领域的研究员。博士期间师从李飞飞。博士期间,我在谷歌做过两次实习,研究Youtube视频上的大规模特征学习,并于2015年在DeepMind实习,研究深度强化学习。毕业后,Karpathy成为OpenAI的一名研究科学家,之后于2017年6月加入特斯拉,担任人工智能和自动驾驶视觉总监。今天他发布了这篇能够为深度学习研究者提供极其清晰见解的博客,同时也在推特上引起了极大的关注。1.谁说神经网络训练很容易?许多人认为开始训练神经网络很容易。大量的库和框架声称用30行代码就能解决你的数据问题,留给大家的是(错误的)印象:训练一个神经网络非常简单。可以即插即用不同的模块来构建深度模型。一个简单的建模过程通常是这样的:>>>your_data=#plugyouawesomedatasethere>>>model=SuperCrossValidator(SuperDuper.fit,your_data,ResNet50,SGDOptimizer)#conquerworldhere这些库和示例让我们想起熟悉的标准软件和模块,CleanAPIs和抽象通常在标准软件中可用。例如Request库的使用如下:>>>r=requests.get('https://api.github.com/user',auth=('user','pass'))>>>r.status_code200cool!这些库和框架的开发者背负着大量理解用户查询字符串、url、GET/POST请求、HTTP连接等的需求,将复杂性隐藏在几行代码之后。这是我们熟悉和期待的。然而,神经网络不同,它们不是现成的技术。我曾在2016年写的一篇博客中试图说明这一点,但现在情况似乎越来越糟。Backprop+SGD并不是让你的网络正常工作的魔法;批量归一化不会神奇地让你的网络收敛得更快;并且RNN不会神奇地让你直接处理文本。不要认为仅仅因为你可以将你的问题表述为强化学习,你就应该这样做。如果在不了解技术原理的情况下坚持使用它,很可能会失败。2.不在我背后工作的神经网络当你破坏代码或错误配置代码时,你通常会遇到某种异常。您在本应插入字符串的位置插入了一个整数;导入出错;关键字不存在...此外,您很可能会为调试目的的函数创建单元测试。而这仅仅是个开始。在训练神经网络时,可能所有代码在句法上都是正确的,但整个训练就是不正确的。也许问题是逻辑上的(而不是语法上的)并且很难通过单元测试找到。例如,你尝试截断损失而不是梯度,这会导致训练期间的异常值被忽略,但语法或维度等检查不会失败。或者,你把正则化强度、学习率、衰减率、模型大小等设置错了,如果你幸运的话网络会报错,但大多数时候它会继续训练并默默地变得更糟。..因此,神经网络的“快速”“强化”训练是无用的,只会导致困难。现在,这些经验困难是使神经网络正常工作的障碍,您需要更仔细地调试网络以降低难度,你需要大量的可视化来理解一切。根据我的经验,深度学习成功的重要因素是耐心和对细节的关注。如何解决基于以上两个事实,我开发了一个将神经网络应用于新的具体过程问题。这个过程非常重视上面的两个原则:耐心和注重细节。具体来说,它是由简单到复杂的构建,我们对每一步将要发生的事情做出准确的假设,然后使用实验来检验假设或调查,直到发现问题。我们尽最大努力防止大量“未经证实”的复杂性同时出现,这可能会导致永远不会被发现的错误/错误配置。如果您要像训练神经网络一样对其进行编码,您会希望在每次迭代后使用非常小的学习率、猜测和评估整个测试集。1.梳理数据训练神经网络代码不要碰,先把自己的数据彻底查一遍。这一步非常关键。我喜欢花很多时间研究数以千计的样本,了解它们的分布,寻找模式。幸运的是,人脑非常擅长这一点。有一次,我发现数据包含重复样本,还有一次,我发现损坏的图像/标签。我寻找数据不平衡和偏见。我通常也会关注我自己的数据分类过程,这将揭示我们最终探索的架构。例如,局部特征是否足够或全局上下文?标签有多吵?此外,由于神经网络是数据集的压缩/编译版本,您可以查看网络的(错误)预测并了解预测的来源。如果网络预测与您在数据中找到的不匹配,那么一定是有问题。对数据有了一些了解后,您可以编写一些简单的代码来搜索/过滤/排序标签类型、标签大小、标签数量等,并可视化其沿任意轴的分布和离群值。离群值通常可以揭示数据质量或预处理方面的错误。2.配置端到端训练/评估架构并获得基线结果既然我们了解了数据,我们是否可以开始构建一个高大上的多尺度ASPPFPNResNet并训练一个强大的模型?当然还没有,这是一条布满荆棘的路。我们的下一步是构建一个完整的训练、评估架构,并运行一系列实验来确定我们对准确性的信心。在这个阶段,你选择一些不会出错的简单模型,例如线性分类器或非常精简的ConvNet等。我们要训练这些模型并将训练损失、模型预测和其他指标(如准确性)可视化).当然,在这个过程中,我们还需要基于一些明确的假设,进行一系列的对照实验(消融实验)。此阶段的一些提示和注意事项:固定随机种子:始终使用固定随机种子可保证许多特性,例如当我们运行相同代码两次时获得相同输出。这消除了做出合理判断的可变因素。简化:确保禁用不必要的技巧。例如,在此阶段肯定需要关闭数据增强。数据扩充可以在稍后阶段引入,并充当强大的正则化策略。但是如果在这个阶段引入,它有机会引入一些愚蠢的错误。使用很多数据,很少的验证评估:当我们绘制测试损失时,我们需要对整个更大的测试集进行评估。不要在几个批次上一次绘制测试损失,然后依赖TensorBoard的平滑。我们虽然追求准确,但也要杜绝这些低级错误。Verifylossduringinitialization:验证你的损失函数在初始化过程中有一个合理的损失值。例如,如果你正确地初始化了最后一层,那么你应该通过-log(1/n_classes)测量初始化的Softmax值。L2回归和Huber损失函数都具有相同的默认值。良好的初始化:正确初始化最后一层。例如,如果你正在回归一些均值为50的数据,那么初始偏差项应该是50。如果你有一个不平衡的数据集(两种类型的样本数是1:10),那么你需要在logits上设置一个偏差项,以便模型在初始化时预测概率为0.1。正确配置这些偏差项将加速收敛,因为网络基本上只在前几次迭代中学习偏差。人类基线结果:监控损失值和其他应由人类解释和检查的指标(例如准确性)。尽可能多地评估您自己的(人类)准确性,并将其与您构建的模型进行比较。或者把测试数据标注两次,一次给预测值,一次给标注值。Input-independentbaselineresults:训练一个独立于输入的基线模型,例如最简单的方法是将所有输入设置为0。这样的模型应该比实际输入数据表现更差。您的模型准备好从任何输入中提取任何信息了吗?Overfittingonbatchdata:对单批数据(两个或多个样本)的过度拟合。为此,我们需要增加模型拟合度并验证我们是否可以达到损失值(即0)。我还想在同一张图中显示标签和预测,并确保它们在损失最小化后排成一行。Validationtraininglossdrop:在这个阶段,你可能希望在数据集上实现欠拟合,这个阶段的模型应该是最小的。然后我们试着把模型的拟合能力提高一点点,看看trainingloss是不是下降一点点。馈入网络之前的可视化:在运行模型之前,我们需要对数据进行可视化。即我们需要将输入到网络的具体数据可视化,即原始张量的数据和标签。这就是“真相之源”,我因为这个过程节省了很多时间,并揭示了数据预处理和数据扩充过程中的问题。可视化预测过程:我喜欢在训练期间对固定测试数据批次进行模型预测的可视化。这显示了预测值如何变化的进程,让我们对训练过程有很好的直觉。很多时候,如果网络以某种方式轻微波动,那么模型很可能试图拟合数据,这也表现出一些不稳定性。由于大量抖动,学习率太低或太高也很容易被注意到。使用反向传播绘制依赖关系:您的深度学习代码通常包括复杂的、矢量化的、广播操作。一个常见的错误是人们不经意地使用视图而不是转置/置换,在批量数据中混淆维度信息。但是,您的网络仍将正常训练,它们只是学会忽略来自其他样本的数据。一种调试方法是将某些样本i的损失设置为1.0,然后一直运行反向传播到输入并确保第i个样本具有非零梯度。更一般地说,梯度为我们提供了网络中的依赖关系,这在调试中非常有用。概括特殊情况:这是一种更通用的编码技术,但我经常看到人们在使用这些技术时产生新的错误,尤其是在从头构建通用函数时。相反,我喜欢直接编写非常具体的功能,只涵盖我现在需要做的事情。我会先让函数工作,然后概括函数并确保实现相同的结果。通常这个过程体现在向量化代码中,我会先循环写一些程序,然后一次一个循环地把它们变成向量化代码。3.过拟合这个阶段我们应该对数据集有一个了解,有一个完整的训练+评估的过程。对于任何给定的模型,我们都可以计算出我们的信任度。并且还准备了performanceforinput-independentbaselines,一些dumbbaselines的performance(建议超过这些),我们人类对performance有一个大概的了解(也希望能实现这个)。现在,我们准备迭代一个好的模型。我要用来找到一个好的模型的方法有两个阶段:首先得到一个足够大的模型,以便它可以过度拟合(即关注训练损失),然后适当地对其进行正则化(丢弃一些训练损失以改善验证损失)。我喜欢这两个阶段的原因是,如果我们不能用任何模型实现低错误率,它可能再次表明存在一些问题、错误和错误配置。此阶段的一些提示和注意事项:选择模型:为了达到理想的训练损失,我们不妨为数据选择合适的架构。当我们选择一个模型时,我的建议是不要把目标定得太高。我看到很多人一开始就非常渴望堆叠一些新模块,或者创造性地使用各种异构架构,所以他们想一步到位。我建议您可以找到最相关的论文并直接利用其简单的架构来获得良好的性能。后面我们可以在这个架构的基础上修改完善,加入我们的想法。Adam是一般的选择:在配置baseline模型的前期,我喜欢使用Adam算法(学习率3e-4)。以我的经验,Adam对超参数的容忍度比较高,不是很好的learningrate也能得到平庸的结果。对于ConvNets,通常仔细调整的SGD几乎总是略胜Adam,但学习率的可能区域要窄得多。一次复杂化一个:如果你有多个特征插入到分类器中,我建议一个一个地插入它们以确保获得所需的性能增益。不要一开始就一次性全部加进去,这样你就不知道哪个特性带来了性能提升。还有其他增加复杂性的方法,例如,您可以尝试先插入较小的图像,然后慢慢增加它们。不要相信默认的学习率衰减:如果您修改来自其他领域的代码,您应该谨慎使用学习率衰减方法。针对不同的问题,你不仅要使用不同的衰减策略,而且因为Epochs的数量不同,衰减过程也会不同。比如数据集的大小会影响Epoch的个数,很多learningratedecay策略都和Epoch直接相关。在我自己的工作中,我经常完全关闭学习率衰减,即使用恒定的学习率。4.正则化理想情况下,我们现在至少有一个适合训练集的大型模型。现在是时候对其进行正则化并通过放弃一些训练准确性来提高验证准确性。这些技巧包括:更多数据:首先,在任何当前实际设置中对模型进行正则化的方法是添加更多真实的训练数据。当您可以收集更多数据时,花费大量工程时间试图从小数据集中获得更好的结果是一个常见的错误。我认为添加更多数据是单调提高配置良好的神经网络性能的必经之路。数据增广:不如真实数据的方法是半假数据,更激进的数据增广正在实验中。创造力增强:如果半假数据也不存在,假数据也可以。人们正在寻找创造性的方法来扩展数据集。例如,巧妙的混合方法,如域随机化、使用模拟数据、将数据插入场景,甚至是GAN。预训练:即使你有足够的数据,你也可以使用损失很小的预训练网络。坚持监督学习:不要对无监督学习过于兴奋。据我所知,目前还没有在计算机视觉任务上有很强效果的无监督学习方法(虽然NLP领域现在有BERT等类似模型,但这更多是由于文本和噪声的更成熟的性质比。更好的信号)。较小的输入维度:删除可能包含虚假信号的特征。如果您的数据集很小,添加任何虚假输入只会增加过度拟合的可能性。同样,如果低级细节没有太大帮助,请尝试输入较小的图像。较小的模型:在许多情况下,您可以在网络上使用领域知识约束来减小模型大小。例如,在ImageNet主干之上使用全连接层曾经很流行,但后来被简单的平均池化取代,从过程中消除了大量参数。减小batchsize:由于BN是根据batchsize进行归一化的,batchsize越小正则化效果越强。这主要是因为一个batch的统计均值和标准差是实际均值和标准差的近似值,所以scaling和offset在小batch内波动更大。drop:增加dropout。在ConvNet上使用dropout2d(空间丢失)。保守使用dropout,因为它似乎对batchnormalization不友好。重量衰减:增加了重量衰减惩罚。Earlystopping:根据你得到的验证损失停止训练,在模型即将过拟合之前得到模型。尝试更大的模型:我在过去多次发现较大的模型最终会过度拟合,但它们比较小的模型“提前停止”要好得多。为了确保网络是一个合理的分类器,我喜欢可视化网络一层的权重,以确保我得到有意义的边缘。如果图层的过滤器看起来像噪声,则需要删除某些内容。同样,网络中的激活函数有时可以揭示问题。5.微调现在你应该在数据集的中间,探索实现更低验证损失的架构模型的空间。此步骤的一些技巧包括:随机网格搜索:同时微调多个超参数时,使用网格搜索来确保覆盖所有环境听起来很诱人。但请记住,使用随机搜索是可行的方法。直观上,因为神经网络对某些参数比较敏感。在极限情况下,如果参数a很重要并且更改b没有影响,那么您宁愿对a进行完整采样,也不愿在固定点多次采样。超参数优化:现在社区里有很多不错的贝叶斯超参数优化工具箱,我的一些朋友已经用得很好。但我个人的经验是,探索一个好的、广泛的模型空间和超参数方法是为了得到一个实习生。开玩笑的,哈哈哈。6.Squeeze一旦你找到了好的架构类型和超参数,你仍然可以使用更多的技巧来让系统变得更好:Ensemble:模型集成是稳步提高2%精度的好方法。如果您负担不起测试阶段的计算成本,请尝试使用《Distilling the Knowledge in a Neural Network》中的方法将您的模型提炼到网络中。继续训练:我经常看到人们在验证损失趋于平缓时中断模型训练,根据我的经验,网络在很长一段时间内都保持不直观的训练。有一次寒假忘记关掉模型训练,一月份回来发现竟然达到了SOTA的成绩。结论一旦你做到了这一点,你就具备了成功的所有要素:对神经网络、数据集和问题有足够深入的理解,配置完整的训练/评估系统,获得高置信度的准确性,并逐步探索更复杂的模型并提高性能步步。现在一切准备就绪,阅读大量论文,尝试大量实验并获得SOTA结果。原文链接:https://karpathy.github.io/2019/04/25/recipe/【本文为《机器之心》专栏原文翻译,微信公众号《机器之心》(id:almosthuman2014)"]点此阅读作者更多好文
