Python教程

《Deep Learning for Computer Vision withPython》阅读笔记-StarterBundle(第2 - 3章)

本文主要是介绍《Deep Learning for Computer Vision withPython》阅读笔记-StarterBundle(第2 - 3章),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

//2021.12.16日下午15::12开始学习

2.什么是深度学习?

2.1 神经网络与深度学习简史

在许多应用中,CNN现在被认为是最强大的图像分类器,目前负责推动利用机器学习的计算机视觉子领域的最新发展。要更全面地回顾神经网络和深度学习的历史,请参考Goodfello等人[10]以及Jason Brownlee在机器学习大师[20]上发表的这篇优秀博文。

2.2 分层特征学习

机器学习算法(通常)分为三大阵营——有监督、无监督和半监督学习。我们将在本章中讨论有监督和无监督学习,同时将半监督学习留作将来讨论。

在有监督的情况下,机器学习算法同时给出一组输入和目标输出。然后,该算法尝试学习可用于自动将输入数据点映射到其正确目标输出的模式。监督学习类似于让老师看着你参加考试。考虑到你以前的知识,你会尽力在考试中给正确答案打分;然而,如果你不正确,你的老师会在下次引导你做出更好、更有教育意义的猜测。

在无监督的情况下,机器学习算法试图自动发现有区别的特征,而不需要任何关于输入是什么的提示。在这种情况下,我们的学生尝试将类似的问题和答案分组在一起,即使学生不知道正确答案是什么,老师也不在那里为他们提供真实答案。无监督学习显然比监督学习更具挑战性——通过了解答案(即目标输出),我们可以更容易地定义区分模式,将输入数据映射到正确的目标分类。

在机器学习应用于图像分类的背景下,机器学习算法的目标是获取这些图像集并识别可用于区分各种图像类/对象的模式。

过去,我们使用手工设计的特征来量化图像的内容——我们很少使用原始像素强度作为机器学习模型的输入,这在深度学习中很常见。对于数据集中的每个图像,我们执行特征提取,或获取输入图像,根据某种算法(称为特征提取程序或图像描述符)对其进行量化,并返回旨在量化图像内容的向量(即数字列表)的过程。下面的图2.5描述了通过一系列黑盒颜色、纹理和形状图像描述符对包含处方药的图像进行量化的过程。

我们的手工设计功能试图编码纹理(局部二进制模式[21]、Haralick纹理[22])、形状(Hu矩[23]、Zernike矩[24])和颜色(颜色矩、颜色直方图、颜色相关图[25])。

其他方法,如关键点检测器(FAST[26]、Harris[27]、DoG[28]等等)和局部不变描述符(SIFT[28]、SURF[29]、BRIENT[30]、ORB[31]等)描述图像的显著(即最“有趣”)区域。

其他方法,如方向梯度直方图(HOG)[32]证明,当图像的视点角度与分类器的训练角度相差不大时,可以很好地检测图像中的对象。HOG+线性SVM检测器方法的应用实例如图2.6所示,我们在图像中检测到停车标志的存在。

有一段时间,图像中目标检测的研究是以HOG及其变体为指导的,包括计算成本高昂的方法,如可变形零件模型[34]和样本支持向量机[35]。

要更深入地研究图像描述符、特征提取及其在计算机视觉中的作用,请参阅PyImageSearch专家课程[33]。

在每种情况下,都会手动定义一种算法来量化和编码图像的特定方面(即形状、纹理、颜色等)。给定一个像素的输入图像,我们将对像素应用手工定义的算法,并反过来接收一个量化图像内容的特征向量——图像像素本身除了作为特征提取过程的输入之外,没有其他用途。特征提取产生的特征向量是我们真正感兴趣的,因为它们是机器学习模型的输入。

深度学习,特别是卷积神经网络,采取了不同的方法。这些特征不是手动定义一组规则和算法从图像中提取特征,而是从训练过程中自动学习。

再次,让我们回到机器学习的目标:计算机应该能够从他们试图解决的问题的经验(即示例)中学习。

通过深入学习,我们试图从概念层次上理解问题。每个概念都建立在其他概念之上。网络较低层中的概念对问题的一些基本表示进行编码,而较高层使用这些基本层来形成更抽象的概念。这种分层学习允许我们完全取消手工设计的特征提取过程,并将CNN视为端到端学习器。

给定一幅图像,我们将像素强度值作为输入提供给CNN。一系列隐藏层用于从输入图像中提取特征。这些隐藏层以分层的方式相互构建。首先,在网络的较低层中只检测到类似边缘的区域。这些边区域用于定义角(边相交处)和轮廓(对象轮廓)。结合角点和轮廓可以在下一层中产生抽象的“对象部分”。

