在算法项目落地过程中,如果只考虑机器学习相关部分,个人感觉最花时间的两个部分是数据质量问题处理和模型实验与迭代调优。在之前FullstackDeepLearning介绍的基础上,我们在这篇文章中主要针对第二个问题做一些详细的展开。
阅读建议一不小心,本文又写的有点长……所以这里大概给一个阅读建议:
对于初级算法工程师,希望了解基础的算法建模流程的,可以主要阅读1~5部分。从第6部分开始是更深入的通过数据分析来进行模型调优的一些介绍,以及后续的测试,工程化,上线的简介,比较适合有经验的算法工程师阅读。对于文中有任何描述不明确的地方,欢迎提出宝贵建议,先提前感谢大家啦!
1原则先列举一些模型优化过程中遵循的一些原则:
清晰的优化指标高质量Pipeline明确的实验设计深入的结果分析接下来我们逐步来分析与介绍。
2指标定义2.1什么是一个好的指标从广义的指标定义来看,有几个考量方面:
Actionable,可以指导具体行为。Accessible,简单,容易理解。Auditable,可以进行验证。2.2机器学习项目中的指标在机器学习项目中,我们在遵循上述原则下,往往会定义不同类型的指标:
组织目标,例如增加整个公司的收入,降低成本,或者对社会的整体贡献等。一般会比较宏观,与具体技术的距离相对较远。另外这些指标收到的影响因素也有很多,内外部因素都有。在技术项目实现周期,到能影响到组织目标的变化过程会非常缓慢。因此一般很难直接优化这个指标。业务指标,相对组织目标来说会更加具体和可衡量。注意在这个层面我们经常碰到一些情况是模型输出预测是否符合用户预期,这种较为模糊的指标定义往往难以衡量与改进。因此必须与用户沟通,制定出明确可量化的指标来进行衡量。这个维度的指标也经常会比较复杂,从技术层面来看可能难以直接优化。模型指标,为了能快速迭代实验,我们往往需要深入理解前面的组织目标,业务指标,再转化为模型可以直接优化的指标,例如mae损失函数等。但这里也需要非常小心,模型指标可能并未反映用户的真实感受,或者与最终的业务目标有一些差距。对于这几类的指标,一个通常的做法是可以以不同的频率在不同层级对这些指标进行评估验证。例如在具体的实验中,可以以非常高的每次试验的频率来评估模型指标是否有提升。在天或者周的级别去验证模型效果的提升能够带来业务指标的提升。最后在月甚至更长的维度上去评估业务指标对组织整体目标的实现是否有正向促进作用。
实际项目中,往往会出现业务方面的指标不止一个的情况。例如我们既需要预测在细粒度上的squarederror较低,又需要预测总量上的偏差较小。为了能较好的评估模型,我们一般会设定一个主要的优化指标(可以是多个误差项的综合),将其它指标转化为限制条件。例如在模型预测时间不超过1秒的情况下,取得尽量高的AUC。
3实验流程很多机器学习课程上介绍的做法和很多行业新人在进行实验时会采取随机尝试的策略。例如,我先使用某种方法,得到了一个结果,然后脑子里又蹦出一个新的想法,继续尝试新方法,看结果是否有提升,依此不断循环。
But,这样做的效率太低了,很多时候就算效果有提升,也并不知道为什么,是否稳定,是否对最终的业务效果是正向的促进作用。因此我们更提倡采用数据分析驱动的方式来做各类建模实验。在分析基础上,实验设计的出发点一般需要有明确的假设,然后通过实验结果来验证假设是否成立。一般的步骤如下:
分析:模型问题是什么?提出假设:可能的根源问题是什么?设计实验:改进方案是什么?执行与验证:改进方案是否有效?循环迭代另外在实验涉及的尝试方向上,数据相关的处理往往占据了主要的位置,包括数据修正,转换,更新,增强,采样等,可能占比在80%以上。剩下20%是与模型相关的尝试。这也是业界的一个相对普遍的情况,需要在考虑实验内容方向时多加判断,避免做了一系列高大上的前沿模型尝试,总体产出却非常有限。
3.1问题分类对于模型中可能出现的问题,我们作如下分类:
代码实现中的bug。对于机器学习pipeline来说,很多情况下即使有隐藏的bug,程序也完全能跑通。这对问题排查造成了更大的困扰。超参数设置不合理。很多模型对各类超参数的设置比较敏感,需要针对不同的问题和表现进行超参数的调整。数据相关问题。数据量不足,分布不均衡,出现错误的标签,缺少特定信息,有概念漂移问题等。模型选择问题。针对特定的问题及数据情况,我们需要选择合适的模型。3.2整体流程为了避免这些问题,构建出高效,准确率高的算法模型,我们可以遵循如下的通用步骤:
整体流程从简单的pipeline开始,例如选择最简单的规则,或者基础模型。以深度学习模型为例,我们可以选择最基础的MLP模型,adam优化方法,不加任何regularization,使用标准归一化方法,选取一个子集数据进行尝试。实现并跑通pipeline。确保模型能够运行,并在小数据集上overfit,或复现一些已知结果。评估并分析结果。后续会详细介绍分析手段方法。参数调优。对模型的各种参数,模型结构进行各种调整。数据与模型调优。修复数据中的问题,做数据增强,引入不同类型的数据,收集更多数据,或者特征工程预处理方面的操作。模型方面可以使用更加高级/复杂的模型结构,引入ensemble等。这方面比较好的资料可以参考AndrewNg的《MachineLearningYearning》,后续我们也会做一些具体阐述。
4实验执行与管理4.1Pipeline模型上线之后,需要有高质量的pipeline来进行系统化的运行,debug,及版本管理。这里不做详细展开。从实验与模型优化角度看,对于经常需要尝试迭代更新的部分,应该做好模块分割,便于灵活进行针对性的实验。
实验pipeline对运行效率会有更高要求,通常是针对整个流程中的一小部分,来反复修改尝试,快速获取到实验结果。举例来说,如果我们想做一个新特征的尝试,应该基于历史的特征数据集来进行增量的尝试,而不是修改原有的特征工程代码,触发全量的特征构建流程。一个简单的评估标准是,每次实验运行的总时间中,有多少百分比的时间实际上是在做重复的操作。理想情况下,这部分重复运行的占比要低于10%。
对于实验pipeline的代码质量方面,一个简单的原则就是越需要重复高频使用的实验,越需要做更好的抽象和代码质量保证。建议在notebook中写完草稿后,拷贝到PyCharm等专业IDE中进行代码重构与质量检查。
另外有一些业界研究,例如HELIX就是为了提升实验效率,希望能够自动存储中间结果,来减少重复计算,达到使用同一个pipeline,但重复执行的效率会变得很高的效果。
4.2版本管理在pipeline基础上,我们需要对实验使用到的各类依赖进行版本管理,主要包括:
数据版本,如果使用的产品带数据版本,直接使用即可。否则可以考虑用sha1等文件校验码来记录数据的版本信息。代码版本,对于库函数这类有git管理部分的代码,可以直接使用git的版本号。对于临时的notebook文件,可以每天做一个notebook版本的备份。对于重要结果,例如当前最好效果,也可以随时做版本备份。参数配置,大多数情况下,参数配置可以在代码或者数据的版本中cover。但需要额外注意使用了外部配置文件的情况,对于这些配置文件,也需要与实验的其它运行组成来一起管理(例如放在同一个文件夹下)。模型版本,对于模型训练非常耗时的场景,训练出来的模型也需要进行版本管理,以便于后续的分析与重用。实验版本管理对于项目过程中review进度,确定下一步计划,复现结果并部署上线等方面都非常重要。
5初级建模调优5.1数据流验证首先检验dataflow没有问题。例如使用简单的规则,替代模型模块,查看整个pipeline的流程是否有问题。对pipeline中大块环节的输出做检查。
Pipeline验证5.2跑通模型训练接下来将规则替换成真实的简单模型,进行训练与预测,看是否能跑通。过程中会出现各种抛错,列举一些最常见的bug:
Tensorshape错误预处理错误Lossfunction错误数据中有NaN/Inf等值没有正确的设置训练模式,或其它框架相关常见错误参数或数据处理问题导致的OOM库版本不匹配导致的奇怪exception应对策略:
使用标准化的流程pipeline,比如框架内置方法,或者自己整理的针对某类问题的标准receipe。搜索StackOverflow,Github上相关问题,寻求解决方案。使用debugger和profiler进行深入调试。借助一些专用工具来辅助排查,例如tensor-sensor。5.3在小数据集上过拟合模型可以训练了,我们会使用小批量数据来看是否能让模型在这部分数据上过拟合。这里会碰到的一些常见问题例如:
误差不降反升误差爆炸误差震荡误差停留在一个高位无法下降应对策略:
误差上升的可能原因,学习率太高,lossfunction定义错误误差爆炸的可能原因,学习率太高,各种数值操作的问题,如exp,log,除法等误差震荡的可能原因,学习率太高,原始数据问题如数据错位,预处理bug等,可以进一步通过结果分析定位误差停留在一个高位,可能由于学习率太低,优化器相关设置,正则项过大,模型过于简单,lossfunction欠佳,部分数据有错误,没有做数据归一化,缺乏有效特征等5.4模型参数搜索在模型可以在小数据量上正常优化后,接下来通常的建议可能是增加数据量并做一定的模型参数搜索。不过根据我们的经验,这部分的整体计算开销较大,但回报率相对比较一般(可以参考AutoML文中的一些research结论)。所以如果模型训练开销不大的情况下,我们可以考虑在每天空闲时间(例如晚上下班后),挂一些自动参数搜索的任务进行调优尝试。而在工作时间段,还是应该集中精力做误差分析和问题定位。
5.5深入优化在初始的pipeline跑通,模型可以产出有意义的预测之后,再接下来就逐渐开始进入深水区了。一方面我们要不断降低模型训练误差,另一方面也要开始