提高深度学习(和机器学习)性能的思路


  提升思路分为以下4部分,通常来讲,随着列表自上而下,性能的提升也将变小。部分思路只适用于人工神经网络,但是大部分是通用的。足够用来配合其他技术来碰撞出提升模型性能的方法。
  (1)通过数据提升性能
  (2)通过算法提升性能
  (3)通过算法调参提升性能
  (4)通过嵌套模型提升性能

1. 通过数据提升性能

对训练数据和问题定义进行适当改变,能得到很大的性能提升。或许是最大的性能提升。
以下是我将要提到的思路:
  (1)获取更多数据:更多、更全的数据总是有用的。
  (2)创造更多数据:无法获取更多数据的时候,可以尝试创造数据,比如如果数据是数值型向量,可以随机构造已有向量的修改版本。
  (3)重放缩你的数据:当应用神经网络时,一个传统的经验法则是:重缩放(rescale)你的数据至激活函数的边界。如果你在使用sigmoid激活函数,重缩放你的数据到0和1的区间里。如果你在使用双曲正切(tanh)激活函数,重缩放数据到-1和1的区间里。
  在神经网络中,大的数值累积效应(叠加叠乘)并不是好事,除上述方法之外,还有其他的方法来控制你的神经网络中数据的数值大小,譬如归一化激活函数和权重,如batchnormalization。
  (4)转换你的数据:与上述的重缩放方法类似,但需要更多工作。必须非常熟悉你的数据。通过可视化来考察离群点。
猜测每一列数据的单变量分布。

列数据看起来像偏斜的高斯分布吗?考虑用Box-Cox变换调整偏态。
列数据看起来像指数分布吗?考虑用对数变换。
列数据看起来有一些特征,但是它们被一些明显的东西遮盖了,尝试取平方或者开平方根来转换数据
你能离散化一个特征或者以某种方式组合特征,来更好地突出一些特征吗?

依靠你的直觉,尝试以下方法。

你能利用类似PCA的投影方法来预处理数据吗?
你能综合多维特征至一个单一特征吗?
你能用一个新的布尔标签去发现问题中存在一些有趣的方面吗?
你能用其他方法探索出目前场景下的其他特殊结构吗?

  (5)特征选取:神经网络会用近似于0的权重来弱化那些没有预测能力的特征的贡献。有许多特征选择的方法和特征重要性的方法,这些方法能够给你提供思路,哪些特征该保留,哪些特征该剔除。最简单的方式就是对比所有特征和部分特征的效果。
  (6)重架构你的问题:有时候要试试从你当前定义的问题中跳出来,想想你所收集到的观察值是定义你问题的唯一方式吗?或许存在其他方法。或许其他构建问题的方式能够更好地揭示待学习问题的结构。

看看能够在一个时间窗(时间周期)内对已有的特征/数据做一个合并。
或许你的分类问题可以成为一个回归问题(有时候是回归到分类)。
或许你的二元输出可以变成softmax输出?
或许你可以转而对子问题进行建模。

2、通过算法提升性能

  假如已经选择了深度学习来解释问题。但是这真的是最好的选择吗?是否可以考虑算法选择上的思路:
(1)对算法进行抽样调查
  其实事先无法知道,针对该问题哪个算法是最优的。如果知道,可能就不需要机器学习了。那有没有什么数据(办法)可以证明你选择的方法是正确的?抽样调查一系列可行的方法,来看看哪些还不错,哪些不理想。

首先尝试评估一些线性方法,例如逻辑回归(logistic regression)和线性判别分析(linear discriminate analysis)。
评估一些树类模型,例如CART, 随机森林(Random Forest)和Gradient Boosting。
评估一些实例方法,例如支持向量机(SVM)和K-近邻(kNN)。
评估一些其他的神经网络方法,例如LVQ, MLP, CNN, LSTM, hybrids等

  选取性能最好的算法,然后通过进一步的调参和数据准备来提升。尤其注意对比一下深度学习和其他常规机器学习方法,对上述结果进行排名,比较他们的优劣。很多时候你会发现在你的问题上可以不用深度学习,而是使用一些更简单,训练速度更快,甚至是更容易理解的算法。
