2000字范文,分享全网优秀范文,学习好帮手!
2000字范文 > 【Pytorch with fastai】第 2 章:从模型到生产

【Pytorch with fastai】第 2 章:从模型到生产

时间:2024-03-25 18:17:12

相关推荐

【Pytorch with fastai】第 2 章:从模型到生产

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

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

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

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

🖍foreword

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

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

文章目录

深度学习的实践

开始你的项目

深度学习的状态

计算机视觉

文本(自然语言处理)

结合文字和图像

表格数据

推荐系统

其他数据类型

传动系统方法

收集数据

与最新服务保持联系

从数据到数据加载器

数据加载器

数据增强

训练你的模型,并用它来清理你的数据

不需要大数据

将您的模型变成在线应用程序

使用模型进行推理

从模型创建笔记本应用程序

把你的笔记本变成一个真正的应用程序

部署您的应用程序

如何避免灾难

不可预见的后果和反馈循环

我们在第一章中看到的六行代码只是在实践中使用深度学习过程的一小部分。在本章中,我们将使用一个计算机视觉示例来了解创建深度学习应用程序的端到端过程。更具体地说,我们将构建一个熊分类器!在此过程中,我们将讨论深度学习的能力和限制,探索如何创建数据集,查看在实践中使用深度学习时可能遇到的问题,等等。许多关键点同样适用于其他深度学习问题,例如第 1 章中的问题。如果您解决了与我们的示例问题在关键方面相似的问题,我们希望您能够以很少的代码快速获得出色的结果。

让我们从你应该如何构建你的问题开始。

深度学习的实践

我们已经看到,深度学习可以用很少的代码快速解决许多具有挑战性的问题。作为初学者,有很多问题与我们的示例问题非常相似你可以很快得到非常有用的结果。然而,深度学习并不是魔法!同样的六行代码并不适用于任何人今天能想到的所有问题。

低估限制和高估深度学习的能力可能会导致令人沮丧的糟糕结果,至少在您获得一些经验并能够解决出现的问题之前是这样。相反,高估限制和低估深度学习的能力可能意味着您不会尝试解决可解决的问题,因为您会说服自己放弃它。

我们经常与低估深度学习的限制和能力的人交谈。这两者都可能是问题:低估能力意味着您甚至可能不会尝试可能非​​常有益的事情,而低估约束可能意味着您无法考虑和应对重要问题。

最好的办法是保持开放的心态。如果您对深度学习可能以比您预期更少的数据或复杂性解决部分问题的可能性持开放态度,您可以设计一个流程,通过该流程您可以找到与您的特定问题相关的特定功能和约束。这并不意味着做出任何冒险的赌注——我们将向您展示如何逐步推出模型,以免它们产生重大风险,甚至可以在将它们投入生产之前对其进行回测。

开始你的项目

那么你应该从哪里开始你的深度学习之旅呢?最重要的是确保你有一个项目可以工作——只有通过你自己的项目,你才能获得构建和使用模型的真实经验。选择项目时,最重要的考虑因素是数据可用性。

无论您是为了自己的学习还是为了在组织中的实际应用而做一个项目,您都希望能够快速开始。我们已经看到许多学生、研究人员和行业从业者在试图找到完美的数据集时浪费了数月或数年的时间。目标不是找到“完美”的数据集或项目,而只是从那里开始并迭代。如果您采用这种方法,您将在完美主义者仍处于计划阶段时进行第三次学习和改进!

我们还建议您在项目中从头到尾进行迭代;不要花几个月的时间来微调你的模型,或者打磨完美的 GUI,或标记完美的数据集……相反,在合理的时间内尽可能完成每一步,一直到最后。例如,如果您的最终目标是在手机上运行的应用程序,那应该是您在每次迭代之后所拥有的。但也许在早期的迭代中你会走捷径;例如,通过在远程服务器上进行所有处理并使用简单的响应式 Web 应用程序。通过端到端完成项目,您将看到最棘手的位在哪里,以及哪些位对最终结果的影响最大。

通过使用端到端迭代方法,您还将更好地了解您真正需要多少数据。例如,您可能会发现您只能轻松获得 200 个标记的数据项,并且在您尝试这是否足以获得您的应用程序在实践中正常运行所需的性能之前,您无法真正知道。

在组织环境中,您将能够向您的同事展示您的想法可以通过向他们展示真实的工作原型来实现。我们一再观察到,这是为项目获得良好组织支持的秘诀。

因为最容易开始一个已经有可用数据的项目,这意味着开始一个与你已经在做的事情相关的项目可能是最容易的,因为你已经有了关于你正在做的事情的数据。例如,如果您在音乐行业工作,您可能可以访问许多录音。如果您是放射科医生,您可能可以访问大量医学图像。如果您对野生动物保护感兴趣,您可能会接触到很多野生动物的图片。

有时你必须有点创意。也许您可以找到与您感兴趣的领域相关的以前的机器学习项目,例如 Kaggle 比赛。有时你必须妥协。也许您无法找到您心目中的精确项目所需的确切数据;但是您可能能够从类似的领域中找到一些东西,或者以不同的方式进行衡量,从而解决稍微不同的问题。从事这些类似的项目仍然会让您对整个过程有一个很好的理解,并且可以帮助您识别其他快捷方式、数据源等。

尤其是当你刚刚开始学习深度学习时,扩展到非常不同的领域,以及以前没有应用深度学习的地方并不是一个好主意。那是因为如果你的模型一开始不起作用,你将不知道是因为你犯了一个错误,还是你试图解决的问题根本无法通过深度学习来解决。而且你不知道去哪里寻求帮助。因此,最好首先在网上找到一个示例,该示例显示某人已经取得了不错的效果,并且至少与您尝试实现的目标有些相似,方法是将您的数据转换为类似于其他人的格式以前使用过(例如从您的数据创建图像)。让我们看看深度学习的状态,让你知道深度学习现在擅长哪些方面。

深度学习的状态

让我们首先考虑深度学习是否可以很好地解决您正在寻找的问题。本节提供了一个 年初深度学习状态的总结。然而,事情发展得非常快,当你读到这篇文章时,其中一些限制可能已经不存在了。我们将努力使本书的网站保持最新;此外,谷歌搜索“人工智能现在能做什么”可能会提供当前信息。

计算机视觉

有许多领域没有使用深度学习分析图像,但那些已经尝试过的几乎普遍表明,计算机可以识别图像中的项目,至少和人一样——甚至是受过专门训练的人,比如放射科医生。这称为对象识别。深度学习还擅长识别图像中物体的位置,并且可以突出显示它们的位置并命名每个找到的物体。这就是所谓的对象检测(在我们在第 1 章中看到的一种变体中,每个像素都根据它所属的对象类型进行分类——这称为分割)。

深度学习算法通常不擅长识别结构或风格与用于训练模型的图像有显着差异的图像。例如,如果训练数据中没有黑白图像,则模型在黑白图像上的表现可能会很差。同样,如果训练数据不包含手绘图像,该模型可能会在手绘图像上表现不佳。没有通用的方法来检查训练集中缺少哪些类型的图像,但是我们将在本章中展示一些方法来尝试识别当模型在生产中使用时数据中出现意外的图像类型时(这是称为检查域外数据)。

