普通程序员深度学习教程(fastai及PyTorch)1深度学习快速入门-2第一个模型

1.5第一个模型
正如我们之前所说的,我们将先教你如何做事情,然后再解释为什么它们能起作用。按照这种自上而下的方法,我们将首先实际训练一个图像分类器,以几乎100%的准确率识别猫和狗。为了训练这个模型并运行我们的实验,你需要进行一些初始设置。别担心,这并不像看起来那么难。

要完成本书中的几乎所有内容,你需要使用一台配备英伟达™(NVIDIA®)GPU 的计算机(不幸的是,主要深度学习库并不完全支持其他品牌的 GPU)。

图形处理器(GPU Graphics Processing Unit)也称图形卡。电脑中的一种特殊处理器,可同时处理数千个单项任务,特别设计用于在电脑上显示 3D 环境以玩游戏。这些基本任务与神经网络的工作非常相似,因此 GPU 运行神经网络的速度比普通 CPU 快数百倍。所有现代计算机都包含 GPU,但很少有计算机包含深度学习所需的 GPU。

1.5.1 第一个实例

Jupyter Notebook可以在单个交互式文档中包含格式化文本、代码、、视频等。Jupyter 因其在许多学术领域和工业界的广泛应用和巨大影响,获得了软件界的最高荣誉–ACM 软件系统奖。Jupyter Notebook 是数据科学家最广泛使用的软件,用于开发深度学习模型并与之交互。

你将用Jupyter Notebook 来训练一个可以识别猫狗照片的模型。为此,你将下载一个猫狗照片数据集,并用它来训练一个模型。

数据集就是一堆数据–可以是、电子邮件、财务指标、声音或其他任何东西。有许多免费提供的数据集适合用于训练模型。其中许多数据集是由学者创建的,以帮助推进研究;许多数据集是为竞赛而提供的(数据科学家可以在竞赛中比拼谁的模型最准确!);还有一些数据集是其他流程的副产品(如财务申报)。

Notebook由单元格组成。单元格主要有两种类型:

包含格式化文本、等的单元格。这些单元格使用一种名为 Markdown 的格式,你很快就会了解到。

包含可执行代码的单元格,其下方会立即显示输出结果(可能是纯文本、表格、图像、动画、声音,甚至是交互式应用程序)。

Jupyter 笔记本有两种模式:编辑模式或命令模式。在编辑模式下,通过键盘输入字母,就能以通常的方式将字母输入到单元格中。但在命令模式下,你将看不到任何闪烁的光标,键盘上的每个键都有特殊功能。

在继续之前,请按下键盘上的 Escape 键切换到命令模式(如果已经进入命令模式,则按下 Escape 键不会有任何作用,所以现在按下以防万一)。要查看所有可用功能的完整列表,请按H键;按 Escape 键可移除帮助屏幕。请注意,在命令模式下,与大多数程序不同,命令无需按住 Control、Alt 或类似键,只需按下所需的字母键即可。

按 C 键可以复制一个单元格(首先需要选中该单元格,该单元格周围有轮廓指示;如果尚未选中,请单击该单元格一次)。然后按 V 粘贴副本。

单击以 “# CLICK ME “开头的单元格将其选中。该行的第一个字符表示后面的内容是 Python 中的注释,因此在执行单元格时会忽略它。单元格的其余部分是一个完整的系统,用于创建和训练最先进的猫狗识别模型。那么,我们现在就来训练它!为此,只需按下键盘上的 Shift-Enter 键,或单击工具栏上的 “播放 “按钮。然后等待几分钟,下面的事情就会发生:

我们将从 fast.ai 数据集库中下载一个名为牛津国际理工学院宠物数据集(Oxford-IIIT Pet Dataset)的数据集到您使用的 GPU 服务器上,该数据集包含 37 个品种的 7349 张猫和狗的图像,然后进行提取。

我们将从互联网上下载一个预训练模型,该模型已使用竞赛获奖模型在 130 万张图像上进行过训练。

预训练模型将利用迁移学习的最新进展进行微调,以创建一个专门用于识别猫狗的模型。

前两个步骤只需在 GPU 服务器上运行一次。如果再次运行该单元,它将使用已经下载的数据集和模型,而不是再次下载。让我们来看看单元格的内容和结果:

– coding: utf-8 –

from fastai.vision.all import *
path = untar_data(URLs.PETS)/’images’

def is_cat(x):
return x[0].isupper()
dls = ImageDataLoaders.from_name_func(
path, get_image_files(path), valid_pct=0.2, seed=42,
label_func=is_cat, item_tfms=Resize(224))

learn = cnn_learner(dls, resnet34, metrics=error_rate)
learn.fine_tune(1)

第一次训练的结果

您可能不会看到与这里显示的完全相同的结果。在训练模型的过程中,会出现很多微小的随机变化。不过,在这个例子中,我们通常可以看到误差率远小于 0.02。

