游乐游手机版
首页/AI热点日报/热点详情

深度学习项目从零启动构建完整实战指南

类型:热点整理2026-07-22
以漫画自动着色为案例,从项目启动、数据集创建、模型设计、可视化与指标、网络调试到性能优化六个方面,系统梳理构建深度学习项目的完整流程,强调从小处着手、快速迭代、合理利用迁移学习与成本控制等关键策略。

如何启动一个深度学习项目?这个话题看似基础,实则包含许多值得深入探讨的细节。本文将围绕六个关键环节展开,并以一个自动漫画着色项目作为贯穿始终的案例,完整梳理整个流程。这六个部分分别是:项目启动、数据集创建、模型设计、可视化与指标、网络调试,以及性能优化和调参。

先说第一部分:启动一个深度学习项目。

第一部分:启动一个深度学习项目

该选什么样的项目?

很多AI项目其实并不那么严肃,做起来反而相当有趣。2017年初,我启动了一个为日本漫画上色的项目,作为研究生成对抗网络(GAN)的一部分。这个问题虽然棘手,但极具吸引力——尤其对于像我这样完全不会画画的人来说。在选择项目时,不必只盯着增量改进或构思一个适销对路的产品。有时,创建一个学习速度更快、质量更高的新模型,本身就具有很高的价值。

调试深度网络:棘手是常态

训练深度学习模型往往需要数百万次迭代,因此查找bug的过程极其艰难,而且很容易导致崩溃。正确的做法是从简单的地方入手,循序渐进。例如,模型优化(如正则化)这类工作,完全可以等到代码调试完成之后再进行。此外,要养成经常可视化预测结果和模型度量标准的习惯。优先让模型跑起来,这样就有了一个可以回退的基线。最好不要一开始就陷入一个庞大的模型,试图一次性搞定所有模块,那样只会把自己逼到墙角。

度量与学习:小步快跑

宏伟的项目计划往往伴随着惨痛的失败。大多数个人项目的第一个版本,持续时间大约两到四个月。这个时间其实非常紧张,因为研究、调试和实验都需要大量时间。通常的安排是,让复杂的实验通宵运行,到第二天清晨,我们希望能获取足够的信息,来决定下一步怎么走。在早期阶段,每个实验最好不要超过12个小时,这是一条很实用的经验法则。为了实现这一点,我们将漫画上色项目的范围缩小到了单个动画人物的上色。同时,要设计大量的测试,借助它们来分析模型在实验中的不足。测试计划不必做得太远,关键在于快速度量、快速学习,为下一步设计提供足够多的反馈。

研究与产品:平衡的艺术

2017年春季开始讨论漫画上色项目时,Kevin Frans的Deepcolor项目已经问世,它使用GAN为漫画添加色彩提示。

在确定目标时,你必须花大力气确保项目完成后仍然具有意义。GAN模型相当复杂,2017年初的时候,还没达到能够嵌入产品所需的质量水准。但是,如果你把应用范围缩小到产品能够巧妙处理的程度,就有机会将质量提升到商用水准。因此,无论启动什么类型的深度学习项目,都需要在模型的泛化能力、容量和准确性之间找到平衡。

成本:GPU是必需品

训练实际的模型必须使用GPU,它比CPU快20到100倍。最低配置的亚马逊GPU p2.xlarge实例要价7.5美元/天,8核GPU则高达75美元/天。在我们的项目中,有些实验耗时超过两天,平均每周花费至少150美元。至于更快的AWS实例,花费可能高达1500美元/周。也可以选择购买独立计算机,而不是使用云计算。2018年2月,一台搭载Nvidia GeForce GTX 1080 Ti的台式机售价大约2200美元。在训练精调后的VGG模型时,它比P2实例要快大约5倍。

时间线:分阶段推进

我们把整个开发过程分为四个阶段,后三个阶段需要多次迭代来完成:

  • 项目研究
  • 模型设计
  • 实现及调试
  • 实验及调参

项目研究
我们会先对现有产品进行研究,找出它们的弱点。很多基于GAN的解决方案使用空间颜色提示,结果图案有些模糊,有时还会出现颜色混杂。我们设定了两个月的时间框架,有两个优先事项:生成不带提示的颜色,以及提高颜色保真度。具体目标锁定为:在单个动画角色上为灰度漫画着色,且不使用空间颜色提示。

站在巨人的肩膀上
接下来,就需要了解相关的研究和开源项目了。很多人在动手实践之前,至少要看几十篇论文和项目。比如,当我们深入研究GAN时,发现有十几个新的GAN模型:DRAGAN、cGAN、LSGAN等等。读研究论文确实很痛苦,但非常有意义。

深度学习代码通常很简练,但排查缺陷却很难。很多研究论文还常常遗漏实现细节。许多项目都始于开源实现,解决的问题也类似,所以可以多搜索开源项目。我们就在GitHub上查看了不同GAN变体的代码实现,并对它们做了若干次测试。

