[深度学习] Practical Deep Learning for Coders 程序员的实用深度学习手册[1]

英文原文:https://fastai.github.io/fastbook2e/intro.html

1. 你的深度学习之旅

您好,感谢您让我们加入您的深度学习之旅,无论您已经走了多远! 在本章中,我们将告诉您更多关于本书的内容,介绍深度学习背后的关键概念,并在不同的任务上训练我们的第一个模型。 如果您没有技术或数学背景也没关系(如果您也有这样的背景也没关系!); 我们写这本书的目的是让尽可能多的人能够接触到深度学习。

1.1 深度学习适合所有人

很多人认为你需要各种难以找到的东西才能通过深度学习获得很好的结果,但正如你将在本书中看到的那样,这些人错了。 表 1.1 列出了进行世界级深度学习绝对不需要的一些事情。

表 1.1:深度学习不需要什么

神话(不需要)真相
很多数学只要高中数学就够了
大量数据我们已经看到了 <50 项数据的破纪录结果
很多昂贵的电脑您可以免费获得最先进的工作所需的东西

深度学习是一种通过使用多层神经网络来提取和转换数据的计算机技术,用例范围从人类语音识别到动物图像分类。 每一层都从前一层获取输入并逐步完善它们。 这些层通过算法进行训练,最大限度地减少错误并提高准确性。 通过这种方式,网络学习执行指定的任务。 我们将在下一节中详细讨论训练算法。

深度学习具有强大的功能、灵活性和简单性。 这就是为什么我们认为它应该应用于许多学科。 其中包括社会科学和自然科学、艺术、医学、金融、科学研究等等。 举个个人例子,尽管 Jeremy 没有医学背景,但他创办了 Enlitic,这是一家使用深度学习算法来诊断疾病的公司。 公司成立几个月后,就宣布其算法可以比放射科医生更准确地识别恶性肿瘤。

以下是深度学习或大量使用深度学习的方法在不同领域的数千项任务中的一些任务的列表,这些任务目前是世界上最好的:

  • 自然语言处理(NLP)::回答问题; 语音识别; 总结文件; 对文件进行分类; 在文件中查找姓名、日期等; 搜索提及某个概念的文章
  • 计算机视觉:卫星和无人机图像解释(例如,用于灾难恢复);人脸识别;图像字幕; 阅读交通标志; 定位自动驾驶车辆中的行人和车辆
  • 医学::发现放射图像中的异常,包括 CT、MRI 和 X 射线图像; 计数病理切片中的特征; 测量超声波特征; 诊断糖尿病视网膜病变
  • 生物学::折叠蛋白质; 对蛋白质进行分类; 许多基因组学任务,例如肿瘤正常测序和对临床可操作的基因突变进行分类; 细胞分类; 分析蛋白质/蛋白质相互作用
  • 图像生成::对图像进行着色; 提高图像分辨率; 去除图像中的噪声; 将图像转换为著名艺术家风格的艺术作品
  • 推荐系统::网络搜索; 产品推荐; 主页布局
  • 玩游戏::国际象棋、围棋、大多数 Atari 视频游戏以及许多即时战略游戏
  • 机器人技术:处理难以定位的物体(例如透明、有光泽、缺乏纹理)或难以拾取的物体
  • 其他应用::财务和物流预测、文本转语音等等……

值得注意的是,深度学习具有如此多样化的应用,但几乎所有深度学习都基于单一类型的模型,即神经网络。

但神经网络实际上并不是全新的。 为了对这个领域有更广阔的视野,有必要从一些历史开始。

1.2 神经网络:简史

1943 年,神经生理学家 Warren McCulloch 和逻辑学家 Walter Pitts 联手开发了人工神经元的数学模型。 在他们的论文“神经活动中固有的思想的逻辑演算”中,他们宣称:

由于神经活动的“全有或全无”特征,神经事件及其之间的关系可以用命题逻辑来处理。 我们发现每个网络的行为都可以用这些术语来描述。

McCulloch 和 Pitts 意识到,可以使用简单的加法和阈值来表示真实神经元的简化模型,如图 1.1 所示。 Pitts 是自学成才的,12 岁时就收到了剑桥大学的录取通知书,师从伟大的伯特兰·罗素 (Bertrand Russell)。 他没有接受这个邀请,事实上,他一生也没有接受任何高级学位或权威职位的邀请。 他的大部分著名作品都是在他无家可归时完成的。 尽管他缺乏官方认可的职位并且社会孤立日益严重,但他与 McCulloch 的工作具有影响力,并被一位名叫 Frank Rosenblatt 的心理学家接手。

在这里插入图片描述
在这里插入图片描述
图 1.1:天然和人工神经元

Rosenblatt 进一步开发了人工神经元,赋予其学习能力。 更重要的是,他致力于构建第一个实际使用这些原理的设备,即 Mark I 感知器。 Rosenblatt 在《智能自动机的设计》中这样描述这项工作:“我们现在即将见证这样一台机器的诞生——一台能够在没有任何人类训练或控制的情况下感知、识别和识别周围环境的机器。” 感知器已经建成,并且能够成功识别简单的形状。

一位名叫马文·明斯基(Marvin Minsky)的麻省理工学院教授(他在同一所高中时比罗森布拉特低一个年级!)与西摩·帕佩特(Seymour Papert)一起写了一本名为《感知器》(麻省理工学院出版社)的书,介绍了 Rosenblatt 的发明。 他们表明,这些设备的单层无法学习一些简单但关键的数学函数(例如 XOR)。 在同一本书中,他们还表明,使用多层设备可以解决这些限制。 不幸的是,这些见解中只有第一个得到了广泛认可。 结果,全球学术界在接下来的二十年里几乎完全放弃了神经网络。

也许过去 50 年神经网络领域最关键的工作是 David Rumelhart、James McClellan 和 PDP 研究小组于 1986 年由 MIT Press 出版的多卷并行分布式处理 (PDP)。 第一章提出了与 Rosenblatt 相似的希望:

人们比当今的计算机更聪明,因为大脑采用了一种基本的计算架构,该架构更适合处理人们擅长的自然信息处理任务的核心部分。 …我们将引入一个用于建模认知过程的计算框架,它似乎…比其他框架更接近计算风格,因为它可能是由大脑完成的。

PDP 在这里使用的前提是传统计算机程序的工作方式与大脑非常不同,这可能就是为什么计算机程序(在那时)不擅长做大脑认为容易的事情(例如识别图片中的物体)。 作者声称,PDP 方法“比其他框架更接近”大脑的工作方式,因此它可能能够更好地处理此类任务。

事实上,PDP 中提出的方法与当今神经网络中使用的方法非常相似。 该书将并行分布式处理定义为:

  1. 一组处理单元
  2. 激活状态
  3. 一个单元的输出函数
  4. 单元之间的连接模式
  5. 通过连接网络传播活动模式的传播规则
  6. 用于将影响单元的输入与该单元的当前状态组合起来以产生该单元的输出的激活规则
  7. 根据经验修改连接模式的学习规则
  8. 系统必须运行的环境

我们将在本书中看到现代神经网络可以满足所有这些要求。

在 1980 年代,大多数模型都是用第二层神经元构建的,从而避免了 Minsky 和 Papert 所发现的问题(这是他们的“单元之间的连接模式”,使用上面的框架)。 事实上,神经网络在 80 年代和 90 年代被广泛用于真实、实用的项目。 然而,对理论问题的误解再次阻碍了该领域的发展。 理论上,仅添加一层额外的神经元就足以让任何数学函数用这些神经网络来近似,但在实践中,此类网络通常太大且太慢而无法使用。

尽管研究人员在 30 年前就表明,要获得实际的良好性能,您需要使用更多层的神经元,但直到最近十年,这一原理才得到更广泛的认识和应用。 由于使用了更多层,再加上计算机硬件的改进、数据可用性的增加以及允许神经网络更快地训练的算法调整,神经网络现在终于发挥了其潜力。 更容易。 我们现在拥有 Rosenblatt 所承诺的:“一台能够感知、识别和识别周围环境的机器,无需任何人类训练或控制。”

这就是您将在本书中学习如何构建的内容。 但首先,因为我们要花很多时间在一起,所以让我们互相了解一下……

1.3 我们是谁

我们是 Sylvain (西尔万)和 Jeremy (杰里米),你们这段旅程的向导。 我们希望您会发现我们非常适合这个职位。

Jeremy 使用和教授机器学习已有大约 30 年的历史。 他 25 年前开始使用神经网络。 在此期间,他领导了许多以机器学习为核心的公司和项目,包括创立了第一家专注于深度学习和医学的公司Enlitic,并担任全球最大机器学习公司的总裁兼首席科学家。 社区,Kaggle。 他与 Rachel Thomas 博士是 fast.ai 的联合创始人,该组织构建了本书所基于的课程。

有时,您会在侧边栏中直接听到我们的声音,例如 Jeremy 的以下内容:

J:大家好,我是Jeremy! 您可能有兴趣知道我没有接受过任何正规的技术教育。 我完成了学士学位,主修哲学,但成绩并不好。 我对做实际项目而不是理论研究更感兴趣,所以我在大学期间在一家名为麦肯锡公司的管理咨询公司全职工作。 如果你是一个宁愿亲自动手建造东西也不愿花数年学习抽象概念的人,那么你就会明白我的来历! 请留意我的侧边栏,找到最适合数学或正式技术背景较少的人(即像我这样的人)的信息……

另一方面,Sylvain 对正规技术教育了解很多。 事实上,他已经编写了10本数学教科书,涵盖了整个法国高级数学课程!

S:与 Jeremy 不同,我并没有花费很多年的时间来编码和应用机器学习算法。 相反,我最近通过观看 Jeremy 的 fast.ai 课程视频进入了机器学习世界。 因此,如果您没有打开过终端并在命令行中编写过命令,那么您就会明白我的想法! 请留意我的侧边栏,找到最适合具有更多数学或正式技术背景但现实世界编码经验较少的人的信息,即像我这样的人…

fast.ai 课程已被来自世界各地、各行各业的数十万名学生学习。 Sylvain 是 Jeremy 见过的这门课程中最令人印象深刻的学生,这促使他加入 fast.ai,然后与 Jeremy 一起成为 fast.ai 软件库的合著者。

所有这一切意味着我们之间拥有两全其美的优势:人们比其他人更了解该软件,因为他们编写了该软件; 数学专家、编码和机器学习专家; 他们也了解作为数学领域的相对局外人以及编码和机器学习领域的相对局外人的感受。

看过体育比赛的人都知道,如果有一个两人解说组,那么还需要第三个人来做“特别解说”。 我们的特约评论员是Alexis Gallagher。 Alexis 拥有非常多元化的背景:他曾是数学生物学研究员、剧本作家、即兴表演者、麦肯锡顾问(就像 Jeremy!)、Swift 程序员和首席技术官。

A:我决定是时候学习一下人工智能的东西了! 毕竟,我已经尝试了几乎所有其他方法……但我确实没有构建机器学习模型的背景。 不过……这能有多难呢? 我将像你一样通过这本书来学习。 请留意我的侧边栏,了解我发现对我的旅程有帮助的学习技巧,希望您也会发现有帮助。

1.4 如何学习深度学习

哈佛大学教授戴维·帕金斯 (David Perkins) 着有《让学习变得完整》(Jossey-Bass),他对教学有很多话要说。 基本思想是教授整个游戏。 这意味着,如果你教棒球,你首先要带人们去看棒球比赛或让他们参加比赛。 你不会教他们如何从头开始缠绕麻线来制作棒球,抛物线的物理学,或者球在球棒上的摩擦系数。

哥伦比亚大学数学博士、前布朗大学教授、K-12 数学教师保罗·洛克哈特 (Paul Lockhart) 在颇具影响力的文章《数学家的哀歌》中想象了一个噩梦般的世界,其中音乐和艺术的教学方式与数学的教学方式相同。 孩子们必须花费十多年时间掌握乐谱和理论,并在课程中将乐谱转换成不同的调,否则不允许他们听或演奏音乐。 在艺术课上,学生们学习颜色和涂抹器,但直到上大学才允许真正绘画。 听起来很荒谬吗? 这就是数学的教学方式——我们要求学生花数年时间死记硬背,学习枯燥、互不相关的基础知识,我们声称这些基础知识将在他们大多数人退出该学科很久之后得到回报。

不幸的是,这就是许多深度学习教学资源的起点——要求学习者遵循 Hessian 矩阵的定义和损失函数的泰勒近似定理,而没有给出实际工作代码的示例。 我们并不是在敲微积分。 我们喜欢微积分,Sylvain 甚至在大学里教授过微积分,但我们认为这不是学习深度学习的最佳起点!

在深度学习中,如果您有动力修复模型以使其做得更好,那确实会有所帮助。 这就是你开始学习相关理论的时候。 但首先你需要有模型。 我们几乎通过真实的例子来教授所有内容。 当我们构建这些示例时,我们会越来越深入,我们将向您展示如何使您的项目变得越来越好。 这意味着您将在上下文中逐渐学习所需的所有理论基础,这样您就会明白它为什么重要以及它是如何工作的。

所以,这是我们对您的承诺。 在本书中,我们将遵循以下原则:

  • 教学全过程。 我们将首先展示如何使用完整、有效、非常有用、最先进的深度学习网络,并使用简单、富有表现力的工具来解决现实世界的问题。 然后我们将逐渐深入了解这些工具是如何制造的,以及制造这些工具的工具是如何制造的,等等…
  • 始终通过示例进行教学。 我们将确保您可以直观地理解上下文和目的,而不是从代数符号操作开始。
  • 尽可能地简化。 我们花了数年时间构建工具和教学方法,使以前复杂的主题变得非常简单。
  • 消除障碍。 到目前为止,深度学习一直是一个非常独特的游戏。 我们正在将其开放,并确保每个人都可以玩。

深度学习最难的部分是手工的:你如何知道你是否有足够的数据,数据的格式是否正确,你的模型是否训练正确,如果没有,你应该做什么? 这就是为什么我们相信边做边学。 与基本数据科学技能一样,深度学习只能通过实践经验才能变得更好。 试图在理论上花费太多时间可能会适得其反。 关键是只编码并尝试解决问题:当您有背景和动机时,理论可以稍后出现。

有时候,旅途会感到艰难。 你感觉被困住的时候。 不要放弃! 倒回这本书,找到最后一点你绝对没有被卡住的地方,然后从那里慢慢阅读,找到第一个不清楚的地方。 然后自己尝试一些代码实验,并通过谷歌搜索更多关于您遇到的问题的教程 - 通常您会发现材料上的一些不同角度可能会帮助您解决问题。 另外,第一次阅读时不理解所有内容(尤其是代码)是正常的。 在继续之前尝试连续理解材料有时会很困难。 有时候,当你从未来的部分中获得更多背景信息,从更大的视野中获得更多背景信息后,事情就会水到渠成。 因此,如果您确实在某个部分上遇到困难,请尝试继续前进并记下以便稍后再回来查看。

请记住,您不需要任何特定的学术背景即可在深度学习方面取得成功。 许多重要的突破都是由没有博士学位的人在研究和工业界取得的,例如 Alec 撰写的《利用深度卷积生成对抗网络进行无监督表示学习》,这是过去十年中最具影响力的论文之一,被引用次数超过 5,000 次 Alec Radford在读本科时。 即使在特斯拉,他们正在努力解决制造自动驾驶汽车的极其艰巨的挑战,首席执行官埃隆·马斯克也表示:

绝对不需要博士学位。 重要的是对人工智能的深刻理解以及以实际有用的方式实现神经网络的能力(后一点才是真正困难的地方)。 不在乎你是否高中毕业。

然而,要成功,你需要做的是将本书中学到的知识应用到个人项目中,并始终坚持下去。

你的项目和你的心态

无论您是想通过叶子图片识别植物是否患病、自动生成编织图案、通过 X 射线诊断结核病,还是确定浣熊何时使用您的猫门,我们都会让您在您的机器上使用深度学习 尽快解决自己的问题(通过其他人的预先训练的模型),然后逐步深入研究更多细节。 在下一章的前 30 分钟内,您将学习如何使用深度学习以最先进的精度解决您自己的问题! (如果您渴望立即编码,请直接跳过这里。)有一个有害的神话,您需要拥有 Google 大小的计算资源和数据集才能进行深度学习 ,但这不是真的。

那么,什么样的任务才能构成好的测试用例呢? 你可以训练你的模型来区分毕加索和莫奈的画作,或者挑选出你女儿的照片而不是你儿子的照片。 专注于你的爱好和激情会有所帮助——为自己设定四个或五个小项目,而不是努力解决一个大问题,当你开始时往往会效果更好。 由于很容易陷入困境,过早雄心勃勃往往会适得其反。 然后,一旦掌握了基础知识,就努力完成一些让您真正感到自豪的事情!

J:深度学习几乎可以解决任何问题。 例如,我的第一家初创公司是一家名为 FastMail 的公司,该公司于 1999 年推出时提供增强的电子邮件服务(至今仍然如此)。 2002 年,我将其设置为使用深度学习的原始形式(单层神经网络)来帮助对电子邮件进行分类并阻止客户接收垃圾邮件。

擅长深度学习的人的共同性格特征包括顽皮和好奇心。 已故物理学家理查德·费曼(Richard Feynman)是我们期望在深度学习方面表现出色的人的一个例子:他对亚原子粒子运动的理解的发展来自于他对板块在空气中旋转时如何摆动的兴趣。

现在让我们重点关注您将学到的内容,从软件开始。

1.5 软件:PyTorch、fastai 和 Jupyter

