《Deep Learning for Computer Vision withPython》阅读笔记-PractitionerBundle(第6 - 8章)

6.利用网络集成提高精度

在本章中,我们将探讨集成方法的概念,以及获取多个分类器并将它们聚合成一个大元分类器的过程。通过将多个机器学习模型平均起来,我们可以使用随机选择的单个模型来超越(即获得更高的准确性)。事实上,几乎所有你读到的参与ImageNet挑战赛的最先进的出版物都报告了他们在卷积神经网络集合上的最佳发现。

这一章我们将从讨论Jensen不等式开始——这是集成方法的理论基础。然后,我将演示如何从一个脚本训练多个cnn,并评估它们的性能。然后,我们将把这些cnn合并到一个元分类器中,并注意准确性的提高。

6.1 集成方法

术语“集合方法”通常指的是训练“大量”模型(其中“large”的确切值取决于分类任务),然后通过投票或平均结合它们的输出预测,以提高分类准确度。事实上,集成方法很难适用于深度学习和卷积神经网络。我们已经使用集成方法很多年了。像AdaBoost[18]和Random Forests[19]这样的技术是集成方法的典型例子。

在随机森林中,我们训练了多棵决策树[20,21],并使用我们的森林进行预测。如图6.2(左)所示,我们的随机森林由多个聚合在一起的决策树组成。每个决策树对它认为的最终分类应该是什么进行“投票”。这些投票由元分类器制成表格,投票最多的类别被选为最终的分类。

同样的概念可以应用于深度学习和卷积神经网络。在这里,我们训练多个网络,然后要求每个网络返回给定输入数据点的每个类标签的概率(图6.2,左)。将这些概率相加,得到最终的分类。为了理解为什么在多个模型中平均预测是可行的,我们首先需要讨论Jensen不等式。然后,我们将提供Python和Keras代码来实现一组cnn,并亲眼看到分类精度确实有所提高。


6.1.1 詹森不等式

在最一般的术语中,一个集合是一个有限的模型集合,可以用来获得比在集合中使用单个模型更好的平均预测精度。Dietterich[23]的开创性工作详细说明了为什么集成方法通常可以获得比单个模型更高的精度的理论。

迪特里希的工作基于Jensen不等式,该不等式在机器学习文献中被称为“多样性”或“歧义分解”。Jensen不等式的正式定义表明,凸组合(平均)集合的误差将小于或等于单个模型的平均误差。这可能是一个单个模型误差低于平均的模型,但由于没有标准,我们可以使用“选择”这个模型,我们可以确信所有的平均值模型将执行没有比随机选择任何单一模型。简而言之,只有将预测平均起来,我们才能变得更好;我们不必担心会让我们的分类器变差。

对于我们这些喜欢视觉例子的人来说,也许Jensen不等式和模型平均的概念最好的解释是让你看一看这罐糖果,然后猜里面有多少个糖果(图6.2)。

你猜有多少块糖?100年?200年?500年?你的猜测可能大大高于或低于罐子里实际的糖果数量。可能非常接近。或者如果你很幸运,你可以猜出确切的糖果数量。

然而,这个游戏有一个小技巧——它是基于Jensen不等式的。如果你问我瓶子里有多少糖果,我会去找你和其他所有用Python购买了《计算机视觉深度学习》(Deep Learning for Computer Vision)的人,问他们认为糖果的数量是多少。然后我将把所有这些猜测的平均值放在一起,然后我将使用这个平均值作为我的最终预测。

现在,也许你们中有一小部分人真的是很好的猜测者,可以超过平均水平;然而,我没有任何标准来决定你们谁是真正的好猜测者。因为我不知道谁是最好的猜测者,所以我将取我问的每个人的平均值——因此我保证不会比随机选择任何一个猜测更差(平均而言)。我们每次玩猜糖果游戏时,我可能都赢不了,但我总是领先的;这就是Jensen不等式。

随机猜测糖果数量和深度学习模型之间的区别是:我们假设我们的cnn运行良好,并且是很好的猜测者(即,不是随机猜测)。因此,如果我们将这些预测器的结果平均起来,我们通常会看到分类准确度的提高。这种改进正是为什么你会看到关于深度学习的最先进的出版物训练多个模型,然后在这些集合中报告它们的最佳准确性。

