FastAI 之书(面向程序员的 FastAI)(一)(2)

简介: FastAI 之书(面向程序员的 FastAI)(一)(2)

FastAI 之书(面向程序员的 FastAI)(一)(1)https://developer.aliyun.com/article/1482923

验证集

当您训练模型时,您必须始终同时拥有训练集和验证集,并且必须仅在验证集上测量模型的准确性。如果您训练时间过长,数据不足,您将看到模型的准确性开始变差;这被称为过拟合。fastai 将valid_pct默认设置为0.2,因此即使您忘记了,fastai 也会为您创建一个验证集!

我们的图像识别器训练代码的第五行告诉 fastai 创建一个卷积神经网络(CNN),并指定要使用的架构(即要创建的模型类型)、我们要对其进行训练的数据以及要使用的度量标准

learn = cnn_learner(dls, resnet34, metrics=error_rate)

为什么使用 CNN?这是创建计算机视觉模型的当前最先进方法。我们将在本书中学习有关 CNN 如何工作的所有知识。它们的结构受到人类视觉系统工作方式的启发。

在 fastai 中有许多架构,我们将在本书中介绍(以及讨论如何创建您自己的架构)。然而,大多数情况下,选择架构并不是深度学习过程中非常重要的部分。这是学术界喜欢谈论的内容,但实际上您不太可能需要花费太多时间。有一些标准架构在大多数情况下都有效,而在这种情况下,我们使用的是一种称为ResNet的架构,我们将在本书中大量讨论;它对许多数据集和问题都既快速又准确。resnet34中的34指的是该架构变体中的层数(其他选项是1850101152)。使用层数更多的架构模型训练时间更长,更容易过拟合(即在验证集上的准确率开始变差之前无法训练多少个时期)。另一方面,当使用更多数据时,它们可能会更准确。

什么是度量标准?度量标准是一个函数,使用验证集来衡量模型预测的质量,并将在每个时期结束时打印出来。在这种情况下,我们使用error_rate,这是 fastai 提供的一个函数,它正是它所说的:告诉您验证集中有多少百分比的图像被错误分类。分类的另一个常见度量标准是accuracy(即1.0 - error_rate)。fastai 提供了许多其他度量标准,这将在本书中讨论。

度量标准的概念可能会让您想起损失,但有一个重要区别。损失的整个目的是定义一个“性能度量”,训练系统可以使用它来自动更新权重。换句话说,损失的一个好选择是易于随机梯度下降使用的选择。但度量标准是为人类消费而定义的,因此一个好的度量标准是您易于理解的,并且尽可能接近您希望模型执行的任务。有时,您可能会决定损失函数是一个合适的度量标准,但这并不一定是情况。

cnn_learner还有一个名为pretrained的参数,默认值为True(因此在这种情况下使用,即使我们没有指定),它将您模型中的权重设置为已经由专家训练过的值,以识别 130 万张照片中的一千个不同类别(使用著名的ImageNet数据集)。具有已在另一个数据集上训练过的权重的模型称为预训练模型。您几乎总是应该使用预训练模型,因为这意味着您的模型在您甚至没有展示任何数据之前就已经非常有能力。正如您将看到的,在深度学习模型中,许多这些能力是您几乎无论项目细节如何都需要的。例如,预训练模型的部分将处理边缘、梯度和颜色检测,这些对许多任务都是必需的。

使用预训练模型时,cnn_learner将移除最后一层,因为该层始终是针对原始训练任务(即 ImageNet 数据集分类)专门定制的,并将其替换为一个或多个具有随机权重的新层,适合您正在处理的数据集的大小。模型的最后部分被称为

使用预训练模型是我们训练更准确、更快速、使用更少数据和更少时间和金钱的最重要方法。您可能会认为使用预训练模型将是学术深度学习中最研究的领域…但您会非常、非常错误!预训练模型的重要性通常在大多数课程、书籍或软件库功能中没有得到认可或讨论,并且在学术论文中很少被考虑。当我们在 2020 年初写这篇文章时,事情刚刚开始改变,但这可能需要一段时间。因此要小心:您与之交谈的大多数人可能会严重低估您可以在深度学习中使用少量资源做些什么,因为他们可能不会深入了解如何使用预训练模型。