根据网络速度,下载预训练模型和数据集可能需要几分钟时间。运行fine_tune 可能需要一分钟左右。本书中的模型通常需要几分钟的训练时间,你自己的模型也是如此,所以最好能想出一些好方法来充分利用这段时间。

在表格的最后一列,您可以看到错误率,即错误识别的比例。错误率是我们衡量模型质量的标准,选择它的目的是为了直观易懂。正如您所看到的,尽管训练时间只有几秒钟(不包括一次性下载数据集和预训练模型的时间),但模型几乎是完美的。事实上,您所取得的准确率已经远远超过了10年前任何人所取得的准确率!

最后,让我们来检验一下这个模型是否真的有效。去找一张猫狗的照片:

img = PILImage.create(r’d:\img\cat.png’)
img.to_thumb(192)
is_cat,_,probs = learn.predict(img)
print(f”Is this a cat?: {is_cat}.”)
print(f”Probability it’s a cat: {probs[1].item():.6f}”)

恭喜你建立了第一个分类器!

1.5.2 什么是机器学习?

深度学习只是机器学习这一更广泛学科中的一个现代领域。要理解你在训练自己的分类模型时所做工作的本质,你并不需要了解深度学习。只需了解你的模型和训练过程是如何应用于一般机器学习概念的示例就足够了。

我们将介绍机器学习。我们将探讨关键概念,并了解如何将它们追溯到引入这些概念的原始论文。

机器学习和普通编程一样,是一种让计算机完成特定任务的方法。但是,我们如何使用常规编程来完成上一节中的任务:识别照片中的狗和猫?我们必须为计算机写下完成任务所需的确切步骤。

通常,我们在编写程序时很容易写下完成任务的步骤。我们只要想一想,如果我们必须手工完成任务,我们会采取哪些步骤,然后将它们转化为代码。例如,我们可以编写一个对列表排序的函数。一般来说,我们会写一个类似下图的函数(输入可能是一个未排序的列表,结果是一个已排序的列表)。

但对于识别照片中的物体来说,这就有点棘手了;当我们识别照片中的物体时,我们会采取哪些步骤呢?我们真的不知道,因为这一切都发生在我们的大脑中,而我们却没有意识到!

早在计算机诞生之初,即1949年阿瑟-塞缪尔(Arthur Samuel)的 IBM 研究员就开始研究一种让计算机完成任务的不同方法,他称之为机器学习。在他 1962 年发表的经典论文《人工智能:自动化的前沿(Artificial Intelligence: A Frontier of Automation)》中,他提出了 “机器学习 ”的概念: 自动化的前沿》一文中写道:

对计算机进行编程以完成此类计算充其量只是一项艰巨的任务,这主要不是因为计算机本身有任何固有的复杂性,而是因为需要最令人恼火地详细说明过程中的每一个微小步骤。任何程序员都会告诉你,计算机是巨大的白痴,而不是巨大的大脑。

他的基本想法是:与其告诉计算机解决问题所需的确切步骤,不如向它展示要解决问题的示例,让它自己想办法解决。结果证明这个方法非常有效:到1961年,他的跳棋程序已经学会了很多东西,以至于击败了康涅狄格州的冠军!下面是他对自己想法的描述(摘自前面提到的同一篇文章):

假设我们安排了一些自动方法,以测试当前任何权重分配在实际性能方面的有效性,并提供一种机制来改变权重分配,从而最大限度地提高性能。我们不需要深入探讨这种程序的细节,就可以知道它可以完全自动完成,而且这样编程的机器会从它的经验中 “学习”。
这句简短的话蕴含着许多强大的概念:

权重分配
每个权重分配都有一定的“实际表现(actual performance ”这一事实
要求有一种 “自动方式 (automatic means)”来测试这种性能
需要一种 “机制”(即另一种自动程序),通过改变权重分配来提高性能
让我们逐一讨论这些概念,以了解它们在实践中是如何结合在一起的。首先,我们需要了解塞缪尔所说的权重分配是什么意思。

权重只是变量,而权重分配则是对这些变量值的特定选择。程序的输入是它为产生结果而处理的值–例如,将图像像素作为输入,并返回分类结果 “狗”。程序的权重分配是定义程序运行方式的其他值。

因为它们会对程序产生影响,所以从某种意义上说,它们是另一种输入。

我们已将程序框的名称从 “程序 ”改为 “模型”。这是为了遵循现代术语,并反映出模型是一种特殊的程序:它可以根据权重做许多不同的事情。它可以以多种不同的方式实现。例如,在塞缪尔的跳棋程序中,不同的权重值会产生不同的跳棋策略。

(顺便说一句,塞缪尔所说的 “权重 ”如今一般被称为模型参数,以防你遇到过这个词)。权重一词专指特定类型的模型参数)。