6.1.2 构建一组CNN网络

构建一个整体的CNN的第一步是训练每个单独的CNN。在使用Python的计算机视觉深度学习中,我们已经看到了许多训练单个CNN的例子——但是我们如何训练多个网络呢?一般来说,我们有两个选择:

  1. 多次运行用于训练单个网络的脚本,将输出序列化模型权值的路径更改为每次运行时唯一的。
  2. 创建一个单独的Python脚本,该脚本使用for循环来训练N个网络,并在每次迭代结束时输出序列化的模型。

这两种方法对于训练一个简单的cnn集合是完全可以接受的。由于我们可以很轻松地运行一个命令来生成一个输出CNN,所以让我们尝试第二种选择,其中一个脚本负责训练多个网络。打开一个新文件,命名为train_models.py,插入以下代码:

代码:

# 导入需要的库
import matplotlib
matplotlib.use("Agg")


# 导入需要的库
from sklearn.preprocessing import LabelBinarizer
from sklearn.metrics import classification_report
from pyimagesearch.nn.conv import MiniVGGNet
from keras.preprocessing.image import ImageDataGenerator
from keras.optimizers import SGD
from keras.datasets import cifar10
import matplotlib.pyplot as plt
import numpy as np
import argparse
import os

第8行:我们将训练多个MiniVGGNet模型来形成我们的集合。•第9行:在训练我们的网络时,我们将使用ImageDataGenerator类来应用数据增强。•第10行和第11行:我们的MiniVGGNet模型将使用SGD优化器在CIFAR-10数据集上进行训练。

——output参数将作为基本输出目录,我们将在其中保存分类报告以及我们将训练的每个网络的损失/精度图。然后我们有——models开关,它控制到输出目录的路径,我们将在那里存储我们序列化的网络权重。

最后,——num-models参数表示集合中网络的数量。我们默认这个值为5个网络。而传统的整体方法,如随机森林通常由> 30决策树在很多情况下(> 100),我们通常只看到5 - 10卷积神经网络在一个整体——原因是由于cnn更耗费时间和计算昂贵的培训。

我们的下一个代码块处理从磁盘加载CIFAR-10数据集,将像素强度缩放到范围[0,1],并对我们的类标签进行一次热编码,因此我们可以应用分类交叉熵作为损失函数:

在第48行,我们开始对要训练的——num模型的数量进行循环。第52行初始化SGD优化器,使用学习速率α = 0.01,动量γ = 0.9,以及学习速率的标准Keras学习速率衰减除以总的时代数(第16章,Starter Bundle)。我们还会指出应该使用涅斯捷洛夫加速度。第54-57行然后实例化各个MiniVGGNet模型并编译它。

需要注意的是,我们永远不会直接对集成进行训练——我们将首先进行一系列实验,以确定在给定数据集上,哪种架构、优化器和超参数的组合能够产生最高的精度。

一旦你达到了这个最佳的组合集,我们就会切换到训练多个模型来形成一个集合。在你的第一个实验中训练一个集成被认为是过早的优化,因为你不知道什么样的架构、优化器和超参数组合最适合你给定的数据集。

说到这里,我们从Starter Bundle的第15章中知道,使用SGD训练的MiniVGGNet提供了83%的分类精度,通过应用集成方法,我们希望能提高这一精度。

5个网络中有4个获得了83%的分类准确率,而其余的网络仅达到82%的准确率。此外,查看所有5个训练图(图6.3),我们可以看到每组学习曲线看起来有些相似,尽管每组看起来也都是独特的,这表明每个MiniVGGNet模型都以不同的方式“学习”。

6.1.3 在集合模型之后进行评估

//截止到2022.1.24日晚上1:13

P79页

//2022.1.24日上午11:09开始阅读

创建test_ensemble文件。

从那里,我们可以加载CIFAR-10数据集,只保留测试集,因为我们只是评估(而不是训练)我们的网络:

我们现在需要收集到我们预先训练的MiniVGGNet网络的路径,这很容易使用Python内置的glob模块:

# construct the path used to collect the models then initialize the

30 # models list

31 modelPaths = os.path.sep.join([args["models"], "*.model"])