使用一个预训练模型来执行一个与其最初训练目的不同的任务被称为迁移学习。不幸的是,由于迁移学习研究不足,很少有领域提供预训练模型。例如,目前在医学领域很少有预训练模型可用,这使得在该领域使用迁移学习具有挑战性。此外,目前还不清楚如何将迁移学习应用于诸如时间序列分析之类的任务。

术语:迁移学习

使用一个预训练模型来执行一个与其最初训练目的不同的任务。

我们代码的第六行告诉 fastai 如何适应模型:

learn.fine_tune(1)

正如我们所讨论的,架构只是描述数学函数的模板;直到我们为其包含的数百万参数提供值之前,它才会真正发挥作用。

这是深度学习的关键之处——确定如何适应模型的参数以使其解决您的问题。要适应一个模型,我们必须提供至少一条信息:每个图像查看多少次(称为时代数)。您选择的时代数将在很大程度上取决于您有多少时间可用,以及您发现在实践中适应模型需要多长时间。如果选择的数字太小,您可以随时稍后进行更多时代的训练。

但为什么这种方法被称为fine_tune,而不是fit?fastai 确实有一个名为fit的方法,它确实适合一个模型(即,多次查看训练集中的图像,每次更新参数使预测越来越接近目标标签)。但在这种情况下,我们已经从一个预训练模型开始,并且我们不想丢弃它已经具有的所有这些功能。正如您将在本书中了解到的,有一些重要的技巧可以使预训练模型适应新数据集,这个过程称为微调

术语:微调

一种迁移学习技术,通过使用与预训练不同的任务进行额外时代的训练来更新预训练模型的参数。

当您使用fine_tune方法时,fastai 将为您使用这些技巧。您可以设置一些参数(我们稍后会讨论),但在此处显示的默认形式中,它执行两个步骤:

  1. 使用一个时代来适应模型的那些部分,以使新的随机头部能够正确地与您的数据集配合工作。
  2. 在调用适合整个模型的方法时,请使用请求的时代数,更快地更新后面的层(特别是头部)的权重,而不是早期的层(正如我们将看到的,通常不需要对预训练权重进行太多更改)。

模型的头部是新添加的部分,专门针对新数据集。一个时代是对数据集的一次完整遍历。在调用fit之后,每个时代后的结果都会被打印出来,显示时代编号,训练和验证集的损失(用于训练模型的“性能度量”),以及您请求的任何指标(在这种情况下是错误率)。

因此,通过所有这些代码,我们的模型学会了仅仅通过标记的示例来识别猫和狗。但它是如何做到的呢?

我们的图像识别器学到了什么

在这个阶段,我们有一个工作良好的图像识别器,但我们不知道它在做什么!尽管许多人抱怨深度学习导致不可理解的“黑匣子”模型(即,可以提供预测但没有人能理解的东西),但事实并非如此。有大量研究表明如何深入检查深度学习模型并从中获得丰富的见解。话虽如此,各种机器学习模型(包括深度学习和传统统计模型)都可能难以完全理解,特别是考虑到它们在遇到与用于训练它们的数据非常不同的数据时的行为。我们将在本书中讨论这个问题。

2013 年,博士生 Matt Zeiler 和他的导师 Rob Fergus 发表了《可视化和理解卷积网络》,展示了如何可视化模型每一层学到的神经网络权重。他们仔细分析了赢得 2012 年 ImageNet 比赛的模型,并利用这一分析大大改进了模型,使他们能够赢得 2013 年的比赛!图 1-10 是他们发表的第一层权重的图片。

图 1-10。CNN 第一层的激活(由 Matthew D. Zeiler 和 Rob Fergus 提供)

这张图片需要一些解释。对于每一层,具有浅灰色背景的图像部分显示了重建的权重,底部较大的部分显示了与每组权重最匹配的训练图像部分。对于第一层,我们可以看到模型发现了代表对角线、水平和垂直边缘以及各种梯度的权重。(请注意,对于每一层,只显示了部分特征;实际上,在所有层中有成千上万个特征。)