(2)借鉴已有文献
  state of art ,借鉴已有的文献资料。可能有人已经研究过该问题相关的问题,可以看看他们用的什么方法。阅读论文,书籍,博客,问答网站,教程,以及任何能在xx搜索到的东西。写下所有的想法,然后用你的方式把他们研究一遍。
(3)重采样方法
  深度学习模型在训练阶段非常缓慢。这通常意味着,无法用一些常用的方法,例如k层交叉验证,去估计模型的性能。

1、或许你在使用一个简单的训练集/测试集分割,这是常规套路。如果是这样,你需要确保这种分割针对你的问题具有代表性。单变量统计和可视化是一个好的开始。
2、或许你能利用硬件来加速估计的过程。例如,如果你有集群或者AWS云端服务(Amazon Web Services)账号,你可以并行地训练n个模型,然后获取结果的均值和标准差来得到更鲁棒的估计。
3、或许你可以利用hold-out验证方法来了解模型在训练后的性能(这在早停法(early stopping)中很有用)。
4、或许你可以先隐藏一个完全没用过的验证集,等到已经完成模型选择之后再使用它。

  而有时候另外的方式,或许你能够让数据集变得更小,以及使用更强的重采样方法。

1、有些情况下你会发现在训练集的一部分样本上训练得到的模型的性能,和在整个数据集上训练得到的模型的性能有很强的相关性。也许你可以先在小数据集上完成模型选择和参数调优,然后再将最终的方法扩展到全部数据集上。
2、或许你可以用某些方式限制数据集,只取一部分样本,然后用它进行全部的建模过程。

3. 通过算法调参提升性能

  这通常是工作的关键所在。你经常可以通过抽样调查快速地发现一个或两个性能优秀的算法。但是如果想得到最优的算法可能需要几天,几周,甚至几个月。为了获得更优的模型,以下是对神经网络算法进行参数调优的几点思路:

诊断(Diagnostics)
权重初始化(Weight Initialization)
学习速率(Learning Rate)
激活函数
网络拓扑(Network Topology)
批次和周期(Batches and Epochs)
正则化
优化和损失
早停法

  可能需要训练一个给定“参数配置”的神经网络模型很多次(3-10次甚至更多),才能得到一个估计性能不错的参数配置。
(1)诊断
  模型是过拟合还是欠拟合?永远牢记这个问题。
  模型总是会遇到过拟合或者欠拟合,只是程度不同罢了。快速了解模型学习行为的方法是,在每个周期,评估模型在训练集和验证集上的表现,并作出图表。

如果训练集上的模型总是优于验证集上的模型,你可能遇到了过拟合,你可以使用诸如正则化的方法。
如果训练集和验证集上的模型都很差,你可能遇到了欠拟合,你可以提升网络的容量,以及训练更多或者更久。
如果有一个拐点存在,在那之后训练集上的模型开始优于验证集上的模型,你可能需要使用早停法。

  经常画一画这些图表,学习它们来了解不同的方法,你能够提升模型的性能。这些图表可能是你能创造的最有价值的(模型状态)诊断信息。
  另一个有用的诊断是网络模型判定对和判定错的观察值。

对于难以训练的样本,或许你需要更多的数据。
或许你应该剔除训练集中易于建模的多余的样本。
也许可以尝试对训练集划分不同的区域,在特定区域中用更专长的模型。

(2)权重初始化
  经验法则通常是:用小的随机数进行初始化。
  在实践中,这可能依旧效果不错,但是对于你的网络来说是最佳的吗?对于不同的激活函数也有一些启发式的初始化方法,但是在实践应用中并没有太多不同。
  固定你的网络,然后尝试多种初始化方式。记住,权重是你的模型真正的参数,你需要找到他们。有很多组权重都能有不错的性能表现,但我们要尽量找到最好的。

1、尝试所有不同的初始化方法,考察是否有一种方法在其他情况不变的情况下(效果)更优。
2、尝试用无监督的方法,例如自动编码(autoencoder),来进行预先学习。
3、尝试使用一个已经存在的模型,只是针对你的问题重新训练输入层和输出层(迁移学习(transfer learning))
4、需要提醒的一点是,改变权重初始化方法和激活函数,甚至优化函数/损失函数紧密相关。