32 modelPaths = list(glob.glob(modelPaths))

33 models = []

第31行构建了一个通配符路径(注意文件路径中的星号“*”),指向——models目录中的所有.modelfiles。使用一滴。在第32行glob中,我们可以自动找到其中的所有文件路径——以.modelfile扩展名结尾的模型。在执行第32行之后,我们的modelPaths列表现在包含以下条目:

实现预测:

在第44行,我们初始化了我们的预测列表。模型列表中的每个模型将为测试中的每个数据点产生10个概率(CIFAR-10数据集中的每个类标签产生一个概率)集。假设CIFAR-10数据集中有10,000个数据点,每个模型将生成10,000 × 10大小的数组——每一行对应一个给定的数据点,每一列对应相应的概率。

为了积累这些预测,我们在第47行对每个单独的模型进行循环。然后对测试数据调用.predict,并使用各自模型生成的概率更新预测列表。在我们遍历集合中的5个模型并更新预测列表之后,我们的预测数组现在有了形状(5,10000,10),这意味着有5个模型,每个模型为10,000个测试数据点产生10个类别标签概率。第54行然后平均所有5个模型中每个测试数据点的概率。

为了亲眼看到这一点,我们可以研究预测数组的形状,它现在是(10000,10),这意味着五个模型中的每个模型的概率都被平均了。求平均值是我们称这种方法为集合的原因——我们取多个独立模型的输出,并将它们相加求平均值,以得到最终的输出。根据Jensen的不等式,应用集成方法的平均表现应该不会比随机选择一个模型差。

最后,第55和56行显示了集合预测的分类报告。为了确定我们的MiniVGGNet模型集合是否提高了分类精度,执行以下命令:

查看输出分类报告,我们可以看到,通过简单地组合多个网络的输出,我们的准确性从83%提高到84%,即使这些网络是在使用完全相同的超参数的相同数据集上训练的。一般来说,在应用卷积神经网络集成时,根据你的数据集,你可以期望提高1-5%的准确度。

6.2 总结

在本章中,我们回顾了集成机器学习技术,以及如何训练多个独立模型,然后将结果平均在一起,可以提高分类准确度。

通过回顾Jensen不等式可以发现集成方法的理论依据,该不等式指出,平均而言,我们最好将多个模型的结果平均起来,而不是随机选择一个。

事实上,你看到的由最先进的论文(包括Inception [17], ResNet[24],等等)报告的最顶级的结果是多个模型的平均值(通常是3-5,取决于作者在他们的出版期限之前训练他们的网络的时间)。根据您的数据集,您通常可以预期1-5%的准确性提高。

虽然集合可能是一种提高分类精度的简单方法,但它们也是一种计算昂贵的方法——我们现在负责训练N个集合,而不是训练一个单独的网络。训练CNN已经是一项耗时的操作,所以线性缩放的方法在某些情况下可能不实用。

为了减轻训练多个模型的计算负担,Huang et al.[25]在他们2017年的论文《Snapshot ensemble: train 1, get M》中提出了使用循环学习速率计划在单个训练过程中训练多个模型的想法。

该方法的工作原理是先以较高的学习率开始训练,然后快速降低学习率,节省模型权值,然后在不重新初始化网络权值的情况下将学习率重新设置为初始值。这一行动使网络理论上能够在训练过程中多次将覆盖范围扩展到局部最小区域(或至少是低损耗区域)。快照集合超出了本书的范围,但如果您需要提高分类精度,但无法训练多个模型,则值得研究。

7.先进的优化方法

到目前为止,在这本书中,我们只学习并使用了随机梯度下降(SGD)来优化我们的网络——但在深度学习中还有其他的优化方法。具体来说,这些更高级的优化技术寻求的是:

  1. 减少时间(即epoch的数量)以获得合理的分类精度;
  2. 使网络在更大范围的超参数下表现得更“良好”,而不是学习速率;
  3. 理想情况下,获得比SGD更高的分类精度;

随着深度学习的最新体现,出现了一种新的优化技术,每种技术都试图改进SGD,并提供自适应学习速率的概念。正如我们所知道的,SGD根据给定的学习速率等比例修改网络中的所有参数。然而,考虑到网络的学习速率是(1)最重要的hyperparameter努力调整和(2)一个,乏味hyperparameter设置正确,深度学习研究人员假设,可以自适应地调整学习速率(每参数)在某些情况下,随着网络训练。