这些是模型为计算机视觉学习的基本构建块。它们已经被神经科学家和计算机视觉研究人员广泛分析,结果表明,这些学习的构建块与人眼的基本视觉机制以及在深度学习之前开发的手工计算机视觉特征非常相似。下一层在图 1-11 中表示。

图 1-11。CNN 第二层的激活(由 Matthew D. Zeiler 和 Rob Fergus 提供)

对于第 2 层,模型找到的每个特征都有九个权重重建示例。我们可以看到模型已经学会创建寻找角、重复线条、圆圈和其他简单模式的特征检测器。这些是从第一层中开发的基本构建块构建的。对于每个特征,图片右侧显示了与这些特征最匹配的实际图像的小块。例如,第 2 行第 1 列中的特定模式与日落相关的梯度和纹理相匹配。

图 1-12 显示了一篇论文中展示第 3 层特征重建结果的图片。

图 1-12。CNN 第三层的激活(由 Matthew D. Zeiler 和 Rob Fergus 提供)

通过观察图片右侧,您可以看到特征现在能够识别和匹配更高级的语义组件,如汽车车轮、文字和花瓣。利用这些组件,第 4 层和第 5 层可以识别更高级的概念,如图 1-13 所示。

图 1-13。CNN 的第四和第五层的激活(由 Matthew D. Zeiler 和 Rob Fergus 提供)

本文研究了一个名为AlexNet的旧模型,该模型只包含五层。自那时以来开发的网络可以有数百层 - 所以你可以想象这些模型开发的特征有多丰富!

当我们早期微调我们的预训练模型时,我们调整了最后几层关注的内容(花朵、人类、动物),以专注于猫与狗问题。更一般地,我们可以将这样的预训练模型专门用于许多不同的任务。让我们看一些例子。

图像识别器可以处理非图像任务

图像识别器只能识别图像,顾名思义。但很多事物可以被表示为图像,这意味着图像识别器可以学会完成许多任务。

例如,声音可以转换为频谱图,这是一种图表,显示音频文件中每个时间的每个频率的数量。fast.ai 学生 Ethan Sutin 使用这种方法,轻松击败了一种最先进的环境声音检测模型的发布准确率,使用了 8732 个城市声音的数据集。fastai 的show_batch清楚地显示了每个声音具有相当独特的频谱图,如图 1-14 所示。

图 1-14。显示具有声音频谱图的 show_batch

时间序列可以很容易地通过简单地在图表上绘制时间序列来转换为图像。然而,通常最好尝试以尽可能简单的方式表示数据,以便提取出最重要的组件。在时间序列中,季节性和异常很可能是感兴趣的。

时间序列数据有各种转换方法。例如,fast.ai 学生 Ignacio Oguiza 使用一种称为 Gramian Angular Difference Field(GADF)的技术,从一个时间序列数据集中为橄榄油分类创建图像,你可以在图 1-15 中看到结果。然后,他将这些图像输入到一个图像分类模型中,就像你在本章中看到的那样。尽管只有 30 个训练集图像,但他的结果准确率超过 90%,接近最先进水平。

图 1-15。将时间序列转换为图像

另一个有趣的 fast.ai 学生项目示例来自 Gleb Esman。他在 Splunk 上进行欺诈检测,使用了用户鼠标移动和鼠标点击的数据集。他通过绘制显示鼠标指针位置、速度和加速度的图像,使用彩色线条,并使用小彩色圆圈显示点击,将这些转换为图片,如图 1-16 所示。他将这些输入到一个图像识别模型中,就像我们在本章中使用的那样,效果非常好,导致了这种方法在欺诈分析方面的专利!

图 1-16。将计算机鼠标行为转换为图像

另一个例子来自 Mahmoud Kalash 等人的论文“使用深度卷积神经网络进行恶意软件分类”,解释了“恶意软件二进制文件被分成 8 位序列,然后转换为等效的十进制值。这个十进制向量被重塑,生成了一个代表恶意软件样本的灰度图像”,如图 1-17 所示。

图 1-17。恶意软件分类过程

作者们随后展示了通过恶意软件分类生成的“图片”,如图 1-18 所示。