第二部分:创建一个深度学习数据集

深度学习项目的成败,很大程度上取决于数据集的质量。这一部分,我们来聊聊创建优质训练数据集需要关注的核心问题。

公开及学术数据集

对于研究项目,优先搜索已建立好的公开数据集。这些数据集通常样本更整齐,还附带基线模型性能。如果有多个可用的公开数据集,那就选择和你的问题最相关、质量最好的那些。

自定义数据集

对于实际问题,需要有来自问题领域的样本。首先尝试查找公共数据集。关于如何创建高质量自定义数据集的研究并不多。如果找不到可用的资料,那就得搜寻能从哪些地方抓取数据。这样的地方通常有很多参考,但数据质量一般比较低,还需要投入大量精力去整理。在抓取样本之前,要专门抽出时间评估所有选项,然后选择最相关的那个。

高质量的数据集应该具备这些特征:类别均衡、数据充足、标签和数据的信息质量高、错误非常少、和你的问题紧密相关。

不要一次爬取所有数据。我们经常借助标签和分类从网站抓取样本,从而获取与问题相关的数据。最好的爬取方法是先训练、测试少量的样本,根据得到的经验教训来改善抓取方法。

清理抓取到的数据非常重要,否则,即使最好的模型设计,性能也达不到和人类相当的水平。Danbooru和Safebooru是两个很受欢迎的动漫人物来源,但一些深度学习应用更倾向于Getchu,因为那里的绘图质量更高。我们可以用一组标签从Safebooru下载图像,直观地检查样本并运行测试来分析错误(也就是表现不佳的样本)。

模型训练和视觉评估都能提供进一步的信息,帮助我们细化标签选择。随着迭代的进行,我们学到的会越来越多,样本也会慢慢积累起来。还需要用分类器进一步过滤与问题无关的样本,比如清除所有人物过小的图像。和学术数据集相比,小型项目收集的样本很少,在适当的情况下可以应用迁移学习。

下面的左图由PaintsChainer提供,右图由最终的模型上色:

用一些训练样本对算法进行测试,结果并没有带来惊喜:应用的颜色很少,样式也不对。

经过一段时间的训练,我们对什么样的绘图表现欠佳有了更清晰的认识。不出所料,结构错综复杂的绘图最难上色。

这说明,好好选择样本非常重要。作为一款产品,PaintsChainer专注于它们擅长的线条类型,这个策略很明智。这次我使用了从互联网上挑选的干净线条艺术,结果再次带来惊喜。

这里有些经验教训:数据本身没有好坏之分,只是有些数据满足不了你的需求。此外,随着样本类别的增加,训练的难度和保持输出质量的难度都会上升。删除不相关的数据,反而能得到一个更好的模型。

在开发早期,我们就意识到有些绘图的结构过于错综复杂。在不显著增加模型容量的情况下,这些绘图在训练中产生的价值很小,最好不用,否则只会影响训练效率。

第三部分:深度学习设计

这一部分介绍一些高层次的深度学习策略,接下来会详细说明最常见的设计选择,可能需要一些基础的深度学习背景知识。

简单灵活:从小处着手

设计之初,务求简单、小巧。在学习阶段,脑海里会冒出很多很酷的想法,总倾向于一次性把所有细节都编码进去。但这不现实,最开始就想超越顶尖结果也不实际。从较少的网络层和自定义设计开始,后面再做必要的超参数精调。关键是要始终确认损失函数在持续下降,不要一开始就在大模型上浪费时间。

经过简短的Debug之后,我们简单模型经过5000次迭代就产生了初步结果。虽然还很粗糙,但至少模型所上的颜色开始限制在固定区域内,肤色也有些显露出来。

模型是否开始上色?这个结果给了我们非常有价值的反馈。所以,别从大模型入手,否则你会把大量时间花在Debug和训练上。

优先性与增量设计

要创造简单的设计,首先得选出优先项。把复杂问题分解成小问题,一步一步解决。做深度学习的正确策略是快速执行学到的东西。在跳到使用“无暗示”模型之前,我们先使用带有空间颜色暗示的模型。不要一步就跳到“无暗示”模型设计。例如,我们先去掉暗示中的空间信息,颜色质量就急剧下降,所以我们转变优先性,在做下一步之前先精炼模型。在设计模型的过程中,惊喜接二连三。与其做一个需要不断改变的长期计划,不如采用以优先性驱动的计划。使用更短、更小的设计迭代,保证项目始终在可控范围内。

避免随机改进

首先分析自己模型的弱点,而不是随意改进,比如盲目地使用双向LSTM或PReLU。我们需要根据可视化模型误差(表现极差的场景)以及性能参数,来确定模型的问题所在。随意做改进反而会适得其反,成比例地增加训练成本,而回报极小。

限制:让学习更高效

