2. 深度学习、神经网络、调参技巧(2)


用sklearn的grid_search,可以在你给定的参数范围内进行遍历。只要把模型继承为BaseEstimator的子类并实现fit,和predict就行;

请教一个问题,如果数据量很大的话,怎么用grid search来进行参数搜索呢?因为数据量很大,就不能用fit方法了,要用类似于fit_generator(keras)方法。不知道gridsearch如何来实现这个方法。贝叶斯优化Python有实现好的库的

先写个简单的调度脚本,你不工作的时候按照某个指定顺序跑积压任务……不然的话两小时一次的调参的一大问题是你半夜时间利用不了……

只有一台机器的话别想着实现太高级的参数搜索算法了……随机参数或者 grid search 先写一个再说。没理解错的话,你这个硬件量,应该还没有哪个启发式搜索算法的效率能赶上一个真人。

先从简单的模型开始,慢慢增加模型的复杂度;或者直接升级硬件; 楼上提到用sklearn的grid_search,在你给定的参数范围内进行遍历。只要把模型继承为BaseEstimator的子类并实现fit,和predict就行;

最近也深陷在调参的泥淖中。目前感觉可以采用的策略是Random Search粗调,然后找到最好的结果周围Grid Search细调。看到很多地方说贝叶斯优化,但是并没有找到对应的好用的工具,看看有没有人推荐一下。

就个人而言,设备不足调参着实蛋疼。不知道你做的什么方向,其实对于大部分模型,可以先用小模型和现有的超参数跑出个baseline来,其实大部分的模型超参数都是一致的。微调超参数确实能提高准确率,但是对于我等计算资源不足的人来说感觉入不敷出。建议先通过该模型把准确率调上去,最后的最后再调超参数。最主要的还是学习率吧。学习率与batchsize和image size 是相关的,可以先用之前paper的图片尺寸然后根据你的显存设置batchsize,然后线性设置学习率。至于网络有几层每层channel数有多少,全看造化了。

动网络结构的超参数吧,有两种途径,第一砸钱买设备,第二自己写权重移植的函数,把未更改的网络结构的权重移植过去,改过的网络结构的权重进行初始化,然后相当于做一个迁移学习?

听我没错的, 小网络小数据先贸然调起来。 听我没错的, 小网络小数据先贸然调起来。

其他人已经说了参数搜索的方法,除了在用这些什么网格,随机参数搜索外。

我觉得答主想问的也包括工程或者比赛上的一些方法技巧,有不少kaggle经验总结,这里我就提一个。

或许可以试试把原始图都缩小到比一般输入224更小的96或者112,其他不变。可以更快得到结果,先整体筛选一遍所有的模型,可能会得到一个或几个候选模型,然后再在该较小的图像尺度下选择合适的其他参数,最后选完了,再结合起来。用一般的大小或者更大的输入尺寸训练,重新来过。

主要是因为图像大小直接影响训练速度和精度。毕竟目的是快点拿到模型提交结果。提高效率。

kaggle上有很多树模型的调参经验贴,不过个人觉得数据处理其实才是最关键的。比赛的时候才会比调参,因为数据别人都给你规定好了,而真实业务情况需要你自己结合业务场景来确定采集什么样的数据,确定什么样的特征。

此外,树模型中作用大的参数就那么几个,hypeopt我试过,跑出来最优组合最后还是跟我自己按照经验拍出来的参数差不了多少,当然没有经验知识的时候用来跑个冷启动倒也可以。

最后给你安利一个工具shap,用来可视化树模型的特征分析和预测效果,这个才是非常有用的,祝使用愉快哈哈

调参工具试试 hyperopt 或者 

Google再做神经网络自动设计,主要设计算法,这看起来可能没什么关系,但是在实际工作中神经网络的结构也本看成一个超参数处理。

autosklearn与autoweka则是算法,参数同时解决,是复合性。真正做到了机器学习的自动化。超参数得到了较好的处理,其中autosklearn也在17年的自动化机器学习大赛中夺得魁首。autosklearn的主要使用了贝叶斯优化与元学习,现在手机不太方便,下面只放个截图。