图 1-18。恶意软件示例

正如您所看到的,不同类型的恶意软件在人眼中看起来非常独特。研究人员基于这种图像表示训练的模型在恶意软件分类方面比学术文献中显示的任何先前方法都更准确。这表明将数据集转换为图像表示的一个很好的经验法则:如果人眼可以从图像中识别类别,那么深度学习模型也应该能够做到。

总的来说,您会发现在深度学习中,少数几种通用方法可以走得很远,只要您在如何表示数据方面有点创造性!您不应该将这里描述的方法视为“巧妙的变通方法”,因为它们通常(如此处)击败了以前的最先进结果。这确实是正确思考这些问题领域的方法。

术语回顾

我们刚刚涵盖了很多信息,让我们简要回顾一下。表 1-3 提供了一个方便的词汇表。

表 1-3. 深度学习词汇表

术语 意义
标签 我们试图预测的数据,比如“狗”或“猫”
架构 我们试图拟合的模型的 * 模板 *;即我们将输入数据和参数传递给的实际数学函数
模型 架构与特定一组参数的组合
参数 模型中改变任务的值,通过模型训练进行更新
拟合 更新模型的参数,使得使用输入数据的模型预测与目标标签匹配
训练 * 拟合 * 的同义词
预训练模型 已经训练过的模型,通常使用大型数据集,并将进行微调
微调 为不同任务更新预训练模型
纪元 一次完整通过输入数据
损失 衡量模型好坏的指标,选择以驱动通过 SGD 进行训练
指标 使用验证集衡量模型好坏的测量标准,选择供人类消费
验证集 从训练中保留的一组数据,仅用于衡量模型好坏
训练集 用于拟合模型的数据;不包括验证集中的任何数据
过拟合 以使模型 * 记住 * 输入数据的特定特征而不是很好地泛化到训练期间未见的数据的方式训练模型
CNN 卷积神经网络;一种特别适用于计算机视觉任务的神经网络

有了这个词汇表,我们现在可以将迄今介绍的所有关键概念汇集在一起。花点时间回顾这些定义,并阅读以下摘要。如果您能理解解释,那么您就有能力理解接下来的讨论。

  • 机器学习 *是一种学科,我们通过从数据中学习来定义程序,而不是完全自己编写它。 * 深度学习 *是机器学习中使用具有多个 * 层 * 的 * 神经网络 * 的专业领域。 * 图像分类 * 是一个代表性的例子(也称为 * 图像识别 *)。我们从 * 标记数据 * 开始 - 一组我们为每个图像分配了 * 标签 * 的图像,指示它代表什么。我们的目标是生成一个称为 * 模型 * 的程序,给定一个新图像,将对该新图像代表的内容进行准确的 * 预测 *。

每个模型都从选择 * 架构 * 开始,这是该类型模型内部工作方式的一般模板。 * 训练 *(或 * 拟合 *)模型的过程是找到一组 * 参数值 *(或 * 权重 *),这些参数值将该一般架构专门化为适用于我们特定数据类型的模型。为了定义模型在单个预测上的表现如何,我们需要定义一个 * 损失函数 *,它确定我们如何将预测评分为好或坏。

为了让训练过程更快,我们可以从一个预训练模型开始——一个已经在其他人的数据上训练过的模型。然后我们可以通过在我们的数据上进一步训练它来使其适应我们的数据,这个过程称为微调

当我们训练一个模型时,一个关键问题是确保我们的模型泛化:它从我们的数据中学到的一般性教训也适用于它将遇到的新项目,这样它就可以对这些项目做出良好的预测。风险在于,如果我们训练模型不当,它实际上会记住它已经看到的内容,而不是学习一般性教训,然后它将对新图像做出糟糕的预测。这样的失败被称为过拟合

为了避免这种情况,我们总是将数据分为两部分,训练集验证集。我们通过只向模型展示训练集来训练模型,然后通过查看模型在验证集中的表现来评估模型的表现如何。通过这种方式,我们检查模型从训练集中学到的教训是否适用于验证集。为了评估模型在验证集上的整体表现,我们定义一个度量。在训练过程中,当模型看到训练集中的每个项目时,我们称之为一个周期