同样,请记住,这些过滤器正在学习检测的概念类型是自动学习的——我们在学习过程中没有干预。最后,输出层用于对图像进行分类并获取输出类别标签–输出层直接或间接地受到网络中其他每个节点的影响。

我们可以将此过程视为分层学习:网络中的每一层都使用前一层的输出作为“构建块”,以构建越来越抽象的概念。这些层是自动学习的–我们的网络中没有手工制作的功能工程。图2.7比较了使用手工特征的经典图像分类算法与通过深度学习和卷积神经网络的表示学习。

深度学习和卷积神经网络的一个主要好处是,它允许我们跳过特征提取步骤,而是专注于训练网络学习这些滤波器的过程。然而,正如我们在本书后面会发现的那样,训练网络在给定的图像数据集上获得合理的精度并不总是一件容易的任务。

2.3 “深”有多深?

现在我们需要看看网络类型的问题。根据定义,卷积神经网络(CNN)是一种深度学习算法。但假设我们有一个只有一个卷积层的CNN——这个网络是浅层的,但仍然属于深度学习阵营中被认为是“深度”的一系列算法吗?

我个人的观点是,任何具有两个以上隐藏层的网络都可以被认为是“深层的”。我的推理基于之前对ANN的研究,这些ANN受到以下因素的严重阻碍:

  1. 我们缺乏可用于培训的大型标记数据集
  2. 我们的计算机速度太慢,无法训练大型神经网络
  3. 激活功能不足

由于这些问题,在20世纪80年代和90年代(当然还有更早的时期),我们无法轻松训练具有两个以上隐藏层的网络。事实上,杰夫·辛顿(Geoff Hinton)在2016年的演讲《深度学习》(Deep Learning)[37]中支持这一观点,他在演讲中讨论了为什么深度学习(ANNs)的前代版本在20世纪90年代没有兴起:

  1. 我们标记的数据集太小了数千倍。
  2. 我们的计算机速度太慢了数百万倍。
  3. 我们用一种愚蠢的方式初始化了网络权重。
  4. 我们使用了错误类型的非线性激活函数。

所有这些原因都表明,训练深度大于两个隐藏层的网络是徒劳的,如果不是计算上的,也是不可能的。

在当前的化身中,我们可以看到潮汐已经改变。我们现在有:

  1. 更快的计算机
  2. 高度优化的硬件(即GPU)
  3. 以数百万张图像为顺序的大型标记数据集
  4. 更好地理解权重初始化函数以及哪些功能不起作用
  5. 优越的激活函数和对为什么以前的非线性函数研究停滞不前的理解

从Andrew Ng的2013次谈话、深度学习、自学学习和无监督的特征学习(38),我们现在能够构建更深层次的神经网络,并用更多的数据来训练他们。

随着网络深度的增加,分类精度也随之提高。这种行为与传统的机器学习算法(即逻辑回归、支持向量机、决策树等)不同,在传统的机器学习算法中,即使可用的训练数据增加,我们的性能也会达到一个稳定期。Andrew Ng的2015次谈话启发了一个情节,科学家应该知道关于深度学习的数据,(39)可以在图2.8中看到,提供了这种行为的一个例子。

随着训练数据量的增加,我们的神经网络算法获得了更高的分类精度,而以前的方法在某一点上趋于平稳。由于更高的准确性和更多的数据之间的关系,我们也倾向于将深度学习与大型数据集联系起来。

在使用自己的深度学习应用程序时,我建议使用以下经验法则来确定给定的神经网络是否深度:

  1. 您是否使用了专门的网络架构,如卷积神经网络、递归神经网络或长-短期记忆(LSTM)网络?如果是这样,是的,您正在进行深度学习。
  2. 您的网络深度是否大于2?如果是,您正在进行深入学习。
  3. 您的网络深度是否大于10?如果是这样的话,你正在进行非常深入的学习[40]。

综上所述,尽量不要被围绕深度学习和什么是/不是深度学习的流行语所困扰。从根本上讲,深度学习在过去60年中基于不同的思想流派经历了许多不同的化身——但这些思想流派都集中在受大脑结构和功能启发的人工神经网络周围。无论网络的深度、宽度或专门的网络架构如何,您仍然在使用人工神经网络执行机器学习。

2.4 总结

正如我们发现的那样,深度学习从20世纪40年代就开始了,根据不同的思想流派和特定时期的流行研究趋势,有不同的名称和化身。最核心的是,深度学习属于人工神经网络(ANN)家族,这是一组算法,用于学习受大脑结构和功能启发的模式。

