图像分类 订阅
图像分类,根据各自在图像信息中所反映的不同特征,把不同类别的目标区分开来的图像处理方法。它利用计算机对图像进行定量分析,把图像或图像中的每个像元或区域划归为若干个类别中的某一种,以代替人的视觉判读。 展开全文
图像分类,根据各自在图像信息中所反映的不同特征,把不同类别的目标区分开来的图像处理方法。它利用计算机对图像进行定量分析,把图像或图像中的每个像元或区域划归为若干个类别中的某一种,以代替人的视觉判读。
信息
外文名
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中只有图像对象之间的空间拓扑关系具有旋转不变性,在进行图像分类的时候没有考虑对象之间的相对距离。
收起全文
精华内容
下载资源
问答
  • 图像分类

    千次阅读 2017-06-26 20:30:55
    内容如下:简述图像分类,数据驱动和管道K近邻分离器验证集合,交叉验证和超参数调优近邻算法的优点和缺点总结总结:kNN在实践中的应用扩展阅读图像分类 (Image Classification)动机(Motivation),在这个章节中,...

    这是一篇介绍性的文章,旨在向人们介绍计算机视觉的外围应用:图片分类问题。现在我们介绍一种基于数据驱动的方法。内容如下:

    简述图像分类,数据驱动和管道

    K近邻分离器

    验证集合,交叉验证和超参数调优

    近邻算法的优点和缺点

    总结

    总结:kNN在实践中的应用

    扩展阅读

    图像分类 (Image Classification)

    动机(Motivation),在这个章节中,我们讲介绍图像分类问题,任务是给定一个输入图片,将其指派到一个已知的混合类别中的某一个标签。图像分类是计算机视觉领域的核心问题之一,尽管它很(看上去)很简单,但是却有广泛的实践应用。而且,在之后的课程中我们将看到,许多其他的看上去不同的计算机视觉任务(例如物体识别,分割),都能够还原成图像分类。
    例子,例如,在下图中,一个图像分类模型将一个图片分配给四个类别(cat,dog,hat,mug)标签的概率。如图所示,记住对于计算机而言,图片被表示成一个大的3位数字矩阵。在这个例子中,猫图宽248像素,高400像素,并且有3个颜色通过Red,Green,Blue简称RGB 。因此,这个图片包括248 x 400 x 3个数,总共197600个数字。 每一个数字都在0到255之间,其中0表示黑色,255表示白色。我们的任务是转换这个百万级别的数字到一个单独的标签,例如“猫”。
    
    图片分类的任务是对于一个给定的图片,预测其的类别标签。图片是一个的0-255之间的3维数组,大小是宽 x 高 x 3。3表示颜色通道Red,Green,Blue。
    挑战:虽然视觉识别的概念对于人类来讲是一个相对简单的问题,但是从计算视觉算法的角度来看,这儿有许多值得考虑的挑战。正如我们下面展示的一个挑战列表,我们要牢记,一个原始的图片是一个由亮度值组成的3维数组。
    

    这里写图片描述
    1、视觉点变化(Viewpoint variation):一个对像的单个实例可以根据相机的方向来定位。
    2、规模变化(Scale variation):视觉上的类经常展示在他们大小上的变化。
    3、变形(Deformation):许多感兴趣的对象,不是一个僵硬不变的身体,能够以多方式变形。
    4、遮挡(Occlusion):我们感兴趣的对象被遮挡,有时仅仅是目标对象的一小部分能够显示。
    5、光照条件(Illumination conditions):在像素层上,光照的影响是巨大的。
    6、背景杂乱(Background clutter):感兴趣的目标可能混合在背景中,使得他们很难被识别。
    7、类别内部的变化(Intra-class variation):我们感兴趣的类别相对广泛,例如椅子,就有许多不同的形式。
    一个好的图像分类模型对于这些所有变化的交叉的变化必须是不变的,并且要在类别内部变化中保持有敏感性。
    这里写图片描述
    这里写图片描述
    数据驱动的方法(Data-driven approach):我们怎样写一个算法分类图片到不同的类别?这个算法不像排序算法,在图片中识别猫的算法并不是那么显而易见。因此,我们不是指定定感兴趣的类别中的每一个类别的直接代码,(自己都翻译蒙了),我们采取的方法就像一个孩子的方法:我们将提供计算机每一个类中的许多例子,进而看着这些类学习每一个类的视觉显示的算法。这种算法就叫做数据驱动的算法,因为它依赖与第一次选取的带有标签的训练数据集。这种例子看起来就像这样:

    一个有四个类别的训练集合,在现实中,我们可能有成千个类别,每一类有成白上千个图片。
    图像分类管道(The image classification pipeline):我们已经知道在图像分类中,是使用一个像素的数组来表示单一的图像,进而分配标记给它。我们的完整的通道被定义如下:
    输入(Input):输入包括N个图片的集合,每一个图片都标记为k个不同的类之一,叫做训练数据。
    学习(Learning):我们的任务是使用训练数据学习每一个类别看起来像什么,这一步叫做训练一个分类器,或者学习一个模型。
    评价(Evaluation):在最后,通过让它预测之前从没见过图像,评价这个模型的质量。我们将比较这些图片的真实标签和预测结果。直观地,我们希望尽可能多的预测和真实答案匹配。

    最近邻分类器(Nearest Neighbor Classifier)
    我们的第一个方法是,开发一个最近邻分离器。这个分离器与卷积神经网络没有任何关系,并且在实践中很少使用,但是对于图像分类问题,它使我们从基本的方法的出发得到一个idea。
    例如图像分类数据集:CIFAR-10。CIFAR-10 数据集是一个著名的小图像分类数据集。这个数据集包含60000个宽和高都是32像素的小图片。每个图片被标记成10个类别中的一个。这60000个图片被分成50000个训练集和10000个测试集。下图你将看到10个类中每一个显示10个随机的图片。
    Left:样例图片来自于CIFAR-10 dataset。Right:第一列表示1一些测试图片,接下来表示根据最近邻算法得到的最相近的10个图片。
    这里写图片描述
    假设现在你已经得到CIFAR-10的50000训练集,接下来我们希望标记剩下的10000个图片。最近邻算法讲每一个测试图片和训练数据中的图片进行比较,预测的是最接近的训练数据的标签。上图的右边,我们看到一个结果的例子。注意只有3个是同一类的检索,其他的7个并不是如此。例如在第8行中,马头在训练数据集张最接近的是红色的车,可能是由于强烈的黑色背景。结果,图片马就被错误的标记成一个车。
    你也许已经注意到,我们剩下的未提及的细节是怎么比较两个图片,在这个例子中我们有两个32 x 32 x 3的块数据。一个最简单的方法就是比较所有的像素值,并加上所有像素的差值。换句话说,给你两个图片,并将他们表示成向量I_1和I_2,一个合理的选择是比较他们的L1距离。下面是一个可视化的例子:
    这里写图片描述
    两个图片相减,之后求和。
    下面是让我们实现分类器的代码,第一步加载CIFAR-10数据到内存中得到4个数组,训练数据和标签,测试数据和标签。Xtr大小是50000 x 32 x 32 x 3训练其中的所有图片,对应的一维数据是Ytr长度50000,表示的是训练数据的标签,其在0-9之间。

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

    现在所有的图片作为一个行数据,接着我们训练和评测这个分类器。

    nn = NearestNeighbor() # create a Nearest Neighbor classifier class
    nn.train(Xtr_rows, Ytr) # train the classifier on the training images and labels
    Yte_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距离进行度量。

    import numpy as np
    
    class 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%的正确率和最先进的卷积神经网络(CNN)95%的分类器,相差太远了。
    选择距离:有许多其他的计算两个向量之间的距离的方法。另一个常用的选择是L2距离,它是计算两个向量之间欧几里得距离的几何解释。公式如下:
    这里写图片描述
    用python numpy一行代码就可以表示上式;

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

    注意上式中包括了np.sqrt,但是在实际的最近邻应用中,由于平方根是单调函数,我们一般不进行开方。虽然这表示了绝对大小,但是比较的顺序是不变的,因此最近邻是正确的。如果你使用带有这个距离方法的最近邻分类CIFAR-10,你可能得到35.4%的正确率。
    L1 vs. L2,比较两者之间差异,特别当涉及到两个向量的差异是,L2比L1更加的敏感。
    也就是说L2距离更倾向与一个大的分歧,L1和L2是p-范数中最常用的两个距离表示。

    k-最近邻分类器(k-Nearest Neighbor Classifier)
    你可能已经注意到,当我们希望做个预测时,只是用一个最近的标签是奇怪的。更进一步,我们使用k-最近邻时,总会做的更好。它的思想是简单的,不是在训练集中发现一个最近的图片,而是发现k的最近的图片,用这k个图片对测试图片进行投票。特别地,当k=1时就是最近邻。直观地,较高的k具有平滑的作用,使得分类器能够抵抗异常值。
    这里写图片描述

    这是最近邻和k=5最近邻的算法在一个二维数据和3个类别之间的不同。颜色边界表示使用L2距离度量的分类器的决策边界。白色表示未分类。可以看到5-最近邻在于这些不规则的点更加光滑。

    超参数调优的验证集(Validation sets for hyperparameter tuning)
    k-最近邻分类器要求设置k值,但是k取多少才最好呢?而且,我们知道有很多距离函数,包括我们用过的L1范数,L2范数,和我们提到的其他的范数。这些选择被叫做超参数,它们经常在基于数据的机器学习算法中出现。通常不清楚什么值/设置应该选择。

    你可能试图建议我们尝试每一个不同的值,观测谁工作的最好。这是一个好主意,实际上也是我们要做的,但是这样做必须要小心。特别地,我们不能使用测试集来调整超参数。无论
    你设计机器学习算法的什么时候,你都应该将测试数据作为做宝贵的资源,直到最后之前保证它没有被接触过。否则,如果你在测试集集上调整超参数,使得它工作很好,在你部署模型之后,你将看到一个性能的明显的下降。实际上,我们将这种情况叫做过拟合。另一种观察方式是,如果您在测试集上调整超参数,您有效地使用测试集作为训练集,因此在部署模型时 您实现的性能对于您实际观察到的效果将是过于乐观。但是如果你仅仅在最后使用一次测试集,它仍然是你的分类器的好的代表。只在最后评测测试集。
    幸运的是,有个正确的方法来调整超参数,并且不碰测试集。一个好的注意就是经训练集分成两部分:选出一小部分的训练集,我们叫做验证集(validation set)。使用CIFAR-10作为一个例子,使用49000个图片作为训练集,剩下1000作为验证集。验证集基本作为一个假的测试集来优化超参数。
    在CIFAR-10上的例子:

    # assume we have Xtr_rows, Ytr, Xte_rows, Yte as before
    # recall Xtr_rows is 50,000 x 3072 matrix
    Xval_rows = Xtr_rows[:1000, :] # take first 1000 for validation
    Yval = Ytr[:1000]
    Xtr_rows = Xtr_rows[1000:, :] # keep last 49,000 for train
    Ytr = Ytr[1000:]
    
    # find hyperparameters that work best on the validation set
    validation_accuracies = []
    for k in [1, 3, 5, 10, 20, 50, 100]:
    
      # use a particular value of k and evaluation on validation data
      nn = NearestNeighbor()
      nn.train(Xtr_rows, Ytr)
      # here we assume a modified NearestNeighbor class that can take a k as input
      Yval_predict = nn.predict(Xval_rows, k = k)
      acc = np.mean(Yval_predict == Yval)
      print 'accuracy: %f' % (acc,)
    
      # keep track of what works on the validation set
      validation_accuracies.append((k, acc))

    在程序结束的时候,我们作图显示哪个k工作的最好,并将这个k值在特测试集上验证。
    交叉验证(Cross-validation):在某些例子中,训练集可能很小,人们有时使用一个叫做交叉验证的更加复杂的技术。在我们的前面的工作中,我们的想法是武断的选则1000个数据点作为验证集,剩下的作为训练集。通过迭代所有不同的验证集,平均他们的性能,你将得到一个确定k值的更好的低噪声的估计。例如,我们使用5-折交叉验证,分离训练集作为5等份,使用4份作为训练集,剩下的1份作为验证集。我们将在每一份上进行验证,估计性能,最终平均这个不同份的性能。
    这里写图片描述
    我们可以看到k=7时有最好的表现
    实践中,由于交叉验证的计算昂贵,人们一般避免交叉验证,而是选择一个单一的验证集。一般使用50%-90%作为训练集,其他作为验证集。但是这依赖于多种因素:如果有很多的超参数,就需要大的验证集。在所有例子中,验证集很小,因此使用交叉验证是更安全。在实践中最常用的交叉验证是3折交叉验证,5折交叉验证和7折交叉验证。
    这里写图片描述
    交叉验证的可视化表示

    最近邻算法的优缺点(Pros and Cons of Nearest Neighbor classifier.)
    优点:
    简单、易于实现、好理解
    没有训练时间,但要存储训练集和下标
    缺点:
    测试时,计算复杂,在实践中,一般我们更关心测试效率。
    提出近似最近邻算法(Approximate Nearest Neighbor)来加速最近邻算法,kd树加速算法。
    虽然最近邻有时对于低纬度数据是很好的选择,但是在实际的图片分类中它很少使用。一个原因是图片是一个高维的数据对象,需要更多的空间存储。
    一般情况下,使用像素的不同来比较图片是不充分的。下图中,是根据L2像素距离显示的。
    这里写图片描述
    CIFAR-10上使用t-SNE技术,嵌入到二维上。相邻的图片是也是其L2距离最近的。注意到背景比类别有更大的影响。

    总结
    我们介绍了图像分类问题,并给出了带有单独标记的图片集合。要求预测测试集中的分类并给出预测的正确率。
    简单介绍了最近邻分类器,简单介绍了超参数的调优。例如最近邻中的k值。
    介绍了验证集来调整超参数的选择,如果数据缺少时,交叉验证的使用。
    一旦最优的参数被发现,将它使用到测试集上进行评价。
    我们看到k最近邻在CIFAR-10上只有大约40%的正确率,它简单但是要求存储所有的训练数据,并且测试昂贵。
    最后说了,L1和L2距离在图片分类问题上使用是不充分地,因为背景起到了太大的作用。
    在下一节我们将着手解决这些挑战,达到一个90%的正确率,而且我们将完全放弃训练集,
    评价测试集时的时间低于毫秒。

    扩展阅读:
    A Few Useful Things to Know about Machine Learning, 特别是第六章,但是整篇文章也值得读
    Recognizing and Learning Object Categories, 物体分类的简单介绍。

    原文地址:http://cs231n.github.io/classification/

    展开全文
  • 基于支持向量机的图像分类(下篇:MATLAB实现)

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

    摘要:本文通过图文详细介绍如何利用支持向量机对图像进行分类,经过上篇文章对原理的介绍,这里介绍利用MATLAB编程实现。更多相关资源详解也可参考博主最新博文基于支持向量机的手写数字识别详解(MATLAB GUI代码,提供手写板)。本文后续章节将介绍的主要部分有:

    • 图片数据集整理
    • 特征提取
    • SVM训练与测试
    • 分类结果评价
    • 结果显示

    点我下载:SVM图像分类的MATLAB完整程序及图片集文件


    1. 前言

    机器学习是人工智能研究发展到一定阶段的必然产物。二十世纪八十年代是机器学习成为一个独立学科的学科领域、各种机器学习技术百花绽放的时期。支持向量机于1995年正式发表[Cortes and Vapnik,1995],由于在文本分类任务中的卓越性能[Joachims,1998],很快成为机器学习的主流技术,并直接掀起了“统计学习”(statistical learning)在2000年前后的高潮。——《机器学习》 周志华

    2010年前后,随着计算能力的迅猛提升和大数据的涌现,神经网络研究在“深度学习”的名义下又重新崛起,并迎来又一次发展高潮。近年研究SVM的论文少了很多,SVM的风头很多时候确实已被强势崛起的深度学习浪潮所淹没,95年的SVM比我们年龄还大,有点仿佛英雄迟暮的感觉。不过在我看来,实现简单而且非常强大的分类算法SVM仍然有其研究价值,与神经网络相比SVM亦有过人之处,如特征维数多于样本数的情况,而小样本学习至今仍是深度学习的一大难题。

    当浅层神经网络效果不佳时,人们将目光转向支持向量机,而支持向量机亦不负众望,以不错的成绩让人们对机器学习重拾信心。感谢支持向量机,感谢在神经网络几经起落的时候,支持向量机继往开来、自成一脉,填补了机器学习的一段空窗期,让这条曲折向上的研究之路绵延至今迎来了现在人工智能百花齐放的时代!

    接下来就通过简单的图片分类问题,通过MATLAB程序理解认识一下这一简单而强大的分类算法——支持向量机.


    2. 图片数据集整理

    首先需要准备好分类的数据集,数据的整理是机器学习中的重要一环。这里我们自行整理一个用于分类的图片集,图片集有四类图片,分别为车、猫、花、鱼。从百度上下载这四种图片,并分别存放在四个文件夹中,如下图所示

    70

    四类图片每类分别下载100张左右的图片,这四百张图片作为分类的数据集,以7:3的比例将其分为训练图片集和测试图片集,分别放到picturestestPictures两个文件夹中。这两个文件夹下同上图一样都有car、cat、flw、fsh四个文件夹,值得注意的是测试样本的图片应可能不出现在训练集图片库中。做好以上工作,用于分类的图片集就准备完毕了。

    (当然用于分类的图片集常用的是cafir10图片集,这个数据集是写论文或研究时普遍用到的,可能会在后面的文章中介绍其用法,这里就暂时不使用cafir了。)

    为了便于后面的特征提取等对每张图片进行的操作,这里在程序中有必要将图片文件的存储位置、数量、类别等信息整理到一个数据结构中,新建一个m文件,程序代码如下

    dir=('D:\pictures');
    testdir=('D:\testPictures\test');
    trainingSet = imageSet(dir,'recursive');
    testSet = imageSet(testdir,'recursive');
    

    以上代码中用到imageSet( )函数是一个图片集整理的函数(MATLAB R2016b及以上版本支持),返回的是dir文件路径下文件夹内的文件信息。例如得到的trainingSet为一个1*4的imageSet变量,每个imageSet变量由Description、ImageLocation、Count三个属性组成,分别代表对子文件的描述、文件存储位置和图片数量。如下图所示是testSet(1)内部情况

    70

    3. 主要步骤

    和深度学习的算法相比,传统的机器学习在进行图片分类时输入的不是原始图片而是先进行一个特征提取的步骤。在上篇中已经介绍了特征提取的相关内容,这里用的是方向梯度直方图(HOG)以及灰度共生矩阵(GLCM)。

    70

    3.1 GLCM提取

    MATLAB中灰度共生矩阵的提取可以调用graycomatrix( )函数,不过这里为了取不同方向(0、45、90、135度)的灰度共生矩阵,通过循环计算各个方向的灰度共生矩阵并进行归一化处理(计算对比度、逆差距、熵、自相关),然后取平均值和方差作为最终提取的特征。

    新建一个m文件并命名为getGLCMFeatures,输入以下代码

    function [features] = getGLCMFeatures(image)
    features_all  = [];
    for i = 1:10
        glcm = graycomatrix(image, 'Offset', [0,i]);
        stats = graycoprops(glcm);
        
        glcm45 = graycomatrix(image, 'Offset', [-i,i]);
        stats45 = graycoprops(glcm45);
        
        glcm90 = graycomatrix(image, 'Offset', [-i,0]);
        stats90 = graycoprops(glcm90);
        
        glcm135 = graycomatrix(image, 'Offset', [-i,-i]);
        stats135 = graycoprops(glcm135);
        
        stats7x4 = [stats.Contrast stats.Correlation stats.Energy stats.Homogeneity;
            stats45.Contrast stats45.Correlation stats45.Energy stats45.Homogeneity;
            stats90.Contrast stats90.Correlation stats90.Energy stats90.Homogeneity;
            stats135.Contrast stats135.Correlation stats135.Energy stats135.Homogeneity];
        features_all = [features_all mean(stats7x4,1) std(stats7x4,0,1)];
    end
    features = features_all;
    

    新建的getGLCMFeatures函数输入为彩色图像转换后的灰度图像矩阵,输出为提取后的灰度共生矩阵特征。

    3.2 合并特征

    自己编写一个提取特征的函数命名为extractFeature,这个函数输入为整理过的训练集和测试集,输出为训练集的特征、标签和测试集的特征、标签。这个函数的功能是将HOG特征和前面提取的GLCM特征合并。

    代码第2到13行是为了确定每张图片提取特征后得到的矩阵大小,以方便后面的操作同时也是为了预分配空间以提高代码效率。首先取第一张图片进行灰度化以及阈值分割,将图片大小调整在256*256的范围(统一大小)分别进行HOG和GLCM的特征提取,分别得到两种特征向量,取两个向量的长度之和就是一张图片特征提取后的总长度了。

    function [trainingFeatures,trainingLabels,testFeatures,testLabels]=extractFeature(trainingSet,testSet)
    %% 确定特征向量尺寸
    img = read(trainingSet(1), 1);
    %转化为灰度图像
    img=rgb2gray(img);
    %转化为2值图像
    lvl = graythresh(img);
    img = im2bw(img, lvl);
    img=imresize(img,[256 256]);
    cellSize = [4 4];
    [hog_feature, vis_hog] = extractHOGFeatures(img,'CellSize',cellSize);
    glcm_feature = getGLCMFeatures(img);
    SizeOfFeature = length(hog_feature)+ length(glcm_feature);
    
    %% 构建训练样本特征向量和训练样本标签
    trainingFeatures = [];
    trainingLabels   = [];
    for digit = 1:numel(trainingSet)       
        numImages = trainingSet(digit).Count;
        features  = zeros(numImages, SizeOfFeature, 'single');%初始化特征向量
        % 遍历每张图片
        for i = 1:numImages
            img = read(trainingSet(digit), i);% 取出第i张图片
            
            img=rgb2gray(img);                % 转化为灰度图像
            glcm_feature = getGLCMFeatures(img);  % 提取GLCM特征
           
            lvl = graythresh(img);            % 阈值化
            img = im2bw(img, lvl);            % 转化为2值图像
            img=imresize(img,[256 256]);
            % 提取HOG特征
            [hog_feature, vis_hog] = extractHOGFeatures(img,'CellSize',cellSize);
            % 合并两个特征
            features(i, :) = [hog_feature glcm_feature];
        end
        % 使用图像描述作为训练标签
        labels = repmat(trainingSet(digit).Description, numImages, 1);  
        % 逐个添加每张训练图片的特征和标签
        trainingFeatures = [trainingFeatures; features];
        trainingLabels   = [trainingLabels; labels];       
    end
    
    
    %% 提取测试图片集的特征向量
    testFeatures = [];
    testLabels   = [];
    for digit = 1:numel(testSet)
               
        numImages = testSet(digit).Count;
        %初始化特征向量
        features  = zeros(numImages, SizeOfFeature, 'single');
        
        for i = 1:numImages
            
            img = read(testSet(digit), i);
            %转化为灰度图像
            img=rgb2gray(img);
            glcm_feature = getGLCMFeatures(img);
            %转化为2值图像
            lvl = graythresh(img);
            img = im2bw(img, lvl);
            img=imresize(img,[256 256]);
            [hog_4x4, vis4x4] = extractHOGFeatures(img,'CellSize',cellSize);
            features(i, :) = [hog_4x4 glcm_feature];
        end
        
        % 使用图像描述作为训练标签
        labels = repmat(testSet(digit).Description, numImages, 1);
            
        testFeatures = [testFeatures; features];
        testLabels=[testLabels; labels];
            
    end
    end
    

    代码18-41行是构建训练样本特征向量和训练样本标签,与前面步骤相似,只不过现在是遍历训练集每一张图片,对其进行灰度化、阈值化、调整大小,然后进行特征提取,将HOG特征和GLCM特征合并成一个向量作为特征矩阵的一行即一张图片的特征向量。样本的标签构建则将每张图片所处的文件夹的名字作为该图片的标签,并与特征向量顺序相对应。

    第47-73行是构建测试样本特征向量和训练样本标签,这里将图片集换成了测试集,而步骤与训练集是一致的。

    3.3 SVM训练与测试

    调用前面的特征提取函数得到训练和测试用的特征向量与对应的标签,便可以进行SVM的训练和测试。MATLAB自带的训练svm函数可以用fitcecoc函数,测试可以用predict函数预测结果,训练和测试的代码如下

    % 训练一个svm分类器
    % fitcecoc 使用11的方案
    classifier = fitcecoc(trainingFeatures, trainingLabels);
    save classifier.mat classifier;
    
    % 使用测试图像的特征向量预测样本标签
    predictedLabels = predict(classifier, testFeatures);
    

    代码中classifier为训练得到的SVM分类器,利用该分类器以及测试集特征向量预测测试集的标签predictLabels。后面可以将predictLabels与实际的测试标签进行对比即可评估分类好坏。

    3.4 分类结果评价

    在上一篇文章中提到过了,为了评价分类的好坏可以通过混淆矩阵,通过计算混淆矩阵对角线上的值占每行总数的比值得出分类正确率,其实现代码如下

    %% 评估分类器
    % 使用没有标签的图像数据进行测试,生成一个混淆矩阵表明分类效果
    confMat=confusionmat(testLabels, predictedLabels)
    accuracy=(confMat(1,1)/sum(confMat(1,:))+confMat(2,2)/sum(confMat(2,:))+...
        confMat(3,3)/sum(confMat(3,:))+confMat(4,4)/sum(confMat(4,:)))/4
    

    其结果如下图所示

    70

    3.5 结果显示

    尽管以上代码能得到分类正确率,但我们希望更直观的看到输入一张图片后SVM分类器的分类结果,这里编写一个函数通过图形窗口显示预测结果。新建一个m文件命名为Predict,输入如下代码

    function [] = Predict(imageurl)
    load classifier.mat;
    figure;
    img = imread(imageurl);
    imshow(img);
    
    %提取图像的特征向量
    %转化为灰度图像
    img=rgb2gray(img);
    glcm_feature = getGLCMFeatures(img);
    %转化为2值图像
    lvl = graythresh(img);
    img = im2bw(img, lvl);
    
    % imshow(img);
    % figure
    img=imresize(img,[256 256]);
    [hog_4x4, ~] = extractHOGFeatures(img,'CellSize',[4 4]);
    testFeature = [hog_4x4 glcm_feature];
    
    
    % 使用测试图像的特征向量预测样本标签
    predictedLabel = predict(classifier, testFeature);
    
    str = ['分类结果:' predictedLabel];
    dim = [0.25 0.0004 0.2 0.2];
    annotation('textbox', dim, 'string', str, 'fontsize', 20, 'color', 'g','edgecolor', 'none');
    

    函数输入为图片的存储路径,调用函数则会通过图形窗口显示图片及分类结果,如在命令窗口输入如下代码

    Predict('D:\testPictures\test\car\car9.jpg');
    

    输出结果如下图

    70

    4. 完整代码

    为了方便使用这里贴出完整代码

    主函数:

    clear;
    dir=('D:\pictures');
    testdir=('D:\testPictures\test');
    trainingSet = imageSet(dir,'recursive');
    testSet = imageSet(testdir,'recursive');
    
    [trainingFeatures,trainingLabels,testFeatures,testLabels]=extractFeature(trainingSet,testSet);
    %% 
    %训练一个svm分类器
    %fitcecoc 使用11的方案
    classifier = fitcecoc(trainingFeatures, trainingLabels);
    save classifier.mat classifier;
    
    % 使用测试图像的特征向量预测样本标签
    predictedLabels = predict(classifier, testFeatures);
    
    %% 评估分类器
    %使用没有标签的图像数据进行测试,生成一个混淆矩阵表明分类效果
    confMat=confusionmat(testLabels, predictedLabels)
    accuracy=(confMat(1,1)/sum(confMat(1,:))+confMat(2,2)/sum(confMat(2,:))+...
        confMat(3,3)/sum(confMat(3,:))+confMat(4,4)/sum(confMat(4,:)))/4
    
    Predict('D:\testPictures\test\car\car9.jpg');
    

    getGLCMFeatures.m:

    function [features] = getGLCMFeatures(image)
    features_all  = [];
    for i = 1:10
        glcm = graycomatrix(image, 'Offset', [0,i]);
        stats = graycoprops(glcm);
        
        glcm45 = graycomatrix(image, 'Offset', [-i,i]);
        stats45 = graycoprops(glcm45);
        
        glcm90 = graycomatrix(image, 'Offset', [-i,0]);
        stats90 = graycoprops(glcm90);
        
        glcm135 = graycomatrix(image, 'Offset', [-i,-i]);
        stats135 = graycoprops(glcm135);
        
        stats7x4 = [stats.Contrast stats.Correlation stats.Energy stats.Homogeneity;
            stats45.Contrast stats45.Correlation stats45.Energy stats45.Homogeneity;
            stats90.Contrast stats90.Correlation stats90.Energy stats90.Homogeneity;
            stats135.Contrast stats135.Correlation stats135.Energy stats135.Homogeneity];
        features_all = [features_all mean(stats7x4,1) std(stats7x4,0,1)];
    end
    features = features_all;
    

    extractFeature.m:

    function [trainingFeatures,trainingLabels,testFeatures,testLabels]=extractFeature(trainingSet,testSet)
    %% 确定特征向量尺寸
    img = read(trainingSet(1), 1);
    %转化为灰度图像
    img=rgb2gray(img);
    %转化为2值图像
    lvl = graythresh(img);
    img = im2bw(img, lvl);
    img=imresize(img,[256 256]);
    cellSize = [4 4];
    [hog_feature, vis_hog] = extractHOGFeatures(img,'CellSize',cellSize);
    glcm_feature = getGLCMFeatures(img);
    SizeOfFeature = length(hog_feature)+ length(glcm_feature);
    
    %% 构建训练样本特征向量和训练样本标签
    trainingFeatures = [];
    trainingLabels   = [];
    for digit = 1:numel(trainingSet)       
        numImages = trainingSet(digit).Count;
        features  = zeros(numImages, SizeOfFeature, 'single');%初始化特征向量
        % 遍历每张图片
        for i = 1:numImages
            img = read(trainingSet(digit), i);% 取出第i张图片
            
            img=rgb2gray(img);                % 转化为灰度图像
            glcm_feature = getGLCMFeatures(img);  % 提取GLCM特征
           
            lvl = graythresh(img);            % 阈值化
            img = im2bw(img, lvl);            % 转化为2值图像
            img=imresize(img,[256 256]);
            % 提取HOG特征
            [hog_feature, vis_hog] = extractHOGFeatures(img,'CellSize',cellSize);
            % 合并两个特征
            features(i, :) = [hog_feature glcm_feature];
        end
        % 使用图像描述作为训练标签
        labels = repmat(trainingSet(digit).Description, numImages, 1);  
        % 逐个添加每张训练图片的特征和标签
        trainingFeatures = [trainingFeatures; features];
        trainingLabels   = [trainingLabels; labels];       
    end
    
    
    %% 提取测试图片集的特征向量
    testFeatures = [];
    testLabels   = [];
    for digit = 1:numel(testSet)
               
        numImages = testSet(digit).Count;
        %初始化特征向量
        features  = zeros(numImages, SizeOfFeature, 'single');
        
        for i = 1:numImages
            
            img = read(testSet(digit), i);
            %转化为灰度图像
            img=rgb2gray(img);
            glcm_feature = getGLCMFeatures(img);
            %转化为2值图像
            lvl = graythresh(img);
            img = im2bw(img, lvl);
            img=imresize(img,[256 256]);
            [hog_4x4, vis4x4] = extractHOGFeatures(img,'CellSize',cellSize);
            features(i, :) = [hog_4x4 glcm_feature];
        end
        
        % 使用图像描述作为训练标签
        labels = repmat(testSet(digit).Description, numImages, 1);
            
        testFeatures = [testFeatures; features];
        testLabels=[testLabels; labels];
            
    end
    end
    

    Predict.m:

    function [] = Predict(imageurl)
    load classifier.mat;
    figure;
    img = imread(imageurl);
    imshow(img);
    
    %提取图像的特征向量
    %转化为灰度图像
    img=rgb2gray(img);
    glcm_feature = getGLCMFeatures(img);
    %转化为2值图像
    lvl = graythresh(img);
    img = im2bw(img, lvl);
    
    % imshow(img);
    % figure
    img=imresize(img,[256 256]);
    [hog_4x4, ~] = extractHOGFeatures(img,'CellSize',[4 4]);
    testFeature = [hog_4x4 glcm_feature];
    
    
    % 使用测试图像的特征向量预测样本标签
    predictedLabel = predict(classifier, testFeature);
    
    str = ['分类结果:' predictedLabel];
    dim = [0.25 0.0004 0.2 0.2];
    annotation('textbox', dim, 'string', str, 'fontsize', 20, 'color', 'g','edgecolor', 'none');
    

    5. 结束语

    本博文的完整MATLAB程序文件与图片集文件已经上传,下载即可运行(注意根据实际修改程序中的图片路径哦)下载地址如下

    点我下载:SVM的图像分类MATLAB完整程序及图片集文件

    更多相关资源详解也可参考博主最新博文基于支持向量机的手写数字识别详解(MATLAB GUI代码,提供手写板)

    公众号获取
        本人微信公众号已创建,扫描以下二维码并关注公众号“AI技术研究与分享”,后台回复“SV20180411”即可获取全部资源文件信息。

    watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMyODkyMzgz,size_16,color_FFFFFF,t_70

    由于编者能力有限,代码即使经过了多次校对,也难免会有疏漏之处。希望您能热心指出其中的错误,以便下次修改时能以一个更完美更严谨的样子,呈现在大家面前。同时如果有更好的实现方法也请您不吝赐教。

    展开全文
  • 这篇文章将详细讲解图像分类知识,包括常见的图像分类算法,并介绍Python环境下的贝叶斯图像分类算法、基于KNN算法的图像分类和基于神经网络算法的图像分类等案例。万字长文整理,希望对您有所帮助。 同时,该部分...

    该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解图像入门、OpenCV基础用法,中期讲解图像处理的各种算法,包括图像锐化算子、图像增强技术、图像分割等,后期结合深度学习研究图像识别、图像分类应用。希望文章对您有所帮助,如果有不足之处,还请海涵~

    前面一篇文章介绍了图像增强知识,从而改善图像质量,增强图像识别效果,核心内容分为直方图均衡化、局部直方图均衡化和自动色彩均衡三部分。这篇文章将详细讲解图像分类知识,包括常见的图像分类算法,并介绍Python环境下的贝叶斯图像分类算法、基于KNN算法的图像分类和基于神经网络算法的图像分类等案例。万字长文整理,希望对您有所帮助。 同时,该部分知识均为作者查阅资料撰写总结,并且开设成了收费专栏,为小宝赚点奶粉钱,感谢您的抬爱。当然如果您是在读学生或经济拮据,可以私聊我给你每篇文章开白名单,或者转发原文给你,更希望您能进步,一起加油喔~

    代码下载地址(如果喜欢记得star,一定喔):

    前文参考:


    一.图像分类概述

    图像分类(Image Classification)是对图像内容进行分类的问题,它利用计算机对图像进行定量分析,把图像或图像中的区域划分为若干个类别,以代替人的视觉判断。

    图像分类的传统方法是特征描述及检测,这类传统方法可能对于一些简单的图像分类是有效的,但由于实际情况非常复杂,传统的分类方法不堪重负。现在,广泛使用机器学习和深度学习的方法来处理图像分类问题,其主要任务是给定一堆输入图片,将其指派到一个已知的混合类别中的某个标签。

    在图1中,图像分类模型将获取单个图像,并将为4个标签{cat,dog,hat,mug}分配对应的概率{0.6, 0.3, 0.05, 0.05},其中0.6表示图像标签为猫的概率,其余类比。

    在这里插入图片描述

    如图1所示,该图像被表示为一个三维数组。在这个例子中,猫的图像宽度为248像素,高度为400像素,并具有红绿蓝三个颜色通道(通常称为RGB)。因此,图像由248×400×3个数字组成或总共297600个数字,每个数字是一个从0(黑色)到255(白色)的整数。图像分类的任务是将这接近30万个数字变成一个单一的标签,如“猫(cat)”。

    那么,如何编写一个图像分类的算法呢?又怎么从众多图像中识别出猫呢?
    这里所采取的方法和教育小孩看图识物类似,给出很多图像数据,让模型不断去学习每个类的特征。在训练之前,首先需要对训练集的图像进行分类标注,如图2所示,包括cat、dog、mug和hat四类。在实际工程中,可能有成千上万类别的物体,每个类别都会有上百万张图像。

    在这里插入图片描述

    图像分类是输入一堆图像的像素值数组,然后给它分配一个分类标签,通过训练学习来建立算法模型,接着使用该模型进行图像分类预测,具体流程如下:

    • 输入:输入包含N个图像的集合,每个图像的标签是K种分类标签中的一种,这个集合称为训练集;
    • 学习:第二步任务是使用训练集来学习每个类的特征,构建训练分类器或者分类模型;
    • 评价:通过分类器来预测新输入图像的分类标签,并以此来评价分类器的质量。通过分类器预测的标签和图像真正的分类标签对比,从而评价分类算法的好坏。如果分类器预测的分类标签和图像真正的分类标签一致,表示预测正确,否则预测错误。

    二.常见的分类算法

    常见的分类算法包括朴素贝叶斯分类器、决策树、K最近邻分类算法、支持向量机、神经网络和基于规则的分类算法等,同时还有用于组合单一类方法的集成学习算法,如Bagging和Boosting等。

    1.朴素贝叶斯分类算法

    朴素贝叶斯分类(Naive Bayes Classifier)发源于古典数学理论,利用Bayes定理来预测一个未知类别的样本属于各个类别的可能性,选择其中可能性最大的一个类别作为该样本的最终类别。在朴素贝叶斯分类模型中,它将为每一个类别的特征向量建立服从正态分布的函数,给定训练数据,算法将会估计每一个类别的向量均值和方差矩阵,然后根据这些进行预测。

    在这里插入图片描述

    朴素贝叶斯分类模型的正式定义如下:

    在这里插入图片描述

    该算法的特点为:如果没有很多数据,该模型会比很多复杂的模型获得更好的性能,因为复杂的模型用了太多假设,以致产生欠拟合。


    2.KNN分类算法

    K最近邻分类(K-Nearest Neighbor Classifier)算法是一种基于实例的分类方法,是数据挖掘分类技术中最简单常用的方法之一。该算法的核心思想如下:一个样本x与样本集中的k个最相邻的样本中的大多数属于某一个类别yLabel,那么该样本x也属于类别yLabel,并具有这个类别样本的特性。简而言之,一个样本与数据集中的k个最相邻样本中的大多数的类别相同。

    在这里插入图片描述

    由其思想可以看出,KNN是通过测量不同特征值之间的距离进行分类,而且在决策样本类别时,只参考样本周围k个“邻居”样本的所属类别。因此比较适合处理样本集存在较多重叠的场景,主要用于预测分析、文本分类、降维等处理。

    该算法在建立训练集时,就要确定训练数据及其对应的类别标签;然后把待分类的测试数据与训练集数据依次进行特征比较,从训练集中挑选出最相近的k个数据,这k个数据中投票最多的分类,即为新样本的类别。KNN分类算法的流程描述为如图3所示。

    在这里插入图片描述

    该算法的特点为:简单有效,但因为需要存储所有的训练集,占用很大内存,速度相对较慢,使用该方法前通常训练集需要进行降维处理。


    3.SVM分类算法

    支持向量机(Support Vector Machine)是数学家Vapnik等人根据统计学习理论提出的一种新的学习方法,其基本模型定义为特征空间上间隔最大的线性分类器,其学习策略是间隔最大化,最终转换为一个凸二次规划问题的求解。

    SVM分类算法基于核函数把特征向量映射到高维空间,建立一个线性判别函数,解最优在某种意义上是两类中距离分割面最近的特征向量和分割面的距离最大化。离分割面最近的特征向量被称为“支持向量”,即其它向量不影响分割面。图像分类中的SVM如图4所示,将图像划分为不同类别。

    在这里插入图片描述

    下面的例子可以让读者对SVM快速建立一个认知。给定训练样本,支持向量机建立一个超平面作为决策曲面,使得正例和反例的隔离边界最大化。决策曲面的构建过程如下所示:

    第一步,在图5中,想象红球和蓝球为球台上的桌球,首先需要找到一条曲线将蓝球和红球分开,于是得到一条黑色的曲线;

    在这里插入图片描述

    第二步,为了使黑色曲线离任意的蓝球和红球距离最大化,我们需要找到一条最优的曲线,如图6所示;

    在这里插入图片描述

    第三步,假设这些球不是在球桌上,而是抛在空中,但仍然需要将红球和蓝球分开,这时就需要一个曲面,而且该曲面仍然满足所有任意红球和蓝球的间距最大化,如图7所示。离这个曲面最近的红色球和蓝色球就被称为“支持向量(Support Vector)”。

    在这里插入图片描述

    该算法的特点为:当数据集比较小的时候,支持向量机的效果非常好。同时,SVM分类算法较好地解决了非线性、高维数、局部极小点等问题,维数大于样本数时仍然有效。


    4.随机森林分类算法

    随机森林(Random Forest)是用随机的方式建立一个森林,在森林里有很多决策树的组成,并且每一棵决策树之间是没有关联的。当有一个新样本出现的时候,通过森林中的每一棵决策树分别进行判断,看看这个样本属于哪一类,然后用投票的方式,决定哪一类被选择的多,并作为最终的分类结果。

    在这里插入图片描述

    随机森林中的每一个决策树“种植”和“生长”主要包括以下四个步骤:

    • 假设训练集中的样本个数为N,通过有重置的重复多次抽样获取这N个样本,抽样结果将作为生成决策树的训练集;
    • 如果有M个输入变量,每个节点都将随机选择m(m<M)个特定的变量,然后运用这m个变量来确定最佳的分裂点。在决策树的生成过程中,m值是保持不变的;
    • 每棵决策树都最大可能地进行生长而不进行剪枝;
    • 通过对所有的决策树进行加来预测新的数据(在分类时采用多数投票,在回归时采用平均)。

    该算法的特点为:在分类和回归分析中都表现良好;对高维数据的处理能力强,可以处理成千上万的输入变量,也是一个非常不错的降维方法;能够输出特征的重要程度,能有效地处理缺省值。


    5.神经网络分类算法

    神经网络(Neural Network)是对非线性可分数据的分类方法,通常包括输入层、隐藏层和输出层。其中,与输入直接相连的称为隐藏层(Hidden Layer),与输出直接相连的称为输出层(Output Layer)。神经网络算法的特点是有比较多的局部最优值,可通过多次随机设定初始值并运行梯度下降算法获得最优值。图像分类中使用最广泛的是BP神经网络和CNN神经网络。

    1.BP神经网络
    BP神经网络是一种多层的前馈神经网络,其主要的特点为:信号是前向传播的,而误差是反向传播的。BP神经网络的过程主要分为两个阶段,第一阶段是信号的前向传播,从输入层经过隐含层,最后到达输出层;第二阶段是误差的反向传播,从输出层到隐含层,最后到输入层,依次调节隐含层到输出层的权重和偏置,输入层到隐含层的权重和偏置,具体结构如图8所示。

    在这里插入图片描述

    神经网络的基本组成单元是神经元。神经元的通用模型如图9所示,其中常用的激活函数有阈值函数、Sigmoid函数和双曲正切函数等。

    在这里插入图片描述

    神经元的输出为:

    在这里插入图片描述

    2.CNN卷积神经网络
    卷积神经网络(Convolutional Neural Networks)是一类包含卷积计算且具有深度结构的前馈神经网络,是深度学习的代表算法之一。卷积神经网络的研究始于二十世纪80至90年代,时间延迟网络和LeNet-5是最早出现的卷积神经网络。在二十一世纪后,随着深度学习理论的提出和数值计算设备的改进,卷积神经网络得到了快速发展,并被大量应用于计算机视觉、自然语言处理等领域。

    在这里插入图片描述

    图10是一个识别的CNN模型。最左边的图片是输入层二维矩阵,然后是卷积层,卷积层的激活函数使用ReLU,即。在卷积层之后是池化层,它和卷积层是CNN特有的,池化层中没有激活函数。卷积层和池化层的组合可以在隐藏层出现很多次,上图中循环出现了两次,而实际上这个次数是根据模型的需要而定。常见的CNN都是若干卷积层加池化层的组合,在若干卷积层和池化层后面是全连接层,最后输出层使用了Softmax激活函数来做图像识别的分类。


    三.基于朴素贝叶斯算法的图像分类

    本章主要使用Scikit-Learn包进行Python图像分类处理。Scikit-Learn扩展包是用于Python数据挖掘和数据分析的经典、实用扩展包,通常缩写为Sklearn。Scikit-Learn中的机器学习模型是非常丰富的,包括:

    • 线性回归
    • 决策树
    • SVM
    • KMeans
    • KNN
    • PCA

    用户可以根据具体分析问题的类型选择该扩展包的合适模型,从而进行数据分析,其安装过程主要通过“pip install scikit-learn”实现。

    实验所采用的数据集为Sort_1000pics数据集,该数据集包含了1000张图片,总共分为10大类,分别是人(第0类)、沙滩(第1类)、建筑(第2类)、大卡车(第3类)、恐龙(第4类)、大象(第5类)、花朵(第6类)、马(第7类)、山峰(第8类)和食品(第9类),每类100张。如图11所示。

    在这里插入图片描述

    接着将所有各类图像按照对应的类标划分至“0”至“9”命名的文件夹中,如图12所示,每个文件夹中均包含了100张图像,对应同一类别。

    在这里插入图片描述

    比如,文件夹名称为“6”中包含了100张花的图像,如图13所示。

    在这里插入图片描述

    下面是调用朴素贝叶斯算法进行图像分类的完整代码,调用sklearn.naive_bayes中的BernoulliNB()函数进行实验。它将1000张图像按照训练集为70%,测试集为30%的比例随机划分,再获取每张图像的像素直方图,根据像素的特征分布情况进行图像分类分析。

    # -*- coding: utf-8 -*-
    # By: Eastmount CSDN 2021-04-01
    import os
    import cv2
    import numpy as np
    from sklearn.model_selection import train_test_split
    from sklearn.metrics import confusion_matrix, classification_report
    
    #----------------------------------------------------------------------------------
    # 第一步 切分训练集和测试集
    #----------------------------------------------------------------------------------
    
    X = [] #定义图像名称
    Y = [] #定义图像分类类标
    Z = [] #定义图像像素
    
    for i in range(0, 10):
        #遍历文件夹,读取图片
        for f in os.listdir("photo/%s" % i):
            #获取图像名称
            X.append("photo//" +str(i) + "//" + str(f))
            #获取图像类标即为文件夹名称
            Y.append(i)
    
    X = np.array(X)
    Y = np.array(Y)
    
    #随机率为100% 选取其中的30%作为测试集
    X_train, X_test, y_train, y_test = train_test_split(X, Y,                                                   
    test_size=0.3, random_state=1)
    
    print(len(X_train), len(X_test), len(y_train), len(y_test))
    
    #----------------------------------------------------------------------------------
    # 第二步 图像读取及转换为像素直方图
    #----------------------------------------------------------------------------------
    
    #训练集
    XX_train = []
    for i in X_train:
        #读取图像
        #print i
        image = cv2.imread(i)
        
        #图像像素大小一致
        img = cv2.resize(image, (256,256),
                         interpolation=cv2.INTER_CUBIC)
    
        #计算图像直方图并存储至X数组
        hist = cv2.calcHist([img], [0,1], None,
                                [256,256], [0.0,255.0,0.0,255.0])
    
        XX_train.append(((hist/255).flatten()))
    
    #测试集
    XX_test = []
    for i in X_test:
        #读取图像
        #print i
        image = cv2.imread(i)
        
        #图像像素大小一致
        img = cv2.resize(image, (256,256),
                         interpolation=cv2.INTER_CUBIC)
    
        #计算图像直方图并存储至X数组
        hist = cv2.calcHist([img], [0,1], None,
                                [256,256], [0.0,255.0,0.0,255.0])
    
        XX_test.append(((hist/255).flatten()))
    
    #----------------------------------------------------------------------------------
    # 第三步 基于朴素贝叶斯的图像分类处理
    #----------------------------------------------------------------------------------
    
    from sklearn.naive_bayes import BernoulliNB
    clf = BernoulliNB().fit(XX_train, y_train)
    predictions_labels = clf.predict(XX_test)
    
    print('预测结果:')
    print(predictions_labels)
    
    print('算法评价:')
    print(classification_report(y_test, predictions_labels))
    
    #输出前10张图片及预测结果
    k = 0
    while k<10:
        #读取图像
        print(X_test[k])
        image = cv2.imread(X_test[k])
        print(predictions_labels[k])
        #显示图像
        cv2.imshow("img", image)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
        k = k + 1
    

    代码中对预测集的前十张图像进行了显示,其中“368.jpg”图像如图14所示,其分类预测的类标结果为“3”,表示第3类大卡车,预测结果正确。

    在这里插入图片描述

    图15展示了“452.jpg”图像,其分类预测的类标结果为“4”,表示第4类恐龙,预测结果正确。

    在这里插入图片描述

    图16展示了“507.jpg”图像,其分类预测的类标结果为“7”,错误地预测为第7类恐龙,其真实结果应该是第5类大象。

    在这里插入图片描述

    使用朴素贝叶斯算法进行图像分类实验,最后预测的结果及算法评价准确率(Precision)、召回率(Recall)和F值(F1-score)如图16所示。

    在这里插入图片描述


    四.基于KNN算法的图像分类

    下面是基于KNN算法的图像分类代码,调用sklearn.neighbors中的KNeighborsClassifier()函数进行实验。核心代码如下:

    • from sklearn.neighbors import KNeighborsClassifier
    • clf = KNeighborsClassifier(n_neighbors=11).fit(XX_train, y_train)
    • predictions_labels = clf.predict(XX_test)

    完整代码参照下面的文件。

    # -*- coding: utf-8 -*-
    # By: Eastmount CSDN 2021-04-01
    import os
    import cv2
    import numpy as np
    from sklearn.model_selection import train_test_split
    from sklearn.metrics import confusion_matrix, classification_report
    
    #----------------------------------------------------------------------------------
    # 第一步 切分训练集和测试集
    #----------------------------------------------------------------------------------
    
    X = [] #定义图像名称
    Y = [] #定义图像分类类标
    Z = [] #定义图像像素
    
    for i in range(0, 10):
        #遍历文件夹,读取图片
        for f in os.listdir("photo/%s" % i):
            #获取图像名称
            X.append("photo//" +str(i) + "//" + str(f))
            #获取图像类标即为文件夹名称
            Y.append(i)
    
    X = np.array(X)
    Y = np.array(Y)
    
    #随机率为100% 选取其中的30%作为测试集
    X_train, X_test, y_train, y_test = train_test_split(X, Y,
                                                        test_size=0.3, random_state=1)
    
    print(len(X_train), len(X_test), len(y_train), len(y_test))
    
    #----------------------------------------------------------------------------------
    # 第二步 图像读取及转换为像素直方图
    #----------------------------------------------------------------------------------
    
    #训练集
    XX_train = []
    for i in X_train:
        #读取图像
        #print i
        image = cv2.imread(i)
        
        #图像像素大小一致
        img = cv2.resize(image, (256,256),
                         interpolation=cv2.INTER_CUBIC)
    
        #计算图像直方图并存储至X数组
        hist = cv2.calcHist([img], [0,1], None,
                                [256,256], [0.0,255.0,0.0,255.0])
    
        XX_train.append(((hist/255).flatten()))
    
    #测试集
    XX_test = []
    for i in X_test:
        #读取图像
        #print i
        image = cv2.imread(i)
        
        #图像像素大小一致
        img = cv2.resize(image, (256,256),
                         interpolation=cv2.INTER_CUBIC)
    
        #计算图像直方图并存储至X数组
        hist = cv2.calcHist([img], [0,1], None,
                                [256,256], [0.0,255.0,0.0,255.0])
    
        XX_test.append(((hist/255).flatten()))
    
    #----------------------------------------------------------------------------------
    # 第三步 基于KNN的图像分类处理
    #----------------------------------------------------------------------------------
    
    from sklearn.neighbors import KNeighborsClassifier
    clf = KNeighborsClassifier(n_neighbors=11).fit(XX_train, y_train)
    predictions_labels = clf.predict(XX_test)
    
    print('预测结果:')
    print(predictions_labels)
    
    print('算法评价:')
    print((classification_report(y_test, predictions_labels)))
    
    #输出前10张图片及预测结果
    k = 0
    while k<10:
        #读取图像
        print(X_test[k])
        image = cv2.imread(X_test[k])
        print(predictions_labels[k])
        #显示图像
        cv2.imshow("img", image)
        cv2.waitKey(0)
        cv2.destroyAllWindows()
        k = k + 1
    

    代码中对预测集的前十张图像进行了显示,其中“818.jpg”图像如图17所示,其分类预测的类标结果为“8”,表示第8类山峰,预测结果正确。

    在这里插入图片描述

    图18展示了“929.jpg”图像,其分类预测的类标结果为“9”,正确地预测为第9类食品。

    在这里插入图片描述

    使用KNN算法进行图像分类实验,最后算法评价的准确率(Precision)、召回率(Recall)和F值(F1-score)如图19所示,其中平均准确率为0.63,平均召回率为0.55,平均F值为0.49,其结果略差于朴素贝叶斯的图像分类算法。

    在这里插入图片描述


    五.基于神经网络算法的图像分类

    下面是基于神经网络算法的图像分类代码,主要是结合“誓天断发”老师的博客实现的,通过自定义的神经网络实现图像分类。它的基本思想为:先计算每一层的状态和激活值,直到最后一层(即信号是前向传播的);接着计算每一层的误差,误差的计算过程是从最后一层向前推进的(反向传播);最后更新参数(目标是误差变小),迭代前面两个步骤,直到满足停止准则,比如相邻两次迭代的误差的差别很小。

    具体代码如下:

    # -*- coding: utf-8 -*-
    # By: Eastmount CSDN 2021-04-01
    import os
    import cv2
    import numpy as np
    from sklearn.model_selection import train_test_split
    from sklearn.metrics import confusion_matrix, classification_report
    
    #----------------------------------------------------------------------------------
    # 第一步 图像读取及转换为像素直方图
    #----------------------------------------------------------------------------------
    
    X = []
    Y = []
    
    for i in range(0, 10):
        #遍历文件夹,读取图片
        for f in os.listdir("photo/%s" % i):
            #获取图像像素
            Images = cv2.imread("photo/%s/%s" % (i, f)) 
            image=cv2.resize(Images,(256,256),interpolation=cv2.INTER_CUBIC)
            hist = cv2.calcHist([image], [0,1], None, [256,256], [0.0,255.0,0.0,255.0]) 
            X.append((hist/255).flatten())
            Y.append(i)
            
    X = np.array(X)
    Y = np.array(Y)
    
    #切分训练集和测试集
    X_train, X_test, y_train, y_test = train_test_split(X, Y,
                                                        test_size=0.3, random_state=1)
    
    #----------------------------------------------------------------------------------
    # 第二步 定义神经网络函数
    #----------------------------------------------------------------------------------
    
    from sklearn.preprocessing import LabelBinarizer
    import random
    
    def logistic(x):
        return 1 / (1 + np.exp(-x))
    
    def logistic_derivative(x):
        return logistic(x) * (1 - logistic(x))
    
    class NeuralNetwork:
        def predict(self, x):
            for b, w in zip(self.biases, self.weights):
                # 计算权重相加再加上偏向的结果
                z = np.dot(x, w) + b
                # 计算输出值
                x = self.activation(z)
            return self.classes_[np.argmax(x, axis=1)]
        
    class BP(NeuralNetwork):
        
        def __init__(self,layers,batch):
                    
            self.layers = layers
            self.batch = batch
            self.activation = logistic
            self.activation_deriv = logistic_derivative
            
            self.num_layers = len(layers)
            self.biases = [np.random.randn(x) for x in layers[1:]]
            self.weights = [np.random.randn(x, y) for x, y in zip(layers[:-1], layers[1:])]
            
        def fit(self, X, y, learning_rate=0.1, epochs=1):
        
            labelbin = LabelBinarizer()
            y = labelbin.fit_transform(y)
            self.classes_ = labelbin.classes_
            training_data = [(x,y) for x, y in zip(X, y)]
            n = len(training_data)
            for k in range(epochs):
            #每次迭代都循环一次训练
                #训练集乱序
                random.shuffle(training_data)
                batches = [training_data[k:k+self.batch] for k in range(0, n, self.batch)]
                #批量梯度下降
                for mini_batch in batches:
                    x = []
                    y = []
                    for a,b in mini_batch:
                        x.append(a)
                        y.append(b)
                    activations = [np.array(x)]
                    #向前一层一层的走
                    for b, w in zip(self.biases, self.weights):
                        #计算激活函数的参数,计算公式:权重.dot(输入)+偏向 
                        z = np.dot(activations[-1],w)+b 
                        #计算输出值
                        output = self.activation(z)
                        #将本次输出放进输入列表 后面更新权重的时候备用
                        activations.append(output)
                    #计算误差值
                    error = activations[-1]-np.array(y)
                    #计算输出层误差率
                    deltas = [error * self.activation_deriv(activations[-1])]
                    
                    #循环计算隐藏层的误差率 从倒数第2层开始
                    for l in range(self.num_layers-2, 0, -1):
                        deltas.append(self.activation_deriv(activations[l]) * np.dot(deltas[-1],self.weights[l].T))
    
                    #将各层误差率顺序颠倒 准备逐层更新权重和偏向
                    deltas.reverse()
                    #更新权重和偏向
                    for j in range(self.num_layers-1):
                        # 权重的增长量 计算公式为: 增长量 = 学习率 × (错误率.dot(输出值))
                        delta = learning_rate/self.batch*((np.atleast_2d(activations[j].sum(axis=0)).T).dot(np.atleast_2d(deltas[j].sum(axis=0))))
                        #更新权重
                        self.weights[j] -= delta
                        #偏向增加量 计算公式为: 学习率 × 错误率
                        delta = learning_rate/self.batch * deltas[j].sum(axis=0)
                        #更新偏向
                        self.biases[j] -= delta
            return self   
    
    #----------------------------------------------------------------------------------
    # 第三步 基于神经网络的图像分类处理
    #----------------------------------------------------------------------------------
    
    clf = BP([X_train.shape[1],10],10).fit(X_train,y_train,epochs=100)
    predictions_labels = clf.predict(X_test)
    print('预测结果:')
    print(predictions_labels)
    print('算法评价:')
    print(classification_report(y_test, predictions_labels))
    

    使用神经网络算法进行图像分类实验,最后算法评价的准确率(Precision)、召回率(Recall)和F值(F1-score)如图16-20所示,其中平均准确率为0.63,平均召回率为0.63,平均F值为0.62,整体分类结果良好。

    在这里插入图片描述

    这里可能会疑惑效果为什么会这么差呢?

    • 一方面是采用拉直函数,正常图像分类更建议将整个图像矩阵映射进行分类;
    • 另一方面我们采用的算法比较传统,后续作者会介绍CNN、RNN、LSTM之类的对比;
    • 该篇文章更重要的是普及图像分类算法,并实现一个简单的demo。

    六.总结

    写到这里,本文就介绍完毕。这篇主要讲解Python环境下的图像分类算法,首先普及了常见的分类算法,包括朴素贝叶斯、KNN、SVM、随机森林、神经网络等,接着通过朴素贝叶斯、KNN和神经网络分别实现了1000张图像的图像分类实验,对读者有一定帮助。

    • 一.图像分类概述
    • 二.常见的分类算法
      1.朴素贝叶斯分类算法
      2.KNN分类算法
      3.SVM分类算法
      4.随机森林分类算法
      5.神经网络分类算法
    • 三.基于朴素贝叶斯算法的图像分类
    • 四.基于KNN算法的图像分类
    • 五.基于神经网络算法的图像分类

    源代码下载地址,记得帮忙点star和关注喔。

    时光嘀嗒嘀嗒的流失,这是我在CSDN写下的第八篇年终总结,比以往时候来的更早一些。《敏而多思,宁静致远》,仅以此篇纪念这风雨兼程的一年,这感恩的一年。转眼小宝六个月了,哈哈~这是四月的第一篇文章,加油!

    2020年8月18新开的“娜璋AI安全之家”,主要围绕Python大数据分析、网络空间安全、人工智能、Web渗透及攻防技术进行讲解,同时分享CCF、SCI、南核北核论文的算法实现。娜璋之家会更加系统,并重构作者的所有文章,从零讲解Python和安全,写了近十年文章,真心想把自己所学所感所做分享出来,还请各位多多指教,真诚邀请您的关注!谢谢。

    在这里插入图片描述

    (By:Eastmount 2021-04-01 晚上12点 http://blog.csdn.net/eastmount/ )


    参考文献:

    • [1] 罗子江. Python中的图像处理[M]. 科学出版社 2020.
    • [2] 冈萨雷斯. 数字图像处理(第3版)[M]. 北京:电子工业出版社, 2013.
    • [3] 张恒博, 欧宗瑛. 一种基于色彩和灰度直方图的图像检索方法[J]. 计算机工程, 2004.
    • [4] 杨秀璋, 颜娜. Python网络数据爬取及分析从入门到精通(分析篇)[M]. 北京航天航空大学出版社, 2018.
    • [5] https://blog.csdn.net/gzq0723/article/details/82185832
    • [6] https://blog.csdn.net/baidu_28342107/article/details/82999249.
    • [7] https://blog.csdn.net/baidu_28342107/article/details/82870436.
    • [8] https://www.jianshu.com/p/57e862d695f2
    • [9] ttps://www.jianshu.com/p/6ab6f53874f7
    • [10] https://blog.csdn.net/smilejiasmile/article/details/80752889
    • [11] https://blog.csdn.net/baidu_28342107/article/details/83307633
    展开全文
  • Pytorch实战2:ResNet-18实现Cifar-10图像分类 实验环境: Pytorch 0.4.0 torchvision 0.2.1 Python 3.6 CUDA8+cuDNN v7 (可选) Win10+Pycharm 整个项目代码:点击这里 ResNet-18网络结构: ResN...

    版权说明:此文章为本人原创内容,转载请注明出处,谢谢合作!


    Pytorch实战2:ResNet-18实现Cifar-10图像分类

    实验环境:

    1. Pytorch 0.4.0
    2. torchvision 0.2.1
    3. Python 3.6
    4. CUDA8+cuDNN v7 (可选)
    5. Win10+Pycharm

    整个项目代码:点击这里

    ResNet-18网络结构:

    这里写图片描述
    ResNet全名Residual Network残差网络。Kaiming He 的《Deep Residual Learning for Image Recognition》获得了CVPR最佳论文。他提出的深度残差网络在2015年可以说是洗刷了图像方面的各大比赛,以绝对优势取得了多个比赛的冠军。而且它在保证网络精度的前提下,将网络的深度达到了152层,后来又进一步加到1000的深度。论文的开篇先是说明了深度网络的好处:特征等级随着网络的加深而变高,网络的表达能力也会大大提高。因此论文中提出了一个问题:是否可以通过叠加网络层数来获得一个更好的网络呢?作者经过实验发现,单纯的把网络叠起来的深层网络的效果反而不如合适层数的较浅的网络效果。因此何恺明等人在普通平原网络的基础上增加了一个shortcut, 构成一个residual block。此时拟合目标就变为F(x),F(x)就是残差:
    这里写图片描述!

    Pytorch上搭建ResNet-18:

    '''ResNet-18 Image classfication for cifar-10 with PyTorch 
    
    Author 'Sun-qian'.
    
    '''
    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    
    class ResidualBlock(nn.Module):
        def __init__(self, inchannel, outchannel, stride=1):
            super(ResidualBlock, self).__init__()
            self.left = nn.Sequential(
                nn.Conv2d(inchannel, outchannel, kernel_size=3, stride=stride, padding=1, bias=False),
                nn.BatchNorm2d(outchannel),
                nn.ReLU(inplace=True),
                nn.Conv2d(outchannel, outchannel, kernel_size=3, stride=1, padding=1, bias=False),
                nn.BatchNorm2d(outchannel)
            )
            self.shortcut = nn.Sequential()
            if stride != 1 or inchannel != outchannel:
                self.shortcut = nn.Sequential(
                    nn.Conv2d(inchannel, outchannel, kernel_size=1, stride=stride, bias=False),
                    nn.BatchNorm2d(outchannel)
                )
    
        def forward(self, x):
            out = self.left(x)
            out += self.shortcut(x)
            out = F.relu(out)
            return out
    
    class ResNet(nn.Module):
        def __init__(self, ResidualBlock, num_classes=10):
            super(ResNet, self).__init__()
            self.inchannel = 64
            self.conv1 = nn.Sequential(
                nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False),
                nn.BatchNorm2d(64),
                nn.ReLU(),
            )
            self.layer1 = self.make_layer(ResidualBlock, 64,  2, stride=1)
            self.layer2 = self.make_layer(ResidualBlock, 128, 2, stride=2)
            self.layer3 = self.make_layer(ResidualBlock, 256, 2, stride=2)
            self.layer4 = self.make_layer(ResidualBlock, 512, 2, stride=2)
            self.fc = nn.Linear(512, num_classes)
    
        def make_layer(self, block, channels, num_blocks, stride):
            strides = [stride] + [1] * (num_blocks - 1)   #strides=[1,1]
            layers = []
            for stride in strides:
                layers.append(block(self.inchannel, channels, stride))
                self.inchannel = channels
            return nn.Sequential(*layers)
    
        def forward(self, x):
            out = self.conv1(x)
            out = self.layer1(out)
            out = self.layer2(out)
            out = self.layer3(out)
            out = self.layer4(out)
            out = F.avg_pool2d(out, 4)
            out = out.view(out.size(0), -1)
            out = self.fc(out)
            return out
    
    
    def ResNet18():
    
        return ResNet(ResidualBlock)
    

    Pytorch上训练:

    所选数据集为Cifar-10,该数据集共有60000张带标签的彩色图像,这些图像尺寸32*32,分为10个类,每类6000张图。这里面有50000张用于训练,每个类5000张,另外10000用于测试,每个类1000张。训练时人为修改学习率,当epoch:[1-135] ,lr=0.1;epoch:[136-185], lr=0.01;epoch:[186-240] ,lr=0.001。训练代码如下:

    import torch
    import torch.nn as nn
    import torch.optim as optim
    import torchvision
    import torchvision.transforms as transforms
    import argparse
    from resnet import ResNet18
    import os
    
    # 定义是否使用GPU
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    
    # 参数设置,使得我们能够手动输入命令行参数,就是让风格变得和Linux命令行差不多
    parser = argparse.ArgumentParser(description='PyTorch CIFAR10 Training')
    parser.add_argument('--outf', default='./model/', help='folder to output images and model checkpoints') #输出结果保存路径
    args = parser.parse_args()
    
    # 超参数设置
    EPOCH = 135   #遍历数据集次数
    pre_epoch = 0  # 定义已经遍历数据集的次数
    BATCH_SIZE = 128      #批处理尺寸(batch_size)
    LR = 0.01        #学习率
    
    # 准备数据集并预处理
    transform_train = transforms.Compose([
        transforms.RandomCrop(32, padding=4),  #先四周填充0,在吧图像随机裁剪成32*32
        transforms.RandomHorizontalFlip(),  #图像一半的概率翻转,一半的概率不翻转
        transforms.ToTensor(),
        transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)), #R,G,B每层的归一化用到的均值和方差
    ])
    
    transform_test = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010)),
    ])
    
    trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform_train) #训练数据集
    trainloader = torch.utils.data.DataLoader(trainset, batch_size=BATCH_SIZE, shuffle=True, num_workers=2)   #生成一个个batch进行批训练,组成batch的时候顺序打乱取
    
    testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform_test)
    testloader = torch.utils.data.DataLoader(testset, batch_size=100, shuffle=False, num_workers=2)
    # Cifar-10的标签
    classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
    
    # 模型定义-ResNet
    net = ResNet18().to(device)
    
    # 定义损失函数和优化方式
    criterion = nn.CrossEntropyLoss()  #损失函数为交叉熵,多用于多分类问题
    optimizer = optim.SGD(net.parameters(), lr=LR, momentum=0.9, weight_decay=5e-4) #优化方式为mini-batch momentum-SGD,并采用L2正则化(权重衰减)
    
    # 训练
    if __name__ == "__main__":
    	if not os.path.exists(args.outf):
    		os.makedirs(args.outf)
        best_acc = 85  #2 初始化best test accuracy
        print("Start Training, Resnet-18!")  # 定义遍历数据集的次数
        with open("acc.txt", "w") as f:
            with open("log.txt", "w")as f2:
                for epoch in range(pre_epoch, EPOCH):
                    print('\nEpoch: %d' % (epoch + 1))
                    net.train()
                    sum_loss = 0.0
                    correct = 0.0
                    total = 0.0
                    for i, data in enumerate(trainloader, 0):
                        # 准备数据
                        length = len(trainloader)
                        inputs, labels = data
                        inputs, labels = inputs.to(device), labels.to(device)
                        optimizer.zero_grad()
    
                        # forward + backward
                        outputs = net(inputs)
                        loss = criterion(outputs, labels)
                        loss.backward()
                        optimizer.step()
    
                        # 每训练1个batch打印一次loss和准确率
                        sum_loss += loss.item()
                        _, predicted = torch.max(outputs.data, 1)
                        total += labels.size(0)
                        correct += predicted.eq(labels.data).cpu().sum()
                        print('[epoch:%d, iter:%d] Loss: %.03f | Acc: %.3f%% '
                              % (epoch + 1, (i + 1 + epoch * length), sum_loss / (i + 1), 100. * correct / total))
                        f2.write('%03d  %05d |Loss: %.03f | Acc: %.3f%% '
                              % (epoch + 1, (i + 1 + epoch * length), sum_loss / (i + 1), 100. * correct / total))
                        f2.write('\n')
                        f2.flush()
    
                    # 每训练完一个epoch测试一下准确率
                    print("Waiting Test!")
                    with torch.no_grad():
                        correct = 0
                        total = 0
                        for data in testloader:
                            net.eval()
                            images, labels = data
                            images, labels = images.to(device), labels.to(device)
                            outputs = net(images)
                            # 取得分最高的那个类 (outputs.data的索引号)
                            _, predicted = torch.max(outputs.data, 1)
                            total += labels.size(0)
                            correct += (predicted == labels).sum()
                        print('测试分类准确率为:%.3f%%' % (100 * correct / total))
                        acc = 100. * correct / total
                        # 将每次测试结果实时写入acc.txt文件中
                        print('Saving model......')
                        torch.save(net.state_dict(), '%s/net_%03d.pth' % (args.outf, epoch + 1))
                        f.write("EPOCH=%03d,Accuracy= %.3f%%" % (epoch + 1, acc))
                        f.write('\n')
                        f.flush()
                        # 记录最佳测试分类准确率并写入best_acc.txt文件中
                        if acc > best_acc:
                            f3 = open("best_acc.txt", "w")
                            f3.write("EPOCH=%d,best_acc= %.3f%%" % (epoch + 1, acc))
                            f3.close()
                            best_acc = acc
                print("Training Finished, TotalEPOCH=%d" % EPOCH)
    
    
    

    实验结果:best_acc= 95.170%

    这里写图片描述
    (损失图是matlab画的,用保存下来的txt日志)

    展开全文
  • 本篇文章将分享图像分类原理,并介绍基于KNN、朴素贝叶斯算法的图像分类案例。基础性文章,希望对你有所帮助。同时,该部分知识均为杨秀璋查阅资料撰写,转载请署名CSDN+杨秀璋及原地址出处,谢谢!!
  • 文章目录深度学习-07(PaddlePaddle图像分类)图像分类概述概述什么是图像分类图像分类粒度图像分类发展历程图像分类问题的挑战常用数据集介绍MNIST数据集CIFAR10数据集ImageNet数据集FDDB人脸数据集WIDER Face数据集...
  • 遥感图像分类就是以计算机系统为支撑环境,利用模式识别技术与人工智能技术相结合,根据遥感图像中目标地物的各种影像特征,结合专家知识库中目标地物的解译经验和成像规律等知识进行分析和推理,实现对遥感图像的...
  • 遥感图像分类

    万次阅读 多人点赞 2019-01-28 21:36:02
    遥感图像分类 一、背景简介 遥感图像分类就是利用计算机通过对遥感图像中各类地物的光谱信息和空间信息进行分析,选择特征,将图像中各个像元按照某种规则或算法划分不同的类别,然后获得遥感图像中与实际地物的...
  • 高光谱图像分类(三)分类流程

    万次阅读 多人点赞 2016-10-18 16:33:35
    如何利用稀疏表示进行高光谱图像分类呢?前面我们已经了解了高光谱图像分类的一些基本概念,那这篇文章当中将讲解高光谱图像分类具体的流程是怎么样的。以下是高光谱图像分类的具体详细步骤: 1.导入indian_pines高...
  • OCT图像分类

    千次阅读 2019-02-27 17:59:43
    OCT图像分类1:相关论文统计 darknet分类OCT图像
  • 无监督图像分类问题是图像分类领域一项极具挑战的研究课题,本文介绍了无监督图像分类算法的发展现状,供大家参考学习。作者 | 郭冰洋编辑 | 言有三 1 简介近年来,深度学...
  • 1 构建图像分类器 训练一个卷积神经网络,用fastai库(建在PyTorch上)将图像分类为纸板,玻璃,金属,纸张,塑料或垃圾。使用了由Gary Thung和Mindy Yang手动收集的图像数据集。数据集下载地址如下,然后将其移至...
  • 欢迎大家来到图像分类专栏,本篇基于Pytorch完成一个多类别图像分类实战。作者| 郭冰洋编辑 | 言有三1 简介实现一个完整的图像分类任务,大致需要分为五个步骤:1、...
  • 欢迎大家来到《图像分类》专栏,今天讲述基于pytorch的细粒度图像分类实战!作者&编辑 | 郭冰洋 1 简介针对传统的多类别图像分类任务,经典的CNN网络已经...
  • 一、图像分类 二、图像识别 三、图像检索 四、三者的联系 五、三者的区别 六、人脸检测 七、人脸识别 一、图像分类  图像分类是给定一幅测试图像,利用训练好的分类器判定它所属的类别,而分类器是利用带...
  • 网上有很多图像分类的代码,有很多是必须要在GPU上面才能跑的,因为我想在自己的电脑跑,所以很多都是不能用的,而且说实话很多对我这个小白来说,都很难看懂。所以我找了一个就是之间用CNN写的神经卷积模型用来进行...
  • 遥感图像分类技术

    千次阅读 2019-06-05 21:01:54
    什么是遥感图像分类技术? 图像分类是将土地覆盖类别分配给像素的过程。例如,这9个全球土地覆盖数据集将图像分为森林、城市、农业和其他类别。 https://gisgeography.com/free-global-land-cover-land-use-data/ ...
  • 欢迎大家来到图像分类专栏,类别不平衡时是很常见的问题,本文介绍了类别不平衡图像分类算法的发展现状,供大家参考学习。作者&编辑 | 郭冰洋 1 简介小伙伴们在利用...
  • 图像分类笔记

    千次阅读 2017-03-02 14:13:06
    声明:本文笔记是阅读知乎杜客的图像分类笔记系列而总结,文中不少语句参考了原文作者,请知晓。 1、分类问题 已有固定分类标签,对于输入的图像,预测其所属的分类标签。 2、问题难点 图像视角变化...
  • 高光谱图像分类 初学者指南 (Beginner’s Guide) This article provides detailed implementation of different classification algorithms on Hyperspectral Images(HSI). 本文提供了在高光谱图像(HSI)上不同分类...
  • 第4章 图像分类基础一张图片胜过千言万语。我们不断地攫取视觉内容,解释它的含义,并且存储它们以备后用。但是,对于计算机要解释一张图片的内容是很难的,因为计算机看到的图片是一个大的数字矩阵,它对图像传递的...
  • 细粒度图像分类(FGVC)---综述

    万次阅读 多人点赞 2019-04-28 16:28:02
    什么是细粒度图像分类 细粒度图像分类问题是对大类下的子类进行识别。细粒度图像分析任务相对通用图像(General/Generic Images)任务的区别和难点在于其图像所属类别的粒度更为精细。 以图1为例,通用图像分类其...
  • 深度学习之图像分类

    万次阅读 多人点赞 2019-03-28 15:18:16
    图像分类,核心是从给定的分类集合中给图像分配一个标签的任务。实际上,这意味着我们的任务是分析一个输入图像并返回一个将图像分类的标签。标签总是来自预定义的可能类别集。 示例:我们假定一个可能的类别集...
  • 网上有很多图像分类的代码,有很多是必须要在GPU上面才能跑的,因为我想在自己的电脑跑,所以很多都是不能用的,而且说实话很多对我这个小白来说,都很难看懂。所以我找了一个就是之间用CNN写的神经卷积模型用来进行...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 36,863
精华内容 14,745
关键字:

图像分类