所有这些概念都适用于机器学习。它们适用于各种通过训练数据定义模型的方案。深度学习的独特之处在于一类特定的架构:基于神经网络的架构。特别是,像图像分类这样的任务在卷积神经网络上严重依赖,我们将很快讨论。

深度学习不仅仅适用于图像分类

近年来,深度学习在分类图像方面的有效性已经被广泛讨论,甚至在识别 CT 扫描中的恶性肿瘤等复杂任务上显示出超人类的结果。但它可以做的远不止这些,正如我们将在这里展示的。

例如,让我们谈谈对于自动驾驶汽车至关重要的一点:在图片中定位物体。如果自动驾驶汽车不知道行人在哪里,那么它就不知道如何避开!创建一个能够识别图像中每个单独像素内容的模型被称为分割。以下是我们如何使用 fastai 训练一个分割模型,使用来自 Gabriel J. Brostow 等人的论文“视频中的语义对象类:高清实况数据库”中的CamVid数据集的子集:

path = untar_data(URLs.CAMVID_TINY)
dls = SegmentationDataLoaders.from_label_func(
    path, bs=8, fnames = get_image_files(path/"images"),
    label_func = lambda o: path/'labels'/f'{o.stem}_P{o.suffix}',
    codes = np.loadtxt(path/'codes.txt', dtype=str)
)
learn = unet_learner(dls, resnet34)
learn.fine_tune(8)
epoch train_loss valid_loss time
0 2.906601 2.347491 00:02
epoch train_loss valid_loss time
0 1.988776 1.765969 00:02
1 1.703356 1.265247 00:02
2 1.591550 1.309860 00:02
3 1.459745 1.102660 00:02
4 1.324229 0.948472 00:02
5 1.205859 0.894631 00:02
6 1.102528 0.809563 00:02
7 1.020853 0.805135 00:02

我们甚至不会逐行走过这段代码,因为它几乎与我们之前的示例完全相同!(我们将在第十五章深入探讨分割模型,以及本章中我们简要介绍的所有其他模型以及更多更多。)

我们可以通过要求模型为图像的每个像素着色来可视化它的任务完成情况。正如您所看到的,它几乎完美地对每个对象中的每个像素进行分类。例如,请注意所有的汽车都被叠加着相同的颜色,所有的树都被叠加着相同的颜色(在每对图像中,左侧图像是地面实况标签,右侧是模型的预测):

learn.show_results(max_n=6, figsize=(7,8))

另一个深度学习在过去几年显著改进的领域是自然语言处理(NLP)。计算机现在可以生成文本,自动从一种语言翻译到另一种语言,分析评论,标记句子中的单词等等。以下是训练一个模型所需的所有代码,该模型可以比五年前世界上任何东西更好地分类电影评论的情感:

from fastai.text.all import *
dls = TextDataLoaders.from_folder(untar_data(URLs.IMDB), valid='test')
learn = text_classifier_learner(dls, AWD_LSTM, drop_mult=0.5, metrics=accuracy)
learn.fine_tune(4, 1e-2)
epoch train_loss valid_loss accuracy time
0 0.594912 0.407416 0.823640 01:35
epoch train_loss valid_loss accuracy time
0 0.268259 0.316242 0.876000 03:03
1 0.184861 0.246242 0.898080 03:10
2 0.136392 0.220086 0.918200 03:16
3 0.106423 0.191092 0.931360 03:15

这个模型使用了 Andrew Maas 等人的论文“Learning Word Vectors for Sentiment Analysis”中的IMDb Large Movie Review dataset。它在许多千字长的电影评论中表现良好,但让我们在一个短评论上测试一下看看它的表现如何:

learn.predict("I really liked that movie!")
('pos', tensor(1), tensor([0.0041, 0.9959]))

在这里我们可以看到模型认为评论是积极的。结果的第二部分是我们数据词汇中“pos”的索引,最后一部分是分配给每个类的概率(“pos”为 99.6%,“neg”为 0.4%)。

现在轮到你了!写下你自己的迷你电影评论,或者从互联网上复制一个,看看这个模型对它的看法。