(3)学习率
  调整学习率很多时候也是行之有效的时段。

1、实验很大和很小的学习率
2、网格搜索文献里常见的学习速率值,考察你能学习多深的网络。
3、尝试随周期递减的学习率
4、尝试经过固定周期数后按比例减小的学习率。
5、尝试增加一个动量项(momentum term),然后对学习速率和动量同时进行网格搜索。

  越大的网络需要越多的训练,反之亦然。如果你添加了太多的神经元和层数,适当提升你的学习速率。同时学习率需要和训练周期,batch size大小以及优化方法联系在一起考虑。
(4)激活函数
  或许应该使用修正激活函数(rectifier activation functions)。他们也许能提供更好的性能。
  在这之前,最早的激活函数是sigmoid和tanh,之后是softmax, 线性激活函数,或者输出层上的sigmoid函数。不建议尝试更多的激活函数,除非你知道你自己在干什么。
  尝试全部三种激活函数,并且重缩放你的数据以满足激活函数的边界。
  显然,你想要为输出的形式选择正确的传递函数,但是可以考虑一下探索不同表示。例如,把在二元分类问题上使用的sigmoid函数切换到回归问题上使用的线性函数,然后后置处理你的输出。这可能需要改变损失函数使之更合适。
(5)网络拓扑
  需要多少层以及多少个神经元?抱歉没有人知道。不要问这种问题。那怎么找到适用你的问题的配置呢?去实验吧。

1、尝试一个隐藏层和许多神经元(广度模型)。
2、尝试一个深的网络,但是每层只有很少的神经元(深度模型)。
3、尝试上述两种方法的组合。
4、借鉴研究问题与你的类似的论文里面的结构。
5、尝试拓扑模式(扇出(fan out)然后扇入(fan in))和书籍论文里的经验法则

  选择总是很困难的。通常说来越大的网络有越强的代表能力,或许你需要它。越多的层数可以提供更强的从数据中学到的抽象特征的能力。或许需要它。深层的神经网络需要更多的训练,无论是训练周期还是学习率,都应该相应地进行调整。
(6)Batche size和周期
  batch size大小会决定最后的梯度,以及更新权重的频度。一个周期(epoch)指的是神经网络看一遍全部训练数据的过程。
  在很深的网络结构里你会经常看到:小的batch size配以大的训练周期。
  下面这些或许能有助于你的问题,也或许不能。你要在自己的数据上尝试和观察。

1、尝试选取与训练数据同大小的batch size,但注意一下内存(批次学习(batch learning))
2、尝试选取1作为batch size(在线学习(online learning))
3、尝试用网格搜索不同的小的batch size(8,16,32,…)
4、分别尝试训练少量周期和大量周期。

  考虑一个接近无穷的周期值(持续训练),去记录到目前为止能得到的最佳的模型。
  一些网络结构对batch size更敏感。我知道多层感知器(Multilayer Perceptrons)通常对batch size是鲁棒的,而LSTM和CNNs比较敏感,但是这只是一个说法。
(7)正则化
  正则化是一个避免模型在训练集上过拟合的好方法。
  神经网络里最新最热的正则化技术是dropout方法,你是否试过?dropout方法在训练阶段随机地跳过一些神经元,驱动这一层其他的神经元去捕捉松弛。简单而有效。

1、网格搜索不同的丢失比例。
2、分别在输入,隐藏层和输出层中试验dropout方法
3、dropout方法也有一些拓展,比如你也可以尝试drop connect方法。

  也可以尝试其他更传统的神经网络正则化方法,例如:

1、权重衰减(Weight decay)去惩罚大的权重
2、激活约束(Activation constraint)去惩罚大的激活值

  也可以试验惩罚不同的方面,或者使用不同种类的惩罚/正则化(L1, L2, 或者二者同时)。
