Skip to content

Latest commit

 

History

History
259 lines (148 loc) · 17.6 KB

图像分类流程.md

File metadata and controls

259 lines (148 loc) · 17.6 KB

图像分类流程

系列简介

本系列将介绍Stanford深度学习课程的主要内容,做以下说明:本系列不是对原视频翻译,而是对每一课的主要内容进行说明及补充,其中关于课程中的行政事务我们将不做说明。 由于水平有限,在文章中难免出现错误,希望各位多多包含,帮助指正。

本文为该课程第二篇,主要介绍图像分类的一般流程。

图像数据组成

这部分课程中没有,算是图像处理的最基本的知识。本文为没有做过图像处理或者不了解图片组成的读者进行一个简单的介绍。

图像就是通常使用相机、手机等设备拍摄的照片,真实世界的场景想要被计算机所识别,所存储,就必须要将照片转化为计算机可以识别的格式。图像又称为数字图像,因为在计算机里,图像是以数字形式存储的。

现在我们最常见的照片都是彩色照片,彩色照片一般为RGB格式或者CMYK格式,本文介绍RGB格式。R代表红色(Red),G代表绿色(Green),B代表蓝色(Blue),红色、绿色、蓝色被称为三原色,通过不同比例的三种颜色的组合可以组合出各种各样的颜色。通常衡量图片大小是以像素来衡量的,什么800万像素啊,1500万像素之类的。像素可以理解为一个小的正方形区域,比如下面一张图片,它的大小为358 * 360,也就是说该图片可以看成358列360行的方格,每一个小方格就是一个像素。

同时我们看到,图片是彩色图片,所以每个像素上面会有三个数值R(Red),G(Green),B(Blue),三个数值的取值范围都为0-255。对于R来说,0代表正红色,255代表白色,之间眼色渐进,共256种不同的红色,对于蓝色和绿色也是一样,所以RGB图像可以表示256 * 256 * 256 种不同的颜色。

若是将图片数据读入到计算机中,该图片就是一个三维的矩阵,矩阵大小为 358 * 360 * 3,358 代表宽度,360代表高度,3代表深度(R,G,B)。

图像分类的困难

图像分类很困难,因为有很多因素会影响分类结果,列举如下(图片来自于Stanford课程):

  1. 图片的亮度不同

从上面的四张图片都是猫,人一眼就能判断出来,但是对于计算机,这几张照片差异很大,比如前两张的猫都是暗色,且背景也是暗色,第三张的猫和背景都是亮色,而第四张猫是暗色,背景光为亮色。

  1. 图片中的物体有不同的形状

还是猫,不是每只猫的动作不一样,给计算机增加了不少难度。

  1. 环境遮挡

上图中的猫被环境中的物体遮挡住了部分身体,也会给计算机进行图像分类增加很大难度。特别第三张图片,人们可以根据露出的一个尾巴及周围的环境猜出那里极有可能是一只猫,但是这对计算机来说很难。

  1. 背景混淆

上面两个图中,猫的颜色和背景颜色很像,给计算机增加了区分难度。

  1. 图像重叠

图上都多只猫相互有重叠遮挡。

图像分类

分类的机器学习步骤一般如下:

  1. 收集数据,并将数据图片和对应的分类标记好
  2. 使用机器学习训练一个分类器
  3. 使用训练好的分类器判断新的图片的属类

最邻近算法

最邻近算法应该可以说是最简单的分类器了,算法思想如下:对于任意一个测试图片,查看测试图片与所有训练图片的距离,选出与测试图片距离最近的训练图片,然后将该训练图片的类别作为测试图片的类别。前面说到了距离最近,所以需要选择一个距离,常用的距离有L1和L2距离,这里以L1为例。 L1距离代表两个图片差的绝对值,下图为一个简单示例。

该算法实现起来也非常简单,对于一个分类器,需要一个训练的函数以及一个预测的函数。

import numpy as np

class NearestNeighbor:
  def __init__(self):
    pass
  
  def train(self, X, y):
    self.Xtr = X
    self.ytr = y
    
  def test(self, X):
    num_test = X.shape[0]
    Ypred = np.zeros(num_test, dtype = self.ytr.dtype)
    
    for i in xrange(num_test):
      distances = np.sum(np.abs(self.Xtr - X[i, :]), axis = 1)
      min_index = np.argmin(distances)
      Ypred[i] = self.ytr[min_index]
    return Ypred
  