在本章中,我们将回顾自适应学习率方法。我还将提供建议,说明您应该在自己的项目中使用哪些优化算法。

7.1 自适应学习率方法

为了理解本节中的每一种优化算法,我们将从伪代码的角度来研究它们——特别是更新步骤。本章的大部分内容都受到了Karpathy[26]和Ruder[27]对优化方法的出色概述的启发。我们将扩展(在某些情况下,简化)他们对这些方法的解释,以使内容更易于理解。

首先,让我们看看一个我们已经很熟悉的算法——vanilla SGD的更新阶段:

  1. W:权重矩阵;
  2. Lr:学习率;
  3. dW:W的梯度;

在这里,我们的学习速率是固定的,只要它足够小,我们就知道在训练过程中我们的损失会减少。我们还在第七章看到了SGD的扩展,其中包含了动量和Nesterov加速。有了这些符号,让我们来探索一下在深度学习职业生涯中会遇到的常见的自适应学习速率优化器。

7.1.1 Adagrad

我们要探索的第一个自适应学习率方法是Adagrad,它首先由Duchi等人[28]引入。Adagrad根据网络参数调整学习速率。较大的更新是对不经常变化的参数执行的,而较小的更新是对频繁变化的参数执行的。

下面我们可以看到Adagrad更新的伪代码:

这里你会注意到的第一个参数是缓存——这个变量维护每个参数梯度的平方和,并在训练过程中的每个小批量更新。通过检查缓存,我们可以看到哪些参数频繁更新,哪些参数不频繁更新。

然后,我们可以将lr * dx除以缓存的平方根(添加一个epsilon值来平滑和防止除以零误差)。将更新按之前所有的平方梯度和缩放,这样我们就可以自适应地更新网络中的参数。

在缓存中频繁更新/大梯度的权重将缩放更新的大小,有效地降低参数的学习率。另一方面,在缓存中具有不频繁更新/较小梯度的权值将扩大更新的大小,从而有效地提高特定参数的学习率。

Adagrad的主要好处是,我们不再需要手动调整学习速率——大多数Adagrad算法的实现将初始学习速率保持在0.01,并允许算法的自适应特性以每个参数为基础来调整学习速率。

然而,通过检查缓存可以看出Adagrad的弱点。在每个小批处理中,梯度的平方在分母中累积。由于梯度是平方的(因此总是正的),这种积累在训练过程中不断增长。正如我们所知道的,用一个小的数(梯度)除以一个非常大的数(缓存)将导致一个无穷小的更新,小到网络在以后的时代里无法学习到任何东西。

即使是很小的、不经常更新的参数也会出现这种现象,因为缓存中的正值单调增长,这就是为什么我们很少看到Adagrad用于训练(现代)深度学习神经网络。不过,有必要回顾一下,这样我们才能理解Adagrad算法的扩展。

7.1.2 Adadelta

Adadelta算法是由Zeiler在2012年的论文《Adadelta: An Adaptive Learning Rate Method[29]》中提出的。Adadelta可以被看作是Adagrad的扩展,旨在减少由缓存导致的单调下降的学习速率。

在Adagrad算法中,我们用之前所有的平方梯度更新缓存。然而,Adadelta通过只积累少量的过去梯度来限制这个缓存更新——当实际实现时,这个操作相当于计算所有过去梯度平方的递减平均值。

因此,Adadelta可以被视为Adagrad的改进;然而,与之密切相关的RMSprop算法(它也执行缓存衰减)通常比Adadelta更受欢迎。

7.1.3 RMSprop

RMSprop算法独立于Adadelta开发,是一种(未发表的)优化算法,在Geoffrey Hinton的Coursera课程[2]的幻灯片中显示。与Adadelta类似,RMSprop试图通过将缓存转换为指数加权移动平均来纠正全局累积缓存的负面影响。

让我们看看RMSprop伪代码更新:

你会注意到RMSprop的第一个方面是,对权重矩阵W的实际更新与Adagrad的更新是相同的——这里重要的是如何更新缓存。decay_rate,通常定义为ρ,是一个超参数,通常设置为0.9。这里我们可以看到,缓存中的前一个条目的权重将大大小于新的更新。RMSprop的“移动平均”方面允许缓存“泄漏”旧的平方梯度,并用更新的、“更新鲜的”梯度替换它们。

同样,对W的实际更新与Adagrad的更新是一致的,算法的关键在于对缓存进行指数衰减,避免了训练过程中学习速率单调下降的情况。在实践中,当应用于训练各种深度学习网络[5]时,RMSprop往往比Adagrad和Adadelta更有效。而且,RMSprop的收敛速度明显快于SGD。

除了SGD, RMSprop可以说是近期深度学习文献中第二常用的优化算法;然而,我们将要讨论的下一个优化方法,Adam,现在使用的比RMSprop更多。

7.1.4 Adam

由Kingma和Ba在2014年的论文《Adam: A Method for Stochastic optimization[1]》中提出的Adam (Adaptive矩估计)优化算法本质上是只添加了动量的RMSprop:

再次,我想特别注意这些伪代码更新,因为它们是由Karpathy的优秀优化方法[26]派生和推广的。

m和v的值与SGD动量相似,依赖于它们各自从t−1开始的前一个值。m表示梯度的第一个矩(均值),v表示第二个矩(方差)。

实际更新W RMSprop几乎是相同的,只是现在我们使用的是“平滑”版本(由于计算均值)m的而不是原始梯度dW -使用意思往往会导致更多的更新中我们可以消除嘈杂的更新原始dW的价值观。通常beta1设置为0.9,而beta2设置为0.999——当使用Adam优化器时,这些值很少(如果有的话)更改。

实际上,Adam在很多情况下都比RMSprop工作得更好。更多关于Adam优化算法的详细信息,请参见Kingma和Ba[1]。

7.1.5 Nadam

就像Adam是带有动量的RMSprop,那达慕是带有Nesterov加速的RMSprop。那达慕是由斯坦福大学(Stanford University)博士生蒂莫西·多扎特(Timothy Dozat)提出的。我们通常不会看到那达姆在野外被使用,但重要的是要理解亚当的这种变体确实存在。

7.2 选择一个优化方法

在所有这些优化算法中,你应该选择哪一个呢?不幸的是,答案是非常不确定的- Schaul等人在2014年的工作,为随机优化[31]的单元测试,试图对许多这些优化方法进行基准测试,发现尽管自适应学习率算法表现良好,但没有明确的赢家。

深度学习优化算法(以及如何选择它们)仍然是一个开放的研究领域,而且可能会持续很多年。因此,与其竭尽全力地尝试你所能找到的每一个优化算法,将每个算法扔到你的数据集中,并注意哪些算法最有效,不如掌握两到三个优化算法。通常,深度学习项目的成功取决于优化算法(和相关参数)以及研究人员“驱动”算法的熟练程度。

7.2.1 三个你应该学会的优化方法:SGD,Adam和RMSprop

此时,选择使用哪种算法似乎在很大程度上取决于用户对算法的熟悉程度(为了便于超参数调优)。——古德费罗等人。

考虑到RMSprop和Adam等自适应学习率算法的成功,您可能会倾向于忽略SGD,并将其视为一种过时的工具。毕竟,“更好的”方法是存在的,不是吗?

然而,暗示忽略SGD将是一个巨大的错误。看看最近发布的关于具有挑战性的图像分类数据集的最先进的深度学习出版物,如ImageNet: AlexNet [6], VGGNet [11], SqueezeNet [32], Inception [17], ResNet[33]——所有这些最先进的架构都是使用SGD进行训练的。

但这是为什么呢?我们可以清楚地看到应用自适应学习速率的算法的好处,如RMSprop和Adam——网络可以更快地收敛。然而,收敛速度虽然重要,但并不是最重要的因素-超参数仍然胜出。如果您不能将超参数调优到给定的优化器(和相关模型),那么您的网络将永远无法获得合理的准确性。

虽然SGD的收敛速度肯定比自适应学习速率算法慢,但它也是一种经过更多研究的算法。研究人员更熟悉SGD,并且已经花了数年时间使用它来训练网络。