目标检测系统的一个主要挑战是图像标记可能缓慢且昂贵。目前有很多工作需要尝试使这种标记更快、更容易,并且需要更少的手工标签来训练准确的对象检测模型。一种特别有用的方法是综合生成输入图像的变化,例如通过旋转它们或改变它们的亮度和对比度;这称为数据增强,也称为适用于文本和其他类型的模型。我们将在本章中详细讨论它。

要考虑的另一点是,尽管您的问题可能看起来不像计算机视觉问题,但有一点想象力就可以将其变成一个问题。例如,如果您要分类的是声音,您可以尝试将声音转换为声学波形的图像,然后在这些图像上训练模型。

文本(自然语言处理)

计算机擅长根据垃圾邮件或非垃圾邮件等类别对短文档和长文档进行分类,情绪(例如,评论是正面还是负面)、作者、来源网站等。我们不知道在该领域进行过任何严格的工作来将计算机与人类进行比较,但有趣的是,在我们看来,深度学习的表现与人类在这些任务上的表现相似。

深度学习还擅长生成适合上下文的文本,例如回复社交媒体帖子,以及模仿特定作者的风格。它也擅长使这些内容对人类有吸引力——事实上,它甚至比人类生成的文本更引人注目。然而,深度学习并不擅长产生正确的反应!我们没有例如,将医学信息知识库与深度学习模型相结合以生成医学上正确的自然语言响应的可靠方法。这是危险的,因为创建在外行看来很有吸引力但实际上完全不正确的内容非常容易。

另一个担忧是,社交媒体上适合上下文的、高度引人注目的回应可能会被大规模使用——比以前看到的任何巨魔农场都要大数千倍——传播虚假信息,制造动乱,鼓励冲突。根据经验,文本生成模型在技术上总是领先于识别自动生成文本的模型。例如,可以使用可以识别人工生成的内容的模型来实际改进创建该内容的生成器,直到分类模型不再能够完成其任务。

尽管存在这些问题,深度学习在 NLP 中有很多应用:它可以用来翻译文本一种语言到另一种语言,将长文档总结成可以更快消化的东西,找到所有提到的感兴趣的概念等等。不幸的是,翻译或摘要很可能包含完全不正确的信息!然而,性能已经足够好,以至于很多人都在使用这些系统——例如,谷歌的在线翻译系统(以及我们所知道的所有其他在线服务)都是基于深度学习的。

结合文字和图像

深度学习将文本和图像组合成一个模型的能力通常比大多数人的直觉预期要好得多。为了例如,一个深度学习模型可以在输入图像上训练,输出用英文写的标题,并且可以学习为新图像自动生成出乎意料的合适标题!但同样,我们有上一节中讨论过的相同警告:不能保证这些标题是正确的。

由于这个严重的问题,我们通常建议不要将深度学习用作完全自动化的过程,但作为模型和人类用户密切交互的过程的一部分。与完全手动的方法相比,这可能会使人类的生产力提高几个数量级,并产生比单独使用人类更准确的过程。

例如,可以使用自动系统直接从 CT 扫描中识别潜在的中风患者,并发送高优先级警报以快速查看这些扫描。治疗中风的时间只有三个小时,因此这种快速反馈循环可以挽救生命。然而,与此同时,所有扫描都可以继续以通常的方式发送给放射科医师,因此不会减少人工输入。其他深度学习模型可以自动测量扫描中看到的项目并将这些测量结果插入报告中,警告放射科医生他们可能错过的发现,并告诉他们可能相关的其他病例。

表格数据

为了分析时间序列和表格数据,深度学习最近取得了长足的进步。但是,深度学习通常用作多种类型模型的集合的一部分。如果您已经有一个使用随机森林或梯度增强机器(您将很快了解的流行表格建模工具)的系统,那么切换到或添加深度学习可能不会带来任何显着的改进。

深度学习确实极大地增加了您可以包含的列的种类——例如,包含自然语言的列(书名、评论等)和高基数分类列(即,包含大量离散选择的内容,例如作为邮政编码或产品 ID)。不利的一面是,深度学习模型的训练时间通常比随机森林或梯度增强机器要长,尽管这要归功于RAPIDS等提供 GPU 加速的库对于整个建模管道。我们将在第 9 章详细介绍所有这些方法的优缺点。

推荐系统

推荐系统实际上只是一种特殊类型的表格数据。特别是,它们通常有一个代表用户的高基数分类变量,另一个代表产品(或类似的东西)。像亚马逊这样的公司将其客户的每一次购买都表示为一个巨大的稀疏矩阵,其中客户为行,产品为列。一旦他们拥有这种格式的数据,数据科学家就会应用某种形式的协同过滤来填充矩阵。例如,如果客户 A 购买产品 1 和 10,客户 B 购买产品 1、2、4 和 10,那么引擎会建议 A 购买 2 和 4。

因为深度学习模型擅长处理高基数的分类变量,所以它们非常擅长处理推荐系统。当将这些变量与其他类型的数据(例如自然语言或图像)结合起来时,它们尤其会发挥自己的作用,就像表格数据一样。他们还可以很好地将所有这些类型的信息与表示为表格的其他元数据结合起来,例如用户信息、以前的交易等等。

然而,几乎所有机器学习方法都有缺点,它们只告诉你特定用户可能喜欢哪些产品,而不是告诉你哪些推荐对用户有帮助。用户可能喜欢的多种产品推荐可能根本没有帮助——例如,如果用户已经熟悉产品,或者它们只是他们已经购买的产品的不同包装(例如盒装的小说,当他们已经拥有该集合中的每个项目时)。Jeremy 喜欢阅读 Terry Pratchett 的书,有一段时间亚马逊只向他推荐 Terry Pratchett 的书(见图 2-1),这真的没有帮助,因为他已经知道这些书了!

图 2-1。一个不太有用的建议

其他数据类型

通常,您会发现特定领域的数据类型非常适合现有类别。例如,蛋白质链看起来很像自然语言文档,因为它们是离散标记的长序列,在整个序列中具有复杂的关系和含义。事实上,事实证明,使用 NLP 深度学习方法是目前用于多种蛋白质分析的最先进方法。作为另一个例子,声音可以表示作为频谱图,可以将其视为图像;图像的标准深度学习方法在频谱图上表现得非常好。

传动系统方法

许多准确的模型对任何人都没有用,许多不准确的模型非常有用。为确保您的建模工作在实践中有用,您需要考虑如何使用您的工作。 年,Jeremy 与 Margit Zwemer 和 Mike Loukides 一起引入了一种称为传动系统方法的方法来思考这个问题。