在网络设计中引入限制,可以保证训练更高效。搭建深度学习网络并不是简单地把网络层堆在一起。增加好的约束(constraints),能使学习更有效,也更智能。例如,应用注意力机制,能让网络知道该关注哪里;在变分自编码器中,我们训练隐藏因子使其服从正态分布。在我们的设计中,我们应用去噪方法,通过归零操作去除了空间颜色暗示的大量分数。啼笑皆非的是,这反而让模型能更好地学习和泛化。

设计细节

接下来,讨论深度学习项目中会遇到的一些常见设计选择。

深度学习软件框架
自谷歌2015年11月发布TensorFlow以来,短短6个月它就成了最流行的深度学习框架。虽然短期内看起来难有竞争对手,但一年后Facebook就发布了PyTorch,极大地引起了研究社区的关注。到2018年,已经有大量平台可供选择,包括TensorFlow、PyTorch、Caffe、Caffe2、MXNet、CNTK等。

一些研究员转向PyTorch,一个主要因素是其设计非常注重终端用户(end-user),API简单且直观。错误信息容易理解,API文档也很完整。PyTorch中的特征,例如预训练模型、数据预处理、载入常用数据集,都非常受欢迎。

TensorFlow也很棒,但目前为止它还是采用自下而上的方式,导致其极为复杂。TensorFlow的API很冗长,Debug方式也不一样,它大概有十几种建立深度网络的API模型。

截止到2018年2月,TensorFlow依然独占鳌头,开发者社区也是最大的。这是非常重要的因素。如果你需要多个机器训练模型,或者把推理引擎部署到移动手机上,TensorFlow是唯一选择。然而,其他平台如果变得更加专注于终端用户,可以预见会有更多从小项目向中级项目迁移的趋势。

随着TensorFlow的发展,有很多API可供选择来建立深度网络。最高层的API是提供隐式积分的评估器,TensorBoard提供了性能评估。最低层的API非常冗长,分散在许多模块中。现在,它用封装器API合并到了tf.layers、tf.metrics和tf.losses模块,从而更容易地建立深度网络层。

对于想要更直观API的研究者,还有Keras、TFLearn、TF-Slim等选项,这些都可以直接在TensorFlow上使用。建议选择带有所需预训练模型与工具(用于下载数据集)的框架。在学术界,用Keras API做原型设计相当流行。

迁移学习
不要做重复的工作。许多深度学习软件平台都有VGG19、ResNet、Inception v3这样的预训练模型。从头开始训练非常耗时。就像2014年VGG论文中说的:“VGG模型用4块英伟达Titan Black GPU训练,根据架构不同,训练单个网络需要2到3周的时间。”

很多预训练模型都可以用来解决深度学习难题。例如,用预训练VGG模型提取图像特征,再把这些特征反馈给LSTM模型来生成描述。很多预训练模型都使用ImageNet数据集训练。如果你的目标数据和ImageNet差别不大,可以固定大部分模型参数,只重新训练最后几个全连接层。否则,就需要用训练数据集对整个网络进行端到端的重训练。但无论哪种情况,由于模型已经过预训练,再训练所需的迭代次数会大大减少。训练时间缩短后,即使训练数据集不够大,也更容易避免过拟合。这种迁移学习在许多学科都很有效,比如用预先训练好的英语模型来训练汉语模型。

然而,这种迁移学习仅适用于需要复杂模型来提取特征的问题。在我们的项目中,样本与ImageNet不同,我们需要对模型进行端到端的重新训练。但当我们只需要相对简单的潜在因素(颜色)时,来自VGG19的复杂度又太高了。因此,我们决定建立一个新的、更简单的CNN特征提取模型。

成本函数
不是所有成本函数都是等价的,它会直接影响模型的训练难度。有些成本函数是标准的,但有些问题域需要仔细斟酌。

  • 分类问题:交叉熵,折页损失函数(SVM)
  • 回归:均方误差(MSE)
  • 对象检测或分割:交并比(IoU)
  • 策略优化:KL散度
  • 词嵌入:噪音对比估计(NCE)
  • 词向量:余弦相似度

在理论分析中看起来不错的成本函数,实践中可能并不好用。例如,GAN中鉴别器网络的成本函数,采用的就是更实用且经得起实验考验的方法,而不是理论分析中看起来最优的方案。在某些问题域中,成本函数可以是部分猜测加部分实验,也可以是几个成本函数的组合。我们的项目始于标准GAN成本函数,此外还添加了使用MSE和其他正则化成本的重建成本。然而,如何找到更好的成本函数,一直是我们项目中尚未解决的问题之一,我们相信它会对色彩保真度产生重大影响。

度量标准
良好的度量标准有助于更好地比较和调整模型。对于特定问题,可以看看Kaggle平台,它组织了很多深度学习竞赛,并提供了详细的度量标准。遗憾的是,在我们的项目中,很难定义一个精确的公式来衡量艺术渲染的准确性。

