【构建ML驱动的应用程序】第 5 章 :训练和评估模型

news2024/11/24 17:54:32

   🔎大家好,我是Sonhhxg_柒,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎

📝个人主页-Sonhhxg_柒的博客_CSDN博客 📃

🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​

📣系列专栏 - 机器学习【ML】 自然语言处理【NLP】  深度学习【DL】

 🖍foreword

✔说明⇢本人讲解主要包括Python、机器学习(ML)、深度学习(DL)、自然语言处理(NLP)等内容。

如果你对这个系列感兴趣的话,可以关注订阅哟👋

文章目录

最简单的适当模型

简单模型

快速实施

可以理解

可部署

从模式到模型

我们想忽略特征尺度

我们的预测变量是预测变量的线性组合

我们的数据有时间方面

每个数据点都是模式的组合

ML 编辑器模型

拆分您的数据集

验证集

测试集

相对比例

数据泄露

ML 编辑器数据拆分

评委表现

偏差方差权衡

超越聚合指标

评估您的模型:超越准确性

对比数据和预测

混淆矩阵

ROC 曲线

校准曲线

错误的降维

Top-k方法

k个表现最好的例子

k个表现最差的例子

k个最不确定的例子

Top-k 实现技巧

ML Editor 的 Top-k 方法

其他型号

评估特征重要性

直接来自分类器

黑匣子解释器

结论


在前面的章节中,我们介绍了如何确定要解决的正确问题、制定解决计划、构建简单的管道、探索数据集以及生成一组初始特征。这些步骤使我们能够收集到足够的信息来开始训练一个合适的模型。这里的适当模型意味着模型非常适合手头的任务,并且很有可能表现良好。

在本章中,我们将首先简要回顾一下选择模型时的一些注意事项。然后,我们将描述分离数据的最佳实践,这将有助于在现实条件下评估您的模型。最后,我们将研究分析建模结果和诊断错误的方法。

最简单的适当模型

现在准备好训练模型后,我们需要决定从哪个模型开始。尝试所有可能的模型,对所有模型进行基准测试,然后根据某些指标在保留的测试集上选择具有最佳结果的模型可能很诱人。

一般来说,这不是最好的方法。它不仅计算量大(有很多模型集,每个模型都有很多参数,所以实际上你只能测试一个次优子集),它还将模型视为预测黑盒,完全忽略了ML 模型编码隐式以他们学习的方式对数据进行假设

不同的模型对数据做出不同的假设,因此适用于不同的任务。此外,由于 ML 是一个迭代领域,您需要选择可以快速构建和评估的模型。

让我们首先定义如何识别简单模型。然后,我们将介绍一些数据模式示例和适当的模型来利用它们。

简单模型

一个简单的模型应该能够快速实现、易于理解和部署:快速实现因为你的第一个模型可能不会是你的最后一个模型,易于理解因为它可以让你更轻松地调试它,并且易于部署因为这是 ML 的基本要求供电的应用程序。让我们首先探讨我所说的快速实施的意思。

可部署

作为提醒一下,你的模型的最终目标是为使用它的人提供有价值的服务。这意味着当您考虑要训练哪个模型时,您应该始终考虑是否能够部署它。

我们将在第 IV 部分介绍部署,但您应该已经在考虑以下问题:

  • 经过训练的模型需要多长时间才能为用户做出预测?在考虑预测延迟时,您不仅应该包括模型输出结果所需的时间,还应该包括用户提交预测请求和接收结果之间的延迟。这包括任何预处理步骤,例如特征生成、任何网络调用,以及发生在模型输出和呈现给用户的数据之间的任何后处理步骤。

  • 如果我们考虑我们预期的并发用户数量,这个推理管道对于我们的用例来说是否足够快?

  • 训练模型需要多长时间,我们需要多久训练一次?如果训练需要 12 小时,并且您需要每 4 小时重新训练您的模型以保持新鲜,那么不仅您的计算费用会非常昂贵,而且您的模型将始终过时。

我们可以使用如图 5-1 所示的表格来比较模型的简单程度。随着 ML 领域的发展和新工具的构建,今天可能部署复杂或难以解释的模型可能会变得更易于使用,并且需要更新此表。出于这个原因,我建议您根据您的特定问题域构建您自己的版本。

图 5-1。基于简单性的评分模型

即使在简单、可解释和可部署的模型中,仍有许多潜在的候选者。要选择模型,您还应该考虑在第 4 章中确定的模式。

从模式到模型

我们已经确定的模式和我们生成的特征应该指导我们的模型选择。让我们介绍一些数据模式示例和适当的模型来利用它们。

我们的预测变量是预测变量的线性组合

有时,有充分的理由相信我们可以仅使用特征的线性组合做出好的预测。在这些情况下,我们应该使用线性模型,例如连续问题的线性回归或逻辑回归或用于分类问题的朴素贝叶斯分类器。

这些模型简单、高效,并且通常可以直接解释它们的权重,从而帮助我们识别重要特征。如果我们认为我们的特征和我们预测的变量之间的关系更复杂,使用一个非线性模型,例如多层神经网络或生成特征交叉(参见“让数据通知特征和模型”的开头)可以提供帮助。

每个数据点都是模式的组合

什么时候例如,在解决图像领域的问题时,卷积神经网络 (CNN) 通过学习平移不变滤波器的能力证明是有用的。这意味着无论位置如何,它们都能够提取图像中的局部模式。一旦 CNN 学会了如何检测眼睛,它就可以在图像中的任何地方检测到它,而不仅仅是它在训练集中出现的地方。

卷积滤波器已被证明在包含局部模式的其他领域中很有用,例如语音识别或文本分类,其中 CNN 已成功用于句子分类。例如,请参阅 Yoon Kim 在论文“用于句子分类的卷积神经网络”中的实现。