深度学习架构和优化算法也是如此。使用给定的架构和优化算法进行的实验越多,我们对训练过程的复杂性了解得就越多。考虑到SGD是近60年来训练神经网络的基石,这也就难怪这种算法至今仍在使用——与模型的性能(准确性)相比,收敛速度根本不重要。

简单地说:如果我们可以使用SGD在给定的数据集上获得更高的精度,我们可能会使用SGD,即使它比使用Adam或RMSprop花费1.5倍的训练时间,这只是因为我们更好地理解超参数。目前,最常用的深度学习优化算法有:

  1. SGD
  2. RMSprop
  3. Adam

我建议您首先掌握sgd,并将其应用到您遇到的每一个体系结构和数据集。在某些情况下。它会表现得很好,但在其他方面,它会表现得很差。这里的目标是让您使用特定的优化算法尽可能多地暴露于深度学习问题中,并学习如何调优相关的超参数。记住,深度学习部分是科学,部分是艺术——掌握优化算法绝对是一门需要大量练习的艺术。然后,继续使用RMSprop或Adam。

我个人建议在RMSprop之前学习Adam,因为根据我的经验,Adam在大多数情况下往往比RMSprop表现更好。

7.3 总结

在本章中,我们讨论了可以代替SGD的自适应学习率优化算法。选择一种优化算法来训练深度神经网络在很大程度上取决于你对以下知识的熟悉程度:

  1. 数据集
  2. 模型架构
  3. 优化算法(相关超参数)

与其竭尽全力地进行实验,尝试你能找到的每一种优化算法,不如掌握两到三种技术以及如何调优它们的超参数。成为这些技术的专家将使您能够更轻松地将新的模型体系结构应用到以前从未使用过的数据集。

我个人的建议是,在你的深度学习生涯早期花大量时间掌握如何使用SGD;特别是SGD的发展势头。一旦您习惯将SGD应用于各种架构和数据集,就可以继续使用Adam和RMSprop。

最后,请记住,模型速率收敛的速度是次要于损失和精度的——选择一个优化算法,您可以(自信地)调整超参数,从而得到一个性能合理的网络。

8.应用深度学习的最佳途径

在深度学习的职业生涯中,您会发现,可以说深度学习最困难的方面是检查您的准确性/损失曲线,并做出下一步的决定。如果你的训练误差太大,你该怎么办?如果您的验证错误也很高,会发生什么?当你的验证错误与训练错误相匹配时,你如何调整你的配方?但是你的测试集误差很高?

在本章中,我将讨论应用深度学习技术的最佳方式,从你可以用来调整训练配方的经验法则开始。然后,我将提供一个决策过程,您可以使用它来决定是从头开始训练深度学习模型,还是应用迁移学习。在本章结束时,您将对深度学习专家在培训自己的网络时使用的经验法则有一个较强的理解。

8.1 训练网络的秘诀

以下部分主要是受到Andrew Ng在NIPS 2016上的优秀教程《构建深度学习应用程序的螺母和螺栓[34]》的启发。在这次演讲中,Ng讨论了如何将深度学习方法应用到我们自己的产品、业务和学术研究中。从Ng的演讲中,我们可以得出以下最重要的结论:

Ng和Malisiewicz在这里所说的是,你应该非常小心地确保你的训练数据能够代表你的验证和测试集。是的,获取、注释和标记数据集非常耗时,甚至在某些情况下非常昂贵。是的,深度学习方法确实在某些情况下具有很好的泛化能力。然而,你不能指望任何机器学习模型训练的数据是不具代表性的成功。

例如,假设我们的任务是构建一个深度学习系统,该系统负责在我们开车行驶时,通过安装在汽车上的摄像头识别汽车的品牌和型号(图8.1,左)。

第一步是收集我们的训练数据。为了加快数据收集的过程,我们决定抓取网页上既有汽车的照片和他们的制造和型号的网站-这类网站的好例子包括Autotrader.com, eBay, CarMax等。对于每一个这样的网站,我们都可以构建一个简单的爬行器,它可以在网站上爬行,找到各个产品列表(例如,列出车辆规格的“汽车页面”),然后下载图像和make +模型信息。

这种方法非常简单,除了开发爬行器所需的时间外,积累一个相当大的标记数据集并不需要很长时间。然后,我们将该数据集分成两部分:训练和验证,并继续训练给定的深度学习体系结构达到较高的准确率(> 90%)。

