图像分类_图像分类模型 - CSDN
图像分类 订阅
图像分类,根据各自在图像信息中所反映的不同特征,把不同类别的目标区分开来的图像处理方法。它利用计算机对图像进行定量分析,把图像或图像中的每个像元或区域划归为若干个类别中的某一种,以代替人的视觉判读。 展开全文
图像分类,根据各自在图像信息中所反映的不同特征,把不同类别的目标区分开来的图像处理方法。它利用计算机对图像进行定量分析,把图像或图像中的每个像元或区域划归为若干个类别中的某一种,以代替人的视觉判读。
信息
外文名
image classification
处理对象
图像
中文名
图像分类
工    具
计算机
图像分类分类方法
基于色彩特征的索引技术色彩是物体表面的一种视觉特性,每种物体都有其特有的色彩特征,譬如人们说到绿色往往是和树木或草原相关,谈到蓝色往往是和大海或蓝天相关,同一类物体往拍几有着相似的色彩特征,因此我们可以根据色彩特征来区分物体.用色彩特特征进行图像分类一可以追溯到Swain和Ballard提出的色彩直方图的方法.由于色彩直方图具有简单且随图像的大小、旋转变化不敏感等特点,得到了研究人员的厂泛关注,目前几乎所有基于内容分类的图像数据库系统都把色彩分类方法作为分类的一个重要手段,并提出了许多改进方法,归纳起主要可以分为两类:全局色彩特征索引和局部色彩特征索引。基于纹理的图像分类技术纹理特征也是图像的重要特征之一,其本质是刻画象素的邻域灰度空间分布规律由于它在模式识别和计算机视觉等领域已经取得了丰富的研究成果,因此可以借用到图像分类中。在70年代早期,Haralick等人提出纹理特征的灰度共生矩阵表示法(eo一oeeurrenee matrix representation),这个方法提取的是纹理的灰度级空间相关性(gray level Spatial dependenee),它首先基于象素之间的距离和方向建立灰度共生矩阵,再由这个矩阵提取有意义的统计量作为纹理特征向量。基于一项人眼对纹理的视觉感知的心理研究,Tamuar等人提出可以模拟纹理视觉模型的6个纹理属性,分别是粒度,对比度,方向性,线型,均匀性和粗糙度。QBIC系统和MARS系统就采用的是这种纹理表示方法。在90年代初期,当小波变换的理论结构建一认起来之后,许多研究者开始研究如何用小波变换表示纹理特征。smiht和chang利用从小波子带中提取的统计量(平均值和方差)作为纹理特征。这个算法在112幅Brodatz纹理图像中达到了90%的准确率。为了利用中间带的特征,Chang和Kuo开发出一种树型结构的小波变化来进一步提高分类的准确性。还有一些研究者将小波变换和其他的变换结合起来以得到更好的性能,如Thygaarajna等人结合小波变换和共生矩阵,以兼顾基于统计的和基于变换的纹理分析算法的优点。基于形状的图像分类技术形状是图像的重要可视化内容之一在二维图像空间中,形状通常被认为是一条封闭的轮廓曲线所包围的区域,所以对形状的描述涉及到对轮廓边界的描述以及对这个边界所包围区域的描述.目前的基于形状分类方法大多围绕着从形状的轮廓特征和形状的区域特征建立图像索引。关于对形状轮廓特征的描述主要有:直线段描述、样条拟合曲线、傅立叶描述子以及高斯参数曲线等等。实际上更常用的办法是采用区域特征和边界特征相结合来进行形状的相似分类.如Eakins等人提出了一组重画规则并对形状轮廓用线段和圆弧进行简化表达,然后定义形状的邻接族和形族两种分族函数对形状进行分类.邻接分族主要采用了形状的边界信息,而形状形族主要采用了形状区域信息.在形状进行匹配时,除了每个族中形状差异外,还比较每个族中质心和周长的差异,以及整个形状的位置特征矢量的差异,查询判别距离是这些差异的加权和。基于空间关系的图像分类技术在图像信息系统中,依据图像中对象及对象间的空间位置关系来区别图像库中的不同图像是一个非常重要的方法。因此,如何存贮图像对象及其中对象位置关系以方便图像的分类,是图像数据库系统设计的一个重要问题。而且利用图像中对象间的空间关系来区别图像,符合人们识别图像的习惯,所以许多研究人员从图像中对象空间位置关系出发,着手对基于对象空间位置关系的分类方法进行了研究。早在1976年,Tanimoto提出了用像元方法来表示图像中的实体,并提出了用像元来作为图像对象索引。随后被美国匹兹堡大学chang采纳并提出用二维符号串(2D一String)的表示方法来进行图像空间关系的分类,由于该方法简单,并且对于部分图像来说可以从ZD一String重构它们的符号图,因此被许多人采用和改进,该方法的缺点是仅用对象的质心表示空间位置;其次是对于一些图像来说我们不能根据其ZD一string完个重构其符号图;再则是上述的空间关系太简单,实际中的空间关系要复杂得多。,针对这些问题许多人提出了改进力一法。Jungert根据图像对象的最小包围盒分别在:x轴方向和y轴上的投影区间之间的交叠关系来表示对象之间的空间关系,随后Cllallg和Jungert等人又提出了广义ZD一string(ZDG一String)的方法,将图像对象进一步切分为更小的子对象来表示对象的空间关系,但是该方法不足之处是当图像对象数日比较多且空间关系比较复杂时,需要切分的子对象的数目很多,存储的开销太大,针对此Lee和Hsu等人提出了ZDC一string的方一法,它们采用Anell提出的13种时态间隔关系并应用到空间投影区问上来表达空间关系。在x轴方向和y轴方向的组合关系共有169种,他提出了5种基本关系转换法则,在此基础上又提出了新的对象切分方法。采用ZDC一string的方法比ZDG一string切分子对象的数目明显减少。为了在空间关系中保留两个对象的相对空间距离和对象的大小,Huang等人提出了ZDC书string的方法提高符号图的重构精度,并使得对包含对象相对大小、距离的符号图的推理成为可能。上述方法都涉及到将图像对象进行划分为子对象,且在用符号串重构对象时处理时间的开销都比较大,为解决这些方法的不足,Lee等人又提出了ZDB一String的方法,它不要求对象进一步划分,用对象的名称来表示对象的起点和终点边界。为了解决符号图的重构问题,Chin一ChenCllang等人提出了面向相对坐标解决符号图的重构问题,Chin一ChenChang等人提出了面向相对坐标符号串表示(RCOS串),它们用对象最小外接包围盒的左下角坐标和右上角坐标来表示对象之间的空间关系.对于对象之间的空间关系采用Allen提出的13种区间表示方法。实际上上述所有方法都不是和对象的方位无关,为此Huang等人又提出了RSString表示方法。虽然上述各种方法在对图像对象空间信息的分类起到过一定作用,由于它们都是采用对象的最小外接矩形来表示一个对象空间位置,这对于矩形对象来说是比较合适的,但是当两个对象是不规则形状,且它们在空间关系上是分离时,它们的外接矩形却存在着某种包含和交叠,结果出现对这些对象空间关系的错误表示。用上述空间关系进行图像分类都是定性的分类方一法,将图像的空间关系转换为图像相似性的定量度量是一个较为困难的事情。Nabil综合ZD一String方法和二维平面中对象之间的点集拓扑关系。提出了ZD一PIR分类方法,两个对象之间的相似与否就转换为两个图像的ZD一PIR图之间是否同构。ZD一PIR中只有图像对象之间的空间拓扑关系具有旋转不变性,在进行图像分类的时候没有考虑对象之间的相对距离。
收起全文
精华内容
参与话题
  • 选自Medium机器之心编译参与:蒋思源、黄小天、吴攀图像分类是人工智能领域的基本研究主题之一,研究者也已经开发了大量用于图像分类的算法。近日,Shiyu Mou 在 Medium 上发表了一篇文章,对五种用于图像分类的...
    

    选自Medium

    机器之心编译

    参与:蒋思源、黄小天、吴攀


    图像分类是人工智能领域的基本研究主题之一,研究者也已经开发了大量用于图像分类的算法。近日,Shiyu Mou 在 Medium 上发表了一篇文章,对五种用于图像分类的方法(KNN、SVM、BP 神经网络、CNN 和迁移学习)进行了实验比较,该研究的相关数据集和代码也已经被发布在了 GitHub 上。


    项目地址:https://github.com/Fdevmsy/Image_Classification_with_5_methods


    图像分类,顾名思义,就是为输入图像打上固定类别的标签。这是计算机视觉领域的核心问题之一。尽管听起来很简单,但图像分类有大量不同的实际应用。


    传统方式:特征描述和检测



    也许对一些样本任务有好处,但实际情况要复杂得多。



    因此,我们并没有通过代码的形式直接指出每一类型的外观(visual appearance),而是使用机器学习——为计算机提供每一类的诸多实例,接着开发学习算法观察这些实例,并学习每一类的外观。


    然而,图像分类如此复杂,以至于其处理经常用到深度学习模型,比如 CNN(卷积神经网络)。我们已经知道,我们在课堂上学习的不少算法(如 KNN、SVM)通常很擅长数据挖掘;但是对于图像分类,它们却不是最佳选择。


    因此,我们将对课堂中学到的以及 CNN 和迁移学习等算法做一个对比。


    目标


    我们的目标是:


    1. 把 KNN、SVM、BP 神经网络与业界处理图像识别问题的算法——CNN 和迁移学习——进行对比。

    2. 获得深度学习经验。

    3. 通过 TensorFlow 探索机器学习框架。


    系统设计 & 实现细节


    算法与工具


    本项目使用的 5 个方法是 KNN、SVM、BP 神经网络、CNN 和迁移学习。


    全项目可分为 3 类方法:


    • 第一类方法:使用 KNN、SVM、BP 神经网络这些课堂算法。这些算法强大易实现。我们主要使用 sklearn 实现这些算法。

    • 第二类方法:尽管传统的多层感知器模型已成功应用于图像识别,但由于其节点之间的全连接性,它们遭遇了维度的难题,从而不能很好地扩展到更高分辨率的图像。因此我们使用深度学习框架 TensorFlow 打造了一个 CNN。

    • 第三个方法:重新训练一个被称作 Inception V3 的预训练深度神经网络的最后一层,同样由 TensorFlow 提供。Inception V3 是为 ImageNet 大型视觉识别挑战赛训练的,使用了 2012 年的数据。这是计算机视觉的常规任务,其中模型试图把全部图像分为 1000 个类别,比如斑马、达尔阿提亚人和洗碗机。为了再训练这一预训练网络,我们要保证自己的数据集没有被预训练。


    实现


    第一类方法:预处理数据集,并使用 sklearn 实现 KNN、SVM、BP 神经网络。


    首先,我们使用 OpenCV 包定义了 2 个不同的预处理函数:第一个是图像到特征向量,它可以重调图像大小,并把图像转化为行像素列表;第二个是提取颜色直方图,即使用 cv2.normalize 从 HSV 颜色空间提取 3D 颜色直方图,并平化(flatten)结果。


    接着,建构若干个我们需要解析的参数。由于想要同时测试整个数据集和带不同数量标签的子数据集的精确度,我们构建了一个作为参数的数据集并解析进我们的程序。我们同样构建了用于 k-NN 方法的邻元素数作为解析参数。


    之后,我们开始提取数据集中的每一图像特征,并将其放入数组。我们使用 cv2.imread 读取每一图像,通过从图像名称中提取字符串来拆分标签。在我们的数据集中,我们使用相同格式——类别标签. 图像序号.jpg——设置名称,因此我们可以轻易提取每张图像的分类标签。接着我们使用这两个函数提取 2 种特征并附加到数组 rawImages,而之前提取的标签附加到数组标签。


    下一步是使用从 sklearn 包导入的函数 train_test_split 拆分数据集。这个集具有后缀 RI,RL 是 rawImages 和标签对的拆分结果,另一个是特征和标签对的拆分结果。我们使用 85% 的数据集作为训练集,余下的 15% 作为测试集。


    最后,我们应用 KNN、SVM、BP 神经网络函数评估数据。对于 KNN 我们使用 KNeighborsClassifier,对于 SVM 我们使用 SVC,对于 BP 神经网络我们使用 MLPClassifier。


    第二类方法:使用 TensorFlow 构建 CNN。TensorFlow 的全部目的在于使你打造一张计算图(使用 Python 等语言),接着在 C++ 中执行该图(在相同计算量的情况下,C++比 Python 更高效)。


    TensorFlow 也可自动计算优化图变量所需的梯度,从而使模型表现更好。这是由于该图由简单的数学表达式组合而成,因此可通过导数链式法则计算全图的梯度。


    一张 TensorFlow 图包含以下几个部分,每一部分将在下文详述:


    • 占位符变量,用于输入数据到图。

    • 优化向量以使卷积网络表现更好。

    • 卷积网络的数学公式。

    • 可用于指导变量优化的成本衡量标准。

    • 更新变量的优化方法。

    • CNN 架构由一堆不同的层组成,这些层通过可微分函数可把输入量转化为输出量。


    因此,在我们的实现中,第一层是保存图像,接着我们使用 2 x 2 最大池化和修正线性单元(ReLU)的构建 3 个卷积层。输入是 4 维张量:


    • 图像序号。

    • 每一图像的 Y 轴。

    • 每一图像的 X 轴。

    • 每一图像的通道(channel)。


    输出是另一个 4 维张量:


    • 图像序号,与输入相同。

    • 每一图像的 Y 轴。如果使用 2x2 池化,接着输入图像的高和宽除以 2。

    • 每一图像的 X 轴。同上。

    • 由卷积滤波器生成的通道。


    接着,我们我们在网络末端构建了 2 个全连接层。输入是一个 2 维的形状张量 [num_images、num_inputs]。输出也是一个 2 维的形状张量 [num_images、num_outputs]


    然而,为了连接卷积层和全连接层,我们需要一个平层(Flatten Layer)以把 4 维向量减少至可输入到全连接层的 2 维。


    CNN 末端通常是一个 softmax 层,它可归一化来自全连接层的输出,因此每一元素被限制在 0 与 1 之间,并且所有元素总和为 1。


    为了优化训练结果,我们需要一个成本衡量标准并在每次迭代中将成本降至最少。这里我们使用的成本函数是交叉熵(tf.nn.oftmax_cross_entropy_with_logits()),并在所有的图像分类中取交叉熵的平均值。优化方法是 tf.train.AdamOptimizer(),它是梯度下降的高级形式。这是一个可被调节的参数学习率。


    第三种方法:再训练 Inception V3。现代目标识别模型有数以百万计的参数,并可能需要花费数周的时间才能完全训练一个模型。迁移学习是一种采用在分类数据集(如 ImageNet)中已训练的模型而快速完成这一工作的方法,因为其只需要重新训练新类别的权重就行。虽然这样的模型并没有完全训练的模型表现好,但对于许多应用来说,这是非常高效的,因为其不需要 GPU 并可以在笔记本上花半个小时就完成训练。


    读者可以点击一下链接进一步了解迁移学习的训练过程:https://www.tensorflow.org/tutorials/image_retraining


    首先我们需要获取预训练模型,并移除旧的顶层神经网络,然后再基于我们的数据集重新训练一个输出层。虽然猫的所有品种并没有在原始 ImageNet 数据集和全训练的模型中体现,但迁移学习的神奇之处就在于其可以利用已训练模型用来识别某些目标的底层特征,因为底层特征可以在很多不更改的情况下应用于很多识别任务。然后我们分析本地的所有图片并计算每张的瓶颈值(bottleneck values)。因为每张图片在训练过程中重复使用了多次,所以计算每个瓶颈值需要花费大量时间,但我们可以加快缓存这些瓶颈值,也就可以省去重复的计算。


    该脚本将运行 4000 次训练步。每一步从训练集中随机选择 10 张图片,并从缓存中搜索其瓶颈值,然后再将它们训练最后一层以得到预测。这些预测会通过对比真实标注值而通过反向传播过程更新最后一层的权重。


    实验


    数据集


    Oxford-IIIT Pet 数据集:http://www.robots.ox.ac.uk/~vgg/data/pets/


    该数据集有 25 种狗和 12 种猫。每一种类别有 200 张相片。我们在该项目中只会使用 10 种猫。



    在该项目中我们用的类别为 [斯芬克斯猫、暹罗猫、布偶猫、波斯猫、缅因猫、英国短毛猫、孟买猫、伯曼猫、孟加拉豹猫、阿比西尼亚猫]。


    因此在数据集中我们总共有 2000 张图片。虽然图片的尺寸是不同的,但我们可以调整为固定的大小如 64x64 或 128x128。


    预处理


    在该项目中,我们主要使用 OpenCV 对图片进行预处理,如读取图片放入阵列或调整为我们需要的大小等。


    提升图像训练结果的一个常用方法就是对训练输入随机进行变形、裁剪或亮度调整处理。由于采用了同一图片所有可能的变体,该方法不仅具有扩展有效训练数据大小的优点,同时还倾向帮助网络使用分类器学习处理所有在现实生活中可能出现的畸变。


    具体请查看:https://github.com/aleju/imgaug.


    评估


    第一个方法:第一部分为预处理数据集和使用 sklearn 应用 KNN、SVM 和 BP 神经网络。


    在程序中有很多参数可以调整:在 image_to_feature_vector 函数中,我们设置的图片尺寸为 128x128,我们之前也尝试过使用其他尺寸(如 8x8、 64x64、256x256)进行训练。我们发现虽然图片的尺寸越大效果越好,但大尺寸的图片同样也增加了执行时间和内存需求。因此我们最后决定使用 128x128 的图片尺寸,因为其并不太大,同时还保证了准确度。


    在 extract_color_histogram 函数中,我们将每个通道的二进制值设置为 32,32,32。在先前的函数中,我们还尝试了 8, 8, 8 和 64, 64, 64。虽然更高的数值能有更优的结果,但同时也要求更长的执行时间,因此我们认为 32,32,32 是比较合适的。


    对于数据集,我们训练了 3 种。第一种是有 400 张图片、2 种标注的子数据集。第二种是有 1000 张图片、5 种标注的子数据集。最后一种是有 1997 张图片、10 种标注的全数据集。我们将不同的数据集解析为程序中的参数。


    在 KNeighborsClassifier 中,我们只改变近邻的数量并储存每一种数据集最优 K 值的分类结果。其他所有参数都设为默认。


    在 MLPClassifier 中,我们设置每一个隐藏层有 50 个神经元。我们确实测试了多个隐藏层,但好像对最后的结果没有明显的变化。最大的迭代次数设置为 1000,并且为了确保模型能够收敛,我们容忍差设置为 1e-4。同时还需要设置 L2 罚项的参数 alpha 为默认值,随机状态为 1,求解器设置为学习速率为 0.1 的「sgd」。


    在 SVC 中,最大迭代次数为 1000,类别权重设置为「balanced」。


    我们程序的运行时间并不会太久,对于我们的三种数据集大概分别花 3 到 5 分钟左右。


    第二种方法:使用 TensorFlow 构建 CNN


    使用整个大数据集会需要很长的时间计算模型的梯度,因此我们在优化器每一次迭代中都只使用小批量的图片更新权重,批量大小一般是 32 或 64。该数据集分为包含 1600 张图片的训练集、包含 400 张图片的验证集和包含 300 张图片的测试集。


    该模型同样有许多参数需要调整。


    首先是学习率。优良的学习率因为其足够小而很容易令模型收敛,同时又足够大令模型的收敛速度不至于太慢。所以我们选择了 1 x 10^-4。


    第二个需要调整的参数是投入到网络的图片尺寸。我们训练了 64x64 和 128x128 两种图片尺寸,结果表明尺寸越大模型精度就越高,但代价是运行时间会更长。


    然后是神经网络层级数和它的形状。然而实际上由于这一方面有太多的参数可以调整,所以很难在所有的参数间找到一个最优值。


    根据网上的很多资源,我们发现对于构建神经网络,参数的选择很大一部分都是根据已有的经验。


    最开始,我们希望构建相当复杂的神经网络,其所采用的参数如下:


    • # Convolutional Layer 1. filter_size1 = 5 num_filters1 = 64

    • # Convolutional Layer 2. filter_size2 = 5 num_filters2 = 64

    • # Convolutional Layer 3. filter_size3 = 5 num_filters3 = 128

    • # Fully-connected layer 1. fc1_size = 256

    • # Fully-connected layer 2. fc1_size = 256


    我们采用 3 个卷积层和 2 个全连接层,它们的结构都比较复杂。


    然而,我们的结果是:过拟合。对于这样的复杂网络,训练精度在迭代一千次后就达到了 100%,但测试精度仅仅只有 30%。最开始,我们十分疑惑为什么模型会过拟合,然后开始随机调整参数,但这时候模型的表现却又变好了。幸好几天后我碰巧读到了 Google 在讨论深度学习的一篇文章:https://medium.com/@blaisea/physiognomys-new-clothes-f2d4b59fdd6a 该文章指出他们所主导的项目是有问题的:「一个技术性的问题是如果少于 2000 个样本,那么其是不足以训练和测试如同 AlexNet 那样的卷积神经网络而不出现过拟合情况。」所以我才意识到我们的数据集实在是太小了,而网络构架又太复杂,这才产生了过拟合现象。


    我们的数据集正好包含 2000 张图片


    因此,我开始减少神经网络的层级数和核函数的大小。我尝试调整了很多参数,以下是我们最后使用的神经网络架构参数:


    • # Convolutional Layer 1. filter_size1 = 5 num_filters1 = 64

    • # Convolutional Layer 2. filter_size2 = 3 num_filters2 = 64

    • # Fully-connected layer 1. fc1_size = 128

    • # Number of neurons in fully-connected layer.

    • # Fully-connected layer 2. fc2_size = 128

    • # Number of neurons in fully-connected layer.

    • # Number of color channels for the images: 1 channel for gray-scale. num_channels = 3


    我们仅仅使用 2 个小型的卷积层和 2 个全连接层。训练结果并不好,在迭代 4000 次后同样出现了过拟合现象,但测试精度还是要比前面的模型高 10%。


    我们仍然在寻找解决的办法,然而一个显然易见的原因是我们的数据集实在是太小了,我们也没有足够的时间做更多的改进。


    作为最后的结果,我们在 5000 次迭代后大概实现了 43% 的精度,该训练花了一个半小时。实际上,我们对这一结果比较沮丧,因此我们准备使用另一标准数据集 CIFAR-10。



    CIFAR-10 数据集由 60000 张 32x32 10 类彩色图片,每一个类别都有 6000 张图片。该数据集包含了 50000 张训练集和 10000 张测试集。


    我们使用了和上面相同的神经网络架构,在 10 小时的训练后,我们在测试集上实现了 78% 的准确度。


    第三种方法:再训练 Inception V3,我们随机选取一些图片进行训练,而另一批图片用于验证。


    该模型同样有许多参数需要调整。


    首先是训练步,默认值是 4000 步。我们也可以根据情况增加或减少以尽快获得一个可接受的结果。


    随后是学习率,该参数控制了在训练期间更新至最后一层的量级。直观地说,如果学习速率小,那么需要更多的时间进行学习,但最终其可能收敛到更优的全局精度。训练批量大小控制了在一个训练步中检查图片的多少,又因为学习率应用于每一个批量,如果能以更大的批量获得相似的全局效果,我们需要减少它。


    因为深度学习任务所需要的运行时间通常很长,所以我们并不希望模型在训练几小时后实际上表现很糟糕。所以我们需要经常获得验证精度的报告。这样我们同样可以避免过拟合。数据集的分割是将 80% 的图片投入到主要的训练中,10% 的图片作为训练期间经常进行的验证集,而剩下 10% 的图片作为最终的测试集以预测分类器在现实世界中的表现。


    结果


    第一类方法:预处理数据集并使用 sklearn 实现 KNN、SVM 和 BP 神经网络。


    结果在下表中。由于 SVM 结果非常差,甚至低于随机猜测,我们不再展示其结果。



    从结果中我们看到:


    • 在 k-NN 中,原始像素和直方图精确度是相对等同的。在 5 个标签的子数据集,直方图精确度比原始像素高一点;但是整体来讲,原始像素的结果更好。

    • 在神经网络 MLP 分类器中,原始像素精确度远低于直方图。对于整个数据集(10 个标签),原始像素精确度甚至低于随机猜测。

    • 所有这 2 个 sklearn 方法并没有良好表现,在整个数据集中(10 标签数据集)识别正确分类的精确度仅约有 24%。这些结果说明,通过 sklearn 分类图像效果欠佳,它们在使用多个类别分类复杂图像时表现并不好。但是相比于随机猜测,它们确实有提升,只是还不够。


    基于以上结果,我们发现为了提升精确度,使用一些深度学习方法很必要。


    第二类方法:使用 TensorFlow 构建 CNN。如上所述,由于过拟合我们不能获取好的结果。



    正常情况下训练需要半个小时,然而由于结果过拟合,我们认为这一运行时间并不重要。通过和第一类方法的比较,我们看到:尽管 CNN 过拟合训练数据,我依然得到了更好的结果。

    展开全文
  • 图像分类的任务就是给定一个图像,正确给出该图像所属的类别。对于超级强大的人类视觉系统来说,判别出一个图像的类别是件很容易的事,但是对于计算机来说,并不能像人眼那样一下获得图像的语义信息。 计算机能看到...

    简介

    图像分类的任务就是给定一个图像,正确给出该图像所属的类别。对于超级强大的人类视觉系统来说,判别出一个图像的类别是件很容易的事,但是对于计算机来说,并不能像人眼那样一下获得图像的语义信息。
    计算机能看到的只是一个个像素的数值,对于一个RGB图像来说,假设图像的尺寸是32*32,那么机器看到的就是一个形状为3*32*32的矩阵,或者更正式地称其为“张量”(“张量”简单来说就是高维的矩阵),那么机器的任务其实也就是寻找一个函数关系,这个函数关系能够将这些像素的数值映射到一个具体的类别(类别可以用某个数值表示)。

    算法

    较为简单的算法

    Nearest Neighbor

    "Nearest Neighbor"是处理图像分类问题一个较为简单、直接、粗暴的方法:首先在系统中“记住”所有已经标注好类别的图像(其实这就是训练集),当遇到一个要判断的还未标注的图像(也就是测试集中的某个图像)时,就去比较这个图像与“记住的”图像的“相似性”,找到那个最相似的已经标注好的图像,用那个图像的类别作为正在分类的图像的类别,这也就是"Nearest Neighbor"名称的含义。

    关于如何判断图像“最相似”,可以有多种方法,比如直接求相同位置像素值的差的总和(也就是两个图像的L1距离),也可以采用两个图像的L2距离,也就是先对相同位置像素值作差并求平方,然后对所有平方值求和,最后总体开方,准确的表述如下:记图像分别为I1I_1I2I_2I1kI^k_1表示图像I1I_1在k位置处的像素值,那么图像I1I_1I2I_2的L1和L2距离可以分别表示为:
    d1(I1,I2)=kI1kI2kd_1(I_1, I_2) = \sum_k|I^k_1 - I^k_2| d2(I1,I2)=k(I1kI2k)2d_2(I_1, I_2) = \sqrt{\sum_k(I^k_1 - I^k_2)^2}

    "Nearest Neighbor"容易实现,但是存在诸多缺点:

    1. 预测/测试的过程太慢,给定一个图像时,需要一个个去比较训练集中的图像,每预测一次的计算量都很大,特别是图片的尺寸较大时
    2. 预测/测试时,仍需要较大的空间去存储训练集
    3. 准确率不高,实验发现,该方法在CIFAR-10上只能取得38.59%左右的正确率(其实也不算太糟糕,因为总共有10个类别,如果完全随机猜的话,正确率只有10%),其实是因为该方法没有足够的理论支撑(只有一定的道理),显然的例子是:对于一个图像,如果将其中的物体向左平移一点获得一个新的图像,则这两个图像应该是相同的类别,但是利用"Nearest Neighbor"判断时,则有可能因为相同位置的像素值不再一样而判断错误(因为L1距离和L2距离都是计算相同位置像素值的接近程度,一平移后相同位置的像素值有可能会发生很大的改变)

    Nearest Neighbor的代码实现

    环境:Python 3.6 + PyTorch 1.0

    import torch
    import torchvision
    
    
    class NearestNeighbor:
        def __init__(self):
            self.x_train = 0
            self.y_train = 0
        
        # 训练阶段:存储训练集
        def train(self, x_train, y_train):
            self.x_train = x_train
            self.y_train = y_train
        
        # 测试阶段:比较待分类的图像与所有训练图像的L1距离,取最小距离的图像的类别
        def test(self, x_test):
            L1_distance = torch.sum(torch.abs(x_test - self.x_train), 1)
            min_index = torch.argmin(L1_distance)
            return self.y_train[min_index]
    
    
    if __name__ == '__main__':
        # 定义要对数据集的原始数据进行的变换,此处的变换是将图像转化为Tensor
        transform = torchvision.transforms.Compose([torchvision.transforms.ToTensor()])
        # 加载数据集
        trainset = torchvision.datasets.CIFAR10(root='./', train=True, download=False, transform=transform)
        trainloader = torch.utils.data.DataLoader(trainset, batch_size=1, shuffle=False)
        testset = torchvision.datasets.CIFAR10(root='./', train=False, download=False, transform=transform)
        testloader = torch.utils.data.DataLoader(testset, batch_size=1, shuffle=False)
        # 构造一个训练集和测试集的迭代器,用于遍历
        train_iterator = iter(trainloader)
        test_iterator = iter(testloader)
    
        # 训练集,x_train是所有图像像素形成的Tensor,y_train是所有图像的label
        # 将每一个形状为3*32*32的图像都展开成了长度为3*32*32的行向量
        x_train = torch.zeros((len(trainset), 3 * 32 * 32))
        y_train = torch.zeros((len(trainset), 1))
        for i, (image, label) in enumerate(train_iterator):
            x_train[i] = image.reshape(-1)
            y_train[i] = label
    
        nn = NearestNeighbor()
        nn.train(x_train, y_train)
        # 正确预测的数目、总数目
        right_num, total_num = 0, 0
        for i, (image, label) in enumerate(test_iterator):
            predict_label = nn.test(image.reshape(1, -1))
            if predict_label.item() == label.item():
                right_num += 1
            total_num += 1
        print('Accuracy is %.2f' % (right_num / total_num * 100) + '%')
    

    K-Nearest Neighbor

    "K-Nearest Neighbor"是很自然想到的一个在"Nearest Neighbor"基础上进行改进的方法,与"Nearest Neighbor"不同的是,"K-Nearest Neighbor"不再将“最接近”的那一个图像的类别作为预测图像的类别,而是选出K个与预测图像“最接近”的图像,看其中哪个类别占的比例最高,就将其作为预测图像的类别,这样可以在某种程度上增加预测模型的稳定性。
    此处的K是一个hyper-parameter(超参数),也就是不能由模型学得,而是需要自己去设定,可以尝试的值如10、5、20等,具体选取哪个值可以通过Cross Validation(交叉验证法)来确定,详见机器学习的模型评估方法
    "K-Nearest Neighbor"的代码实现只需要在与"Nearest Neighbor"的代码上作少量修改即可。

    正确率较高的算法

    Linear Classification

    上面的"Nearest Neighbor"和"K-Nearest Neighbor"方法,都是直接比较图像的相似性,存在测试效率太低的问题,并且不能够提取图像的语义信息,导致错误率很高。
    Linear Classification利用一个“全连接层”(Fully Connected Layer),输入图像的所有像素值,经过全连接层的运算后输出每个类别的“得分”,最终选取得分最高的类别作为图像的类别。

    全连接层

    先看一张图

    如图所示,x1,x2,x3x_1, x_2, x_3都是输入的像素值,真实的图像中,输入可能会有很多个,比如CIFAR-10的数据集,图像尺寸是3*32*32(3是RGB这3个通道),那么输入就有3*32*32个;w11,w12,w23w_{11}, w_{12}, w_{23}等表示权重,y1,y2,y3y_1, y_2, y_3是输出的每个类别的得分,如y1y_1表示猫这个类别的得分
    输出的计算方式是:
    y1=w11x1+w12x2+w13x3y_1 = w_{11}*x_1 + w_{12}*x_2 + w_{13}*x_3y2=w21x1+w22x2+w23x3y_2 = w_{21}*x_1 + w_{22}*x_2 + w_{23}*x_3y3=w31x1+w32x2+w33x3y_3 = w_{31}*x_1 + w_{32}*x_2 + w_{33}*x_3
    将其向量化,令:
    X=[x1  x2  x3]TX = [x_1\ \ x_2\ \ x_3]^TY=[y1  y2  y3]TY = [y_1\ \ y_2\ \ y_3]^TW=[w11w12w13w21w22w23w31w32w33]W = \left[ \begin{matrix} w_{11} & w_{12} & w_{13}\\ w_{21} & w_{22} & w_{23}\\ w_{31} & w_{32} & w_{33} \end{matrix} \right]
    则有:
    Y=WXY = W\cdot X
    在最终实现时,还会给每个类别的得分加一个偏置量(bias),类似于原来是“正比例函数”,总是经过原点,现在加一个偏置,变成了普通的”一次函数“,不再一定经过原点,这样可以让表达式更加一般化,也就是表达能力更强,即:
    y1=w11x1+w12x2+w13x3+b1y_1 = w_{11}*x_1 + w_{12}*x_2 + w_{13}*x_3 + b_1y2=w21x1+w22x2+w23x3+b2y_2 = w_{21}*x_1 + w_{22}*x_2 + w_{23}*x_3 + b_2y3=w31x1+w32x2+w33x3+b3y_3 = w_{31}*x_1 + w_{32}*x_2 + w_{33}*x_3 + b_3
    同样,也可以将其向量化,为了简便起见,可以将偏置结合在输入X中,令:
    X=[x1  x2  x3  1]TX = \left[x_1\ \ x_2\ \ x_3\ \ 1\right]^TY=[y1  y2  y3  1]TY = \left[y_1\ \ y_2\ \ y_3\ \ 1\right]^TW=[w11w12w13b1w21w22w23b2w31w32w33b3]W = \left[ \begin{matrix} w_{11} & w_{12} & w_{13} & b_1\\ w_{21} & w_{22} & w_{23} & b_2\\ w_{31} & w_{32} & w_{33} & b_3 \end{matrix} \right]
    可以发现,Y=WXY = W\cdot X的展开结果与上面的非向量化的形式一致。

    在PyTorch中,全连接层很容易实现,如下

    import torchvision
    import torch
    from torch import nn
    
    
    class LinearClassifier(nn.Module):
        def __init__(self):
            super(LinearClassifier, self).__init__()
            # 定义两个全连接层
            self.fc1 = nn.Linear(3*32*32, 200)
            self.fc2 = nn.Linear(200, 10)
    
        def forward(self, x):
            x = self.fc1(x)
            # sigmoid激活函数
            x = torch.sigmoid(x)
            x = self.fc2(x)
            return x
    
    
    if __name__ == '__main__':
        transform = torchvision.transforms.Compose([torchvision.transforms.ToTensor()])
        trainset = torchvision.datasets.CIFAR10(root='./', train=True, download=False, transform=transform)
        trainloader = torch.utils.data.DataLoader(trainset, batch_size=16, shuffle=False)
        testset = torchvision.datasets.CIFAR10(root='./', train=False, download=False, transform=transform)
        testloader = torch.utils.data.DataLoader(testset, batch_size=64, shuffle=False)
    
    	# 定义一个线性分类的多分类网络
        linear_classifier = LinearClassifier()
        # 由于是多分类问题,所以用交叉熵作为损失函数
        criterion = nn.CrossEntropyLoss()
        # 优化器
        optimizer = torch.optim.Adam(linear_classifier.parameters())
    
        for epoch in range(20):
            print('EPOCH:', epoch, end=' ')
            total_loss = 0
            train_iterator = iter(trainloader)
            for batch in train_iterator:
                batch[0] = batch[0].reshape(batch[0].shape[0], -1)
                scores = linear_classifier(batch[0])
                loss = criterion(scores, batch[1])
                optimizer.zero_grad()
                loss.backward()
                optimizer.step()
                total_loss += loss
            print(total_loss, end=' ')
    
            right_num = 0
            test_loader = iter(testloader)
            for batch in testloader:
                scores = linear_classifier(batch[0])
                predict = torch.argmax(scores, dim=1)
                right_num += torch.sum(predict == batch[1])
            print('Accuracy: %.2f' % (right_num.item() / len(testset) * 100) + '%')
    

    本以为该方法准确率会比较高,但是发现正确率还是在30%-40%左右,可能是因为2个全连接层的模型表达能力不够强,还是不能够获得图像的语义信息。

    Convolutional Neural Network(CNN,卷积神经网络)

    利用CNN可以进一步提高图像分类的正确率,甚至已经可以超过人类,关于CNN的细节以及原理,在后面的文章中会详细写,此处只给出用CNN进行图片分类的代码
    环境:Python 3.6 + PyTorch 1.0

    import torchvision
    import torch
    from torch import nn
    
    
    class LinearClassifier(nn.Module):
        def __init__(self):
            super(LinearClassifier, self).__init__()
            self.conv1 = nn.Conv2d(3, 8, kernel_size=3, stride=1, padding=1).cuda()
            self.pool1 = nn.MaxPool2d(2, 2).cuda()
            self.conv2 = nn.Conv2d(8, 16, kernel_size=3, stride=1, padding=1).cuda()
            self.pool2 = nn.MaxPool2d(2, 2).cuda()
            self.conv3 = nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1).cuda()
            self.pool3 = nn.MaxPool2d(2, 2).cuda()
            self.fc1 = nn.Linear(32*4*4, 100).cuda()
            self.fc2 = nn.Linear(100, 10).cuda()
    
        def forward(self, x):
            x = self.conv1(x)
            x = torch.relu(x)
            x = self.pool1(x)
            x = self.conv2(x)
            x = torch.relu(x)
            x = self.pool2(x)
            x = self.conv3(x)
            x = torch.relu(x)
            x = self.pool3(x)
            x = self.fc1(x.reshape(x.shape[0], -1))
            x = self.fc2(x)
            return x
    
    
    if __name__ == '__main__':
        transform = torchvision.transforms.Compose([torchvision.transforms.ToTensor(), ])
        trainset = torchvision.datasets.CIFAR10(root='./', train=True, download=False, transform=transform)
        trainloader = torch.utils.data.DataLoader(trainset, batch_size=32, shuffle=False)
        testset = torchvision.datasets.CIFAR10(root='./', train=False, download=False, transform=transform)
        testloader = torch.utils.data.DataLoader(testset, batch_size=32, shuffle=False)
    
        linear_classifier = LinearClassifier()
        criterion = nn.CrossEntropyLoss()
        optimizer = torch.optim.SGD(linear_classifier.parameters(), lr=0.01)
    
        for epoch in range(20):
            print('Epoch:', epoch, end='  ')
            total_loss = 0
            train_iterator = iter(trainloader)
            for batch in train_iterator:
                batch[0] = batch[0].cuda()
                batch[0].requires_grad = False
                scores = linear_classifier(batch[0])
                loss = criterion(scores, batch[1].cuda())
                optimizer.zero_grad()
                loss.backward()
                optimizer.step()
                total_loss += loss
            print('Loss =', total_loss.item())
    
            test_iterator = iter(testloader)
            right_num = 0
            for batch in test_iterator:
                scores = linear_classifier(batch[0].cuda())
                predict = torch.argmax(scores, dim=1)
                right_num += torch.sum(predict == batch[1].cuda())
            print('Accuracy: %.2f' % (right_num.item() / len(testset) * 100) + '%')
    

    实验发现,具有3个卷积层的网络,可以将图片分类的精度提升到70%左右,相较于前面的方法已经有了很大的进步,但其实利用深度神经网络还可以表现的更好(所谓的“深度神经网络”其实就是让网络具有更多的卷积层,变得“更深”),一些深度的网络已经可以将图片分类的精度提升到了95%以上。后面的文章会介绍CNN的原理细节。

    展开全文
  • 干货——图像分类(上)

    万次阅读 2018-08-29 16:44:33
    这是译自斯坦福CS231n课程笔记image classification notes,由课程教师Andrej Karpathy授权进行翻译。本篇教程由杜客翻译完成。非常...
        

    这是译自斯坦福CS231n课程笔记image classification notes,由课程教师Andrej Karpathy授权进行翻译。本篇教程由杜客翻译完成。非常感谢那些无偿奉献的大师,在此代表所有爱好学习者向您们致敬,谢谢!


    这是斯坦福大学的课程,希望对即将入门DL的您打下基础,还是给已经处在DL届的您们巩固,都希望您们对基础知识有深入的理解。

    随便分享CS231n的网址,有兴趣的朋友可以进一步去了解:http://cs231n.github.io/

    图像分类

    目标这一节我们将介绍图像分类问题。

    图像分类,顾名思义,是一个输入图像,输出对该图像内容分类的描述的问题。它是计算机视觉的核心,实际应用广泛。图像分类的传统方法是特征描述及检测,这类传统方法可能对于一些简单的图像分类是有效的,但由于实际情况非常复杂,传统的分类方法不堪重负。现在,我们不再试图用代码来描述每一个图像类别,决定转而使用机器学习的方法处理图像分类问题。主要任务是给定一个输入图片,将其指派到一个已知的混合类别中的某一个标签。 

    例子在下图中,一个图像分类模型将一个图片分配给四个类别(cat,dog,hat,mug)标签的概率。

    如图所示,图片被表示成一个大的3维数字矩阵。在下面例子中,图像分类的最终目标就是转换这个数字矩阵到一个单独的标签,例如“Cat”。 图片分类的任务是对于一个给定的图片,预测其的类别标签。 

    ——————————————————

    640?wx_fmt=png

    ——————————————————

    困难和挑战对于人来说,识别猫特别简单,首先我们之前就大量接触这类图像,对其对特的特征有深入的认识,所以人类识别是简单的任务,但是对于,计算机视觉算法,那就那难于上青天。

    我们在下面列举了至今计算机视觉领域遇到的困难,也是现在亟待需解决的问题:

    • 刚体&非刚体的变化:不同类型其变化都不一样;

    • 多视角:收集同一个物体图像,获取的角度是多变的;

    • 尺度:在现实生活中,很多物体的尺度都是千变万化;

    • 遮挡:目标物体可能被挡住。有时候只有物体的一小部分是可见的;

    • 光照条件:在像素层面上,光照的影响非常大;

    • 类内差异:一类物体的个体之间有许多不同的对象,每个都有自己的外形。

    ——————————————————

    640?wx_fmt=jpeg——————————————————

    数据驱动方法如何写一个图像分类的算法呢?怎么写一个从图像中认出猫的算法?

    因此,我们采取的方法和教小孩儿看图识物类似:给模型很多图像数据,让其不断去学习,学习到每个类的特征。这就是数据驱动方法

    既然第一步需要将已经做好分类标注的图片作为训练集,下面就看看训练数据集长什么样?如下图:

    ——————————————————

    640?wx_fmt=jpeg

    一共有4个类别的训练集。在实际中,可能有成千上万类别的物体,每个类别都会有百万的图像。

    ——————————————————

    图像分类流程在课程视频中已经学习过,图像分类就是输入一个元素为像素值的数组,然后给它分配一个分类标签。完整流程如下:

    • 输入:输入是包含N个图像的集合,每个图像的标签是K种分类标签中的一种。这个集合称为训练集。

    • 学习:这一步的任务是使用训练集来学习每个类到底长什么样。一般该步骤叫做训练分类器或者学习一个模型

    • 评价:让分类器来预测它未曾见过的图像的分类标签,并以此来评价分类器的质量。我们会把分类器预测的标签和图像真正的分类标签对比。毫无疑问,分类器预测的分类标签和图像真正的分类标签如果一致,那就是好事,这样的情况越多越好。

    Nearest Neighbor分类器

    作为课程介绍的第一个方法,我们来实现一个Nearest Neighbor分类器。虽然这个分类器和卷积神经网络没有任何关系,实际中也极少使用,但通过实现它,可以让读者对于解决图像分类问题的方法有个基本的认识。

    图像分类数据集:CIFAR-10一个非常流行的图像分类数据集是CIFAR-10。这个数据集包含了60000张32X32的小图像。每张图像都有10种分类标签中的一种。这60000张图像被分为包含50000张图像的训练集和包含10000张图像的测试集。在下图中你可以看见10个类的10张随机图片。

    ——————————————————

    640?wx_fmt=jpeg左边:从CIFAR-10数据库来的样本图像。右边:第一列是测试图像,然后第一列的每个测试图像右边是使用Nearest Neighbor算法,根据像素差异,从训练集中选出的10张最类似的图片。

    ——————————————————

    假设现在我们有CIFAR-10的50000张图片(每种分类5000张)作为训练集,我们希望将余下的10000作为测试集并给他们打上标签。Nearest Neighbor算法将会拿着测试图片和训练集中每一张图片去比较,然后将它认为最相似的那个训练集图片的标签赋给这张测试图片。上面右边的图片就展示了这样的结果。请注意上面10个分类中,只有3个是准确的。比如第8行中,马头被分类为一个红色的跑车,原因在于红色跑车的黑色背景非常强烈,所以这匹马就被错误分类为跑车了。

    那么具体如何比较两张图片呢?在本例中,就是比较32x32x3的像素块。最简单的方法就是逐个像素比较,最后将差异值全部加起来。换句话说,就是将两张图片先转化为两个向量640?wx_fmt=png640?wx_fmt=png,然后计算他们的L1距离:

    640?wx_fmt=png

    这里的求和是针对所有的像素。下面是整个比较流程的图例:

    ——————————————————

    640?wx_fmt=png

    以图片中的一个颜色通道为例来进行说明。两张图片使用L1距离来进行比较。逐个像素求差值,然后将所有差值加起来得到一个数值。如果两张图片一模一样,那么L1距离为0,但是如果两张图片很是不同,那L1值将会非常大。

    ——————————————————

    下面,让我们看看如何用代码来实现这个分类器。首先,我们将CIFAR-10的数据加载到内存中,并分成4个数组:训练数据和标签,测试数据和标签。在下面的代码中,Xtr(大小是50000x32x32x3)存有训练集中所有的图像,Ytr是对应的长度为50000的1维数组,存有图像对应的分类标签(从0到9):

    Xtr, Ytr, Xte, Yte = load_CIFAR10('data/cifar10/') # a magic function we provide# flatten out all images to be one-dimensionalXtr_rows = Xtr.reshape(Xtr.shape[0], 32 * 32 * 3) # Xtr_rows becomes 50000 x 3072Xte_rows = Xte.reshape(Xte.shape[0], 32 * 32 * 3) # Xte_rows becomes 10000 x 3072

    现在我们得到所有的图像数据,并且把他们拉长成为行向量了。接下来展示如何训练并评价一个分类器:

    nn = NearestNeighbor() # create a Nearest Neighbor classifier classnn.train(Xtr_rows, Ytr) # train the classifier on the training images and labelsYte_predict = nn.predict(Xte_rows) # predict labels on the test images# and now print the classification accuracy, which is the average number# of examples that are correctly predicted (i.e. label matches)print 'accuracy: %f' % ( np.mean(Yte_predict == Yte) )

    作为评价标准,我们常常使用准确率,它描述了我们预测正确的得分。请注意以后我们实现的所有分类器都需要有这个API:train(X, y)函数。该函数使用训练集的数据和标签来进行训练。从其内部来看,类应该实现一些关于标签和标签如何被预测的模型。这里还有个predict(X)函数,它的作用是预测输入的新数据的分类标签。现在还没介绍分类器的实现,下面就是使用L1距离的Nearest Neighbor分类器的实现套路:

    import numpy as npclass NearestNeighbor(object):
      def __init__(self):
        pass
    
      def train(self, X, y):
        """ X is N x D where each row is an example. Y is 1-dimension of size N """
        # the nearest neighbor classifier simply remembers all the training data
        self.Xtr = X
        self.ytr = y
    
      def predict(self, X):
        """ X is N x D where each row is an example we wish to predict label for """
        num_test = X.shape[0]
        # lets make sure that the output type matches the input type
        Ypred = np.zeros(num_test, dtype = self.ytr.dtype)
    
        # loop over all test rows
        for i in xrange(num_test):
          # find the nearest training image to the i'th test image
          # using the L1 distance (sum of absolute value differences)
          distances = np.sum(np.abs(self.Xtr - X[i,:]), axis = 1)
          min_index = np.argmin(distances) # get the index with smallest distance
          Ypred[i] = self.ytr[min_index] # predict the label of the nearest example
    
        return Ypred

    如果你用这段代码跑CIFAR-10,你会发现准确率能达到38.6%。这比随机猜测的10%要好,但是比人类识别的水平(据研究推测是94%)和卷积神经网络能达到的95%还是差多了。点击查看基于CIFAR-10数据的Kaggle算法竞赛排行榜

    距离选择计算向量间的距离有很多种方法,另一个常用的方法是L2距离,从几何学的角度,可以理解为它在计算两个向量间的欧式距离。L2距离的公式如下:

    640?wx_fmt=png

    换句话说,我们依旧是在计算像素间的差值,只是先求其平方,然后把这些平方全部加起来,最后对这个和开方。在Numpy中,我们只需要替换上面代码中的1行代码就行:

    distances = np.sqrt(np.sum(np.square(self.Xtr - X[i,:]), axis = 1))

    注意在这里使用了np.sqrt,但是在实际中可能不用。因为求平方根函数是一个单调函数,它对不同距离的绝对值求平方根虽然改变了数值大小,但依然保持了不同距离大小的顺序。所以用不用它,都能够对像素差异的大小进行正确比较。如果你在CIFAR-10上面跑这个模型,正确率是35.4%,比刚才低了一点。

    L1和L2比较。比较这两个度量方式是挺有意思的。在面对两个向量之间的差异时,L2比L1更加不能容忍这些差异。也就是说,相对于1个巨大的差异,L2距离更倾向于接受多个中等程度的差异。L1和L2都是在p-norm常用的特殊形式。

    k-Nearest Neighbor分类器

    你可能注意到了,为什么只用最相似的1张图片的标签来作为测试图像的标签呢?这不是很奇怪吗!是的,使用k-Nearest Neighbor分类器就能做得更好。它的思想很简单:与其只找最相近的那1个图片的标签,我们找最相似的k个图片的标签,然后让他们针对测试图片进行投票,最后把票数最高的标签作为对测试图片的预测。所以当k=1的时候,k-Nearest Neighbor分类器就是Nearest Neighbor分类器。从直观感受上就可以看到,更高的k值可以让分类的效果更平滑,使得分类器对于异常值更有抵抗力。

    ——————————————————

    640?wx_fmt=jpeg

    上面示例展示了Nearest Neighbor分类器和5-Nearest Neighbor分类器的区别。例子使用了2维的点来表示,分成3类(红、蓝和绿)。不同颜色区域代表的是使用L2距离的分类器的决策边界。白色的区域是分类模糊的例子(即图像与两个以上的分类标签绑定)。需要注意的是,在NN分类器中,异常的数据点(比如:在蓝色区域中的绿点)制造出一个不正确预测的孤岛。5-NN分类器将这些不规则都平滑了,使得它针对测试数据的泛化(generalization能力更好(例子中未展示)。注意,5-NN中也存在一些灰色区域,这些区域是因为近邻标签的最高票数相同导致的(比如:2个邻居是红色,2个邻居是蓝色,还有1个是绿色)。

    ——————————————————

    在实际中,大多使用k-NN分类器。但是k值如何确定呢?接下来就讨论这个问题。

    图像分类笔记(上)完。

    展开全文
  • 经典卷积分类网络 一点废话:CNN网络主要特点是使用卷积层,这其实是模拟了人的视觉神经,单个神经元只能对某种特定的图像特征产生响应,比如横向或者纵向的边缘,本身是非常简单的,但是这些简单的神经元构成一层...

    本文原创,转载请引用 https://blog.csdn.net/dan_teng/article/details/87192430

    CNN图像分类网络

    一点废话:CNN网络主要特点是使用卷积层,这其实是模拟了人的视觉神经,单个神经元只能对某种特定的图像特征产生响应,比如横向或者纵向的边缘,本身是非常简单的,但是这些简单的神经元构成一层,在层数足够多后,就可以获取足够丰富的特征。从机制上讲,卷积神经网络与人的视觉神经还真是像。下面进入正题。

    LeNet(1998)

    网络基本架构为:conv1 (6) -> pool1 -> conv2 (16) -> pool2 -> fc3 (120) -> fc4 (84) -> fc5 (10) -> softmax,括号内数字表示channel数。这是个很小的五层网络(特指卷积或者全连接层),图中subsampling下采样是pooling layer, kernel size 是2x2, stride 2,feature map刚好为上层一半大小。该网络用于对支票(还是邮政?)的手写数字分类。网络受制于当时的硬件条件和训练数据大小,并未带来神经网络的爆发。
    LeNet网络结构

    AlexNet(2012)

    AlexNet是2012年ILSVRC(ImageNet Large Scale Visual Recognition Challenge)冠军,以高出10%的正确率力压第二名,这是CNN网络首次获胜,将卷积神经网络的巨大优势带入人们视野。
    ILSVRC 历年top5错误率及神经网络深度(层数):
    ILSVRC top5错误率及网络深度
    AlexNet基本架构为:conv1 (96) -> pool1 -> conv2 (256) -> pool2 -> conv3 (384) -> conv4 (384) -> conv5 (256) -> pool5 -> fc6 (4096) -> fc7 (4096) -> fc8 (1000) -> softmax。AlexNet有着和LeNet相似网络结构,但更深、有更多参数。conv1使用11×11的滤波器、步长为4使空间大小迅速减小(227×227 -> 55×55)。

    AlexNet的特点:

    • 第一次使用ReLU激活函数,有更好的梯度特性、训练更快。
    • 使用了随机失活(dropout),p=0.5,可以防止过拟合
    • 大量使用数据扩充技术
    • 使用SGD,Momentum 0.9
    • learning rate 1e-2 (0.01), reduced by 10 manually when val accuracy plateaus
    • L2 weight decay 5e-4
    • batch size 128
    • 使用Norm layers(不再使用)

    由于当时GPU不够强大,网络有两个分支,放在两个GPU上分别训练,当前已经不存在这个问题了,因此也常见到只有一个分支的网络结构图。另外需说明的是,图上表的输入图片大小是224,其实应该是227,否则网络跑不通。

    双分支网络结构:
    AlexNet原网络单分支网络结构(当下使用这个就行)
    AlexNet单分支网络结构
    ILSVRC 2013冠军是ZFNet,仅在AlexNet上做了一些改进,没有突破性技术,这里不再赘述。

    VGGNet

    ILSVRC 2014冠军是GoogLeNet,亚军是VGG。虽然VGG网络是亚军,但是其应用更加广泛。
    VGG网络作者尝试了多种结构,较常用的有VGG16和VGG19(VGG16网络更简单,性能也可以,应用最广泛)。
    VGG16的基本架构为conv1^2 (64) -> pool1 -> conv2^2 (128) -> pool2 -> conv3^3 (256) -> pool3 -> conv4^3 (512) -> pool4 -> conv5^3 (512) -> pool5 -> fc6 (4096) -> fc7 (4096) -> fc8 (1000) -> softmax。 ^3代表重复3次。
    VGG网络结构
    VGG16内存主要消耗在前两层卷积,而参数最主要在第一层全连接中最多。这里说的内存消耗,主要是指存储各层feature map所用的空间,对第一层而言,输入是图片,占用大小就是图片长×宽×通道数,卷积后输出占用的内存就是输出尺寸乘积;参数量中参数是网络需要学习的部分,也就是卷积和全连接层的权重矩阵大小,因为网络中权重矩阵以kernel形式存在,因此参数量就是kernel的(长x宽x通道数)x个数。
    VGG16内存和参数消耗tricks:由于主要参数消耗在fc6(各层命名见后图)这一层,可以替换为对上一层7x7x512的feature map 在7x7上做average pooling,得到512个数,也是可行的(Andrej Karpathy在2016 CS231n课上讲的),这点在GoogLeNet中有应用。

    VGGNet特点:

    • 结构简单,只有3x3,stride 1,pad 1的卷积和2x2,stride 2的max pooling,每过一次pooling,feature map大小降低一半。
    • 参数量大(参数和内存解析见上图)
    • 合适的网络初始化
    • 使用batch normalization
    • FC7提取的特征对其他任务有帮助。FC7始于AlexNet,表示某一全连接层,该层提取特征用于分类任务。

    VGG16中对各层的命名如下:
    VGG16各层命名
    需注意的是,VGGNet之所以使用更小的kernel,是因为3个3x3的conv和1个7x7的conv具有的感受野是相同的,但是3层3x3带来更深的网络结构,非线性更强,另外参数量更少:3*(3x3xCxC)vs 7x7xCxC (这里C是channel数,同时认为kernel数也是C,等价于输出的channel是C)

    GoogLeNet

    GoogLeNet是ILSVRC2014冠军,取名源自作者所处单位Google,其中L大写是为了向LeNet致敬。该网络如之前所提,使用average pooling代替了最耗参数(相应的也最耗时间)的全连接层,同时使用inception模块来代替简单的卷积层(inception的名字来源于盗梦空间中的we need to go deeper的梗);另外,使用1x1的卷积进行了降维。
    inception module

    ResNet

    ResNet是ILSVRC 2015的冠军。ResNet最大的贡献在于解决了深层网络难以训练的问题(反向传播梯度弥散),它的网络深度达到了152层!ResNet网络结构如下图所示。
    ResNet网络结构

    ResNet网络之所以能够训练下去主要得益于residual block(残差模块)的使用。残差模块是一种短路连接,如下图所示。通常的“plain”结构如左侧所示,而residual网络如右侧所示,加了一条短路路径,使得前面的输入可以直接连接到输出。原本图中几层要学习的是H(x),现在由于多加了输入x的影响,网络层需要拟合的变成了F(x) = H(x) - x
    residual blockResNet的特点:

    • 使用BN(Batch Normalization)layer在每个conv layer后
    • 每个residual block包含两个3x3 conv layer
    • 周期性的使用stride 2 pooling降低维度,相当于除2
    • 最耗时的FC层使用pool代替
    • SGD + Momentum 0.9
    • learning rate 0.1, divided by 10 when validation error plateaus
    • Mini-batch size 256
    • Weight decay 1e-5
    • 不使用dropout

    截至2017年,典型CNN网络的准确度和复杂度:
    网络复杂度

    参考资料:
    斯坦福CS231n 2016/2017 教学视频和课件
    https://zhuanlan.zhihu.com/p/31727402

    展开全文
  • 从机器学习基础算法开始,然后进入到图像分类领域,使用MNIST手写数据集和CIFAR10图像数据集,从简单神经网络到深度神经网络,再到卷积神经网络,最终完成复杂模型:残差网络的搭建。完成这条主线,学员将可以自如地...
  • 图像分类&图像检索

    千次阅读 2019-05-09 15:10:33
    图像检索(指基于内容的图像检索,即以图搜图)则是给定一幅查询图像,搜索与之相似(视觉或语义上)的图像图像检索一般是提取图像特征后直接基于相似性(距离)度量标准计算查询图特征和数据库中图像特征之间的相似...
  • 一共有四种基于内容的图像分类方法,即颜色、纹理、形状和空间关系。 1.基于颜色特征的分类技术 目前,提取颜色特征己经成为几乎所有基于内容图像分类技术的重要手段。由于颜色是物体必备的视觉特性,同一类...
  • 文章发布于公号【数智物语】 ...图像分类是计算机视觉中最基础的任务,基本上深度学习模型的发展史就是图像分类任务提升的发展历史,不过图像分类并不是那么简单,也没有被完全解决。   01 什么是图像分类...
  • 图像分类 (image classification)

    千次阅读 2019-06-27 16:55:34
    图像分类的任务是判断该图像所属类别。 2. 常用数据集 难度递增:MNIST、CIFAR-10、CIFAR-100、Image-Net 3. 分类经典网络结构 LeNet-5、AlexNet、VGG-16 / VGG-19、GoogLeNet、Inception v3 / v4、ResNet、...
  • 常用图像分类网络

    千次阅读 2018-10-30 22:27:15
    想对图像分类网络写个简要的概括,如有介绍不当之处,还望指出。 一、VGG网络 更新于2018年10月20日 参考博客:深度学习经典卷积神经网络之VGGNet 论文地址:VERY DEEP CONVOLUTIONAL NETWORKS FOR LARGE-SCALE ...
  • 基于支持向量机的图像分类(下篇:MATLAB实现)

    万次阅读 多人点赞 2020-04-13 12:31:05
    摘要:本文通过图文详细介绍如何利用支持...点我下载:SVM图像分类的MATLAB完整程序及图片集文件 1. 前言 机器学习是人工智能研究发展到一定阶段的必然产物。二十世纪八十年代是机器学习成为一个独立学...
  • 基于支持向量机的图像分类(上篇)

    万次阅读 多人点赞 2018-03-31 21:28:29
    这篇文章从什么是图像分类任务开始一步步详细介绍支持向量机原理,以及如何用它解决图像多分类任务。将这部分内容分为上下两篇:上篇重点详细介绍实现原理,下篇衔接上篇进行编程实现并对程序进行解释,本篇为上篇。...
  • 图像分类基本流程及 KNN 分类器

    千次阅读 2018-09-07 16:14:06
    1. 图像分类以及基本流程 1.1 什么是图像分类   所谓图像分类问题,就是已有固定的分类标签集合,然后对于输入的图像,从分类标签集合中找出一个分类标签,最后把分类标签分配给该输入图像。虽然看起来挺简单的...
  • 深度学习之图像分类

    千次阅读 2019-05-23 11:49:26
    图像分类,核心是从给定的分类集合中给图像分配一个标签的任务。实际上,这意味着我们的任务是分析一个输入图像并返回一个将图像分类的标签。标签总是来自预定义的可能类别集。 示例:我们假定一个可能的类别集...
  • 本篇文章主要通过Tensorflow+Opencv实现CNN自定义图像分类案例,它能解决我们现实论文或实践中的图像分类问题,并与机器学习的图像分类算法进行对比实验。基础性文章,希望对您有所帮助,如果文章中存在错误或不足之...
  • 图像分类与检测概述

    千次阅读 2018-10-11 14:13:34
    图像分类与检测是现今计算机视觉处理中最为常见的两项任务,本文尽量综述一下传统的图像分类与检测与现今的图像分类与检测技术。以下是要讲的几个方面: 图像分类与检测概述 传统的图像分类与检测方法 现今的图像...
  • 遥感图像分类技术

    千次阅读 2019-06-05 21:06:10
    什么是遥感图像分类技术? 图像分类是将土地覆盖类别分配给像素的过程。例如,这9个全球土地覆盖数据集将图像分为森林、城市、农业和其他类别。 https://gisgeography.com/free-global-land-cover-land-use-data/ ...
  • 高光谱图像分类(三)分类流程

    万次阅读 多人点赞 2017-04-11 19:04:36
    如何利用稀疏表示进行高光谱图像分类呢?前面我们已经了解了高光谱图像分类的一些基本概念,那这篇文章当中将讲解高光谱图像分类具体的流程是怎么样的。以下是高光谱图像分类的具体详细步骤: 1.导入indian_pines高...
  • 细粒度图像分类(FGVC)---综述

    千次阅读 多人点赞 2020-09-08 19:09:50
    什么是细粒度图像分类 细粒度图像分类问题是对大类下的子类进行识别。细粒度图像分析任务相对通用图像(General/Generic Images)任务的区别和难点在于其图像所属类别的粒度更为精细。 以图1为例,通用图像分类其...
  • 基于Libsvm的图像分类

    万次阅读 多人点赞 2018-09-05 13:29:26
    基于Libsvm的图像分类 关于Libsvm的废话 基于Libsvm的图像分类实例 说说图像分类的处理结果 1. 关于Libsvm的废话 先来一段废话,大家有心情看看就行,那就是关于支持向量机的问题,支持向量机是在统计学习理论基础...
1 2 3 4 5 ... 20
收藏数 221,011
精华内容 88,404
关键字:

图像分类