在考虑使用正确的模型时,还有许多其他要点需要考虑。为了对于大多数经典的 ML 问题,我建议使用scikit-learn 团队提供的这个方便的流程图。它为许多常见用例提供模型建议。

ML 编辑器模型

为了ML Editor,我们希望我们的第一个模型能够快速且相当容易调试。此外,我们的数据由单个示例组成,无需考虑时间方面(例如一系列问题)。出于这个原因,我们将从一个流行且有弹性的基线,一个随机森林分类器开始。

一旦您确定了一个看起来合理的模型,就可以训练它了。作为一般准则,您不应在第 4 章中收集的整个数据集上训练您的模型。您首先要从训练集中拿出一些数据。让我们介绍为什么以及如何这样做。

拆分您的数据集

我们模型的主要目标是为我们的用户将提交的数据提供有效的预测。这意味着我们的模型最终必须在它以前从未见过的数据上表现良好。

当你在一个数据集上训练一个模型时,测量它在同一个数据集上的性能只会告诉你它在对它已经看到的数据做出预测方面有多好。如果您只在数据的子集上训练模型,则可以使用模型未训练的数据来估计它在看不见的数据上的表现。

在图 5-2中,您可以看到根据数据集的一个属性(问题的作者)分成三个独立的集合(训练、验证和测试)的示例。在本章中,我们将介绍这些集合中的每一个的含义,以及如何看待它们。

图 5-2。拆分关于作者的数据,同时将正确比例的问题分配给每个拆分

要考虑的第一个留出集是验证集。

测试集

自从我们将在我们的模型上经历多个迭代周期,并在每个周期测量其在验证集上的性能,我们可能会偏向我们的模型,使其在验证集上表现良好。这有助于我们的模型泛化到训练集之外,但也带来了简单地学习仅在我们的特定验证集上表现良好的模型的风险。理想情况下,我们希望有一个模型可以很好地处理因此不包含在验证集中的新数据。

出于这个原因,我们通常会提供第三组称为测试集,一旦我们对迭代感到满意,它就会作为我们在未见数据上的性能的最终基准。虽然使用测试集是最佳实践,但从业者有时会使用验证集作为测试集。这增加了模型偏向验证集的风险,但在仅运行少数实验时可能是合适的。

重要的是要避免使用测试集的性能来告知建模决策,因为该集应该代表我们将在生产中面对的看不见的数据。调整建模方法以在测试集上表现良好存在导致高估模型性能的风险。

有一个在生产中执行的模型,你训练的数据应该类似于将与你的产品交互的用户产生的数据。理想情况下,您可以从用户那里收到的任何类型的数据都应该在您的数据集中表示。如果不是这种情况,请记住,您的测试集性能仅代表一部分用户的性能。

对于 ML 编辑器,这意味着不符合writers.stackoverflow.com人口统计数据的用户可能不会得到我们推荐的服务。如果我们想解决这个问题,我们应该扩展数据集以包含更能代表这些用户的问题。我们可以从合并来自其他 Stack Exchange 网站的问题开始,以涵盖更广泛的主题,或完全涵盖不同的问答网站。

以这种方式纠正数据集对于副项目来说可能具有挑战性。然而,在构建消费级产品时,有必要在用户接触到模型弱点之前尽早发现它们。许多我们将在第 8 章中介绍的故障模式中的一部分可以通过更具代表性的数据集来避免。

相对比例

一般来说,您应该最大化模型可用于学习的数据量,同时提供足够大的验证和测试集以提供准确的性能指标。从业者经常使用 70% 的数据进行训练,20% 用于验证,10% 用于测试,但这完全取决于数据的数量。对于非常大的数据集,您可以负担得起使用更大比例的数据进行训练,同时仍然有足够的数据来验证模型。对于较小的数据集,您可能需要使用较小的比例进行训练,以便拥有足够大的验证集来提供准确的性能测量。

现在您知道为什么要拆分数据,以及要考虑哪些拆分,但是您应该如何决定每个拆分中的数据点呢?您使用的拆分方法对建模性能有重大影响,应取决于数据集的特定特征。

数据泄露

用于分离数据的方法是验证的关键部分。您的目标应该是使您的验证/测试集接近您期望的未见数据。

大多数情况下,训练集、验证集和测试集由随机采样数据点分开。在某些情况下,这会导致数据泄露。当(由于我们的训练程序)模型在训练期间接收到在生产中在真实用户面前使用时无法访问的信息时,就会发生数据泄漏。

应不惜一切代价避免数据泄漏,因为它会导致对我们模型性能的夸大看法。在表现出数据泄漏的数据集上训练的模型能够利用信息做出预测,而当它遇到不同的数据时则不会。这使得模型的任务人为地更容易,但这只是由于信息泄露。该模型的性能在保留数据上看起来很高,但在生产中会差得多。

在图 5-3中,我列出了一些将数据随机拆分成集合会导致数据泄漏的常见原因。数据泄露的潜在原因有很多,接下来我们将探讨两个常见的原因。

为了开始我们的探索,让我们处理图 5-3顶部的示例,时间数据泄漏。然后,我们将继续研究样本污染,该类别包含图 5-3中底部的两个示例。

图 5-3。随机拆分数据往往会导致数据泄露

样品污染

一个数据泄漏的常见来源在于随机性发生的级别。在构建预测学生论文成绩的模型时,我协助的一位数据科学家曾经发现他的模型在保留测试集上的表现接近完美。

在如此艰巨的任务中,应该仔细检查表现如此出色的模型,因为它经常表明存在错误或数据泄漏。有人会说,墨菲定律的 ML 等价物是,您对模型在测试数据上的表现越惊喜,您的管道中出错的可能性就越大。