正则化
L1正则化和L2正则化都很常见,但L2正则化在深度学习中更受欢迎。

L1正则化的优点在于它倾向于产生更稀疏的参数,这有助于解开底层表示。由于每个非零参数都会给成本添加惩罚,与L2正则化中的许多微小参数相比,L1更青睐零参数。L1正则化使过滤器更干净、更易于解释,是特征选择的不错选择。L1对异常值也比较不敏感,数据不那么干净时,运行效果可能更好。不过,L2正则化仍然更受欢迎,因为它的解可能更稳定。

梯度下降
始终要密切监视梯度是否消失或爆炸。梯度下降问题有许多可能的原因,往往难以证实。不要一上来就调整学习速率或匆忙改变模型设计。小梯度可能仅仅由编程bug引起,比如输入数据未正确缩放,或者权重全部初始化为零。

如果排除了其他可能的原因,在梯度爆炸时可以应用梯度截断(特别是对于NLP)。跳跃连接是缓解梯度下降问题的常用技术。在ResNet中,残差模块允许输入绕过当前层到达下一层,这有效地增加了网络的深度。

缩放
对输入特征进行缩放。通常将特征缩放为以零为均值、在特定范围内,如[-1, 1]。特征缩放不当是梯度爆炸或缩小最常见的原因之一。有时需要从训练数据中计算均值和方差,使数据更接近正态分布。如果对验证或测试数据进行缩放,要再次利用训练数据的均值和方差。

批归一化和层归一化
每层激活函数之前节点输出的不平衡性是梯度问题的另一个主要来源。必要时需要对CNN应用批量归一化(BN)。如果输入数据做了适当标准化(缩放),深度网络将学习得更快更好。在BN中,我们从每批训练数据中计算每个空间位置的均值和方差。例如,批次大小为16,特征图具有10×10的空间维度,我们会计算100个平均值和100个方差(每个位置一个)。每个位置处的均值来自16个样本对应位置的平均值。然后使用这些均值和方差来重新归一化每个位置的节点输出。BN能提高准确度,同时缩短训练时间。

然而,BN对RNN无效,这时需要使用层归一化。在RNN中,来自BN的均值和方差不适合用来重新归一化RNN单元的输出,这可能是因为RNN的循环属性和共享参数。在层归一化中,输出由当前样本的层输出计算出的平均值和方差重新归一化。一个含有100个元素的层,仅使用来自当前输入的一个平均值和一个方差来重新归一化该层。

Dropout
可以将Dropout应用于层以正则化模型。2015年批量归一化兴起后,dropout热度有所降低。批量归一化使用均值和标准差重新缩放节点输出,这有点像引入噪声,迫使层对输入中的变量进行更鲁棒的学习。由于批量归一化也有助于解决梯度下降问题,它逐渐取代了Dropout。

是否结合Dropout和L2正则化,通常取决于领域。在调优过程中,可以测试dropout,收集经验数据来证明其益处。

激活函数
在深度学习中,ReLU是最常用的非线性激活函数。如果学习速率太高,很多节点的激活值可能会处于零值。如果改变学习速率没有帮助,可以试试leaky ReLU或PReLU。在leaky ReLU中,当x < 0时,它不输出0,而是有一个小的预定义下降斜率(如0.01或由超参数设置)。参数ReLU(PReLU)则更进一步,每个节点将具有可训练的斜率。

拆分数据集
为了测试实际性能,通常将数据分为三部分:70%用于训练,20%用于验证,10%用于测试。确保样本在每个数据集和每批训练样本中都得到充分打乱。在训练过程中,使用训练数据集来构建具有不同超参数的模型。使用验证数据集来运行这些模型,并选择精确度最高的。为了保险起见,最后再用那10%的测试数据做一个最终的错乱检查。如果测试结果与验证结果差异很大,就说明数据打乱得不够充分,或者需要收集更多数据。

基线
设置基线有助于比较模型和进行Debug。例如,可以把VGG19模型作为分类问题的基线。或者,先扩展一些已有的简单模型来解决我们的问题,这有助于更好地了解问题,并建立性能基线以供比较。在我们的项目中,我们修改了已有的GAN实现,并重新设计了作为基线的生成网络。

检查点
定期保存模型的输出和度量,以便比较。有时,我们希望重现模型的结果,或者重新加载模型以继续训练。检查点允许我们保存模型,以便以后重新加载。但要注意,如果模型设计已经更改,可能无法加载所有旧的检查点。我们也使用Git标签来跟踪多个模型,并为特定检查点重新加载正确的模型。我们的设计中,每个检查点占用4GB空间。使用云环境时,要相应配置足够的存储空间。由于经常启动和终止Amazon云实例,我们将所有文件存储在Amazon EBS中,以便于重新连接。

