Chapter 02
From Model to Production
#hide
! [ -e /content ] && pip install -Uqq fastbook
import fastbook
fastbook.setup_book()#hide
from fastbook import *
from fastai.vision.widgets import *From Model to Production
从模型到生产
The six lines of code we saw in <<chapter_intro>> are just one small part of the process of using deep learning in practice. In this chapter, we're going to use a computer vision example to look at the end-to-end process of creating a deep learning application. More specifically, we're going to build a bear classifier! In the process, we'll discuss the capabilities and constraints of deep learning, explore how to create datasets, look at possible gotchas when using deep learning in practice, and more. Many of the key points will apply equally well to other deep learning problems, such as those in <<chapter_intro>>. If you work through a problem similar in key respects to our example problems, we expect you to get excellent results with little code, quickly.
Let's start with how you should frame your problem.
我们在<>中看到的六行代码只是在实践中使用深度学习过程的一小部分。在本章中,我们将使用一个计算机视觉示例来查看创建深度学习应用程序的端到端过程。更具体地说,我们将构建一个熊分类器!在这个过程中,我们将讨论深度学习的能力和约束,探索如何创建数据集,查看在实践中使用深度学习时可能的陷阱,等等。许多关键点将同样适用于其他深度学习问题,例如<>中的问题。如果您解决的问题在关键方面与我们的示例问题相似,我们希望您用很少的代码快速获得出色的结果。 让我们从你应该如何构建你的问题开始。
The Practice of Deep Learning
深度学习的实践
We've seen that deep learning can solve a lot of challenging problems quickly and with little code. As a beginner, there's a sweet spot of problems that are similar enough to our example problems that you can very quickly get extremely useful results. However, deep learning isn't magic! The same 6 lines of code won't work for every problem anyone can think of today. Underestimating the constraints and overestimating the capabilities of deep learning may lead to frustratingly poor results, at least until you gain some experience and can solve the problems that arise. Conversely, overestimating the constraints and underestimating the capabilities of deep learning may mean you do not attempt a solvable problem because you talk yourself out of it.
We often talk to people who underestimate both the constraints and the capabilities of deep learning. Both of these can be problems: underestimating the capabilities means that you might not even try things that could be very beneficial, and underestimating the constraints might mean that you fail to consider and react to important issues.
The best thing to do is to keep an open mind. If you remain open to the possibility that deep learning might solve part of your problem with less data or complexity than you expect, then it is possible to design a process where you can find the specific capabilities and constraints related to your particular problem as you work through the process. This doesn't mean making any risky bets — we will show you how you can gradually roll out models so that they don't create significant risks, and can even backtest them prior to putting them in production.
我们已经看到深度学习可以快速解决许多具有挑战性的问题,而且只需很少的代码。作为初学者,有一个与我们的示例问题足够相似的问题,您可以很快获得非常有用的结果。然而,深度学习并不神奇!同样的6行代码并不适用于当今任何人都能想到的所有问题。低估约束和高估深度学习的能力可能会导致令人沮丧的糟糕结果,至少在您获得一些经验并能够解决出现的问题之前是这样。相反,高估约束和低估深度学习的能力可能意味着您不会尝试可解决的问题,因为您会说服自己放弃它。
我们经常与低估深度学习的约束和能力的人交谈。这两者都可能成为问题:低估能力意味着你可能甚至不会尝试可能非常有益的事情,而低估约束可能意味着你没有考虑并且对重要的事情作出反应。
最好的办法是保持开放的心态。如果你愿意接受这样一种可能性,即深度学习可能会以比你预期更少的数据或复杂性解决你的部分问题,那么你就有可能设计一个流程,在这个流程中,你可以找到与你的特定问题相关的具体能力和限制。这并不意味着要做任何冒险的赌注——我们将向你展示如何逐步推出模型,这样它们就不会产生重大风险,甚至可以在投入生产之前对它们进行回溯测试。
Starting Your Project
开始您的项目
So where should you start your deep learning journey? The most important thing is to ensure that you have some project to work on—it is only through working on your own projects that you will get real experience building and using models. When selecting a project, the most important consideration is data availability. Regardless of whether you are doing a project just for your own learning or for practical application in your organization, you want something where you can get started quickly. We have seen many students, researchers, and industry practitioners waste months or years while they attempt to find their perfect dataset. The goal is not to find the "perfect" dataset or project, but just to get started and iterate from there.
If you take this approach, then you will be on your third iteration of learning and improving while the perfectionists are still in the planning stages!
We also suggest that you iterate from end to end in your project; that is, don't spend months fine-tuning your model, or polishing the perfect GUI, or labelling the perfect dataset… Instead, complete every step as well as you can in a reasonable amount of time, all the way to the end. For instance, if your final goal is an application that runs on a mobile phone, then that should be what you have after each iteration. But perhaps in the early iterations you take some shortcuts, for instance by doing all of the processing on a remote server, and using a simple responsive web application. By completing the project end to end, you will see where the trickiest bits are, and which bits make the biggest difference to the final result.
那么你应该从哪里开始你的深度学习之旅呢?最重要的是确保你有一些项目要做——只有通过在你自己的项目上工作,你才会获得构建和使用模型的真正经验。在选择项目时,最重要的考虑因素是数据可用性。无论你做一个项目只是为了你自己的学习还是为了在你的组织中的实际应用,你都想要一些你可以快速开始的东西。我们看到许多学生、研究人员和行业从业者在试图找到完美的数据集时浪费了几个月或几年的时间。目标不是找到“完美”的数据集或项目,而是从哪里开始并迭代。
如果你采取这种方法,那么当完美主义者还处于计划阶段时,你将处于学习和提高的第三次迭代中!
我们还建议您在项目中从头到尾进行迭代;也就是说,不要花几个月的时间微调您的模型,或润色完美的GUI,或标记完美的数据集......相反,在合理的时间内尽可能好地完成每一步,一直到最后。例如,如果您的最终目标是在手机上运行的应用程序,那么这应该是您每次迭代后都拥有的。但也许在早期迭代中,您会采取一些捷径,例如在远程服务器上完成所有处理,并使用简单的响应式Web应用程序。通过端到端完成项目,您将看到最棘手的部分在哪里,以及哪些部分对最终结果产生最大影响。
As you work through this book, we suggest that you complete lots of small experiments, by running and adjusting the notebooks we provide, at the same time that you gradually develop your own projects. That way, you will be getting experience with all of the tools and techniques that we're explaining, as we discuss them.
s: To make the most of this book, take the time to experiment between each chapter, be it on your own project or by exploring the notebooks we provide. Then try rewriting those notebooks from scratch on a new dataset. It's only by practicing (and failing) a lot that you will get an intuition of how to train a model.
By using the end-to-end iteration approach you will also get a better understanding of how much data you really need. For instance, you may find you can only easily get 200 labeled data items, and you can't really know until you try whether that's enough to get the performance you need for your application to work well in practice.
In an organizational context you will be able to show your colleagues that your idea can really work by showing them a real working prototype. We have repeatedly observed that this is the secret to getting good organizational buy-in for a project.
当你在读这本书时,我们建议你通过运行和调整我们提供的笔记本来完成许多小实验,同时逐渐开发自己的项目。这样,当我们讨论时,你将获得我们正在解释的所有工具和技术的经验。
S:为了充分利用这本书,请在每一章之间花时间进行实验,无论是在您自己的项目中还是通过探索我们提供的笔记本。然后尝试在新数据集上从头开始重写这些笔记本。只有通过大量练习(和失败),您才会对如何训练模型有直觉。
通过使用端到端迭代方法,您还可以更好地了解您真正需要多少数据。例如,您可能会发现您只能轻松获得200个标注的数据项,并且您无法确定这些数据是否足够能让您的应用表现良好,直到开始实践。
在组织环境中,您将能够通过向同事展示真实的工作原型来向他们展示您的想法确实可行。我们一再观察到,这是为项目获得良好组织支持的秘诀。
Since it is easiest to get started on a project where you already have data available, that means it's probably easiest to get started on a project related to something you are already doing, because you already have data about things that you are doing. For instance, if you work in the music business, you may have access to many recordings. If you work as a radiologist, you probably have access to lots of medical images. If you are interested in wildlife preservation, you may have access to lots of images of wildlife.
Sometimes, you have to get a bit creative. Maybe you can find some previous machine learning project, such as a Kaggle competition, that is related to your field of interest. Sometimes, you have to compromise. Maybe you can't find the exact data you need for the precise project you have in mind; but you might be able to find something from a similar domain, or measured in a different way, tackling a slightly different problem. Working on these kinds of similar projects will still give you a good understanding of the overall process, and may help you identify other shortcuts, data sources, and so forth.
Especially when you are just starting out with deep learning, it's not a good idea to branch out into very different areas, to places that deep learning has not been applied to before. That's because if your model does not work at first, you will not know whether it is because you have made a mistake, or if the very problem you are trying to solve is simply not solvable with deep learning. And you won't know where to look to get help. Therefore, it is best at first to start with something where you can find an example online where somebody has had good results with something that is at least somewhat similar to what you are trying to achieve, or where you can convert your data into a format similar to what someone else has used before (such as creating an image from your data). Let's have a look at the state of deep learning, just so you know what kinds of things deep learning is good at right now.
在一个你已经有数据的项目中开始是最容易的,这意味着开始一个与你已经在做的事情相关的项目可能是最容易的,因为你已经有了关于你正在做的事情的数据。例如,如果你在音乐行业工作,你可能可以访问许多录音。如果你是放射科医生,你可能可以访问许多医学图像。如果你对野生动物保护感兴趣,你可能可以访问许多野生动物的图像。
有时候,你必须有点创造力。也许你可以找到一些以前的机器学习项目,比如一个和你感兴趣的领域相关的Kaggle竞赛。有时候,你必须妥协。也许你找不到你心目中具体项目所需的确切数据;但是你也许可以从一个相似的领域找到一些东西,或者以不同的方式衡量,解决一个稍微不同的问题。从事这些类似的项目仍然会让你很好地了解整个过程,并可能帮助你识别其他捷径、数据源等等。
尤其是当你刚开始深度学习的时候,扩展到非常不同的领域,深度学习以前没有应用过的地方不是一个好主意。这是因为如果你的模型一开始不起作用,你就不知道这是因为你犯了一个错误,还是你试图解决的问题根本无法通过深度学习解决。你也不知道去哪里寻求帮助。因此,最好首先从你可以在网上找到一个例子开始,在这个例子中,有人在至少与你试图实现的目标有些相似的事情上取得了很好的结果,或者你可以将你的数据转换为类似于其他人以前使用过的格式(例如从你的数据创建图像)。让我们看看深度学习的状态,这样你就知道深度学习现在擅长哪些事情。
The State of Deep Learning
深度学习的现状
Let's start by considering whether deep learning can be any good at the problem you are looking to work on. This section provides a summary of the state of deep learning at the start of 2020. However, things move very fast, and by the time you read this some of these constraints may no longer exist. We will try to keep the book's website up-to-date; in addition, a Google search for "what can AI do now" is likely to provide current information.
让我们从考虑深度学习是否能很好地解决你想要解决的问题开始。本节概述了2020年初深度学习的状态。然而,事情发展得非常快,当你读到这篇文章时,其中一些限制可能已经不存在了。我们将努力保持本书的网站是最新的;此外,谷歌搜索“人工智能现在能做什么”可能会提供当前信息。
Computer vision
计算机视觉
There are many domains in which deep learning has not been used to analyze images yet, but those where it has been tried have nearly universally shown that computers can recognize what items are in an image at least as well as people can—even specially trained people, such as radiologists. This is known as object recognition. Deep learning is also good at recognizing where objects in an image are, and can highlight their locations and name each found object. This is known as object detection (there is also a variant of this that we saw in <<chapter_intro>>, where every pixel is categorized based on what kind of object it is part of—this is called segmentation). Deep learning algorithms are generally not good at recognizing images that are significantly different in structure or style to those used to train the model. For instance, if there were no black-and-white images in the training data, the model may do poorly on black-and-white images. Similarly, if the training data did not contain hand-drawn images, then the model will probably do poorly on hand-drawn images. There is no general way to check what types of images are missing in your training set, but we will show in this chapter some ways to try to recognize when unexpected image types arise in the data when the model is being used in production (this is known as checking for out-of-domain data).
One major challenge for object detection systems is that image labelling can be slow and expensive. There is a lot of work at the moment going into tools to try to make this labelling faster and easier, and to require fewer handcrafted labels to train accurate object detection models. One approach that is particularly helpful is to synthetically generate variations of input images, such as by rotating them or changing their brightness and contrast; this is called data augmentation and also works well for text and other types of models. We will be discussing it in detail in this chapter.
Another point to consider is that although your problem might not look like a computer vision problem, it might be possible with a little imagination to turn it into one. For instance, if what you are trying to classify are sounds, you might try converting the sounds into images of their acoustic waveforms and then training a model on those images.
在许多领域,深度学习还没有被用于分析图像,但那些已经尝试过的领域几乎普遍表明,计算机至少可以像人类——甚至是受过专门训练的人一样识别图像中的项目,例如放射科医生。这被称为对象识别。深度学习还擅长识别图像中的对象在哪里,并且可以突出显示它们的位置并为每个找到的对象命名。这被称为目标检测(我们在<>中看到的还有一个变体,其中每个像素都根据它是什么样的对象的一部分进行分类——这被称为分割)。深度学习算法通常不擅长识别结构或风格与用于训练模型的图像显著不同的图像。例如,如果训练数据中没有黑白图像,模型可能在黑白图像上表现不佳。同样,如果训练数据不包含手绘图像,那么模型可能会在手绘图像上表现不佳。没有通用的方法来检查训练集中缺少哪些类型的图像,但我们将在本章中展示一些方法,以尝试识别模型在生产中使用时数据中何时出现意外的图像类型(这称为检查域外数据)。
目标检测系统面临的一个主要挑战是图像标记可能既慢又昂贵。目前有很多工作要做,试图让这种标记更快、更容易,并且需要更少的手工标记来训练准确的目标检测模型。一种特别有用的方法是合成生成输入图像的变化,例如旋转它们或改变它们的亮度和对比度;这被称为数据增强,也适用于文本和其他类型的模型。我们将在本章详细讨论它。
另一点需要考虑的是,尽管你的问题看起来不像是计算机视觉问题,但只要有一点想象力,就有可能把它变成一个问题。例如,如果你试图分类的是声音,你可以试着把声音转换成它们的声音波形的图像,然后在这些图像上训练一个模型。
Text (natural language processing)
文本(自然语言处理)
Computers are very good at classifying both short and long documents based on categories such as spam or not spam, sentiment (e.g., is the review positive or negative), author, source website, and so forth. We are not aware of any rigorous work done in this area to compare them to humans, but anecdotally it seems to us that deep learning performance is similar to human performance on these tasks. Deep learning is also very good at generating context-appropriate text, such as replies to social media posts, and imitating a particular author's style. It's good at making this content compelling to humans too—in fact, even more compelling than human-generated text. However, deep learning is currently not good at generating correct responses! We don't currently have a reliable way to, for instance, combine a knowledge base of medical information with a deep learning model for generating medically correct natural language responses. This is very dangerous, because it is so easy to create content that appears to a layman to be compelling, but actually is entirely incorrect.
Another concern is that context-appropriate, highly compelling responses on social media could be used at massive scale—thousands of times greater than any troll farm previously seen—to spread disinformation, create unrest, and encourage conflict. As a rule of thumb, text generation models will always be technologically a bit ahead of models recognizing automatically generated text. For instance, it is possible to use a model that can recognize artificially generated content to actually improve the generator that creates that content, until the classification model is no longer able to complete its task.
Despite these issues, deep learning has many applications in NLP: it can be used to translate text from one language to another, summarize long documents into something that can be digested more quickly, find all mentions of a concept of interest, and more. Unfortunately, the translation or summary could well include completely incorrect information! However, the performance is already good enough that many people are using these systems—for instance, Google's online translation system (and every other online service we are aware of) is based on deep learning.
计算机非常擅长根据垃圾邮件或非垃圾邮件、情绪(例如,评论是正面还是负面)、作者、源网站等类别对短文档和长文档进行分类。我们不关心在这一领域任何将它们与人类进行比较的严格工作,但有趣的是,在我们看来,深度学习的表现与人类在这些任务上的表现相似。深度学习还非常擅长生成适合上下文的文本,例如对社交媒体帖子的回复,并模仿特定作者的风格。它也擅长让这些内容对人类有吸引力——事实上,甚至比人类生成的文本更有吸引力。然而,深度学习目前不擅长生成正确的反应!例如,我们目前没有可靠的方法将医学信息知识库与深度学习模型相结合,以生成医学上正确的自然语言反应。这是非常危险的,因为创建外行人认为引人注目但实际上完全不正确的内容是如此容易。
另一个担忧是社交媒体上适合上下文、高度引人注目的反应可能被大规模使用——比以往任何巨魔农场都要大几千倍——传播虚假信息、制造动荡和鼓励冲突。作为经验法则,文本生成模型在技术上总是比识别自动生成文本的模型领先一点。例如,可以使用可以识别人工生成内容的模型来实际改进创建内容的生成器,直到分类模型不再能够完成其任务。
尽管存在这些问题,深度学习在NLP中仍有许多应用:它可用于将文本从一种语言翻译成另一种语言,将长文档总结为可以更快消化的内容,查找所有提及兴趣概念的内容等等。不幸的是,翻译或摘要很可能包含完全不正确的信息!然而,性能已经足够好,以至于许多人都在使用这些系统——例如,谷歌的在线翻译系统(以及我们所知道的所有其他在线服务)都是基于深度学习的。
Combining text and images
结合文本和图像
The ability of deep learning to combine text and images into a single model is, generally, far better than most people intuitively expect. For example, a deep learning model can be trained on input images with output captions written in English, and can learn to generate surprisingly appropriate captions automatically for new images! But again, we have the same warning that we discussed in the previous section: there is no guarantee that these captions will actually be correct.
Because of this serious issue, we generally recommend that deep learning be used not as an entirely automated process, but as part of a process in which the model and a human user interact closely. This can potentially make humans orders of magnitude more productive than they would be with entirely manual methods, and actually result in more accurate processes than using a human alone. For instance, an automatic system can be used to identify potential stroke victims directly from CT scans, and send a high-priority alert to have those scans looked at quickly. There is only a three-hour window to treat strokes, so this fast feedback loop could save lives. At the same time, however, all scans could continue to be sent to radiologists in the usual way, so there would be no reduction in human input. Other deep learning models could automatically measure items seen on the scans, and insert those measurements into reports, warning the radiologists about findings that they may have missed, and telling them about other cases that might be relevant.
深度学习将文本和图像组合成一个模型的能力通常比大多数人直观地预期的要好得多。例如,深度学习模型可以在输入图像上进行训练,输出标题是用英语写的,并且可以学习为新图像自动生成令人惊讶的合适标题!但是,我们再次提出了与上一节讨论的相同警告:不能保证这些标题实际上是正确的。
由于这个严重的问题,我们通常建议深度学习不要作为一个完全自动化的过程,而是作为模型和人类用户密切互动的过程的一部分。这可能会使人类比完全手动的方法更有效率,并且实际上比单独使用人类更准确。例如,自动系统可用于直接从CT扫描中识别潜在的中风患者,并发送高优先级警报以快速查看这些扫描。只有三个小时的时间来治疗中风,因此这种快速反馈可以挽救生命。但是,与此同时,所有扫描可以继续以通常的方式发送给放射科医生,因此不会减少人工输入。其他深度学习模型可以自动测量扫描中看到的项目,并将这些测量值插入报告中,警告放射科医生他们可能错过的发现,并告诉他们其他可能相关的病例。
Tabular data
表格数据
For analyzing time series and tabular data, deep learning has recently been making great strides. However, deep learning is generally used as part of an ensemble of multiple types of model. If you already have a system that is using random forests or gradient boosting machines (popular tabular modeling tools that you will learn about soon), then switching to or adding deep learning may not result in any dramatic improvement. Deep learning does greatly increase the variety of columns that you can include—for example, columns containing natural language (book titles, reviews, etc.), and high-cardinality categorical columns (i.e., something that contains a large number of discrete choices, such as zip code or product ID). On the down side, deep learning models generally take longer to train than random forests or gradient boosting machines, although this is changing thanks to libraries such as RAPIDS, which provides GPU acceleration for the whole modeling pipeline. We cover the pros and cons of all these methods in detail in <<chapter_tabular>>.
在分析时间序列和表格数据方面,深度学习最近取得了长足的进步。然而,深度学习通常被用作多种类型模型集成的一部分。如果您已经有一个系统正在使用随机森林或梯度提升机(您将很快了解到的流行表格建模工具),那么切换到或添加深度学习可能不会带来任何显着的改进。深度学习确实大大增加了您可以包含的列的种类——例如,包含自然语言(书名、评论等)的列和高基数分类列(即包含大量离散选择的东西,例如邮政编码或产品ID)。不利的一面是,深度学习模型通常比随机森林或梯度提升机器需要更长的时间来训练,尽管由于RAPIDS等库,这种情况正在改变,它为整个建模管道提供GPU加速。我们在<>中详细介绍了所有这些方法的优缺点。
Recommendation systems
推荐系统
Recommendation systems are really just a special type of tabular data. In particular, they generally have a high-cardinality categorical variable representing users, and another one representing products (or something similar). A company like Amazon represents every purchase that has ever been made by its customers as a giant sparse matrix, with customers as the rows and products as the columns. Once they have the data in this format, data scientists apply some form of collaborative filtering to fill in the matrix. For example, if customer A buys products 1 and 10, and customer B buys products 1, 2, 4, and 10, the engine will recommend that A buy 2 and 4. Because deep learning models are good at handling high-cardinality categorical variables, they are quite good at handling recommendation systems. They particularly come into their own, just like for tabular data, when combining these variables with other kinds of data, such as natural language or images. They can also do a good job of combining all of these types of information with additional metadata represented as tables, such as user information, previous transactions, and so forth.
However, nearly all machine learning approaches have the downside that they only tell you what products a particular user might like, rather than what recommendations would be helpful for a user. Many kinds of recommendations for products a user might like may not be at all helpful—for instance, if the user is already familiar with the products, or if they are simply different packagings of products they have already purchased (such as a boxed set of novels, when they already have each of the items in that set). Jeremy likes reading books by Terry Pratchett, and for a while Amazon was recommending nothing but Terry Pratchett books to him (see <>), which really wasn't helpful because he already was aware of these books!
推荐系统实际上只是一种特殊类型的表格数据。特别是,它们通常有一个代表用户的高基数分类变量,另一个代表产品(或类似的东西)。像亚马逊这样的公司将客户曾经进行过的每一次购买都表示为一个巨大的稀疏矩阵,客户作为行,产品作为列。一旦他们拥有这种格式的数据,数据科学家就会应用某种形式的协同过滤来填充矩阵。例如,如果客户A购买产品1和10,客户B购买产品1、2、4和10,引擎会建议A购买2和4。因为深度学习模型擅长处理高基数分类变量,所以它们非常擅长处理推荐系统。当将这些变量与其他类型的数据(如自然语言或图像)相结合时,它们特别适合自己,就像表格数据一样。它们还可以很好地将所有这些类型的信息与表示为表格的附加元数据相结合,例如用户信息、以前的交易等。
然而,几乎所有的机器学习方法都有缺点,它们只告诉你特定用户可能喜欢什么产品,而不是哪些推荐对用户有帮助。用户可能喜欢的产品的许多类型的推荐可能一点帮助都没有——例如,如果用户已经熟悉这些产品,或者如果它们只是他们已经购买的产品的不同包装(例如一套盒装小说,当他们已经拥有该集中的每一项时)。杰里米喜欢读特里·普拉切特的书,有一段时间亚马逊只向他推荐特里·普拉切特的书(见<>),这真的没有帮助,因为他已经知道这些书了!