如果您对 fastai 的任何方法有任何疑问,您应该使用doc函数,将方法名称传递给它:

doc(learn.predict)

一个窗口弹出,包含一个简短的一行解释。 “在文档中显示”链接将带您到完整的文档,在那里您将找到所有细节和许多示例。此外,fastai 的大多数方法只是几行代码,因此您可以单击“源”链接查看幕后发生的情况。

让我们继续讨论一些不那么性感,但可能在商业上更有用的事情:从普通表格数据构建模型。

术语:表格

表格形式的数据,例如来自电子表格、数据库或逗号分隔值(CSV)文件。表格模型是一种试图根据表格中其他列的信息来预测表格中一列的模型。

事实证明,这看起来非常相似。以下是训练一个模型所需的代码,该模型将根据个人的社会经济背景预测一个人是否是高收入者:

from fastai.tabular.all import *
path = untar_data(URLs.ADULT_SAMPLE)
dls = TabularDataLoaders.from_csv(path/'adult.csv', path=path, y_names="salary",
    cat_names = ['workclass', 'education', 'marital-status', 'occupation',
                 'relationship', 'race'],
    cont_names = ['age', 'fnlwgt', 'education-num'],
    procs = [Categorify, FillMissing, Normalize])
learn = tabular_learner(dls, metrics=accuracy)

正如您所看到的,我们不得不告诉 fastai 哪些列是分类(包含一组离散选择之一的值,例如occupation)与连续(包含表示数量的数字,例如age)。

这个任务没有预训练模型可用(一般来说,预训练模型在任何表格建模任务中都不广泛可用,尽管一些组织已经为内部使用创建了这些模型),所以在这种情况下我们不使用fine_tune。相反,我们使用fit_one_cycle,这是训练 fastai 模型从头开始(即没有迁移学习)最常用的方法:

learn.fit_one_cycle(3)
epoch train_loss valid_loss accuracy time
0 0.359960 0.357917 0.831388 00:11
1 0.353458 0.349657 0.837991 00:10
2 0.338368 0.346997 0.843213 00:10

这个模型使用了 Ron Kohavi 的论文“Scaling Up the Accuracy of Naive-Bayes Classifiers: a Decision-Tree Hybrid”中的Adult数据集,其中包含一些关于个人的人口统计数据(如他们的教育、婚姻状况、种族、性别以及是否年收入超过 5 万美元)。该模型的准确率超过 80%,训练时间约为 30 秒。

让我们再看一个例子。推荐系统很重要,特别是在电子商务中。像亚马逊和 Netflix 这样的公司努力推荐用户可能喜欢的产品或电影。以下是如何训练一个模型,根据用户以前的观影习惯,预测用户可能喜欢的电影,使用MovieLens 数据集

from fastai.collab import *
path = untar_data(URLs.ML_SAMPLE)
dls = CollabDataLoaders.from_csv(path/'ratings.csv')
learn = collab_learner(dls, y_range=(0.5,5.5))
learn.fine_tune(10)
epoch train_loss valid_loss time
0 1.554056 1.428071 00:01
epoch train_loss valid_loss time
0 1.393103 1.361342 00:01
1 1.297930 1.159169 00:00
2 1.052705 0.827934 00:01
3 0.810124 0.668735 00:01
4 0.711552 0.627836 00:01
5 0.657402 0.611715 00:01
6 0.633079 0.605733 00:01
7 0.622399 0.602674 00:01
8 0.629075 0.601671 00:00
9 0.619955 0.601550 00:01

这个模型在 0.5 到 5.0 的范围内预测电影评分,平均误差约为 0.6。由于我们预测的是一个连续数值,而不是一个类别,我们必须告诉 fastai 我们的目标范围是多少,使用y_range参数。

虽然我们实际上并没有使用预训练模型(和表格模型一样的原因),但这个例子显示了 fastai 在这种情况下仍然让我们使用fine_tune(您将在第五章中学习到这是如何以及为什么有效)。有时最好尝试fine_tunefit_one_cycle,看看哪个对您的数据集效果更好。

我们可以使用之前看到的相同的show_results调用来查看一些用户和电影 ID、实际评分和预测:

learn.show_results()
userId movieId rating rating_pred
0 157 1200 4.0 3.558502
1 23 344 2.0 2.700709
2 19 1221 5.0 4.390801
3 430 592 3.5 3.944848
4 547 858 4.0 4.076881
5 292 39 4.5 3.753513
6 529 1265 4.0 3.349463
7 19 231 3.0 2.881087
8 475 4963 4.0 4.023387
9 130 260 4.5 3.979703

我们训练的每个模型都显示了训练和验证损失。一个好的验证集是训练过程中最重要的部分之一。让我们看看为什么,并学习如何创建一个。

验证集和测试集

正如我们所讨论的,模型的目标是对数据进行预测。但模型训练过程基本上是愚蠢的。如果我们用所有的数据训练一个模型,然后使用同样的数据评估模型,我们将无法判断我们的模型在未见过的数据上表现如何。没有这个非常宝贵的信息来指导我们训练模型,很有可能模型会擅长对这些数据进行预测,但在新数据上表现不佳。

为了避免这种情况,我们的第一步是将数据集分成两组:训练集(模型在训练中看到的)和验证集,也称为开发集(仅用于评估)。这样我们可以测试模型是否从训练数据中学到的经验可以推广到新数据,即验证数据。

理解这种情况的一种方式是,在某种意义上,我们不希望我们的模型通过“作弊”来获得好的结果。如果它对一个数据项做出准确的预测,那应该是因为它已经学到了那种类型的特征,而不是因为模型已经被实际看到那个特定项所塑造。

将验证数据集分离出来意味着我们的模型在训练中从未见过它,因此完全没有被它污染,并且没有以任何方式作弊。对吧?

实际上,并非一定如此。情况更为微妙。这是因为在现实场景中,我们很少仅通过一次训练参数来构建模型。相反,我们可能通过各种建模选择来探索模型的许多版本,包括网络架构、学习率、数据增强策略等因素,我们将在接下来的章节中讨论。其中许多选择可以描述为超参数的选择。这个词反映了它们是关于参数的参数,因为它们是控制权重参数含义的高级选择。

问题在于,即使普通的训练过程只看训练数据的预测结果来学习权重参数的值,我们却不是这样。作为建模者,当我们决定探索新的超参数值时,我们通过查看验证数据的预测结果来评估模型!因此,模型的后续版本间接地受到我们看到验证数据的影响。就像自动训练过程有过拟合训练数据的危险一样,我们通过人为试错和探索有过拟合验证数据的危险。

解决这个难题的方法是引入另一个更高度保留数据的层级:测试集。就像我们在训练过程中保留验证数据一样,我们必须连自己都不使用测试集数据。它不能用来改进模型;它只能在我们努力的最后阶段用来评估模型。实际上,我们定义了一个基于我们希望如何完全隐藏数据的层次结构:训练数据完全暴露,验证数据较少暴露,测试数据完全隐藏。这种层次结构与不同种类的建模和评估过程本身相对应——自动训练过程与反向传播,尝试不同超参数之间的更手动过程,以及我们最终结果的评估。

测试集和验证集应该有足够的数据来确保您对准确性有一个良好的估计。例如,如果您正在创建一个猫检测器,通常您希望验证集中至少有 30 只猫。这意味着如果您有数千个项目的数据集,使用默认的 20%验证集大小可能超出您的需求。另一方面,如果您有大量数据,将其中一部分用于验证可能没有任何不利之处。

拥有两个级别的“保留数据”——验证集和测试集,其中一个级别代表您几乎隐藏自己的数据——可能看起来有点极端。但通常是必要的,因为模型往往倾向于朝着做出良好预测的最简单方式(记忆)发展,而我们作为易犯错误的人类往往倾向于欺骗自己关于我们的模型表现如何。测试集的纪律帮助我们保持思想上的诚实。这并不意味着我们总是需要一个单独的测试集——如果您的数据很少,您可能只需要一个验证集——但通常最好尽可能使用一个。

如果您打算雇用第三方代表您进行建模工作,这种纪律也可能至关重要。第三方可能无法准确理解您的要求,或者他们的激励甚至可能鼓励他们误解。一个好的测试集可以极大地减轻这些风险,并让您评估他们的工作是否解决了您实际的问题。