然而,当我们将新训练的模型应用于示例图像时,例如图8.1(左),我们发现结果很糟糕——在现实世界中部署时,我们幸运地获得了5%的准确率。这是为什么呢?

原因是我们选择了简单的方法。我们没有停下来想一想,Autotrader、CarMax和eBay上列出的汽车产品照片(图8.1,右)并不代表我们的深度学习视觉系统将看到的安装在汽车仪表盘上的汽车。虽然我们的深度学习系统可以很好地在产品镜头中识别出汽车的品牌和型号,但它可能无法从正面或后视图识别出汽车的品牌,这在开车时是很常见的。

构建自己的图像数据集没有捷径可走。如果你希望深度学习系统在给定的真实世界环境中获得较高的精度,那么请确保这个深度学习系统是在代表它将部署的位置的图像上训练的,否则你将会对它的性能非常失望。

假设我们已经收集了足够的训练数据,这些数据代表了我们试图解决的分类任务,Andrew Ng提供了一个四个步骤的过程来帮助我们进行训练[34]。

由图8.2可以看出,Ng在训练深度学习模型时提出了四组数据拆分:

  1. 训练;
  2. 训练验证;
  3. 验证;
  4. 测试;

我们之前已经看到了训练、验证和测试的分裂——但是这个新的“训练验证”集是什么呢?Ng建议我们把所有的数据分成60%用于训练,剩下的40%用于测试。然后我们将测试数据分成两部分:一部分用于验证,另一部分用于真正的测试(即,在我们准备好评估网络性能之前,我们永远不会接触到的数据)。然后,我们从我们的训练集中取出一小块,并将其添加到我们的“训练-验证集”中。训练集将帮助我们确定模型的偏差,而训练验证集将帮助确定方差。

如果我们的训练误差太高,如图8.3(左上)所示,那么我们应该考虑通过添加更多的层和神经元来深化我们当前的架构。在调整学习速率的同时,我们也应该考虑更长的训练时间(即更多的epoch)——使用更小的学习速率可以使你在帮助避免过度拟合的同时训练更长的时间。最后,如果在使用我们当前的体系结构和变化的学习速率进行了许多实验之后,证明没有什么用,那么我们可能需要尝试一个完全不同的模型体系结构。

接下来是流程图中的第二项,如果我们的训练验证误差很高(图8.3,右上),那么我们应该检查网络中的正则化参数。我们是否在网络架构中应用了退出层?是否使用数据增强来帮助生成新的训练样本?实际的损失/更新函数本身是什么-是正则化惩罚被包括在内吗?在您自己的深度学习实验的背景下检查这些问题,并开始添加正则化。

在这一点上,您还应该考虑收集更多的训练数据(再次强调,要注意这些训练数据代表了模型将部署在哪里)——在几乎所有情况下,拥有更多的训练数据从来都不是一件坏事。您的模型可能没有足够的训练数据来学习示例图像中的底层模式。最后,在用尽了这些方法之后,您将再次考虑使用不同的网络架构。

继续看图8.3(左下)中的流程图,如果我们的训练验证错误很低,但是我们的验证集错误很高,我们需要更仔细地检查我们的训练数据。我们是否绝对肯定我们的训练图像和我们的验证图像是相似的?

对自己诚实点——你不能指望一个在图像上训练的深度学习模型能表现得很好,因为它不能代表他们在验证或测试中看到的图像。如果您确实认识到这一点,那么就回到数据集收集阶段,花些时间收集更多的数据。没有数据代表你的深度学习模型将部署在哪里,你将无法获得高精度的结果。您还应该再次检查您的正则化参数-您的正则化足够强吗?最后,您可能再次需要考虑一个新的模型体系结构。

最后,我们进入流程图的最后一步——我们的测试误差高吗?在这一点上,我们已经将我们的模型过度适合于训练和验证数据(图8.3右下)。我们需要回去为验证集收集更多的数据,以帮助我们识别过度拟合开始发生的时间。

8.2 转移学习或从头开始训练