上面的NearestNeighbor类中,有train和predict两个函数,train函数实现的很简单,就是记住训练数据,就是将训练图片与对应的分类记录下来。predict函数也很简单,就是对每一个测试图片,计算该测试图片与所有训练图片的L1距离,然后取出具有最小距离的图片的分类作为预测的类别。

上面的函数,假如训练样本有10000张照片,测试照片有100张,我们来看看完成上述的训练与预测需要计算次数。对于训练,显然只需要执行10000照片的存储。对于测试,对每一张测试照片我们都需要访问所有的10000张照片一次,所以若是100张照片,我们需要执行10000 * 100 = 1000000 次。这不是一个好的机器学习分类模型!一个好的机器学习分类模型我们希望预测的时间越短越好,相反训练时间稍长也没有关系,因为对于一个模型,一般情况下我们只需要训练一次,而需要预测很多次。

最邻近算法效果

以上的最邻近算法会产生什么样的效果呢?下面是一个示例:

上图中带颜色的点代表训练数据,不同的颜色代表不同的分类。现在假如有个测试样例,如果使用最邻近算法,那么这个测试样例该如何分布呢?后面的背景颜色区域标识着:若测试样本中间绿色区域,那么该测试样本会被分类为绿色类,对其他区域有相同的效果。从上面结果我们可以看到绿色区域的中间有个黄色区域,该黄色区域是由于训练数据中有一个黄色的点位于绿色点中间,该点可以理解为一个outlier。所以上面的最邻近算法给出的结果不是我们理想的结果,那么有什么办法解决这个问题呢?

K邻近算法

上面说了最邻近算法的效果,最邻近算法中会出现一些问题,那么可以以K邻近算法来优化这个问题。K邻近算法大概是这样的:训练时和最邻近算法相同,但是测试时,我们不再寻找与测试图片最近的训练图片,而是找到K张与该测试图片最近的训练图片,然后将这K个训练图片大部分所属的类别作为该测试图片的预测类别。

下面说一下如何实现K邻近算法(这部分课程没有)

import numpy as np
from scipy.stats import mode

class KNearestNeighbor:
  def __init__(self):
    pass
  
  def train(self, X, y):
    self.Xtr = X
    self.ytr = y
    
  def test(self, X, K):
    num_test = X.shape[0]
    Ypred = np.zeros(num_test, dtype = self.ytr.dtype)
    
    for i in xrange(num_test):
      distances = np.sum(np.abs(self.Xtr - X[i, :]), axis = 1)
      sort_index = np.argsort(distances)
      min_index = sort_index[:K]
      k_ytr = [self.ytr[tmp_index] for tmp_index in min_index]
      pred, pred_count = mode(k_ytr)
      if pred_count[0] == 1:
        Ypred[i] = -1
      else:
        Ypred[i] = pred[0]
    return Ypred
  

上述程序要想成功,我们需要设定图片的分类为数字,1,2,3,4等等。若是K个最邻近的训练数据中,每个数据都属于不同的分类,那么返回-1,说明该测试集不能判断属于哪个类。K邻近算法在预测的时候多了一个参数K,代表最近的K个点。显然当K等于1的时候,就是最邻近算法。

K邻近算法效果

首先我们来看一下不同的K对预测结果有什么影响,还是之前最邻近算法的例子

从这个结果可以看出,当K=1时,结果与最邻近算法一致。当K=3和K=5时的结果如后面两个图,图上白色区域是无法确定哪个分类区域。 同时下面的两个图展示了K=1时,不同的距离L1(曼哈顿距离)和L2(欧氏距离)对结果的影响。从图中可以看出,L1距离时,不同区域的分界线会更加的倾向于平行于坐标轴或者与坐标轴成45度角。

超参数

上面的K是由我们输入的,不是由数据训练得到的,则被称为超参数。超参数如何确定呢?超参数特别依赖于问题,不同的问题所需的超参数也不相同,通常要多试试来进行超参数调参。

下面介绍几种设置超参数的方法。(以K邻近算法为例)

  1. 选择预测数据最好的超参数

以所有数据作为训练集,然后预测这些数据,选择能预测得到最好结果的K。这样不好,因为超参数选择基于当前所有数据,对于新的数据的表现可能会很差,出现过拟合的现象。

  1. 将数据分为训练集和测试集

按照一定比例将数据分为训练集和测试集,以训练集训练模型,选择能使得测试集得到最好结果的K做超参数。这个感觉好像没什么问题了,其实这样的方式也不怎么好,因为我们选择的超参数已经使得现有的测试集最好了,可能会使得超参数在当前的测试集上过拟合,从而影响碰到新数据的效果。

  1. 将数据分为训练集,验证集和测试集