自定义层
深度学习软件包中的内建层经过了更好的测试和优化。尽管如此,如果想自定义层,你需要:

  • 用非随机数据对前向传播和反向传播代码进行模块测试;
  • 将反向传播结果与朴素梯度检查进行对比;
  • 在分母中添加小量的ϵ或用对数计算来避免NaN值。

归一化
深度学习的一大挑战是可复现性。在调试过程中,如果初始模型参数在会话间不断变化,很难进行调试。因此,我们明确地对所有随机生成器初始化了种子。在项目中,我们对Python、NumPy和TensorFlow都初始化了种子。在精调过程中,则关闭种子初始化,从而为每次运行生成不同的模型。为了复现模型的结果,我们会对其进行检查点保存,并在稍后重新加载它。

优化器

Adam优化器是深度学习中流行度很高的优化器之一。它适用于多种问题,包括带稀疏或带噪声梯度的模型。其易于精调的特性,使其能快速获得很好的结果。实际上,默认的参数配置通常已经能工作得很好。Adam优化器结合了AdaGrad和RMSProp的优点,对每个参数使用相同的学习率,并随着学习的进行独立地适应。Adam基于动量的算法,利用了梯度的历史信息。因此,梯度下降可以运行得更加平滑,并抑制因大梯度和大学习率导致的参数振荡问题。

Adam优化器调整
Adam有4个可配置参数:

  • 学习率(默认0.001)
  • β1:第一个矩估计的指数衰减率(默认0.9)
  • β2:第二个矩估计的指数衰减率(默认0.999),这个值在稀疏梯度问题中应设置成接近1
  • ϵ(默认值1e^-8)用于避免除以零运算

β(动量)通过累积梯度的历史信息来平滑化梯度下降。通常早期阶段,默认设置已经能工作得很好。否则,最可能需要改变的参数是学习率。

第四部分:可视化深度神经网络模型和指标

在为深度神经网络排除故障方面,人们总是太快、太早下结论。在了解如何排除故障前,要先明确要找什么,再花费数小时追踪故障。这一部分,我们来聊如何可视化深度学习模型和性能指标。

TensorBoard

在每一步追踪每个动作、检查结果非常重要。在预置工具如TensorBoard的帮助下,可视化模型和性能指标变得简单,且几乎是即时反馈。

数据可视化(输入、输出)

验证模型的输入和输出。在向模型馈送数据之前,先保存一些训练和验证样本用于视觉验证,然后取消数据预处理,将像素值重新调整回[0, 255]。检查多个批次,确认没有重复使用相同批次的数据。

有时,验证输入数据的直方图效果很好。理想情况下,数据应该以0为中心,区间在-1和1之间。如果特征在不同尺度上,梯度要么下降要么爆炸(取决于学习率)。

定期保存对应模型的输出,用于验证和误差分析。例如,验证输出中的颜色可能稍浅。

指标(损失 & 准确率)

除了定期记录损失和准确率,还可以记录并绘制它们,分析长期趋势。下图是TensorBoard上展示的准确率和交叉熵损失。

绘制损失图有助于调整学习率。损失的持续上升往往表明学习率太高了。如果学习率较低,学习速度则会变慢。

这里有另一个学习率太高的真实样本。可以看到损失函数突然上升(可能由梯度突然上升引起)。

使用准确率图来调整正则化因子。如果验证和训练准确率之间存在很大差距,该模型就出现了过拟合。为了缓解过拟合,需要提高正则化因子。

小结

权重 & 偏置:紧密监控权重和偏置。下图是层1在不同训练迭代中的权重和偏置。出现大型(正/负)权重是不正常的。正态分布的权重表明训练过程顺利(但也不一定)。

激活:为了梯度下降能实现最佳性能,激活函数之前的节点输出应该呈正态分布。如果不是,那么可能需要向卷积层应用批归一化,或者向RNN层应用层归一化。还要监控激活函数之后无效节点(0激活)的数量。

梯度:监控每一层的梯度,以判断最严重的问题之一:梯度消失或爆炸。如果梯度从最右层向最左层快速下降,就出现了梯度消失问题。

可视化CNN滤波器并不常见,但它能识别出模型提取的特征类型。如下图所示,前两个卷积层在检测边界和颜色。

对于CNN,我们可以看到特征图在学习什么。

这种图像重建很少进行。但在生成模型中,我们经常改变一个潜在因子、保持其他不变,以验证模型是否在智能地学习。

第五部分:调试深度学习网络

深度学习的问题解决步骤

在前期开发中,多个问题会同时出现。正如前文提到的,深度学习训练由数百万次迭代组成,找到bug非常难,且容易崩。从简单开始,渐渐做一些改变。像正则化这样的模型优化,可以在代码debug完成后再做。以功能优先的方式检查模型:

  • 把正则化因子设置为0
  • 不使用其他正则化(包括dropout)
  • 使用默认设置的Adam优化器
  • 使用ReLU
  • 不使用数据增强
  • 使用更少的网络层
  • 对输入数据做缩放,但跳过非必要的预处理
  • 不要在长时间训练迭代或大batch size上浪费时间