图 2-2所示的传动系统方法在“设计大数据产品”中进行了详细描述。基本思想是从考虑您的目标开始,然后考虑您可以采取哪些行动来实现该目标以及您拥有(或可以获得)哪些数据可以提供帮助,然后构建一个模型,您可以使用该模型来确定最佳就您的目标而言,为获得最佳结果而采取的行动。

图 2-2。传动系统方法

考虑自动驾驶汽车中的模型:您想帮助汽车驾驶无需人工干预即可安全地从 A 点到 B 点。出色的预测建模是解决方案的重要组成部分,但它并不是独立存在的;随着产品变得越来越复杂,它消失在管道中。使用自动驾驶汽车的人完全不知道数百(如果不是数千)模型和使其工作的 PB 数据。但随着数据科学家构建越来越复杂的产品,他们需要一种系统的设计方法。

我们使用数据不仅是为了生成更多数据(以预测的形式),而且是为了产生可操作的结果。这就是传动系统方法的目标。首先定义一个明确的目标。例如,谷歌在创建其第一个搜索引擎时,考虑了“用户输入搜索查询的主要目标是什么?”这导致了 Google 的目标,即“显示最相关的搜索结果”。下一步是考虑您可以拉动哪些杠杆(即您可以采取哪些行动)以更好地实现该目标。在谷歌的例子中,这就是搜索结果的排名。第三步是考虑他们需要哪些新数据来产生这样的排名;他们意识到有关哪些页面链接到哪些其他页面的隐含信息可用于此目的。

只有在前三个步骤之后,我们才开始考虑构建预测模型。我们的目标和可用杠杆、我们已经拥有的数据以及我们需要收集的额外数据,决定了我们可以构建的模型。模型将杠杆和任何不可控变量作为输入;模型的输出可以结合起来预测我们目标的最终状态。

让我们考虑另一个例子:推荐系统。推荐引擎的目标是通过以下方式推动额外的销售推荐他们不会在没有推荐的情况下购买的商品,让客户感到惊讶和高兴。杠杆是推荐的排名。必须收集新数据以生成能带来新销售的建议。这将需要进行许多随机实验,以便为广泛的客户收集有关广泛建议的数据。这是很少有组织采取的步骤;但没有它,您就没有根据您的真实目标优化推荐所需的信息(更多销售!)。

最后,您可以建立两个购买概率模型,以看到或未看到推荐为条件。这两个概率之间的差异是针对给定客户推荐的效用函数。如果算法推荐了一本客户已经拒绝的熟悉的书(两个组件都很小),或者即使没有推荐他们也会购买的书(两个组件都很大并且相互抵消),那么它就会很低。

如您所见,在实践中,模型的实际实现通常需要的不仅仅是训练模型!您经常需要进行实验以收集更多数据,并考虑如何将您的模型整合到您正在开发的整个系统中。说到数据,现在让我们关注如何为您的项目查找数据。

收集数据

对于许多类型的项目,您可能能够在线找到您需要的所有数据。我们将在本章中完成的项目是熊探测器。它将区分三种类型的熊:灰熊、黑熊和泰迪熊。互联网上有很多我们可以使用的每种熊的图像。我们只需要一种方法来找到它们并下载它们。

我们提供了一个可以用于此目的的工具,因此您可以按照本章的内容为您感兴趣的任何类型的对象创建自己的图像识别应用程序。在 fast.ai 课程中,成千上万的学生们在课程论坛上展示了他们的作品,展示了从特立尼达的蜂鸟品种到巴拿马的公共汽车类型的所有内容——一位学生甚至创建了一个应用程序,可以帮助他的未婚妻在圣诞假期认出他的 16 个表亲!

在撰写本文时,必应图像搜索是我们所知道的最佳选择用于查找和下载图像。每月最多 1,000 个查询是免费的,每个查询最多可以下载 150 张图像。但是,在我们撰写本文和您阅读本书之间可能会出现更好的情况,因此请务必查看本书的网站以获取我们当前的推荐。

与最新服务保持联系

可用于创建数据集的服务一直来来去去,它们的功能、界面和定价也经常变化。在本节中,我们将展示如何使用在本书编写时,必应图像搜索 API作为 Azure 认知服务的一部分提供。

要使用 Bing Image Search 下载图像,请在Microsoft Azure上注册一个免费帐户。您将获得一个密钥,您可以按如下方式复制并输入一个单元格(替换XXX为您的密钥并执行它):

key = os.environ.get('AZURE_SEARCH_KEY', 'XXX')

或者,如果您对命令行感到满意,您可以在终端中设置它

export AZURE_SEARCH_KEY=your_key_here

然后重新启动 Jupyter Notebook,并使用上面的行而不进行编辑。

设置key好之后就可以使用了search_images_bing。该功能由utils在线笔记本附带的小班提供(如果您不确定函数定义在哪里,可以直接在笔记本中输入查找,如下所示):

search_images_bing

<function utils.search_images_bing(key, term, min_sz=128)>

让我们试试这个功能:

results = search_images_bing(key, 'grizzly bear')ims = results.attrgot('content_url')len(ims)

150

我们已经成功下载了 150 只灰熊的 URL(或者,至少是 Bing Image Search 为该搜索词找到的图像)。我们来看一个:

dest = 'images/grizzly.jpg'download_url(ims[0], dest)

im = Image.open(dest)im.to_thumb(128,128)

这似乎工作得很好,所以让我们使用fastaidownload_images下载所有 URL我们的每个搜索词。我们将把每一个放在一个单独的文件夹中:

bear_types = 'grizzly','black','teddy'path = Path('bears')

if not path.exists():path.mkdir()for o in bear_types:dest = (path/o)dest.mkdir(exist_ok=True)results = search_images_bing(key, f'{o} bear')download_images(dest, urls=results.attrgot('contentUrl'))

正如我们所料,我们的文件夹有图像文件:

fns = get_image_files(path)fns