接下来,塞缪尔说我们需要一种自动的方法来测试当前权重分配在实际性能方面的有效性。就他的跳棋程序而言,模型的 “实际性能”就是它的下棋水平。你可以自动测试两个模型的性能,方法是设置它们相互对弈,看看哪个模型通常会赢。

最后,他说我们需要一种机制来改变权重分配,从而最大限度地提高性能。例如,我们可以查看获胜模型和失败模型之间的权重差异,然后向获胜方向调整权重。

我们现在可以理解为什么他说这样的程序可以完全自动完成,而且这样编程的机器会从经验中 “学习”。当权重的调整也是自动的时候,学习就会变得完全自动–我们不再通过手动调整权重来改进模型,而是依靠一种自动机制来根据表现进行调整。

请注意模型的结果(如跳棋游戏中的棋步)和性能(如是否赢得游戏或赢得速度)之间的区别。

还要注意的是,一旦模型训练完成,也就是说,一旦我们选择了最终的、最好的、最喜欢的权重分配,我们就可以认为权重是模型的一部分,因为我们不再改变权重了。

训练好的模型可以像普通计算机程序一样处理。

机器学习:通过让计算机从自己的经验中学习,而不是通过手动编码各个步骤来开发程序的训练。

1.5.3 什么是神经网络?

不难想象跳棋程序的模型是什么样的。可能会有一系列跳棋策略编码和某种搜索机制,然后权重可以改变选择策略的方式、搜索过程中关注棋盘的哪些部分等等。但是,对于图像识别程序、理解文本或我们可能想象到的许多其他有趣的问题来说,这个模型可能是什么样的,这一点都不明显。

我们需要的是一种非常灵活的函数,只要改变它的权重,就能解决任何问题。令人惊奇的是,这种函数确实存在!这就是我们已经讨论过的神经网络。也就是说,如果把神经网络看成一个数学函数,它就会变成一个根据权重而极其灵活的函数。一个名为 “通用近似定理 ”的数学证明表明,从理论上讲,这个函数可以以任何精度解决任何问题。神经网络如此灵活这一事实意味着,在实践中,神经网络通常是一种合适的模型,你可以将精力集中在训练神经网络的过程中,也就是找到好的权重分配。

但这个过程又是怎样的呢?我们可以想象,您可能需要找到一种新的 “机制 ”来自动更新每个问题的权重。这将非常费力。在这里,我们也希望有一种完全通用的方法来更新神经网络的权重,使其在任何给定任务中都能有所改进。方便的是,这种方法也存在!
这就是随机梯度下降法(SGD stochastic gradient descent)。我们将在第 4 章中详细介绍神经网络和 SGD 的工作原理,并解释通用逼近定理。不过,现在我们将使用塞缪尔自己的话: 我们不需要深入研究这种程序的细节,就能知道它可以完全自动完成,也能知道这样编程的机器会从它的经验中 “学习”。

杰里米说:别担心,SGD 和神经网络在数学上都不复杂。两者都几乎完全依靠加法和乘法来完成工作(但它们要做大量的加法和乘法!)。当学生们看到这些细节时,他们的主要反应是 “这就是全部吗?

换句话说,神经网络是一种特殊的机器学习模型,与塞缪尔最初的概念不谋而合。神经网络之所以特殊,是因为它们具有高度灵活性,这意味着只需找到正确的权重,它们就能解决异常广泛的问题。这一点非常强大,因为随机梯度下降为我们提供了一种自动寻找权重值的方法。

在放大之后,现在让我们重新放大,使用塞缪尔的框架来重温我们的图像分类问题。

我们的输入是图像。我们的权重是神经网络中的权重。我们的模型是神经网络。我们的结果就是神经网络计算出的值,比如 “狗 ”或 “猫”。

那么下一部分呢,即根据实际性能测试当前权重分配有效性的自动方法?确定 “实际性能”非常简单:我们可以简单地将模型的性能定义为预测正确答案的准确性。

假设SGD是我们更新权重分配的机制,我们就可以看到我们的图像分类器是一个机器学习模型,这与塞缪尔的设想非常相似。

1.5.4 一些深度学习术语

塞缪尔是在20世纪60年代工作的,从那时起,术语已经发生了变化。以下是我们讨论过的所有部分的现代深度学习术语:

模型的功能形式被称为架构(但要注意,有时人们会把模型当作架构的同义词来使用,因此这可能会引起混淆)。
权重称为参数。
预测是根据自变量计算出来的,而自变量就是不包括标签的数据。
模型的结果称为预测。
衡量性能的标准称为损失。
损失不仅取决于预测结果,还取决于正确的标签(也称为目标或因变量),例如 “狗 ”或 “猫”。

1.5.5 机器学习的限制

从这幅图中,我们现在可以看到有关训练深度学习模型的一些基本情况:

模型的创建离不开数据。
模型只能根据用于训练它的输入数据中的模式来学习操作。
这种学习方法只能创建预测,而不是推荐操作。
仅有输入数据的示例是不够的,我们还需要为这些数据添加标签(例如,狗和猫的不足以训练模型;我们需要为每张添加标签,说明哪些是狗,哪些是猫)。
一般来说,我们发现大多数组织说他们没有足够的数据,实际上是指他们没有足够的标注数据。如果任何组织有兴趣用一个模型来做一些实际工作,那么他们肯定会有一些输入数据来运行他们的模型。而且,他们可能已经用其他方法(如手动或启发式程序)做了一段时间,因此他们拥有这些过程中产生的数据!例如,放射科几乎肯定会有医学扫描档案(因为他们需要检查病人的病情进展情况),但这些扫描可能没有包含诊断或干预列表的结构化标签(因为放射科医生通常创建的是自由文本自然语言报告,而不是结构化数据)。我们将在本书中多次讨论标签方法,因为这在实践中是一个非常重要的问题。

由于这类机器学习模型只能进行预测(即试图复制标签),这可能会导致组织目标与模型能力之间存在巨大差距。例如,在本书中,你将学习如何创建一个能够预测用户可能购买的产品的推荐系统。这通常用于电子商务,例如通过显示排名最高的商品来定制主页上显示的商品。但这种模型通常是通过查看用户及其购买历史(输入)和他们继续购买或查看的商品(标签)来创建的,这意味着模型很可能会告诉你用户已经拥有或已经了解的商品,而不是他们最有可能感兴趣的新商品。这与当地书商的专家所做的工作截然不同,他们会通过提问来了解你的品味,然后向你介绍你从未听说过的作家或系列作品。

另一个重要的见解来自于考虑模型如何与环境互动。这可以形成反馈回路,如这里所述:

预测性警务模型是根据过去的逮捕地点创建的。实际上,这并不是在预测犯罪,而是在预测逮捕,因此部分地反映了现有警务流程中的偏差。

然后,执法人员可以使用该模型来决定在哪些地方集中开展警务活动,从而增加这些地区的逮捕人数。

这些额外逮捕的数据将被反馈到模型的未来版本中进行再训练。

这是一个正反馈循环:模型使用得越多,数据的偏差就越大,从而使模型更加偏差,如此循环往复。

在商业环境中,反馈循环也会产生问题。例如,视频推荐系统可能会偏向于推荐最常观看视频的用户所消费的内容(例如,阴谋论者和极端分子往往比普通人观看更多的在线视频内容),导致这些用户增加视频消费,从而推荐更多此类视频。我们将在第 3 章中更详细地讨论这个问题。

现在你已经看到了理论基础,让我们回到代码示例,详细看看代码是如何与我们刚才描述的过程相对应的。

参考资料

软件测试精品书籍文档下载持续更新 https://github.com/china-testing/python-testing-examples 请点赞,谢谢!
本文涉及的python测试开发库 谢谢点赞! https://github.com/china-testing/python_cn_resouce
python精品书籍下载 https://github.com/china-testing/python_cn_resouce/blob/main/python_good_books.md
Linux精品书籍下载 https://www.cnblogs.com/testing-/p/17438558.html
1.5.6 图像识别器如何工作

让我们来看看我们的图像识别器代码是如何与这些想法相对应的。我们将把每一行放在一个单独的单元格中,然后看看每一行在做什么(我们还不会解释每个参数的每个细节,但会对重要的部分进行描述;完整的细节将在本书的后面部分介绍)。第一行导入 fastai.vision 库的所有内容:

from fastai.vision.all import *
path = untar_data(URLs.PETS)/’images’

def is_cat(x):
return x[0].isupper()

dls = ImageDataLoaders.from_name_func(
path, get_image_files(path), valid_pct=0.2, seed=42,
label_func=is_cat, item_tfms=Resize(224))

learn = cnn_learner(dls, resnet34, metrics=error_rate)
learn.fine_tune(1)

img = PILImage.create(r’d:\img\cat.png’)
img.to_thumb(192)
is_cat,_,probs = learn.predict(img)
print(f”Is this a cat?: {is_cat}.”)
print(f”Probability it’s a cat: {probs[1].item():.6f}”)
这将为我们提供创建各种计算机视觉模型所需的所有函数和类。

杰里米说:很多Python程序员都建议避免像这样导入整个库(使用 import * 语法),因为在大型软件项目中这样做可能会造成问题。不过,对于 Jupyter 笔记本等交互式工作来说,这样做效果很好。fastai 库就是为支持这种交互式使用而专门设计的,它只会将必要的部分导入到你的环境中。

第二行将fast.ai数据集集合中的一个标准数据集(如果之前未下载过)下载到服务器上,然后将其提取出来(如果之前未提取过),并返回一个包含提取位置的Path对象:

然后定义了一个函数 is_cat,它可以根据数据集创建者提供的文件名规则给猫贴标签:

之后使用该函数,它告诉fastai我们有什么样的数据集以及数据集的结构:针对不同类型的深度学习数据集和问题,有各种不同的类,这里我们使用的是 ImageDataLoaders。类名的第一部分通常是数据类型,如图像或文本。