(以及为什么这不重要)

我们已经使用数十种不同的软件包和许多不同的编程语言完成了数百个机器学习项目。 在 fast.ai,我们使用当今使用的大多数主要深度学习和机器学习包编写了课程。 PyTorch 于 2017 年问世后,我们花了一千多个小时对其进行测试,然后决定将其用于未来的课程、软件开发和研究。 从那时起,PyTorch 已成为世界上增长最快的深度学习库,并且已被用于顶级会议上的大多数研究论文。 这通常是工业使用的领先指标,因为这些纸张最终会在商业产品和服务中使用。 我们发现 PyTorch 是最灵活、最具表现力的深度学习库。 它不会为了简单性而牺牲速度,而是两者兼而有之。

PyTorch 最适合作为低级基础库,为更高级别的功能提供基本操作。 fastai 库是在 PyTorch 之上添加此高级功能的最流行的库。 它也特别适合本书的目的,因为它在提供深层软件架构方面是独一无二的(甚至有一篇关于这种分层 API 的同行评审学术论文)。 在本书中,随着我们越来越深入地了解深度学习的基础,我们也将越来越深入地了解fastai的各个层次。 本书涵盖了 fastai 库的第二版,该版本是从头开始重写的,提供了许多独特的功能。

然而,你学习什么软件并不重要,因为学习从一个库切换到另一个库只需要几天的时间。 真正重要的是正确学习深度学习基础和技术。 我们的重点是使用能够清楚表达您需要学习的概念的代码。 在我们教授高级概念的地方,我们将使用高级 fastai 代码。 当我们教授低级概念时,我们将使用低级 PyTorch,甚至纯 Python 代码。

如果感觉现在新的深度学习库正在快速出现,那么您需要为未来几个月和几年更快的变化做好准备。 随着越来越多的人进入这个领域,他们会带来更多的技能和想法,并尝试更多的东西。 您应该假设您今天学习的任何特定库和软件将在一两年内过时。 想想网络编程世界中一直发生的库和技术堆栈的变化数量——这是一个比深度学习成熟得多、发展缓慢的领域。 我们坚信,学习的重点需要放在理解底层技术以及如何在实践中应用它们,以及如何在新工具和技术发布时快速建立专业知识。

在本书结束时,您将了解 fastai 中的几乎所有代码(以及 PyTorch 的大部分代码),因为在每一章中,我们都会更深入地了解我们在构建和训练时到底发生了什么 我们的模型。 这意味着您将学习现代深度学习中最重要的最佳实践——不仅仅是如何使用它们,还有它们的实际工作原理和实施方式。 如果您想在另一个框架中使用这些方法,您将拥有所需的知识(如果需要)。

由于学习深度学习最重要的是编写代码和实验,因此拥有一个用于实验代码的优秀平台非常重要。 最流行的编程实验平台称为 Jupyter。 这就是我们将在本书中使用的内容。 我们将向您展示如何使用 Jupyter 来训练和试验模型,并反思数据预处理和模型开发管道的每个阶段。 Jupyter Notebook 是使用 Python 进行数据科学的最流行工具,这是有充分理由的。 它功能强大、灵活且易于使用。 我们认为您会喜欢它!

让我们在实践中看看它并训练我们的第一个模型。

1.6 你的第一个模型

正如我们之前所说,在解释它们为何有效之前,我们将教您如何做事。 按照这种自上而下的方法,我们将首先实际训练图像分类器以几乎 100% 的准确度识别狗和猫。 要训练该模型并运行我们的实验,您需要进行一些初始设置。 别担心,它并不像看起来那么难。

s:不要跳过设置部分,即使它一开始看起来很吓人,特别是如果您很少或没有使用终端或命令行等东西的经验。 其中大部分实际上是不必要的,您会发现只需使用常用的网络浏览器即可设置最简单的服务器。 为了学习,在阅读本书的同时进行自己的实验是至关重要的。

获取 GPU 深度学习服务器

要完成本书中的几乎所有内容,您需要使用配备 NVIDIA GPU 的计算机(不幸的是,主要深度学习库并不完全支持其他品牌的 GPU)。 但是,我们不建议您购买; 事实上,即使您已经拥有,我们也不建议您立即使用它! 设置计算机需要时间和精力,而您现在希望将所有精力都集中在深度学习上。 因此,我们建议您租用一台已经预装了您所需的一切并准备就绪的计算机。 使用时的费用可低至每小时 0.25 美元,有些选项甚至是免费的。

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

本书使用的 GPU 服务器的最佳选择会随着时间的推移、公司的更替和价格的变化而变化。 我们在本书的网站上保留了推荐选项的列表,因此请立即访问该网站并按照说明连接到 GPU 深度学习服务器。 不用担心,在大多数平台上设置只需大约两分钟,许多平台甚至不需要任何付款,甚至不需要信用卡即可开始。

答:我的两分钱:注意这个建议! 如果您喜欢计算机,您会很想设置自己的计算机。 谨防! 这是可行的,但令人惊讶地复杂且分散注意力。 本书没有命名为“您想了解的有关 Ubuntu 系统管理、NVIDIA 驱动程序安装、apt-get、conda、pip 和 Jupyter 笔记本配置的一切”是有充分理由的。 那将是一本自己的书。 在工作中设计和部署我们的生产机器学习基础设施后,我可以证明它令人满意,但它与建模无关,就像维护飞机与驾驶飞机一样。

网站上显示的每个选项都包含一个教程; 完成本教程后,您将看到如图 1.2 所示的屏幕。

在这里插入图片描述图 1.2:Jupyter Notebook 的初始视图

您现在已经准备好运行您的第一个 Jupyter 笔记本了!

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

运行你的第一个笔记本

这些笔记本按章节进行标记,然后按笔记本编号进行标记,因此它们的顺序与本书中的顺序相同。 因此,您将看到列出的第一个笔记本就是您现在需要使用的笔记本。 您将使用此笔记本来训练可以识别狗和猫照片的模型。 为此,您将下载狗和猫照片的数据集,并使用它来训练模型。 数据集只是一堆数据——它可以是图像、电子邮件、财务指标、声音或其他任何内容。 有许多免费提供的数据集适合训练模型。 其中许多数据集是由学者创建的,以帮助推进研究,许多数据集可用于竞赛(数据科学家可以在竞赛中竞争,看看谁拥有最准确的模型!),还有一些是其他过程的副产品(例如 作为财务申报)。

注意:完整笔记本和精简笔记本:有两个文件夹包含不同版本的笔记本。 完整文件夹包含用于创建您现在正在阅读的书籍的确切笔记本,以及所有散文和输出。 精简版本具有相同的标题和代码单元,但所有输出和散文都已被删除。 阅读完本书的一部分后,我们建议您关闭书本并浏览精简的笔记本,看看您是否可以在执行之前弄清楚每个单元格将显示什么。 还要尝试回忆一下代码所演示的内容。

要打开笔记本,只需单击它即可。 笔记本将打开,如图 1.3 所示(请注意,不同平台之间的细节可能略有差异;您可以忽略这些差异)。

在这里插入图片描述
图 1.3:Jupyter 笔记本

笔记本由单元组成。 Cell主要有两种类型:

  • 包含格式化文本、图像等的单元格。 它们使用一种称为 Markdown 的格式,您很快就会了解它。
  • 包含可以执行的代码的单元格和输出将立即出现在下面(可以是纯文本、表格、图像、动画、声音,甚至是交互式应用程序)。

Jupyter 笔记本可以处于两种模式之一:编辑模式或命令模式。 在编辑模式下,在键盘上键入内容以通常的方式将字母输入到单元格中。 但是,在命令模式下,您不会看到任何闪烁的光标,并且键盘上的每个按键都有特殊的功能。

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

您可以通过按 C 来复制单元格(需要首先选择该单元格,并用其周围的轮廓表示;如果尚未选择,请单击它一次)。 然后按 V 粘贴它的副本。

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

  1. 一个名为 Oxford-IIIT Pet Dataset 的数据集包含来自 37 个不同品种的 7,349 张猫和狗的图像,将从 fast.ai 数据集集合下载到您正在使用的 GPU 服务器,然后进行提取。
  2. 将从互联网上下载已使用竞赛获胜模型对 130 万张图像进行训练的预训练模型。
  3. 预训练模型将利用迁移学习的最新进展进行微调,以创建专门用于识别狗和猫的模型。

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

# CLICK ME
from fastai.vision.all import *
path = untar_data(URLs.PETS)/'images'

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

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

在这里插入图片描述
您可能不会看到与书中完全相同的结果。 训练模型中涉及很多小的随机变化来源。 然而,在此示例中,我们通常看到错误率远低于 0.02。

