手机版网站原理,中山网页设计公司,没企业可以做网站吗,成都网站设公司深度学习 2#xff1a;第 1 部分第 1 课 原文#xff1a;medium.com/hiromi_suenaga/deep-learning-2-part-1-lesson-1-602f73869197 译者#xff1a;飞龙 协议#xff1a;CC BY-NC-SA 4.0 来自 fast.ai 课程的个人笔记。随着我继续复习课程以“真正”理解它#xff0c;这…深度学习 2第 1 部分第 1 课 原文medium.com/hiromi_suenaga/deep-learning-2-part-1-lesson-1-602f73869197 译者飞龙 协议CC BY-NC-SA 4.0 来自 fast.ai 课程的个人笔记。随着我继续复习课程以“真正”理解它这些笔记将继续更新和改进。非常感谢 Jeremy 和Rachel 给了我这个学习的机会。 第一课
开始 [0:00] 为了训练神经网络您几乎肯定需要图形处理单元GPU —— 具体来说是 NVIDIA GPU因为它是唯一支持 CUDA几乎所有深度学习库和从业者使用的语言和框架的 GPU。 有几种租用 GPU 的方法Crestle [04:06], Paperspace [06:10]
Jupyter Notebook 和 猫狗分类简介 [12:39] 您可以通过选择单元格并按shiftenter来运行单元格您可以按住shift并多次按enter以继续向下移动单元格或者您可以点击顶部的运行按钮。一个单元格可以包含代码、文本、图片、视频等。 Fast.ai 需要 Python 3
%reload_ext autoreload
%autoreload 2
%matplotlib inline*
# This file contains all the main external libs well use
from fastai.imports import *
from fastai.transforms import *
from fastai.conv_learner import *
from fastai.model import *
from fastai.dataset import *
from fastai.sgdr import *
from fastai.plots import *
PATH data/dogscats/
sz224首先看图片 [15:39]
!ls {PATH}models sample test1 tmp train valid! 告诉使用 bashshell而不是 python 如果您不熟悉训练集和验证集请查看实用机器学习课程或阅读Rachel 的博客
!ls {PATH}validcats dogsfiles !ls {PATH}valid/cats | head
files[cat.10016.jpg,cat.1001.jpg,cat.10026.jpg,cat.10048.jpg,cat.10050.jpg,cat.10064.jpg,cat.10071.jpg,cat.10091.jpg,cat.10103.jpg,cat.10104.jpg]这个文件夹结构是共享和提供图像分类数据集的最常见方法。每个文件夹告诉您标签例如dogs或cats。
img plt.imread(f{PATH}valid/cats/{files[0]})
plt.imshow(img);f’{PATH}valid/cats/{files[0]}’ — 这是 Python 3.6. 格式化字符串是一种方便的格式化字符串的方法。
img.shape(198, 179, 3)img[:4,:4]array([[[ 29, 20, 23],[ 31, 22, 25],[ 34, 25, 28],[ 37, 28, 31]],**[[ 60, 51, 54],[ 58, 49, 52],[ 56, 47, 50],[ 55, 46, 49]],**[[ 93, 84, 87],[ 89, 80, 83],[ 85, 76, 79],[ 81, 72, 75]],**[[104, 95, 98],[103, 94, 97],[102, 93, 96],[102, 93, 96]]], dtypeuint8)*img 是一个三维数组也称为秩为 3 的张量。 这三个项目例如[29, 20, 23]代表介于 0 和 255 之间的红绿蓝像素值。 这个想法是拿这些数字并使用它们来预测这些数字是否代表一只猫还是一只狗基于查看大量猫和狗的图片。 这个数据集来自Kaggle 竞赛当它发布时2013 年最先进的技术准确率为 80%。
让我们训练一个模型 [20:21]
这是训练模型所需的三行代码
data ImageClassifierData.from_paths(PATH, tfmstfms_from_model(resnet34, sz))
learn ConvLearner.pretrained(resnet34, data, precomputeTrue)
learn.fit(0.01, 3)[ 0\. 0.04955 0.02605 0.98975]
[ 1\. 0.03977 0.02916 0.99219]
[ 2\. 0.03372 0.02929 0.98975]这将进行 3 轮这意味着它将三次查看整个图像集。 输出中的三个数字中的最后一个是验证集上的准确率。 前两个是训练集和验证集的损失函数值在本例中是交叉熵损失。 起始例如0.、1.是轮数。 我们在 17 秒内用 3 行代码实现了约 99% 的准确率这在 2013 年将赢得 Kaggle 竞赛[21:49] 很多人认为深度学习需要大量时间、资源和数据 —— 总的来说这并不是真的
Fast.ai 库 [22:24] 该库采用了他们能找到的所有最佳实践和方法 —— 每次有一篇看起来有趣的论文出来时他们会测试它如果它在各种数据集上表现良好并且他们能够找出如何调整它那么它就会被实现在库中。 Fast.ai 为您整理了所有这些最佳实践并打包起来大多数情况下会自动找出最佳处理方式。 Fast.ai 建立在一个名为 PyTorch 的库之上这是一个由 Facebook 编写的非常灵活的深度学习、机器学习和 GPU 计算库。 大多数人对 TensorFlow 比 PyTorch 更熟悉但 Jeremy 现在认识的大多数顶尖研究人员已经转向 PyTorch。 Fast.ai 非常灵活您可以根据需要使用所有这些精心策划的最佳实践。您可以轻松地在任何时候连接并编写自己的数据增强、损失函数、网络架构等我们将在本课程中学习所有这些。
分析结果[24:21]
这是验证数据集标签将其视为正确答案的样子
data.val_yarray([0, 0, 0, ..., 1, 1, 1])这些 0 和 1 代表什么
data.classes[cats, dogs]data包含验证和训练数据 learn包含模型
让我们对验证集进行预测预测以对数刻度表示
log_preds learn.predict()
log_preds.shape(2000, 2)log_preds[:10]array([[ -0.00002, -11.07446],[ -0.00138, -6.58385],[ -0.00083, -7.09025],[ -0.00029, -8.13645],[ -0.00035, -7.9663 ],[ -0.00029, -8.15125],[ -0.00002, -10.82139],[ -0.00003, -10.33846],[ -0.00323, -5.73731],[ -0.0001 , -9.21326]], dtypefloat32)输出表示对猫的预测和对狗的预测
preds np.argmax(log_preds, axis1) # from log probabilities to 0 or 1
probs np.exp(log_preds[:,1]) # pr(dog)在 PyTorch 和 Fast.ai 中大多数模型返回预测的对数而不是概率本身我们将在课程中稍后学习原因。现在只需知道要获得概率您必须执行np.exp() 确保您熟悉 numpynp
# 1\. A few correct labels at random
plot_val_with_title(rand_by_correct(True), Correctly classified)图像上方的数字是狗的概率
# 2\. A few incorrect labels at random
plot_val_with_title(rand_by_correct(False), Incorrectly classified)plot_val_with_title(most_by_correct(0, True), Most correct cats)plot_val_with_title(most_by_correct(1, True), Most correct dogs)更有趣的是以下是模型认为肯定是狗的东西但结果是猫反之亦然
plot_val_with_title(most_by_correct(0, False), Most incorrect cats)plot_val_with_title(most_by_correct(1, False), Most incorrect dogs)most_uncertain np.argsort(np.abs(probs -0.5))[:4]
plot_val_with_title(most_uncertain, Most uncertain predictions)为什么查看这些图像很重要Jeremy 在构建模型后的第一件事是找到一种可视化其构建内容的方法。因为如果他想让模型更好那么他需要利用做得好的事情并修复做得不好的事情。 在这种情况下我们已经了解了数据集本身的一些信息即这里有一些可能不应该存在的图像。但很明显这个模型还有改进的空间例如数据增强 - 我们将在以后学习。 现在您已经准备好构建自己的图像分类器用于常规照片 - 也许不是 CT 扫描例如这里是一个学生的示例。 查看此论坛帖子以了解不同的可视化结果方式例如当存在超过 2 个类别时等
自上而下 vs 自下而上[30:52]
自下而上学习您需要的每个构建块最终将它们组合在一起 难以保持动力 难以了解“全局图景” 难以知道您实际需要哪些部分
fast.ai让学生立即使用神经网络尽快获得结果
逐渐剥开层修改查看内部
课程结构[33:53] 使用深度学习的图像分类器代码行数最少 多标签分类和不同类型的图像例如卫星图像 结构化数据例如销售预测- 结构化数据来自数据库或电子表格 语言NLP 分类器例如电影评论分类 协同过滤例如推荐引擎 生成语言模型如何逐个字符从头开始编写您自己的尼采哲学 回到计算机视觉 - 不仅识别猫照片还要找到照片中的猫所在位置热图并学习如何从头开始编写我们自己的架构ResNet
图像分类器示例
图像分类算法对许多事物非常有用。 例如AlphaGo[42:20]查看了成千上万个围棋棋盘每个棋盘上都有一个标签说明这个棋盘最终是赢家还是输家。因此它学会了一种能够查看围棋棋盘并判断它是好还是坏的图像分类——这是打好围棋最重要的一步知道哪一步走得更好。 另一个例子是一个早期的学生创建了一个鼠标移动图像分类器并检测到欺诈交易。
深度学习≠机器学习[44:26] 深度学习是一种机器学习 机器学习是由 Arthur Samuel 发明的。在 50 年代末他让 IBM 大型机比他更擅长下棋发明了机器学习。他让大型机反复对弈并找出导致胜利的种种因素然后利用这些因素以某种方式编写自己的程序。1962 年Arthur Samuel 说未来绝大多数计算机软件将使用这种机器学习方法编写而不是手工编写。 C-Path计算病理学家[45:42]是传统机器学习方法的一个例子。他拍摄了乳腺癌活检的病理学切片咨询了许多病理学家关于与长期生存相关的模式或特征可能是什么。然后他们编写了专家算法来计算这些特征通过逻辑回归进行运算并预测了生存率。它胜过了病理学家但需要领域专家和计算机专家多年的工作才能构建。
更好的方法[47:35] 具有这三个特性的算法类别是深度学习。
无限灵活的函数神经网络[48:43] 深度学习使用的基础函数称为神经网络
现在你需要知道的是它由许多简单的线性层和许多简单的非线性层组成。当你交错这些层时你会得到一个称为通用逼近定理的东西。通用逼近定理所说的是只要添加足够的参数这种函数可以解决任何给定的问题达到任意接近的精度。
全能参数拟合梯度下降[49:39] 快速且可扩展GPU[51:05] 上面显示的神经网络示例有一个隐藏层。我们在过去几年学到的一些东西是这种神经网络如果不添加多个隐藏层就不会快速或可扩展因此被称为“深度”学习。
将所有内容放在一起[53:40] 以下是一些例子 research.googleblog.com/2015/11/computer-respond-to-this-email.html deepmind.com/blog/deepmind-ai-reduces-google-data-centre-cooling-bill-40/ www.skype.com/en/features/skype-translator/ arxiv.org/abs/1603.01768 诊断肺癌[56:55] 其他当前应用 卷积神经网络[59:13]
线性层
setosa.io/ev/image-kernels/ 非线性层[01:02:12]
神经网络和深度学习
在这一章中我给出了普适性定理的简单且大部分是可视化的解释。我们将一步一步地进行…
Sigmoid 和 ReLU 线性层和逐元素非线性函数的组合使我们能够创建任意复杂的形状 — 这是普适性定理的本质。
如何设置这些参数来解决问题[01:04:25]
随机梯度下降 — 我们沿着山坡小步前进。步长被称为学习率 如果学习率太大它会发散而不是收敛 如果学习率太小将需要很长时间
可视化和理解卷积网络[01:08:27] 我们从一些非常简单的东西开始但如果我们将其用作足够大的规模由于普适性定理和深度学习中多个隐藏层的使用我们实际上获得了非常丰富的能力。这实际上是我们在训练狗和猫识别器时使用的方法。
狗 vs. 猫再访——选择学习率[01:11:41]
learn.fit(0.01, 3)第一个数字0.01是学习率。 学习率决定了你想要多快或多慢地更新权重或参数。学习率是最难设置的参数之一因为它会显著影响模型性能。 方法learn.lr_find()可以帮助你找到一个最佳的学习率。它使用了 2015 年的论文Cyclical Learning Rates for Training Neural Networks中开发的技术我们简单地从一个非常小的值开始不断增加学习率直到损失停止减少。我们可以绘制跨批次的学习率看看这是什么样子。
learn ConvLearner.pretrained(arch, data, precomputeTrue)
learn.lr_find()我们的learn对象包含一个包含我们学习率调度器的属性sched并具有一些方便的绘图功能包括这个
learn.sched.plot_lr()Jeremy 目前正在尝试指数增加学习率与线性增加学习率。
我们可以看到损失与学习率的图表以查看我们的损失何时停止减少
learn.sched.plot()然后我们选择损失仍然明显改善的学习率 — 在这种情况下是1e-20.01
选择迭代次数[1:18:49] [ 0\. 0.04955 0.02605 0.98975]
[ 1\. 0.03977 0.02916 0.99219]
[ 2\. 0.03372 0.02929 0.98975]你想要多少都可以但如果运行时间太长准确性可能会开始变差。这被称为“过拟合”我们稍后会更多地了解它。 另一个考虑因素是你可用的时间。
技巧和窍门[1:21:40]
1.Tab — 当你记不住函数名时它会自动完成 2. Shift Tab — 它会显示函数的参数 3. Shift Tab Tab — 它会显示文档即 docstring 4. Shift Tab Tab Tab — 它会打开一个带有相同信息的单独窗口。 在单元格中键入?后跟一个函数名并运行它将与shift tab3 次相同 5. 输入两个问号将显示源代码 6. 在 Jupyter Notebook 中键入H将打开一个带有键盘快捷键的窗口。尝试每天学习 4 或 5 个快捷键 7. 停止 Paperspace、Crestle、AWS — 否则你将被收费$$
8. 请记住关于论坛和course.fast.ai/每节课的最新信息。
深度学习 2第 1 部分第 2 课 原文medium.com/hiromi_suenaga/deep-learning-2-part-1-lesson-2-eeae2edd2be4 译者飞龙 协议CC BY-NC-SA 4.0 来自 fast.ai 课程的个人笔记。随着我继续复习课程以“真正”理解它这些笔记将继续更新和改进。非常感谢 Jeremy 和Rachel 给了我这个学习的机会。 第 2 课
笔记本
上一课的回顾[01:02] 我们用 3 行代码构建了一个图像分类器。 为了训练模型数据需要以一定方式组织在PATH在本例中为data/dogscats/下 应该有一个train文件夹和一个valid文件夹每个文件夹下面都有带有分类标签的文件夹例如本例中的cats和dogs其中包含相应的图像。 训练输出[*epoch #*,* *training loss*, *validation loss*, *accuracy*] [ 0\. 0.04955 0.02605 0.98975]学习率[4:54] 学习率的基本思想是它将决定我们快速地聚焦在解决方案上。 如果学习率太小将需要很长时间才能到达底部 如果学习率太大它可能会从底部摆动。 学习率查找器learn.lr_find会在每个小批次后增加学习率。最终学习率会变得太高损失会变得更糟。然后我们查看学习率与损失的图表并确定最低点然后后退一个数量级并选择该学习率在下面的示例中为1e-2。 小批量是我们每次查看的几个图像以便有效地利用 GPU 的并行处理能力通常每次 64 或 128 个图像。 在 Python 中 通过调整这个数字您应该能够获得相当不错的结果。fast.ai 库会为您选择其余的超参数。但随着课程的进行我们将学习到一些更多的可以调整以获得稍微更好结果的东西。但学习率对我们来说是关键数字。 学习率查找器位于其他优化器例如动量、Adam 等之上并帮助您选择最佳学习率考虑您正在使用的其他调整例如高级优化器但不限于优化器。 问题在 epoch 期间改变学习率的优化器会发生什么这个查找器是否选择了初始学习率[14:05] 我们稍后会详细了解优化器但基本答案是否定的。即使是 Adam 也有一个学习率该学习率会被平均先前梯度和最近平方梯度的总和除以。即使那些所谓的“动态学习率”方法也有学习率。 使模型更好的最重要的事情是提供更多数据。由于这些模型有数百万个参数如果您训练它们一段时间它们开始做所谓的“过拟合”。 过拟合 - 模型开始看到训练集中图像的具体细节而不是学习一些可以转移到验证集的通用内容。 我们可以收集更多数据但另一种简单的方法是数据增强。
数据增强[15:50] 每个 epoch我们会随机微调图像。换句话说模型每个 epoch 都会看到图像的略微不同版本。 您希望为不同类型的图像使用不同类型的数据增强水平翻转、垂直翻转、放大、缩小、变化对比度和亮度等。
学习率查找问题 为什么不选择最低点损失最低的点是红色圆圈所在的位置。但是在那一点学习率实际上太大了不太可能收敛。因此前一个点可能是更好的选择总是选择比太大的学习率更小的学习率更好 何时学习lr_find在开始时运行一次也许在解冻层之后再运行我们稍后会学习。还有当我改变我正在训练的东西或改变我训练的方式时。运行它永远不会有害。
回到数据增强
tfms tfms_from_model(resnet34, sz, aug_tfmstransforms_side_on, max_zoom1.1)transform_side_on - 用于侧面照片的预定义转换集还有transform_top_down。稍后我们将学习如何创建自定义转换列表。 这并不是在创建新数据而是让卷积神经网络学习如何从略有不同的角度识别猫或狗。
data ImageClassifierData.from_paths(PATH, tfmstfms)
learn ConvLearner.pretrained(arch, data, precomputeTrue)learn.fit(1e-2, 1)现在我们创建了一个包含增强的新data对象。最初由于precomputeTrue增强实际上什么也没做。 卷积神经网络有这些称为“激活”的东西。激活是一个数字表示“这个特征在这个位置以这个置信度概率”。我们正在使用一个已经学会识别特征的预训练网络即我们不想改变它学到的超参数所以我们可以预先计算隐藏层的激活然后只训练最终的线性部分。 这就是为什么当你第一次训练模型时需要更长时间 - 它正在预计算这些激活。 尽管我们每次都试图展示猫的不同版本但我们已经为特定版本的猫预先计算了激活即我们没有使用改变后的版本重新计算激活。 要使用数据增强我们必须执行learn.precomputeFalse
learn.precomputeFalselearn.fit(1e-2, 3, cycle_len1)[ 0\. 0.03597 0.01879 0.99365]
[ 1\. 0.02605 0.01836 0.99365]
[ 2\. 0.02189 0.0196 0.99316]坏消息是准确性没有提高。训练损失在减少但验证损失没有但我们没有过拟合。过拟合是指训练损失远低于验证损失。换句话说当你的模型在训练集上表现比在验证集上好得多时这意味着你的模型没有泛化。 cycle_len1这使得**随机梯度下降重启SGDR**成为可能。基本思想是当你越来越接近具有最小损失的位置时你可能希望开始减小学习率采取更小的步骤以确切地到达正确的位置。 在训练过程中降低学习率的想法被称为学习率退火这是非常常见的。最常见和“hacky”方法是使用某个学习率训练模型一段时间当它停止改进时手动降低学习率分阶段退火。 更好的方法是简单地选择某种功能形式 - 结果表明真正好的功能形式是余弦曲线的一半它在开始时保持高学习率然后在接近时迅速下降。 然而我们可能发现自己处于一个不太有弹性的权重空间中 - 也就是说对权重进行微小的更改可能导致损失的巨大变化。我们希望鼓励我们的模型找到既准确又稳定的权重空间的部分。因此我们不时增加学习率这是“SGDR”中的“重启”这将迫使模型跳到权重空间的不同部分如果当前区域“尖锐”。如果我们三次重置学习率它可能看起来像这样在这篇论文中他们称之为“循环 LR 计划” 重置学习率之间的周期数由cycle_len设置这种情况下发生的次数被称为周期数实际上是我们作为fit()的第二个参数传递的内容。这是我们实际学习率的样子 问题我们可以通过使用随机起始点获得相同的效果吗在创建 SGDR 之前人们通常会创建“集成”他们会重新学习一个全新的模型十次希望其中一个会变得更好。在 SGDR 中一旦我们接近最佳和稳定区域重置实际上不会“重置”而是权重保持更好。因此SGDR 将比随机尝试几个不同的起始点给出更好的结果。 选择一个学习率这是 SGDR 使用的最高学习率很重要它足够大可以使重置跳转到函数的不同部分。 SGDR 会在每个小批次中降低学习率并且重置每个cycle_len周期在这种情况下设置为 1。 问题我们的主要目标是泛化而不是陷入狭窄的最优解。在这种方法中我们是否跟踪最小值并对其进行平均处理并集成它们这是另一种复杂程度您可以在图表中看到“快照集成”。我们目前没有这样做但如果您希望泛化得更好可以在重置之前保存权重并取平均值。但目前我们只会选择最后一个。 如果您想要跳过还有一个名为cycle_save_name的参数您可以添加它以及cycle_len它将在每个学习率周期结束时保存一组权重然后您可以将它们集成。
保存模型
learn.save(224_lastlayer)
learn.load(224_lastlayer)当您预计算激活或创建调整大小的图像我们将很快学习到会创建各种临时文件您可以在data/dogcats/tmp文件夹下看到。如果出现奇怪的错误可能是因为预计算的激活只完成了一半或者以某种方式与您正在进行的操作不兼容。因此您可以随时继续并删除此/tmp文件夹看看是否可以消除错误相当于将其关闭然后重新打开。 您还会看到一个名为/models的目录这是当您说learn.save时保存模型的位置。
微调和差分学习率 到目前为止我们还没有重新训练任何预训练的特征 - 具体来说卷积核中的任何权重。我们所做的只是在顶部添加了一些新层并学会了如何混合和匹配预训练的特征。 像卫星图像、CT 扫描等图像具有完全不同类型的特征与 ImageNet 图像相比因此您需要重新训练许多层。 对于狗和猫图像与模型预先训练的图像相似但我们仍然可能发现微调一些后续层会有所帮助。 这是如何告诉学习者我们要开始实际更改卷积滤波器本身的方法
learn.unfreeze()“冻结”层是一个未被训练/更新的层。unfreeze会解冻所有层。 像第一层检测对角边缘或梯度或第二层识别角落或曲线这样的早期层可能根本不需要或只需要很少的更改。 后续层更有可能需要更多的学习。因此我们创建了一个学习率数组差分学习率
lrnp.array([1e-4,1e-3,1e-2])1e-4用于前几层基本几何特征 1e-3用于中间层复杂的卷积特征 1e-2用于我们添加的顶部层 为什么是 3实际上它们是 3 个 ResNet 块但现在可以将其视为一组层。
问题如果我的图片比模型训练的图片大怎么办简短的答案是使用这个库和我们正在使用的现代架构我们可以使用任何大小的图片。
问题我们可以只解冻特定的层吗我们还没有这样做但如果你想的话你可以使用learn.unfreeze_to(n)这将从第n层开始解冻层。Jeremy 几乎从来没有发现这有帮助他认为这是因为我们使用了不同的学习率优化器可以学习到它需要的一样多。他发现有帮助的一个地方是如果他使用一个真正大的内存密集型模型而且他的 GPU 快要用完了你解冻的层数越少占用的内存和时间就越少。
使用不同的学习率我们的准确率达到了 99.5%
learn.fit(lr, 3, cycle_len1, cycle_mult2)[ 0\. 0.04538 0.01965 0.99268]
[ 1\. 0.03385 0.01807 0.99268]
[ 2\. 0.03194 0.01714 0.99316]
[ 3\. 0.0358 0.0166 0.99463]
[ 4\. 0.02157 0.01504 0.99463]
[ 5\. 0.0196 0.0151 0.99512]
[ 6\. 0.01356 0.01518 0.9956 ]之前我们说3是周期的数量但实际上是周期。所以如果cycle_len2它将执行 3 个周期每个周期为 2 个周期即 6 个周期。那为什么是 7 个这是因为cycle_mult。 cycle_mult2这会在每个周期后乘以周期的长度1 个周期2 个周期4 个周期7 个周期。
直观地说如果周期长度太短它开始下降寻找一个好的位置然后弹出再次下降寻找一个好的位置然后弹出永远无法找到一个好的位置。在早期你希望它这样做因为它试图找到一个更平滑的位置但后来你希望它做更多的探索。这就是为什么cycle_mult2似乎是一个好方法。
我们正在引入越来越多的超参数告诉你没有很多。你可以只选择一个好的学习率但添加这些额外的调整可以在不费力的情况下获得额外的提升。一般来说好的起点是 n_cycle3cycle_len1cycle_mult2 n_cycle3cycle_len2没有cycle_mult
问题为什么更平滑的表面与更广义的网络相关 假设你有一个尖锐的东西蓝线。X 轴显示了当你改变这个特定参数时它在识别狗和猫方面的表现如何。可泛化意味着当我们给它一个略微不同的数据集时我们希望它能够工作。略微不同的数据集可能在这个参数和猫狗之间的关系上有略微不同。它可能看起来像红线。换句话说如果我们最终到达蓝色尖锐部分那么它在这个略微不同的数据集上不会表现良好。或者如果我们最终到达较宽的蓝色部分它仍然会在红色数据集上表现良好。
这里有一些关于峰值最小值的有趣讨论。
测试时间增强TTA
我们的模型已经达到了 99.5%。但我们还能让它变得更好吗让我们看看我们错误预测的图片 在这里Jeremy 打印出了所有这些图片。当我们进行验证集时我们模型的所有输入必须是正方形的。原因有点小的技术细节但如果不同的图片有不同的尺寸GPU 不会很快。它需要保持一致以便 GPU 的每个部分都可以做同样的事情。这可能是可以解决的但目前这是我们拥有的技术状态。
为了使它成为正方形我们只需挑选中间的正方形——正如你所看到的可以理解为什么这张图片被错误分类 我们将进行所谓的“测试时间增强”。这意味着我们将随机进行 4 次数据增强以及未增强的原始图像中心裁剪。然后我们将为所有这些图像计算预测取平均值并将其作为我们的最终预测。请注意这仅适用于验证集和/或测试集。
要做到这一点您只需learn.TTA()——这将将准确性提高到 99.65%
log_preds,y learn.TTA()
probs np.mean(np.exp(log_preds),0)
accuracy(probs, y)0.99650000000000005关于增强方法的问题[01:01:36]为什么不使用边框或填充使其变成正方形通常 Jeremy 不会做太多填充而是会做一点缩放。有一种叫做反射填充的东西在卫星图像中效果很好。一般来说使用 TTA 加数据增强最好的做法是尽可能使用尽可能大的图像。此外固定裁剪位置加上随机对比度、亮度、旋转变化可能对 TTA 更好。
问题非图像数据集的数据增强[01:03:35] 没有人似乎知道。看起来会有帮助但例子很少。在自然语言处理中人们尝试替换同义词但总体来说这个领域研究不足发展不足。
问题fast.ai 库是开源的吗[01:05:34] 是的。然后他讲解了Fast.ai 从 Keras TensorFlow 切换到 PyTorch 的原因
随机笔记PyTorch 不仅仅是一个深度学习库。它实际上让我们可以从头开始编写任意 GPU 加速的算法——Pyro 是人们现在在 PyTorch 之外进行的一个很好的例子。
分析结果[01:11:50]
混淆矩阵
分类结果的简单查看方式称为混淆矩阵——不仅用于深度学习而且用于任何类型的机器学习分类器。如果你试图预测四五类特别有帮助可以看出你在哪个组别遇到了最大的困难。 preds np.argmax(probs, axis1)
probs probs[:,1]
from sklearn.metrics import confusion_matrix
cm confusion_matrix(y, preds)
plot_confusion_matrix(cm, data.classes)让我们再次看看图片[01:13:00]
大多数错误的猫只有左边两个是错误的——默认显示 4 个 大多数错误的点 回顾训练世界一流的图像分类器的简单步骤[01:14:09] 启用数据增强precomputeTrue 使用lr_find()找到损失仍然明显改善的最高学习率 从预计算的激活中训练最后一层 1-2 个时期 使用数据增强训练最后一层即precomputeFalse2-3 个时期cycle_len1 解冻所有层 将前面的层设置为比下一层低 3 倍至 10 倍的学习率。经验法则ImageNet 类似的图像为 10 倍卫星或医学成像为 3 倍 再次使用lr_find()注意如果您设置了不同的学习率并调用lr_find它打印出的是最后几层的学习率。 使用cycle_mult2训练完整网络直到过拟合
让我们再做一次狗品种挑战 [01:16:37] 您可以使用Kaggle CLI下载 Kaggle 竞赛的数据 笔记本没有公开因为它是一个活跃的竞赛
%reload_ext autoreload
%autoreload 2
%matplotlib inlinefrom fastai.imports import *
from fastai.transforms import *
from fastai.conv_learner import *
from fastai.model import *
from fastai.dataset import *
from fastai.sgdr import *
from fastai.plots import *
PATH data/dogbreed/
sz 224
arch resnext101_64
bs16
label_csv f{PATH}labels.csv
n len(list(open(label_csv)))-1
val_idxs get_cv_idxs(n)
!ls {PATH}这与我们以前的数据集有点不同。它没有一个包含每个狗品种的单独文件夹的train文件夹而是有一个带有正确标签的 CSV 文件。我们将使用 Pandas 读取 CSV 文件。Pandas 是我们在 Python 中用来进行结构化数据分析的工具比如 CSV通常被导入为pd
label_df pd.read_csv(label_csv)
label_df.head()label_df.pivot_table(indexbreed, aggfunclen).sort_values(id, ascendingFalse)每个品种有多少狗图像
tfms tfms_from_model(arch, sz, aug_tfmstransforms_side_on, max_zoom1.1)
data ImageClassifierData.from_csv(PATH, train, f{PATH}labels.csv, test_nametest, val_idxsval_idxs, suffix.jpg, tfmstfms, bsbs)max_zoom——我们将放大 1.1 倍 ImageClassifierData.from_csv — 上次我们使用了from_paths但由于标签在 CSV 文件中我们将使用from_csv。 test_name — 如果要提交到 Kaggle 比赛我们需要指定测试集的位置 val_idx — 没有validation文件夹但我们仍然想要跟踪我们的本地表现有多好。因此你会看到上面的
n len(list(open(label_csv)))-1打开 CSV 文件创建一个行列表然后取长度。 -1是因为第一行是标题。因此n是我们拥有的图像数量。
val_idxs **get_cv_idxs**(n) “获取交叉验证索引” — 默认情况下这将返回随机 20%的行确切的索引作为验证集。你也可以发送val_pct以获得不同的数量。 suffix.jpg — 文件名以.jpg结尾但 CSV 文件没有。因此我们将设置suffix以便它知道完整的文件名。
fn PATH data.trn_ds.fnames[0]; fndata/dogbreed/train/001513dfcb2ffafc82cccf4d8bbaba97.jpg你可以通过说data.trn_ds来访问训练数据集trn_ds包含很多东西包括文件名fnames
img PIL.Image.open(fn); imgimg.size(500, 375)现在我们检查图像大小。如果它们很大那么你必须非常仔细地考虑如何处理它们。如果它们很小也是具有挑战性的。大多数 ImageNet 模型都是在 224x224 或 299x299 的图像上训练的
size_d {k: PIL.Image.open(PATHk).size for k in data.trn_ds.fnames}字典推导 — 键: 文件名值: 文件大小
row_sz, col_sz list(zip(*size_d.values()))*size_d.values()将解压缩一个列表。zip将元组的元素配对以创建一个元组列表。
plt.hist(row_sz);行的直方图
如果你在 Python 中进行任何数据科学或机器学习Matplotlib 是你想要非常熟悉的东西。Matplotlib 总是被称为plt。
问题我们应该使用多少图像作为验证集[01:26:28] 使用 20%是可以的除非数据集很小 — 那么 20%就不够了。如果你多次训练相同的模型并且得到非常不同的验证集结果那么你的验证集太小了。如果验证集小于一千很难解释你的表现如何。如果你关心准确度的第三位小数并且验证集中只有一千个数据一个图像的变化就会改变准确度。如果你关心 0.01 和 0.02 之间的差异你希望这代表 10 或 20 行。通常 20%似乎效果不错。
def get_data(sz, bs):tfms tfms_from_model(arch, sz, aug_tfmstransforms_side_on,max_zoom1.1)data ImageClassifierData.from_csv(PATH, train, f{PATH}labels.csv, test_nametest, num_workers4,val_idxsval_idxs, suffix.jpg, tfmstfms, bsbs) return data if sz300 else data.resize(340, tmp) 这是常规的两行代码。当我们开始使用新数据集时我们希望一切都能快速进行。因此我们可以指定大小并从 64 开始这样会运行得更快。稍后我们将使用更大的图像和更大的架构到那时你可能会耗尽 GPU 内存。如果你看到 CUDA 内存不足错误你需要做的第一件事是重新启动内核你无法从中恢复然后减小批量大小。
data get_data(224, bs)
learn ConvLearner.pretrained(arch, data, precomputeTrue)
learn.fit(1e-2, 5)[0\. 1.99245 1.0733 0.76178]
[1\. 1.09107 0.7014 0.8181 ]
[2\. 0.80813 0.60066 0.82148]
[3\. 0.66967 0.55302 0.83125]
[4\. 0.57405 0.52974 0.83564]对于 120 个类别来说83%是相当不错的。
learn.precompute False
learn.fit(1e-2, 5, cycle_len1)提醒一个epoch是对数据的一次遍历一个cycle是你说一个周期中有多少个 epoch
learn.save(224_pre)
learn.load(224_pre)增加图像大小 [1:32:55]
learn.set_data(get_data(299, bs))如果你在较小尺寸的图像上训练了一个模型然后可以调用learn.set_data并传入一个更大尺寸的数据集。这将采用到目前为止已经训练过的模型并让你继续在更大的图像上训练。 从小图像开始训练几个时期然后切换到更大的图像并继续训练是一个非常有效的避免过拟合的方法。 learn.fit(1e-2, 3, cycle_len1)[0\. 0.35614 0.22239 0.93018]
[1\. 0.28341 0.2274 0.92627]
[2\.* *0.28341**0.2274* *0.92627]如你所见验证集损失0.2274远低于训练集损失0.28341 — 这意味着它是欠拟合。当你欠拟合时意味着cycle_len1太短了学习率在适当缩小之前被重置。所以我们将添加cycle_mult2即第一个周期是 1 个时期第二个周期是 2 个时期第三个周期是 4 个时期
learn.fit(1e-2, 3, cycle_len1, cycle_mult2)[0\. 0.27171 0.2118 0.93192]
[1\. 0.28743 0.21008 0.9324 ]
[2\. 0.25328 0.20953 0.93288]
[3\. 0.23716 0.20868 0.93001]
[4\. 0.23306 0.20557 0.93384]
[5\. 0.22175 0.205 0.9324 ]
[6\. 0.2067 0.20275 0.9348 ]现在验证损失和训练损失大致相同 — 这是正确的轨道。然后我们尝试TTA
log_preds, y learn.TTA()
probs np.exp(log_preds)
accuracy(log_preds,y), metrics.log_loss(y, probs)(0.9393346379647749, 0.20101565705592733)其他尝试 尝试再运行一个 2 个时期的周期 解冻在这种情况下训练卷积层根本没有帮助因为图像实际上来自 ImageNet 删除验证集只需重新运行相同的步骤并提交 - 这样我们可以使用 100%的数据。
问题我们如何处理不平衡的数据集[01:38:46]这个数据集不是完全平衡的在 60 和 100 之间但不够不平衡以至于 Jeremy 不会再考虑。最近的一篇论文说处理非常不平衡的数据集的最佳方法是复制罕见情况。
问题precomputeTrue和unfreeze之间的区别 我们从预训练网络开始 我们在其末尾添加了几层这些层最初是随机的。当所有内容都被冻结且precomputeTrue时我们学到的只是我们添加的层。 使用precomputeTrue数据增强不起作用因为每次显示的激活完全相同。 然后我们将precomputeFalse设置为假这意味着我们仍然只训练我们添加的层因为它被冻结但数据增强现在正在工作因为它实际上正在重新计算所有激活。 最后我们解冻这意味着“好的现在您可以继续更改所有这些早期卷积滤波器”。
问题为什么不从一开始就将precomputeFalse设置为假将precomputeTrue的唯一原因是它速度更快快 10 倍或更多。如果您正在处理相当大的数据集它可以节省相当多的时间。从来没有理由使用precomputeTrue来提高准确性。
获得良好结果的最小步骤 使用lr_find()找到损失仍然明显改善的最高学习率 使用数据增强即precomputeFalse训练最后一层 2-3 个周期cycle_len1 解冻所有层 将较早的层设置为比下一层更高的层次低 3 倍至 10 倍的学习率 使用cycle_mult2训练完整网络直到过拟合
问题减少批量大小只影响训练速度吗[1:43:34]是的基本上是这样。如果每次显示的图像较少则使用较少的图像计算梯度 - 因此准确性较低。换句话说知道要走哪个方向以及在该方向上走多远的准确性较低。因此随着批量大小变小它变得更加不稳定。它会影响您需要使用的最佳学习率但实际上将批量大小除以 2 与除以 4 似乎并没有太大变化。如果更改批量大小很大可以重新运行学习率查找器进行检查。
问题灰色图像与右侧图像之间有什么区别 可视化和理解卷积网络
第一层它们确实是滤波器的样子。很容易可视化因为输入是像素。后来变得更难因为输入本身是激活是激活的组合。Zeiler 和 Fergus 提出了一种聪明的技术展示滤波器平均倾向于什么样子 - 称为反卷积我们将在第 2 部分学习。右侧是激活该滤波器的图像块的示例。
问题如果狗在角落或很小你会怎么做关于狗品种识别[01:47:16]我们将在第 2 部分学习但有一种技术可以让您大致确定图像的哪些部分最有趣。然后您可以裁剪出该区域。
进一步改进[01:48:16]
立即可以做两件事来使其更好 假设您使用的图像大小小于您所获得的图像的平均大小您可以增加大小。正如我们之前所看到的您可以在训练期间增加它。 使用更好的架构。有不同的方法来组合卷积滤波器的大小以及它们如何连接在一起不同的架构具有不同数量的层内核大小滤波器等。
我们一直在使用 ResNet34 — 一个很好的起点通常也是一个很好的终点因为它没有太多参数并且在小数据集上表现良好。还有另一种架构叫做 ResNext它是去年 ImageNet 比赛的第二名。ResNext50 的训练时间是 ResNet34 的两倍内存使用量是其 2-4 倍。
这里是几乎与原始狗和猫相同的笔记本。使用了 ResNext50实现了 99.75%的准确率。
卫星图像 [01:53:01] 笔记本
代码基本与之前看到的相同。以下是一些不同之处 transforms_top_down — 由于它们是卫星图像所以在垂直翻转时仍然有意义。 学习率更高 — 与这个特定数据集有关 lrs np.array([lr/9,lr/3,lr]) — 差异学习率现在变为 3 倍因为图像与 ImageNet 图像非常不同 sz64 — 这有助于避免卫星图像的过拟合但对于狗和猫或狗品种与 ImageNet 相似的图像他不会这样做因为 64x64 相当小可能会破坏预训练权重。
如何设置您的 AWS [01:58:54]
您可以跟着视频或这里是一位学生写的很好的文章。
深度学习 2第 1 部分第 3 课 原文medium.com/hiromi_suenaga/deep-learning-2-part-1-lesson-3-74b0ef79e56 译者飞龙 协议CC BY-NC-SA 4.0 来自 fast.ai 课程的个人笔记。随着我继续复习课程以“真正”理解它这些笔记将继续更新和改进。非常感谢 Jeremy 和Rachel 给了我这个学习的机会。 第 3 课
学生们制作的有用材料 AWS 如何操作 Tmux 第 2 课总结 学习率查找器 PyTorch 学习率与批量大小 错误表面的平滑区域与泛化 5 分钟内的卷积神经网络 解码 ResNet 架构 又一个 ResNet 教程
我们接下来要做什么 回顾[08:24]
Kaggle CLI如何下载数据 1
Kaggle CLI是从 Kaggle 下载时使用的好工具。因为它是通过屏幕抓取从 Kaggle 网站下载数据当网站更改时会中断。当发生这种情况时运行pip install kaggle-cli --upgrade。
然后您可以运行
$ kg download -u username -p password -c competition用您的凭据替换usernamepasswordcompetition是 URL 中/c/后面的内容。例如如果您想从https://www.kaggle.com**/c/**dog-breed-identification下载狗品种数据命令将如下所示
$ kg download -u john.doe -p mypassword -c dog-breed-identification确保您已经从计算机上点击了下载按钮并接受了规则 CurWgetChrome 扩展程序如何下载数据 2 快速狗与猫[13:39]
from fastai.conv_learner import *
PATH data/dogscats/
sz224; bs64通常笔记本假设您的数据在data文件夹中。但也许您想把它们放在其他地方。在这种情况下您可以使用符号链接简称 symlink 以下是一个端到端的过程用于获得狗与猫的最新结果 快速狗与猫
稍微进一步的分析
data ImageClassifierData.from_paths(PATH, tfms tfms, bsbs, test_nametest)from_paths表示子文件夹名称是标签。如果您的train文件夹或valid文件夹有不同的名称您可以发送trn_name和val_name参数。 test_name如果您想提交到 Kaggle 竞赛您需要填写测试集所在文件夹的名称。
learn ConvLearner.pretrained(resnet50, data)请注意我们没有设置pre_compueTrue。这只是一个快捷方式可以缓存一些中间步骤这些步骤不必每次重新计算。如果您对此感到困惑可以将其留空。 请记住当pre_computeTrue时数据增强不起作用。
learn.unfreeze()
learn.bn_freeze(True)
%time learn.fit([1e-5, 1e-4,1e-2], 1, cycle_len1)bn_freeze如果您正在使用更大更深的模型如 ResNet50 或 ResNext101任何数字大于 34 的模型在一个与 ImageNet 非常相似的数据集上即侧面拍摄的标准物体的照片其大小与 ImageNet 在 200-500 像素之间您应该添加这一行。我们将在课程的后半部分学到更多但这会导致批量归一化移动平均值不会被更新。
如何使用其他库 — Keras [20:02]
了解如何使用 Fast.ai 以外的库是很重要的。Keras 是一个很好的例子因为就像 Fast.ai 建立在 PyTorch 之上一样它也建立在各种库之上如 TensorFlow、MXNet、CNTK 等。
如果您想运行笔记本运行pip install tensorflow-gpu keras
定义数据生成器
train_data_dir f{PATH}train
validation_data_dir f{PATH}valid
train_datagen ImageDataGenerator(rescale1. / 255,shear_range0.2, zoom_range0.2, horizontal_flipTrue
)
test_datagen ImageDataGenerator(rescale1. / 255)
train_generator train_datagen.flow_from_directory(train_data_dir,target_size(sz, sz),batch_sizebatch_size, class_modebinary
)
validation_generator test_datagen.flow_from_directory(validation_data_dir,shuffleFalse,target_size(sz, sz),batch_sizebatch_size, class_modebinary
)训练文件夹和验证文件夹的子文件夹与标签名称的想法是常见的Keras 也这样做。 Keras 需要更多的代码和更多的参数来设置。 与创建单个数据对象不同在 Keras 中您定义DataGenerator并指定要进行的数据增强类型还要指定要进行的规范化类型。换句话说在 Fast.ai 中我们可以说“ResNet50 需要什么就请为我做”但在 Keras 中您需要知道期望的是什么。没有标准的增强集。 然后您必须创建一个验证数据生成器您负责创建一个没有数据增强的生成器。您还必须告诉它不要对验证数据集进行洗牌否则您无法跟踪您的表现如何。
2. 创建模型
base_model ResNet50(weightsimagenet, include_topFalse)
x base_model.output
x GlobalAveragePooling2D()(x)
x Dense(1024, activationrelu)(x)
predictions Dense(1, activationsigmoid)(x)Jeremy 在 Quick Dogs and Cats 中使用 ResNet50 的原因是因为 Keras 没有 ResNet34。我们想要进行苹果对苹果的比较。 您不能要求它构建适合特定数据集的模型因此您必须手动完成。 首先创建一个基本模型然后构建您想要添加到其顶部的层。
3. 冻结层并编译
model Model(inputsbase_model.input, outputspredictions)
for layer in base_model.layers: layer.trainable Falsemodel.compile(optimizerrmsprop, lossbinary_crossentropy, metrics[accuracy])通过循环层并手动调用layer.trainableFalse来冻结它们 您需要编译一个模型 传递优化器、损失和指标的类型
4. 拟合
model.fit_generator(train_generator, train_generator.n//batch_size,epochs3, workers4, validation_datavalidation_generator,validation_stepsvalidation_generator.n // batch_size
)Keras 希望知道每个 epoch 有多少批次。 workers要使用的处理器数量
5. 微调解冻一些层编译然后再次拟合
split_at 140
for layer in model.layers[:split_at]: layer.trainable False
for layer in model.layers[split_at:]: layer.trainable True
model.compile(optimizerrmsprop, lossbinary_crossentropy,metrics[accuracy]
)
%%time model.fit_generator(train_generator, train_generator.n // batch_size, epochs1, workers3,validation_datavalidation_generator,validation_stepsvalidation_generator.n // batch_size
)Pytorch — 如果您想要部署到移动设备PyTorch 仍处于早期阶段。
Tensorflow — 如果您想将在本课程中学到的内容转换为更多的 Keras 工作但这需要更多的工作很难获得相同水平的结果。也许将来会有 TensorFlow 兼容版本的 Fast.ai。我们将看到。
为 Kaggle 创建提交文件[32:45]
要创建提交文件我们需要两个信息 data.classes包含所有不同的类 data.test_ds.fnames测试文件名
log_preds, y learn.TTA(is_testTrue)
probs np.exp(log_preds)始终使用TTA是一个好主意 is_testTrue它将为您提供测试集的预测而不是验证集 默认情况下PyTorch 模型将返回预测的对数因此您需要执行np.exp(log_preds)以获得概率。
ds pd.DataFrame(probs)
ds.columns data.classes创建 Pandas DataFrame 将列名设置为data.classes
ds.insert(0, id, [o[5:-4] for o in data.test_ds.fnames])在位置零插入一个名为id的新列。删除前 5 个和最后 4 个字母因为我们只需要 ID文件名看起来像test/0042d6bf3e5f3700865886db32689436.jpg
ds.head()SUBM f{PATH}sub/
os.makedirs(SUBM, exist_okTrue)
ds.to_csv(f{SUBM}subm.gz, compressiongzip, indexFalse)现在您可以调用ds.to_csv创建一个 CSV 文件compressiongzip将在服务器上对其进行压缩。
FileLink(f{SUBM}subm.gz)您可以使用 Kaggle CLI 直接从服务器提交或者您可以使用FileLink它将为您提供一个链接从服务器下载文件到您的计算机。
单个预测[39:32]
如果我们想通过模型运行单个图像以获得预测会怎样
fn data.val_ds.fnames[0]; fntrain/001513dfcb2ffafc82cccf4d8bbaba97.jpgImage.open(PATH fn)我们将从验证集中选择第一个文件。
这是获得预测的最简单方法
trn_tfms, val_tfms tfms_from_model(arch, sz)
im val_tfms(Image.open(PATHfn))preds learn.predict_array(im[None])
np.argmax(preds)图像必须被转换。tfms_from_model返回训练转换和验证转换。在这种情况下我们将使用验证转换。 传递给模型或从模型返回的所有内容通常被假定为在一个小批次中。这里我们只有一张图片但我们必须将其转换为一批包含一张图片的小批次。换句话说我们需要创建一个张量不仅是[行列通道]而是[图片数量行列通道]。 im[None]Numpy 技巧将额外的单位轴添加到开头。
理论卷积神经网络背后实际发生了什么[42:17] 我们在第 1 课中看到了一点理论 — setosa.io/ev/image-kernels/ 卷积是一种操作其中我们有一个小矩阵在深度学习中几乎总是 3x3将该矩阵的每个元素与图像的 3x3 部分的每个元素相乘然后将它们全部加在一起以获得在一个点上的卷积结果。
Otavio 的出色可视化他创建了 Word Lens
youtu.be/Oqm9vsf_hvU
Jeremy 的可视化 电子表格 [49:51] 我使用office.live.com/start/Excel.aspx 这些数据来自 MNIST 激活 通过对输入中的一些数字应用某种线性操作来计算的数字。 修正线性单元ReLU丢弃负数 — 即 MAX(0, x) 滤波器/卷积核 用于卷积的 3D 张量的 3x3 切片 张量 多维数组或矩阵 隐藏层 既不是输入也不是输出的层 最大池化 (2,2)最大池化将在高度和宽度上减半 — 将其视为一个摘要 全连接层 为每个激活赋予权重并计算总乘积。权重矩阵与整个输入一样大。 注意在最大池化层之后可以做许多事情。其中之一是在整个大小上再做一次最大池化。在旧的架构或结构化数据中我们会做全连接层。大量使用全连接层的架构容易过拟合且速度较慢。ResNet 和 ResNext 不使用非常大的全连接层。
问题如果输入有 3 个通道会发生什么[1:05:30] 它将看起来类似于具有 2 个通道的 Conv1 层 — 因此滤波器每个滤波器有 2 个通道。预训练的 ImageNet 模型使用 3 个通道。当你的通道少于 3 个时你可以使用一些技术例如复制一个通道使其变为 3 个或者如果你有 2 个通道那么取平均值并将其视为第三个通道。如果你有 4 个通道你可以向卷积核添加额外的级别所有值都为零。
接下来会发生什么[1:08:47]
我们已经走到了全连接层它执行经典的矩阵乘积。在 Excel 表中有一个激活。如果我们想要查看输入是哪一个十位数我们实际上想要计算 10 个数字。
让我们看一个例子我们试图预测一张图片是猫、狗、飞机、鱼还是建筑物。我们的目标是 从全连接层获取输出没有 ReLU因此可能有负数 计算 5 个数字每个数字都在 0 和 1 之间它们加起来等于 1。
为此我们需要一种不同类型的激活函数应用于激活的函数。
为什么我们需要非线性如果堆叠多个线性层它仍然只是一个线性层。通过添加非线性层我们可以拟合任意复杂的形状。我们使用的非线性激活函数是 ReLU。
Softmax [01:14:08]
Softmax 只会出现在最后一层。它输出介于 0 和 1 之间的数字它们加起来为 1。理论上这并不是绝对必要的 - 我们可以要求我们的神经网络学习一组核这些核给出的概率尽可能接近我们想要的。一般来说在深度学习中如果你可以构建你的架构使得所需的特征尽可能容易表达你将得到更好的模型学习更快参数更少。 通过e^x去除负数因为我们不能有负概率。它也突出了值的差异2.854.08 → 17.2559.03
所有你需要熟悉的数学来进行深度学习 然后我们将exp列182.75相加然后将e^x除以总和。结果总是正的因为我们将正数除以正数。每个数字将在 0 和 1 之间总和为 1。
问题如果我们想要将图片分类为猫和狗我们应该使用什么样的激活函数这正好是我们现在要做的事情。我们可能想这样做的一个原因是进行多标签分类。
星球竞赛[01:20:54]
笔记本 / Kaggle 页面 我绝对建议你拟人化你的激活函数。它们有个性。[1:22:21] Softmax 不喜欢预测多个事物。它想要选择一个事物。
Fast.ai 库会在有多个标签时自动切换到多标签模式。所以你不需要做任何事情。但是这是幕后发生的事情
from planet import f2metrics[f2]
f_model resnet34label_csv f**{PATH}**train_v2.csv
n len(list(open(label_csv)))-1
val_idxs get_cv_idxs(n)
def get_data(sz):tfms tfms_from_model(f_model, sz,aug_tfmstransforms_top_down, max_zoom1.05) return ImageClassifierData.from_csv(PATH, train-jpg,label_csv, tfmstfms, suffix.jpg,val_idxsval_idxs, test_nametest-jpg)
data get_data(256)使用 Keras 风格的方法无法进行多标签分类其中子文件夹是标签的名称。所以我们使用from_csv transform_top_down它不仅仅是垂直翻转。对于一个正方形有 8 种可能的对称性 - 它可以通过 0、90、180、270 度旋转对于每一个它可以被翻转八面体群。
x,y next(iter(data.val_dl))我们已经看到了data.val_dstest_dstrain_dsds数据集你可以通过data.train_ds[0]来获取单个图像例如。 dl是一个数据加载器它会给你一个小批量特别是转换后的小批量。使用数据加载器你不能要求一个特定的小批量你只能得到next小批量。在 Python 中它被称为“生成器”或“迭代器”。PyTorch 真正利用了现代 Python 方法。 如果你很了解 PythonPyTorch 会非常自然。如果你不太了解 PythonPyTorch 是学习 Python 的一个很好的理由。 x一批图像y一批标签。
如果你不确定一个函数需要什么参数按下shifttab。
list(zip(data.classes, y[0]))
[(agriculture, 1.0),(artisinal_mine, 0.0),(bare_ground, 0.0),(blooming, 0.0),(blow_down, 0.0),(clear, 1.0),(cloudy, 0.0),(conventional_mine, 0.0),(cultivation, 0.0),(habitation, 0.0),(haze, 0.0),(partly_cloudy, 0.0),(primary, 1.0),(road, 0.0),(selective_logging, 0.0),(slash_burn, 1.0),(water, 1.0)]在幕后PyTorch 和 fast.ai 将我们的标签转换为独热编码标签。如果实际标签是狗它看起来像 我们取actuals和softmax之间的差异将它们相加以表示有多少错误即损失函数[1:31:02]。
独热编码对于存储来说非常低效所以我们将存储一个索引值单个整数而不是目标值y的 0 和 1。如果您查看狗品种竞赛的y值您实际上不会看到一个大的 1 和 0 的列表而是会看到一个单个整数。在内部PyTorch 将索引转换为独热编码向量即使您永远不会看到它。PyTorch 有不同的损失函数适用于独热编码和其他不是独热编码的情况但这些细节被 fast.ai 库隐藏因此您不必担心。但要意识到的很酷的事情是我们对单标签分类和多标签分类都做了完全相同的事情。
问题改变 softmax 的对数基数有意义吗[01:32:55] 不改变基数只是一个线性缩放神经网络可以轻松学习 plt.imshow(data.val_ds.denorm(to_np(x))[0]*1.4);*1.4图像被冲洗了所以让它更明显“稍微提亮”。图像只是数字矩阵所以我们可以做这样的事情。 尝试这样的图像是很好的因为这些图像根本不像 ImageNet。你所做的绝大多数涉及卷积神经网络的事情实际上都不像 ImageNet医学成像分类不同种类的钢管卫星图像等
sz64
data get_data(sz)
data data.resize(int(sz*1.3), tmp)我们不会在猫狗竞赛中使用sz64因为我们从预训练的 ImageNet 网络开始它几乎完美。如果我们用 64x64 的图像重新训练整个集合我们会破坏已经非常好的权重。请记住大多数 ImageNet 模型是用 224x224 或 299x299 的图像训练的。 ImageNet 中没有像上面那样的图像。而且只有前几层对我们有用。所以从较小的图像开始在这种情况下效果很好。
learn ConvLearner.pretrained(f_model, data, metricsmetrics)
lrflearn.lr_find()
learn.sched.plot()lr 0.2
learn.fit(lr, 3, cycle_len1, cycle_mult2)[ 0\. 0.14882 0.13552 0.87878]
[ 1\. 0.14237 0.13048 0.88251]
[ 2\. 0.13675 0.12779 0.88796]
[ 3\. 0.13528 0.12834 0.88419]
[ 4\. 0.13428 0.12581 0.88879]
[ 5\. 0.13237 0.12361 0.89141]
[ 6\. 0.13179 0.12472 0.8896 ]lrs np.array(**[lr/9, lr/3, lr]**)learn.unfreeze()
learn.fit(lrs, 3, cycle_len1, cycle_mult2)[ 0\. 0.12534 0.10926 0.90892]
[ 1\. 0.12035 0.10086 0.91635]
[ 2\. 0.11001 0.09792 0.91894]
[ 3\. 0.1144 0.09972 0.91748]
[ 4\. 0.11055 0.09617 0.92016]
[ 5\. 0.10348 0.0935 0.92267]
[ 6\. 0.10502 0.09345 0.92281][lr/9, lr/3, lr] — 这是因为这些图像不像 ImageNet 图像而且较早的层可能与它们需要的不太接近。
learn.sched.plot_loss()sz 128
learn.set_data(get_data(sz))
learn.freeze()
learn.fit(lr, 3, cycle_len1, cycle_mult2)[ 0\. 0.09729 0.09375 0.91885]
[ 1\. 0.10118 0.09243 0.92075]
[ 2\. 0.09805 0.09143 0.92235]
[ 3\. 0.09834 0.09134 0.92263]
[ 4\. 0.096 0.09046 0.9231 ]
[ 5\. 0.09584 0.09035 0.92403]
[ 6\. 0.09262 0.09059 0.92358]learn.unfreeze()
learn.fit(lrs, 3, cycle_len1, cycle_mult2)
learn.save(f{sz})[ 0\. 0.09623 0.08693 0.92696]
[ 1\. 0.09371 0.08621 0.92887]
[ 2\. 0.08919 0.08296 0.93113]
[ 3\. 0.09221 0.08579 0.92709]
[ 4\. 0.08994 0.08575 0.92862]
[ 5\. 0.08729 0.08248 0.93108]
[ 6\. 0.08218 0.08315 0.92971]sz 256
learn.set_data(get_data(sz))
learn.freeze()
learn.fit(lr, 3, cycle_len1, cycle_mult2)[ 0\. 0.09161 0.08651 0.92712]
[ 1\. 0.08933 0.08665 0.92677]
[ 2\. 0.09125 0.08584 0.92719]
[ 3\. 0.08732 0.08532 0.92812]
[ 4\. 0.08736 0.08479 0.92854]
[ 5\. 0.08807 0.08471 0.92835]
[ 6\. 0.08942 0.08448 0.9289 ]learn.unfreeze()
learn.fit(lrs, 3, cycle_len1, cycle_mult2)
learn.save(f{sz})[ 0\. 0.08932 0.08218 0.9324 ]
[ 1\. 0.08654 0.08195 0.93313]
[ 2\. 0.08468 0.08024 0.93391]
[ 3\. 0.08596 0.08141 0.93287]
[ 4\. 0.08211 0.08152 0.93401]
[ 5\. 0.07971 0.08001 0.93377]
[ 6\. 0.07928 0.0792 0.93554]log_preds,y learn.TTA()
preds np.mean(np.exp(log_preds),0)
f2(preds,y)0.93626519738612801有几个人问了这个问题[01:38:46]
data data.resize(int(sz*1.3), tmp)当我们指定要应用的转换时我们发送一个大小
tfms tfms_from_model(f_model, sz,aug_tfmstransforms_top_down, max_zoom1.05
)数据加载器的一项工作是按需调整图像的大小。这与data.resize无关。如果初始图像是 1000x1000读取该 JPEG 并将其调整为 64x64 比训练卷积网络需要更多时间。data.resize告诉它我们不会使用大于sz*1.3的图像因此请通过一次并创建新的这个大小的 JPEG。由于图像是矩形的因此最小边为sz*1.3的新 JPEG中心裁剪。这将节省您大量时间。
metrics[f2]我们在这个笔记本中使用F-beta而不是accuacy这是一种权衡假阴性和假阳性的方法。我们使用它的原因是因为这个特定的 Kaggle 竞赛想要使用它。查看planet.py看看如何创建自己的指标函数。这是最后打印出来的内容[ 0\. 0.08932 0.08218 **0.9324** ]
多标签分类的激活函数[01:44:25]
多标签分类的激活函数称为sigmoid。 问题为什么我们不从不同的学习率开始训练而是只训练最后的层[01:50:30] 您可以跳过训练最后一层直接进行不同的学习率但您可能不想这样做。卷积层都包含预训练权重因此它们不是随机的 — 对于接近 ImageNet 的东西它们非常好对于不接近 ImageNet 的东西它们比没有好。然而我们所有的全连接层都是完全随机的。因此您始终希望通过先训练它们使全连接权重比随机更好一些。否则如果直接解冻那么您实际上将在后续层仍然是随机的情况下摆弄那些早期层的权重 — 这可能不是您想要的。
问题当您使用不同的学习率时这三个学习率是否均匀分布在各层之间[01:55:35]我们将在课程后面更多地讨论这个问题但是在 fast.ai 库中有一个“层组”的概念。在像 ResNet50 这样的模型中有数百个层您可能不想编写数百个学习率因此库为您决定如何分割它们最后一个始终指的是我们随机初始化并添加的全连接层。
可视化层[01:56:42]
learn.summary()[(Conv2d-1,OrderedDict([(input_shape, [-1, 3, 64, 64]),(output_shape, [-1, 64, 32, 32]),(trainable, False),(nb_params, 9408)])),(BatchNorm2d-2,OrderedDict([(input_shape, [-1, 64, 32, 32]),(output_shape, [-1, 64, 32, 32]),(trainable, False),(nb_params, 128)])),(ReLU-3,OrderedDict([(input_shape, [-1, 64, 32, 32]),(output_shape, [-1, 64, 32, 32]),(nb_params, 0)])),(MaxPool2d-4,OrderedDict([(input_shape, [-1, 64, 32, 32]),(output_shape, [-1, 64, 16, 16]),(nb_params, 0)])),(Conv2d-5,OrderedDict([(input_shape, [-1, 64, 16, 16]),(output_shape, [-1, 64, 16, 16]),(trainable, False),(nb_params, 36864)]))...‘input_shape’, [-1, **3, 64, 64**] — PyTorch 在图像尺寸之前列出通道。当按照这个顺序进行 GPU 计算时一些计算会更快。这是通过转换步骤在幕后完成的。 -1表示批量大小有多大。Keras 使用None。 ‘output_shape’, [-1, 64, 32, 32] — 64 是卷积核的数量
问题对于一个非常小的数据集学习率查找器返回了奇怪的数字绘图为空[01:58:57] — 学习率查找器将逐个小批量进行。如果您有一个微小的数据集那么就没有足够的小批量。因此诀窍是将批量大小设置得非常小如 4 或 8。
结构化数据[01:59:48]
在机器学习中我们使用两种类型的数据集 非结构化 — 音频、图像、自然语言文本其中对象内的所有内容都是同一种类型的东西 — 像素、波形振幅或单词。 结构化 — 损益表关于 Facebook 用户的信息其中每列在结构上都非常不同。 “结构化”指的是列式数据就像您在数据库或电子表格中找到的那样不同的列代表不同类型的事物每行代表一个观察。
结构化数据在学术界经常被忽视因为如果您有更好的物流模型很难在高端会议论文中发表。但这是让世界运转的东西让每个人都赚钱和提高效率。我们不会忽视它因为我们正在进行实际的深度学习Kaggle 也不会因为人们在 Kaggle 上提供奖金来解决现实世界的问题 Corporación Favorita Grocery Sales Forecasting — 目前正在进行中 Rossmann Store Sales — 几乎与上述相同但是已经完成的比赛。
Rossmann Store Sale [02:02:42]
笔记本
from fastai.structured import *
from fastai.column_data import *
np.set_printoptions(threshold50, edgeitems20)PATHdata/rossmann/fastai.structured — 不是特定于 PyTorch 的也在机器学习课程中使用使用随机森林而没有 PyTorch。它可以独立使用而无需使用 Fast.ai 库的其他部分。 fastai.column_data — 允许我们使用列式结构化数据进行 Fast.ai 和 PyTorch 操作。 对于结构化数据需要大量使用 Pandas。Pandas 是在 Python 中尝试复制 R 的数据框架如果您对 Pandas 不熟悉这里有一本好书 — Python 数据分析第二版
有很多数据预处理。这个笔记本包含了第三名获奖者的整个流程分类变量的实体嵌入。数据处理在本课程中没有涉及但在一些机器学习课程中有详细介绍因为特征工程非常重要。
查看 CSV 文件
table_names [train, store, store_states, state_names, googletrend, weather, test
]
tables [pd.read_csv(f{PATH}{fname}.csv, low_memoryFalse) for fname in table_names
]
for t in tables: display(t.head())StoreType — 您经常会得到一些列包含“代码”的数据集。实际上这个代码的含义并不重要。不要过多地了解它先看看数据说了什么。
连接表
这是一个关系型数据集您需要将许多表连接在一起 — 这在 Pandas 的 merge 中很容易实现
def join_df(left, right, left_on, right_onNone, suffix_y):if right_on is None: right_on left_onreturn left.merge(right, howleft, left_onleft_on,right_onright_on, suffixes(, suffix))来自 Fast.ai 库
add_datepart(train, Date, dropFalse)取一个日期并提取出一堆列比如“星期几”“季度开始”“年份的月份”等等并将它们全部添加到数据集中。 持续时间部分将计算诸如距下一个假期还有多长时间距上一个假期已经过去多长时间等等。
joined.to_feather(f{PATH}joined)to_feather将 Pandas 的数据框保存为“feather”格式该格式将数据框原封不动地转储到磁盘上。因此速度非常快。厄瓜多尔杂货店竞赛有 3.5 亿条记录因此您会关心保存需要多长时间。
下周 将列分为两种类型分类和连续。分类列将被表示为独热编码而连续列将被直接输入到全连接层中。 分类商店 #1 和商店 #2 之间没有数值关联。同样星期几的星期一第 0 天和星期二第 1 天也没有数值关联。 连续像到最近竞争对手的公里数这样的距离是我们以数字方式处理的一个数字。 ColumnarModelData