Other data types
其他数据类型
Often you will find that domain-specific data types fit very nicely into existing categories. For instance, protein chains look a lot like natural language documents, in that they are long sequences of discrete tokens with complex relationships and meaning throughout the sequence. And indeed, it does turn out that using NLP deep learning methods is the current state-of-the-art approach for many types of protein analysis. As another example, sounds can be represented as spectrograms, which can be treated as images; standard deep learning approaches for images turn out to work really well on spectrograms.
通常你会发现特定领域的数据类型非常适合现有的类别。例如,蛋白质链看起来很像自然语言文档,因为它们是离散标记的长序列,在整个序列中具有复杂的关系和意义。事实上,事实证明,使用NLP深度学习方法是许多类型蛋白质分析的当前状态。另一个例子是,声音可以表示为光谱图,可以被视为图像;图像的标准深度学习方法在光谱图上非常有效。
The Drivetrain Approach
传动系统方法
There are many accurate models that are of no use to anyone, and many inaccurate models that are highly useful. To ensure that your modeling work is useful in practice, you need to consider how your work will be used. In 2012 Jeremy, along with Margit Zwemer and Mike Loukides, introduced a method called the Drivetrain Approach for thinking about this issue.
有许多准确的模型对任何人都没有用处,也有许多不准确的模型非常有用。为了确保您的建模工作在实践中有用,您需要考虑您的工作将如何使用。2012年,Jeremy与Margit Zwemer和Mike Loukides一起引入了一种称为Drivetray方法的方法来思考这个问题。
The Drivetrain Approach, illustrated in <>, was described in detail in "Designing Great Data Products". The basic idea is to start with considering your objective, then think about what actions you can take to meet that objective and what data you have (or can acquire) that can help, and then build a model that you can use to determine the best actions to take to get the best results in terms of your objective.
在<>中说明的传动系统方法在“设计出色的数据产品”中有详细描述。基本思想是从考虑您的目标开始,然后考虑您可以采取哪些行动来实现该目标以及您拥有(或可以获得)哪些数据可以提供帮助,然后构建一个模型,您可以使用该模型来确定要采取的最佳行动,以获得目标方面的最佳结果。