我们需要告诉fastai的另一个重要信息是如何从数据集中获取标签。计算机视觉数据集的结构通常是这样的:图像的标签是文件名或路径的一部分,最常见的是父文件夹的名称。在这里,我们告诉fastai使用我们刚刚定义的 is_cat 函数。

最后,我们定义所需的Transforms。一个Transform包含在训练过程中自动应用的代码;fastai包含许多预定义的 Transform,添加新的 Transform 就像创建一个 Python 函数一样简单。变换有两种:item_tfms 应用于每个条目(在本例中,每个条目都被调整为224像素的正方形),而 batch_tfms 则使用GPU一次应用于一批条目,因此速度特别快(我们会在本书中看到很多这样的例子)。

为什么是224像素?由于历史原因,这是标准尺寸(旧的预训练模型正是需要这种尺寸),但你可以通过几乎任何尺寸。如果增大尺寸,通常会得到效果更好的模型(因为它能关注更多细节),但代价是速度和内存消耗;如果减小尺寸,情况则恰恰相反。

分类和回归在机器学习中有着非常特殊的含义。这是我们将在本书中研究的两种主要模型类型。分类模型是一种试图预测类或类别的模型。也就是说,它是从一些离散的可能性中进行预测,比如 “狗 ”或 “猫”。回归模型是一种试图预测一个或多个数字量的模型,例如温度或位置。有时,人们使用回归一词来指代一种称为线性回归模型的特殊模型;这是一种不好的做法,我们在本书中不会使用这种术语!

宠物数据集包含7,390张猫狗,由37个品种组成。每张都使用文件名进行标注:例如,文件great_pyrenees_173.jpg 是数据集中第 173 张大白熊犬。如果图像是猫,文件名就以大写字母开头,否则就以小写字母开头。我们必须告诉 fastai 如何从文件名中获取标签,具体方法是调用 from_name_func(这意味着可以使用应用于文件名的函数来提取文件名),并传入 x[0].isupper(),如果第一个字母是大写字母(即是猫),则求值为 True。

这里最重要的参数是 valid_pct=0.2。它告诉 fastai 保留 20% 的数据,完全不用于训练模型。这 20% 的数据称为验证集,其余 80% 的数据称为训练集。验证集用于衡量模型的准确性。默认情况下,这 20% 的数据是随机选取的。每次运行代码时,参数 seed=42 都会将随机种子设置为相同的值,这意味着每次运行代码时,我们都会得到相同的验证集–这样,如果我们更改模型并重新训练它,我们就会知道任何差异都是由于模型的更改造成的,而不是由于随机验证集的不同造成的。

fastai 将始终只显示使用验证集的模型准确率,而不会显示训练集的准确率。这一点非常重要,因为如果长时间训练一个足够大的模型,它最终会记住数据集中每一项的标签!这样做的结果将不会是一个有用的模型,因为我们关心的是我们的模型在以前未见过的图像上运行得如何。这也是我们创建模型的目标:让模型在训练完成后,在将来看到的数据上发挥作用。

即使模型没有完全记住所有数据,它也可能在训练的早期就记住了其中的某些部分。因此,训练时间越长,训练集上的准确率就会越高;验证集上的准确率也会提高一段时间,但最终会开始变差,因为模型开始记忆训练集,而不是从数据中找到可概括的基本模式。当这种情况发生时,我们就会说模型过拟合了。

下图展示了过度拟合时的情况,使用的是一个简化示例,其中只有一个参数和一些基于函数 x**2 随机生成的数据。如图所示,虽然过拟合模型对观测数据点附近的数据预测准确,但在观测数据点范围之外的数据预测就有很大偏差。

对于所有机器学习从业者和所有算法来说,过拟合是训练时最重要和最具挑战性的问题。正如你所看到的,创建一个模型很容易,它可以在训练过的数据上做出很好的预测,但要在模型从未见过的数据上做出准确的预测就难得多了。当然,这些数据在实践中才是最重要的。例如,如果你创建了一个手写数字分类器(我们很快就会这样做!),并用它来识别写在支票上的数字,那么你将永远不会看到模型所训练过的任何数字–每张支票都会有略微不同的书写方式需要处理。

你将在本书中学到很多避免过度拟合的方法。但是,只有在确认发生了过度拟合后(即在训练过程中观察到验证准确率越来越低),才可以使用这些方法。我们经常看到一些实践者使用避免过度拟合的技术,即使他们有足够多的数据,并不需要这样做,最终得到的模型可能比他们本可以达到的精度更低。

验证集:在训练模型时,您必须同时拥有训练集和验证集,并且只能在验证集上测量模型的准确性。fastai 默认 valid_pct 为 0.2,所以即使你忘记了,fastai 也会为你创建一个验证集!