用小量训练数据使模型过拟合,是debug深度学习的最好方式。如果经过数千次迭代损失值仍然不下降,就进一步debug代码。当准确率超越瞎猜的水平,你就获得了第一个里程碑。然后对模型做后续修改:增加网络层和自定义,开始用完整训练数据进行训练,通过监控训练和验证数据集之间的准确率差异,增加正则化来控制过拟合。

如果卡住了,就移除所有内容,从更小的问题重新开始。

初始化超参数

许多超参数与模型优化更相关。关掉超参数或使用默认值。使用Adam优化器,它速度快、高效,默认学习率也很不错。前期的问题主要来自bug,而不是模型设计和精调问题。在做微调之前,先过一遍下面的检查列表。这些问题更常见,也更容易检查。如果损失值还没下降,就调整学习率。如果损失值降得太慢,学习率增加10倍。如果损失值上升或梯度爆炸,学习率降低10倍。重复这个过程,直到损失值逐渐下降。典型的学习率在1到1e-7之间。

检查列表

数据:

  • 可视化并检查输入数据(在数据预处理之后、馈送到模型之前)
  • 检查输入标签的准确率(在数据扰动之后)
  • 不要一遍又一遍地馈送同一批数据
  • 适当缩放输入数据(一般可缩放到区间(-1, 1)之间,且零均值)
  • 检查输出的范围(如,在区间(-1, 1)之间)
  • 总是使用训练集的平均值/方差来重新调节验证/测试集
  • 模型所有输入数据有同样的维度
  • 评估数据集的整体质量(是否有太多异常值或坏样本)

模型:

  • 模型参数准确初始化,权重不要全部设为0
  • 对激活或梯度消失/爆炸的网络层做debug(从最右边到最左边)
  • 对权重大部分是0或权重太大的网络层做debug
  • 检查并测试损失函数
  • 对于预训练模型,输入数据范围要匹配模型中使用的范围
  • 推理和测试中的Dropout应该始终关掉

权重初始化

把权重全部初始化为零是最常见的错误,这样深度网络什么也学不到。权重应该按照高斯分布做初始化:

缩放与归一化

缩放与归一化人们已经理解得很好了,但这仍然是最容易被轻视的问题之一。如果输入特征和节点输出都被归一化,模型就更容易训练。如果做得不准确,损失值就不会随着学习率降低。应该监控输入特征和每层节点输出的直方图。要对输入做适当缩放。对于节点输出,理想形状是零均值,且值不太大(无论是正还是负)。如果不是,且该层存在梯度问题,就在卷积层做批归一化,在RNN单元上做层归一化。

损失函数

检查和测试损失函数的准确性。模型的损失值一定要比随机猜测的值低。例如,在10类别分类问题中,随机猜测的交叉熵损失是-ln(1/10)。

分析误差

检查表现不好(误差)的地方并加以改进,对误差进行可视化。在我们的项目中,模型对结构高度纠缠的图像表现不好。例如,增加更多带有更小滤波器的卷积层来解开小特征。如果有必要,就增强数据或收集更多类似的样本来更好地训练模型。在某些情景下,可能需要移除这些样本,将模型限制在更聚焦的范围。

正则化精调

关掉正则化(使模型过拟合)直到做出合理的预测。

一旦模型代码可以工作,接下来要调整的参数就是正则化因子。需要增加训练数据的体量,然后增加正则化来缩小训练和验证准确率之间的差别。但不要做得太过分,因为希望模型稍微过拟合。要密切监测数据和正则化成本。在长时间尺度下,正则化损失不应该主导数据损失。如果用大型正则化还不能缩小两个准确率间的差距,那就先debug正则化代码或方法。

类似于学习率,我们以对数比例改变测试值,例如开始时改变1/10。注意,每个正则化因子都可能是完全不同的数量级,我们可以反复调整这些参数。

多个损失函数

在第一次实现中,避免使用多个数据损失函数。每个损失函数的权重可能有不同的数量级,也需要一些精力去调整。如果只有一个损失函数,就可以只关心学习率了。

固定变量

当使用预训练模型时,可以固定特定层的模型参数,从而加速计算。一定要再次检查是否有变量固定错的错误。

单元测试

虽然很少被谈到,但应对核心模块进行单元测试,以便代码改变时实现依旧稳健。如果一个网络层的参数用随机生成器初始化,检查其输出并不简单。另外,可以模仿输入数据、检查输出。对每个模块(层),我们可以检查:

  • 训练和推理输出的形状
  • 可训练变量的数量(不是参数的数量)

维度误匹配