(8)优化和损失
  最常见是应用随机梯度下降法(stochastic gradient descent),但是现在有非常多的优化器。你试验过不同的优化(方法)过程吗?
  随机梯度下降法是默认的选择。先好好利用它,配以不同的学习率和动量。
  许多更高级的优化方法有更多的参数,更复杂,也有更快的收敛速度。 好与坏,是不是需要用,取决于你的问题。
  为了更好的利用好一个给定的(优化)方法,你真的需要弄明白每个参数的意义,然后针对你的问题通过网格搜索不同的的取值。困难,消耗时间,但是值得。
  我发现了一些更新更流行的方法,它们可以收敛的更快,并且针对一个给定网络的容量提供了一个快速了解的方式,例如:ADAM,RMSprop。
  你还可以探索其他优化算法,例如,更传统的(Levenberg-Marquardt)和不那么传统的(genetic algorithms)。其他方法能够为随机梯度下降法和其他类似方法提供好的出发点去改进。
  要被优化的损失函数与你要解决的问题高度相关。然而,你通常还是有一些余地(可以做一些微调,例如回归问题中的均方误(MSE)和平均绝对误差(MAE)等),有时候变换损失函数还有可能获得小的性能提升,这取决于你输出数据的规模和使用的激活函数。
(9)Early Stopping/早停法
  一旦训练过程中出现(验证集)性能开始下降,你可以停止训练与学习。这可以节省很多时间,而且甚至可以让你使用更详尽的重采样方法来评估你的模型的性能。
  早停法是一种用来避免模型在训练数据上的过拟合的正则化方式,它需要你监测模型在训练集以及验证集上每一轮的效果。一旦验证集上的模型性能开始下降,训练就可以停止。
  如果某个条件满足(衡量准确率的损失),你还可以设置检查点(Checkpointing)来储存模型,使得模型能够继续学习。检查点使你能够早停而非真正的停止训练,因此在最后,你将有一些模型可供选择。

4、通过嵌套模型提升性能

  你可以组合多个模型的预测能力。刚才提到了算法调参可以提高最后的性能,调参之后这是下一个可以提升的大领域。
  事实上,你可以经常通过组合多个“足够好的”模型来得到优秀的预测能力,而不是通过组合多个高度调参的(脆弱的)模型。
  你可以考虑以下三个方面的嵌套方式:

(1)组合模型
(2)组合视角
(3)堆叠(Stacking)

(1)组合模型
  有时候我们干脆不做模型选择,而是直接组合它们。
  如果你有多个不同的深度学习模型,在你的研究问题上每一个都表现的还不错,你可以通过取它们预测的平均值来进行组合。
  模型差异越大,最终效果越好。例如,你可以应用非常不同的网络拓扑或者不同的技术。如果每个模型都效果不错但是不同的方法/方式,嵌套后的预测能力将更加鲁棒。。
  每一次你训练网络,你初始化不同的权重,然后它会收敛到不同的最终权重。你可以多次重复这一过程去得到很多网络,然后把这些网络的预测值组合在一起。
  它们的预测将会高度相关,但是在那些难以预测的特征上,它会给你一个意外的小提升。
(2)组合视角
  同上述类似,但是从不同视角重构你的问题,训练你的模型。
  同样,目标得到的是效果不错但是不同的模型(例如,不相关的预测)。得到不同的模型的方法,你可以依赖我们在数据那一小节中罗列的那些非常不同的放缩和转换方法。
  你用来训练模型的转换方法越不同,你构建问题的方式越不同,你的结果被提升的程度就越高。
  简单使用预测的均值将会是一个好的开始。
(3)stacking/堆叠
  你还可以学习如何最佳地组合多个模型的预测。这称作堆叠泛化(stacked generalization),或者简短来说就叫堆叠。
  通常上,你使用简单线性回归方法就可以得到比取预测平均更好的结果,像正则化的回归(regularized regression),就会学习如何给不同的预测模型赋权重。基线模型是通过取子模型的预测均值得到的,但是应用学习了权重的模型会提升性能。

总结

  内容很多,但并不需要去做所有事,也许这里面的某一点就足以给你好的想法去提升性能。简单说来大概包括下面这些:
选取一个方向;
  数据;
  算法;
  调参;
  嵌套模型;
在某一方向里选取一种方法;
在选取的方法中选取一件事情去尝试;
比较结果,如果性能有提升,则保留;
不断重复

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值