cnn_learner告诉 fastai 创建一个卷积神经网络 (CNN),并指定使用什么架构(即创建什么样的模型)、我们要在什么数据上训练它,以及使用什么指标:

为什么要使用 CNN?这是目前创建计算机视觉模型的最先进方法。我们将在本书中全面了解 CNN 的工作原理。它们的结构灵感来源于人类视觉系统的工作原理。

fastai 中有许多架构,我们将在本书中加以介绍(并讨论如何创建自己的架构)。不过,大多数时候,选择架构并不是深度学习过程中非常重要的一部分。这是学术界喜欢谈论的事情,但在实践中,你不太可能需要花太多时间在这上面。有一些标准架构在大多数情况下都能发挥作用,在本例中,我们使用了一种名为 ResNet 的架构,我们将在书中详细介绍它;对于许多数据集和问题来说,它既快速又准确。resnet34 中的 34 指的是该架构变体的层数(其他选项包括 18、50、101 和 152)。使用层数更多的架构训练模型需要更长的时间,而且更容易出现过拟合(即在验证集上的准确率开始变差之前,无法训练更多的epochs)。另一方面,在使用更多数据的情况下,它们的准确度会更高。

什么是度量?度量是一个函数,用于衡量模型使用验证集进行预测的质量,并在每个历元结束时打印出来。在本例中,我们使用的是 error_rate,它是 fastai 提供的一个函数,其作用如其所言:告诉你验证集中被错误分类的图像的百分比。另一个常用的分类指标是准确率(准确率仅为 1.0 – error_rate)。fastai 还提供了更多指标,我们将在本书中逐一讨论。

度量的概念可能会让你联想到损失,但两者之间有重要区别。损失的整个目的是定义一个 “性能指标”,训练系统可以利用它来自动更新权重。换句话说,对于随机梯度下降法来说,损失是一个很好的选择。但是,度量标准是为人类消费而定义的,因此一个好的度量标准应该是你容易理解的,并且尽可能贴近你希望模型做的事情。有时,您可能会认为损失函数是一个合适的指标,但事实并不一定如此。

cnn_learner 还有一个参数 pretrained,默认值为 True(因此本例中使用了这个参数,尽管我们没有指定),它可以将模型中的权重设置为专家已经训练过的值,以便识别 130 万张照片中的一千个不同类别(使用著名的 ImageNet 数据集)。权重已经在另一个数据集上训练过的模型称为预训练模型。你几乎总是应该使用预训练模型,因为这意味着你的模型在你向它展示任何数据之前,就已经具备了很强的能力。正如你将看到的,在深度学习模型中,这些能力中有很多都是你需要的,几乎与你的项目细节无关。例如,预训练模型的部分功能会处理边缘、梯度和颜色检测,这在很多任务中都需要。

在使用预训练模型时,cnn_learner 会移除最后一层,因为这一层总是专门为原始训练任务(即 ImageNet 数据集分类)定制的,取而代之的是一个或多个具有随机权重的新层,其大小与您正在使用的数据集相适应。模型的最后一部分被称为 “头部”。

使用预训练模型是最重要的方法,它能让我们用更少的数据、更少的时间和金钱,更快地训练出更精确的模型。你可能会认为,这意味着使用预训练模型将是学术界深度学习研究最多的领域……但你大错特错了!在大多数课程、书籍或软件库功能中,预训练模型的重要性通常得不到认可或讨论,在学术论文中也很少被提及。当我们在 2020 年初写这篇文章时,情况才刚刚开始改变,但这可能还需要一段时间。所以要小心:与你交谈的大多数人可能都会大大低估你在深度学习方面的能力,因为他们可能不会深入了解如何使用预训练模型。

将预先训练好的模型用于不同于最初训练的任务,这就是所谓的迁移学习。遗憾的是,由于对迁移学习的研究太少,很少有领域能使用预训练模型。例如,目前医学领域几乎没有预训练模型,因此在该领域使用迁移学习具有挑战性。此外,人们对如何将迁移学习用于时间序列分析等任务还不甚了解。

迁移学习:将预先训练好的模型用于不同于最初训练的任务。

learn.fine_tune(1)告诉 fastai 如何拟合模型,架构只是描述了一个数学函数的模板;在我们为它所包含的数百万个参数提供值之前,它不会做任何实际工作。

这就是深度学习的关键–确定如何拟合模型参数,让模型解决你的问题。要拟合一个模型,我们至少要提供一条信息:每张图像要看多少次(称为历元数)。您所选择的历元数在很大程度上取决于您有多少可用时间,以及您发现在实践中拟合模型需要多长时间。如果选择的epoch数太小,以后还可以增加训练epoch(历元)数。

fastai确实有一个叫fit的方法,它确实可以拟合模型(即多次查看训练集中的图像,每次更新参数,使预测结果越来越接近目标标签)。但在这种情况下,我们已经有了一个预先训练好的模型,我们不想放弃它已经具备的所有能力。正如你将在本书中学到的,有一些重要的技巧可以让预训练模型适应新的数据集–这个过程叫做微调。

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