专家们对于究竟是什么使神经网络“深入”还没有达成共识;然而,我们知道:

  1. 深度学习算法以分层的方式学习,因此将多个层次堆叠在彼此之上,以学习越来越多的抽象概念。
  2. 一个网络应该有两层以上被认为是“深层的”(这是我基于几十年神经网络研究的轶事观点)。
  3. 一个超过10层的网络被认为是非常深的(尽管这个数字会随着诸如ResNet这样的体系结构成功地训练了超过100层而改变)。

如果你在阅读本章后感到有点困惑甚至不知所措,不要担心——这里的目的只是提供一个非常高层次的深度学习概述以及“深度”的确切含义。

本章还介绍了一些你可能不熟悉的概念和术语,包括像素、边和角,我们的下一章将讨论这些类型的图像基础,并给你一个立足的具体基础。然后我们将开始学习神经网络的基础知识,让我们在本书后面的部分学习深度学习和卷积神经网络。虽然本章是公认的高水平,但本书的其余章节将是非常实际的,使您能够掌握计算机视觉概念的深入学习。

3.图像基础

在我们开始构建自己的图像分类器之前,我们首先需要了解图像是什么。我们将从图像的建筑块开始–像素。我们将详细讨论像素是什么,如何使用它们来形成图像,以及如何访问表示为NumPy数组的像素(几乎所有Python中的图像处理库都是这样做的,包括OpenCV和scikit图像)。本章最后将讨论图像的纵横比及其在准备用于训练神经网络的图像数据集时的关系。

3.1像素:图像的构建块

像素是图像的原始构建块。每个图像都由一组像素组成。没有比像素更精细的粒度了。

通常,一个像素被认为是出现在我们图像中某个给定位置的光的“颜色”或“强度”。如果我们把一幅图像看作一个网格,那么每个正方形都包含一个像素。例如,查看图3.1。

上图3.1中的图像分辨率为1000×750,这意味着它宽1000像素,高750像素。我们可以将图像概念化为(多维)矩阵。在本例中,我们的矩阵有1000列(宽度)和750行(高度)。总体而言,我们的图像中有1000×750=750000个总像素。

大多数像素以两种方式表示:

  1. 灰度/单通道
  2. 颜色

在灰度图像中,每个像素都是介于0和255之间的标量值,其中0对应于“黑色”,255对应于“白色”。介于0和255之间的V值是不同的灰度,接近0的值较暗,接近255的值较亮。图3.2中的灰度梯度图像显示左侧较暗的像素,右侧逐渐变亮的像素。

彩色像素;但是,通常在RGB颜色空间中表示(其他颜色空间确实存在,但不在本书范围内,与深入学习无关)。

如果您对学习颜色空间(以及计算机视觉和图像处理的基础知识)感兴趣,请参阅实用Python和OpenCV以及PyImageSearch专家课程。

RGB颜色空间中的像素不再是灰度/单通道图像中的标量值,而是由三个值的列表表示:一个值表示红色分量,一个值表示绿色分量,另一个值表示蓝色分量。要在RGB颜色模型中定义颜色,我们只需定义单个像素中包含的红色、绿色和蓝色的数量。

每个红色、绿色和蓝色通道可以在[0255]范围内定义总共256个“阴影”的值,其中0表示无表示,255表示完全表示。假设像素值只需要在[0255]范围内,我们通常使用8位无符号整数来表示强度。

正如我们将看到的,一旦我们构建了第一个神经网络,我们通常会通过执行均值减法或缩放来预处理图像,这将要求我们将图像转换为浮点数数据类型。请记住这一点,因为从磁盘加载图像的库(如OpenCV)所使用的数据类型通常需要在将学习算法直接应用于图像之前进行转换。

给定三个红色、绿色和蓝色值,我们可以将它们组合成一个RGB元组(红色、绿色、蓝色)。此元组表示RGB颜色空间中的给定颜色。RGB颜色空间是加法颜色空间的一个示例:添加的每种颜色越多,像素越亮,越接近白色。我们可以在图3.3(左)中可视化RGB颜色空间。如您所见,添加红色和绿色将导致黄色。加上红色和蓝色可以得到粉红色。和将三个红色、绿色和蓝色加在一起,我们可以创建白色。

为了让这个例子更具体,让我们再考虑“白色”的颜色——我们将完全填满每个红色、绿色和蓝色的水桶,像这样:(255, 255, 255)。然后,为了创建黑色,我们将清空每个桶(0,0,0),因为黑色是没有颜色的。要创建纯红色,我们将完全填充红色桶(并且仅填充红色桶):(255,0,0)。