重要提示: 训练时间:根据您的网络速度,下载预训练模型和数据集可能需要几分钟的时间。 运行fine_tune 可能需要一分钟左右。 本书中的模型通常需要几分钟的时间来训练,你自己的模型也是如此,因此最好想出好的技术来充分利用这段时间。 例如,在模型训练时继续阅读下一节,或者打开另一个笔记本并用它进行一些编码实验。

侧边栏:本书是用 Jupyter Notebooks 编写的

我们使用 Jupyter 笔记本编写了这本书,因此对于本书中的几乎每个图表、表格和计算,我们都会向您展示自行复制所需的确切代码。 这就是为什么在本书中,您经常会看到一些代码,后面紧跟着表格、图片或只是一些文本。 如果您访问本书的网站,您会找到所有代码,并且您可以尝试自己运行和修改每个示例。

您刚刚看到了输出表格的单元格在书中的样子。 以下是输出文本的单元格的示例:

1+1

2

Jupyter 将始终打印或显示最后一行的结果(如果有)。 例如,以下是输出图像的单元格的示例:

img = PILImage.create(image_cat())
img.to_thumb(192)

在这里插入图片描述

结束侧边栏

那么,我们怎么知道这个模型好不好呢? 在表的最后一列中,您可以看到错误率,即被错误识别的图像的比例。 错误率作为我们的指标——我们对模型质量的衡量标准,选择直观且易于理解。 正如您所看到的,尽管训练时间只有几秒钟(不包括一次性下载数据集和预训练模型),但该模型几乎是完美的。 事实上,您已经达到的准确度远远好于 10 年前任何人所达到的精度!

最后,让我们检查一下这个模型是否真的有效。 去拍一张狗或猫的照片; 如果您手头没有,只需搜索 Google 图片并下载在那里找到的图片即可。 现在执行定义了上传程序的单元格。 它将输出一个可以单击的按钮,以便您可以选择要分类的图像:

uploader = widgets.FileUpload()
uploader

在这里插入图片描述
现在您可以将上传的文件传递给模型。 确保它是单只狗或猫的清晰照片,而不是线条画、卡通或类似的照片。 笔记本会告诉你它认为自己是狗还是猫,以及它的自信程度。 希望您会发现您的模型做得很好:

img = PILImage.create(uploader.data[0])
is_cat,_,probs = learn.predict(img)
print(f"Is this a cat?: {is_cat}.")
print(f"Probability it's a cat: {probs[1].item():.6f}")

Is this a cat?: True.
Probability it’s a cat: 1.000000

恭喜你的第一个分类器!

但是,这是什么意思? 你实际上做了什么? 为了解释这一点,让我们再次缩小视野以了解全局。

什么是机器学习?

您的分类器是一个深度学习模型。 正如已经提到的,深度学习模型使用神经网络,它最初可以追溯到 20 世纪 50 年代,并且由于最近的进步而变得非常强大。

另一个关键的背景是深度学习只是更一般的机器学习学科中的一个现代领域。 要了解训练自己的分类模型时所做工作的本质,您不需要了解深度学习。 只需了解您的模型和训练过程如何作为一般适用于机器学习的概念的示例就足够了。

所以在本节中,我们将描述什么是机器学习。 我们将研究关键概念,并展示如何将它们追溯到介绍它们的原始文章。

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

通常,我们在编写程序时很容易写下完成任务的步骤。 我们只考虑如果我们必须手动完成任务,我们会采取哪些步骤,然后将它们转换成代码。 例如,我们可以编写一个对列表进行排序的函数。 一般来说,我们会编写一个类似于图 1.4 的函数(其中输入可能是未排序的列表,结果是排序的列表)。
在这里插入图片描述
图 1.4:传统程序

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

早在 1949 年计算机诞生之初,一位名叫 Arthur Samuel 的 IBM 研究人员就开始研究一种不同的方法来让计算机完成任务,他称之为机器学习。 在 1962 年的经典文章《人工智能:自动化前沿》中,他写道:

为此类计算进行计算机编程充其量是一项艰巨的任务,主要不是因为计算机本身固有的复杂性,而是因为需要以最令人恼火的细节阐明该过程的每一步。 正如任何程序员都会告诉你的那样,计算机是巨大的白痴,而不是巨大的大脑。

他的基本想法是这样的:不要告诉计算机解决问题所需的确切步骤,而是向计算机展示要解决的问题的示例,并让它自己弄清楚如何解决它。 结果证明这是非常有效的:到 1961 年,他的西洋跳棋程序已经学到了很多东西,甚至击败了康涅狄格州冠军! 他是这样描述他的想法的(来自上面的同一篇文章):

假设我们安排一些自动方法来测试任何当前权重分配在实际性能方面的有效性,并提供一种改变权重分配的机制,以便最大化性能。 我们不需要深入研究这样一个过程的细节,就可以看到它可以完全自动化,并看到这样编程的机器可以从其经验中“学习”。

这个简短的声明中包含了许多强大的概念:

  • “权重分配”的想法
  • 事实上,每个权重分配都有一些“实际表现”
  • 要求有一种“自动手段”来测试该性能,
  • 需要一种通过改变权重分配来提高性能的“机制”(即另一个自动过程)

让我们一一了解这些概念,以了解它们在实践中如何结合在一起。 首先,我们需要了解 Samuel 所说的权重分配是什么意思。

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

由于它们会影响程序,因此它们在某种意义上是另一种输入,因此我们将更新图 1.4 中的基本图片并将其替换为图 1.5,以便考虑到这一点。

在这里插入图片描述
图 1.5:使用权重分配的程序

我们已将盒子的名称从程序更改为模型。 这是为了遵循现代术语并反映该模型是一种特殊的程序:它可以根据权重做许多不同的事情。 它可以通过多种不同的方式来实现。 例如,在Samuel 的跳棋程序中,不同的权重值会导致不同的跳棋策略。

(顺便说一句,Samuel 所说的“权重”现在通常被称为模型参数,以防您遇到过该术语。术语权重是为特定类型的模型参数保留的。)

接下来,Samuel 说我们需要一种自动方法来测试任何当前权重分配在实际性能方面的有效性。 就他的西洋跳棋程序而言,模型的“实际性能”就是它的表现如何。 您可以通过将两个模型设置为相互对抗来自动测试它们的性能,并查看哪一个通常会获胜。

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

我们现在可以明白为什么他说这样的程序可以完全自动化,并且…如此编程的机器可以从其经验中“学习”。 当权重的调整也是自动的时,学习将变得完全自动化——当我们不再通过手动调整权重来改进模型时,我们依赖于一种根据性能进行调整的自动化机制。

图 1.6 显示了 Samuel 训练机器学习模型的想法的全貌。

在这里插入图片描述
图 1.6:训练机器学习模型

请注意模型 results 结果(例如跳棋游戏中的动作)与其 performance 性能(例如是否赢得比赛或获胜速度)之间的区别。

另请注意,一旦模型经过训练,也就是说,一旦我们选择了最终的、最好的、最喜欢的权重分配,那么我们就可以将权重视为模型的一部分,因为我们不再改变它们。

因此,训练后的模型的实际使用如图 1.7 所示。

在这里插入图片描述
图 1.7:使用经过训练的模型作为程序

这看起来与图 1.4 中的原始图相同,只是将“程序”一词替换为“模型”。 这是一个重要的见解:经过训练的模型可以像常规计算机程序一样对待。

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

什么是神经网络?

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

我们想要的是某种非常灵活的函数,只需改变其权重即可解决任何给定的问题。 令人惊讶的是,这个功能确实存在! 这就是我们已经讨论过的神经网络。 也就是说,如果你将神经网络视为一个数学函数,那么它会根据其权重而变得非常灵活。 称为万能逼近定理的数学证明表明,理论上该函数可以以任何精度级别解决任何问题。 神经网络如此灵活这一事实意味着,在实践中,它们通常是一种合适的模型,您可以将精力集中在训练它们的过程上,即找到良好的权重分配。

但这个过程又如何呢? 人们可以想象,您可能需要找到一种新的“机制”来自动更新每个问题的权重。 这会很费力。 我们在这里还想要一种完全通用的方法来更新神经网络的权重,以使其在任何给定任务上得到改进。 方便的是,这也存在!

这称为 stochastic gradient descent 随机梯度下降(SGD)。 我们将在第 4 章详细了解神经网络和 SGD 的工作原理,并解释万能逼近定理。 然而,现在我们将改用 Samuel 自己的话:我们不需要深入研究这样一个过程的细节,就可以看到它可以完全自动化,并看到这样编程的机器可以从其经验中“学习”。

J:别担心,SGD 和神经网络在数学上都不复杂。 两者几乎完全依赖加法和乘法来完成其工作(但它们执行大量加法和乘法!)。 当学生看到细节时,我们听到的主要反应是:“就是这样吗?”

换句话说,回顾一下,神经网络是一种特殊的机器学习模型,这恰好符合 Samuel 最初的构想。 神经网络的特殊之处在于它们高度灵活,这意味着它们只需找到正确的权重就可以解决异常广泛的问题。 这很强大,因为随机梯度下降为我们提供了一种自动找到这些权重值的方法。