使用微调方法时,fastai 会为你使用这些技巧。你可以设置一些参数(我们稍后会讨论),但在这里显示的默认形式下,它会执行两个步骤:

使用一个历元来拟合模型中必要的部分,以使新的随机头在数据集上正确工作。
使用调用该方法时请求的epoch次数来拟合整个模型,更新后层(尤其是头部)权重的速度要快于前层(正如我们将看到的,前层通常不需要对预处理的权重进行太多更改)。
模型的头部是针对新数据集新添加的部分。一个历元是对数据集的一次完整传递。调用拟合后,每个epoch后的结果都会打印出来,显示epoch数、训练集和验证集损失(用于训练模型的 “性能衡量标准”),以及您要求的任何指标(本例中为错误率)。

有了这些代码,我们的模型就学会了仅从标记示例中识别猫和狗。但它是怎么做到的呢?

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

现阶段,我们的图像识别器运行良好,但我们不知道它在做什么!虽然很多人抱怨深度学习会产生无法破解的 “黑盒子 ”模型(即能给出预测结果,但却无人能懂),但事实并非如此。有大量研究表明,如何深入检查深度学习模型并从中获得丰富的见解。尽管如此,要完全理解所有类型的机器学习模型(包括深度学习和传统的统计模型)还是很有挑战性的,尤其是当考虑到它们在遇到与用于训练它们的数据截然不同的数据时会如何表现时。我们将在本书中讨论这个问题。

2013 年,博士生 Matt Zeiler 和他的导师 Rob Fergus 共同发表了《可视化和理解卷积网络》(Visualizing and Understanding Convolutional Networks)一文,介绍了如何可视化模型每一层学习到的神经网络权重。他们仔细分析了在 2012 年 ImageNet 竞赛中获胜的模型,并通过分析大大改进了模型,从而在 2013 年的竞赛中获胜!下图是他们公布的第一层权重。

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

这些都是计算机视觉模型学习到的基本构件。神经科学家和计算机视觉研究人员对它们进行了广泛的分析,结果表明,这些学习到的构建模块与人眼的基本视觉机制以及深度学习时代之前开发的手工制作的计算机视觉特征非常相似。下一层如图:

对于第 2 层,有 9 个权重重构的例子,模型发现了每个特征。我们可以看到,该模型已经学会了创建特征检测器,以寻找角、重复线、圆和其他简单模式。这些都是由第一层中开发的基本构件构建而成的。对于每一种特征,右侧都显示了与这些特征最匹配的实际图像中的小块图案。例如,第 2 行第 1 列中的特定图案与日落相关的渐变和纹理相匹配。下图为第三层:

从图的右侧可以看到,这些特征现在能够识别并匹配更高层次的语义成分,如汽车车轮、文字和花瓣。如下图所示,利用这些成分,第 4 层和第 5 层可以识别更高级别的概念。

这篇文章研究的是一种名为 AlexNet 的旧模型,它只包含五层。从那时起开发的网络可以有数百个层,所以你可以想象这些模型开发的功能有多么丰富!

当我们早些时候微调预训练模型时,我们调整了最后几层的关注点(花、人、动物),以专门解决猫对狗的问题。更广泛地说,我们可以将这样一个预训练模型专门用于许多不同的任务。让我们来看几个例子。

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

顾名思义,图像识别器只能识别图像。但很多东西都可以用图像来表示,这意味着图像识别器可以学习完成很多任务。

例如,可以将声音转换成频谱图,这是一种显示音频文件中每个时间段每个频率的数量的图表。Fast.ai 的学生伊桑-苏廷(Ethan Sutin)使用这种方法,在一个包含 8732 种城市声音的数据集中,轻松击败了最先进的环境声音检测模型所公布的准确率。如图所示,fastai 的 show_batch 可以清楚地显示每种声音都有一个相当独特的频谱图。

只需在图表上绘制时间序列,就能轻松将时间序列转换为图像。不过,通常情况下,最好还是尝试用一种能让人尽可能轻松地提取出最重要组成部分的方式来表示数据。在时间序列中,季节性和异常现象最有可能引起人们的兴趣。

时间序列数据可进行各种转换。例如,fast.ai 的学生伊格纳西奥-奥古伊萨(Ignacio Oguiza)从时间序列数据集中创建了用于橄榄油分类的图像,他使用了一种名为 “格兰角差场”(GADF)的技术;您可以在下图看到结果。然后,他将这些图像输入到一个图像分类模型中,就像本章中的模型一样。尽管只有 30 张训练集图像,但他的结果准确率远远超过 90%,接近最先进的水平。