在这个例子中,因为大多数学生写了多篇论文,随机拆分数据导致同一学生的论文同时出现在训练和测试集中。这使得模型能够获取识别学生的特征,并使用该信息做出准确的预测(该数据集中的学生在所有论文中的成绩往往相似)。

如果我们要部署这个作文分数预测器以备将来使用,它将无法为它以前没有见过的学生预测有用的分数,而只会预测它所训练过的学生的历史分数。这根本没有用。

为了解决这个例子中的数据泄漏,在学生而不是论文级别进行了新的拆分。这意味着每个学生要么只出现在训练集中,要么只出现在验证集中。由于任务变得更加困难,这导致模型准确性下降。然而,由于训练任务现在更接近于生产中的任务,因此这个新模型更有价值。

在常见任务中,样品污染可能会以细微的方式发生。让我们以公寓租赁预订网站为例。该网站包含一个点击预测模型,在给定用户查询和一个项目的情况下,预测用户是否会点击该项目。该模型用于决定向用户显示哪些列表。

为了训练这样的模型,该网站可以使用用户特征的数据集,例如他们之前的预订数量、与呈现给他们的公寓配对以及他们是否点击了它们。此数据通常存储在生产数据库中,可以查询该数据库以生成此类对。如果这个网站的工程师只是简单地查询数据库来构建这样一个数据集,他们很可能会面临数据泄露的情况。你能明白为什么吗?

在图 5-4中,我通过描述对特定用户的预测来勾勒出可能出错的示例。在顶部,您可以看到模型可以在生产中使用的功能来提供点击预测。在这里,没有先前预订的新用户会看到给定的公寓。在底部,您可以看到几天后工程师从数据库中提取数据时的功能状态。

图 5-4。数据泄漏可能由于微妙的原因而发生,例如由于缺乏数据版本控制

请注意 中的差异previous_bookings,这是由于用户在最初看到列表后发生的活动所致。通过使用数据库快照,有关用户未来操作的信息被泄露到训练集中。我们现在知道用户最终会预订五套公寓!这种泄漏会导致使用底部信息训练的模型对错误的训练数据输出正确的预测。模型在生成的数据集上的准确性会很高,因为它利用了在生产中无法访问的数据。当部署模型时,它的性能会比预期的要差。

如果您对这个轶事有任何看法,那就是始终调查模型的结果,尤其是当它显示出惊人的强大性能时。

ML 编辑器数据拆分

我们用来训练 ML Editor 的数据集包含 Stack Overflow 上提出的问题及其答案。乍一看,随机拆分似乎就足够了,并且在 scikit-learn 中实现起来非常简单。例如,我们可以编写如下所示的函数:

from sklearn.model_selection import train_test_split

def get_random_train_test_split(posts, test_size=0.3, random_state=40):
    """
    Get train/test split from DataFrame
    Assumes the DataFrame has one row per question example
    :param posts: all posts, with their labels
    :param test_size: the proportion to allocate to test
    :param random_state: a random seed
    """
    return train_test_split(
        posts, test_size=test_size, random_state=random_state
    )

这种方法可能会导致泄漏;你能认出它吗?

如果我们回想我们的用例,我们知道我们希望我们的模型处理它以前没有见过的问题,只看它们的内容。然而,在问答网站上,许多其他因素可以影响问题是否成功回答。这些因素之一是作者的身份。

如果我们随机拆分数据,则给定的作者可能同时出现在我们的训练和验证集中。如果某些受欢迎的作者具有独特的风格,我们的模型可能会过度适应这种风格,并由于数据泄漏而在我们的验证集上达到人为的高性能。为避免这种情况,确保每个作者仅出现在训练或验证中对我们来说更安全。这与我们之前在学生评分示例中描述的泄漏类型相同。

使用scikit-learn 的GroupShuffleSplit类并将表示作者唯一 ID 的特征传递给它的拆分方法,我们可以保证给定的作者只出现在其中一个拆分中。

from sklearn.model_selection import GroupShuffleSplit

def get_split_by_author(
    posts, author_id_column="OwnerUserId", test_size=0.3, random_state=40
):
    """
    Get train/test split
    Guarantee every author only appears in one of the splits
    :param posts: all posts, with their labels
    :param author_id_column: name of the column containing the author_id
    :param test_size: the proportion to allocate to test
    :param random_state: a random seed
    """
    splitter = GroupShuffleSplit(
        n_splits=1, test_size=test_size, random_state=random_state
    )
    splits = splitter.split(posts, groups=posts[author_id_column])
    return next(splits)

要查看两种拆分方法之间的比较,请参阅本书 GitHub 存储库中的拆分数据笔记本。

拆分数据集后,可以将模型拟合到训练集。我们已经在“从一个简单的管道开始”中介绍了训练管道的必要部分。在本书 GitHub 存储库中的一个简单模型笔记本的训练中,我展示了一个用于 ML Editor 的端到端训练管道示例。我们将分析该管道的结果。

我们已经涵盖了在拆分数据时要牢记的主要风险,但是一旦我们的数据集被拆分并且我们已经在训练拆分上训练了一个模型,我们应该做什么?在下一节中,我们将讨论评估训练模型的不同实用方法以及如何最好地利用它们。

评委表现

现在我们已经拆分了数据,我们可以训练我们的模型并判断它的表现。大多数模型都经过训练以最小化成本函数,该函数表示模型的预测与真实标签的差距。成本函数的值越小,模型对数据的拟合越好。您最小化哪个函数取决于您的模型和您的问题,但通常最好查看它在训练集和验证集上的值。

这个通常有助于估计我们模型的偏差方差权衡,它衡量我们的模型从数据中学习到有价值的可概括信息的程度,而无需记住我们训练集的细节。

笔记