要一直跟踪Tensor(矩阵)的形状,并将其归档到代码中。对于形状为[N, channel, W, H]的Tensor,如果W(宽)和H(高)有同样的维度,交换两者可能不会出错。因此,应用非对称形状做代码单元测试。例如,用[4, 3]的Tensor,而非[4, 4]做测试。

第六部分:提升深度学习模型性能及网络调参

提升模型容量

要提升模型容量,可以逐渐向深度网络添加层和节点。更深的层会输出更复杂的模型。还可以降低滤波器大小。较小的滤波器(3×3或5×5)性能通常优于较大的滤波器。

调参过程更重实践而非理论。逐渐添加层和节点,可以让模型过拟合,因为之后可以用正则化再将其调低。重复该迭代过程直到准确率不再提升,不再值得为降低计算性能而训练。

但是,GPU的内存是有限的。截止2018年初,高端显卡NVIDIA GeForce GTX 1080 TI的内存为11GB。两个仿射层之间隐藏节点的最大数量受内存大小限制。

对于非常深的网络,梯度消失问题很严重。可以添加跳跃连接(类似ResNet中的残差连接)来缓解该问题。

模型 & 数据集设计变化

以下是提升性能的检查列表:

  • 在验证数据集中分析误差(糟糕的预测结果)
  • 监控激活函数。在激活函数不以零为中心或非正态分布时,考虑批归一化或层归一化
  • 监控无效节点的比例
  • 使用梯度截断(尤其是NLP任务)来控制梯度爆炸问题
  • 打乱数据集(手动或通过程序)
  • 平衡数据集(每个类别具备相似数量的样本)

应在激活函数之前密切监控激活直方图。如果它们的规模差别很大,梯度下降将无效。使用归一化。如果深度网络有大量无效节点,应进一步追踪该问题。它可能由bug、权重初始化或梯度消失导致。如果都不是,尝试一些高级ReLU函数,如leaky ReLU。

数据集收集 & 清洗

如果想构建自己的数据集,最好的建议就是仔细研究如何收集样本。找最优质的资源,过滤掉与问题无关的所有数据,分析误差。在我们的项目中,具备高度纠缠结构的图像性能非常糟糕。可以添加卷积层和小型滤波器来改变模型,但模型已经很难训练了。也可以添加更多纠缠样本来进一步训练,但已经有足够多了……另一种方式:可以精细化项目范围,缩小样本范围。

数据增强

收集有标签的数据成本很高。对于图片,可以使用数据增强方法如旋转、随机剪裁、移位等对已有数据进行修改,生成更多数据。颜色失真则包括色调、饱和度和曝光偏移。

半监督学习

还可以使用无标注数据补充训练数据。使用模型对数据进行分类,把具备高置信度预测的样本添加到具有对应标签预测的训练数据集中。

调整

学习率调整

先简单回顾如何调整学习率。在早期开发阶段,关掉所有非关键超参数或设为0,包括正则化。对于Adam优化器,默认学习率通常性能就很好。如果对自己的代码有信心,但损失没有下降,就需要调整学习率。典型学习率在1和1e-7之间。每次把学习率降低10%,并在简短迭代中进行测试,密切监控损失。如果它持续上升,说明学习率太高了。如果没有下降,说明学习率太低。提高学习率,直到损失提前变得平缓。

下面是一个真实样本,展示了学习率太高的情况,这导致成本突然上涨:

在不常用的实践中,人们监控W ratio的更新情况:

  • 如果ratio > 1e-3,考虑调低学习率
  • 如果ratio < 1e-3,考虑调高学习率

超参数调整

在模型设计稳定后,可以进一步调整模型。最经常调整的超参数是:

  • mini-batch尺寸
  • 学习率
  • 正则化因子
  • 特定层的超参数(如dropout)

Mini-batch尺寸

通常的批尺寸是8、16、32或64。如果批尺寸太小,梯度下降不会很顺畅,模型学习速度慢,损失可能会振荡。如果批尺寸太大,完成一次训练迭代(一次更新)的时间太长,返回的收益较小。在我们的项目中,降低批尺寸,因为每次训练迭代时间太长。密切监控学习速度和损失。如果损失振荡剧烈,就知道批尺寸降低的幅度太大了。批尺寸会影响正则化因子等超参数。一旦确定了批尺寸,通常就锁定这个值。

学习率 & 正则化因子

可以用上述方法进一步调整学习率和正则化因子。监控损失来控制学习率,监控验证与训练准确率之间的差距来调整正则化因子。不需要把学习率降低10%,降低3%就够了(精细调整中或许更小)。

调参不是线性过程。超参数是相互关联的,需要反复调整。学习率和正则化因子高度相关,有时需要一起调。不要太早进行精细调整,否则可能浪费时间。设计改变的话,这些努力就白费了。

Dropout

Dropout率通常在20%到50%之间。先从20%开始。如果模型出现过拟合,再提高这个值。

其他调整

稀疏度:模型参数的稀疏度可以简化计算优化,并减少能耗(这对移动设备至关重要)。如果需要,可以用L1正则化替代L2正则化。