Consider a model in an autonomous vehicle: you want to help a car drive safely from point A to point B without human intervention. Great predictive modeling is an important part of the solution, but it doesn't stand on its own; as products become more sophisticated, it disappears into the plumbing. Someone using a self-driving car is completely unaware of the hundreds (if not thousands) of models and the petabytes of data that make it work. But as data scientists build increasingly sophisticated products, they need a systematic design approach.
We use data not just to generate more data (in the form of predictions), but to produce actionable outcomes. That is the goal of the Drivetrain Approach. Start by defining a clear objective. For instance, Google, when creating their first search engine, considered "What is the user’s main objective in typing in a search query?" This led them to their objective, which was to "show the most relevant search result." The next step is to consider what levers you can pull (i.e., what actions you can take) to better achieve that objective. In Google's case, that was the ranking of the search results. The third step was to consider what new data they would need to produce such a ranking; they realized that the implicit information regarding which pages linked to which other pages could be used for this purpose. Only after these first three steps do we begin thinking about building the predictive models. Our objective and available levers, what data we already have and what additional data we will need to collect, determine the models we can build. The models will take both the levers and any uncontrollable variables as their inputs; the outputs from the models can be combined to predict the final state for our objective.
考虑一下自动驾驶汽车中的模型:你想帮助汽车在没有人工干预的情况下安全地从A点驾驶到B点。出色的预测建模是解决方案的重要组成部分,但它不能独立存在;随着产品变得越来越复杂,它会消失在管道中。使用自动驾驶汽车的人完全不知道使其工作的数百(如果不是数千)个模型和PB级数据。但随着数据科学家构建越来越复杂的产品,他们需要一种系统的设计方法。
我们使用数据不仅是为了生成更多数据(以预测的形式),也是为了产生可操作的结果。这是驱动程序方法的目标。首先定义一个明确的目标。例如,谷歌在创建他们的第一个搜索引擎时,考虑了“用户输入搜索查询的主要目标是什么?”这将他们引向了他们的目标,即“显示最相关的搜索结果”。下一步是考虑你可以使用什么杠杆(即你可以采取什么行动)来更好地实现这一目标。在谷歌的案例中,这是搜索结果的排名。第三步是考虑他们需要什么样的新数据来产生这样的排名;他们意识到关于哪些页面链接到哪些其他页面的隐含信息可以用于此目的。只有在前三步之后,我们才开始考虑构建预测模型。我们的目标和可用杠杆,我们已经拥有的数据以及我们需要收集的额外数据,决定了我们可以构建的模型。模型将把杠杆和任何不可控变量作为它们的输入;模型的输出可以组合起来预测我们目标的最终状态。
Let's consider another example: recommendation systems. The objective of a recommendation engine is to drive additional sales by surprising and delighting the customer with recommendations of items they would not have purchased without the recommendation. The lever is the ranking of the recommendations. New data must be collected to generate recommendations that will cause new sales. This will require conducting many randomized experiments in order to collect data about a wide range of recommendations for a wide range of customers. This is a step that few organizations take; but without it, you don't have the information you need to actually optimize recommendations based on your true objective (more sales!).
Finally, you could build two models for purchase probabilities, conditional on seeing or not seeing a recommendation. The difference between these two probabilities is a utility function for a given recommendation to a customer. It will be low in cases where the algorithm recommends a familiar book that the customer has already rejected (both components are small) or a book that they would have bought even without the recommendation (both components are large and cancel each other out).
As you can see, in practice often the practical implementation of your models will require a lot more than just training a model! You'll often need to run experiments to collect more data, and consider how to incorporate your models into the overall system you're developing. Speaking of data, let's now focus on how to find data for your project.
让我们考虑另一个例子:推荐系统。推荐引擎的目标是通过向客户推荐他们在没有推荐的情况下不会购买的商品来增加销售。杠杆是推荐的排名。必须收集新数据来生成将导致新销售的推荐。这将需要进行许多随机实验,以便为广泛的客户收集有关广泛推荐的数据。这是很少有组织采取的步骤;但没有它,你就没有根据你的真实目标(更多销售!)实际优化推荐所需的信息。
最后,你可以建立两个购买概率模型,条件是看到或没有看到推荐。这两个概率之间的差异是给定推荐给客户的效用函数。如果算法推荐一本客户已经拒绝的熟悉的书(两个组件都很小)或一本即使没有推荐他们也会购买的书(两个组件都很大,并且相互抵消),它会很低。
如您所见,在实践中,模型的实际实现通常需要的不仅仅是训练模型!您通常需要运行实验来收集更多数据,并考虑如何将您的模型整合到您正在开发的整个系统中。说到数据,现在让我们关注如何为您的项目找到数据。
Gathering Data
收集数据
For many types of projects, you may be able to find all the data you need online. The project we'll be completing in this chapter is a bear detector. It will discriminate between three types of bear: grizzly, black, and teddy bears. There are many images on the internet of each type of bear that we can use. We just need a way to find them and download them. We've provided a tool you can use for this purpose, so you can follow along with this chapter and create your own image recognition application for whatever kinds of objects you're interested in. In the fast.ai course, thousands of students have presented their work in the course forums, displaying everything from hummingbird varieties in Trinidad to bus types in Panama—one student even created an application that would help his fiancée recognize his 16 cousins during Christmas vacation!
对于许多类型的项目,您可以在线找到所需的所有数据。我们将在本章中完成的项目是熊探测器。它将区分三种熊:灰熊、黑熊和泰迪熊。互联网上有许多我们可以使用的每种熊的图像。我们只需要一种找到它们并下载它们的方法。我们提供了一个工具,因此您可以按照本章的要求为您感兴趣的任何类型的对象创建自己的图像识别应用程序。在fast.ai课程中,成千上万的学生在课程论坛上展示了他们的作品,展示了从特立尼达的蜂鸟品种到巴拿马的公共汽车类型的一切——一名学生甚至创建了一个应用程序,可以帮助他的未婚妻在圣诞节假期认出他的16个堂兄弟!
At the time of writing, Bing Image Search is the best option we know of for finding and downloading images. It's free for up to 1,000 queries per month, and each query can download up to 150 images. However, something better might have come along between when we wrote this and when you're reading the book, so be sure to check out the book's website for our current recommendation.
在撰写本文时,必应图像搜索是我们所知的查找和下载图像的最佳选择。每月最多可免费进行1,000次查询,每个查询最多可下载150张图像。然而,在我们写这本书和您阅读这本书之间可能会出现更好的东西,所以请务必查看本书的网站以获取我们当前的推荐。
important: Keeping in Touch With the Latest Services: Services that can be used for creating datasets come and go all the time, and their features, interfaces, and pricing change regularly too. In this section, we'll show how to use the Bing Image Search API available at the time this book was written. We'll be providing more options and more up to date information on the book's website, so be sure to have a look there now to get the most current information on how to download images from the web to create a dataset for deep learning.
重要提示:与最新服务保持联系:可用于创建数据集的服务总是来来去去,它们的功能、界面和定价也会定期变化。在本节中,我们将展示如何使用本书编写时可用的必应图像搜索API。我们将在本书的网站上提供更多选项和更多最新信息,因此请务必立即查看那里,以获取有关如何从Web下载图像以创建深度学习数据集的最新信息。
clean
To download images with Bing Image Search, sign up at Microsoft Azure for a free account. You will be given a key, which you can copy and enter in a cell as follows (replacing 'XXX' with your key and executing it):
要使用必应图像搜索下载图像,请在Microsoft Azure注册一个免费帐户。您将获得一个密钥,您可以将其复制并输入到单元格中,如下所示(将“XXX”替换为您的密钥并执行它):
key = os.environ.get('AZURE_SEARCH_KEY', 'XXX')Or, if you're comfortable at the command line, you can set it in your terminal with:
export AZURE_SEARCH_KEY=your_key_hereand then restart Jupyter Notebook, and use the above line without editing it.
Once you've set key, you can use search_images_bing. This function is provided by the small utils class included with the notebooks online. If you're not sure where a function is defined, you can just type it in your notebook to find out:
或者,如果您比较喜欢使用命令行,您可以在终端中使用以下方式设置它: export AZURE_SEARCH_KEY=your_key_here 然后重新启动Jupyter Notebook,并使用上面的行而无需编辑它。 设置键后,您可以使用search_images_bing。此函数由在线笔记本中包含的小utils类提供。如果您不确定函数在哪里定义,您可以在笔记本中键入它以查找:
search_images_bingresults = search_images_bing(key, 'grizzly bear')
ims = results.attrgot('contentUrl')
len(ims)We've successfully downloaded the URLs of 150 grizzly bears (or, at least, images that Bing Image Search finds for that search term).
NB: there's no way to be sure exactly what images a search like this will find. The results can change over time. We've heard of at least one case of a community member who found some unpleasant pictures of dead bears in their search results. You'll receive whatever images are found by the web search engine. If you're running this at work, or with kids, etc, then be cautious before you display the downloaded images.
Let's look at one:
我们已经成功下载了150只灰熊的URL(或者,至少,图像搜索必应该搜索词找到的图像)。 注意:没有办法确定像这样的搜索会找到什么图片。结果会随着时间的推移而改变。我们至少听说过一个社区成员在搜索结果中发现一些令人不快的死熊图片的案例。你会收到网络搜索引擎找到的任何图片。如果你在工作中或与孩子一起运行这个程序,那么在显示下载的图像之前要小心。 让我们看一个:
#hide
ims = ['http://3.bp.blogspot.com/-S1scRCkI3vY/UHzV2kucsPI/AAAAAAAAA-k/YQ5UzHEm9Ss/s1600/Grizzly%2BBear%2BWildlife.jpg']dest = 'images/grizzly.jpg'
download_url(ims[0], dest)im = Image.open(dest)
im.to_thumb(128,128)This seems to have worked nicely, so let's use fastai's download_images to download all the URLs for each of our search terms. We'll put each in a separate folder:
这似乎很有效,所以让我们使用Fastai的download_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'))Our folder has image files, as we'd expect:
正如我们所料,我们的文件夹有图像文件:
fns = get_image_files(path)
fnsj: I just love this about working in Jupyter notebooks! It's so easy to gradually build what I want, and check my work every step of the way. I make a lot of mistakes, so this is really helpful to me...
J:我就是喜欢在Jupyter笔记本上工作!逐步构建我想要的东西是如此容易,并在每一步检查我的工作。我犯了很多错误,所以这对我真的很有帮助...
Often when we download files from the internet, there are a few that are corrupt. Let's check:
通常,当我们从Internet下载文件时,有一些文件已损坏。让我们检查一下:
failed = verify_images(fns)
failedTo remove all the failed images, you can use unlink on each of them. Note that, like most fastai functions that return a collection, verify_images returns an object of type L, which includes the map method. This calls the passed function on each element of the collection:
要删除所有失败的图像,您可以对每个图像使用unlink。请注意,与大多数返回集合的快速函数一样,verify_images返回一个类型为L的对象,其中包括map方法。这会调用集合每个元素上的传递函数:
failed.map(Path.unlink);Sidebar: Getting Help in Jupyter Notebooks
侧边栏:在Jupyter笔记本中获得帮助
Jupyter notebooks are great for experimenting and immediately seeing the results of each function, but there is also a lot of functionality to help you figure out how to use different functions, or even directly look at their source code. For instance, if you type in a cell:
??verify_imagesa window will pop up with:
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 in
enumerate(parallel(verify_image, fns)) if not o)
File: ~/git/fastai/fastai/vision/utils.py
Type: functionThis tells us what argument the function accepts (fns), then shows us the source code and the file it comes from. Looking at that source code, we can see it applies the function verify_image in parallel and only keeps the image files for which the result of that function is False, which is consistent with the doc string: it finds the images in fns that can't be opened.
Here are some other features that are very useful in Jupyter notebooks:
- At any point, if you don't remember the exact spelling of a function or argument name, you can press Tab to get autocompletion suggestions.
- When inside the parentheses of a function, pressing Shift and Tab simultaneously will display a window with the signature of the function and a short description. Pressing these keys twice will expand the documentation, and pressing them three times will open a full window with the same information at the bottom of your screen.
- In a cell, typing
?func_nameand executing will open a window with the signature of the function and a short description. - In a cell, typing
??func_nameand executing will open a window with the signature of the function, a short description, and the source code. - If you are using the fastai library, we added a
docfunction for you: executingdoc(func_name)in a cell will open a window with the signature of the function, a short description and links to the source code on GitHub and the full documentation of the function in the library docs. - Unrelated to the documentation but still very useful: to get help at any point if you get an error, type
%debugin the next cell and execute to open the Python debugger, which will let you inspect the content of every variable.
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 in
enumerate(parallel(verify_image, fns)) if not o)
File: ~/git/fastai/fastai/vision/utils.py
Type: function
这告诉我们函数接受什么参数(fns),然后向我们显示源代码和它来自的文件。查看该源代码,我们可以看到它并行应用函数verify_image,并且只保留该函数结果为False的图像文件,这与doc字符串一致:它在fns中查找无法打开的图像。
以下是Jupyter笔记本中非常有用的其他一些功能: 在任何时候,如果您不记得函数或参数名称的确切拼写,您可以按Tab获取自动完成建议。 当在函数的括号内时,同时按Shift和Tab将显示一个带有函数签名和简短描述的窗口。按两次这些键将展开留档,按三次将在屏幕底部打开一个包含相同信息的完整窗口。 在单元格中,键入?func_name并执行将打开一个带有函数签名和简短描述的窗口。 在单元格中,键入??func_name并执行将打开一个窗口,其中包含函数签名、简短描述和源代码。 如果您使用的是Fastai库,我们为您添加了一个doc函数:在单元格中执行doc(func_name)将打开一个窗口,其中包含函数的签名、简短的描述和指向GitHub上源代码的链接以及库文档中函数的完整留档。 与留档无关,但仍然非常有用:如果您遇到错误,要在任何时候获得帮助,请在下一个单元格中键入%debug并执行以打开Python 编程语言编程语言调试器,这将允许您检查每个变量的内容。
End sidebar
结束侧边栏
One thing to be aware of in this process: as we discussed in <<chapter_intro>>, models can only reflect the data used to train them. And the world is full of biased data, which ends up reflected in, for example, Bing Image Search (which we used to create our dataset). For instance, let's say you were interested in creating an app that could help users figure out whether they had healthy skin, so you trained a model on the results of searches for (say) "healthy skin." <<healthy_skin>> shows you the kinds of results you would get.
在这个过程中需要注意的一件事:正如我们在<>中讨论的那样,模型只能反映用于训练它们的数据。这个世界充满了有偏差的数据,最终反映在例如必应图像搜索(我们用来创建数据集)中。例如,假设您有兴趣创建一个应用程序来帮助用户确定他们是否拥有健康的皮肤,因此您根据搜索(例如)“健康皮肤”的结果训练了一个模型。<>向您展示了您将获得的结果类型。