我是假设熟悉标准分类指标,但这里有一个简短的提醒以防万一。对于分类问题,准确性表示模型正确预测的示例的比例。换句话说,它是真实结果的比例,既是真阳性又是真阴性。在严重不平衡的情况下,高精度可以掩盖较差的模型。如果 99% 的案例是阳性的,那么始终预测阳性类别的模型将具有 99% 的准确率,但可能不是很有用。精确率、召回率和 f1 分数解决了这个限制。精确是预测为正的示例中真阳性的比例。记起是具有正标签的元素中真阳性的比例。这f1 分数是精确率和召回率的调和平均值。

为了在本书的 GitHub 存储库中训练一个简单的模型笔记本,我们使用 TF-IDF 向量和我们在“ML 编辑器功能”中确定的功能训练了随机森林的第一个版本。

以下是我们训练集和验证集的准确性、精确度、召回率和 f1 分数。

Training accuracy = 0.585, precision = 0.582, recall = 0.585, f1 = 0.581Validation accuracy = 0.614, precision = 0.615, recall = 0.614, f1 = 0.612

快速查看这些指标可以让我们注意到两件事:

  • 由于我们有一个由两个类组成的平衡数据集,因此为每个示例随机选择一个类会给我们大约 50% 的准确率。我们模型的准确率达到 61%,优于随机基线。

  • 我们在验证集上的准确性高于训练集。看来我们的模型在看不见的数据上效果很好。

让我们更深入地了解模型的性能。

超越聚合指标

一个性能指标有助于确定模型是否已从数据集中正确学习或是否需要改进。下一步是进一步检查结果,以了解模型失败或成功的方式。这很重要,原因有二:

性能验证

表现指标可能非常具有欺骗性。当处理数据严重不平衡的分类问题时,例如预测出现在不到 1% 患者身上的罕见疾病,任何始终预测患者健康的模型都将达到 99% 的准确率,即使它没有预测能力完全没有力量。存在适用于大多数问题的性能指标(f1 分数对于前一个问题会更好),但关键是要记住它们是聚合指标并且描绘了不完整的情况。要信任模型的性能,您需要在更精细的级别检查结果。

迭代

建筑模型是一个迭代过程,开始迭代循环的最佳方法是确定要改进什么以及如何改进它。性能指标无助于确定模型的问题所在以及管道的哪一部分需要改进。很多时候,我看到数据科学家试图通过简单地尝试许多其他模型或超参数,或者随意构建其他功能来提高模型性能。这种方法相当于蒙住眼睛向墙上投掷飞镖。快速构建成功模型的关键是识别并解决模型失败的具体原因。

考虑到这两个动机,我们将介绍几种深入研究模型性能的方法。

评估您的模型:超越准确性

那里有无数种方法可以检查模型的性能,我们不会涵盖所有可能的评估方法。我们将重点关注一些通常有助于梳理表面下可能发生的事情的一些问题。

在调查模型性能时,将自己想象成一名侦探,接下来介绍的每种方法都是揭示线索的不同方式。我们将从涵盖多种技术开始,这些技术将模型的预测与数据进行对比以发现有趣的模式。

对比数据和预测

深入评估模型的第一步是找到比聚合指标更精细的方法来对比数据和预测。我们想分解聚合性能指标,例如我们数据的不同子集的准确性、精确度或召回率。让我们看看如何应对常见的 ML 分类挑战。

您可以在本书的 GitHub 存储库中的比较数据与预测笔记本中找到所有代码示例。

为了对于分类问题,我通常建议从查看混淆矩阵开始,如图 5-6所示,其行代表每个真实类,列代表我们模型的预测。具有完美预测的模型将有一个混淆矩阵,除了从左上角到右下角的对角线外,到处都是零。实际上,这种情况很少见。让我们来看看为什么混淆矩阵通常非常有用。

混淆矩阵

一个混淆矩阵让我们一眼就能看出我们的模型是否在某些类别上特别成功,而在其他类别上是否挣扎。这对于具有许多不同类或不平衡类的数据集特别有用。

通常,我已经看到具有令人印象深刻的准确性的模型显示一个混淆矩阵,其中一列完全为空,这意味着模型永远不会预测到一个类。这通常发生在稀有类上,有时可能是无害的。但是,如果稀有类别代表重要结果,例如借款人拖欠贷款,混淆矩阵将帮助我们注意到问题。例如,我们可以通过在模型的损失函数中更重地权衡稀有类别来纠正它。

图 5-6的第一行显示我们训练的初始模型在预测低质量问题时表现良好。底行显示该模型难以检测到所有高质量问题。事实上,在所有获得高分的问题中,我们的模型只有一半的时间正确预测了他们的类别。然而,查看右栏,我们可以看到当模型预测一个问题是高质量的时,它的预测往往是准确的。

在处理两个以上类别的问题时,混淆矩阵可能会更有用。例如,我曾经和一位工程师一起工作,他试图对来自为他的最新模型绘制混淆矩阵的语音话语。他立即注意到两个对称的非对角线值异常高。这两个类(每个类代表一个词)混淆了模型及其大部分错误的原因。经过进一步检查,发现混淆模型的词是whenwhere。为这两个示例收集额外的数据足以帮助模型更好地区分这些发音相似的词。

混淆矩阵允许我们将模型的预测与每个类的真实类进行比较。在调试模型时,我们可能希望比它们的预测更深入地观察并检查模型输出的概率。

图 5-6。我们问题分类任务初始基线的混淆矩阵

ROC 曲线

为了对于二元分类问题,接受者操作特征 (ROC) 曲线也可以提供非常丰富的信息。ROC 曲线将真阳性率 (TPR) 绘制为假阳性率 (FPR) 的函数。

分类中使用的绝大多数模型都会返回给定示例属于特定类别的概率分数。这意味着在推理时,如果模型给出的概率高于某个阈值,我们可以选择将示例归于某个类别。这个通常称为决策阈值