缩小之后,现在让我们重新放大并使用 Samuel 的框架重新审视我们的图像分类问题。

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

下一个怎么样,一种自动测试任何当前权重分配在实际性能方面的有效性的方法? 确定“实际性能”非常简单:我们可以简单地将模型的性能定义为其预测正确答案的准确性。

将所有这些放在一起,并假设 SGD 是我们更新权重分配的机制,我们可以看到我们的图像分类器如何成为一个机器学习模型,就像 Samuel 设想的那样。

一些深度学习术语

Samuel 的工作时间是 20 世纪 60 年代,从那时起术语就发生了变化。 以下是我们讨论的所有内容的现代深度学习术语:

  • 模型的功能形式称为其架构(但要小心,有时人们将模型用作架构的同义词,因此这可能会令人困惑)。
  • 权重称为参数。
  • 预测是根据自变量计算的,自变量是不包括标签的数据。
  • 模型的结果称为预测。
  • 性能的衡量标准称为损失。
  • 损失不仅取决于预测,还取决于正确的标签(也称为目标或因变量); 例如,“狗”或“猫”。

进行这些更改后,图 1.6 中的图表如图 1.8 所示。
在这里插入图片描述

机器学习固有的局限性

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

  • 没有数据就无法创建模型。
  • 模型只能学习对用于训练它的输入数据中看到的模式进行操作。
  • 这种学习方法只会产生预测,而不产生建议的行动。
  • 仅仅有输入数据的示例是不够的; 我们还需要这些数据的标签(例如,狗和猫的图片不足以训练模型;我们需要为每个数据添加一个标签,说明哪些是狗,哪些是猫)。

一般来说,我们看到大多数组织说他们没有足够的数据,实际上意味着他们没有足够的标记数据。 如果任何组织有兴趣在实践中使用模型做某事,那么他们可能有一些计划用于运行模型的输入。 想必他们已经以其他方式这样做了一段时间(例如,手动或使用一些启发式程序),因此他们拥有来自这些过程的数据! 例如,放射学实践几乎肯定会有医疗扫描的档案(因为他们需要能够检查患者随时间的进展情况),但这些扫描可能没有包含诊断或干预列表的结构化标签(因为 放射科医生通常创建自由文本的自然语言报告,而不是结构化数据)。 我们将在本书中大量讨论标签方法,因为它在实践中是一个非常重要的问题。

由于这些类型的机器学习模型只能进行预测(即尝试复制标签),这可能会导致组织目标和模型能力之间存在巨大差距。 例如,在本书中,您将学习如何创建一个可以预测用户可能购买哪些产品的推荐系统。 这通常用于电子商务,例如通过显示排名最高的商品来自定义主页上显示的产品。 但这样的模型通常是通过查看用户及其购买历史(输入)以及他们继续购买或查看的内容(标签)来创建的,这意味着该模型可能会告诉您有关用户已经拥有或拥有的产品的信息。 已经知道的产品,而不是他们最有可能有兴趣听到的新产品。 这与当地书店的专家可能会做的事情非常不同,他们会提出问题来了解您的品味,然后告诉您有关您以前从未听说过的作家或系列的信息。

另一个重要的见解来自于考虑模型如何与其环境交互。 这可以创建反馈循环,如下所述:

  • 预测性警务模型是根据过去逮捕地点创建的。 实际上,这实际上并不是预测犯罪,而是预测逮捕,因此部分简单地反映了现有警务流程中的偏见。
  • 然后,执法人员可能会使用该模型来决定将警察活动集中在哪里,从而导致这些地区的逮捕人数增加。
  • 有关这些额外逮捕的数据将被反馈以重新训练该模型的未来版本。

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

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

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

我们的图像识别器如何工作

让我们看看我们的图像识别器代码如何映射到这些想法。 我们将把每一行放入一个单独的单元格中,并查看每个行在做什么(我们不会解释每个参数的每个细节,但会给出重要位的描述;完整的细节将在本书的后面部分提供 )。

第一行导入所有 fastai.vision 库。

from fastai.vision.all import *

这为我们提供了创建各种计算机视觉模型所需的所有函数和类。

J:许多 Python 程序员建议避免像这样导入整个库(使用 import * 语法),因为在大型软件项目中这可能会导致问题。 然而,对于交互式工作(例如在 Jupyter 笔记本中),它的效果非常好。 fastai 库是专门为支持这种交互式使用而设计的,它只会将必要的部分导入到您的环境中。

第二行将一个标准数据集从 fast.ai 数据集集合(如果之前没有下载过)下载到您的服务器,提取它(如果之前没有提取过),并返回一个带有提取位置的 Path 对象:

path = untar_data(URLs.PETS)/'images'

S:在 fast.ai 学习期间,甚至直到今天,我学到了很多关于高效编码实践的知识。 fastai 库和 fast.ai 笔记本充满了很棒的小技巧,帮助我成为一名更好的程序员。 例如,请注意 fastai 库不仅返回包含数据集路径的字符串,还返回 Path 对象。 这是 Python 3 标准库中一个非常有用的类,它使访问文件和目录变得更加容易。 如果您以前没有遇到过它,请务必查看其文档或教程并尝试一下。 请注意,https://book.fast.ai[网站] 包含每章推荐教程的链接。 当我们遇到一些我发现有用的编码技巧时,我会不断地向您介绍这些技巧。

在第三行中,我们定义一个函数 is_cat,它根据数据集创建者提供的文件名规则来标记猫:

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

我们在第四行中使用该函数,它告诉 fastai 我们拥有什么样的数据集以及它的结构:

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

对于不同类型的深度学习数据集和问题,有各种不同的类 - 这里我们使用 ImageDataLoaders。 类名的第一部分通常是您拥有的数据类型,例如图像或文本。

我们必须告诉 fastai 的另一个重要信息是如何从数据集中获取标签。 计算机视觉数据集的结构通常是图像的标签是文件名或路径的一部分(最常见的是父文件夹名称)。 fastai 附带了许多标准化的标签方法,以及编写您自己的方法。 在这里,我们告诉 fastai 使用我们刚刚定义的 is_cat 函数。

最后,我们定义我们需要的 Transforms。 Transform 包含在训练期间自动应用的代码; fastai 包含许多预定义的 Transforms,添加新的 Transforms 就像创建 Python 函数一样简单。 有两种:item_tfms 应用于每个项目(在这种情况下,每个项目的大小调整为 224 像素的正方形),而 batch_tfms 使用 GPU 一次应用于一批项目,因此它们特别快 (我们将在本书中看到许多这样的例子)。

为什么是 224 像素? 由于历史原因,这是标准大小(旧的预训练模型完全需要这个大小),但您几乎可以传递任何内容。 如果增加尺寸,您通常会得到一个具有更好结果的模型(因为它将能够专注于更多细节),但代价是速度和内存消耗; 如果减小尺寸,则相反。

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

Pet 数据集包含 7,390 张狗和猫的图片,涵盖 37 个不同品种。 每个图像都使用其文件名进行标记:例如,文件great_pyrenees_173.jpg 是数据集中大比利牛斯犬种图像的第 173 个示例。 如果图像是猫,则文件名以大写字母开头,否则以小写字母开头。 我们必须告诉 fastai 如何从文件名中获取标签,我们通过调用 from_name_func (这意味着可以使用应用于文件名的函数来提取标签)并传递 is_cat (它返回 x[0].isupper() 来实现) ,如果第一个字母是大写(即,它是一只猫),则计算结果为 True。

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

fastai 将始终仅使用验证集而不是训练集向您展示模型的准确性。 这绝对是至关重要的,因为如果你训练足够大的模型足够长的时间,它最终会记住数据集中每个项目的标签! 结果实际上不会是一个有用的模型,因为我们关心的是我们的模型在以前未见过的图像上的工作效果如何。 这始终是我们创建模型时的目标:让它对模型经过训练后只能在未来看到的数据有用。

即使您的模型没有完全记住所有数据,在训练的早期,它也可能已经记住了其中的某些部分。 因此,你训练的时间越长,你在训练集上的准确性就越高; 验证集的准确性也会暂时提高,但最终会开始变得更糟,因为模型开始记住训练集,而不是在数据中找到可概括的基础模式。 当这种情况发生时,我们说模型 overfitting(过度拟合)。

图 1.9 使用一个简化的示例显示了过度拟合时会发生的情况,其中我们只有一个参数,以及一些基于函数 x**2 随机生成的数据。 正如您所看到的,虽然过拟合模型中的预测对于观察到的数据点附近的数据是准确的,但当超出该范围时,它们就会偏离很远。

在这里插入图片描述
图 1.9:过度拟合的示例