激活函数:ReLU是最流行的激活函数。对于一些深度学习竞赛,人们使用更高级的ReLU变体来提高准确率。在某些场景中,它还可以减少无效节点。

高级调参

一些高级精细调参方法包括:

  • 学习率衰减调度
  • 动量(Momentum)
  • 早停

不使用固定学习率,而是定期降低学习率。超参数包括学习率下降的频率和幅度。例如,可以在每十万次迭代时减少0.95的学习率。调整这些参数时,需要监控成本,以确定下降得更快但又不至于过早平缓的参数。

高级优化器使用动量使梯度下降过程平稳进行。Adam优化器中存在两种动量设置,分别控制一阶(默认0.9)和二阶(默认0.999)动量。对于有梯度陡降问题的问题域如NLP,可以稍稍提高动量值。

当验证误差持续上升时,过拟合可以通过停止训练来缓解。

但这只是概念可视化。实时误差可能暂时上升,然后再次下降。可以定期检查模型,记录对应的验证误差,稍后选择模型。

网格搜索

一些超参数高度相关,应该使用对数尺度上的可能性网格一起调整。例如,对于两个超参数λ和γ,从相应的初始值开始,并在每个步骤中降低10倍:

(e-1, e-2, … 和 e-8)

(e-3, e-4, … 和 e-6)

相应的网格会是 [(e-1, e-3), (e-1, e-4), … , (e-8, e-5) 和 (e-8, e-6)]。

不使用明确的交叉点,而是稍微随机移动这些点。这种随机性可能会帮助发现一些隐藏的性质。如果最佳点位于网格的边界(蓝色点),就在边界区域重新测试。

网格搜索计算量很大。对于较小项目,会被零星使用。开始时用较少迭代调整粗粒度参数。在后期细调阶段,使用更长迭代,并将数值调至3(或更低)。

模型集合

在机器学习中,可以从决策树中投票进行预测。这种方法效果很好,因为判断失误通常有局部性质:两个模型发生同一个错误的几率很小。在深度学习中,可以从随机猜测开始训练(提交一个没有明确设置的随机种子),优化模型也不是唯一的。可以使用验证数据集测试多次,选出表现最佳的模型,也可以让多个模型进行内部投票,最终输出预测结果。这种方式需要进行多个会话,很耗系统资源。也可以只训练一次,检查多个模型,选在这个过程中表现最佳的。通过集合模型,可以基于以下方式做准确预测:

  • 每个模型预测的“投票”
  • 基于预测置信度进行加权投票

模型集合在提高一些问题的预测准确率上很有效,经常被深度学习竞赛团队采用。

模型提升

在微调模型之外,也可以尝试使用模型的不同变体来提升性能。例如,考虑使用色彩生成器部分或全部替代标准LSTM。这种概念并不陌生:可以分步绘制图片。

直观地说,在图像生成任务中引入时间序列方法是有优势的,这种方法已在DRAW: A Recurrent Neural Network For Image Generation中被证明过。

微调与模型提升

性能重大提升的背后往往是模型设计的改变。不过,有时对模型进行微调也可以提升机器学习性能。最终判断可能取决于对相应任务的基准测试结果。

Kaggle

在开发过程中,可能会有一些简单问题,比如:需要使用Leaky ReLU吗?有时问题很简单,但永远无法在任何地方找到答案。在一些论文中,你会看到Leaky ReLU的优越性,但另一些项目的经验显示并没有性能提升。太多的项目,太多的变量缺乏衡量多种可能性的验证结果。Kaggle是数据科学竞赛的开放平台,深度学习是其中的重要部分。深入观察一些优秀选手的方法,也许就能找到最普遍的性能指标。一些竞赛团队还会把他们的代码(称为kernel)上传开源。只要用心探索,Kaggle会是一个很棒的信息源。

实验框架

深度学习开发依赖大量经验,调节超参数是一件乏味的工作。创建一个实验框架可以加速这个过程。例如,一些人会开发代码将模型定义外化为字符串以便调节。然而,这些努力通常不能为小团队带来收益。经验表明,这样做的代码简洁性和可追溯性损失远大于受益,意味着难以对代码进行简单修改。易于阅读的代码必然简洁灵活。与此相反,很多AI云产品已经开始提供自动调节超参数的特性。虽然目前这种技术仍处于初始阶段,但无需人类编写框架的流程应该是大势所趋,请时刻留意这一趋势。

结论

现在,你已经拥有了一个调整好的模型,可以正式部署了。希望这个系列教程能有所帮助。深度学习可以帮助解决很多问题——其适用范围超出你的想象。想用深度学习替代前端设计?可以试试pix2code!

来源:https://m.elecfans.com/article/2366082.html

相关热点

继续查看同栏目近期热点。

延伸阅读

补充最近整理过的热点入口。