默认情况下,大多数分类器使用 50% 的概率作为决策阈值,但我们可以根据我们的用例进行更改。通过从 0 到 1 定期改变阈值并测量每个点的 TPR 和 FPR,我们获得了 ROC 曲线。

一旦我们有了模型的预测概率和相关的真实标签,就可以使用 scikit-learn 轻松获得 FPR 和 TPR。然后我们可以生成 ROC 曲线。

from sklearn.metrics import roc_curve

fpr, tpr, thresholds = roc_curve(true_y, predicted_proba_y)

对于如图 5-7中绘制的 ROC 曲线,有两个细节很重要。首先,从左下角到右上角的对角线代表随机猜测。这意味着要击败随机基线,分类器/阈值对应该位于这条线之上。此外,完美模型将由左上角的绿色虚线表示。

图 5-7。初始模型的 ROC 曲线

因为在这两个细节中,分类模型通常使用曲线下面积 (AUC) 来表示性能。AUC 越大,我们的分类器就越接近“完美”模型。随机模型的 AUC 为 0.5,而完美模型的 AUC 为 1。然而,在考虑实际应用时,我们应该选择一个特定阈值,为我们的用例提供最有用的 TPR/FPR 比率.

出于这个原因,我建议在代表我们产品需求的 ROC 曲线中添加垂直或水平线。当构建一个系统,如果认为足够紧急时,将客户请求路由给员工,那么你能负担得起的 FPR 完全取决于你的支持人员的能力和你拥有的用户数量。这意味着甚至不应考虑 FPR 高于该限制的任何模型。

在 ROC 曲线上绘制阈值可以让您拥有比简单地获得最大 AUC 分数更具体的目标。确保你的努力对你的目标有用!

我们的 ML Editor 模型将问题分类为好或坏。在这种情况下,TPR 代表了我们的模型正确判断为好的高质量问题的比例。FPR 是我们的模型声称是好的坏问题的比例。如果我们不帮助我们的用户,我们希望至少保证我们不会伤害他们。这意味着我们不应该使用任何可能会过于频繁地推荐错误问题的模型。因此,我们应该为我们的 FPR 设置一个阈值,例如 10%,并使用我们可以在该阈值下找到的最佳模型。在图 5-8中,您可以在我们的 ROC 曲线上看到此要求;它大大减少了模型可接受的决策阈值空间。

ROC 曲线让我们更细致地了解模型的性能如何随着我们做出或多或少的保守预测而变化。查看模型预测概率的另一种方法是将其分布与真实类别分布进行比较,以查看它是否经过良好校准。

图 5-8。添加代表我们产品需求的 ROC 线

Top-k方法

发现密集的错误区域有助于识别模型的故障模式。上面,我们使用降维来帮助我们找到这样的区域,但我们也可以直接使用模型本身。通过利用预测概率,我们可以识别最具挑战性或模型最不确定的数据点。我们称这种方法为top-k 方法

top-k 方法很简单。首先,选择数量可控的示例来可视化我们将调用的 k。对于一个人将可视化结果的个人项目,从十到十五个例子开始。对于您之前找到的每个类或集群,可视化:

  • k个表现最好的例子

  • k个表现最差的例子

  • k个最不确定的例子

可视化这些示例将帮助您识别对您的模型来说容易、难或容易混淆的示例。让我们更详细地探讨每个类别。

k个表现最好的例子

一、陈列您的模型预测正确且最有信心的 k 个示例。在可视化这些示例时,旨在确定它们之间可以解释模型性能的特征值的任何共性。这将帮助您识别模型成功利用的特征。

在可视化成功的示例以识别模型利用的特征之后,绘制不成功的示例以识别它未能拾取的特征。

k个表现最差的例子

展示您的模型预测错误并且最有信心的 k 个示例。从训练数据中的 k 个示例开始,然后进行验证。

就像可视化错误集群一样,可视化模型在训练集中表现最差的 k 个示例可以帮助识别模型失败的数据点的趋势。显示这些数据点可帮助您识别可使模型更容易使用的其他特征。

什么时候例如,在探索 ML 编辑器的初始模型错误时,我发现发布的一些问题得分较低,因为它们不包含实际问题。该模型最初无法预测此类问题的低分,因此我添加了一个功能来计算文本正文中的问号。添加此功能使模型能够对这些“非问题”问题做出准确的预测。

可视化验证数据中的 k 个最差示例可以帮助识别与训练数据显着不同的示例。如果您确实在验证集中发现了太难的示例,请参阅“拆分您的数据集”中的提示以更新您的数据拆分策略。

最后,模型并不总是对或错。他们还可以输出不确定的预测。接下来我会介绍这些。

k个最不确定的例子

可视化k 个最不确定的示例包括显示模型对其预测最不自信的示例。对于本书主要关注的分类模型,不确定示例是指模型为每个类别输出尽可能接近相等概率的示例。

如果模型经过良好校准(请参阅“校准曲线”以了解校准说明),它将为人类贴标签者也不确定的示例输出统一概率。例如,对于猫狗分类器,同时包含狗和猫的图片将属于该类别。

训练集中不确定的例子通常是标签冲突的症状。事实上,如果一个训练集包含两个重复或相似的例子,每个例子都被标记为不同的类别,模型将在训练过程中通过输出每个类别的等概率来最小化它的损失,当出现这个例子时。因此,冲突的标签会导致不确定的预测,您可以使用 top-k 方法尝试找到这些示例。

绘制验证集中前 k 个最不确定的示例可以帮助找到训练数据中的差距。模型不确定但人工标注者清楚的验证示例通常表明该模型尚未在其训练集中接触过此类数据。绘制验证集的前 k 个不确定示例可以帮助识别应该出现在训练集中的数据类型。

