精华内容
下载资源
问答
  • 机器学习模型可解释性的详尽介绍

    千次阅读 多人点赞 2019-11-26 12:22:00
    机器之心平台来源:腾讯技术工程模型可...本文对机器学习模型可解释性相关资料汇总survey。综述机器学习业务应用以输出决策判断为目标。可解释性是指人类能够理解决策原因的程度。机器学习模型的可解释性越高,人...

    机器之心平台

    来源:腾讯技术工程

    模型可解释性方面的研究,在近两年的科研会议上成为关注热点,因为大家不仅仅满足于模型的效果,更对模型效果的原因产生更多的思考,这样的思考有助于模型和特征的优化,更能够帮助更好的理解模型本身和提升模型服务质量。本文对机器学习模型可解释性相关资料汇总survey。


    综述

    机器学习业务应用以输出决策判断为目标。可解释性是指人类能够理解决策原因的程度。机器学习模型的可解释性越高,人们就越容易理解为什么做出某些决定或预测。模型可解释性指对模型内部机制的理解以及对模型结果的理解。其重要性体现在:建模阶段,辅助开发人员理解模型,进行模型的对比选择,必要时优化调整模型;在投入运行阶段,向业务方解释模型的内部机制,对模型结果进行解释。比如基金推荐模型,需要解释:为何为这个用户推荐某支基金。

    机器学习流程步骤:收集数据、清洗数据、训练模型、基于验证或测试错误或其他评价指标选择最好的模型。第一步,选择比较小的错误率和比较高的准确率的高精度的模型。第二步,面临准确率和模型复杂度之间的权衡,但一个模型越复杂就越难以解释。一个简单的线性回归非常好解释,因为它只考虑了自变量与因变量之间的线性相关关系,但是也正因为如此,它无法处理更复杂的关系,模型在测试集上的预测精度也更有可能比较低。而深度神经网络处于另一个极端,因为它们能够在多个层次进行抽象推断,所以他们可以处理因变量与自变量之间非常复杂的关系,并且达到非常高的精度。但是这种复杂性也使模型成为黑箱,我们无法获知所有产生模型预测结果的这些特征之间的关系,所以我们只能用准确率、错误率这样的评价标准来代替,来评估模型的可信性。

    事实上,每个分类问题的机器学习流程中都应该包括模型理解和模型解释,下面是几个原因:

    • 模型改进:理解指标特征、分类、预测,进而理解为什么一个机器学习模型会做出这样的决定、什么特征在决定中起最重要作用,能让我们判断模型是否符合常理。一个深度的神经网络来学习区分狼和哈士奇的图像。模型使用大量图像训练,并使用另外的一些图像进行测试。90%的图像被准确预测,这值得我们高兴。但是在没有计算解释函数(explainer function)时,我们不知道该模型主要基于背景:狼图像通常有一个下雪的背景,而哈士奇的图像很少有。所以我们不知不觉地做了一个雪地探测器,如果只看准确率这样的指标,我们就不会看到这一点。知道了模型是如何使用特征进行预测的,我们就能直觉地判断我们的模型是否抓住了有意义的特征,模型是或否能泛化到其他样本的预测上。

    • 模型可信性与透明度:理解机器学习模型在提高模型可信度和提供审视预测结果透明度上是非常必要的,让黑箱模型来决定人们的生活是不现实的,比如贷款和监狱刑法。另一个对机器学习结果可信度提出质疑的领域是药品,模型结果会直接决定病人的生与死。机器学习模型在区分恶性肿瘤和不同类型的良性肿瘤方面是非常准确的,但是我们依然需要专家对诊断结果进行解释,解释为什么一个机器学习模型将某个患者的肿瘤归类为良性或恶性将大大帮助医生信任和使用机器学习模型来支持他们工作。长久来看,更好地理解机器学习模型可以节省大量时间、防止收入损失。如果一个模型没有做出合理的决定,在应用这个模型并造成不良影响之前,我们就可以发现这一点。

    • 识别和防止偏差:方差和偏差是机器学习中广泛讨论的话题。有偏差的模型经常由有偏见的事实导致,如果数据包含微妙的偏差,模型就会学习下来并认为拟合很好。一个有名的例子是,用机器学习模型来为囚犯建议定罪量刑,这显然反映了司法体系在种族不平等上的内在偏差。其他例子比如用于招聘的机器学习模型,揭示了在特定职位上的性别偏差,比如男性软件工程师和女性护士。机器学习模型在我们生活的各个层面上都是强有力的工具,而且它也会变得越来越流行。所以作为数据科学家和决策制定者来说,理解我们训练和发布的模型如何做出决策,让我们可以事先预防偏差的增大以及消除他们,是我们的责任。

    可解释性特质:

    • 重要性:了解“为什么”可以帮助更深入地了解问题,数据以及模型可能失败的原因。

    • 分类:建模前数据的可解释性、建模阶段模型可解释性、运行阶段结果可解释性。

    • 范围:全局解释性、局部解释性、模型透明度、模型公平性、模型可靠性。

    • 评估:内在还是事后?模型特定或模型不可知?本地还是全局?

    • 特性:准确性、保真性、可用性、可靠性,鲁棒性、通用性等。

    • 人性化解释:人类能够理解决策原因的程度,人们可以持续预测模型结果的程度标示。


    动机

    在工业界中,数据科学或机器学习的主要焦点是更偏“应用”的解决复杂的现实世界至关重要的问题,而不是理论上有效地应用这些模型于正确的数据。机器学习模型本身由算法组成,该算法试图从数据中学习潜在模式和关系,而无需硬编码固定规则。因此,解释模型如何对业务起作用总是会带来一系列挑战。有一些领域的行业,特别是在保险或银行等金融领域,数据科学家通常最终不得不使用更传统的机器学习模型(线性或基于树的)。原因是模型可解释性对于企业解释模型所采取的每个决策非常重要。

    残酷的现实是,如果没有对机器学习模型或数据科学pipeline如何运作的合理理解,现实中的项目很少成功。现实中的数据科学项目,通常会有业务和技术两方面。数据科学家通常致力于构建模型并为业务提供解决方案。但是,企业可能不知道模型如何工作的复杂细节。

    数据科学从业者将知道存在典型的模型可解释性与模型性能权衡。这里需要记住的一点是,模型性能不是运行时或执行性能,而是模型在决策中的准确程度。有几种模型,包括简单的线性模型甚至是基于树的模型,它们可以很容易地解释模型为获得特定的洞察力或预测而做出的决策,但是你可能需要牺牲模型性能,因为它们总是不能产生最好的结果是由于高偏差(线性模型)或高方差的固有问题,导致过度拟合(完全成长的树模型)。更复杂的模型,如集合模型和最近的深度学习模型系列通常会产生更好的性能,但被认为是黑盒模型,因为很难解释模型如何真正做出决定。

    理解模型可解释性

    模型解释作为一个概念仍然主要是理论和主观的。任何机器学习模型的核心都有一个响应函数,它试图映射和解释独立(输入)自变量和(目标或响应)因变量之间的关系和模式。当模型预测或寻找见解时,需要做出某些决定和选择。模型解释试图理解和解释响应函数所做出的这些决定,即what,why以及how。模型解释的关键是透明度,质疑能力以及人类理解模型决策的难易程度。模型解释的三个最重要的方面解释如下。

    1. 是什么驱动了模型的预测?我们应该能够查询我们的模型并找出潜在的特征交互,以了解哪些特征在模型的决策策略中可能是重要的。这确保了模型的公平性。

    2. 为什么模型会做出某个决定?我们还应该能够验证并证明为什么某些关键特征在预测期间驱动模型所做出的某些决策时负有责任。这确保了模型的可靠性。

    3. 我们如何信任模型预测?我们应该能够评估和验证任何数据点以及模型如何对其进行决策。对于模型按预期工作的关键利益相关者而言,这应该是可证明且易于理解的。这确保了模型的透明度。

    在比较模型时,除了模型性能之外,如果模型的决策比其他模型的决策更容易理解,那么模型被认为比其他模型具有更好的可解释性。

    可解释性的重要性

    在解决机器学习问题时,数据科学家往往倾向于关注模型性能指标,如准确性,精确度和召回等等(毫无疑问,这很重要!)。这在大多数围绕数据科学和机器学习的在线竞赛中也很普遍。但是,指标只能说明模型预测决策的部分故事。随着时间的推移,由于环境中的各种因素导致的模型概念漂移,性能可能会发生变化。因此,了解推动模型采取某些决策的因素至关重要。

    如果一个模型工作得很好,为什么还要深入挖掘呢?在解决现实世界中的数据科学问题时,为了让企业信任您的模型预测和决策,他们会不断提出“我为什么要相信您的模型?”这一问题,这一点非常有意义。如果一个人患有癌症或糖尿病,一个人可能对社会构成风险,或者即使客户会流失,您是否会对预测和做出决策(如果有的话)感到满意?也许不是,如果我们能够更多地了解模型的决策过程(原因和方式),我们可能会更喜欢它。这使我们更加透明地了解模型为何做出某些决策,在某些情况下可能出现的问题,并且随着时间的推移它有助于我们在这些机器学习模型上建立一定程度的信任。

    • 了解预测背后的原因在评估信任方面非常重要,如果计划基于预测采取行动,或者选择是否部署新模型,那么这是至关重要的。

    • 无论人类是直接使用机器学习分类器作为工具,还是在其他产品中部署模型,仍然存在一个至关重要的问题:如果用户不信任模型或预测,他们就不会使用它。

    这是我们在本文中多次讨论的内容,也是决定数据科学项目在行业中取得成功的关键区别之一。这推动了模型解释的必要性和重要性的紧迫性。

    可解释性的标准

    有一些特定的标准可用于分类模型解释方法。Christoph Molnar,2018年“可解释的机器学习,制作黑箱模型可解释指南”中提到了一个很好的指南。

    • 内在还是事后?内在可解释性就是利用机器学习模型,该模型本质上是可解释的(如线性模型,参数模型或基于树的模型)。事后可解释性意味着选择和训练黑匣子模型(集合方法或神经网络)并在训练后应用可解释性方法(特征重要性,部分依赖性图)。我们将更多地关注我们系列文章中的事后模型可解释方法。

    • 模型特定或模型不可知?特定于模型的解释工具非常特定于内在模型解释方法,这些方法完全依赖于每个模型的功能和特征。这可以是系数,p值,与回归模型有关的AIC分数,来自决策树的规则等等。与模型无关的工具与事后方法更相关,可用于任何机器学习模型。这些不可知方法通常通过分析(和输入的扰动)特征输入和输出对来操作。根据定义,这些方法无法访问任何模型内部,如权重,约束或假设。

    • 本地还是全局?这种解释分类讨论了解释方法是解释单个预测还是整个模型行为?或者如果范围介于两者之间?我们将很快谈论全球和地方的解释。


    可解释性的范围

    如何定义可解释性的范围和界限?一些有用的方面可以是模型的透明度,公平性和责任性。全局和局部模型解释是定义模型解释范围的明确方法。

    全局可解释:就是试图理解“模型如何进行预测?”和“模型的子集如何影响模型决策?”。要立即理解和解释整个模型,我们需要全局可解释性。全局可解释性是指能够基于完整数据集上的依赖(响应)变量和独立(预测变量)特征之间的条件交互来解释和理解模型决策。尝试理解特征交互和重要性始终是理解全球解释的一个很好的一步。当然,在尝试分析交互时,在超过两维或三维之后可视化特征变得非常困难。因此,经常查看可能影响全局知识模型预测的模块化部分和特征子集会有所帮助。全局解释需要完整的模型结构,假设和约束知识。

    局部解释:试图理解“为什么模型为单个实例做出具体决策?”和“为什么模型为一组实例做出具体决策?”。对于本地可解释性,我们不关心模型的固有结构或假设,我们将其视为黑盒子。为了理解单个数据点的预测决策,我们专注于该数据点并查看该点周围的特征空间中的局部子区域,并尝试基于该局部区域理解该点的模型决策。本地数据分布和特征空间可能表现完全不同,并提供更准确的解释而不是全局解释。局部可解释模型 - 不可知解释(LIME)框架是一种很好的方法,可用于模型不可知的局部解释。我们可以结合使用全局和局部解释来解释一组实例的模型决策。

    模型透明度:为试图理解“如何根据算法和特征创建模型?”。我们知道,通常机器学习模型都是在数据特征之上利用算法来构建将输入映射到潜在输出(响应)的表示。模型的透明度可能试图了解模型的构建方式以及可能影响其决策的更多技术细节。这可以是神经网络的权重,CNN滤波器的权重,线性模型系数,决策树的节点和分裂。但是,由于业务可能不太精通这些技术细节,因此尝试使用不可知的局部和全局解释方法来解释模型决策有助于展示模型透明度。

    可解释性的作用

    对于想要了解模型如何工作的数据科学家来说,评估模型的准确性通常是不够的。数据科学家通常想知道模型输入变量如何工作以及模型的预测如何根据输入变量的值而变化

    机器学习算法和模型的工程应用中用到最多的主要是树类模型(lgb,xgb)和神经网络(cnn, rnn),使用者往往习惯于很少去思考其中的含义和解释性。需要思考一个模型的哪些东西是可解释的?

    所以有几个问题值得讨论:

    • 哪些特征在模型看到是最重要的?

    • 关于某一条记录的预测,每一个特征是如何影响到最终的预测结果的?

    • 从大量的记录整体来考虑,每一个特征如何影响模型的预测的?

    为什么这些解释信息是有价值的呢:

    • 调试模型用
      一般的真实业务场景会有很多不可信赖的,没有组织好的脏数据。你在预处理数据时就有可能加进来了潜在的错误,或者不小心泄露了预测目标的信息等,考虑各种潜在的灾难性后果,debug的思路就尤其重要了。当你遇到了用现有业务知识无法解释的数据的时候,了解模型预测的模式,可以帮助你快速定位问题。

    • 指导工程师做特征工程
      特征工程通常是提升模型准确率最有效的方法。特征工程通常涉及到到反复的操作原始数据(或者之前的简单特征),用不同的方法来得到新的特征。有时候你完成FE的过程只用到了自己的直觉。这其实还不够,当你有上百个原始特征的时候,或者当你缺乏业务背景知识的时候,你将会需要更多的指导方向。如何创造出这样优秀的特征呢?如何找到最重要的特征的方法,并且可以发现两个特别相关的特征,当面对越来越多的特征的时候,这些方法就会很重要啦。

    • 指导数据采集的方向
      对于网上下载的数据集你完全控制不了。不过很多公司和机构用数据科学来指导他们从更多方面收集数据。一般来说,收集新数据很可能花费比较高或者不是很容易,所以大家很想要知道哪些数据是值得收集的。基于模型的洞察力分析可以教你很好的理解已有的特征,这将会帮助你推断什么样子的新特征是有用的。

    • 指导人们做决策
      一些决策是模型自动做出来的,虽然亚马逊不会用人工来决定展示给你网页上的商品,但是很多重要的决策是由人来做出的,而对于这些决定,模型的洞察力会比模型的预测结果更有价值。

    • 建立模型和人之间的信任
      很多人在做重要决策的时候不会轻易的相信模型,除非他们验证过模型的一些基本特性,这当然是合理的。实际上,把模型的可解释性展示出来,如果可以匹配上人们对问题的理解,那么这将会建立起大家对模型的信任,即使是在那些没有数据科学知识的人群中。


    方法

    模型效果评估指标图


    Confusion Matrix

    一个完美的分类模型就是,如果一个客户实际上属于类别 good,也预测成good,处于类别 bad,也就预测成 bad。实际上一些是 good 的客户,根据我们的模型,却预测他为 bad,对一些原本是 bad 的客户,却预测他为 good。我们需要知道,这个模型到底预测对了多少,预测错了多少,混淆矩阵就把所有这些信息,都归到一个表里:

    Sensitivity(覆盖率,True Positive Rate)= 正确预测到的正例数 / 实际正例总数;Recall (True Positive Rate,or Sensitivity) =true positive/total actual positive=d/c+d;

    PV+ (命中率,Precision, Positive Predicted Value) = 正确预测到的正例数 / 预测正例总数;Precision (Positive Predicted Value, PV+) =true positive/ total predicted positive=d/b+d;

    Specificity (负例的覆盖率,True Negative Rate) = 正确预测到的负例个数 / 实际负例总数;Specificity (True Negative Rate) =true negative/total actual negative=a/a+b;

    图中关于混淆矩阵结果理解:recall:0.54;precision:0.915;specificity:0.95;

    Lift

    它衡量的是,与不利用模型相比,模型的预测能力 “变好” 了多少。实质上它强调的是投入与产出比。不利用模型,我们只能利用 “正例的比例是 c+d/a+b+c+d” 这个样本信息来估计正例的比例(baseline model),而利用模型之后,我们不需要从整个样本中来挑选正例,只需要从我们预测为正例的那个样本的子集(b+d)中挑选正例,这时预测的准确率为 d/b+d。

    显然,lift(提升指数)越大,模型的运行效果越好。如果这个模型的预测能力跟 baseline model 一样,那么 d/b+d 就等于 c+d/a+b+c+d(lift 等于 1),这个模型就没有任何 “提升” 了(套一句金融市场的话,它的业绩没有跑过市场)。

    ROC曲线 & PR曲线 & KS曲线

    实际应用中,通常是先基于训练好的分类器得出测试样本的预测概率,然后将该测试样本的预测概率与给定的阈值进行比较,若该预测概率大于给定阈值,则将该测试样本划分为正类,反之则将其划分为反类。对于不同的分类任务,该分类阈值的取值也是不一样的。

    • ROC曲线(The Receiver Operating Characteristic Curve)给出的是不同分类阈值情况下真正率(TPr)和假正率(FPr)的变化曲线。PR曲线(Precision-Recall Curve)给出的是不同分类阈值情况下查准率(Precision)和查全率(Recall)的变化曲线。有文献指出,ROC曲线相比PR曲线有一个非常好的特性:就是当正负样本分布发生变化的时候,ROC曲线的形状能够基本保持不变,而PR曲线的形状会发生较剧烈的变化。为了使得ROC曲线之间能更好的进行比较,通常采用AUC,即ROC曲线下的面积来衡量一个分类算法的性能。其中,AUC的值越大,表明分类性能越好。

    • KS(Kolmogorov-Smirnov Curve)曲线横轴为不同的分类阈值,纵轴为真正率(TPr)和假正率(FPr)的变化曲线。KS值=max|TPr-FPr|,等价于ΔTPr=ΔFPr,这和ROC曲线上找最优阈值的条件一致。KS值常在征信评分模型中用于衡量区分预测正负样本的分隔程度。一般来说,KS值越大,表明正负样本区分的程度越好,说明模型区分度越高。但并非所有的情况KS值都是越高越好的,尤其在征信模型中,如正负样本完全分错的情况下,KS值依旧可以很高。征信模型最期望得到的信用分数分布为正态分布,如果KS值过大,如0.9,就可以认为正负样本分得过开了,不太可能是正态分布,反而比较可能是极端化的分布状态(如U字型),这样的分数就很不好,基本可以认为不可用。

    Cumulative gains chart

    横坐标表示:代表我们样本的百分比,假设有10000个样本,0.1代表1000个,1代表10000个样本。

    纵坐标表示:代表横轴所代表的那么多样本中,判断正确的比率。

    baseline表示:如果我们不用模型,那我们对每一个人的打分都是一样的,正率在所有样本空间都是一样的,连接起来就成为一条直线。

    曲线含义:采用模型进行预测。y值的分子代表模型预测且预测为正例的人数,分母是整个群体正例人数。

    Silhouette Analysis

    Silhouette指的是一种解释和验证数据集群内一致性的方法。该技术提供了每个对象分类的简洁图形表示。

    轮廓值是对象与其自身群集(内聚)相比与其他群集(分离)相似程度的度量。轮廓范围从-1到+1,其中高值表示对象与其自己的簇很好地匹配并且与相邻簇很不匹配。如果大多数对象具有高值,则群集配置是合适的。如果许多点具有低值或负值,则群集配置可能具有太多或太少的群集。

    图中通过Silhouette方法大致对数据集样本分类有了掌握,可以看到0/1类别大致比例。

    Learning Curve

    概念:学习曲线就是通过画出不同训练集大小时训练集和交叉验证的准确率,可以看到模型在新数据上的表现,进而来判断模型是否方差偏高或偏差过高,以及增大训练集是否可以减小过拟合。

    Bias是用所有可能的训练数据集训练出的所有模型的输出的平均值真实模型的输出值之间的差异。

    Variance不同的训练数据集训练出的模型输出值之间的差异。

    解读:当训练集和测试集的误差收敛但却很高时,为高偏差。左上角的偏差很高,训练集和验证集的准确率都很低,很可能是欠拟合。我们可以增加模型参数,比如,构建更多的特征,减小正则项。此时通过增加数据量是不起作用的。当训练集和测试集的误差之间有大的差距时,为高方差。当训练集的准确率比其他独立数据集上的测试结果的准确率要高时,一般都是过拟合。右上角方差很高,训练集和验证集的准确率相差太多,应该是过拟合。我们可以增大训练集,降低模型复杂度,增大正则项,或者通过特征选择减少特征数。理想情况是是找到偏差和方差都很小的情况,即收敛且误差较小。

    Permutation Importance

    一个最基本的问题大概会是什么特征对我模型预测的影响最大呢?这个东西就叫做“feature importance”即特征重要性。anyway,字面意思看着就很重要啦。我们有很多方法来衡量特征的重要性,这里呢,将会介绍一种方法:排列重要性。这种方法和其他方法比起来,优势有:

    • 计算速度快

    • 广泛使用和理解

    • 我们希望特征重要性与属性具有一致性

    工作原理:排列重要性,一定是在model训练完成后,才可以计算的。简单来说,就是改变数据表格中某一列的数据的排列,保持其余特征不动,看其对预测精度的影响有多大。大概三个步骤:

    • 训练好模型

    • 拿某一个feature column, 然后随机打乱顺序。然后用模型来重新预测一遍,看看自己的metric或者loss 。function变化了多少。

    • 把上一个步骤中打乱的column复原,换下一个column重复上一个步骤,直到所有column都算一遍。

    代码示例:

    from xgboost import XGBClassifier    
    from sklearn.model_selection import train_test_split
    import eli5   # python计算permutation importance工具包   
    from eli5.sklearn import PermutationImportance

    path = './census_income_dataset.csv'
    data = pd.read_csv(path)
    #...省略数据预处理过程
    X_train, X_test, y_train, y_test = train_test_split(df, y, test_size=0.2, random_state = 400)

    # 训练XGBoost模型
    model = xgb.XGBClassifier(
                            learning_rate =0.05,
                             n_estimators=100,
                             max_depth=3,
                             min_child_weight=1,
                             gamma=0.3,
                             subsample=0.8,
                             colsample_bytree=0.8,
                             objective= 'multi:softprob',
                             nthread=4,
                             scale_pos_weight=1,
                             num_class=2,
                             seed=27
                        ).fit(X_train, y_train)

    perm = PermutationImportance(model, random_state = 1).fit(X_test, y_test) # 实例化
    eli5.show_weights(perm, feature_names = X_test.columns.tolist())

    结果分析:

    • 靠近上方的绿色特征,表示对模型预测较为重要的特征;

    • 为了排除随机性,每一次 shuffle 都会进行多次,然后取结果的均值和标准差;

    • 部分特征出现负值,表示其 shuffle 之后,对精度反而有所提升。这通常出现在特征不那么重要的时候。当数据集较小的时候,这种情况更为常见;

    • “+ - ”之后的数字衡量的是一次重新洗牌后的表现如何变化;

    这个数据集是收入水平数据集,这个例子里,最重要的特征是“capital_gain”, 这看起来是合理的。

    PDP

    部分依赖图(PDP或PD图)显示特征对机器学习模型的预测结果的边际效应,可以展示一个特征是如何影响预测的。部分依赖图可以显示目标与特征之间的关系是线性的,单调的还是更复杂的。例如,当应用于线性回归模型时,部分依赖图总是显示线性关系。

    回归的部分依赖函数定义为:

    • xSxS是部分依赖图要画的特征集合

    • xCxC是其他特征

    通常,集合SS中有一到两个特征,这个集合中的特征我们想知道他们对预测的影响。在集合SS和集合CC中的特征并集组成了全部特征空间x。边际化机器学习模型输出在集合C的特征分布上。PDP的一个假设是,C中的特征与s中的特征不相关。如果违反这个假设,部分依赖图的平均值将包括非常不可能甚至不可能的数据点。

    边缘化概念
    边缘化是一种通过累加一个变量的可能值以判定另一个变量的边缘分布的方法。这听起来有点抽象,让我们看一个例子:

    假设我们想知道天气是如何影响英国人的幸福感的,也就是P(幸福感|天气)。假定我们具有衡量某人的幸福感所需的定义和设备,同时记录了某个英格兰人和某个苏格兰人所处位置的天气。可能苏格兰人通常而言要比英格兰人幸福。所以我们其实在衡量的是P(幸福感, 国|天气),即,我们同时考察幸福感和国。

    边缘化告诉我们,我们可以通过累加国家的所有可能值(英国由3国组成:英格兰、苏格兰、威尔士),得到想要计算的数字,即P(幸福感|天气) = P(幸福感, 国=英格兰|天气) + P(幸福感, 国=苏格兰|天气) + P(幸福感, 国=威尔士|天气)。

    部分函数f^xSf^xS通过计算在训练数据的平均值,即Monte Carlo方法:

    • x(i)CxC(i)是数据集中的真实特征值,这些特征是不关注的特征。

    特征重要性可以告诉你哪些特征是最重要的或者是不重要的。

    partial dependence图可以告诉你一个特征是如何影响预测的。

    PDP分析步骤如下:

    1. 训练一个Xgboost模型(假设F1 … F4是我们的特征,Y是目标变量,假设F1是最重要的特征)。

    2. 我们有兴趣探索Y和F1的直接关系。

    3. 用F1(A)代替F1列,并为所有的观察找到新的预测值。采取预测的平均值。(称之为基准值)

    4. 对F1(B)… F1(E)重复步骤3,即针对特征F1的所有不同值。

    5. PDP的X轴具有不同的F1值,而Y轴是虽该基准值F1值的平均预测而变化。

    PDP特别适合用来回答类似这样的问题:

    • 在所有的收入水平的特征中,年龄和学历是如何影响收入的?或者说,在不同的国家相同年龄的人群收入水平有多少相似呢?

    • 预测推荐基金时,投资偏好的不同会带来多大的影响?还是有其他更重要的影响因素?

    如果你对线性回归或者逻辑回归比较熟悉,那么partial dependence可以被类比为这两类模型中的“系数”。并且partial dependence在复杂模型中的作用比在简单模型中更大,抓出更复杂的特性。

    同样还是用census_income的数据集,不同的个体在各个方面都是不一样的。比如种族,年龄,受教育程度等等。一眼看过去,很难区分这些特征对结果的影响有多大。为了清晰的分析,我们还是先只拿出某一行数据,比如说这一行数据里,有种族White,45岁,Bachelors。我们将会用已有模型来预测结果,将这一行的某一个变量,反复的进行修改和重新预测,比如将年龄修改从45修改为60,等等。持续观察预测结果,在不同的年龄时有什么样的变化。

    这里的例子,只用到了一行数据。特征之间的相互作用关系通过这一行来观察可能不太妥当,那么考虑用多行数据来进行试验,然后根据平均值画出图像来。

    from pdpbox import pdp

    feature = 'age'
    # 创建好画图所需的数据
    pdp_goals = pdp.pdp_isolate(model, X_train, df.columns, feature)
    # 画出“age”这一特征的partial dependence plot
    pdp.pdp_plot(pdp_goals, feature)
    plt.show()

    第一:y轴是预测结果的变化量。
    第二:蓝色阴影区域代表了置信的大小。
    从这幅图可以看出,age的增加肯定可以增加高收入概率,但是增加到一定的时候,对这个概率影响不大了。

    置信区间概念

    给定置信水平,根据估计值确定真实值可能出现的区间范围,该区间通常以估计值为中心,该区间则为置信区间。

    feature = 'education_num'
    pdp_goals = pdp.pdp_isolate(model, X_train, df.columns, feature)
    pdp.pdp_plot(pdp_goals, feature)
    plt.show()

    从这副图可以看出,受教育程度对收入起积极作用,随着受的教育越多,收入越高,也符合常人理解。

    fig, axes, summary_df_1 = info_plots.target_plot_interact(
        df=dataset, features=['age', 'education_num'], feature_names=['age', 'education_num'], target='income_level'
    )

    在此图表中,气泡大小不太重要,因为它与观测数量(事件发生的次数)有关。最重要的见解来自气泡的颜色,较暗的气泡意味着更高的默认概率。这是一个强大的工具,因为它可以深入了解我们选择的两个变量对因变量的影响。

    features_to_plot = ['age', 'education_num']
    inter1  = pdp.pdp_interact(model, df, df.columns, features_to_plot)
    pdp.pdp_interact_plot(inter1, features_to_plot, plot_type='grid', x_quantile=True, ncols = 2, plot_pdp=True)
    plt.show()

    上图可以看出,受教育程度和年龄对收入水平有着正相关作用,且随着受教育程度增加,年龄从35-90,高收入的概率越来越大。

    fig, axes = pdp.pdp_interact_plot(
        inter1, ['age', 'education_num'], plot_type='contour', x_quantile=True, ncols=2, 
        plot_pdp=True
    )

    重要的是要记住,在该图中,较暗的颜色并不一定意味着较高的默认概率。在这里,我们绘制了受教育等级和年龄与收入等级概率。我们可以推断,在这两个自变量中,education_num起着更重要的作用,因为等高线图主要是垂直的,遵循x轴刻度标记(至少达到一个点)。

    ICE

    部分依赖图(PDP)和个体条件期望图(ICE)说明了一个或多个输入变量与黑盒模型的预测结果之间的关系。它们都基于可视化,模型不可知的技术。ICE图可以更深入地探索个体差异并识别模型输入之间的子组和相互作用

    另一方面,ICE图使得可以深入到单个观察的水平。它们可以帮助探索个体差异,并确定模型输入之间的子组和交互。可以将每个ICE曲线视为一种模拟,显示如果改变特定观察的一个特征,模型预测会发生什么。为避免可视化过载,ICE图一次只显示一个模型变量。

    可以将每个ICE曲线视为一种模拟,显示如果您改变特定观察的一个特征,模型预测会发生什么。如图9所示,通过在曲线变量的唯一值上复制个体观察并对每个重复进行评分,获得一个观察的ICE曲线。

    下图中的PD图结果基本上是平坦的,给人的印象是X1与模型的预测之间没有关系。

    当我们观察ICE图时,它们呈现出一幅截然不同的图:这种关系对于一次观察非常正面,但对另一次观察则非常负面。因此,与PD图告诉我们的情况相反,ICE图显示X1实际上与目标有关;。基本上,ICE图分离PD功能(毕竟是平均值)以揭示相互作用和个体差异。

    当对大数据集分析时,则可能需要进行一些调整。例如,可以对选定的变量进行分箱,也可以对数据集进行采样或分组。这些技术可以更快地提供实际图的合理近似值。

    如果想进一步了解PD和ICE图,Ray Wright写了一篇很好的论文,展示了PD和ICE图如何用于比较和获得机器学习模型的洞察力,特别是所谓的“黑盒”算法,如随机森林,神经网络和梯度增强。在他的论文中,他还讨论了PD图的局限性,并提供了有关如何为大数据生成可缩放图的建议。https://www.sas.com/content/dam/SAS/support/en/sas-global-forum-proceedings/2018/1950-2018.pdf

    LIME

    局部可解释不可知模型(LIME)是一种算法,它提供了一种新颖的技术,以可解释和可信任的方式解释任何预测模型的结果。它的工作原理是围绕想要解释的预测在本地训练可解释的模型。这个工作发表于2016年KDD的论文。工具学习地址。

    流程

    • 训练模型,模型(记作 ff)可以是LR、NN、Wide and deep、C4.5 Decision tree、Random forest、GBDT等任意模型。

    • 训练结束后我们需要解析模型,先选择一个待解析的样本,样本通过模型计算可以得到一个prediction(包含预测的label以及预测为1的probability),这时我们在这个样本的附近选择新的样本并用模型计算出多个prediction,这样样本组合新的样本集。

    • 然后使用新的可解析的特征和prediction作为label来训练新的简单模型(例如LR),然后使用简单模型的权重作为这些特征的重要性作为输出。

    通俗来说

    就是选择一个样本以及样本附近的点,然后训练一个简单模型来拟合,虽然简单模型不能在完整数据集上有效,但至少在这个点附近都是有效的,这个简单模型的特征是人类可解析的,而训练出的权重也可以表示特征重要性。

    论文中算法描述:

    为了更好地理解LIME的工作原理,让我们考虑两种不同类型的可解释性:

    • 全局可解释性:全局解释有助于我们理解由训练的响应函数建模的整个条件分布,但全局解释可以是近似的或基于平均值。

    • 局部可解释性:局部解释促进对单个数据点或分布的小范围的理解,例如一组输入记录及其相应的预测。由于小范围的条件分布很可能是线性的,因此局部解释可能比全局解释更准确。LIME旨在提供局部可解释性,因此对于特定决策或结果最为准确。

    我们希望解释器与模型无关,并且在局部可靠。局部可靠的解释捕获要解释的实例邻域中的分类器行为。为了学习局部解释,LIME使用可解释的模型近似分类器围绕特定实例的决策边界。LIME与模型无关,这意味着它将模型视为黑盒子,并且不对模型行为做出任何假设。这使得LIME适用于任何预测模型。

    LIME的核心在于三个方面:

    • 这里不对模型整体提供解释,而是局部对每一个样本单独进行解释

    • 即使机器学习模型训练过程会产生一些抽象的特征,但是解释基于当前输入数据的变量特征

    • 通过局部建立简单模型进行预测来对大多数重要特征进行解释

    LIME作用在单个样本上。

    首先,我们取出一个样本,并(permute)重复这个数据同时增加一些微小扰动,这样就得到了一个新的数据集,数据集中包含相似的样本,都基于取出来的那个样本。对于这个新数据集中的每一个样本,我们可以计算它跟取出的样本之间的相似性,即在permutation中它被调整了多大,所有的统计距离、相似性矩阵都可以用在这里,比如用指定宽度的指数内核将欧式距离转化为相似度。

    下一步,使用最初训练的复杂模型,在新数据上进行预测。正因为新数据样本间的细微差别,我们可以跟踪那些微小扰动对预测结果的影响。

    最后,我们在新数据上训练出一个简单模型(通常是线性模型),并使用最重要的特征进行预测。最重要的特征有不同的决定方法,在指定加入模型解释中的特征数量(通常在5到10附近)的前提下,可以

    • 选择在使用复杂模型进行预测时回归拟合上具有最高权重的特征

    • 运用正向选择,选择可以提高复杂模型的预测的回归拟合的变量

    • 在复杂的机器学习模型预测的基础上,选择正则化的收缩率最小的lasso预测拟合的特征

    • 使用不多于我们已经选择了的特征的节点数量来构建决策树

    ## 创建LIME解释器
    explainer = lime.lime_tabular.LimeTabularExplainer(X_train ,feature_names = features_name, class_names=['0','1'], categorical_features=data_cat_features, 
    categorical_names=cat_columns, kernel_width=3)
    predict_fn_xgb = lambda x: xgb.predict_proba(x).astype(float)
    exp = explainer.explain_instance(X_test[2], predict_fn_xgb, num_features=6)
    exp.show_in_notebook(show_all=False)

    上图给我们解释了对于一个样本的预测结果,是哪些特征决定样本被分类到类别0,哪些特征决定样本被分类到类别1,且具体列出样本在这些特征的数值大小。很直观和明确的解释为什么模型做这个决定。

    SHAP

    Shaply值由美国洛杉矶加州大学教授罗伊德·夏普利(Lloyd Shapley)提出,用于解决合作博弈的贡献和收益分配问题。N人合作中,单个成员的贡献不一样,收益分配也应该不一样。理想的分配方式是:贡献=收益;

    贡献和收益分配是否有可以量化的方法呢?

    Shapley方法就是这样一种方法:Shapley值:单个成员所得与自己的贡献相等。

    基于Shap值的模型解释是一种和模型无关的方法。如上图,模型预测和Shap值解释是两个并行流程,Shap对模型预测的结果进行解释。NIPS 论文地址:A Unified Approach to Interpreting Model Predictions,也可以参考这篇博客:One Feature Attribution Method to (Supposedly) Rule Them All: Shapley Values。

    原理:一个特征的shapley value是该特征在所有的特征序列中的平均边际贡献。

    优点:

    • 解决了多重共线性问题;

    • 不仅考虑单个变量的影响,而且考虑变量组的影响,变量之间可能存在协同效应;

    缺点:计算效率低。

    适用范围:

    • 计算个体的特征shapley value;

    • 所有个体的每个特征的shapley value的绝对值求和或求平均即为整体的特征重要性;

    Shap方法的两大特性

    • 特征归因(收益)一致性:

      定义

    • 模型改变(A->B),特征x的贡献不递减(增加或者保持现状),则归因(收益)也不递减;

      特点

    • 特征作用越大(小),重要度越高(低),和模型变化无关;

      全局特征一致性

    • mean(|Tree SHAP|): Shap值;

    • Gain : 特征用于划分时所带来的训练损失减益的平均值;

    • Split Count: 根据特征用于划分的次数计算重要性;

    • Permutation: 将特征的值随机排列,用排列前后的模型误差来计算重要性;

      局部样本(Fever=yes,cough=yes的样本)一致性

    • Saabas[5] : 树创建完成后,根据样本预测值,将父节点和子节点value的差异,作为父节点的特征重要性;

    • Tree SHAP : 基于Shap值矩阵(样本数*特征数),计算出Fever和Cough的重要性;

    • 特征归因(收益)可加性:

      解释性方法如果具有特征归因可加性,特征重要性和模型预测值可以通过特征贡献的线性组合来表示。简单模型最好的解释是它本身;复杂模型,直接进行解释并不容易,需要通过代理模型来解释。接下来引入代理模型(解释模型)来描述特征归因可加性。

    树模型Shap值的解

    • N为全体特征集合,S为N的一个排列子集(顺序相关)

    • 求和第一项:排列数

    • 求和第二项:对于任意子集S,特征i的贡献

    • 特征i的shap值可以理解为i的贡献归因

    详细内容参考论文。

    用Shap值识别特征交叉

    Shap方法计算两两特征交叉影响:

    通俗理解:交叉影响=两个人合作贡献增益,减去各自单干的贡献;

    单个特征的贡献

    Shap方法计算单个特征的贡献(剔除交叉影响):

    通俗理解:个人影响=个人合作贡献,减去其它N-1个人的贡献;下面还是以收入水平数据集进行案例分析:
    row_to_show = 5
    data_for_prediction = X_test.iloc[row_to_show]  # use 5 row of data here. Could use multiple rows if desired
    data_for_prediction_array = data_for_prediction.values.reshape(1, -1)

    # 计算model的shap值
    explainer = shap.TreeExplainer(model)
    # 计算样本数据的shap值
    shap_values = explainer.shap_values(data_for_prediction)

    shap.initjs()
    shap.force_plot(explainer.expected_value[1], shap_values[1], data_for_prediction)

    图形解释

    • Base value :模型在数据集上的输出均值:-0.1524

    • Output value:模型在单个样本的输出值:0.68

    • 起正向作用的特征:marital_status2、occupation3

    • 起负向作用的特征:capital_gain、education_num

    特征解释

    • 解释Output value(单个样本)和Base value(全体样本Shap平均值)的差异,以及差异是由哪些特征造成的

    • 红色是起正向作用的特征,蓝色是起负向作用的特征

    shap_values_b = explainer.shap_values(X_test)
    shap.force_plot(explainer.expected_value[0], shap_values_b[0], X_test, link="logit")

    特征解释

    • 解释Output value和Base value的差异,以及差异是由哪些特征造成的

    Summary Plots:

    shap_values = explainer.shap_values(X_test)
    shap.summary_plot(shap_values[1], X_test)


    图形解释

    • 每个点是一个样本(人),图片中包含所有样本

    • X轴:样本按Shap值排序-

    • Y轴:特征按Shap值排序

    • 颜色:特征的数值越大,越红

    特征解释

    • martial_status2这个特征最重要,且值越大,收入会相对更高,到达一定峰值,会明显下降

    • 年龄也是影响结果的重要特征,年龄小收入普遍低,但年龄到达一定程度,并不会增加收入,存在年龄小,收入高的人群。

    • 收入水平和capital_gain大致呈正相关。

    shap.summary_plot(shap_values[1],X_test, plot_type="bar")

    上图是特征重要性图谱,由上向下重要性依次减弱。

    shap_values = explainer.shap_values(df)
    shap.dependence_plot('age', shap_values[1], df, interaction_index="capital_gain")

    图形解释:

    • X轴:age

    • Y轴(左):一个样本的age对应的Shap值

    • 颜色:capital_gain越大越红

    特征解释:

    • 排除所有特征的影响,描述age和capital_gain的关系。

    • 年龄大的人更趋向于有大的资本收益,小部分年轻人有大的资本收益。


    RETAIN

    概述

    论文使用称为RETAIN的建模策略解决了这个限制,这是一种两级神经网络顺序数据的注意模型,提供对预测结果的详细解释保持与RNN相当的预测精度。为此,RETAIN依赖于关注机制被建模以表示在遭遇期间医生的行为。一个区别RETAIN的功能(参见图1)是利用注意力生成来利用序列信息机制,同时学习可解释的表示。并模仿医生的行为,RETAIN以相反的时间顺序检查患者的过去访问,从而促进更稳定的注意后代。因此,RETAIN会识别最有意义的访问次数并量化访问量有助于预测的功能。

    模型使用两套权重,一套是visit-level attention ,另外一套是variable-level attention。使用两个RNN网络分别产生。

    Step1:使用线性embedding
    Step2:产生visit-level attention。其中输入RNN中的数据采用时间逆序输入。对于稀疏的attention,使用Sparsemax而不是Softmax。
    Step3:产生variable-levelattention,其中输入RNN中的数据采用时间逆序输入。
    Step4:根据以上两步生成的attentionweight,生成context vector。Ci表示病人第i次visit。
    Step5:根据Context Vector生成预测结果。

    LRP

    逐层相关性传播(LRP)是一种通过在神经网络中运行反向传递来识别重要像素的方法。向后传递是保守的相关再分配过程,其中对较高层贡献最大的神经元从其获得最大相关性。LRP程序如下图所示。

    该方法可以在大多数编程语言中容易地实现并且集成到现有的神经网络框架中。当应用于深度ReLU网络时,LRP可以被理解为预测的深度泰勒分解。

    这里有如何实现LRP用于解释深度模型的代码教程,有兴趣可以动手实现,用于解释自己的深度模型。

    参考文献

    • Interpretable Machine Learning

      https://christophm.github.io/interpretable-ml-book/pdp.html

    • Partial dependence ——集成树的可解析性

      https://zhuanlan.zhihu.com/p/40356430

    • Machine Learning for Insights Challenge

      https://zhuanlan.zhihu.com/p/45898896

    • https://yyqing.me/post/2018/2018-09-25-kaggle-model-insights

    • http://rstudio-pubs-static.s3.amazonaws.com/283647_c3ab1ccee95a403ebe3d276599a85ab8.html

    • 《通向人类可理解、可解释的人工智能》

    • https://github.com/lopusz/awesome-interpretable-machine-learning

    • https://github.com/jphall663/awesome-machine-learning-interpretability

    • https://github.com/Henrilin28/awesome-Interpretable-ML

    • http://xiangruix.com/2018/07/31/lime/

    • https://www.jianshu.com/p/b52efa66154e

    • https://zhuanlan.zhihu.com/p/32891505

    • https://suensummit.github.io/intro-lime/#1

    • https://www.oreilly.com/learning/introduction-to-local-interpretable-model-agnostic-explanations-lime

    • https://github.com/slundberg/shap

    • http://km.oa.com/group/22630/articles/show/380452?kmref=search&from_page=1&no=1

    感谢 zizhewang(汪子哲) 同学协助整理本文,汇总对机器学习模型可解释性相关资料。

    推荐原创干货阅读:  

     聊聊近状, 唠十块钱的

    【Deep Learning】详细解读LSTM与GRU单元的各个公式和区别

    【手把手AI项目】一、安装win10+linux-Ubuntu16.04的双系统(全网最详细)

    【Deep Learning】为什么卷积神经网络中的“卷积”不是卷积运算?

    【TOOLS】Pandas如何进行内存优化和数据加速读取(附代码详解)

    【TOOLS】python3利用SMTP进行邮件Email自主发送

    【手把手AI项目】七、MobileNetSSD通过Ncnn前向推理框架在PC端的使用

    公众号:AI蜗牛车

    保持谦逊、保持自律、保持进步

    点个在看,么么哒!

    展开全文
  • 深度学习模型测试方法总结

    千次阅读 2019-12-17 18:06:26
    深度学习模型测试的方法和标准整理 深度学习模型测试,是指系统性地对深度学习算法的可靠性、可移植性、效率进行评估。简单来说,算法测试主要做的是三件事:收集测试数据,思考需要什么样的测试数据以及数据的标注...

    深度学习模型测试的方法和标准整理

    深度学习模型测试,是指系统性地对深度学习算法的可靠性、可移植性、效率进行评估。简单来说,算法测试主要做的是三件事:收集测试数据,思考需要什么样的测试数据以及数据的标注;跑测试数据,编写测试脚本批量运行;查看数据结果,统计正确和错误的个数,计算准确率等相关指标,查看错误数据中是否有共同的特征。

    1相关术语
    1.1Accuracy(准确率)、Precision(精确率)、Recall(召回率)

    对于二值分类器,或者说分类算法,如分类猫和狗,分类性别男和女。TP、FP、TN、FN,即:True Positive, False Positive, True Negative, False Negative。预测值与真实值相同,记为T(True);预测值与真实值相反,记为F(False);预测值为正例,记为P(Positive);预测值为反例,记为N(Negative)。具体组合见图1.1的分类结果混淆矩阵:

                                              

                                                           图1.1分类结果混淆矩阵

    根据分类结果混淆矩阵可得:

    1. 准确率:Accuracy = (TP+TN)/(P+N) ,预测正确的样本(TP和TN)在所有样本中占的比例。在各类样本不均衡时,准确率不能很好表示模型性能,因为会出现大类准确率高,而少数类准确率低。这样情况下,需要对每一类样本单独观察。
    2. 精确率(查准率): Precision = TP/(TP+FP),即所有被预测为正例的样本中,多少比例是真的正例。
    3. 召回率(查全率): Recall = TP/(TP+FN),即所有真的正例中,多少比例被模型预测出来了。

    不同的问题中,有的侧重精确率,有的侧重召回率。对于推荐系统,更侧重于精确率。即推荐的结果中,用户真正感兴趣的比例。因为给用户展示的窗口有限,必须尽可能的给用户展示他真实感兴趣的结果。对于医学诊断系统,更侧重与召回率。即疾病被发现的比例。因为疾病如果被漏诊,则很可能导致病情恶化。精确率和召回率是一对矛盾的度量。一般来说精确率高时召回率往往偏低,而召回率高时精确率往往偏低。

    1.2 F1 Score

    精确率和召回率的调和平均。F1认为精确率和召回率同等重要。计算公式为:

                                          

                                                                  图1.2   F1 Score 计算公式

    1.3 可靠性 (reliability)、可靠性评估(reliability assessment)

    可靠性指在规定的条件下和规定的时间内,深度学习算法正确完成预期功能,且不引起系统失效或异常的能

    力。

    可靠性评估指确定现有深度学习算法的可靠性所达到的预期水平的过程。

    1.4 响应时间 response time

    在给定的软硬件环境下,深度学习算法对给定的数据进行运算并获得结果所需要的时间。

     

    2深度学习算法的可靠性指标体系

    基于深度学习算法可靠性的内外部影响考虑,结合用户实际的应用场景,深度学习算法的可靠性评估指标体系如图2.1所示,包含7个一级指标和20个二级指标。在实施评估过程中,应根据可靠性目标选取相应指标。

                                                        

     

     

                                                                        图2.1 深度学习算法的可靠性评估指标体系

    2.1 算法功能实现的正确性

    用于评估深度学习算法实现的功能是否满足要求,应包括但不限于下列内容:

    a) 任务指标:用户可以根据实际的应用场景选择任务相关的基本指标,用于评估算法完成功能的能力;

    示例:分类任务中的查准率、查全率、准确率等;语音识别任务中的词错误率、句错误率等;目标检测任务中的平均正确率等;算法在使用中错误偏差程度带来的影响等。

    b) 响应时间。

    2.2 代码实现的正确性

    用于评估代码实现功能的正确性,应包括下列内容:

    a) 代码规范性:代码的声明定义、版面书写、指针使用、分支控制、跳转控制、运算处理、函数

    调用、语句使用、循环控制、类型转换、初始化、比较判断和变量使用等是否符合相关标准或

    规范中的编程要求;

    b) 代码漏洞:指代码中是否存在漏洞。

    示例:栈溢出漏洞、堆栈溢出漏洞、整数溢出、数组越界、缓冲区溢出等。

    2.3 目标函数的影响

    用于评估计算预测结果与真实结果之间的误差,应包括下列内容:

    a) 优化目标数量:包括优化目标不足或过多。优化目标过少容易造成模型的适应性过强,优化目标过多容易造成模型收敛困难;

    b) 拟合程度:包括过拟合或欠拟合。过拟合是指模型对训练数据过度适应,通常由于模型过度地学习训练数据中的细节和噪声,从而导致模型在训练数据上表现很好,而在测试数据上表现很差,也即模型的泛化性能变差。欠拟合是指模型对训练数据不能很好地拟合,通常由于模型过于简单造成,需要调整算法使得模型表达能力更强。

    2.4 训练数据集的影响

    用于评估训练数据集带来的影响,应包括下列内容:

    a) 数据集均衡性:指数据集包含的各种类别的样本数量一致程度和数据集样本分布的偏差程度;

    b) 数据集规模:通常用样本数量来衡量,大规模数据集通常具有更好的样本多样性;

    c) 数据集标注质量:指数据集标注信息是否完备并准确无误;

    d) 数据集污染情况:指数据集被人为添加的恶意数据的程度。

    2.5 对抗性样本的影响

    用于评估对抗性样本对深度学习算法的影响,应包括下列内容:

    a) 白盒方式生成的样本:指目标模型已知的情况下,利用梯度下降等方式生成对抗性样本;

    b) 黑盒方式生成的样本:指目标模型未知的情况下,利用一个替代模型进行模型估计,针对替代模型使用白盒方式生成对抗性样本;

    c) 指定目标生成的样本:指利用已有数据集中的样本,通过指定样本的方式生成对抗性样本;

    d) 不指定目标生成的样本:指利用已有数据集中的样本,通过不指定样本(或使用全部样本)的方式生成对抗性样本。

    2.6 软硬件平台依赖的影响

    用于评估运行深度学习算法的软硬件平台对可靠性的影响,应包括下列内容:

    a) 深度学习框架差异:指不同的深度学习框架在其所支持的编程语言、模型设计、接口设计、分布式性能等方面的差异对深度学习算法可靠性的影响;

    b) 操作系统差异:指操作系统的用户可操作性、设备独立性、可移植性、系统安全性等方面的差异对深度学习算法可靠性的影响;

    c) 硬件架构差异:指不同的硬件架构及其计算能力、处理精度等方面的差异对深度学习算法可靠性的影响。

    2.7 环境数据的影响

    用于评估实际运行环境对算法的影响,应包括下列内容:

    a) 干扰数据:指由于环境的复杂性所产生的非预期的真实数据,可能影响算法的可靠性;

    b) 数据集分布迁移:算法通常假设训练数据样本和真实数据样本服从相同分布,但在算法实际使用中,数据集分布可能发生迁移,即真实数据集分布与训练数据集分布之间存在差异性;

    c) 野值数据:指一些极端的观察值。在一组数据中可能有少数数据与其余的数据差别比较大,也称为异常观察值。

     

    3执行测试

    该部分主要考虑如何具体进行测试,

    3.1 测试用例的选择

    选择测试用例时,要考虑以下问题:

    1. 项目落地实际使用场景,根据场景思考真实的数据情况,倒推进行测试数据收集。
    2. 模型的训练数据有多少,训练数据的分布情况,训练数据的标注是否准确。
    3. 模型的输入和输出,图片,csv还是文本,语音等等。
    4. 算法的实现方式。
    5. 选择模型评价指标。
    6. 评价指标的上线要求。
    7. 项目的流程,数据流。
    8. 算法外的业务逻辑。

    3.2 测试中可能出现的一些问题

    实际项目中不仅是有算法相关代码还会有工程代码。如模型加载,入参的处理,异常判断,数据库相关,日志相关等等。所以项目测试,还会有工程代码功能的测试。

    举例一些常见的:

    1,有的依赖包在不同环境版本不一致,导致结果不一样。

    2,科学计算错误

    3,工程代码问题

    4,模型效果差

    科学计算即数值计算,是指应用计算机处理科学研究和工程技术中所遇到的数学计算问题。比如图像处理、机器学习、深度学习等很多领域都会用到科学计算。

    一张图片输入,卷积神经网络顺序通常为:输入-卷积层-池化层-全连接层-输出。深度学习预测的过程就有大量的数值计算。可能就会碰到一些边界数值情况,导致计算出错。

    3.3 模型结果评估

    3.3.1单个标签分类的问题

    对于单个标签分类的问题,评价指标主要有Accuracy,Precision,Recall,F-score,PR曲线,ROC和AUC。

    如果对于每一类,若想知道类别之间相互误分的情况,查看是否有特定的类别之间相互混淆,就可以用混淆矩阵画出分类的详细预测结果。对于包含多个类别的任务,混淆矩阵很清晰的反映出各类别之间的错分概率,如下图:

                       

     

                             

                                                                           图3.1 分类结果混淆矩阵

    上图表述的是一个包含20个类别的分类任务,混淆矩阵为20*20的矩阵,其中第i行第j列,表示第i类目标被分类为第j类的概率,越好的分类器对角线上的值更大,其他地方应该越小。

     

    3.3.2 ROC曲线与AUC指标

    以上的准确率Accuracy,精确度Precision,召回率Recall,F1 score,混淆矩阵都只是一个单一的数值指标,如果想观察分类算法在不同的参数下的表现情况,就可以使用一条曲线,即ROC曲线,全称为receiver operating characteristic。

    ROC曲线可以用于评价一个分类器在不同阈值下的表现情况。在ROC曲线中,每个点的横坐标是false positive rate(FPR),纵坐标是true positive rate(TPR),描绘了分类器在True Positive和False Positive间的平衡,两个指标的计算如下:

    TPR=TP/(TP+FN),代表分类器预测的正类中实际正实例占所有正实例的比例。

    FPR=FP/(FP+TN),代表分类器预测的正类中实际负实例占所有负实例的比例,FPR越大,预测正类中实际负类越多。

    ROC曲线通常如下

                                             

     

                                                                                     图 3.2 ROC曲线

     

    3.3.3 图像生成评价指标

    当需要评估一个生成模型的性能的时候,有2个最重要的衡量指标。

    (1) 确定性:生成模型生成的样本一定属于特定的类别,也就是真实的图像,而且必须要是所训练的图片集,不能用人脸图像训练得到了手写数字。

    (2) 多样性:样本应该各式各样,如果用mnist进行训练,在没有条件限制的条件下,应该生成0,1,2,3…,而不是都是0,生成的各个数字也应该具有不同的笔触,大小等。除此之外,还会考虑分辨率等。

     

    4参考资料

    1、也许这有你想知道的人工智能 (AI) 测试.https://blog.csdn.net/lhh08hasee/article/details/100534862

    2、《人工智能深度学习算法评估规范》,中国人工智能开源软件发展联盟标准http://www.cesi.cn/images/editor/20180703/20180703174359294.pdf

    3、深度学习模型评估指标,https://www.cnblogs.com/tectal/p/10870064.html

    4、模型评估与调优,https://machine-learning-from-scratch.readthedocs.io/zh_CN/latest/%E6%A8%A1%E5%9E%8B%E8%AF%84%E4%BC%B0%E4%B8%8E%E6%A8%A1%E5%9E%8B%E8%B0%83%E4%BC%98.html#header-n408

    5、AI模型的黑盒测试与白盒测试实践,http://mini.eastday.com/mobile/190924064408433.html

     

    展开全文
  • 深度学习模型提升性能的策略

    万次阅读 2020-04-28 14:12:45
    缺乏数据的问题是,我们的深度学习模型可能无法从数据中学习模式或功能,因此它可能无法在未看到的数据上提供良好的性能。 我们可以利用数据增强技术来代替花费数天时间来收集数据。 数据增强是在不实际收集...

    角度1

    缺乏可用于训练的数据

    一般来说,数据越多,模型的性能就越好。缺乏数据的问题是,我们的深度学习模型可能无法从数据中学习模式或功能,因此它可能无法在未看到的数据上提供良好的性能。

    我们可以利用数据增强技术来代替花费数天时间来收集数据。

    数据增强是在不实际收集新数据的情况下,生成新数据或增加数据以训练模型的过程。

    图像数据有多种数据增强技术,常用的增强技术有旋转、剪切、翻转等。

    过拟合

    当一个模型在训练集上执行得非常好,但是在验证集(或不可见的数据)上性能下降时,就会被认为是过拟合。

    在这里插入图片描述
    上图中蓝色标记的部分是过拟合模型,因为训练误差非常小并且测试误差非常高。过拟合的原因是该模型甚至从训练数据中学习了不必要的信息,因此它在训练集上的表现非常好。
    但是,当引入新数据时,它将无法执行。我们可以向模型的架构中引入Dropout,以解决过拟合的问题。
    使用Dropout,我们随机关闭神经网络的某些神经元。假设我们在最初有20个神经元的图层上添加了概率为0.5的Dropout层,因此,这20个神经元中的10个将被抑制,我们最终得到了一个不太复杂的体系结构。
    因此,该模型将不会学习过于复杂的模式,可以避免过拟合。

    欠拟合

    欠拟合是指模型无法从训练数据本身中学习模式,因此训练集上的性能较低。

    为了克服欠拟合的问题,你可以尝试以下解决方案:

    • 增加训练数据
    • 制作一个复杂的模型
    • 增加训练的epoch
      对于我们的问题,欠拟合不是问题,因此,我们将继续研究提高深度学习模型性能的下一种方法。

    训练时间长

    有些情况下,你可能会发现你的神经网络需要花很多时间来收敛。这背后的主要原因是输入到神经网络层的分布发生了变化。
    在训练过程中,神经网络各层的权值发生变化,激活也随之变化。现在,这些激活是下一层的输入,因此每一次连续的迭代都会改变分布。
    由于这种分布的变化,每一层都必须适应不断变化的输入—这就是为什么训练时间增加的原因。
    为了克服这一问题,我们可以应用批处理标准化(batch normalization),其中我们正常化的激活隐藏层,并试图作出相同的分布。

    角度2

    从数据上提升性能

    1. 收集更多的数据
    2. 产生更多的数据
    3. 对数据做缩放
    4. 对数据做变换
    5. 特征选择
    6. 重新定义问题
      1)收集更多的数据
      你还能收集到更多的训练数据吗?你的模型的质量往往取决于你的训练数据的质量。你需要确保使用的数据是针对问题最有效的数据。你还希望数据尽可能多。深度学习和其它现代的非线性机器学习模型在大数据集上的效果更好,尤其是深度学习。这也是深度学习方法令人兴奋的主要原因之一。

    在这里插入图片描述
    数据集压倒算法
    多数情况下,数据集越多越好

    2)产生更多的数据
    深度学习算法往往在数据量大的时候效果好。我们在上一节已经提到过这一点。如果由于某些原因你得不到更多的数据,也可以制造一些数据。

    • 如果你的数据是数值型的向量,那么随机生成已有向量的变形向量。
    • 如果你的数据是图像,用已有的图像随机生成相似图像。
    • 如果你的数据是文本,做法你懂得……
      这类做法通常被称为数据扩展或是数据生成。你可以使用生成模型,也可以用一些简单的小技巧。举个例子,若是用图像数据,简单地随机选择和平移已有的图像就能取得很大的提升。它能提升模型的泛化能力,如果新的数据中包含这类变换就能得到很好的处理。有时候是往数据中增加噪声,这相当于是一种规则方法,避免过拟合训练数据

    深度学习中的图像数据扩充
    训练有噪声的数据

    3)对数据做缩放此方法简单有效。
    使用神经网络模型的一条经验法宝就是:将数据缩放到激活函数的阈值范围。

    • 如果你使用sigmoid激活函数,将数据缩放到0-1之间。
    • 如果选用tanh激活函数,将值域控制在-1~1之间。输入、输出数据都经过同样的变换。比如,如果在输出层有一个sigmoid函数将输出值转换为二值数据,则将输出的y归一化为二进制。
    • 如果选用的是softmax函数,对y进行归一化还是有效的。我还建议你将训练数据扩展生成多个不同的版本:
      · 归一化到0 ~ 1
      · 归一化到-1 ~ 1
      · 标准化

    然后在每个数据集上测试模型的性能,选用最好的一组生成数据。如果更换了激活函数,最好重复做一次这个小实验。在模型中不适合计算大的数值。此外,还有许多其它方法来压缩模型中的数据,比如对权重和激活值做归一。

    输入数据标准化?
    Scikt-Learn准备输入数据

    4) 对数据做变换
    与上一节的方法相关,但是需要更多的工作量。你必须真正了解所用到的数据。数据可视化,然后挑出异常值。先猜测每一列数据的分布

    • 这一列数据是不是倾斜的高斯分布,若是如此,尝试用Box-Cox方法纠正倾斜
    • 这一列数据是不是指数分布,若是如此,则进行对数变换
    • 这一列数据是不是存在某些特性,但是难以直观地发现,尝试一下对数据平方或者开方
    • 是否可以将特征离散化,以便更好地强调一些特征

    凭你的直觉,尝试几种方法

    • 是否可以用投影的方法对数据预处理,比如PCA?
    • 是否可以将多个属性合并为单个值?
    • 是否可以发掘某个新的属性,用布尔值表示?
    • 是否可以在时间尺度或是其它维度上有些新发现?

    神经网络有特征学习的功能,它们能够完成这些事情。不过你若是可以将问题的结构更好地呈现出来,网络模型学习的速度就会更快。在训练集上快速尝试各种变换方法,看看哪些方法有些,而哪些不起作用。
    如何定义机器学习问题
    特征挖取工程
    如何用Scikit-Learn准备输入的数据

    5) 特征选择
    神经网络受不相关数据的影响很小。它们会对此赋予一个趋近于0的权重,几乎忽略此特征对预测值的贡献。你是否可以移除训练数据的某些属性呢?我们有许多的特征选择方法和特征重要性方法来鉴别哪些特征可以保留,哪些特征需要移除。动手试一试,试一试所有的方法。如果你的时间充裕,我还是建议在相同的神经网络模型上选择尝试多个方法,看看它们的效果分别如何。

    • 也许用更少的特征也能得到同样的、甚至更好的效果。
    • 也许所有的特征选择方法都选择抛弃同一部分特征属性。那么就真应该好好审视这些无用的特征。
    • 也许选出的这部分特征给你带来了新的启发,构建出更多的新特征。

    特征选择入门介绍
    基于Pytrhon的机器学习中的特征选择问题

    6)问题重构

    在回到你问题的定义上来。你所收集到的这些观测数据是描述问题的唯一途径吗也许还有其它的途径。也许其它途径能更清晰地将问题的结构暴露出来。我自己非常喜欢这种练习,因为它强迫我们拓宽思路。很难做好。尤其是当你已经投入大量的时间、精力、金钱在现有的方法上。即使你列举了3 ~ 5种不同的方式,至少你对最后所选用的方式有充足的信心。

    • 也许你可以将时间元素融入到一个窗口之中。
    • 也许你的分类问题可以转化为回归问题,反之亦然。也许可以把二值类型的输出转化为softmax的输出
    • 也许你可以对子问题建模。

    深入思考问题是一个好习惯,最好在选择工具下手之前先完成上述步骤,以减少无效的精力投入。无论如何,如果你正束手无策,这个简单的连续能让你思如泉涌。另外,你也不必抛弃前期的大量工作。

    如何定义机器学习问题

    从算法上提升性能

    1. 算法的筛选
    2. 从文献中学习
    3. 重采样的方法

    你事先不可能知道哪种算法对你的问题效果最好。如果你已经知道,你可能也就不需要机器学习了。你有哪些证据可以证明现在已经采用的方法是最佳选择呢?我们来想想这个难题。

    当在所有可能出现的问题上进行效果评测时,没有哪一项单独的算法效果会好于其它算法。所有的算法都是平等的。这就是天下没有免费的午餐理论的要点。

    也许你选择的算法并不是最适合你的问题。现在,我们不指望解决所有的问题,但当前的热门算法也许并不适合你的数据集。我的建议是先收集证据,先假设有其它的合适算法适用于你的问题。

    筛选一些常用的算法,挑出其中适用的几个。

    • 尝试一些线性算法,比如逻辑回归和线性判别分析
    • 尝试一些树模型,比如CART、随机森林和梯度提升
    • 尝试SVM和kNN等算法
    • 尝试其它的神经网络模型,比如LVQ、MLP、CNN、LSTM等等

    采纳效果较好的几种方法,然后精细调解参数和数据来进一步提升效果。将你所选用的深度学习方法与上述这些方法比较,看看是否能击败他们?也许你可以放弃深度学习模型转而选择更简单模型,训练的速度也会更快,而且模型易于理解。

    一种数据驱动的机器学习方法
    面对机器学习问题为何需要筛选算法
    用scikit-learn筛选机器学习的分类算法

    2) 从文献中学习
    从文献中“窃取”思路是一条捷径。其它人是否已经做过和你类似的问题,他们使用的是什么方法。阅读论文、书籍、问答网站、教程以及Google给你提供的一切信息。记下所有的思路,然后沿着这些方向继续探索。这并不是重复研究,这是帮助你发现新的思路。
    优先选择已经发表的论文

    3) 重采样的方法

    你必须明白自己模型的效果如何。你估计的模型效果是否可靠呢?深度学习模型的训练速度很慢。

    • 这就意味着我们不能用标准的黄金法则来评判模型的效果,比如k折交叉验证。
    • 也许你只是简单地把数据分为训练集和测试集。如果是这样,就需要保证切分后的数据分布保持不变。单变量统计和数据可视化是不错的方法。
    • 也许你们可以扩展硬件来提升效果。举个例子,如果你有一个集群或是AWS的账号,我们可以并行训练n个模型,然后选用它们的均值和方差来获取更稳定的效果。
    • 也许你可以选择一部分数据做交叉验证(对于early stopping非常有效)。
    • 也许你可以完全独立地保留一部分数据用于模型的验证。另一方面,也可以让数据集变得更小,采用更强的重采样方法。
    • 也许你会看到在采样后的数据集上训练得到的模型效果与在全体数据集上训练得到的效果有很强的相关性。那么,你就可以用小数据集进行模型的选择,然后把最终选定的方法应用于全体数据集上。
    • 也许你可以任意限制数据集的规模,采样一部分数据,用它们完成所有的训练任务。

    用Keras评估深度学习模型的效果
    用重采样的方法评估机器学习算法的效果

    从算法调优上提升性能

    你通过算法筛选往往总能找出一到两个效果不错的算法。但想要达到这些算法的最佳状态需要耗费数日、数周甚至数月。下面是一些想法,在调参时能有助于提升算法的性能。

    1. 模型可诊断性
    2. 权重的初始化
    3. 学习率
    4. 激活函数
    5. 网络结构
    6. batch和epoch
    7. 正则项
    8. 优化目标
    9. 提早结束训练

    你可能需要指定参数来多次(3-10次甚至更多)训练模型,以得到预计效果最好的一组参数。对每个参数都要不断的尝试。有一篇关于超参数最优化的优质博客:如何用Keras网格搜索深度学习模型的超参数

    1) 可诊断性
    只有知道为何模型的性能不再有提升了,才能达到最好的效果。是因为模型过拟合呢,还是欠拟合呢?千万牢记这个问题。千万

    模型总是处于这两种状态之间,只是程度不同罢了。一种快速查看模型性能的方法就是每一步计算模型在训练集和验证集上的表现,将结果绘制成图表。
    在这里插入图片描述

    在训练集和验证集上测试模型的准确率

    • 如果训练集的效果好于验证集,说明可能存在过拟合的现象,试一试增加正则项。
    • 如果训练集和验证集的准确率都很低,说明可能存在欠拟合,你可以继续提升模型的能力,延长训练步骤。
    • 如果训练集和验证集的曲线有一个焦点,可能需要用到early stopping的技巧了。经常绘制类似的图表,深入研究并比较不同的方法,以提高模型的性能。

    这些图表也许是你最有价值的诊断工具。
    另一种有效的诊断方法是研究模型正确预测或是错误预测的样本。在某些场景下,这种方法能给你提供一些思路。

    2) 权重的初始化
    有一条经验规则:**用小的随机数初始化权重。**事实上,这可能已经足够了。但是这是你网络模型的最佳选择吗?不同的激活函数也可以有不同的应对策略,但我不记得在实践中存在什么显著的差异。保持你的模型结构不变,试一试不同的初始化策略。记住,权重值就是你模型需要训练的参数。几组不同的权重值都能取得不错的效果,但你想得到更好的效果。

    • 尝试所有的初始化方法,找出最好的一组初始化值。
    • 试一试用非监督式方法预学习,比如自动编码机。
    • 尝试用一组现有的模型权重参数,然后重新训练输入和输出层(迁移学习)。

    记住,修改权重初始化值的方法与修改激活函数或者目标函数的效果相当。
    深度网络模型的初始化

    3) 学习率调节
    学习率也能带来效果提升。这里也有一些探索的思路:

    • 尝试非常大、非常小的学习率。
    • 根据参考文献,在常规值附近用网格化搜索。· 尝试使用逐步减小的学习率。
    • 尝试每隔固定训练步骤衰减的学习率。
    • 尝试增加一个向量值,然后用网格搜索。

    大的网络模型需要更多的训练步骤,反之亦然。如果你添加了更多的神经节点和网络层,请加大学习率。学习率与训练步骤、batch大小和优化方法都有耦合关系。
    使用Keras对深度学习模型进行学习率调节
    反向传播算法该选用什么学习率?

    4) 激活函数
    也许你应该选用ReLU激活函数。仅仅因为它们的效果更好。

    在ReLU之前流行sigmoid和tanh,然后是输出层的softmax、线性和sigmoid函数。除此之外,我不建议尝试其它的选择。这三种函数都试一试,记得把输入数据归一化到它们的值域范围。

    显然,你需要根据输出内容的形式选择转移函数。比方说,将二值分类的sigmoid函数改为回归问题的线性函数,然后对输出值进行再处理。同时,可能需要调整合适的损失函数。在数据转换章节去寻找更多的思路吧。
    为何使用激活函数

    5) 网络拓扑结构
    调整网络的拓扑结构也会有一些帮助。
    你需要设计多少个节点,需要几层网络呢?别打听了,鬼知道是多少。你必须自己找到一组合理的参数配置。

    • 试一试加一层有许多节点的隐藏层(拓宽)。
    • 试一试一个深层的神经网络,每层节点较少(纵深)。
    • 尝试将上面两种组合。
    • 尝试模仿近期发表的问题类似的论文。
    • 尝试拓扑模式。

    这是一个难题。越大的网络模型有越强的表达能力,也许你就需要这样一个。

    更多层的结构提供了抽象特征的更多结构化组合的可能,也许你也需要这样一个网络。后期的网络模型需要更多的训练过程,需要不断地调节训练步长和学习率。

    我的网络模型该设计几层呢
    我的网络模型该设计几个节点呢

    6) batch和epoch
    batch的大小决定了梯度值,以及权重更新的频率。一个epoch指的是训练集的所有样本都参与了一轮训练,以batch为序。你尝试过不同的batch大小和epoch的次数吗?在前文中,我们已经讨论了学习率、网络大小和epoch次数的关系。深度学习模型常用小的batch和大的epoch以及反复多次的训练。这或许对你的问题会有帮助。

    • 尝试将batch大小设置为全体训练集的大小(batch learning)。‘
    • 尝试将batch大小设置为1(online learning)。
    • 用网格搜索尝试不同大小的mini-batch(8,16,32,…)
    • 尝试再训练几轮epoch,然后继续训练很多轮epoch。
    • 尝试设置一个近似于无限大的epoch次数,然后快照一些中间结果,寻找效果最好的模型。有些模型结构对batch的大小很敏感。我觉得多层感知器对batch的大小很不敏感,而LSTM和CNN则非常敏感,但这都是仁者见仁。
      什么是批量学习、增量学习和在线学习?

    7) 正则项
    正则化是克服训练数据过拟合的好方法。最近热门的正则化方法是dropout,你试过吗?Dropout方法在训练过程中随机地略过一些神经节点,强制让同一层的其它节点接管。简单却有效的方法。

    • 权重衰减来惩罚大的权重值。
    • 激活限制来惩罚大的激活函数值。尝试用各种惩罚措施和惩罚项进行实验,比如L1、L2和两者之和。

    使用Keras对深度学习模型做dropout正则化
    权值衰减

    8) 优化方法和损失函数
    以往主要的求解方法是随机梯度下降,然而现在有许许多多的优化器。你尝试过不同的优化策略吗?随机梯度下降是默认的方法。先用它得到一个结果,然后调节不同的学习率、动量值进行优化。许多更高级的优化方法都用到更多的参数,结构更复杂,收敛速度更快。这取决于你的问题,各有利弊吧。

    为了压榨现有方法的更多潜力,你真的需要深入钻研每个参数,然后用网格搜索法测试不同的取值。过程很艰辛,很花时间,但值得去尝试。

    我发现更新/更流行的方法收敛速度更快,能够快速了解某个网络拓扑的潜力,例如:ADAM RMSprop

    你也可以探索其它的优化算法,例如更传统的算法(Levenberg-Marquardt)和比较新的算法(基因算法)。其它方法能给SGD创造好的开端,便于后续调优。待优化的损失函数则与你需要解决的问题更相关。

    不过,也有一些常用的伎俩(比如回归问题常用MSE和MAE),换个损失函数有时也会带来意外收获。同样,这可能也与你输入数据的尺度以及所使用的激活函数相关。

    相关阅读:
    1)梯度下降优化算法概览
    2)什么是共轭梯度和Levenberg-Marquardt? 3)深度学习的优化方法,2011

    9) Early Stopping
    你可以在模型性能开始下降的时候停止训练。这帮我们节省了大量时间,也许因此就能使用更精细的重采样方法来评价模型了。early stopping也是防止数据过拟合的一种正则化方法,需要你在每轮训练结束后观察模型在训练集和验证集上的效果。

    一旦模型在验证集上的效果下降了,则可以停止训练。你也可以设置检查点,保存当时的状态,然后模型可以继续学习。

    相关阅读:
    1)如何在Keras给深度学习模型设置check-point
    2)什么是early stopping?

    从模型融合上提升性能

    你可以将多个模型的预测结果融合。继模型调优之后,这是另一个大的提升领域。事实上,往往将几个效果还可以的模型的预测结果融合,取得的效果要比多个精细调优的模型分别预测的效果好。我们来看一下模型融合的三个主要方向:

    1. 模型融合
    2. 视角融合
    3. stacking

    1) 模型融合
    不必挑选出一个模型,而是将它们集成。如果你训练了多个深度学习模型,每一个的效果都不错,则将它们的预测结果取均值。模型的差异越大,效果越好。举个例子,你可以使用差异很大的网络拓扑和技巧。如果每个模型都独立且有效,那么集成后的结果效果更稳定。相反的,你也可以反过来做实验。每次训练网络模型时,都以不同的方式初始化,最后的权重也收敛到不同的值。多次重复这个过程生成多个网络模型,然后集成这些模型的预测结果。它们的预测结果会高度相关,但对于比较难预测的样本也许会有一点提升。
    相关阅读:
    1) 用scikit-learn集成机器学习算法
    2)如何提升机器学习的效果

    2) 视角融合
    如上一节提到的,以不同的角度来训练模型,或是重新刻画问题。我们的目的还是得到有用的模型,但是方式不同(如不相关的预测结果)。你可以根据上文中提到的方法,对训练数据采取完全不同的缩放和变换技巧。所选用的变化方式和问题的刻画角度差异越大,效果提升的可能性也越大。简单地对预测结果取均值是一个不错的方式。

    3)stacking你还可以学习如何将各个模型的预测结果相融合。这被称作是stacked泛化,或者简称为stacking。通常,可以用简单的线性回归的方式学习各个模型预测值的权重。把各个模型预测结果取均值的方法作为baseline,用带权重的融合作为实验组。Stacked Generalization (Stacking)

    展开全文
  • 最近在一个自然语言处理方面的项目,选用的深度学习模型有两个,一个是CNN+LSTM模型,一个是GRU模型,这两个模型在GPU服务器上训练好了,然后需要使用Java调用这两个模型,CNN+LSTM使用TensorFlow写的,GRU是用Keras...

    写在前面

    最近在一个自然语言处理方面的项目,选用的深度学习模型有两个,一个是CNN+LSTM模型,一个是GRU模型,这两个模型在GPU服务器上训练好了,然后需要使用Java调用这两个模型,CNN+LSTM使用TensorFlow写的,GRU是用Keras写的,所以需要用Java部署TensorFlow和Keras训练好的深度学习模型。关于这方面的内容网上并不是很多,我也是费了很多周折才完成任务的,这里来总结一下具体有哪些方法可以用,这些方法又有哪些缺陷,以供大家学习交流。

    一、使用Java深度学习框架直接部署

    (1)使用TensorFlow Java API部署TensorFlow模型

    如果我们使用的是TensorFlow训练的模型,那么我们就可以直接使用Java中的TensorFlow API调用模型。这里需要注意的是我们得把训练好的模型保存为.pb格式的文件。具体代码如下:

    # constant_graph = graph_util.convert_variables_to_constants(sess, sess.graph_def, output_node_names=["quest_out"])
    # 写入序列化的 PB 文件
    # with tf.gfile.FastGFile('/home/amax/zth/qa/new_model2_cpu.pb', mode='wb') as f:
    #     f.write(constant_graph.SerializeToString())
    

    然后我们需要在Java使用这个保存好的模型,在pom.xml中引入TensorFlow的依赖

    <dependency>
                <groupId>org.tensorflow</groupId>
                <artifactId>tensorflow</artifactId>
                <version>1.11.0</version>
            </dependency>
    
            <!-- https://mvnrepository.com/artifact/org.tensorflow/libtensorflow_jni_gpu -->
            <dependency>
                <groupId>org.tensorflow</groupId>
                <artifactId>libtensorflow_jni_gpu</artifactId>
                <version>1.11.0</version>
            </dependency>
    

    导包成功后,在Java中调用模型

    graphDef = readAllBytes(new FileInputStream(new_model2_cpu.pb));
    graph = new Graph();
    graph.importGraphDef(graphDef);
    session = new Session(graph);
    Tensor result = session.runner()
                    .feed("ori_quest_embedding", Tensor.create(wordVecInputSentence))//输入你自己的数据
                    .feed("dropout", Tensor.create(1.0F))
                    .fetch("quest_out") //和上面python保存模型时的output_node_names对应
                    .run().get(0);
    //这样就能得到模型的输出结果了
    

    (2)使用Deeplearning4J Java API部署Keras模型

    如果我们使用的是Keras训练的模型,那么你就可以选择Deeplearning4J 这个框架来调用模型。
    第一步同样是使用Keras保存训练好的模型

    filepath = "query_models"
     
    checkpoint = ModelCheckpoint(filepath, monitor='val_acc', verbose=1, save_best_only=True)
    
    callback_lists = [checkpoint]
    
    model.fit(x, y, epochs=1,validation_split=0.2,callbacks=callback_lists)
    
    

    然后同样是Java项目中pom.xml导入Deeplearning4J 依赖

      <dependency>      
        <groupId>org.deeplearning4j</groupId>      
        <artifactId>deeplearning4j-core</artifactId>
        <version>1.0.0-beta2</version>    
      </dependency>         
      <dependency>      
        <groupId>org.deeplearning4j</groupId>      
        <artifactId>deeplearning4j-modelimport</artifactId>      
        <version>1.0.0-beta2</version>    
      </dependency>                       
    

    库导入成功后,直接使用Java调用保存好的模型

    MultiLayerNetwork model = KerasModelImport.importKerasSequentialModelAndWeights(“query_models”);
    
    

    这样模型就部署成功了,然后关于怎么使用模型这里就不多说了。
    注意:这里需要注意的是Deeplearning4J 只支持部分深度学习模型,有些模型是不支持的,譬如我这里使用的GRU模型就不支持,运行上面代码会出现以下错误。明确指明不支持GRU模型
    在这里插入图片描述
    去Deeplearning4J 官网查询发现确实现在不支持GRU模型,以下是官网截图
    在这里插入图片描述
    所以如果你想使用Deeplearning4J 来部署训练好的模型,请先查看下是否支持你所使用的模型。

    二、使用Python编写服务端

    (1)使用socket实现进程间的通信

    用python构建服务端,然后通过Java向服务端发送请求调用模型,第一种是使用socket实现进程中的通信,代码如下:

    import socket
    import sys
    import threading
    import json
    import numpy as np
    import jieba
    import os
    import numpy as np
    import nltk
    import keras
    from keras.models import Sequential
    from keras.layers import Dense
    from keras.layers import Dropout
    from keras.layers import LSTM,GRU,TimeDistributed
    from keras.callbacks import ModelCheckpoint
    from keras.utils import np_utils
    from gensim.models.word2vec import Word2Vec
    from keras.optimizers import Adam
    from keras.models import load_model
    import pickle
    # nn=network.getNetWork()
    # cnn = conv.main(False)
    # 深度学习训练的神经网络,使用TensorFlow训练的神经网络模型,保存在文件中
    
    w2v_model = Word2Vec.load("word2vec.w2v").wv
    UNK = pickle.load(open('unk.pkl','rb'))
    model = load_model('query_models')
    a = np.zeros((1, 223,200))
    model.predict(a)
    
    
    def test_init(string):
        cut_list = jieba.lcut(string)
        x_test = np.zeros((1, 223,200))
        for i in range(223):
            x_test[0,i,:] = UNK
        for i in range(len(cut_list)):
            if cut_list[i] in w2v_model:
                x_test[0,i,:] = w2v_model.wv[cut_list[i]]   
        return x_test,len(cut_list)
    
    string_list = list()
    def query_complet(string):
        x_test,length = test_init(string)
        y = model.predict(x_test)
        if length>8:
            return
        word1 = w2v_model.wv.most_similar(positive=[y[0][length-1]], topn=2)[0][0]
        word2 = w2v_model.wv.most_similar(positive=[y[0][length-1]], topn=2)[1][0]
        if word1 == '?' or word1 == '?':
            string_list.append(string)
        else:
            new_str = string+word1
            query_complet(new_str)
    
        if word2 == '?' or word2 == '?':
            string_list.append(string)
        else:
            new_str = string+word2
            query_complet(new_str)
            
    def new_query_complet(string):
        query_complet(string)
        return string_list
    
    def main():
        # 创建服务器套接字
        serversocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        # 设置一个端口
        port = 12345
        # 将套接字与本地主机和端口绑定
        serversocket.bind(("172.17.169.232",port))
        # 设置监听最大连接数
        serversocket.listen(5)
        # 获取本地服务器的连接信息
        myaddr = serversocket.getsockname()
        print("服务器地址:%s"%str(myaddr))
        # 循环等待接受客户端信息
        while True:
            # 获取一个客户端连接
            clientsocket,addr = serversocket.accept()
            print("连接地址:%s" % str(addr))
            try:
                t = ServerThreading(clientsocket)#为每一个请求开启一个处理线程
                t.start()
                pass
            except Exception as identifier:
                print(identifier)
                pass
            pass
        serversocket.close()
        pass
    
    class ServerThreading(threading.Thread):
        # words = text2vec.load_lexicon()
        def __init__(self,clientsocket,recvsize=1024*1024,encoding="utf-8"):
            threading.Thread.__init__(self)
            self._socket = clientsocket
            self._recvsize = recvsize
            self._encoding = encoding
            pass
    
        def run(self):
            print("开启线程.....")
            try:
                #接受数据
                msg = ''
                while True:
                    # 读取recvsize个字节
                    rec = self._socket.recv(self._recvsize)
                    # 解码
                    msg += rec.decode(self._encoding)
                    # 文本接受是否完毕,因为python socket不能自己判断接收数据是否完毕,
                    # 所以需要自定义协议标志数据接受完毕
                    if msg.strip().endswith('over'):
                        msg=msg[:-4]
                        break
                # 发送数据
                self._socket.send("啦啦啦啦".encode(self._encoding))
                pass
            except Exception as identifier:
                self._socket.send("500".encode(self._encoding))
                print(identifier)
                pass
            finally:
                self._socket.close() 
            print("任务结束.....")
            pass
    
    //启动服务        
    main()
    

    Java客户端代码如下:

        public  void test2() throws IOException {
            JSONObject jsonObject = new JSONObject();
            String content = "医疗保险缴费需要";
            jsonObject.put("content", content);
            String str = jsonObject.toJSONString();
            // 访问服务进程的套接字
            Socket socket = null;
    //        List<Question> questions = new ArrayList<>();
    //        log.info("调用远程接口:host=>"+HOST+",port=>"+PORT);
            try {
                // 初始化套接字,设置访问服务的主机和进程端口号,HOST是访问python进程的主机名称,可以是IP地址或者域名,PORT是python进程绑定的端口号
                socket = new Socket("172.17.169.232",12345);
                // 获取输出流对象
                OutputStream os = socket.getOutputStream();
                PrintStream out = new PrintStream(os);
                // 发送内容
                out.print(str);
                // 告诉服务进程,内容发送完毕,可以开始处理
                out.print("over");
                // 获取服务进程的输入流
                InputStream is = socket.getInputStream();
                String text = IOUtils.toString(is);
                System.out.println(text);
        
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {if(socket!=null) socket.close();} catch (IOException e) {}
                System.out.println("远程接口调用结束.");
            }
        }
    

    socket实现Python服务端确实比较简单,但是代码量比较大,没有前面Java直接部署训练好的模型简单。

    (2)使用Python的Flask框架

    Flask框架实现服务端,这个框架我是听我同学说的,因为他们公司就是使用这种方法部署深度学习模型的,不过我们项目当中没有用到,有兴趣的同学可以自己去了解一下这个Flask框架,这里不累述了。

    总结

    常用的方法基本上就上面这些了,以上方法各有各的优缺点,大家可以根据自己的项目需求自行选择合适的方法来部署训练好的深度学习模型,希望这篇博客可以帮到你们。

    展开全文
  • 深度学习模型训练全流程!

    万次阅读 多人点赞 2020-06-11 20:00:00
    ↑↑↑关注后"星标"Datawhale每日干货 &每月组队学习,不错过Datawhale干货作者:黄星源、奉现,Datawhale优秀学习者本文从构建数据验...
  • 深度学习模型转换

    千次阅读 多人点赞 2019-05-24 20:44:24
    当用户基于各种原因学习并使用了一种框架的时候,常常会发现应用或者再训练的场景改变了,比如用户用 Caffe 训练好了一个图像识别的模型,但是生产环境是使用 TensorFlow 做预测。再比如某机构主要以TensorFlow作为...
  • 监督学习模型整理

    千次阅读 2019-01-20 23:27:04
    监督学习模型整理 监督学习模型及特点 最近邻 ​ 适用于小型数据集,是很好的基准模型,很容易解释 线性模型 ​ 非常可靠的首选算法,适用于非常大的数据集,也适用于高维数据。 朴素贝叶斯 ​ 只适用于分类...
  • 常用的深度学习模型

    万次阅读 多人点赞 2018-07-16 14:04:41
    RGB-D相机,例如手势识别、骨骼跟踪、增强现实等 视觉导航:视觉SLAM,例如ORB-SLAM 图像分割:图像分割是一项复杂的任务,目标是将每个像素映射到它的合法类,例如语义分割、实例分割等 深度学习模型 现在我们已经...
  • 深度学习模型部署技术方案

    千次阅读 2020-07-12 17:13:55
    深度学习模型部署技术方案训练好的深度学习模型如何进行部署的相关技术方案1 什么是模型部署?2 数据科学项目整个开发流程3 使用flask 将 Keras深度学习模型部署为Web应用程序 训练好的深度学习模型如何进行部署的...
  • 这是计算机视觉发展史上的转折点,因为它表明,深度学习模型能够以前所未有的精度完成非常困难的任务。 但是你是否知道 AlexNet有6.2千万训练参数? 另一个广为人知的模型 VGGNet 则有1.38亿训练参数,是AlexNet ...
  • 6分钟了解所有机器学习模型

    千次阅读 2020-03-15 18:56:03
    所有机器学习模型都可以分为有监督的或无监督的。如果模型是监督模型,则将其再分类为回归模型或分类模型。我们将介绍这些术语的含义以及下面每个类别中对应的模型。 监督学习模型 监督学习涉及基于示例输入-输出对...
  • 深度学习模型在移动端的部署

    万次阅读 多人点赞 2019-04-27 14:47:28
    而深度学习也成了机器学习领域内的热点,现在人工智能、大数据更是越来越贴近我们的日常生活,越来越多的人工智能应用开始在移植到移动端上,那能够快速高效地在移动端部署深度学习模型就变成亟待解决的问题了。...
  • 提高机器学习模型性能的五个关键方法

    万次阅读 多人点赞 2018-09-08 11:52:10
    如何提高机器学习模型性能, 可从五个关键方面入手。 1. 数据预处理 2. 特征工程 3. 机器学习算法 4. 模型集成与融合 5. 数据增强 以下是各个方面的具体分析和方法: [ 说明:1、这里主要是各个关键方法的...
  • 理解深度学习模型复杂度评估

    千次阅读 2020-04-25 04:11:21
    目录一.神经网络复杂度简述两个指标复杂度对模型的影响二.全连接层复杂度计算三.卷积神经网络复杂度计算单个卷积层的时间复杂度(计算量)单个卷积层的空间复杂度...在深度学习神经网络模型中我们也通过: 计算量/...
  • 机器学习模型评估方法

    千次阅读 2018-05-22 23:08:37
    目录 1、基本概念 2、数据集划分方法 ...3.2、如何比较两学习器性能 3.3、ROC、AUC和EER 3.4、代价敏感错误率 4、比较检验 4.1、假设检验 4.2、交叉验证t检验 4.3、McNemar检验 4.4、Friedman检验...
  • 深度学习模型训练流程

    千次阅读 2018-02-02 19:02:31
    工作中训练了很多的深度学习模型,目前到了上升到方法论的角度来看了。日常工作中有的人可能已经在遵循方法论做事,可能自己没有注意,有的人可能没有遵循方法论在做事,虽然可能最后的结果差不多,但花费的时间和...
  • 机器学习模型的超参数优化

    千次阅读 2020-05-04 08:26:40
    模型优化是机器学习算法实现中最困难的挑战之一。机器学习和深度学习理论的所有分支都致力于模型的优化。 机器学习中的超参数优化旨在寻找使得机器学习算法在验证数据集上表现性能最佳的超参数。超参数与一般模型...
  • 深度学习 模型 剪枝

    万次阅读 多人点赞 2018-12-19 18:58:40
    参考文章: ...为了在手机上加速运行深度学习模型,目前实现的方式基本分为两类:一是深度学习框架层面的加速,另一个方向是深度学习模型层面的加速。 深度学习模型的加速又可以分为采用新的卷...
  • 人工智能AI、机器学习模型理解

    万次阅读 多人点赞 2018-10-22 22:05:00
    机器学习是什么:就是算法模型; 算法模型是什么: 俗地说,模型就是机器学习采用的算法。“模型文件”一般说的是这个算法用到的各种输入、输出数据的值。 因为机器学习往往需要大量的运算,所以有必要将中间变量...
  • 机器学习模型应用以及模型优化的一些思路

    万次阅读 多人点赞 2017-03-09 19:55:45
    本文会介绍如何应用机器学习模型来构建一个智能化应用的通用的过程以及过程中每个环节一些实践性的思路,包括问题界定和定义、 label标注的定义、 数据样本的筛选和构造、 选择机器学习算法、 确定模型性能的度量...
  • 深度学习模型压缩方法综述(三)

    万次阅读 多人点赞 2017-07-24 22:43:37
    目前在深度学习领域分类两个派别,一派为学院派,研究强大、复杂的模型网络和实验方法,为了追求更高的性能;另一派为工程派,旨在将算法更稳定、高效的落地在硬件平台上,效率是其追求的目标。复杂的模型固然具有更...
  • 如何快速提高机器学习模型的性能

    千次阅读 2018-11-10 23:06:41
    本篇文章主要介绍,如何针对机器学习模型的在训练集和开发集(验证集)上的评估指标来使用不同的技巧快速提高模型的评估性能。针对机器学习模型的性能优化我们有很多种方式,如增大数据集、增大模型的复杂度、使用更...
  • 深度学习(Deep Learning)因其计算复杂度或参数冗余,在一些场景和设备上限制了相应的模型部署,需要借助模型压缩、优化加速、异构计算等方法突破瓶颈。 模型压缩算法能够有效降低参数冗余,从而减少存储占用、...
  • 机器学习模型 Logistic回归模型 作为一个基础模型,我们将使用scikit-learn库的LogisticRegression, 建立Logistic模型。为此,我们将使用所有的特征,我们也将填补缺失值,归一化特征。 from sklearn.preprocessing ...
  • 机器学习模型的评价指标和方法

    万次阅读 2018-08-24 10:32:13
    衡量分类器的好坏 对于分类器,或者说分类算法,评价指标主要有accuracy, [precision,recall,宏平均和微平均,F-score,pr曲线],ROC-AUC曲线,gini系数。 对于回归分析,主要有mse和...机器学习系统设计系统...
  • 机器学习模型生产环境部署的四种系统架构总结 本文将从简单到复杂介绍典型架构的特点以及其优缺点。 介绍 一旦数据科学家对模型的性能感到满意,下一步便是“模型生产环境部署”, 没有系统的合理配置,您的Kaggle ...
  • 主流的25个深度学习模型

    万次阅读 2019-08-19 15:50:22
    深度学习发展很快,新的模型层出不穷,所以要想全部列举是不可能的。另外,很多模型都是这里提出很长很长时间了,所以也不是说“老”模型就没用,大家学习的话,还是要全面而深入的学习。 1、 Feed forward ...
  • 用深度学习模型提取特征

    千次阅读 2020-04-17 20:20:12
    深度学习模型不仅可以用于分类回归,还能用于提取特征。通常使用训练好的模型,输入图片,输出为提取到的特征向量。 加入特征之后,结果往往不尽如人意,大致有以下原因: 深度学习模型一般有N层结构,不能确定...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,223,102
精华内容 489,240
关键字:

学习模型