而自动调参的方式和方法也很多,常用智能优化算法来处理超参数,比如遗传,粒子群,而在Python中我常用hyperopt来处理超参优化,或者deap自己写也行这样可以使用粒子群和遗传。hyperopt现在的主要搜索算法用的是退火和一种树型搜索算法,可以结合mongo实习异步搜索。去年圣诞节我做了hyperopt的中文翻译,内容不多不过确实国内独一份,链接在下边。

hyperopt的中文翻译: 

autosklearn国内唯一的翻译,也是我做的:

  

现在玩自动化机器学习的主要就两只,一只谷歌,相关内容,你可以看熊炎辰同学的答案,主要方向还是神经网络的自动化设计。另外一只主要在NIPS活跃,其主要原理就是贝叶斯优化与元学习,除此之外自动化机器学习就出现的比较零散了。


曾经用learning to learn的思想尝试过水平集方法的自动调参,算是缩水规模的learning to learn。搞过水平集的人应该知道,这个算法虽然各方面都不错,但是对调参还是很敏感的,不同类别的图像得换不同的参数。

于是在能量函数里加了一堆正则项,每个正则项都有一个系数,把分割的精度减去一个常数当做reward来训练。

后来发现,reinforcement learning这领域坑还真是多,首先这个调参的参数空间是个连续的空间,deepmind做过一些这方面的工作。直接把方法搬过来试试看,网络一开始压根就不收敛。然后又normalize这个reward,发现好一些了,但还是很不稳定,网络经常给一些很奇怪的输出,比如所有的参数都是0什么的。

上网搜,发现无论国内还是国外,大家普遍都在论坛里吐槽reinforcement learning文章复现不出来……

后来我就出坑了……   水平集好处在传统算法唯一可以包含几何先验的了,水平集还慢的不行。

Catboost是否不适于回归问题?

最近做一个project,是regression问题的预测。LGBM和XGboost调参效果都还不错,但是Catboost表现的惨不忍睹……是不是CatBoost本身就不适合回归问题,还是我调参技巧不行?这里有一个对比,https://blog.griddynamics.com/xgboost-vs-catboost-vs-lightgbm-which-is-best-for-price-prediction/;感觉CatboostRMSE真的表现的不好。答:否,跟调参经验有关。

以下经验供您参考:

  1. 当分类型变量没有太多值时,做one-hot encoding可提升表现。(注:数据预处理时谨慎使用)
  2. 检查树的数量是否造成了过拟合或欠拟合。可分析测试集上的metric value(度量值),来选择合适的迭代次数
  3. 调整学习率。若训练时,上次迭代没有过拟合,则提高学习率。若检测到过拟合,则降低学习率。
  4. 树深度。通常最佳的树深度在4-10之间,推荐使用6-10之间的值。
  5. L2正则化,尝试不同值以找到最佳值。
  6. 随机强度,尝试不同值已找到最佳值。
  7. Bagging温度
  8. Border count,这个值会影响GPU训练速度。值越小,训练越快。对大部分数据集而言,设置为128就行了
  9. 若数据集是有序的,调整internal dataset order。

 

https://blog.csdn.net/cauchy7203/article/details/107588241

K折交叉验证:

本质上就是这么个过程:
●将样本拆分为k个子集,用其中k-1个子集的数据训练模型,再在剩下的一个子集上验证模型的性能。当所有子集都被作为测试集轮完-圈之后, 计算模型在所有子集上的平均性能。
●对每一组超参数对应模型执行上述操作,选出平均性能最好的一组参数作为最优参数。实现代码可以参考这个:

机器学习可以学习调参吗?

往大了说就是learning to learn,九十年代就有人提出来了。最近比较火的就是meta learning,但具体做法不是原题目那么去做,可以去了解一下。完全自动的话就是google的automl了(包括模型选择)。你可以看下遗传算法或者粒子群算法优化神经网络的论文,一大堆,你把模型和要优化的参数换一下就可以了;感觉比较像 emperical bayesian。learning to learn,其实写出arg min不是难点,得有办法操作才行,找到优化算法才是难点。这是18年蛮火的领域,auto machine learning的超参优化。Nas也算是这个领域的。