Top-k 评估可以直接进行。在下一节中,我将分享一个工作示例。

Top-k 实现技巧

以下是一个简单的 top-k 实现,适用于 pandas DataFrames。该函数将包含预测概率和标签的 DataFrame 作为输入,并返回上面的每个 top-k。

def get_top_k(df, proba_col, true_label_col, k=5, decision_threshold=0.5):
    """
    For binary classification problems
    Returns k most correct and incorrect example for each class
    Also returns k most unsure examples
    :param df: DataFrame containing predictions, and true labels
    :param proba_col: column name of predicted probabilities
    :param true_label_col: column name of true labels
    :param k: number of examples to show for each category
    :param decision_threshold: classifier decision boundary to classify as
           positive
    :return: correct_pos, correct_neg, incorrect_pos, incorrect_neg, unsure
    """
    # Get correct and incorrect predictions
    correct = df[
        (df[proba_col] > decision_threshold) == df[true_label_col]
    ].copy()
    incorrect = df[
        (df[proba_col] > decision_threshold) != df[true_label_col]
    ].copy()

    top_correct_positive = correct[correct[true_label_col]].nlargest(
        k, proba_col
    )
    top_correct_negative = correct[~correct[true_label_col]].nsmallest(
        k, proba_col
    )

    top_incorrect_positive = incorrect[incorrect[true_label_col]].nsmallest(
        k, proba_col
    )
    top_incorrect_negative = incorrect[~incorrect[true_label_col]].nlargest(
        k, proba_col
    )

    # Get closest examples to decision threshold
    most_uncertain = df.iloc[
        (df[proba_col] - decision_threshold).abs().argsort()[:k]
    ]

    return (
        top_correct_positive,
        top_correct_negative,
        top_incorrect_positive,
        top_incorrect_negative,
        most_uncertain,
    )

让我们通过将 top-k 方法用于 ML 编辑器来说明它。

ML Editor 的 Top-k 方法

出色地将 top-k 方法应用于我们训练的第一个分类器。本书的 GitHub 存储库中提供了包含 top-k 方法使用示例的笔记本。

图 5-10显示了我们的第一个 ML Editor 模型的每个类的前两个最正确的示例。两个类别之间差异最大的特征是text_len,它表示文本的长度。分类器了解到好的问题往往很长,而差的问题往往很短。它在很大程度上依赖于文本长度来区分类别。

图 5-10。Top-k最正确

图 5-11证实了这个假设。我们的分类器预测最有可能回答的未回答问题是最长的,反之亦然。这一观察结果也证实了我们在“评估特征重要性”中的发现,我们在其中看到text_len的是最重要的特征。

图 5-11。Top-k最不正确

 我们已经确定分类器text_len可以轻松识别已回答和未回答的问题,但此功能还不够,会导致错误分类。我们应该添加更多功能来改进我们的模型。可视化两个以上的示例将有助于识别更多候选特征。

在训练数据和验证数据上使用 top-k 方法有助于确定我们的模型和数据集的局限性。我们已经介绍了它如何帮助确定模型是否具有表示数据的能力、数据集是否足够平衡以及它是否包含足够的代表性示例。

我们主要介绍了分类模型的评估方法,因为此类模型适用于许多具体问题。让我们简要地看一下在不进行分类时检查性能的方法。

其他型号

许多模型可以使用分类框架进行评估。在对象检测,例如,目标是让模型输出图像中感兴趣对象周围的边界框,准确性是一个常见的指标。由于每个图像都可以有多个表示对象和预测的边界框,因此计算准确度需要一个额外的步骤。一、计算预测和标签之间的重叠(通常使用Jaccard 索引)允许每个预测被标记为正确或不正确。从那里,可以计算精度并使用本章前面的所有方法。

同样,在构建旨在推荐内容,最好的迭代方式通常是在各种类别上测试模型并报告其性能。然后评估变得类似于分类问题,其中每个类别代表一个类别。

对于此类方法可能会很棘手的问题类型,例如生成模型,您仍然可以使用之前的数据探索将数据集分成多个类别,并为每个类别生成性能指标。

当我与一位数据科学家合作构建一个句子简化模型,检查模型在句子长度条件下的性能表明,较长的句子对模型来说更难。这需要进行检查和手动标记,但会导致明确的下一步行动,即用更长的句子扩充训练数据,这有助于显着提高性能。

我们已经介绍了很多通过将模型的预测与标签进行对比来检查模型性能的方法,但我们也可以检查模型本身。如果一个模型表现不佳,尝试解释其预测可能是值得的。

评估特征重要性

一个分析模型性能的另一种方法是检查模型使用数据的哪些特征进行预测。这样做称为特征重要性分析。评估特征重要性有助于消除或迭代当前对模型没有帮助的特征。特征重要性还可以帮助识别具有可疑预测性的特征,这通常是数据泄漏的迹象。我们将从为可以轻松完成的模型生成特征重要性开始,然后介绍可能不容易直接提取此类特征的情况。

直接来自分类器

要验证模型是否正常工作,请可视化模型正在使用或忽略的特征。对于回归或决策树等简单模型,通过查看模型的学习参数可以直接提取特征的重要性。

为了我们在 ML Editor 案例研究中使用的第一个模型是随机森林,我们可以简单地使用 scikit-learn 的 API 来获取所有特征重要性的排名列表。特征重要性代码及其用法可以在本书的 GitHub 存储库中的特征重要性笔记本中找到。

def get_feature_importance(clf, feature_names):
    importances = clf.feature_importances_
    indices_sorted_by_importance = np.argsort(importances)[::-1]
    return list(
        zip(
            feature_names[indices_sorted_by_importance],
            importances[indices_sorted_by_importance],
        )
    )

如果我们在训练好的模型上使用上面的函数,通过一些简单的列表处理,我们可以获得十个最有用的特征的简单列表:

Top 10 importances:

text_len: 0.0091
are: 0.006
what: 0.0051
writing: 0.0048
can: 0.0043
ve: 0.0041
on: 0.0039
not: 0.0039
story: 0.0039
as: 0.0038

这里有几点需要注意:

  • 文本的长度是信息量最大的特征。

  • 我们生成的其他特征根本没有出现,其重要性比其他特征低一个数量级以上。该模型无法利用它们来有意义地分离类。

  • 其他特征代表非常常见的单词或与写作主题相关的名词。

因为我们的模型和特征很简单,所以这些结果实际上可以为我们提供构建新特征的想法。例如,我们可以添加一个功能来计算常用词和稀有词的使用情况,以查看它们是否可以预测获得高分的答案。

如果特征或模型变得复杂,则生成特征重要性需要使用模型可解释性工具。

黑匣子解释器

当特征变得复杂时,特征重要性会变得更难解释。一些更复杂的模型,如神经网络,甚至可能无法揭示它们学习到的特征重要性。在这种情况下,利用黑盒解释器,它试图独立于模型的内部运作来解释模型的预测。

通常,这些解释器在给定数据点而不是全局上识别模型的预测特征。他们通过更改给定示例的每个特征值并观察模型的预测结果如何变化来做到这一点。LIME和SHAP是两种流行的黑盒解释器。

有关使用它们的端到端示例,请参阅本书 GitHub 存储库中的黑盒解释器笔记本。

图 5-12显示了 LIME 提供的解释,围绕哪些词在决定将此示例问题分类为高质量时最重要。LIME 通过反复从输入问题中删除单词并查看哪些单词使我们的模型更倾向于一个或另一个类来生成这些解释。

图 5-12。解释一个特定的例子

我们可以看到模型正确预测了该问题会获得高分。然而,该模型并不自信,只输出了 52% 的概率。图 5-12的右侧显示了对预测影响最大的词。这些词似乎不应该与高质量的问题特别相关,所以让我们检查更多示例,看看该模型是否利用了更有用的模式。

为了快速了解趋势,我们可以对更大的问题样本使用 LIME。对每个问题运行 LIME 并汇总结果可以让我们了解我们的模型发现哪个词具有整体预测性以做出决策。

在图 5-13中,我们绘制了数据集中 500 个问题中最重要的预测。我们可以看到我们的模型利用常用词的趋势在这个更大的样本中也很明显。似乎该模型很难在利用常用词之外进行泛化。表示罕见词的词袋特征通常具有零值。为了改进这一点,我们可以收集更大的数据集以将我们的模型暴露在更多样化的词汇表中,或者创建不那么稀疏的特征。

图 5-13。解释多个例子

您通常会对您的模型最终使用的预测变量感到惊讶。如果任何特征对模型的预测能力超出您的预期,请尝试在您的训练数据中查找包含这些特征的示例并检查它们。借此机会仔细检查您如何拆分数据集并观察数据泄漏。

例如,在构建模型以根据电子邮件内容自动将电子邮件分类为不同主题时,我指导的一位 ML 工程师曾经发现,最好的预测指标是电子邮件顶部的三字母代码。事实证明,这是数据集的内部代码,几乎完美地映射到标签。该模型完全忽略了电子邮件的内容,并记住了一个预先存在的标签。这是数据泄漏的一个明显例子,只有通过查看特征重要性才能发现。

结论

在本章的开头,我们介绍了根据我们目前所学的一切来决定初始模型的标准。然后,我们介绍了将数据拆分为多个集合的重要性,以及避免数据泄漏的方法。

在训练了一个初始模型后,我们深入研究了通过寻找不同的方法来比较和对比其预测与数据来判断其表现如何的方法。最后,我们继续检查模型本身,方法是显示特征重要性并使用黑盒解释器来直观地了解它用于进行预测的特征。

到目前为止,您应该对可以对建模进行的改进有一些直觉。这将我们带入第 6 章的主题,我们将通过对 ML 管道进行调试和故障排除,更深入地探讨解决我们在此处出现的问题的方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/28152.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux 文件系统与inode,软硬链接

目录 磁盘的结构 磁盘的抽象(虚拟,逻辑)结构 分区 Block Group 块组: 分析: 文件名 vs inode编号 创建/删除/查看 一个文件,操作系统做了什么? 软硬链接 软连接 硬链接 对比&#xf…

Devart IBDac数据访问组件库

Devart IBDac数据访问组件库 IBDAC是一个完整的InterBase(和FireBird)数据访问组件库,用于将程序连接到FireBird、InterBase和Yaffil。该库有Dolphin、CBuilder、Lazarus和Free Pascal版本,可用于32/64位Windows、Mac OS X、iOS、Android、Linux和FreeBS…

Nacos Config--服务配置

目录 服务配置中心介绍 Nacos Config入门 Nacos Config深入 配置动态刷新 配置共享 nacos的几个概念 创建命名空间(Namespace) 命名空间 组 Nacos多环境切换 如何解决不同环境配置不同 如何解决不同环境配置相同 不同微服务相同配置共享 bootstrap 总结 服务配置…

融云 IM 和 RTC 服务,「助攻」智能物流等客户打通链路、完善生态

关注公众号报名融云&艾瑞“政企数智办公研究报告及新品发布会” 移动互联网时代,通信技术已经突破传统优势项“社交泛娱乐场景”的应用范围,在不同的业务中大放异彩,起到打通链路的关键作用。关注【融云全球互联网通信云】回复【融云】抽…

【数据挖掘】分类与回归预测

OutLine 章节概述1分类与预测2关于分类与预测中存在的问题3决策树分类4贝叶斯分类5BP网络分类6其他分类算法7预测8准确性与误差Chapter 1. 分类与预测 分类 预测分类标签,可以是离散数据或者是名义数据根据训练集和分类属性中的类标签对记录进行分类,…