过度拟合是最重要和最具挑战性的问题
为所有机器学习从业者和所有算法提供培训。 正如您将看到的,创建一个模型非常容易,该模型可以很好地对所训练的确切数据进行预测,但对模型以前从未见过的数据进行准确预测则要困难得多。 当然,这是在实践中真正重要的数据。 例如,如果您创建一个手写数字分类器(我们很快就会这样做!)并用它来识别支票上写的数字,那么您将永远不会看到模型所训练的任何数字 - 支票上会稍微有一些变化。 需要处理不同的写作变体。 您将在本书中学到许多避免过度拟合的方法。 但是,只有在确认确实发生了过度拟合(即,您实际上观察到验证准确性在训练期间变得更糟)后,才应使用这些方法。 我们经常看到从业者使用过度拟合避免技术,即使他们有足够的数据,他们不需要这样做,最终得到的模型可能不如他们所能达到的准确。

重要:验证集:训练模型时,必须始终同时拥有训练集和验证集,并且必须仅在验证集上测量模型的准确性。 如果你训练时间太长,没有足够的数据,你会发现模型的准确性开始变差; 这称为过度拟合。 fastai 默认 valid_pct 为 0.2,所以即使你忘记了,fastai 也会为你创建一个验证集!

训练我们的图像识别器的代码的第五行告诉 fastai 创建一个convolutional neural network 卷积神经网络 (CNN) 并指定要使用的架构(即创建什么样的模型)、我们想要训练它的数据以及要使用的指标 使用:

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

为什么是CNN? 这是当前创建计算机视觉模型的最先进方法。 我们将在本书中全面了解 CNN 的工作原理。 它们的结构受到人类视觉系统工作原理的启发。

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

什么是metric(度量)? 度量是使用验证集衡量模型预测质量的函数,并将在每个时期结束时打印。 在本例中,我们使用 error_rate,这是 fastai 提供的一个函数,它的作用正如其所言:告诉您验证集中有多少图像被错误分类。 分类的另一个常见指标是准确性(仅为 1.0 - error_rate)。 fastai 提供了更多内容,本书将对此进行讨论。

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

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

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

使用预训练模型是我们能够用更少的数据、更少的时间和金钱更快地训练更准确的模型的最重要方法。 您可能认为这意味着使用预训练模型将是学术深度学习中研究最多的领域……但您就错了! 大多数课程、书籍或软件库功能中通常没有认识或讨论预训练模型的重要性,并且在学术论文中也很少考虑。 当我们在 2020 年初写这篇文章时,情况才刚刚开始发生变化,但这可能需要一段时间。 所以要小心:与你交谈的大多数人可能会大大低估你在深度学习中用很少的资源所能做的事情,因为他们可能不会深入了解如何使用预训练模型。

使用预训练模型来完成与最初训练的任务不同的任务称为迁移学习。 不幸的是,由于迁移学习的研究还很少,很少有领域拥有可用的预训练模型。 例如,目前医学领域可用的预训练模型很少,这使得迁移学习在该领域的使用具有挑战性。 此外,目前还没有很好地理解如何将迁移学习用于时间序列分析等任务。

术语:迁移学习:使用预训练模型来完成与最初训练的任务不同的任务。

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

learn.fine_tune(1)

正如我们所讨论的,该架构仅描述了数学函数的模板; 在我们为其包含的数百万个参数提供值之前,它实际上不会执行任何操作。

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

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

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

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

  1. 使用一个epoch(纪元)来拟合模型中使新的随机头正确处理数据集所需的那些部分。
  2. 使用调用该方法时请求的纪元数来拟合整个模型,更新后面层(尤其是头部)的权重比前面层更快(正如我们将看到的,通常不需要从预训练权重)。

模型的头部是新添加的特定于新数据集的部分。 一个纪元是对数据集的一次完整遍历。 调用 fit 后,会打印每个 epoch 后的结果,显示 epoch 编号、训练和验证集损失(用于训练模型的“性能度量”)以及您请求的任何指标(错误率,在此例子中)。

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

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

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

2013 年,博士生 Matt Zeiler 和他的导师 Rob Fergus 发表了论文“可视化和理解卷积网络”,展示了如何可视化模型每一层中学习到的神经网络权重。 他们仔细分析了2012年ImageNet比赛获胜的模型,并利用这个分析极大地改进了模型,使得他们能够继续赢得2013年的比赛! 图 1.10 是他们发布的第一层权重的图片。

在这里插入图片描述
图 1.10:CNN 第一层的激活(由 Matthew D. Zeiler 和 Rob Fergus 提供)

这张图需要一些解释。 对于每一层,浅灰色背景的图像部分显示重建的权重图片,底部较大的部分显示与每组权重最匹配的训练图像部分。 对于第 1 层,我们可以看到模型发现了代表对角线、水平和垂直边缘以及各种不同梯度的权重。 (请注意,对于每一层,仅显示特征的子集;实际上,所有层中都有数千个特征。)这些是模型为计算机视觉学习的基本构建块。 神经科学家和计算机视觉研究人员对它们进行了广泛的分析,事实证明,这些学习的构建模块与人眼的基本视觉机制以及在人工智能时代之前开发的手工计算机视觉功能非常相似。 深度学习。 下一层如图 1.11 所示。

在这里插入图片描述
图 1.11:CNN 第二层的激活(由 Matthew D. Zeiler 和 Rob Fergus 提供)

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

图 1.12 显示了论文中的图像,显示了重建第 3 层特征的结果。
在这里插入图片描述
图 1.12:CNN 第三层的激活(由 Matthew D. Zeiler 和 Rob Fergus 提供)

正如您通过查看此图片的右侧所看到的,这些功能现在能够识别并匹配更高级别的语义组件,例如车轮、文本和花瓣。 使用这些组件,第四层和第五层可以识别更高级别的概念,如图 1.13 所示。

在这里插入图片描述
图 1.13:CNN 第 4 层和第 5 层的激活(由 Matthew D. Zeiler 和 Rob Fergus 提供)

本文研究的是一种名为 AlexNet 的旧模型,该模型仅包含五层。 此后开发的网络可以有数百层——所以你可以想象这些模型开发的特征有多么丰富!

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

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

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

例如,声音可以转换为频谱图,频谱图是显示音频文件中每个时间每个频率数量的图表。 Fast.ai 的学生 Ethan Sutin 使用这种方法,使用 8,732 个城市声音的数据集轻松击败了最先进的环境声音检测模型已发布的准确性。 fastai 的 show_batch 清楚地显示了每种不同的声音如何具有非常独特的频谱图,如图 1.14 所示。

在这里插入图片描述
图 1.14:带有声音频谱图的 show_batch

只需将时间序列绘制在图表上,即可轻松将时间序列转换为图像。 然而,尝试以一种尽可能容易地提取出最重要组件的方式表示数据通常是一个好主意。 在时间序列中,季节性和异常等事物最有可能引起人们的兴趣。 时间序列数据有多种可用的转换。 例如,fast.ai 的学生 Ignacio Oguiza 使用一种名为 Gramian Angular Difference Field (GADF) 的技术,从时间序列数据集中创建了用于橄榄油分类的图像; 您可以在图 1.15 中看到结果。 然后,他将这些图像输入图像分类模型,就像您在本章中看到的那样。 尽管只有 30 个训练集图像,他的结果却远远超过 90%,并且接近最先进的水平。

在这里插入图片描述
图 1.15:将时间序列转换为图像

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

在这里插入图片描述
图 1.16:将计算机鼠标行为转换为图像

另一个例子来自 Mahmoud Kalash 等人的论文“Malware Classification with Deep Convolutional Neural Networks”,其中解释说“恶意软件二进制文件被分为 8 位序列,然后转换为等效的十进制值。 这个十进制向量被重新整形,并生成代表恶意软件样本的灰度图像,如图 1.17 所示。

在这里插入图片描述
图1.17:恶意软件分类流程

然后作者将恶意软件在这一过程中生成的“图片”分为不同的类别,如图1.18所示。

在这里插入图片描述
图 1.18:恶意软件示例

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

一般来说,您会发现,如果您在表示数据的方式上有点创意,深度学习中的少量通用方法可以大有帮助! 您不应该将此处描述的方法视为“黑客解决方法”,因为实际上它们经常(如此处)击败了以前最先进的结果。 这些确实是思考这些问题领域的正确方法。

行话回顾

我们刚刚介绍了很多信息,所以让我们简要回顾一下,表 1.2 提供了一个方便的词汇表。

表 1.2:深度学习词汇