RGB颜色空间通常也被视为立方体(图3.3,右),因为RGB颜色被定义为三值元组,每个值在[0255]范围内,因此我们可以认为立方体包含256×256×256=16777216种可能的颜色,这取决于每个桶中放置了多少红、绿和蓝。

作为一个例子,让我们考虑一下,我们需要多少“红色”、绿色和蓝色来创建一个单一的颜色(图3.4,顶部)。在这里,我们设置R=252,G=198,B=188以创建类似于白种人皮肤的色调(在构建用于检测图像中皮肤/肉数量的应用程序时可能有用)。正如我们所看到的,红色部分用几乎装满的桶表示。绿色和蓝色的比例几乎相等。以相加的方式组合这些颜色,我们获得了类似于白种人皮肤的色调。

上图:一个将各种红色、绿色和蓝色成分添加在一起以创建“白种肤色”的示例,可能在皮肤检测程序中有用。底部:通过混合不同数量的红色、绿色和蓝色,在“PyImageSearch”徽标中创建特定的蓝色阴影。

让我们尝试另一个例子,这次设置R=22,G=159,B=230以获得PyImageSearch徽标中使用的蓝色阴影(图3.4,底部)。在这里,红色用a表示得很低值22–桶是如此的空,以至于红色的值实际上看起来是“黑色”。绿色的水桶装满了50%多一点,而蓝色的水桶装满了90%多一点,这显然是图像中的主要颜色。

RGB颜色空间的主要缺点包括:

  1. 它的加性使得人类在不使用“颜色选择器”工具的情况下轻松定义颜色的深浅有点不直观。
  2. 它不能模仿人类感知颜色的方式。

尽管存在这些缺点,但几乎所有要处理的图像都将在RGB颜色空间中表示(至少最初是这样)。有关颜色模型和颜色空间的完整回顾,请参阅PyImageSearch专家课程[33]。

3.1.1从通道形成图像

我们现在知道,RGB图像由三个值表示,分别代表红色、绿色和蓝色分量。我们可以将RGB图像概念化为由三个独立的宽度W和高度H矩阵组成,每个RGB分量一个,如图3.5所示。我们可以组合这三个矩阵以获得形状为W×H×D的多维阵列,其中D是通道的深度或数量(对于RGB颜色空间,D=3):

请记住,图像的深度与神经网络的深度非常不同——当我们开始训练我们自己的卷积神经网络时,这一点就会变得很清楚。但是,暂时只需了解您将使用的绝大多数图像是:

  1. 在RGB颜色空间中由三个通道表示,每个通道的范围为[0255]。RGB图像中的给定像素是三个整数的列表:一个值表示红色,第二个值表示绿色,最后一个值表示蓝色。
  2. 以编程方式定义为具有宽度、高度和深度的三维NumPy多维数组。

3.2图像坐标系

如本章前面图3.1所述,图像表示为像素网格。为了使这一点更清楚,将我们的网格想象成一张图表。使用此图纸,原点(0,0)对应于图像的左上角。当我们向下和向右移动时,x和y值都会增加。

图3.6提供了该“图纸”表示的视觉表示。这是我们的一张图表上的字母“I”。我们看到这是一个8×8的网格,总共有64个像素。

需要注意的是,我们是从零开始计数,而不是从一开始计数。Python语言是零索引的,这意味着我们总是从零开始计数。请记住这一点,因为以后您将避免很多混乱(特别是如果您来自MA TLAB环境)。

作为零标引的一个例子,考虑右边的像素4列,并用点(3,4)索引5行,再次记住,我们是从零计数,而不是1。

3.2.1图像作为NumPy阵列

图像处理库(如OpenCV和scikit Image)将RGB图像表示为具有形状(高度、宽度、深度)的多维NumPy阵列。第一次使用图像处理库的读者经常会被这种表示法弄糊涂——当我们通常认为一幅图像是先宽后高时,为什么高度要先于宽度呢?

答案是:用矩阵表示法。

在定义矩阵的维数时,我们总是将其写成行x列。图像中的行数是图像的高度,而列数是图像的宽度。深度仍将保持不变。

因此,虽然可能会有点困惑地看到。表示为(高度、宽度、深度)的NumPy数组的形状,在考虑如何构造和注释矩阵时,此表示实际上具有直观意义。

例如,让我们看看OpenCV库和cv2。imread函数用于从磁盘加载图像并显示其尺寸

这里我们加载一个名为example的图像。如图3.7中的屏幕截图所示,将png从磁盘复制并显示到屏幕上。我的终端输出如下:

此图像的宽度为300像素(列数),高度为248像素(行数),深度为3(通道数)。要从图像中访问单个像素值,我们使用简单的NumPy数组索引:

同样,请注意y值是如何在x值之前传入的–这种语法一开始可能会感到不舒服,但它与我们访问矩阵中的值的方式是一致的:首先指定行号,然后指定列号。从那里,我们得到一个元组,表示图像的红色、绿色和蓝色分量。

3.2.2 RGB和BGR排序

需要注意的是,OpenCV以相反的顺序存储RGB通道。虽然我们通常以红色、绿色和蓝色来思考,但OpenCV实际上以蓝色、绿色和红色的顺序存储像素值。

为什么OpenCV会这样做?答案只是历史原因。OpenCV库的早期开发人员选择BGR颜色格式,因为BGR订购在当时的相机制造商和其他软件开发人员中很流行[41]。

简言之,此次BGR订购是出于历史原因,也是我们现在不得不接受的选择。这是一个小警告,但在使用OpenCV时要记住一个重要的警告。

3.3缩放比例和纵横比

缩放,或简单地调整大小,是根据宽度和高度增加或减少图像大小的过程。调整图像大小时,重要的是要记住纵横比,是图像的宽度与高度之比。忽略纵横比可能会导致图像看起来被压缩和扭曲,如图3.8所示。

在左边,我们看到了原始图像。在顶部和底部,我们有两个图像由于没有保留纵横比而被扭曲。最终的结果是这些图像被扭曲、挤压和挤压。为了防止这种行为,我们只需在调整图像大小时将图像的宽度和高度等额缩放即可。

从严格的美学角度来看,在调整图像大小时,您几乎总是希望确保图像的纵横比保持不变,但对于深入学习来说,本指南并不总是适用的。大多数用于图像分类任务的神经网络和卷积神经网络都假定输入的大小固定,这意味着通过网络的所有图像的尺寸必须相同。输入到卷积神经网络的宽度和高度图像大小的常见选择包括32×32、64×64、224×224、227×227、256×256和299×299。

假设我们正在设计一个需要对224×224幅图像进行分类的网络;然而,我们的数据集由312×234、800×600和770×300的图像以及其他图像大小组成——我们应该如何预处理这些图像?我们是否只是忽略纵横比而处理失真(图3.9,左下角)?或者我们是否设计了另一种方案来调整图像大小,例如沿图像的最短尺寸调整图像大小,然后进行中心裁剪(图3.9,右下角)?

正如我们在左下角看到的,我们的图像的纵横比被忽略了,导致图像看起来扭曲和“扭曲”。然后,在右下角,我们看到图像的纵横比保持不变,但代价是裁剪出图像的一部分。如果我们意外地裁剪了希望识别的部分或全部对象,这可能对我们的图像分类系统尤其有害。

哪种方法最好?简言之,这要视情况而定。对于某些数据集,您可以简单地忽略纵横比,在通过网络传送图像之前挤压、扭曲和压缩图像。在其他数据集上,通过沿最短维度调整大小,然后裁剪中心,进一步预处理它们是有利的。

我们将在本书后面更详细地回顾这两种方法(以及如何实现它们),但在学习图像的基础知识时,现在介绍这个主题以及他们是如何被代表的很重要。

3.4摘要

本章回顾了图像的基本构造块–像素。我们了解到,灰度/单通道图像由单个标量表示,即像素的强度/亮度。最常见的颜色空间是RGB颜色空间,其中图像中的每个像素由一个三元组表示:红色、绿色和蓝色分量各一元组。

我们还了解到,Python编程语言中的计算机视觉和图像处理库利用了强大的NumPy数字处理库,从而将图像表示为多维NumPy数组。这些阵列具有形状(高度、宽度、深度)。

首先指定高度,因为高度是矩阵中的行数。接下来是宽度,因为它是矩阵中的列数。最后,深度控制图像中通道的数量。在RGB颜色空间中,深度固定为深度=3。

最后,我们通过回顾图像的纵横比来结束本章,以及当我们调整图像大小作为神经网络和卷积神经网络的输入时,它将发挥的作用。有关颜色空间、图像坐标系、大小/纵横比以及OpenCV库的其他基础知识的更详细的回顾,请参考实用Python和OpenCV[8]以及PyImageSearch专家课程[33]。

上述仅为个人阅读笔记,作为日后复习使用,并无他用。

详细代码见本人github仓库:

TheWangYang/Code_For_Deep_Learning_for_Computer_Vision_with_Python: A code repository for Deep Learning for Computer Vision with Python. (github.com)

这篇关于《Deep Learning for Computer Vision withPython》阅读笔记-StarterBundle(第2 - 3章)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!