下面这一部分的灵感来自于斯坦福大学cs231n班[36]的“迁移学习”课程。我还把我自己的轶事经历加进了你自己的实验中。鉴于迁移学习在第3章(特征提取)和第5章(调优)中取得的成功,您可能想知道什么时候应该应用迁移学习,什么时候应该从头开始训练模型。

为了做出这个决定,你需要考虑两个重要因素:

  1. 数据集的大小。
  2. 您的数据集与预先训练CNN的数据集的相似性(通常是ImageNet)。

基于这些因素,我们可以构建一个图表来帮助我们决定是否需要应用迁移学习或从头开始训练(图8.4)。让我们回顾一下下面四种可能性。

您可以使用该表来决定是从头开始还是转移学习来训练我们的网络。受Greg Chu的启发,Deep Learning Sandbox[37]。

您的数据集很小,并且与原始数据集相似

由于您的数据集很小,您可能没有足够的训练示例从头开始训练CNN(再次提醒您,理想情况下,您应该为每个希望识别的类提供1,000-5,000个示例)。此外,由于缺乏训练数据,尝试微调可能不是一个好主意,因为我们可能会以过度拟合告终。

相反,由于你的图像数据集与预先训练的网络相似,你应该将网络视为一个特征提取器,并在这些特征的基础上训练一个简单的机器学习分类器。您应该从体系结构中更深层的层中提取特性,因为这些特性更丰富,并且更能代表从原始数据集学到的模式。

您的数据集很大,与原始数据集相似

对于一个大的数据集,我们应该有足够的例子来应用微调而不过度拟合。您可能也想从头开始训练自己的模型——这是一个值得进行的实验。然而,由于您的数据集与网络已经训练的原始数据集相似,网络内部的过滤器可能已经具有足够的鉴别性,可以获得一个合理的分类器。因此,在本例中应用微调。

您的数据集很小,并且与原始数据集不同

同样,对于一个小的数据集,我们可能无法通过从头开始的训练获得一个高精度的深度学习模型。相反,我们应该再次应用特征提取并训练一个标准机器学习模型,但由于我们的数据不同于原始数据集,我们应该使用网络中较低层次作为特征提取器。

请记住,我们对网络架构研究得越深入,特定于它所训练的数据集的特征就越丰富和有区别。通过从网络的较低层提取特征,我们仍然可以利用这些过滤器,但不需要由更深层引起的抽象。

您的新数据集是大的和不同于原始数据集

在这种情况下,我们有两个选择。假设我们有足够的训练数据,我们可以从零开始训练我们自己的自定义网络。然而,从像ImageNet这样的数据集上训练的模型中获得的预训练的权值使得初始化非常出色,即使这些数据集是不相关的。因此,我们应该进行两组实验:

  1. 在第一组实验中,尝试调整一个预先训练的网络到您的数据集,并评估性能。
  2. 然后在第二组实验中,从零开始训练一个全新的模型并进行评估。

确切地说,哪种方法执行得最好完全取决于您的数据集和分类问题。然而,我建议首先尝试微调,因为这种方法将允许您建立一个基线,以便在您进行第二套实验和从头开始训练您的网络时进行打击。

​​​​​​​8.3 总结

在本章中,我们探讨了在训练您自己的自定义网络时应用深度学习技术的最佳路径。在收集您的训练数据时,请记住没有捷径可走——花点时间确保用于训练模型的数据能够代表您的网络在实际应用程序中部署时将看到的图像。

有一个古老的计算机科学轶事是这样说的:“垃圾输入,垃圾输出”。如果您的输入数据没有表示您的模型在训练后将看到的数据点的示例,那么您实际上就陷入了这种“垃圾进、垃圾出”的陷阱。这并不是说你的数据是“垃圾”。相反,当你在做实验的时候,提醒你自己这段轶事,并意识到你的深度学习模型不可能在它从未训练过的数据点上表现良好。

我们还回顾了什么时候应该考虑转移学习,什么时候应该从头开始训练自己的网络。对于小数据集,您应该考虑特征提取。对于较大的数据集,首先考虑微调(以建立基线),然后再从头开始训练模型。

上述实验代码详见本人github地址:

GitHub - TheWangYang/Code_For_Deep_Learning_for_Computer_Vision_with_Python: A code repository for Deep Learning for Computer Vision with Python.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wyypersist

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值