这个好,用训练集训练模型,验证集调试超参数,然后在完全没有见过的数据测试集上面看模型效果。对于测试的数据是在训练和调整超参数的时候完全没有见过的数据,所以若是在这个测试集上能有较好效果,在其他新的数据上也应该会有好的结果。

  1. 将数据分为训练集和测试集,然后将训练集在分成多分

训练时每次选出训练集中的一份作为验证集,其他做训练集,重复多次,将验证结果取平均。这种方法在小数据集上非常常用,但是在深度学习中很少使用。

图像分类与K邻近算法

上面介绍了K邻近算法,是一种非常直观,很容易想到,并且很容易理解的一种机器学习思想,但是该方法基本不会有人用来做图像分类。

原因如下:

  1. 在模型测试阶段非常缓慢(前文已经说过)

  2. 维度诅咒

想象一下,在某一个二维平面上有很多点,若是在某个很大的区域范围内都没有训练数据,那么当有一个测试数据在那个范围内时会出现什么样的结果呢?当然根据K邻近算法,这个点应该是可以找到一个分类的。虽然找到了,但是这个点距离同一类中的其它点的距离可能很大,这样的结果显然是不可信的。所以K邻近算法适用于训练数据分布比较紧密的情况。

如下图所示,若是在一维空间上,若是需要4个点能够使训练数据紧密分布,但是若是在二维空间上,此时需要 4 * 4 = 16 个点,在三维空间上需要 4 * 4 * 4 = 64个点,随着维度的增加是成指数增长的。

而图像分类,一张图像可能会有10000个像素,甚至1000000个像素,图像的像素就是数据的维度,对于这个维度大小,想要得到足够的训练数据那是不可能的。

  1. 图像上的距离度量信息量不大

如上图所示,最左边是原始图像,我们可以设计三种对图像的处理,第一种为在图像上加黑框(第二个图),将图像整体下移(第三个图),将图像整体变蓝(第四个图),可以设计移动黑框大小、移动距离、变蓝程度来使得后面的三种变化与原始图像的距离相等。

在这种情况下,完全不同的处理,确得到了相同的距离。这表明图像上的距离度量的信息量不大。

所以图像分类极少使用K邻近算法。

线性分类模型

先介绍一个数据集CIFAR-10,在前面的内容中就提到了,但是一直没有介绍。CIFAR-10数据集中总共有60000张图片,其中50000张为训练集,另外10000张为测试集,所有的这些照片都属于10个分类,包括飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船、卡车十类。这个一个典型的图像分类的数据集,其中每张图片的大小为 32 * 32 * 3,即宽度为32,高度为32,深度为3,所以总共有3072个像素。

若是将这3072个像素上的值用列向量equation表示,用equation表示每张图片上的像素数量,equation表示照片的数量。

那么对于第equation张照片我们可以使用equation表示该照片的类别与其3072个像素间的线性关系,类似于多元线性回归,但是在这个例子里面不在是二分类,而是有十分类,且令equation,那么刚才说的线性模型在所有的equation个分类上就可以表示为equation。其中equation为一个矩阵,其大小为equationequation为一个向量,其大小为equationequation为一个向量,其大小为equation,其值的大小可以分别表示是否属于这equation个分类的衡量标准。通常在操作时,还会在末尾加上一个偏移项,也是一个向量,大小为equation,然后线性模型就表示为equation

在上面的问题中,equation大小为equationequation的大小为equationequation的大小为equation

线性分类示例

下图为线性分类的一个示例。

假如下面的图片只有四个像素,且我们只需要将其分成三类,那么问题就简化成了上图所示的模型。上面的矩阵乘法计算之后得到的最后向量的值分别表示该图片是猫的数值,是狗的数值以及是船的数值。在这个示例中,狗的取值最大,所以被错误的分类为狗。显然通过调整上面的权重和偏移值可能得到正确的结果。

线性不可分问题

线性分类很直观,但是对于很多样的线性不可分问题难以解决。如下面的三个示例,比较直观是的第二个和第三个示例,第二个示例就是判断是否属于中间的圆环,显然是线性不可分的,第三个示例就是判断是否属于三个独立的圆区域,也是线性不可分的。

待续

  1. 损失函数(loss function)
  2. 最优化(optimization)
  3. 卷积神经网络(ConvNets)

索引

上一讲: Stanford深度学习课程|第一课卷积神经网络简介

下一讲: Stanford深度学习课程|第三课损失函数及最优化