术语含义
Label(标签)我们尝试预测的数据,例如“狗”或“猫”
Architecture(结构)我们尝试拟合的模型的模板; 我们将输入数据和参数传递给的实际数学函数
Model(模型)架构与一组特定参数的组合
Parameters(参数)模型中的值会改变它可以执行的任务,并通过模型训练进行更新
Fit(适合)更新模型的参数,使得使用输入数据的模型的预测与目标标签匹配
Train(训练)适合的同义词
Pretrained model(预训练模型)已经训练好的模型,通常使用大型数据集,并将进行微调
Fine-tune(微调)为不同的任务更新预训练模型
Epoch(期)一次完整地传递输入数据
Loss(损失)衡量模型好坏的指标,选择通过 SGD 来驱动训练
Metric(度量)使用供人类消费选择的验证集来衡量模型的好坏
Validation set(验证集)训练中保留的一组数据,仅用于衡量模型的好坏
Training set(训练集)用于拟合模型的数据; 不包含验证集中的任何数据
Overfitting(过度拟合)以记住输入数据的特定特征的方式训练模型,而不是很好地概括训练期间未见过的数据
CNN卷积神经网络; 一种特别适合计算机视觉任务的神经网络

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

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

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

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

当我们训练模型时,一个关键问题是确保我们的模型具有泛化性,也就是说,它从我们的数据中学习一般经验教训,这些教训也适用于它将遇到的新项目,以便它可以对这些项目做出良好的预测。 风险在于,如果我们的模型训练不当,它就会有效地记住已经看到的内容,而不是学习一般的课程,然后它会对新图像做出糟糕的预测。 这种失败称为过度拟合。 为了避免这种情况,我们总是将数据分为两部分:训练集和验证集。 我们通过仅显示训练集来训练模型,然后通过查看模型在验证集中的项目上的表现来评估模型的表现。 通过这种方式,我们检查模型从训练集中学到的教训是否可以推广到验证集。 为了让人们评估模型在验证集上的整体表现如何,我们定义了一个指标。 在训练过程中,当模型看到训练集中的每个项目时,我们称之为一个期。

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

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

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

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

path = untar_data(URLs.CAMVID_TINY)
dls = SegmentationDataLoaders.from_label_func(
    path, bs=8, fnames = get_image_files(path/"images"),
    label_func = lambda o: path/'labels'/f'{o.stem}_P{o.suffix}',
    codes = np.loadtxt(path/'codes.txt', dtype=str)
)

learn = unet_learner(dls, resnet34)
learn.fine_tune(8)

在这里插入图片描述
我们甚至不打算逐行浏览此代码,因为它与我们之前的示例几乎相同! (尽管我们将在第 15 章中深入探讨细分模型,以及我们在本章中简要介绍的所有其他模型,以及更多很多模型。)

通过要求模型对图像的每个像素进行颜色编码,我们可以直观地看到它完成任务的效果。 正如您所看到的,它几乎完美地对每个对象中的每个像素进行了分类。 例如,请注意,所有汽车都覆盖有相同的颜色,所有树木都覆盖有相同的颜色(在每对图像中,左侧图像是地面实况标签,右侧图像是模型的预测 ):

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

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

from fastai.text.all import *

dls = TextDataLoaders.from_folder(untar_data(URLs.IMDB), valid='test')
learn = text_classifier_learner(dls, AWD_LSTM, drop_mult=0.5, metrics=accuracy)
learn.fine_tune(4, 1e-2)

在这里插入图片描述
#clean 如果运行此单元后遇到“CUDA 内存不足错误”,请单击菜单“内核”,然后重新启动。 不要执行上面的单元格,而是将以下代码复制并粘贴到其中:

from fastai.text.all import *

dls = TextDataLoaders.from_folder(untar_data(URLs.IMDB), valid='test', bs=32)
learn = text_classifier_learner(dls, AWD_LSTM, drop_mult=0.5, metrics=accuracy)
learn.fine_tune(4, 1e-2)

这会将批量大小减少到 32(我们将在稍后解释)。 如果您继续遇到相同的错误,请将 32 更改为 16。

该模型使用 Andrew Maas 等人的论文“Learning Word Vectors for Sentiment Analysis”中的“IMDb Large Movie Review dataset”。 它适用于数千字的电影评论,但让我们在一篇很短的电影评论上测试一下,看看它是如何发挥作用的:

learn.predict("I really liked that movie!")

(‘neg’, tensor(0), tensor([0.8786, 0.1214]))

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

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

侧边栏:顺序很重要

在 Jupyter Notebook 中,执行每个单元的顺序非常重要。 它不像 Excel,只要您在任何地方键入内容,所有内容都会更新,它有一个内部状态,每次执行单元格时都会更新。 例如,当您运行笔记本的第一个单元格(带有“CLICK ME”注释)时,您将创建一个名为 learn 的对象,其中包含图像分类问题的模型和数据。 如果我们要立即运行文本中显示的单元格(预测评论是否良好的单元格),我们会收到错误,因为该学习对象不包含文本分类模型。 该单元需要在包含以下内容的单元之后运行:

from fastai.text.all import *

dls = TextDataLoaders.from_folder(untar_data(URLs.IMDB), valid='test')
learn = text_classifier_learner(dls, AWD_LSTM, drop_mult=0.5, 
                                metrics=accuracy)
learn.fine_tune(4, 1e-2)

输出本身可能具有欺骗性,因为它们包含上次执行单元的结果; 如果您更改单元格内的代码而不执行它,则旧的(误导性的)结果将保留。

除非我们明确提及,否则本书网站上提供的笔记本应按从上到下的顺序运行。 一般来说,在实验时,您会发现自己以任意顺序执行单元以加快速度(这是 Jupyter Notebook 的一个超级简洁的功能),但是一旦您探索并达到了代码的最终版本,请确保您可以运行 按顺序排列笔记本的单元格(未来的自己不一定会记得您所走的复杂路径!)。

在命令模式下,按 0 两次将重新启动内核(这是为笔记本电脑供电的引擎)。 这将清除您的状态并使它就像您刚刚在笔记本中开始一样。 从“单元格”菜单中选择“运行所有上方”可运行您所在位置上方的所有单元格。 我们发现这在开发 fastai 库时非常有用。

结束侧边栏

如果您对 fastai 方法有任何疑问,您应该使用函数 doc,并向其传递方法名称:

doc(learn.predict)

这将弹出一个小窗口,其中包含如下内容:

在这里插入图片描述
doc 提供了简短的一行解释。 “在文档中显示”链接将带您访问完整的文档,您可以在其中找到所有详细信息和大量示例。 此外,fastai 的大多数方法都只有几行代码,因此您可以单击“源”链接来查看幕后到底发生了什么。

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

行话:表格:表格形式的数据,例如来自电子表格、数据库或 CSV 文件的数据。 表格模型是一种尝试根据表中其他列中的信息来预测表中某一列的模型。

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

from fastai.tabular.all import *
path = untar_data(URLs.ADULT_SAMPLE)

dls = TabularDataLoaders.from_csv(path/'adult.csv', path=path, y_names="salary",
    cat_names = ['workclass', 'education', 'marital-status', 'occupation',
                 'relationship', 'race'],
    cont_names = ['age', 'fnlwgt', 'education-num'],
    procs = [Categorify, FillMissing, Normalize])

learn = tabular_learner(dls, metrics=accuracy)

正如您所看到的,我们必须告诉 fastai 哪些列是分类的(即包含属于一组离散选择之一的值,例如职业),哪些列是连续的(即包含代表数量的数字,例如 作为年龄)。

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

learn.fit_one_cycle(3)

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

我们再看一个。 推荐系统非常重要,尤其是在电子商务中。 亚马逊和Netflix等公司努力推荐用户可能喜欢的产品或电影。 以下是如何使用 MovieLens 数据集训练一个模型,根据人们之前的观看习惯来预测人们可能喜欢的电影:

from fastai.collab import *
path = untar_data(URLs.ML_SAMPLE)
dls = CollabDataLoaders.from_csv(path/'ratings.csv')
learn = collab_learner(dls, y_range=(0.5,5.5))
learn.fine_tune(10)

在这里插入图片描述
该模型以 0.5 到 5.0 的范围来预测电影评分,平均误差在 0.6 左右。 由于我们预测的是连续数字,而不是类别,因此我们必须使用 y_range 参数告诉 fastai 我们的目标范围是什么。

尽管我们实际上并没有使用预训练模型(与我们没有使用表格模型的原因相同),但此示例表明 fastai 让我们在这种情况下无论如何都可以使用fine_tune(您将了解它的工作原理和原因) 第 5 章)。 有时最好尝试使用fine_tune 与fit_one_cycle 来看看哪一个最适合您的数据集。

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

learn.show_results()

在这里插入图片描述

侧边栏:数据集:模型的食物

您已经在本节中看到了相当多的模型,每个模型都使用不同的数据集进行训练来完成不同的任务。 在机器学习和深度学习中,没有数据我们就什么也做不了。 因此,为我们创建数据集来训练模型的人是(通常被低估的)英雄。 一些最有用和最重要的数据集已成为重要的学术基线; 也就是说,研究人员广泛研究并用于比较算法变化的数据集。 其中一些成为家喻户晓的名字(至少在训练模型的家庭中如此!),例如 MNIST、CIFAR-10 和 ImageNet。