With this as your training data, you would end up not with a healthy skin detector, but a young white woman touching her face detector! Be sure to think carefully about the types of data that you might expect to see in practice in your application, and check carefully to ensure that all these types are reflected in your model's source data. footnote:[Thanks to Deb Raji, who came up with the "healthy skin" example. See her paper "Actionable Auditing: Investigating the Impact of Publicly Naming Biased Performance Results of Commercial AI Products" for more fascinating insights into model bias.]
将此作为您的训练数据,您最终得到的不是健康的皮肤检测器,而是一位年轻的白人女性触摸她的面部检测器!请务必仔细考虑您可能期望在应用程序中实际看到的数据类型,并仔细检查以确保所有这些类型都反映在模型的源数据中。脚注:[感谢Deb Raji,她提出了“健康皮肤”的例子。请参阅她的论文“可操作审计:调查公开命名商业AI产品的有偏性能结果的影响”,以获得有关模型偏差的更迷人见解。]
Now that we have downloaded some data, we need to assemble it in a format suitable for model training. In fastai, that means creating an object called DataLoaders.
现在我们已经下载了一些数据,我们需要将其组装成适合模型训练的格式。在Fastai中,这意味着创建一个名为DataLoaders的对象。
From Data to DataLoaders
从Data到DataLoaders
DataLoaders is a thin class that just stores whatever DataLoader objects you pass to it, and makes them available as train and valid. Although it's a very simple class, it's very important in fastai: it provides the data for your model. The key functionality in DataLoaders is provided with just these four lines of code (it has some other minor functionality we'll skip over for now):
class DataLoaders(GetAttr):
def __init__(self, *loaders): self.loaders = loaders
def __getitem__(self, i): return self.loaders[i]
train,valid = add_props(lambda i,self: self[i])DataLoaders是一个瘦类,它只存储您传递给它的任何DataLoader对象,并使它们作为训练数据和验证数据时有效。虽然它是一个非常简单的类,但它在Fastai中非常重要:它为您的模型提供数据。DataLoaders中的关键功能仅由这四行代码提供(它还有一些其他次要功能,我们现在将跳过):
class DataLoaders(GetAttr):
def __init__(self, *loaders): self.loaders = loaders
def __getitem__(self, i): return self.loaders[i]
train,valid = add_props(lambda i,self: self[i])jargon: DataLoaders: A fastai class that stores multiple
DataLoaderobjects you pass to it, normally atrainand avalid, although it's possible to have as many as you like. The first two are made available as properties.
术语:DataLoaders:一个fastai类,存储您传递给它的多个DataLoader对象,通常是一个训练数据和一个验证数据,尽管可以拥有任意数量。前两个作为属性可用。
Later in the book you'll also learn about the Dataset and Datasets classes, which have the same relationship.
To turn our downloaded data into a DataLoaders object we need to tell fastai at least four things:
- What kinds of data we are working with
- How to get the list of items
- How to label these items
- How to create the validation set
So far we have seen a number of factory methods for particular combinations of these things, which are convenient when you have an application and data structure that happen to fit into those predefined methods. For when you don't, fastai has an extremely flexible system called the data block API. With this API you can fully customize every stage of the creation of your DataLoaders. Here is what we need to create a DataLoaders for the dataset that we just downloaded:
在本书的后面,您还将了解具有相同关系的Dataset和Datasets类。 要将我们下载的数据转换为DataLoaders对象,我们需要告诉Fastai至少四件事:
我们正在处理哪些类型的数据
如何获取项目列表
如何给这些物品贴上标签
如何创建验证集
到目前为止,我们已经看到了许多用于这些东西的特定组合的工厂方法,当您的应用程序和数据结构恰好适合这些预定义的方法时,这些方法很方便。如果您不这样做,Fastai有一个非常灵活的系统,称为数据块API。使用此API,您可以完全自定义创建DataLoader的每个阶段。以下是我们为刚刚下载的数据集创建DataLoader所需的内容:
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))Let's look at each of these arguments in turn. First we provide a tuple where we specify what types we want for the independent and dependent variables:
blocks=(ImageBlock, CategoryBlock)The independent variable is the thing we are using to make predictions from, and the dependent variable is our target. In this case, our independent variables are images, and our dependent variables are the categories (type of bear) for each image. We will see many other types of block in the rest of this book.
For this DataLoaders our underlying items will be file paths. We have to tell fastai how to get a list of those files. The get_image_files function takes a path, and returns a list of all of the images in that path (recursively, by default):
get_items=get_image_filesOften, datasets that you download will already have a validation set defined. Sometimes this is done by placing the images for the training and validation sets into different folders. Sometimes it is done by providing a CSV file in which each filename is listed along with which dataset it should be in. There are many ways that this can be done, and fastai provides a very general approach that allows you to use one of its predefined classes for this, or to write your own. In this case, however, we simply want to split our training and validation sets randomly. However, we would like to have the same training/validation split each time we run this notebook, so we fix the random seed (computers don't really know how to create random numbers at all, but simply create lists of numbers that look random; if you provide the same starting point for that list each time—called the seed—then you will get the exact same list each time):
splitter=RandomSplitter(valid_pct=0.2, seed=42)让我们依次看看这些参数。首先,我们提供一个元组,在其中我们指定自变量和因变量的类型:
blocks=(ImageBlock, CategoryBlock)
自变量是我们用来进行预测的东西,因变量是我们的目标。在这种情况下,我们的自变量是图像,我们的因变量是每个图像的类别(熊的类型)。我们将在本书的其余部分看到许多其他类型的块。 对于这个DataLoaders,我们的底层项目是文件路径。我们必须告诉Fastai如何获取这些文件的列表。get_image_files函数采用一个路径,并返回该路径中所有图像的列表(默认情况下递归):
get_items=get_image_files
通常,您下载的数据集已经定义了一个验证集。有时,这是通过将训练和验证集的图像放入不同的文件夹来实现的。有时,它是通过提供一个CSV文件来实现的,其中列出了每个文件名以及它应该在哪个数据集中。有很多方法可以做到这一点,Fastai提供了一种非常通用的方法,允许您为此使用它的一个预定义类,或者编写自己的类。然而,在这种情况下,我们只是想随机拆分我们的训练和验证集。但是,我们希望每次运行这个笔记本时都有相同的训练/验证拆分,所以我们修复了随机种子(计算机根本不知道如何创建随机数,而是简单地创建看起来随机的数字列表;如果你每次都为该列表提供相同的起点——称为种子——那么你每次都会得到完全相同的列表):
splitter=RandomSplitter(valid_pct=0.2, seed=42)
The independent variable is often referred to as x and the dependent variable is often referred to as y. Here, we are telling fastai what function to call to create the labels in our dataset:
get_y=parent_labelparent_label is a function provided by fastai that simply gets the name of the folder a file is in. Because we put each of our bear images into folders based on the type of bear, this is going to give us the labels that we need.
Our images are all different sizes, and this is a problem for deep learning: we don't feed the model one image at a time but several of them (what we call a mini-batch). To group them in a big array (usually called a tensor) that is going to go through our model, they all need to be of the same size. So, we need to add a transform which will resize these images to the same size. Item transforms are pieces of code that run on each individual item, whether it be an image, category, or so forth. fastai includes many predefined transforms; we use the Resize transform here:
item_tfms=Resize(128)This command has given us a DataBlock object. This is like a template for creating a DataLoaders. We still need to tell fastai the actual source of our data—in this case, the path where the images can be found:
自变量通常称为x,因变量通常称为y。在这里,我们告诉Fastai调用什么函数来在我们的数据集中创建标签:
get_y=parent_labelparent_label是Fastai提供的一个函数,它只是获取文件所在文件夹的名称。因为我们根据熊的类型将每个熊图像放入文件夹中,这将为我们提供所需的标签。 我们的图像都有不同的大小,这是深度学习的一个问题:我们不是一次给模型提供一张图像,而是提供几张(我们称之为迷你批次)。要将它们分组在一个大数组(通常称为张量)中,这将通过我们的模型,它们都需要具有相同的大小。因此,我们需要添加一个转换,将这些图像调整为相同的大小。项目转换是在每个单独的项目上运行的代码片段,无论是图像、类别还是其他。Fastai包括许多预定义的转换;我们在这里使用调整大小转换:
item_tfms=Resize(128)此命令为我们提供了一个DataBlock对象。这就像创建DataLoaders的模板。我们仍然需要告诉Fastai我们数据的实际来源——在这种情况下,可以找到图像的路径:
dls = bears.dataloaders(path)A DataLoaders includes validation and training DataLoaders. DataLoader is a class that provides batches of a few items at a time to the GPU. We'll be learning a lot more about this class in the next chapter. When you loop through a DataLoader fastai will give you 64 (by default) items at a time, all stacked up into a single tensor. We can take a look at a few of those items by calling the show_batch method on a DataLoader:
DataLoader包括验证和训练DataLoader。DataLoader是一个一次向GPU提供几批项目的类。我们将在下一章中了解更多关于这个类的信息。当您循环使用DataLoader时,一次将为您提供64个(默认情况下)项目,所有项目都堆叠成一张量。我们可以通过在DataLoader上调用show_batch方法来查看其中的一些项目:
dls.valid.show_batch(max_n=4, nrows=1)By default Resize crops the images to fit a square shape of the size requested, using the full width or height. This can result in losing some important details. Alternatively, you can ask fastai to pad the images with zeros (black), or squish/stretch them:
默认情况下,使用全宽度或高度调整图像大小以适应请求大小的正方形形状。这可能会导致丢失一些重要的细节。或者,您可以要求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)All of these approaches seem somewhat wasteful, or problematic. If we squish or stretch the images they end up as unrealistic shapes, leading to a model that learns that things look different to how they actually are, which we would expect to result in lower accuracy. If we crop the images then we remove some of the features that allow us to perform recognition. For instance, if we were trying to recognize breeds of dog or cat, we might end up cropping out a key part of the body or the face necessary to distinguish between similar breeds. If we pad the images then we have a whole lot of empty space, which is just wasted computation for our model and results in a lower effective resolution for the part of the image we actually use.
Instead, what we normally do in practice is to randomly select part of the image, and crop to just that part. On each epoch (which is one complete pass through all of our images in the dataset) we randomly select a different part of each image. This means that our model can learn to focus on, and recognize, different features in our images. It also reflects how images work in the real world: different photos of the same thing may be framed in slightly different ways.
In fact, an entirely untrained neural network knows nothing whatsoever about how images behave. It doesn't even recognize that when an object is rotated by one degree, it still is a picture of the same thing! So actually training the neural network with examples of images where the objects are in slightly different places and slightly different sizes helps it to understand the basic concept of what an object is, and how it can be represented in an image.
Here's another example where we replace Resize with RandomResizedCrop, which is the transform that provides the behavior we just described. The most important parameter to pass in is min_scale, which determines how much of the image to select at minimum each time:
所有这些方法看起来都有些浪费,或者有问题。如果我们挤压或拉伸图像,它们最终会变成不切实际的形状,导致模型学习事物看起来与实际情况不同,我们预计这会导致更低的准确率。如果我们裁剪图像,我们就会删除一些允许我们进行识别的特征。例如,如果我们试图识别狗或猫的品种,我们可能最终会裁剪出身体或面部的一个关键部分,以区分相似的品种。如果我们填充图像,那么我们就有很多空白空间,这只是浪费了我们模型的计算,并导致我们实际使用的图像部分的有效分辨率较低。
相反,我们在实践中通常会随机选择图像的一部分,并裁剪到该部分。在每个epoch(这是对数据集中所有图像的一次完整传递),我们会随机选择每张图像的不同部分。这意味着我们的模型可以学习关注并识别图像中的不同特征。它还反映了图像在现实世界中的工作方式:同一事物的不同照片可能以略有不同的方式构建。
事实上,一个完全未经训练的神经网络对图像的行为一无所知。它甚至无法识别当一个物体旋转一度时,它仍然是同一事物的图片!所以实际上用图像示例训练神经网络,其中对象位于稍微不同的位置和稍微不同的大小有助于它理解对象是什么的基本概念,以及它如何在图像中表示。
这是另一个示例,我们将Resize替换为RAnywhere ResizedCrop,这是提供我们刚刚描述的行为的转换。传入的最重要的参数是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)We used unique=True to have the same image repeated with different versions of this RandomResizedCrop transform. This is a specific example of a more general technique, called data augmentation.
我们使用unive=True让相同的图像重复使用不同版本的这种随机缩放变换。这是一种更通用的技术的具体示例,称为数据增强。
Data Augmentation
数据增强
Data augmentation refers to creating random variations of our input data, such that they appear different, but do not actually change the meaning of the data. Examples of common data augmentation techniques for images are rotation, flipping, perspective warping, brightness changes and contrast changes. For natural photo images such as the ones we are using here, a standard set of augmentations that we have found work pretty well are provided with the aug_transforms function. Because our images are now all the same size, we can apply these augmentations to an entire batch of them using the GPU, which will save a lot of time. To tell fastai we want to use these transforms on a batch, we use the batch_tfms parameter (note that we're not using RandomResizedCrop in this example, so you can see the differences more clearly; we're also using double the amount of augmentation compared to the default, for the same reason):
数据增强是指创建输入数据的随机变化,使它们看起来不同,但实际上不会改变数据的含义。图像的常见数据增强技术示例包括旋转、翻转、透视扭曲、亮度变化和对比度变化。对于我们在这里使用的自然照片图像,我们发现工作效果很好的标准增强集提供了aug_transforms功能。因为我们的图像现在都相同大小,我们可以使用GPU将这些增强应用于整整一批图像,这将节省大量时间。为了告诉Fastai我们想在批处理中使用这些转换,我们使用了batch_tfms参数(请注意,我们在本例中没有使用RAnywhere ResizedCrop,因此您可以更清楚地看到差异;出于同样的原因,我们还使用了与默认值相比双倍的增强量):
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)Now that we have assembled our data in a format fit for model training, let's actually train an image classifier using it.
现在我们已经将数据组装成适合模型训练的格式,让我们使用它训练一个图像分类器。
Training Your Model, and Using It to Clean Your Data
训练你的模型,并用它来清理你的数据
Time to use the same lines of code as in <<chapter_intro>> to train our bear classifier.
We don't have a lot of data for our problem (150 pictures of each sort of bear at most), so to train our model, we'll use RandomResizedCrop with an image size of 224 px, which is fairly standard for image classification, and default aug_transforms:
是时候使用与<>中相同的代码行来训练我们的熊分类器了。 我们没有太多的数据来解决我们的问题(每种熊最多150张图片),所以为了训练我们的模型,我们将使用图像大小为224像素的随机缩放作物,这对于图像分类来说是相当标准的,默认aug_transforms:
bears = bears.new(
item_tfms=RandomResizedCrop(224, min_scale=0.5),
batch_tfms=aug_transforms())
dls = bears.dataloaders(path)We can now create our Learner and fine-tune it in the usual way:
我们现在可以创建我们的Learner并以通常的方式对其进行微调:
learn = vision_learner(dls, resnet18, metrics=error_rate)
learn.fine_tune(4)Now let's see whether the mistakes the model is making are mainly thinking that grizzlies are teddies (that would be bad for safety!), or that grizzlies are black bears, or something else. To visualize this, we can create a confusion matrix:
现在让我们看看模型犯的错误是否主要认为灰熊是泰迪熊(这对安全有害!),还是认为灰熊是黑熊,或者其他什么。为了可视化这一点,我们可以创建一个混淆矩阵:
interp = ClassificationInterpretation.from_learner(learn)
interp.plot_confusion_matrix()The rows represent all the black, grizzly, and teddy bears in our dataset, respectively. The columns represent the images which the model predicted as black, grizzly, and teddy bears, respectively. Therefore, the diagonal of the matrix shows the images which were classified correctly, and the off-diagonal cells represent those which were classified incorrectly. This is one of the many ways that fastai allows you to view the results of your model. It is (of course!) calculated using the validation set. With the color-coding, the goal is to have white everywhere except the diagonal, where we want dark blue. Our bear classifier isn't making many mistakes!
It's helpful to see where exactly our errors are occurring, to see whether they're due to a dataset problem (e.g., images that aren't bears at all, or are labeled incorrectly, etc.), or a model problem (perhaps it isn't handling images taken with unusual lighting, or from a different angle, etc.). To do this, we can sort our images by their loss.
The loss is a number that is higher if the model is incorrect (especially if it's also confident of its incorrect answer), or if it's correct, but not confident of its correct answer. In a couple of chapters we'll learn in depth how loss is calculated and used in the training process. For now, plot_top_losses shows us the images with the highest loss in our dataset. As the title of the output says, each image is labeled with four things: prediction, actual (target label), loss, and probability. The probability here is the confidence level, from zero to one, that the model has assigned to its prediction:
行分别代表我们数据集中的所有黑熊、灰熊和泰迪熊。列分别代表模型预测为黑熊、灰熊和泰迪熊的图像。因此,矩阵的对角线显示正确分类的图像,非对角线单元格表示分类错误的图像。这是Fastai允许您查看模型结果的多种方式之一。它(当然!)使用验证集计算。使用颜色编码,目标是除了对角线之外的所有地方都是白色。我们的熊分类器不会犯很多错误!
看看我们的错误到底发生在哪里,看看它们是由于数据集问题(例如,根本不是熊的图像,或者标注不正确等)还是模型问题(也许它没有处理用不寻常的光线拍摄的图像,或者从不同的角度拍摄的图像,等等)。为此,我们可以根据图像的损失对图像进行排序。
如果模型不正确(尤其是如果它也对其错误答案有信心),或者如果它是正确的,但对其正确答案没有信心,损失是一个更高的数字。在几章中,我们将深入了解如何在训练过程中计算和使用损失。目前,plot_top_losses向我们展示了数据集中损失最高的图像。正如输出标题所说,每个图像都标注了四件事:预测、实际(目标标签)、损失和概率。这里的概率是模型分配给其预测的置信度级别,从零到一:
interp.plot_top_losses(5, nrows=1)This output shows that the image with the highest loss is one that has been predicted as "grizzly" with high confidence. However, it's labeled (based on our Bing image search) as "black." We're not bear experts, but it sure looks to us like this label is incorrect! We should probably change its label to "grizzly."
The intuitive approach to doing data cleaning is to do it before you train a model. But as you've seen in this case, a model can actually help you find data issues more quickly and easily. So, we normally prefer to train a quick and simple model first, and then use it to help us with data cleaning.
fastai includes a handy GUI for data cleaning called ImageClassifierCleaner that allows you to choose a category and the training versus validation set and view the highest-loss images (in order), along with menus to allow images to be selected for removal or relabeling:
这个输出显示损失最大的图像是被预测为高置信度的“灰熊”的图像。然而,它被标注(基于我们的图像搜索)为“黑色”。我们不是熊专家,但在我们看来,这个标签肯定是不正确的!我们可能应该把它的标签改为“灰熊”
进行数据清洗的直观方法是在训练模型之前进行。但是正如您在本例中看到的,模型实际上可以帮助您更快、更轻松地发现数据问题。因此,我们通常更喜欢先训练一个快速简单的模型,然后用它来帮助我们进行数据清洗。
Fastai包括一个方便的GUI,用于数据清洗,称为Image分类器,允许您选择类别、训练与验证集,并查看损失最高的图像(按顺序),以及允许选择图像进行删除或重新标记的菜单:
#hide_output
cleaner = ImageClassifierCleaner(learn)
cleaner
#hide
# for idx in cleaner.delete(): cleaner.fns[idx].unlink()
# for idx,cat in cleaner.change(): shutil.move(str(cleaner.fns[idx]), path/cat)We can see that amongst our "black bears" is an image that contains two bears: one grizzly, one black. So, we should choose <Delete> in the menu under this image. ImageClassifierCleaner doesn't actually do the deleting or changing of labels for you; it just returns the indices of items to change. So, for instance, to delete (unlink) all images selected for deletion, we would run:
for idx in cleaner.delete(): cleaner.fns[idx].unlink()To move images for which we've selected a different category, we would run:
for idx,cat in cleaner.change(): shutil.move(str(cleaner.fns[idx]), path/cat)s: Cleaning the data and getting it ready for your model are two of the biggest challenges for data scientists; they say it takes 90% of their time. The fastai library aims to provide tools that make it as easy as possible.
We'll be seeing more examples of model-driven data cleaning throughout this book. Once we've cleaned up our data, we can retrain our model. Try it yourself, and see if your accuracy improves!
我们可以看到,在我们的“黑熊”中,有一张图像包含两只熊:一只灰熊,一只黑色。所以,我们应该在此图像下的菜单中选择。Image分类清洁器实际上并不为您删除或更改标签;它只是返回要更改的项目的索引。因此,例如,要删除(unlink)所有选择删除的图像,我们会运行:
for idx in cleaner.delete(): cleaner.fns[idx].unlink()要移动我们选择了不同类别的图像,我们将运行:
for idx,cat in cleaner.change(): shutil.move(str(cleaner.fns[idx]), path/cat)S:清理数据并为您的模型做好准备是数据科学家面临的两个最大挑战;他们说这需要他们90%的时间。Fastai库旨在提供尽可能简单的工具。
在本书中,我们将看到更多模型驱动的数据清洗示例。一旦我们清理了数据,我们就可以重新训练我们的模型。自己试试,看看你的准确率是否提高了
note: No Need for Big Data: After cleaning the dataset using these steps, we generally are seeing 100% accuracy on this task. We even see that result when we download a lot fewer images than the 150 per class we're using here. As you can see, the common complaint that you need massive amounts of data to do deep learning can be a very long way from the truth!
注意:不需要大数据:使用这些步骤清理数据集后,我们通常会看到这项任务的100%准确率。当我们下载的图像比我们在这里使用的每类150张少得多时,我们甚至还会看到这个结果。如您所见,您需要大量数据来进行深度学习的常见抱怨可能与事实相去甚远!
Now that we have trained our model, let's see how we can deploy it to be used in practice.
现在我们已经训练了我们的模型,让我们看看如何部署它以在实践中使用。
Turning Your Model into an Online Application
将您的模型转换为在线应用程序
We are now going to look at what it takes to turn this model into a working online application. We will just go as far as creating a basic working prototype; we do not have the scope in this book to teach you all the details of web application development generally.
我们现在将研究如何将此模型转变为工作的在线应用程序。我们将只创建一个基本的工作原型;我们在本书中没有范围来教您Web应用程序开发的所有细节。
Using the Model for Inference
使用模型进行推理
Once you've got a model you're happy with, you need to save it, so that you can then copy it over to a server where you'll use it in production. Remember that a model consists of two parts: the architecture and the trained parameters. The easiest way to save the model is to save both of these, because that way when you load a model you can be sure that you have the matching architecture and parameters. To save both parts, use the export method.
This method even saves the definition of how to create your DataLoaders. This is important, because otherwise you would have to redefine how to transform your data in order to use your model in production. fastai automatically uses your validation set DataLoader for inference by default, so your data augmentation will not be applied, which is generally what you want.
When you call export, fastai will save a file called "export.pkl":
一旦你有了一个你满意的模型,你需要保存它,这样你就可以把它复制到服务器上,在那里你将在生产中使用它。请记住,模型由两部分组成:架构和训练好的参数。保存模型的最简单方法是保存这两部分,因为这样当你加载模型时,你可以确保你有匹配的架构和参数。要保存这两个部分,请使用导出方法。
此方法甚至保存了如何创建DataLoader的定义。这很重要,因为否则您将不得不重新定义如何转换数据才能在生产中使用您的模型。默认情况下,Fastai会自动使用您的验证集DataLoader进行推理,因此不会应用您的数据增强,这通常是您想要的。
当您调用export时,Fastai会保存一个名为“export.pkl”的文件:
learn.export()Let's check that the file exists, by using the ls method that fastai adds to Python's Path class:
让我们检查文件是否存在,通过使用ls方法,Fastai添加到Python 编程语言编程语言的Path类中:
path = Path()
path.ls(file_exts='.pkl')You'll need this file wherever you deploy your app to. For now, let's try to create a simple app within our notebook.
When we use a model for getting predictions, instead of training, we call it inference. To create our inference learner from the exported file, we use load_learner (in this case, this isn't really necessary, since we already have a working Learner in our notebook; we're just doing it here so you can see the whole process end-to-end):
无论您将应用程序部署到何处,都需要此文件。现在,让我们尝试在笔记本中创建一个简单的应用程序。
当我们使用模型来获取预测时,我们称之为推理,而不是训练。要从导出的文件创建推理学习器,我们使用load_learner(在这种情况下,这不是真正必要的,因为我们的笔记本中已经有了一个工作学习器;我们只是在这里这样做,这样您就可以看到端到端的整个过程):
learn_inf = load_learner(path/'export.pkl')When we're doing inference, we're generally just getting predictions for one image at a time. To do this, pass a filename to predict:
当我们进行推理时,我们通常一次只获取一个图像的预测。为此,请传递一个文件名来预测:
learn_inf.predict('images/grizzly.jpg')This has returned three things: the predicted category in the same format you originally provided (in this case that's a string), the index of the predicted category, and the probabilities of each category. The last two are based on the order of categories in the vocab of the DataLoaders; that is, the stored list of all possible categories. At inference time, you can access the DataLoaders as an attribute of the Learner:
这返回了三件事:与您最初提供的格式相同的预测类别(在本例中为字符串)、预测类别的索引以及每个类别的概率。最后两个基于DataLoaders词汇表中类别的顺序;即所有可能类别的存储列表。在推理时,您可以作为Learner的属性访问DataLoaders:
learn_inf.dls.vocabWe can see here that if we index into the vocab with the integer returned by predict then we get back "grizzly," as expected. Also, note that if we index into the list of probabilities, we see a nearly 1.00 probability that this is a grizzly.
我们可以在这里看到,如果我们索引到带有预测返回的整数的词汇表中,那么我们就会像预期的那样返回“灰熊”。此外,请注意,如果我们索引到概率列表中,我们会看到接近1.00的概率这是灰熊。
We know how to make predictions from our saved model, so we have everything we need to start building our app. We can do it directly in a Jupyter notebook.
我们知道如何从保存的模型中进行预测,因此我们拥有开始构建应用程序所需的一切。我们可以直接在Jupyter笔记本中完成。
Creating a Notebook App from the Model
从模型创建笔记本应用程序
To use our model in an application, we can simply treat the predict method as a regular function. Therefore, creating an app from the model can be done using any of the myriad of frameworks and techniques available to application developers.
However, most data scientists are not familiar with the world of web application development. So let's try using something that you do, at this point, know: it turns out that we can create a complete working web application using nothing but Jupyter notebooks! The two things we need to make this happen are:
- IPython widgets (ipywidgets)
- Voilà
IPython widgets are GUI components that bring together JavaScript and Python functionality in a web browser, and can be created and used within a Jupyter notebook. For instance, the image cleaner that we saw earlier in this chapter is entirely written with IPython widgets. However, we don't want to require users of our application to run Jupyter themselves.
That is why Voilà exists. It is a system for making applications consisting of IPython widgets available to end users, without them having to use Jupyter at all. Voilà is taking advantage of the fact that a notebook already is a kind of web application, just a rather complex one that depends on another web application: Jupyter itself. Essentially, it helps us automatically convert the complex web application we've already implicitly made (the notebook) into a simpler, easier-to-deploy web application, which functions like a normal web application rather than like a notebook.
But we still have the advantage of developing in a notebook, so with ipywidgets, we can build up our GUI step by step. We will use this approach to create a simple image classifier. First, we need a file upload widget:
要在应用程序中使用我们的模型,我们可以简单地将预测方法视为常规函数。因此,可以使用应用程序开发人员可用的无数框架和技术中的任何一种来从模型创建应用程序。 然而,大多数数据科学家并不熟悉Web应用程序开发的世界。因此,让我们尝试一些您所做的事情,在这一点上,已知:事实证明,我们可以使用Jupyter笔记本创建一个完整工作Web应用程序!我们需要做到这一点的两件事是:
IPython小部件(ipywidgets) Voilà
IPython小部件是在Web浏览器中将JavaScript和Python 编程语言编程语言功能结合在一起的GUI组件,可以在Jupyter笔记本中创建和使用。例如,我们在本章前面看到的图像清理器完全是用IPython小部件编写的。但是,我们不想要求应用程序的用户自己运行Jupyter。
这就是Voilà存在的原因。它是一个让最终用户可以使用由IPython小部件组成的应用程序的系统,而他们根本无需使用Jupyter。Voilà利用了笔记本已经是一种Web应用程序的事实,只是一个依赖于另一个Web应用程序的相当复杂的应用程序:Jupyter本身。从本质上讲,它可以帮助我们自动将我们已经隐式制作的复杂Web应用程序(笔记本)转换为更简单、更易于部署的Web应用程序,其功能类似于普通的Web应用程序,而不是笔记本。 但是我们仍然有在笔记本中开发的优势,所以使用ipywidget,我们可以逐步建立我们的GUI。我们将使用这种方法来创建一个简单的图像分类器。首先,我们需要一个文件上传小部件:
#hide_output
btn_upload = widgets.FileUpload()
btn_upload
Now we can grab the image:
现在我们可以抓取图像:
#hide
# For the book, we can't actually click an upload button, so we fake it
btn_upload = SimpleNamespace(data = ['images/grizzly.jpg'])img = PILImage.create(btn_upload.data[-1])
We can use an Output widget to display it:
我们可以使用输出小部件来显示它:
#hide_output
out_pl = widgets.Output()
out_pl.clear_output()
with out_pl: display(img.to_thumb(128,128))
out_pl
Then we can get our predictions:
然后我们可以得到我们的预测:
pred,pred_idx,probs = learn_inf.predict(img)and use a Label to display them:
并使用标签显示它们:
#hide_output
lbl_pred = widgets.Label()
lbl_pred.value = f'Prediction: {pred}; Probability: {probs[pred_idx]:.04f}'
lbl_predPrediction: grizzly; Probability: 1.0000
We'll need a button to do the classification. It looks exactly like the upload button:
我们需要一个按钮来进行分类。它看起来和上传按钮一模一样:
#hide_output
btn_run = widgets.Button(description='Classify')
btn_runWe'll also need a click event handler; that is, a function that will be called when it's pressed. We can just copy over the lines of code from above:
我们还需要一个点击事件处理程序;也就是说,按下它时会调用的函数。我们可以从上面复制代码行:
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)You can test the button now by pressing it, and you should see the image and predictions update automatically!
We can now put them all in a vertical box (VBox) to complete our GUI:
您现在可以按下按钮进行测试,您应该会看到图像和预测自动更新!
我们现在可以将它们全部放在垂直框(VBox)中以完成我们的GUI:
#hide
#Putting back btn_upload to a widget for next cell
btn_upload = widgets.FileUpload()#hide_output
VBox([widgets.Label('Select your bear!'),
btn_upload, btn_run, out_pl, lbl_pred])
We have written all the code necessary for our app. The next step is to convert it into something we can deploy.
我们已经编写了应用程序所需的所有代码。下一步是将其转换为我们可以部署的东西。
Turning Your Notebook into a Real App
将您的笔记本变成真正的应用程序
#hide
# !pip install voila
# !jupyter serverextension enable --sys-prefix voila Now that we have everything working in this Jupyter notebook, we can create our application. To do this, start a new notebook and add to it only the code needed to create and show the widgets that you need, and markdown for any text that you want to appear. Have a look at the bear_classifier notebook in the book's repo to see the simple notebook application we created.
Next, install Voilà if you haven't already, by copying these lines into a notebook cell and executing it:
!pip install voila
!jupyter serverextension enable --sys-prefix voilaCells that begin with a ! do not contain Python code, but instead contain code that is passed to your shell (bash, Windows PowerShell, etc.). If you are comfortable using the command line, which we'll discuss more later in this book, you can of course simply type these two lines (without the ! prefix) directly into your terminal. In this case, the first line installs the voila library and application, and the second connects it to your existing Jupyter notebook.
Voilà runs Jupyter notebooks just like the Jupyter notebook server you are using now does, but it also does something very important: it removes all of the cell inputs, and only shows output (including ipywidgets), along with your markdown cells. So what's left is a web application! To view your notebook as a Voilà web application, replace the word "notebooks" in your browser's URL with: "voila/render". You will see the same content as your notebook, but without any of the code cells.
Of course, you don't need to use Voilà or ipywidgets. Your model is just a function you can call (pred,pred_idx,probs = learn.predict(img)), so you can use it with any framework, hosted on any platform. And you can take something you've prototyped in ipywidgets and Voilà and later convert it into a regular web application. We're showing you this approach in the book because we think it's a great way for data scientists and other folks that aren't web development experts to create applications from their models.
We have our app, now let's deploy it!
现在我们已经在这个Jupyter笔记本中完成了所有工作,我们可以创建我们的应用程序。为此,启动一个新笔记本并仅向其添加创建和显示您需要的小部件所需的代码,以及要显示的任何文本的标记。查看本书存储库中的bear_classifier笔记本,以查看我们创建的简单笔记本应用程序。 接下来,如果您还没有安装Voilà,请将这些行复制到笔记本单元格中并执行它:
!pip install voila!jupyter serverextension enable --sys-prefix voila
以!开头的单元格不包含Python 编程语言编程语言代码,而是包含传递到shell(bash、Windows PowerShell等)的代码。如果您习惯使用命令行,我们将在本书后面详细讨论,您当然可以简单地将这两行(不带!前缀)直接输入到您的终端中。在这种情况下,第一行安装voila库和应用程序,第二行将其连接到您现有的Jupyter笔记本电脑。
Voilà运行Jupyter笔记本就像您现在使用的Jupyter笔记本服务器一样,但它也做了一些非常重要的事情:它删除了所有单元格输入,并且只显示输出(包括ipywidget)以及您的降价单元格。所以剩下的是一个Web应用程序!要将您的笔记本视为VoilàWeb应用程序,请将浏览器URL中的“notebooks”一词替换为:“voila/render”。您将看到与笔记本相同的内容,但没有任何代码单元格。
当然,你不需要使用Voilà或ipywidgets。你的模型只是一个你可以调用的函数(pred,pred_idx, props=learn.predict(img)),所以你可以将它与任何框架一起使用,托管在任何平台上。你可以把你在ipywidgets和Voilà中原型化的东西转换成一个常规的Web应用程序。我们在书中向你展示了这种方法,因为我们认为这是数据科学家和其他不是Web开发专家的人从他们的模型创建应用程序的好方法。
我们有我们的应用程序,现在让我们部署它!
Deploying your app
部署您的应用
As you now know, you need a GPU to train nearly any useful deep learning model. So, do you need a GPU to use that model in production? No! You almost certainly do not need a GPU to serve your model in production. There are a few reasons for this:
- As we've seen, GPUs are only useful when they do lots of identical work in parallel. If you're doing (say) image classification, then you'll normally be classifying just one user's image at a time, and there isn't normally enough work to do in a single image to keep a GPU busy for long enough for it to be very efficient. So, a CPU will often be more cost-effective.
- An alternative could be to wait for a few users to submit their images, and then batch them up and process them all at once on a GPU. But then you're asking your users to wait, rather than getting answers straight away! And you need a high-volume site for this to be workable. If you do need this functionality, you can use a tool such as Microsoft's ONNX Runtime, or AWS Sagemaker
- The complexities of dealing with GPU inference are significant. In particular, the GPU's memory will need careful manual management, and you'll need a careful queueing system to ensure you only process one batch at a time.
- There's a lot more market competition in CPU than GPU servers, as a result of which there are much cheaper options available for CPU servers.
Because of the complexity of GPU serving, many systems have sprung up to try to automate this. However, managing and running these systems is also complex, and generally requires compiling your model into a different form that's specialized for that system. It's typically preferable to avoid dealing with this complexity until/unless your app gets popular enough that it makes clear financial sense for you to do so.
如您现在所知,您需要一个GPU来训练几乎任何有用的深度学习模型。那么,您需要一个GPU来在生产中使用该模型吗?不!您几乎肯定不需要GPU来在生产中为您的模型提供服务。这有几个原因:
正如我们所看到的,GPU只有在并行执行大量相同的工作时才有用。如果您正在进行(比如说)图像分类,那么您通常一次只对一个用户的图像进行分类,并且通常没有足够的工作要在单个图像中完成,以使GPU保持足够长的时间以使其非常高效。因此,CPU通常会更具成本效益。
另一种选择可能是等待几个用户提交他们的图像,然后将它们批量化并在GPU上一次性处理它们。但是,您要求您的用户等待,而不是立即获得答案!您需要一个大容量的网站才能实现这一点。如果您确实需要此功能,您可以使用Microsoft的ONNX Runtime或AWS Sagemaker等工具
处理GPU推理的复杂性很大。特别是,GPU的内存需要仔细的手动管理,您需要一个仔细的排队系统来确保一次只处理一批。 CPU的市场竞争比GPU服务器激烈得多,因此CPU服务器有更便宜的选择。
由于GPU服务的复杂性,许多系统如雨后春笋般涌现,试图将其自动化。然而,管理和运行这些系统也很复杂,通常需要将您的模型编译成专门针对该系统的不同形式。通常最好避免处理这种复杂性,直到/除非您的应用程序变得足够流行,您这样做才会具有明确的经济意义。
For at least the initial prototype of your application, and for any hobby projects that you want to show off, you can easily host them for free. The best place and the best way to do this will vary over time, so check the book's website for the most up-to-date recommendations. As we're writing this book in early 2020 the simplest (and free!) approach is to use Binder. To publish your web app on Binder, you follow these steps:
- Add your notebook to a GitHub repository.
- Paste the URL of that repo into Binder's URL, as shown in <>.
- Change the File dropdown to instead select URL.
- In the "URL to open" field, enter
/voila/render/name.ipynb(replacingnamewith the name of for your notebook). - Click the clickboard button at the bottom right to copy the URL and paste it somewhere safe.
- Click Launch.
至少对于您的应用程序的初始原型,以及您想炫耀的任何爱好项目,您都可以轻松地免费托管它们。最好的地方和最好的方式会随着时间的推移而变化,因此请查看本书的网站以获取最新的建议。当我们在2020年初编写本书时,最简单(也是免费的!)的方法是使用Binder。要在Binder上发布您的Web应用程序,您可以按照以下步骤操作: 将您的笔记本添加到GitHub存储库。 将该存储库的URL粘贴到Binder的URL中,如<>所示。 将文件下拉列表更改为选择URL。 在“要打开的URL”字段中,输入 /voila/render/name.ipynb(将名称替换为笔记本的名称)。 单击右下角的点击板按钮复制URL并将其粘贴到安全的地方。 单击启动。

The first time you do this, Binder will take around 5 minutes to build your site. Behind the scenes, it is finding a virtual machine that can run your app, allocating storage, collecting the files needed for Jupyter, for your notebook, and for presenting your notebook as a web application.
Finally, once it has started the app running, it will navigate your browser to your new web app. You can share the URL you copied to allow others to access your app as well.
For other (both free and paid) options for deploying your web app, be sure to take a look at the book's website.
第一次这样做时,Binder将需要大约5分钟来构建您的网站。在幕后,它正在寻找一个可以运行您的应用程序的虚拟机、分配存储空间、收集Jupyter、笔记本以及将笔记本呈现为Web应用程序所需的文件。 最后,一旦它启动应用程序运行,它就会将您的浏览器导航到您的新Web应用程序。您可以共享您复制的URL,以允许其他人也访问您的应用程序。 有关部署Web应用程序的其他(免费和付费)选项,请务必查看本书的网站。
You may well want to deploy your application onto mobile devices, or edge devices such as a Raspberry Pi. There are a lot of libraries and frameworks that allow you to integrate a model directly into a mobile application. However, these approaches tend to require a lot of extra steps and boilerplate, and do not always support all the PyTorch and fastai layers that your model might use. In addition, the work you do will depend on what kind of mobile devices you are targeting for deployment—you might need to do some work to run on iOS devices, different work to run on newer Android devices, different work for older Android devices, etc. Instead, we recommend wherever possible that you deploy the model itself to a server, and have your mobile or edge application connect to it as a web service.
There are quite a few upsides to this approach. The initial installation is easier, because you only have to deploy a small GUI application, which connects to the server to do all the heavy lifting. More importantly perhaps, upgrades of that core logic can happen on your server, rather than needing to be distributed to all of your users. Your server will have a lot more memory and processing capacity than most edge devices, and it is far easier to scale those resources if your model becomes more demanding. The hardware that you will have on a server is also going to be more standard and more easily supported by fastai and PyTorch, so you don't have to compile your model into a different form.
There are downsides too, of course. Your application will require a network connection, and there will be some latency each time the model is called. (It takes a while for a neural network model to run anyway, so this additional network latency may not make a big difference to your users in practice. In fact, since you can use better hardware on the server, the overall latency may even be less than if it were running locally!) Also, if your application uses sensitive data then your users may be concerned about an approach which sends that data to a remote server, so sometimes privacy considerations will mean that you need to run the model on the edge device (it may be possible to avoid this by having an on-premise server, such as inside a company's firewall). Managing the complexity and scaling the server can create additional overhead too, whereas if your model runs on the edge devices then each user is bringing their own compute resources, which leads to easier scaling with an increasing number of users (also known as horizontal scaling).
您很可能希望将您的应用程序部署到移动设备或边缘设备(如Raspberry Pi)上。有很多库和框架允许您将模型直接集成到移动应用程序中。然而,这些方法往往需要大量额外的步骤和样板,并且并不总是支持您的模型可能使用的所有机器学习库和快速层。此外,您所做的工作将取决于您针对的是哪种移动设备进行部署——您可能需要在iOS设备上运行一些工作,在较新的Android设备上运行不同的工作,在较旧的Android设备上运行不同的工作,等等。相反,我们建议您尽可能将模型本身部署到服务器,并让您的移动或边缘应用程序作为网页服务连接到它。
这种方法有很多好处。初始安装更容易,因为您只需要部署一个小型GUI应用程序,它连接到服务器来完成所有繁重的工作。也许更重要的是,核心逻辑的升级可以在您的服务器上进行,而不需要分发给您的所有用户。您的服务器将比大多数边缘设备拥有更多的内存和处理能力,并且如果您的模型变得更加苛刻,则更容易扩展这些资源。您将在服务器上拥有的硬件也将更加标准,并且更容易得到Fastai和机器学习库的支持,因此您不必将模型编译成不同的形式。
当然,也有缺点。您的应用程序将需要网络连接,并且每次调用模型时都会有一些延迟。(无论如何,神经网络模型需要一段时间才能运行,因此这种额外的网络延迟在实践中可能对您的用户没有太大影响。事实上,由于您可以在服务器上使用更好的硬件,因此整体延迟甚至可能比在本地运行时更少!)此外,如果您的应用程序使用敏感数据,那么您的用户可能会担心将数据发送到远程服务器的方法,因此有时出于隐私考虑意味着您需要在边缘设备上运行模型(可能可以通过拥有本地服务器来避免这种情况,例如在公司的防火墙内)。管理复杂性和标定服务器也会产生额外的开销,而如果您的模型在边缘设备上运行,那么每个用户都会带来自己的计算资源,这会导致随着用户数量的增加更容易标定(也称为水平标定)。
A: I've had a chance to see up close how the mobile ML landscape is changing in my work. We offer an iPhone app that depends on computer vision, and for years we ran our own computer vision models in the cloud. This was the only way to do it then since those models needed significant memory and compute resources and took minutes to process inputs. This approach required building not only the models (fun!) but also the infrastructure to ensure a certain number of "compute worker machines" were absolutely always running (scary), that more machines would automatically come online if traffic increased, that there was stable storage for large inputs and outputs, that the iOS app could know and tell the user how their job was doing, etc. Nowadays Apple provides APIs for converting models to run efficiently on device and most iOS devices have dedicated ML hardware, so that's the strategy we use for our newer models. It's still not easy but in our case it's worth it, for a faster user experience and to worry less about servers. What works for you will depend, realistically, on the user experience you're trying to create and what you personally find is easy to do. If you really know how to run servers, do it. If you really know how to build native mobile apps, do that. There are many roads up the hill.
Overall, we'd recommend using a simple CPU-based server approach where possible, for as long as you can get away with it. If you're lucky enough to have a very successful application, then you'll be able to justify the investment in more complex deployment approaches at that time.
Congratulations, you have successfully built a deep learning model and deployed it! Now is a good time to take a pause and think about what could go wrong.
A:我有机会近距离观察移动机器学习领域在我的工作中是如何变化的。我们提供了一个依赖于计算机视觉的iPhone应用程序,多年来我们在云中运行自己的计算机视觉模型。这是当时唯一的方法,因为这些模型需要大量的内存和计算资源,并且需要几分钟来处理输入。这种方法不仅需要构建模型(有趣!)还有确保一定数量的“计算工作机器”绝对始终运行的基础设施(可怕),如果流量增加,更多的机器会自动上线,大型输入和输出有稳定的存储,iOS应用程序可以知道并告诉用户他们的工作情况,等等。如今,苹果提供API来转换模型以在设备上高效运行,大多数iOS设备都有专用的机器学习硬件,这就是我们在新型号中使用的策略。这仍然不容易,但在我们的例子中,这是值得的,为了更快的用户体验,少担心服务器。实际上,什么对你有用将取决于你试图创造的用户体验,以及你个人发现什么很容易做到。如果你真的知道如何运行服务器,那就去做。如果你真的知道如何构建原生移动应用程序,那就去做。上山有很多路。
总的来说,我们建议尽可能使用简单的基于CPU的服务器方法,只要您能侥幸逃脱。如果您足够幸运拥有一个非常成功的应用程序,那么您将能够证明当时对更复杂的部署方法的投资是合理的。
恭喜,您已经成功构建并部署了深度学习模型!现在是暂停一下并思考可能出错的地方的好时机。
How to Avoid Disaster
如何避免灾难
In practice, a deep learning model will be just one piece of a much bigger system. As we discussed at the start of this chapter, a data product requires thinking about the entire end-to-end process, from conception to use in production. In this book, we can't hope to cover all the complexity of managing deployed data products, such as managing multiple versions of models, A/B testing, canarying, refreshing the data (should we just grow and grow our datasets all the time, or should we regularly remove some of the old data?), handling data labeling, monitoring all this, detecting model rot, and so forth. In this section we will give an overview of some of the most important issues to consider; for a more detailed discussion of deployment issues we refer to you to the excellent Building Machine Learning Powered Applications by Emmanuel Ameisen (O'Reilly)
One of the biggest issues to consider is that understanding and testing the behavior of a deep learning model is much more difficult than with most other code you write. With normal software development you can analyze the exact steps that the software is taking, and carefully study which of these steps match the desired behavior that you are trying to create. But with a neural network the behavior emerges from the model's attempt to match the training data, rather than being exactly defined.
This can result in disaster! For instance, let's say we really were rolling out a bear detection system that will be attached to video cameras around campsites in national parks, and will warn campers of incoming bears. If we used a model trained with the dataset we downloaded there would be all kinds of problems in practice, such as:
- Working with video data instead of images
- Handling nighttime images, which may not appear in this dataset
- Dealing with low-resolution camera images
- Ensuring results are returned fast enough to be useful in practice
- Recognizing bears in positions that are rarely seen in photos that people post online (for example from behind, partially covered by bushes, or when a long way away from the camera)
在实践中,深度学习模型将只是一个更大系统的一部分。正如我们在本章开始时讨论的那样,数据产品需要考虑从概念到生产使用的整个端到端过程。在本书中,我们不能指望涵盖管理已部署数据产品的所有复杂性,例如管理多个版本的模型、A/B测试、金丝雀、刷新数据(我们应该一直增长和增长我们的数据集,还是应该定期删除一些旧数据?)、处理数据标记、监控所有这些、检测模型腐烂等等。在本节中,我们将概述一些需要考虑的最重要问题;有关部署问题的更详细讨论,我们建议您参阅Emmanuel Ameisen(O'Reilly)的出色构建机器学习支持的应用程序
需要考虑的最大问题之一是理解和测试深度学习模型的行为比你编写的大多数其他代码要困难得多。通过正常的软件开发,您可以分析软件正在采取的确切步骤,并仔细研究这些步骤中的哪些步骤与您试图创建的期望行为相匹配。但是对于神经网络,行为来自模型试图匹配训练数据的尝试,而不是精确定义。 这可能会导致灾难!例如,假设我们真的正在推出一个熊检测系统,该系统将连接到国家公园露营地周围的摄像机上,并警告露营者熊的到来。如果我们使用使用我们下载的数据集训练的模型,在实践中会出现各种各样的问题,例如: 使用视频数据而不是图像 处理可能不会出现在此数据集中的夜间图像 处理低分辨率相机图像 确保返回结果的速度足够快,以便在实践中有用 在人们在网上发布的照片中很少看到的位置识别熊(例如从后面,部分被灌木丛覆盖,或者远离相机时)
A big part of the issue is that the kinds of photos that people are most likely to upload to the internet are the kinds of photos that do a good job of clearly and artistically displaying their subject matter—which isn't the kind of input this system is going to be getting. So, we may need to do a lot of our own data collection and labelling to create a useful system.
This is just one example of the more general problem of out-of-domain data. That is to say, there may be data that our model sees in production which is very different to what it saw during training. There isn't really a complete technical solution to this problem; instead, we have to be careful about our approach to rolling out the technology.
There are other reasons we need to be careful too. One very common problem is domain shift, where the type of data that our model sees changes over time. For instance, an insurance company may use a deep learning model as part of its pricing and risk algorithm, but over time the types of customers that the company attracts, and the types of risks they represent, may change so much that the original training data is no longer relevant.
Out-of-domain data and domain shift are examples of a larger problem: that you can never fully understand the entire behaviour of your neural network. They have far too many parameters to be able to analytically understand all of their possible behaviors. This is the natural downside of their best feature—their flexibility, which enables them to solve complex problems where we may not even be able to fully specify our preferred solution approaches. The good news, however, is that there are ways to mitigate these risks using a carefully thought-out process. The details of this will vary depending on the details of the problem you are solving, but we will attempt to lay out here a high-level approach, summarized in <<deploy_process>>, which we hope will provide useful guidance.
问题的很大一部分在于,人们最有可能上传到互联网的照片是那些能够很好地清晰、艺术地展示其主题的照片——这不是这个系统将获得的输入类型。因此,我们可能需要做大量自己的数据采集和标签来创建一个有用的系统。 这只是领域外数据更普遍问题的一个例子。也就是说,我们的模型在生产中看到的数据可能与训练时看到的非常不同。这个问题没有真正完整的技术解决方案;相反,我们必须小心我们推出技术的方法。 我们还需要小心其他原因。一个非常常见的问题是领域转移,我们的模型看到的数据类型会随着时间的推移而变化。例如,保险公司可能会使用深度学习模型作为其定价和风险算法的一部分,但随着时间的推移,公司吸引的客户类型及其代表的风险类型可能会发生很大变化,以至于原始训练数据不再相关。
领域外数据和领域转移是一个更大问题的例子:你永远无法完全理解你的神经网络的整个行为。它们有太多的参数,无法分析理解它们所有可能的行为。这是它们最佳特性的自然缺点——它们的灵活性,这使它们能够解决复杂的问题,而我们甚至可能无法完全指定我们首选的解决方案。然而,好消息是,有办法通过深思熟虑的过程来降低这些风险。细节将根据您正在解决的问题的细节而有所不同,但我们将尝试在这里列出一个高级方法,总结在<>中,我们希望这将提供有用的指导。

Where possible, the first step is to use an entirely manual process, with your deep learning model approach running in parallel but not being used directly to drive any actions. The humans involved in the manual process should look at the deep learning outputs and check whether they make sense. For instance, with our bear classifier a park ranger could have a screen displaying video feeds from all the cameras, with any possible bear sightings simply highlighted in red. The park ranger would still be expected to be just as alert as before the model was deployed; the model is simply helping to check for problems at this point.
The second step is to try to limit the scope of the model, and have it carefully supervised by people. For instance, do a small geographically and time-constrained trial of the model-driven approach. Rather than rolling our bear classifier out in every national park throughout the country, we could pick a single observation post, for a one-week period, and have a park ranger check each alert before it goes out.
Then, gradually increase the scope of your rollout. As you do so, ensure that you have really good reporting systems in place, to make sure that you are aware of any significant changes to the actions being taken compared to your manual process. For instance, if the number of bear alerts doubles or halves after rollout of the new system in some location, we should be very concerned. Try to think about all the ways in which your system could go wrong, and then think about what measure or report or picture could reflect that problem, and ensure that your regular reporting includes that information.
在可能的情况下,第一步是使用完全手动的过程,让你的深度学习模型方法并行运行,但不直接用于驱动任何行动。参与手动过程的人应该查看深度学习输出,并检查它们是否有意义。例如,使用我们的熊分类器,公园管理员可以有一个屏幕,显示来自所有摄像机的视频,任何可能的熊目击事件都只需用红色突出显示。公园管理员仍然应该像部署模型之前一样警觉;模型只是在这一点上帮助检查问题。
第二步是尝试限制模型的范围,并让人们仔细监督它。例如,对模型驱动的方法进行一个地理和时间限制的小型试验。我们可以选择一个观察站,为期一周,让公园管理员在警报发出前检查每个警报,而不是在全国每个国家公园推出我们的熊分类器。
然后,逐步扩大您的部署范围。在这样做的时候,确保您有非常好的报告系统,以确保您知道与手动流程相比所采取的行动发生了任何重大变化。例如,如果新系统在某个地方推出后,熊市警报的数量增加了一倍或一半,我们应该非常担心。试着考虑您的系统可能出错的所有方式,然后考虑哪些措施、报告或图片可以反映这个问题,并确保您的定期报告包括这些信息。
J: I started a company 20 years ago called Optimal Decisions that used machine learning and optimization to help giant insurance companies set their pricing, impacting tens of billions of dollars of risks. We used the approaches described here to manage the potential downsides of something going wrong. Also, before we worked with our clients to put anything in production, we tried to simulate the impact by testing the end-to-end system on their previous year's data. It was always quite a nerve-wracking process, putting these new algorithms into production, but every rollout was successful.
J: 20年前,我创办了一家名为“最优决策”的公司,它使用机器学习和最优化来帮助大型保险公司设定定价,影响数百亿美元的风险。我们使用这里描述的方法来管理出现问题的潜在负面影响。此外,在我们与客户合作将任何东西投入生产之前,我们试图通过对他们前一年的数据测试到端系统来模拟影响。将这些新算法投入生产总是一个相当令人紧张的过程,但每次推出都很成功。
Unforeseen Consequences and Feedback Loops
不可预见的后果和反馈循环
One of the biggest challenges in rolling out a model is that your model may change the behaviour of the system it is a part of. For instance, consider a "predictive policing" algorithm that predicts more crime in certain neighborhoods, causing more police officers to be sent to those neighborhoods, which can result in more crimes being recorded in those neighborhoods, and so on. In the Royal Statistical Society paper "To Predict and Serve?", Kristian Lum and William Isaac observe that: "predictive policing is aptly named: it is predicting future policing, not future crime."
Part of the issue in this case is that in the presence of bias (which we'll discuss in depth in the next chapter), feedback loops can result in negative implications of that bias getting worse and worse. For instance, there are concerns that this is already happening in the US, where there is significant bias in arrest rates on racial grounds. According to the ACLU, "despite roughly equal usage rates, Blacks are 3.73 times more likely than whites to be arrested for marijuana." The impact of this bias, along with the rollout of predictive policing algorithms in many parts of the US, led Bärí Williams to write in the New York Times: "The same technology that’s the source of so much excitement in my career is being used in law enforcement in ways that could mean that in the coming years, my son, who is 7 now, is more likely to be profiled or arrested—or worse—for no reason other than his race and where we live."
A helpful exercise prior to rolling out a significant machine learning system is to consider this question: "What would happen if it went really, really well?" In other words, what if the predictive power was extremely high, and its ability to influence behavior was extremely significant? In that case, who would be most impacted? What would the most extreme results potentially look like? How would you know what was really going on?
Such a thought exercise might help you to construct a more careful rollout plan, with ongoing monitoring systems and human oversight. Of course, human oversight isn't useful if it isn't listened to, so make sure that there are reliable and resilient communication channels so that the right people will be aware of issues, and will have the power to fix them.
推出一个模型的最大挑战之一是,你的模型可能会改变它所属的系统的行为。例如,考虑一种“预测性警务”算法,它预测某些社区的犯罪率会更高,导致更多警察被派往这些社区,这可能导致这些社区记录更多犯罪,等等。在皇家统计学会的论文《预测和服务?》中,克里斯蒂安·卢姆和威廉·艾萨克观察到:“预测性警务被恰当地命名:它预测未来的警务,而不是未来的犯罪。”
在这种情况下,部分问题在于,在存在偏见的情况下(我们将在下一章深入讨论),反馈循环可能会导致这种偏见的负面影响越来越严重。例如,有人担心这种情况已经在美国发生,那里基于种族原因的逮捕率存在很大的偏见。根据美国公民自由联盟的说法,“尽管使用率大致相同,但黑人因大麻被捕的可能性是白人的3.73倍。”这种偏见的影响,以及预测性警务算法在美国许多地方的推出,导致贝里·威廉姆斯在《纽约时报》上写道:“在我的职业生涯中,同样的技术让我如此兴奋,但它正被用于执法,这可能意味着在未来几年里,我现在7岁的儿子更有可能被描述或逮捕——或者更糟——除了他的种族和我们住在哪里之外,没有其他原因。”
在推出一个重要的机器学习系统之前,一个有用的练习是考虑这个问题:“如果它进行得非常非常好,会发生什么?”换句话说,如果预测能力非常高,它影响行为的能力非常重要,会发生什么?在这种情况下,谁会受到最大的影响?最极端的结果可能会是什么样子?你怎么知道到底发生了什么? 这样的思考练习可能会帮助您构建一个更仔细的部署计划,其中包含持续的监控系统和人工监督。当然,如果不听取人工监督是没有用的,因此请确保有可靠且有弹性的沟通渠道,以便合适的人会意识到问题,并有能力解决问题。
Get Writing!
开始写作吧
One of the things our students have found most helpful to solidify their understanding of this material is to write it down. There is no better test of your understanding of a topic than attempting to teach it to somebody else. This is helpful even if you never show your writing to anybody—but it's even better if you share it! So we recommend that, if you haven't already, you start a blog. Now that you've completed Chapter 2 and have learned how to train and deploy models, you're well placed to write your first blog post about your deep learning journey. What's surprised you? What opportunities do you see for deep learning in your field? What obstacles do you see?
Rachel Thomas, cofounder of fast.ai, wrote in the article "Why You (Yes, You) Should Blog":
____
The top advice I would give my younger self would be to start blogging sooner. Here are some reasons to blog:
* It’s like a resume, only better. I know of a few people who have had blog posts lead to job offers!
* Helps you learn. Organizing knowledge always helps me synthesize my own ideas. One of the tests of whether you understand something is whether you can explain it to someone else. A blog post is a great way to do that.
* I’ve gotten invitations to conferences and invitations to speak from my blog posts. I was invited to the TensorFlow Dev Summit (which was awesome!) for writing a blog post about how I don’t like TensorFlow.
* Meet new people. I’ve met several people who have responded to blog posts I wrote.
* Saves time. Any time you answer a question multiple times through email, you should turn it into a blog post, which makes it easier for you to share the next time someone asks.
____Perhaps her most important tip is this:
: You are best positioned to help people one step behind you. The material is still fresh in your mind. Many experts have forgotten what it was like to be a beginner (or an intermediate) and have forgotten why the topic is hard to understand when you first hear it. The context of your particular background, your particular style, and your knowledge level will give a different twist to what you’re writing about.
We've provided full details on how to set up a blog in <<appendix_blog>>. If you don't have a blog already, take a look at that now, because we've got a really great approach set up for you to start blogging for free, with no ads—and you can even use Jupyter Notebook!
我们的学生发现,要巩固他们对这些材料的理解,最有帮助的事情之一就是把它们写下来。没有什么比尝试把它教给别人更好的测试你对一个主题的理解了。即使你从不向任何人展示你的作品,这也很有帮助——但如果你分享它会更好!所以我们建议,如果你还没有,你开一个博客。既然你已经完成了第二章,并且已经学会了如何训练和部署模型,你就可以写你的第一篇关于深度学习之旅的博客了。你有什么惊讶的?你在你的领域看到了深度学习的哪些机会?你看到了什么障碍? fast.ai的联合创始人Rachel Thomas在《为什么你(是的,你)应该写博客》一文中写道:
我给年轻的自己的最大建议是早点开始写博客。以下是写博客的一些理由: 这就像一份简历,只是更好。我知道有几个人的博客文章会带来工作机会! *帮助你学习。组织知识总是帮助我综合自己的想法。测试你是否理解某事的一个测试是你是否能向别人解释它。博客文章是一个很好的方法。 *我从博客文章中收到了会议邀请和演讲邀请。我被邀请参加TensorFlow开发峰会(太棒了!)因为写了一篇关于我如何不喜欢TensorFlow的博客文章。 *结识新朋友。我遇到了几个回复我写的博客文章的人。 *节省时间。任何时候你通过电子邮件多次回答一个问题,你都应该把它变成博客文章,这样下次有人问的时候你就更容易分享了。
也许她最重要的建议是: :你最有能力帮助比你晚一步的人。你对这些材料仍然记忆犹新。许多专家已经忘记了初学者(或中级)的感觉,也忘记了为什么当你第一次听到这个话题时很难理解。你特定背景、特定风格和知识水平的背景会给你写的东西带来不同的转折。
我们已经提供了关于如何在<>中建立博客的全部细节。如果您还没有博客,现在就看看,因为我们已经为您设置了一个非常好的方法,可以免费开始写博客,没有广告——您甚至可以使用Jupyter Notebook!
Questionnaire
- Provide an example of where the bear classification model might work poorly in production, due to structural or style differences in the training data.
- Where do text models currently have a major deficiency?
- What are possible negative societal implications of text generation models?
- In situations where a model might make mistakes, and those mistakes could be harmful, what is a good alternative to automating a process?
- What kind of tabular data is deep learning particularly good at?
- What's a key downside of directly using a deep learning model for recommendation systems?
- What are the steps of the Drivetrain Approach?
- How do the steps of the Drivetrain Approach map to a recommendation system?
- Create an image recognition model using data you curate, and deploy it on the web.
- What is
DataLoaders? - What four things do we need to tell fastai to create
DataLoaders? - What does the
splitterparameter toDataBlockdo? - How do we ensure a random split always gives the same validation set?
- What letters are often used to signify the independent and dependent variables?
- What's the difference between the crop, pad, and squish resize approaches? When might you choose one over the others?
- What is data augmentation? Why is it needed?
- What is the difference between
item_tfmsandbatch_tfms? - What is a confusion matrix?
- What does
exportsave? - What is it called when we use a model for getting predictions, instead of training?
- What are IPython widgets?
- When might you want to use CPU for deployment? When might GPU be better?
- What are the downsides of deploying your app to a server, instead of to a client (or edge) device such as a phone or PC?
- What are three examples of problems that could occur when rolling out a bear warning system in practice?
- What is "out-of-domain data"?
- What is "domain shift"?
- What are the three steps in the deployment process?
Further Research
- Consider how the Drivetrain Approach maps to a project or problem you're interested in.
- When might it be best to avoid certain types of data augmentation?
- For a project you're interested in applying deep learning to, consider the thought experiment "What would happen if it went really, really well?"
- Start a blog, and write your first blog post. For instance, write about what you think deep learning might be useful for in a domain you're interested in.