为什么大家都把算法工程师叫做调参侠?我做cv的 调参只是在我研究中占很小一部分 影响模型效果的还是要看网络结构和数据和损失函数 这三方面确定下来后 调参基本花不了多少时间。我还专门问了实验室以为挺厉害的博士 他也是这么认为的。我甚至觉得调参只是大部分人网络跑不出效果的借口。有没有算法工程师来交流下?答:真正的老手往往是从数据和特征下手的,而且还需要丰富的行业经验,远远不是调参数这么简单的事情 。一定要记住一句行业内的谚语,数据和特征才决定算法 的上限,而选择的算法和参数只是决定了已逼近这个上限的速度;

我来举一个例子来说明。

在美帝那边曾经发生一个人像识别模型歧视黑人的事情。说有 一个使用大量样本训练出的人脸识别模型歧视黑人,因为白人被识别准确率很高,但是黑人的识别准确率非常低。

这个现象其实本质是数据问题,表面上看可能是黑人的样本过少,大多数样本肤色都比较白,所以模型识别浅色皮肤的人准确率较高。表面上看这是样本分布的问题。

那么作为算法工程师或者数据科学家应该如何解决这个问题呢?表面上看是黑人样本较少的缘故,但是本质上黑皮肤人脸数据内在规律和浅色皮肤人脸数据的内置规律有本质的不同。硬是放在一起,两个规律就会混杂在一起,那么样本多的浅色皮肤数据就会占优势,因为这样整体误差比较小。

解决方案很简单: 把黑皮肤人脸数据和浅色皮肤数据分开,训练两个模型分别用来进行黑人人脸识别和浅色皮肤人脸识别。这样就能解决问题。

  1. Perception Classifier: 前面设置batch size = 10用 sgd, decision boundary一直不怎么动,检查了半天公式错误。最后把batch size改成100才开始收敛。iterate了5000次最后达到optimal point
  2. Backpropagation: 怎么调都不动,不propagate,公式多次检查无误。最后把每层网络的值都print出来发现只有最顶层网络稍稍有所propagate,网络往下走参数动都没动。继续查看每个变量的值,发现问题出在初始化的参数,初始化参数应尽量控制在(0,1)之间且各attributes最好标准化。
  3. gradient值太大,learning rate不够小导致往复横跳
  4. Neural Network, 之前为了使多个nodes的情况下backpropagation能顺利进行,在每一轮的train过程中normalize了每一次train改变的gradient,nodes很多的时候work,nodes少的时候每次更新在原地踏步。因为每次更新的graident被normalize offset掉了。
  5. 简单二分类任务,Neural Network只有在小样本的情况下能收敛,样本稍大就只会全输出为1或0. 原因:尚未确定 可能是收敛到local optimal point去了

算法工程师的工作内容并没有那么简单,因为设置超参数的过程需要专业知识和广泛的试验和试错过程。尤其是针对学习率(learning rate)、批量大小(batch size)、动量( momentum)和权重衰减(weight decay)这些超参数而言,没有简单易行的方法来设置。

深度学习模型充满了超参数,在如此高维空间中找到这些参数的最佳值并不是一项容易的挑战。在讨论找到最佳超参数的方法之前,首先了解这些超参数:学习率、批量大小、动量和权重衰减。这些超参数类似于开关旋钮,可以在模型训练期间进行调整。为了使得模型能够获得最佳结果,需要找到这些超参数的最佳值。

梯度下降

梯度下降是训练机器学习算法中常用的优化技术。训练机器学习算法的主要目的是调整权重w以最小化损失函数或成本函数。通过最小化成本函数,就可以找到产生最佳模型性能的参数[1]。 回归问题的典型损失函数图类似于碗的形状,如下所示。

在梯度下降算法中,首先随机模型参数,并计算每次学习迭代的误差,不断更新模型参数以更接近导致最小成本的值。梯度下降算法将梯度乘以一个标量(学习率),以确定下一个点。

如果用dW和db作为更新参数W和b的梯度,梯度下降算法如下:

如果学习率很小,那么训练会更加可靠,但花费的时间也更多,因为每次移动的步长很小。

如果学习率很大,那么训练可能不收敛。权重变化可能很大,以至于优化器错失最优化并使得损失变大。因此,最终目标是找到可以快速获得最小损失的最佳学习率。

一般而言,可以将梯度下降视为在山谷中滚动的球。希望它能够在停留山脉的最深处,但有时可能会出错。

根据球开始滚动的位置,它可能会停留在山谷的底部。但不是最低的一个,这称为局部最小值。初始化模型权重的方式可能会导致局部最小值。为了避免这种情况,可以随机始化权重向量。

用2-D表示损失面,如下所示: 


红点是全局最小值,希望能够达到这一点。使用梯度下降方法,更新将如下所示:


使用恒定学习率:如果使用恒定的学习率,那么大的恒定动量(即0.9-0.99)将起到伪增加学习率的作用并加速训练。但是,使用过大的动量值会导致训练结果很差。

无论是循环学习速率还是恒定学习速率,可以尝试在0.9到0.99范围内设定动量值,并从中选择一个表现最佳值。

权重衰减

体重衰减是正则化的一种形式,它在训练中起着重要作用,因此需要适当设定[7]。权重衰减被定义为将每个时期的梯度下降中的每个权重乘以因子λ(0 <λ<1)。 一般而言,可以测试权重衰减值为1 /103、1 /10?、1 /10?和0。较小的数据集和模型结构设置较大的权重衰减值,而较大的数据集和更深的模型结构设置较小的值。 如果使用恒定的学习率而不是使用学习率范围进行搜索,则最佳权重衰减会有所不同。由于较大的学习率提供正则化,因此较小的权重衰减值是最佳的。

总结

学习率:

  • 执行学习率范围测试以确定“大”的学习率。 *一轮测试确定最大学习速率,将最小学习速率设置为最大学习速率的十分之一。

动量:

  • 用短期动量值0.99、0.97、0.95和0.9进行测试,以获得动量的最佳值;
  • 如果使用周期学习率计划,最好从该最大动量值开始循环设置动量,并随着学习率的增加而减小到0.8或0.85;

批量大小:

  • 根据硬件条件使用尽可能大的批量大小,然后比较不同批量大小的性能;
  • 小批量添加正规化的效果大,而大批量添加的正则化效果小,因此在适当平衡正规化效果的同时利用好它;
  • 使用更大的批量通常会更好,这样就可以使用更大的学习率;

权重衰减:

  • 网格搜索以确定适当的幅度,但通常不需要超过一个有效数字精度;
  • 更复杂的数据集需要较少的正则化,因此设置为较小的权重衰减值,例如10^-4、10^-5、10^-6、0;
  • 浅层结构需要更多的正则化,因此设置更大的权重衰减值,例如10^-2、10^-3、10^-4;

楼上已经提到了random search的方法了,但在random上还有更高效的方式,现在主要在分为两大块: 

  1. 针对random sample的效率做提升,比如使用bandits来做adaptive budget allocation的方法,early stop一些没有潜力的参数组,从而提升效率。比较有代表性的工作就是Successive Halving 算法,和其集成的hyperband。
  2. 针对random的sampling的方式做提升,比如引入一些假设,来挑选更好的samples,代表性的为贝叶斯优化。

另外还有一些结合的方法,比如BOHB这种,比单一的方式会更强一些。这个方法应该已经在github上开源了

请教一个问题,如果数据量很大的话,怎么用grid search来进行参数搜索呢?因为数据量很大,就不能用fit方法了(不可能一次性将数据全部放进去,内存会不够的),要用类似于fit_generator(keras)方法。不知道gridsearch应该如何来实现这个方法。类似hyperband,你可以先喂一部分数据进去,看看基础效果,然后筛选掉一些,再喂新的一部分数据,再筛选;明白了,谢谢。一直想着用keras中的KerasClassifier来包装模型,然后用scikit的gridsearchCV来进行搜索,结果发现fit方法不接受generator。走进了死胡同。