(#421) [Path('bears/black/00000095.jpg'),Path('bears/black/00000133.jpg'),Path('> bears/black/00000062.jpg'),Path('bears/black/00000023.jpg'),Path('bears/black> /00000029.jpg'),Path('bears/black/00000094.jpg'),Path('bears/black/00000124.j> pg'),Path('bears/black/00000056.jpeg'),Path('bears/black/00000046.jpg'),Path(> 'bears/black/00000045.jpg')...]

通常当我们从互联网上下载文件时,有一些是腐败。让我们检查:

failed = verify_images(fns)failed

(#0) []

要删除所有失败的图像,您可以使用unlink.像大多数返回集合的 fastai 函数一样,verify_images返回一个类型为 的对象L,其中包括该map方法。这会在集合的每个元素上调用传递的函数:

failed.map(Path.unlink);

在 JUPYTER NOTEBOOKS 中获得帮助

Jupyter 笔记本非常适合进行实验并立即查看每个功能的结果,但也有很多功能可以帮助您弄清楚如何使用不同的功能,甚至可以直接查看它们的源代码。例如,假设您在单元格中键入:

??verify_images

将弹出一个窗口,其中包含:

Signature: verify_images(fns)Source:def verify_images(fns):"Find images in `fns` that can't be opened"return L(fns[i] for i,o inenumerate(parallel(verify_image, fns)) if not o)File:~/git/fastai/fastai/vision/utils.pyType:function

这告诉我们函数接受什么参数(fns),然后向我们展示源代码和它来自的文件。查看该源代码,我们可以看到它verify_image并行应用该函数并仅保留该函数的结果为的图像文件,这False与 doc 字符串一致:它找到fns无法打开的图像。

以下是 Jupyter 笔记本中非常有用的其他一些功能:

在任何时候,如果您不记得函数或参数名称的确切拼写,您可以按 Tab 键获取自动完成建议。

在函数的括号内,同时按下 Shift 和 Tab 将显示一个带有功能和简短说明。按这些键两次将展开文档,按三次将在屏幕底部打开一个完整的窗口,其中包含相同的信息。

在单元格中,键入和执行将打开一个窗口,其中包含函数签名和简短描述。?func_name

在单元格中,键入和执行将打开一个窗口,其中包含函数签名、简短描述和源代码。??func_name

如果您使用的是 fastai 库,我们添加了一个doc函数you:在单元格中执行将打开一个窗口,其中包含函数的签名、简短描述、GitHub 上源代码的链接以及库 docs中函数的完整文档。doc(func_name)

与文档无关但仍然非常有用:如果您遇到错误,请随时获取帮助,请输入%debug下一个单元格并执行以打开Python 调试器,这将让您检查每个变量的内容。

在此过程中需要注意的一件事:正如我们在第 1 章中讨论的那样,模型只能反映用于训练它们的数据。世界上到处都是有偏见的数据,最终会反映在必应图像搜索(我们用来创建数据集)中。例如,假设您有兴趣创建一个可以帮助用户确定他们是否拥有健康皮肤的应用程序,因此您根据搜索(例如)“健康皮肤”的结果训练了一个模型。图 2-3显示了你会得到的结果。

图 2-3。健康皮肤检测仪的数据?

以此作为您的训练数据,您最终将得到的不是一个健康的皮肤检测器,而是一个年轻的白人女性触摸她的面部检测器!请务必仔细考虑您可能希望在应用程序中实际看到的数据类型,并仔细检查以确保所有这些类型都反映在模型的源数据中。(感谢 Deb Raji,他提出了健康的皮肤例子。请参阅她的论文“Actionable Auditing: Investigating the Impact of Public Naming Biased Performance Results of Commercial AI Products”,了解更多关于模型偏差的有趣见解。)

现在我们已经下载了一些数据,我们需要将其组装成适合模型训练的格式。在 fastai 中,这意味着创建一个名为DataLoaders.

从数据到数据加载器

DataLoaders是薄仅存储DataLoader您传递给它的任何对象并使它们作为train和可用的类valid。尽管它是一个简单的类,但它在 fastai 中很重要:它为您的模型提供数据。DataLoaders仅这四行代码就提供了其中的关键功能 (它还有一些其他次要功能,我们现在将跳过):

class DataLoaders(GetAttr):def __init__(self, *loaders): self.loaders = loadersdef __getitem__(self, i): return self.loaders[i]train,valid = add_props(lambda i,self: self[i])

数据加载器

一个 fastai 类,它存储DataLoader你传递给它的多个对象——通常是 atrain和 avalid,尽管你可以拥有任意数量的对象。前两个作为属性提供。

在本书后面,您还将了解DatasetDatasets类,它们具有相同的关系。要将我们下载的数据变成一个DataLoaders对象,我们需要告诉 fastai 至少四件事:

我们正在处理哪些类型的数据

如何获取项目列表

如何标记这些项目

如何创建验证集

到目前为止,我们已经看到了许多用于这些东西的特定组合的工厂方法,当你有一个恰好适合这些预定义方法的应用程序和数据结构。如果你不这样做,fastai 有一个非常灵活的系统,称为数据块 API。使用此 API,您可以完全自定义创建您的DataLoaders.下面是我们需要为DataLoaders刚刚下载的数据集创建一个:

bears = DataBlock(blocks=(ImageBlock, CategoryBlock),get_items=get_image_files,splitter=RandomSplitter(valid_pct=0.2, seed=42),get_y=parent_label,item_tfms=Resize(128))

让我们依次看看这些论点。首先,我们提供一个元组,指定我们想要的自变量和因变量的类型:

blocks=(ImageBlock, CategoryBlock)

自变量是我们用来进行预测的东西,而因变量是我们的目标。在这种情况下,我们的自变量是一组图像,而我们的因变量是每个图像的类别(熊的类型)。我们将在本书的其余部分中看到许多其他类型的块。

为此DataLoaders,我们的基础项目将是文件路径。我们必须告诉 fastai 如何获取这些文件的列表。该get_image_files函数接受一个路径,并返回该路径中所有图像的列表(默认情况下递归):

get_items = get_image_files

通常,您下载的数据集已经定义了验证集。有时这是通过放置用于训练的图像来完成的和验证集到不同的文件夹中。有时它是通过提供一个 CSV 文件来完成的,其中列出了每个文件名以及它应该在哪个数据集。有很多方法可以做到这一点,fastai 提供了一种通用方法,允许您使用其预定义类之一为此或编写自己的。

在这种情况下,我们希望随机拆分训练集和验证集。但是,我们希望每次运行这个笔记本时都有相同的训练/验证拆分,所以我们修复了随机种子(计算机根本不知道如何创建随机数,而只是创建看起来随机的数字列表; 如果您每次都为该列表提供相同的起点——称为种子——那么你每次都会得到完全相同的列表)。

splitter=RandomSplitter(valid_pct=0.2, seed=42)

自变量通常称为x,而因变量变量通常称为y。在这里,我们告诉 fastai 调用什么函数来在我们的数据集中创建标签:

get_y = parent_label

parent_label是 fastai 提供的一个函数,它简单地获取文件所在文件夹的名称。因为我们根据熊的类型将每个熊图像放入文件夹中,这将为我们提供我们需要的标签。

我们的图像大小不同,这对于深度学习来说是一个问题:我们不是一次向模型提供一张图像,而是其中几张(我们称之为mini-batch)。要将它们分组到将通过我们的模型的大数组(通常称为张量)中,它们都需要具有相同的大小。因此,我们需要添加一个变换,将这些图像调整为相同大小。项目转换是在每个单独的项目上运行的代码片段,无论是图像、类别等。fastai 包括许多预定义的转换;我们在Resize这里使用变换并指定 128 像素的大小:

item_tfms = Resize(128)

这个命令给了我们一个DataBlock对象。这就像一个用于创建DataLoaders.我们仍然需要告诉 fastai 我们数据的实际来源——在这种情况下,可以找到图像的路径:

dls = bears.dataloaders(path)

ADataLoaders包括验证和训练DataLoader。ADataLoader是一个类,它一次向 GPU 提供几个项目的批次。我们将在下一章中学习更多关于这门课的内容。当您遍历 aDataLoader时,fastai 将一次给您 64 个(默认情况下)项目,所有项目都堆叠成一个张量。show_batch我们可以通过调用a 上的方法来查看其中的一些项目DataLoader

dls.valid.show_batch(max_n=4, nrows=1)

默认情况下,Resize裁剪图像以适合大小的正方形请求,使用全宽或全高。这可能会导致丢失一些重要的细节。或者,您可以要求 fastai 用零(黑色)填充图像,或挤压/拉伸它们:

bears = bears.new(item_tfms=Resize(128, ResizeMethod.Squish))dls = bears.dataloaders(path)dls.valid.show_batch(max_n=4, nrows=1)

bears = bears.new(item_tfms=Resize(128, ResizeMethod.Pad, pad_mode='zeros'))dls = bears.dataloaders(path)dls.valid.show_batch(max_n=4, nrows=1)

所有这些方法似乎有些浪费或有问题。要是我们挤压或拉伸图像,它们最终会变成不切实际的形状,导致模型学习到事物看起来与实际不同,我们预计这会导致准确性降低。如果我们裁剪图像,我们会删除一些允许我们执行识别的特征。例如,如果我们试图识别狗或猫的品种,我们最终可能会裁剪出身体的关键部位或区分相似品种所必需的面部。如果我们填充图像,我们有很多空白空间,这只是浪费了我们模型的计算,并导致我们实际使用的图像部分的有效分辨率较低。

相反,我们通常在实践中做的是随机选择图像的一部分,然后裁剪到那部分。在每个时期(这是对数据集中所有图像的完整遍历),我们随机选择每个图像的不同部分。这意味着我们的模型可以学习关注和识别图像中的不同特征。它还反映了图像在现实世界中的工作方式:同一事物的不同照片可能以略有不同的方式构图。

事实上,一个完全未经训练的神经网络对图像的行为一无所知。它甚至不知道当一个物体旋转一度时,它仍然是同一个物体的图片!因此,使用对象位置略有不同且大小略有不同的图像示例训练神经网络有助于理解对象是什么的基本概念,以及如何在图像中表示它。

这是另一个我们用 替换Resize的示例RandomResizedCrop,它是提供刚刚描述的行为的转换。要传入的最重要的参数是min_scale,它决定了每次最少选择多少图像:

bears = bears.new(item_tfms=RandomResizedCrop(128, min_scale=0.3))dls = bears.dataloaders(path)dls.train.show_batch(max_n=4, nrows=1, unique=True)

在这里,我们曾经unique=True用不同版本的RandomResizedCrop变换重复相同的图像。

RandomResizedCrop是更通用技术的一个具体示例,称为数据增强。

数据增强

数据增强是指创建输入数据的随机变化,使它们看起来不同但不会改变数据的意义。图像的常见数据增强技术的示例是旋转、翻转、透视变形、亮度变化和对比度变化。对于我们在此处使用的自然照片图像,该功能提供了一组我们发现效果很好的标准增强aug_transforms功能。

因为我们的图像现在都是一样的大小,我们可以使用 GPU 将这些增强应用到整个批次中,这将节省大量时间。为了告诉 fastai 我们想在批次上使用这些转换,我们使用batch_tfms参数(注意我们RandomResizedCrop在这个例子中没有使用,所以你可以更清楚地看到差异;我们还使用了两倍于默认,出于同样的原因):

bears = bears.new(item_tfms=Resize(128), batch_tfms=aug_transforms(mult=2))dls = bears.dataloaders(path)dls.train.show_batch(max_n=8, nrows=2, unique=True)

现在我们已经以适合模型训练的格式组装了数据,让我们使用它来训练图像分类器。

训练你的模型,并用它来清理你的数据

是时候使用与第 1 章中相同的代码行来训练我们的熊分类器了。我们的问题没有很多数据(每种熊最多 150 张图片),所以为了训练我们的模型,我们将使用RandomResizedCrop224 像素的图像大小,这对于图像分类来说是相当标准的,和默认值aug_transforms

bears = bears.new(item_tfms=RandomResizedCrop(224, min_scale=0.5),batch_tfms=aug_transforms())dls = bears.dataloaders(path)

我们现在可以创建我们的Learner并以通常的方式对其进行微调:

learn = cnn_learner(dls, resnet18, metrics=error_rate)learn.fine_tune(4)

现在让我们看看模型所犯的错误是否主要是认为灰熊是泰迪熊(这对安全不利!),或者灰熊是黑熊,或者其他什么。为了可视化这一点,我们可以创建一个混淆矩阵:

interp = ClassificationInterpretation.from_learner(learn)interp.plot_confusion_matrix()

这些行分别代表我们数据集中的所有黑色、灰熊和泰迪熊。这些列分别代表模型预测为黑色、灰熊和泰迪熊的图像。因此,矩阵的对角线表示分类正确的图像,非对角线单元表示分类错误的图像。这是 fastai 允许您查看模型结果的多种方式之一。它是(当然!)使用验证集计算的。使用颜色编码,目标是除了对角线之外的所有地方都有白色,我们想要深蓝色。我们的熊分类器不会犯很多错误!

看看我们的错误到底发生在哪里会很有帮助,查看它们是由于数据集问题(例如,根本不是熊或标记不正确的图像)还是模型问题(也许它没有处理使用异常照明或从不同角度拍摄的图像, ETC。)。为此,我们可以按损失对图像进行排序。

如果模型不正确(特别是如果它也对自己的错误答案有信心),或者如果它是正确的但对其正确答案不自信,则损失是一个更高的数字。在第二部分的开头,我们将深入了解损失是如何计算和在训练过程中使用的。现在,plot_top_losses向我们展示数据集中损失最大的图像。正如输出的标题所说,每张图像都标记有四个内容:预测、实际(目标标签)、损失和概率。这里的概率是模型分配给的置信水平,从零到一其预测:

interp.plot_top_losses(5, nrows=1)

这个输出表明损失最高的图像是高度自信地预测为“灰熊”。但是,它被标记为(基于我们的 Bing 图像搜索)为“黑色”。我们不是熊专家,但在我们看来这个标签肯定是不正确的!我们或许应该把它的标签改成“灰熊”。

进行数据清理的直观方法是在您之前进行训练一个模型。但正如您在本例中所见,模型可以帮助您更快速、更轻松地发现数据问题。所以,我们通常更喜欢先训练一个快速简单的模型,然后用它来帮助我们进行数据清洗。

fastai 包含一个方便的数据清理 GUI,ImageClassifierCleaner它允许您选择一个类别和训练与验证集并查看损失最高的图像(按顺序),以及允许选择图像以进行删除或重新标记的菜单:

cleaner = ImageClassifierCleaner(learn)cleaner

我们可以看到,我们的“黑熊”中有一个包含两只熊的图像:一只灰熊,一只黑色。所以,我们应该<Delete>在这张图片下的菜单中选择。ImageClassifierCleaner不会为您删除或更改标签;它只是返回要更改的项目的索引。因此,例如,要删除 (unlink) 所有选择删除的图像,我们将运行以下命令:

for idx in cleaner.delete(): cleaner.fns[idx].unlink()

要移动我们选择了不同类别的图像,我们将运行以下命令:

for idx,cat in cleaner.change(): shutil.move(str(cleaner.fns[idx]), path/cat)

不需要大数据

在使用这些步骤清理数据集后,我们通常会看到此任务的 100% 准确率。当我们下载的图像比我们在这里使用的每类 150 个图像少得多时,我们甚至会看到这个结果。如您所见,需要大量数据来进行深度学习的普遍抱怨可能与事实相去甚远!

现在我们已经训练了我们的模型,让我们看看如何将它部署到实践中。

将您的模型变成在线应用程序

我们现在将看看如何将这个模型变成一个工作在线申请。我们将只创建一个基本的工作原型;我们没有在本书中教你一般性的 Web 应用程序开发的所有细节。

使用模型进行推理

一旦你得到一个你满意的模型,你需要保存它,这样你就可以将它复制到你将在生产中使用它的服务器上。请记住,一个模型由两部分组成:架构和训练参数。保存模型最简单的方法是保存这两者,因为这样,当您加载模型时,您可以确定您拥有匹配的架构和参数。要保存这两个部分,请使用export方法。

这个方法甚至保存了如何创建你的定义DataLoaders.这很重要,因为否则您必须重新定义如何转换数据才能在生产中使用您的模型。fastai 默认情况下会自动使用您的验证集DataLoader进行推理,因此不会应用您的数据扩充,这通常是您想要的。

当您调用时export,fastai 将保存一个名为 export.pkl 的文件:

learn.export()

让我们检查文件是否存在,使用lsfastai 添加到 PythonPath类的方法:

path = Path()path.ls(file_exts='.pkl')

(#1) [Path('export.pkl')]

无论您将应用部署到何处,都将需要此文件。现在,让我们尝试在笔记本中创建一个简单的应用程序。

当我们使用模型而不是训练来获得预测时,我们称之为推理。为了从导出的文件创建我们的推理学习器,我们使用load_learner(在这种情况下,这并不是真正必要的,因为我们的笔记本中已经有一个工作Learner;我们在这里做,所以你可以看到整个过程端到端):

learn_inf = load_learner(path/'export.pkl')

当我们进行推理时,我们通常一次只能获得一张图像的预测。为此,请将文件名传递给predict

learn_inf.predict('images/grizzly.jpg')

('grizzly', tensor(1), tensor([9.0767e-06, 9.9999e-01, 1.5748e-07]))

这返回了三件事:与您最初提供的格式相同的预测类别(在本例中,这是一个字符串)、预测类别的索引以及每个类别的概率。最后两个基于 ; 的词汇中的类别顺序DataLoaders。也就是说,所有可能类别的存储列表。在推理时,您可以DataLoaders作为 的属性访问Learner

learn_inf.dls.vocab

(#3) ['black','grizzly','teddy']

在这里我们可以看到,如果我们使用返回的整数对词汇进行索引predict,我们会得到“grizzly”,正如预期的那样。另外,请注意,如果我们在概率列表中编制索引,我们会看到这是一只灰熊的概率接近 1.00。

我们知道如何从保存的模型中进行预测,因此我们拥有开始构建应用程序所需的一切。我们可以直接在 Jupyter notebook 中完成。

从模型创建笔记本应用程序

要在应用程序中使用我们的模型,我们可以简单地将predict方法视为常规函数。因此,可以使用应用程序开发人员可用的无数框架和技术中的任何一种来从模型创建应用程序。

然而,大多数数据科学家并不熟悉 Web 应用程序开发的世界。因此,让我们尝试使用您所做的事情,此时,知道:事实证明,我们可以只使用 Jupyter 笔记本创建一个完整的工作 Web 应用程序!我们需要做两件事来实现这一点:

IPython 小部件 (ipywidgets)

所以

IPython 小部件是结合了 JavaScript 和Web 浏览器中的 Python 功能,可以在 Jupyter 笔记本中创建和使用。比如我们看到的图像清理器本章前面的部分完全是用 IPython 小部件编写的。但是,我们不想要求我们应用程序的用户自己运行 Jupyter。

这就是Voilà存在的原因。这是一个用于制作应用程序的系统由最终用户可用的 IPython 小部件组成,他们根本不必使用 Jupyter。瞧,笔记本已经是一种 Web 应用程序,只是一个依赖于另一个 Web 应用程序的相当复杂的应用程序:Jupyter 本身。从本质上讲,它帮助我们自动将我们已经隐式创建的复杂 Web 应用程序(笔记本)转换为更简单、更易于部署的 Web 应用程序,其功能类似于普通 Web 应用程序而不是笔记本。

但是我们还是有在笔记本上开发的优势,所以有了ipywidgets,我们就可以一步一步的搭建我们的GUI。我们将使用这种方法来创建一个简单的图像分类器。首先,我们需要一个文件上传小部件:

btn_upload = widgets.FileUpload()btn_upload

现在我们可以抓取图像:

img = PILImage.create(btn_upload.data[-1])

我们可以使用一个Output小部件来显示它:

out_pl = widgets.Output()out_pl.clear_output()with out_pl: display(img.to_thumb(128,128))out_pl

然后我们可以得到我们的预测:

pred,pred_idx,probs = learn_inf.predict(img)

并使用 aLabel来显示它们:

lbl_pred = widgets.Label()lbl_pred.value = f'Prediction: {pred}; Probability: {probs[pred_idx]:.04f}'lbl_pred

Prediction: grizzly; Probability: 1.0000

我们需要一个按钮来进行分类。它看起来与上传按钮一模一样:

btn_run = widgets.Button(description='Classify')btn_run

我们还需要一个点击事件处理程序;也就是说,按下时将调用的函数。我们可以复制前面的代码行:

def on_click_classify(change):img = PILImage.create(btn_upload.data[-1])out_pl.clear_output()with out_pl: display(img.to_thumb(128,128))pred,pred_idx,probs = learn_inf.predict(img)lbl_pred.value = f'Prediction: {pred}; Probability: {probs[pred_idx]:.04f}'btn_run.on_click(on_click_classify)

您现在可以通过单击按钮来测试它,您应该会看到图像和预测自动更新!

我们现在可以将它们全部放在一个垂直框 (VBox) 中以完成我们的 GUI:

VBox([widgets.Label('Select your bear!'),btn_upload, btn_run, out_pl, lbl_pred])

我们已经为我们的应用编写了所有必要的代码。下一步是将其转换为我们可以部署的东西。

把你的笔记本变成一个真正的应用程序

现在我们已经在这个 Jupyter 笔记本中完成了所有工作,我们可以创建我们的应用程序。为此,请启动一个新笔记本并仅向其中添加创建和显示所需小部件所需的代码,并为要显示的任何文本添加 Markdown。查看本书存储库中的bear_classifier笔记本,了解我们创建的简单笔记本应用程序。

接下来,如果您还没有安装 Voilà,请将这些行复制到笔记本单元格中并执行它:

!pip install voila!jupyter serverextension enable --sys-prefix voila

以 a 开头的单元格!不包含 Python 代码,而是包含传递给 shell(bash、Windows PowerShell 等)的代码。!如果您习惯使用命令行(我们将在本书中详细讨论),您当然可以直接在终端中直接键入这两行(不带前缀)。在这种情况下,第一行安装voila库和应用程序,第二行将其连接到您现有的 Jupyter 笔记本。

Voilà 运行 Jupyter 笔记本,就像您现在使用的 Jupyter 笔记本服务器一样,但它也做了一些非常重要的事情:它删除了所有单元格输入,并且只显示输出(包括 ipywidgets)以及您的 Markdown 单元格。所以剩下的是一个网络应用程序!要将您的笔记本作为 Voilà Web 应用程序查看,请将浏览器 URL 中的单词“notebooks”替换为“voila/render”。您将看到与笔记本相同的内容,但没有任何代码单元。

当然,您不需要使用 Voilà 或 ipywidgets。您的模型只是一个您可以调用 (pred,pred_idx,probs = learn.predict(img)) 的函数,因此您可以将它与托管在任何平台上的任何框架一起使用。您可以使用您在 ipywidgets 和 Voilà 中制作的原型,然后将其转换为常规的 Web 应用程序。我们在本书中向您展示了这种方法,因为我们认为这是数据科学家和其他非 Web 开发专家从他们的模型创建应用程序的好方法。

我们有我们的应用程序;现在让我们部署它!

部署您的应用程序

如您所知,您需要一个 GPU 来训练几乎所有有用的深度学习模型。那么,您是否需要 GPU 才能在生产中使用该模型?不!您几乎可以肯定不需要 GPU 来为生产中的模型提供服务。这有几个原因:

正如我们所见,GPU 只有在并行执行大量相同工作时才有用。如果你正在做(比如说)图像分类,你通常一次只对一个用户的图像进行分类,并且通常没有足够的工作可以在单个图像中做足够长的时间来让 GPU 保持足够长的时间来处理它非常有效率。因此,CPU 通常更具成本效益。

另一种方法是等待几个用户提交他们的图像,然后将它们批量处理并在 GPU 上一次处理它们。但那么您是在要求您的用户等待,而不是立即获得答案!你需要一个大容量的网站才能使它可行。如果您确实需要此功能,您可以使用 Microsoft 的ONNX Runtime或AWS SageMaker等工具。

处理 GPU 推理的复杂性非常显着。在特别是,GPU 的内存需要仔细的手动管理,并且您需要一个仔细的排队系统来确保您一次只处理一个批次。

CPU的市场竞争比GPU 服务器,因此,CPU 服务器有更便宜的选择。

由于 GPU 服务的复杂性,许多系统如雨后春笋般涌现尝试自动执行此操作。但是,管理和运行这些系统也很复杂,通常需要将模型编译成专门用于该系统的不同形式。通常最好避免处理这种复杂性,直到/除非您的应用程序足够受欢迎以至于您这样做具有明确的财务意义。

至少对于您的应用程序的初始原型,以及您想要展示的任何爱好项目,您都可以轻松地免费托管它们。最好的地方和最好的方法会随着时间的推移而变化,因此请查看本书的网站以获取最新的建议。当我们在 年初写这本书时,最简单(而且免费!)方法是使用Binder。要在 Binder 上发布您的 Web 应用程序,请执行以下步骤:

将您的笔记本添加到GitHub 存储库。

将该 repo 的 URL 粘贴到 Binder 的 URL 字段中,如图 2-4所示。

将文件下拉菜单更改为选择 URL。

在“打开的 URL”字段中,输入(替换为您的笔记本的名称)。/voila/render/name.ipynbname

单击右下角的剪贴板按钮以复制 URL 并将其粘贴到安全的地方。

单击启动。

图 2-4。部署到 Binder

第一次执行此操作时,Binder 将需要大约 5 分钟来构建您的站点。在幕后,它正在寻找一个可以运行您的应用程序的虚拟机,分配存储空间,并收集 Jupyter、您的笔记本所需的文件,以及将您的笔记本显示为一个 Web 应用程序。

最后,一旦它开始运行应用程序,它会将您的浏览器导航到您的新网络应用程序。您可以共享您复制的 URL,以便其他人也可以访问您的应用程序。

对于部署 Web 应用程序的其他(免费和付费)选项,请一定要看看这本书的网站。

您可能希望将应用程序部署到移动设备上,或者边缘设备,例如 Raspberry Pi。有许多库和框架允许您将模型直接集成到移动应用程序中。但是,这些方法往往需要大量额外的步骤和样板文件,并且并不总是支持您的模型可能使用的所有 PyTorch 和 fastai 层。此外,您所做的工作将取决于您要部署的移动设备的种类——您可能需要做一些工作才能在 iOS 设备上运行,不同的工作才能在较新的 Android 设备上运行,不同的工作才能在较旧的 Android 设备上运行,相反,我们建议您尽可能将模型本身部署到服务器,并让您的移动或边缘应用程序作为 Web 服务连接到它。

这种方法有很多好处。初始安装更容易,因为您只需部署一个小的 GUI 应用程序,它连接到服务器来完成所有繁重的工作。也许更重要的是,核心逻辑的升级可以发生在您的服务器上,而不是需要分发给您的所有用户。您的服务器将比大多数边缘设备拥有更多的内存和处理能力,如果您的模型要求更高,扩展这些资源会容易得多。您将在服务器上拥有的硬件也将更加标准,并且更容易受到 fastai 和 PyTorch 的支持,因此您不必将模型编译成不同的形式。

当然,也有缺点。您的应用程序将需要网络连接,并且每次调用模型时都会有一些延迟。(无论如何,神经网络模型需要一段时间才能运行,因此这种额外的网络延迟在实践中可能不会对您的用户产生太大影响。事实上,由于您可以在服务器上使用更好的硬件,整体延迟甚至可能是比在本地运行时少!)此外,如果您的应用程序使用敏感数据,您的用户可能会担心一种方法将该数据发送到远程服务器,因此有时隐私考虑意味着您需要在边缘设备上运行模型(可以通过拥有本地服务器来避免这种情况,例如在公司的防火墙内)。管理复杂性和扩展服务器也会产生额外的开销,而如果您的模型在边缘设备上运行,每个用户都会带来自己的计算资源,这会导致随着用户数量的增加更容易扩展(也称为水平扩展) .

我有机会近距离了解移动 ML 领域在我的工作中是如何变化的。我们提供的 iPhone 应用程序取决于计算机视觉,多年来我们在云中运行我们自己的计算机视觉模型。这是当时唯一的方法,因为这些模型需要大量的内存和计算资源,并且需要几分钟来处理输入。这种方法不仅需要构建模型(有趣!),还需要构建基础设施,以确保一定数量的“计算工作机器”绝对始终运行(可怕),如果流量增加,更多的机器会自动上线,有用于大量输入和输出的稳定存储,iOS 应用程序可以知道并告诉用户他们的工作如何,等等。如今苹果提供用于转换模型以在设备上高效运行的 API,并且大多数 iOS 设备都有专用的 ML 硬件,因此这是我们用于新模型的策略。这仍然不容易,但在我们的案例中,为了更快的用户体验和减少对服务器的担忧,这是值得的。实际上,对您有用的方法取决于您尝试创建的用户体验以及您个人认为容易做到的事情。如果你真的知道如何运行服务器,那就去做吧。如果你真的知道如何构建原生移动应用程序,那就去做吧。上山的路很多。

总的来说,我们建议使用基于 CPU 的简单服务器尽可能接近,只要你能侥幸逃脱。如果您有幸拥有一个非常成功的应用程序,那么您将能够证明当时对更复杂的部署方法的投资是合理的。

恭喜——您已成功构建并部署了深度学习模型!现在是暂停并考虑可能出现问题的好时机。

如何避免灾难

在实践中,深度学习模型将只是其中的一部分更大的系统。正如我们在本章开头所讨论的,构建数据产品需要考虑从概念到生产使用的整个端到端过程。在这本书中,我们不能希望涵盖管理已部署数据产品的所有复杂性,例如管理多个模型版本、A/B 测试、金丝雀、刷新数据(如果我们一直在增长和增长我们的数据集吗? ,还是我们应该定期删除一些旧数据?),处理数据标记,监控所有这些,检测模型腐烂等等。

在本节中,我们将概述一些需要考虑的最重要的问题;有关部署问题的更详细讨论,请参阅优秀的由 Emmanuel Ameisin (O'Reilly)构建机器学习驱动的应用程序。

要考虑的最大问题之一是理解和测试深度学习模型的行为比您编写的大多数其他代码要困难得多。通过正常的软件开发,您可以分析软件正在执行的确切步骤,并仔细研究这些步骤中的哪些步骤与您尝试创建的所需行为相匹配。但是对于神经网络,行为来自模型尝试匹配训练数据,而不是被精确定义。

这可能导致灾难!例如,假设我们确实正在推出一个熊检测系统,该系统将连接到国家公园露营地周围的摄像机,并警告露营者有熊来袭。如果我们用我们下载的数据集训练的模型,在实践中会出现各种各样的问题,比如这些:

使用视频数据而不是图像

处理可能不会出现在此数据集中的夜间图像

处理低分辨率相机图像

确保结果返回的速度足够快以在实践中有用

在人们在线发布的照片​​中很少看到的位置识别熊(例如从后面、部分被灌木覆盖或远离相机)

问题的很大一部分是人们最有可能上传到互联网的照片类型是能够很好地清晰和艺术地展示他们的主题的照片类型 - 这不是这种输入系统将会得到。所以,我们可能需要做很多我们自己的数据收集和标记来创建一个有用的系统。

这只是域外更普遍问题的一个例子数据。也就是说,我们的模型在生产中看到的数据可能与它在训练期间看到的非常不同。这个问题没有完整的技术解决方案;相反,我们必须小心我们推出这项技术的方法。

还有其他原因我们也需要小心。一个非常常见的问题是域转移,即我们的模型的数据类型看到随着时间的变化。例如,一家保险公司可能会使用深度学习模型作为其定价和风险算法的一部分,但随着时间的推移,公司吸引的客户类型及其所代表的风险类型可能会发生很大变化,以至于原始训练数据不再适用。相关的。

域外数据和域转移是一个更大问题的例子:你永远无法完全理解神经网络的所有可能行为,因为它们的参数太多了。这是他们最好的特性的自然缺点——他们的灵活性,这使他们能够解决我们甚至可能无法完全指定我们首选的解决方案的复杂问题。然而,好消息是,有一些方法可以通过谨慎使用来减轻这些风险深思熟虑的过程。这方面的细节将根据您要解决的问题的细节而有所不同,但我们将尝试制定一种高级方法,如图 2-5中总结的,希望能提供有用的指导。

图 2-5。部署过程

在可能的情况下,第一步是使用完全手动的过程,您的深度学习模型方法并行运行,但不直接用于驱动任何操作。参与手动过程的人员应该查看深度学习输出并检查它们是否有意义。例如,使用我们的熊分类器,公园护林员可以有一个屏幕显示来自所有摄像头的视频,任何可能的熊目击都简单地以红色突出显示。公园护林员仍应保持与部署模型之前一样的警觉;该模型只是帮助检查此时的问题。

第二步是尽量限制模型的范围,并让人们仔细监督。例如,对模型驱动方法进行一个小的地理和时间限制试验。与其在全国的每个国家公园推出我们的熊分类器,我们可以选择一个观察站,为期一周,让公园管理员在警报发出之前检查每个警报。

然后,逐渐扩大您的推广范围。当您这样做时,请确保您拥有真正良好的报告系统,以确保您了解与手动流程相比所采取的措施的任何重大变化。例如,如果在某个地方推出新系统后,熊警报的数量增加了一倍或一半,您应该非常担心。尝试考虑您的系统可能出错的所有方式,然后考虑哪些措施或报告或图片可以反映该问题,并确保您的定期报告包含该信息。

不可预见的后果和反馈循环

推出模型的最大挑战之一是您的模型可能会改变它所属的系统的行为。例如,考虑一种“预测性警务”算法,该算法预测某些社区的更多犯罪,导致更多的警察被派往这些社区,这可能导致这些社区记录更多的犯罪,等等。在皇家统计学会论文“预测和服务?”Kristian Lum 和 William Isaac 观察到“预测性警务被恰当地命名:它是预测未来的警务,而不是未来的犯罪。”

在这种情况下,部分问题在于存在偏见(即我们将在下一章深入讨论),反馈循环会导致这种偏见的负面影响越来越严重。例如,有人担心这种情况已经在美国发生,在美国,基于种族的逮捕率存在很大偏差。根据 ACLU 的说法,“尽管使用率大致相同,但黑人因吸食大麻而被​​捕的可能性是白人的 3.73 倍。”这种偏见的影响,以及在美国许多地区推出的预测性警务算法,导致巴里·威廉姆斯在纽约时报上撰文:“在我的职业生涯中让我兴奋不已的技术正在以某种方式用于执法,这可能意味着在未来几年,我现在 7 岁的儿子更有可能被曝光或逮捕——或者更糟糕的是——除了他的种族和我们住的地方之外没有其他原因。”

在推出一个重要的机器学习系统之前,一个有用的练习是考虑这个问题:“如果它真的非常好,会发生什么?”换句话说,如果预测能力非常高,影响行为的能力非常显着呢?在这种情况下,谁会受到最大的影响?最极端的结果可能是什么样子?你怎么知道真正发生了什么?

这样的思考练习可能会帮助您构建一个更仔细的推出计划,并具有持续的监控系统和人工监督。当然,如果不倾听,人为监督是没有用的,因此请确保存在可靠且有弹性的沟通渠道,以便合适的人意识到问题并有能力解决问题。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。