选择本书中使用的数据集是因为它们为您可能遇到的数据类型提供了很好的示例,并且学术文献中有许多使用这些数据集的模型结果示例,您可以将您的工作与它们进行比较。

本书中使用的大多数数据集的创建者都花费了大量的工作来构建。 例如,在本书的后面,我们将向您展示如何创建一个可以在法语和英语之间进行翻译的模型。 其关键输入是宾夕法尼亚大学 Chris Callison-Burch 教授于 2009 年准备的法语/英语平行文本语料库。 该数据集包含超过 2000 万个法语和英语句子对。 他以一种非常聪明的方式构建了数据集:抓取数百万个加拿大网页(通常是多语言的),然后使用一组简单的启发式方法将法语内容的 URL 转换为指向相同英语内容的 URL。

当你查看本书中的数据集时,请思考它们可能来自哪里,以及它们可能是如何策划的。 然后考虑您可以为自己的项目创建哪些类型的有趣数据集。 (我们甚至会很快引导您逐步完成创建自己的图像数据集的过程。)

fast.ai 花费了大量时间创建流行数据集的精简版本,这些数据集专门用于支持快速原型设计和实验,并且更易于学习。 在本书中,我们通常会从使用一个缩小版本开始,然后放大到全尺寸版本(就像我们在本章中所做的那样!)。 事实上,世界顶尖的实践者在实践中都是这样做的; 他们使用数据子集进行大部分实验和原型设计,并且仅在充分了解自己必须做什么时才使用完整数据集。

结束侧边栏

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

1.8 验证集和测试集

正如我们所讨论的,模型的目标是对数据进行预测。 但模型训练过程从根本上来说是愚蠢的。 如果我们使用所有数据训练模型,然后使用相同的数据评估模型,我们将无法判断模型在未见过的数据上的表现如何。 如果没有这条非常有价值的信息来指导我们训练模型,那么它很有可能擅长对数据进行预测,但在新数据上表现不佳。

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

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

分离我们的验证数据意味着我们的模型在训练中永远不会看到它,因此完全不受它的污染,并且不会以任何方式作弊。 对吗?

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

问题是,即使普通的训练过程在学习权重参数的值时仅查看训练数据的预测,但我们的情况却并非如此。 当我们决定探索新的超参数值时,作为建模者,我们正在通过查看验证数据的预测来评估模型! 因此,模型的后续版本是由我们看到的验证数据间接塑造的。 正如自动训练过程存在过度拟合训练数据的危险一样,我们也存在通过人工试错和探索过度拟合验证数据的危险。

解决这个难题的方法是引入另一个级别的保留度更高的数据,即测试集。 正如我们在训练过程中保留验证数据一样,我们甚至必须从我们自己那里保留测试集数据。 它不能用于改进模型; 它只能用于在我们努力结束时评估模型。 实际上,我们根据我们想要在训练和建模过程中隐藏数据的程度来定义数据切割的层次结构:训练数据完全暴露,验证数据暴露较少,测试数据完全隐藏。 这种层次结构与不同类型的建模和评估过程本身并行——具有反向传播的自动训练过程、在训练会话之间尝试不同超参数的更多手动过程以及对最终结果的评估。

测试和验证集应该有足够的数据,以确保您能够很好地估计准确性。 例如,如果您要创建猫检测器,您通常希望验证集中至少有 30 只猫。 这意味着,如果您的数据集包含数千个项目,则使用默认的 20% 验证集大小可能会超出您的需要。 另一方面,如果您有大量数据,使用其中一些数据进行验证可能没有任何缺点。

拥有两个级别的“保留数据”——验证集和测试集,其中一个级别代表你实际上对自己隐藏的数据——可能看起来有点极端。 但它往往是必要的,因为模型倾向于以最简单的方式进行良好的预测(记忆),而我们作为容易犯错的人类,则倾向于自欺欺人地认为我们的模型表现得有多好。 测试集的纪律有助于我们保持理智上的诚实。 这并不意味着我们总是需要一个单独的测试集 - 如果您的数据很少,您可能只需要一个验证集 - 但通常最好尽可能使用一个。

如果您打算聘请第三方代表您执行建模工作,那么同样的原则也至关重要。 第三方可能无法准确理解您的要求,或者他们的动机甚至可能会促使他们误解您的要求。 一个好的测试集可以极大地减轻这些风险,并让您评估他们的工作是否解决了您的实际问题。

坦率地说,如果您是组织中的高级决策者(或者您正在为高级决策者提供建议),那么最重要的收获是:如果您确保真正了解测试集和验证集是什么以及它们的原因很重要,那么当组织决定使用人工智能时,您将避免我们所看到的最大的失败来源。 例如,如果您正在考虑引入外部供应商或服务,请确保保留一些供应商永远看不到的测试数据。 然后,您根据测试数据检查他们的模型,使用根据实践中对您实际重要的内容选择的指标,并决定什么水平的性能是足够的。 (您自己尝试一些简单的基线也是一个好主意,这样您就知道一个真正简单的模型可以实现什么。通常情况下,您的简单模型的性能与外部“专家”生成的模型一样好 !)

在定义测试集时使用判断

为了做好定义验证集(可能还有测试集)的工作,您有时需要做的不仅仅是随机获取原始数据集的一小部分。 请记住:验证集和测试集的一个关键属性是它们必须代表您将来将看到的新数据。 这听起来像是一个不可能完成的命令! 根据定义,您还没有看到这些数据。 但你通常仍然知道一些事情。

看几个例子是有启发性的。 其中许多示例来自 Kaggle 平台上的预测建模竞赛,这很好地代表了您在实践中可能会看到的问题和方法。

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

假设您想将图 1.19 中的时间序列数据拆分为训练集和验证集。

在这里插入图片描述
图 1.19:时间序列

随机子集是一个糟糕的选择(太容易填补空白,并且不能表明您在生产中需要什么),如图 1.20 所示。
在这里插入图片描述
图 1.20:较差的训练子集

相反,使用较早的数据作为训练集(以及较晚的数据作为验证集),如图 1.21 所示。
在这里插入图片描述
图 1.21:一个好的训练子集

例如,Kaggle 举办了一场预测厄瓜多尔连锁杂货店销售额的竞赛。 Kaggle的训练数据从2013年1月1日到2017年8月15日,测试数据从2017年8月16日到2017年8月31日。这样,比赛组织者就确保了参赛者对未来一段时间的预测,从 他们的模型的视角。 这类似于量化对冲基金交易员根据过去的数据进行回溯测试来检查他们的模型是否可以预测未来时期的方式。

第二种常见情况是,您可以轻松预测在生产中进行预测的数据可能与用于训练模型的数据有质的不同。

在 Kaggle 分心驾驶员竞赛中,自变量是驾驶员驾驶汽车的照片,因变量是发短信、吃饭或安全地向前看等类别。 许多图片都是同一车手在不同位置的照片,如图 1.22 所示。 如果您是一家保险公司,根据这些数据构建模型,请注意,您最感兴趣的是该模型如何在以前从未见过的驾驶员上执行(因为您可能只有一小部分人的训练数据)。 认识到这一点,比赛的测试数据由训练集中未出现的人物图像组成。

在这里插入图片描述
图 1.22:训练数据中的两张图片

如果您将图 1.22 中的一张图像放入训练集中,另一张放入验证集中,您的模型将很容易对验证集中的图像进行预测,因此它的表现似乎会比实际情况更好 关于新人。 另一种观点是,如果你使用所有人来训练你的模型,你的模型可能会过度拟合这些特定人的特殊性,而不仅仅是学习状态(发短信、吃饭等)。

Kaggle 渔业竞赛中也存在类似的动态,该竞赛旨在确定渔船捕获的鱼类种类,以减少对濒危种群的非法捕捞。 测试集由训练数据中未出现的船只组成。 这意味着您希望验证集包含不在训练集中的船只。

有时可能不清楚您的验证数据有何不同。 例如,对于使用卫星图像的问题,您需要收集更多信息,了解训练集是否仅包含某些地理位置,或者是否来自地理上分散的数据。

现在您已经了解了如何构建模型,您可以决定下一步要深入研究什么。

1.9 选择你自己的冒险时刻

如果您想了解更多有关如何在实践中使用深度学习模型的信息,包括如何识别和修复错误、创建真正有效的 Web 应用程序以及避免您的模型对您的组织或社会造成更普遍的意外伤害,请继续阅读 接下来的两章。 如果您想开始学习深度学习在幕后工作原理的基础知识,请跳至第 4 章。(您小时候读过《选择自己的冒险》书籍吗?嗯,这有点像那样……除了更深入的内容) 比该系列丛书所包含的学习内容。)

您需要阅读所有这些章节才能进一步阅读本书,但这完全取决于您阅读的顺序。它们并不相互依赖。 如果您跳到第 4 章,我们会在最后提醒您在继续阅读之前返回并阅读您跳过的章节。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值