【构建ML驱动的应用程序】第 6 章 :调试 ML 问题

🔎大家好,我是Sonhhxg_柒,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎 📝个人主页-Sonhhxg_柒的博客_CSDN博客 📃 🎁欢迎各位→点赞…

iTOP2K1000开发板Makefile文件

Makefile 就是描述了整个工程编译连接等规则的文件。 我们在终端输入完 make 命令之后,会调用 make 工具, make 就会在当前目录按照文件名就会找 makefile 文件, Makefile 的命名必须是 makefile 或 Makefile , m 大写小写都是可以…

ubuntu+Docker部署Django+Vue项目(1-Vue)

文章目录ubuntu安装下载Docker1.卸载(清除旧版本。没下载过也可以执行下试试)2.更新apt包索引并安装包,以允许apt通过HTTPS使用存储库3.添加Docker的官方GPG密钥4.使用以下命令设置存储库5.更新apt包索引6.安装最新版本的Docker Engine、containerd和Docker Compose…

概率论发展史上的几个重要悖论

1. 蒙提霍尔问题(三门问题) 三门问题(Monty Hall problem)亦称为蒙提霍尔问题、蒙特霍问题或蒙提霍尔悖论,大致出自美国的电视游戏节目Lets Make a Deal。问题名字来自该节目的主持人蒙提霍尔(Monty Hall&…

数字图像处理(十)腐蚀和膨胀

文章目录前言一、腐蚀1.概念2.算法的具体步骤3.举例4.python代码二、膨胀1.概念2.算法步骤3.举例4.C代码5. 结果展示参考资料前言 二值图像中一类主要处理是对提取的目标图形进行形态分析。形态学处理中最基本的是腐蚀和膨胀。   腐蚀和膨胀是两个互为对偶的运算。腐蚀的作用…

g++无法找到动态库问题

文章目录一、错误发现二、include两种查找方式三、路径1.gcc与g路径2.头文件路径(1)默认路径(2)使用-l指定路径寻找。(3)gcc搜索头文件的顺序3.库文件路径(1)默认路径(2)编译时指定路径(3)在配置文件中指定路径(4)通过环境变量(5)查找顺序一、错误发现 在使用各种各样的C库的时…

栈进阶:ElasticSearch

栈进阶:ElasticSearch 文章目录前言一、学习ES1、ES课程简介2、聊聊Lucene创始人3、ES概述1、历史2、谁在使用3、ELK简介4、Solr和ES的差别1、ES简介2、Solr简介3、Lucene简介4、ElasticSearch与Solr比较5、ES安装及head插件安装1、ES安装2、Window下安装3、安装可视…

【深入浅出Spring6】第十期——尾声

一、Spring集成了Junit 之前我们只是使用Junit的测试注解 Test&#xff0c;并没有使用Spring对于Junit的支持 Spring6既支持Junit4、也支持Spring5 要想使用Spring对于Junit的支持&#xff0c;我们需要在pom中导入相关依赖 <!--我们引入Spring对junit支持的依赖 >> …

[LeetCode/力扣][Java] 0315. 计算右侧小于当前元素的个数(Count of Smaller Numbers After Self)

题目描述&#xff1a; 给你一个整数数组 nums &#xff0c;按要求返回一个新数组 counts 。数组 counts 有该性质&#xff1a; counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。 示例1&#xff1a; 输入&#xff1a;nums [5,2,6,1] 输出&#xff1a;[2,1,1,0] 解释&…

CSS3------什么是css

什么是CSS 层叠样式表Cascading Style Sheets&#xff0c;缩写为CSS&#xff0c;是一种样式表语言&#xff0c;用来描述HTML或XML&#xff08;包括如SVG、MathML、XHTML 之类的XML 分支语言&#xff09;文档的呈现。 CSS描述了在屏幕、纸质、音频等其它媒体上的元素应该如何被…

uniapp之路由中携带参数跳转

目录 前言 一 路由跳转方式 1. 直接在 template中定义 2.直接在methods中定义 二 携带参数 1.在template中定义 2.在methods里定义 3. 拼接 前言 在我们写 uniapp 小程序时&#xff0c;时常遇到的就是路由携带参数进行跳转&#xff0c;这项功能似乎已成家常便饭一样&am…

(八)笔记.net core学习之特性Attribute声明、使用、验证

1.特性Attribute 特性&#xff1a;是用于在运行时传递程序中各种元素&#xff08;比如类、方法、结构、枚举、组件等&#xff09;的行为信息的声明性标签。您可以通过使用特性向程序添加声明性信息。一个声明性标签是通过放置在它所应用的元素前面的方括号&#xff08;[ ]&…

缺陷修改实践——replace函数的运用|思考?

目录介绍问题出现问题分析解决方法优化实现总结介绍 大家好&#xff0c;我是清风。今天给大家分享一个项目中遇到问题解决问题的案例&#xff0c;编程其实就是一个思考的过程&#xff0c;缺少思考就没有灵魂&#xff0c;遇到问题先静下心去思考&#xff0c;想到方法后再去实践。…

HTML小游戏11 —— 横版恐龙大冒险游戏(附完整源码)

&#x1f482; 网站推荐:【神级源码资源网】【摸鱼小游戏】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 想寻找共同学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】&#x1f4ac; 免费且实用的计…

U++ 插件学习笔记

Type&#xff1a; Editor&#xff1a;插件只能在编辑器有效 Runtime&#xff1a;代表打包出来也会有插件功能 Developer&#xff1a;开发者模式可以使用插件功能 Program&#xff1a;独立的小程序 ServerOnly&#xff1a;服务端可以使用插件功能 ClientOnly&#xff1a;客户…