直截了当地说,如果你是组织中的高级决策者(或者你正在为高级决策者提供建议),最重要的要点是:如果你确保真正理解测试和验证集以及它们的重要性,你将避免我们看到的组织决定使用 AI 时最大的失败源。例如,如果你考虑引入外部供应商或服务,请确保保留一些测试数据,供供应商永远看不到。然后在你的测试数据上检查他们的模型,使用根据实际情况选择的度量标准,并决定什么水平的性能是足够的。(你自己尝试一个简单的基线也是个好主意,这样你就知道一个真正简单的模型能够实现什么。通常情况下,你的简单模型的表现会和外部“专家”制作的模型一样好!)

在定义测试集时要有判断力

要很好地定义验证集(以及可能的测试集),有时你需要做的不仅仅是随机抽取原始数据集的一部分。记住:验证和测试集的一个关键特性是它们必须代表你将来看到的新数据。这听起来可能像一个不可能的要求!根据定义,你还没有看到这些数据。但通常你仍然会知道一些事情。

看一些例子是很有启发性的。这些例子中的许多来自于Kaggle平台上的预测建模竞赛,这是你可能在实践中看到的问题和方法的很好代表。

一个情况可能是当你在查看时间序列数据时。对于时间序列,选择数据的随机子集既太容易(你可以查看你试图预测的日期之前和之后的数据),又不代表大多数业务用例(在这些用例中,你使用历史数据构建模型以供将来使用)。如果你的数据包含日期,并且你正在构建一个将来使用的模型,你将希望选择最新日期的连续部分作为验证集(例如,可用数据的最后两周或最后一个月)。

假设你想将图 1-19 中的时间序列数据分成训练集和验证集。

图 1-19. 一个时间序列

一个随机子集是一个糟糕的选择(填补缺失太容易,且不代表你在生产中所需的),正如我们在图 1-20 中所看到的。


FastAI 之书(面向程序员的 FastAI)(一)(3)https://developer.aliyun.com/article/1482926

相关文章
|
1月前
|
XML 数据可视化 编译器
MuJoCo 入门教程(一)(上)
MuJoCo 入门教程(一)
245 2
|
1月前
|
传感器 XML 存储
MuJoCo 入门教程(一)(下)
MuJoCo 入门教程(一)(上)
169 3
|
4月前
|
机器学习/深度学习 算法 程序员
FastAI 之书(面向程序员的 FastAI)(三)(4)
FastAI 之书(面向程序员的 FastAI)(三)(4)
59 2
|
4月前
|
机器学习/深度学习 PyTorch 程序员
FastAI 之书(面向程序员的 FastAI)(二)(3)
FastAI 之书(面向程序员的 FastAI)(二)(3)
66 2
|
4月前
|
机器学习/深度学习 PyTorch 程序员
FastAI 之书(面向程序员的 FastAI)(二)(4)
FastAI 之书(面向程序员的 FastAI)(二)(4)
60 2
|
4月前
|
机器学习/深度学习 算法 数据挖掘
FastAI 之书(面向程序员的 FastAI)(四)(4)
FastAI 之书(面向程序员的 FastAI)(四)
81 1
|
4月前
|
机器学习/深度学习 自然语言处理 程序员
FastAI 之书(面向程序员的 FastAI)(三)(1)
FastAI 之书(面向程序员的 FastAI)(三)(1)
57 2
|
4月前
|
PyTorch 程序员 API
FastAI 之书(面向程序员的 FastAI)(三)(3)
FastAI 之书(面向程序员的 FastAI)(三)(3)
54 2
|
4月前
|
机器学习/深度学习 PyTorch 程序员
FastAI 之书(面向程序员的 FastAI)(三)(2)
FastAI 之书(面向程序员的 FastAI)(三)(2)
93 2
|
4月前
|
机器学习/深度学习 自然语言处理 搜索推荐
FastAI 之书(面向程序员的 FastAI)(一)(3)
FastAI 之书(面向程序员的 FastAI)(一)(3)
59 0