另一个有趣的 fast.ai 学生项目案例来自 Gleb Esman。他在 Splunk 从事欺诈检测工作,使用的是用户鼠标移动和鼠标点击的数据集。如下图,他将这些数据转换成,绘制了一幅图像,用彩色线条显示鼠标指针的位置、速度和加速度,用彩色小圆圈显示点击。他将此输入到图像识别模型中,就像我们在本章中使用的模型一样,效果非常好,并为这种欺诈分析方法申请了专利!

另一个例子来自 Mahmoud Kalash 等人撰写的论文《利用深度卷积神经网络进行恶意软件分类》,该论文解释说:”恶意软件二进制文件被分为 8 位序列,然后转换为等效的十进制值。对十进制向量进行重塑,生成代表恶意软件样本的灰度图像”:

然后,作者展示了通过这一过程生成的不同类别恶意软件的 “”:

不同类型的恶意软件在人眼看来非常明显。研究人员根据这种图像表示法训练出的模型在恶意软件分类方面比以往学术文献中显示的任何方法都要准确。这为将数据集转换为图像表示法提供了一个很好的经验法则:如果人眼能从图像中识别出类别,那么深度学习模型也应该能做到。

总的来说,你会发现,如果你在如何表示数据方面有点创意,深度学习中的少量通用方法就能发挥很大作用!你不应该把这里描述的方法看作是 “笨办法”,因为它们经常(就像这里描述的那样)打败以前最先进的结果。这些确实是思考这些问题领域的正确方法。

1.5.9术语回顾

标签
我们要预测的数据,如 “狗 ”或 “猫”。

架构
我们试图拟合的模型模板;即我们将输入数据和参数传递给它的实际数学函数

模型
架构与特定参数集的组合

参数
模型中改变其任务的值,通过模型训练进行更新

匹配
更新模型参数,使模型使用输入数据预测的结果与目标标签相匹配

训练
拟合的同义词

预训练模型
已经训练过的模型,通常使用大型数据集,并将进行微调

微调
针对不同任务更新预训练模型

周期(Epoch 或叫历元)
输入数据的一次完整传递

损失
衡量模型好坏的指标,通过 SGD 驱动训练

度量
使用验证集衡量模型的好坏,供人类使用

验证集
从训练中保留下来的数据集,仅用于衡量模型的好坏

训练集
用于拟合模型的数据;不包括验证集中的任何数据

过度拟合
以这样一种方式训练模型,使其记住输入数据的特定特征,而不是很好地泛化到训练期间未见的数据上

卷积神经网络
卷积神经网络;一种神经网络,尤其适用于计算机视觉任务

有了这些词汇,我们现在就可以将迄今为止介绍的所有关键概念汇集在一起了。请花点时间回顾这些定义,并阅读下面的摘要。如果你能理解这些解释,就能很好地理解接下来的讨论。

机器学习是一门学科,在这门学科中,我们不是完全通过自己编写程序,而是通过从数据中学习来定义程序。深度学习是机器学习中的一门专业,它使用多层神经网络。图像分类就是一个很有代表性的例子(也称为图像识别)。我们从有标签的数据开始–这是一组图像,我们为每张图像分配了一个标签,表明它代表了什么。我们的目标是生成一个称为模型的程序,在给定新图像的情况下,准确预测新图像所代表的内容。

每个模型都会先选择一个架构,即该模型内部如何工作的通用模板。训练(或拟合)模型的过程就是寻找一组参数值(或权重)的过程,从而将通用架构专门化,使其成为一个能很好地处理特定数据的模型。为了确定模型在单次预测中的表现,我们需要定义一个损失函数,它决定了我们如何对预测的好坏进行评分。

为了让训练过程更快,我们可能会从一个预训练模型开始–这个模型已经在别人的数据上训练过了。然后,我们可以在自己的数据上对其进行更多的训练,使其适应我们的数据,这一过程称为微调。

当我们训练一个模型时,一个关键问题是要确保我们的模型具有泛化能力:它从我们的数据中学到的一般经验也适用于它将遇到的新项目,因此它可以对这些项目做出很好的预测。这样做的风险在于,如果我们对模型的训练效果不佳,模型非但不能学到通用的经验,反而会有效地记住它已经看到过的东西,从而对新图像做出糟糕的预测。这种失败被称为过拟合。

为了避免这种情况,我们总是将数据分为两部分,即训练集和验证集。我们只使用训练集来训练模型,然后通过观察模型在验证集项目上的表现来评估模型的性能。通过这种方法,我们可以检查模型从训练集中学到的经验是否可以推广到验证集。为了让人们评估模型在验证集上的总体表现,我们定义了一个指标。在训练过程中,当模型看过训练集中的每一个项目时,我们称之为一个纪元。

所有这些概念都适用于一般的机器学习。它们适用于通过数据训练来定义模型的各种方案。让深度学习与众不同的是一类特殊的架构:基于神经网络的架构。尤其是像图像分类这样的任务,在很大程度上依赖于卷积神经网络,我们稍后将讨论这一点。

声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/416760.html

(0)
联系我们
联系我们
分享本页
返回顶部