CS231n- 第二讲 图像分类

What


图像分类为计算机视觉领域的核心问题之一,并且有着各种各样的实际应用。

以下图为例,图像分类模型读取该图片,并生成该图片属于集合 {cat, dog, hat, mug}中各个标签的概率。

需注意的是,计算机中的RGB图像存储为一个由数字构成的三维数组,0表示全黑,255表示全白。

preview

因此,图像分类的任务可表述为:对于一个给定的图像,预测它属于的那个分类标签(或者给出属于一系列不同标签的可能性)

 

Challenges


  • 视角变化(Viewpoint variation):同一个物体,摄像机可以从多个角度来展现。
  • 光照条件(Illumination conditions):在像素层面上,光照的影响非常大。
  • 形变(Deformation):很多东西的形状并非一成不变,会有很大变化。
  • 大小变化(Scale variation):物体可视的大小通常是会变化的(不仅是在图片中,在真实世界中大小也是变化的)。
  • 遮挡(Occlusion):目标物体可能被挡住。有时候有物体的一小部分(可以小到几个像素)是可见的。
  • 背景干扰(Background clutter):物体可能混入背景之中,使之难以被辨认。
  • 类内差异(Intra-class variation):一类物体的个体之间的外形差异很大,比如椅子。这一类物体有许多不同的对象,每个都有自己的外形。

   因此,面对以上所有变化及其组合,好的图像分类模型能够在维持分类结论稳定的同时,保持对类间差异足够敏感

preview

 

HOW


1. 数据驱动方法(Data-Driven Approach)

  • 收集图片和标签集
  • 使用机器学习训练一个分类器
  • 在新的图片上进行测试

2. Nearest Neighbor 分类器

假设现在我们有CIFAR-10的50000张图片(每种分类5000张)作为训练集,我们希望将余下的10000作为测试集并给他们打上标签。

Nearest Neighbor算法将会拿着测试图片和训练集中每一张图片去比较,然后将它认为最相似的那个训练集图片的标签赋给这张测试图片

那么具体如何比较两张图片呢?最简单的方法就是逐个像素比较,最后将差异值全部加起来。换句话说,就是将两张图片先转化为两个向量I_1和$I_2$,然后计算他们的L1距离:$$d_1(I_1,I_2)=\sum_{p}|I_1^p-I_2^p|$$

  • 优点:易于理解,实现简单;算法的训练过程只需要将训练集数据存储起来,训练耗费时间短
  • 缺点:测试要花费大量时间计算,因为每个测试图像都需要和所有存储的训练图像进行比较;而卷积神经网络虽然训练花费很多时间,但是一旦训练完成,对新的测试数据进行分类非常快。这样的模式就符合实际使用需求。

image

代码实现为:

 1 # 将CIFAR-10的数据加载到内存中,并分成4个数组:训练数据和标签,测试数据和标签
  2 Xtr, Ytr, Xte, Yte = load_CIFAR10('data/cifar10/') # a magic function we provide
  3 # flatten out all images to be one-dimensional
  4 Xtr_rows = Xtr.reshape(Xtr.shape[0], 32 * 32 * 3) # Xtr_rows becomes 50000 x 3072
  5 Xte_rows = Xte.reshape(Xte.shape[0], 32 * 32 * 3) # Xte_rows becomes 10000 x 3072
  6
  7 nn = NearestNeighbor() # create a Nearest Neighbor classifier class
  8 nn.train(Xtr_rows, Ytr) # train the classifier on the training images and labels
  9 Yte_predict = nn.predict(Xte_rows) # predict labels on the test images
 10 # and now print the classification accuracy, which is the average number
 11 # of examples that are correctly predicted (i.e. label matches)
 12 print 'accuracy: %f' % ( np.mean(Yte_predict == Yte) )
 13
 14 import numpy as np
 15
 16 class NearestNeighbor(object):
 17   def __init__(self):
 18     pass
 19
 20   def train(self, X, y):
 21     """ X is N x D where each row is an example. Y is 1-dimension of size N """
 22     # the nearest neighbor classifier simply remembers all the training data
 23     self.Xtr = X
 24     self.ytr = y
 25
 26   def predict(self, X):
 27     """ X is N x D where each row is an example we wish to predict label for """
 28     num_test = X.shape[0]
 29     # lets make sure that the output type matches the input type
 30     Ypred = np.zeros(num_test, dtype = self.ytr.dtype)
 31
 32     # loop over all test rows
 33     for i in xrange(num_test):
 34       # find the nearest training image to the i'th test image
 35       # using the L1 distance (sum of absolute value differences)
 36       distances = np.sum(np.abs(self.Xtr - X[i,:]), axis = 1)
 37       min_index = np.argmin(distances) # get the index with smallest distance
 38       Ypred[i] = self.ytr[min_index] # predict the label of the nearest example
 39
 40     return Ypred
View Code

3.K-Nearest Neighbors(KNN)

(1)实现思路与其只找最相近的那1个图片的标签,我们找最相似的k个图片的标签,然后让他们针对测试图片进行投票,最后取票数最高的标签  作为对测试图片的预测。

(2)联系:当k=1的时候,k-Nearest Neighbor分类器就是Nearest Neighbor分类器;从直观感受上就可以看到,k越大时,分类的效果更平滑,使得分类器对于异常值更有抵抗力。

image

(3)距离度量(Distance Metric)

  • L1(Manhattan)距离

    各像素差的绝对值的和,受限于坐标轴,表示为$d_1(I_1,I_2)=\sum_{p}|I_1^p-I_2^p|$

  • L2(Euclidean)距离

  各像素差的平方的和的开方,不受坐标轴限制,表示为$d_1(I_1,I_2)=\sqrt{\sum_{p}(I_1^p-I_2^p)^2}$

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

imageimage

(4) 超参数(Hyperparameter)

  • 找到最合适的 K distance

  • 将数据集分为训练集验证集测试集:训练集训练模型,在验证集设置超参数,最终在测试集评估性能

image

测试数据集只使用一次,即在训练完成后评价最终的模型时使用。如果你使用测试集来调优,而且算法看起来效果不错,那么真正的危险在于:算法实际部署后,性能可能会远低于预期,造成过拟合问题。因此,从训练集中取出一部分数据用来调优,称之为验证集(validation set)。验证集其实就是作为假的测试集来调优。程序结束后,我们会作图分析出哪个k值表现最好,然后用这个k值来跑真正的测试集,并作出对算法的评价。

  1 # assume we have Xtr_rows, Ytr, Xte_rows, Yte as before
  2 # recall Xtr_rows is 50,000 x 3072 matrix
  3 Xval_rows = Xtr_rows[:1000, :] # take first 1000 for validation
  4 Yval = Ytr[:1000]
  5 Xtr_rows = Xtr_rows[1000:, :] # keep last 49,000 for train
  6 Ytr = Ytr[1000:]
  7
  8 # find hyperparameters that work best on the validation set
  9 validation_accuracies = []
 10 for k in [1, 3, 5, 10, 20, 50, 100]:
 11
 12   # use a particular value of k and evaluation on validation data
 13   nn = NearestNeighbor()
 14   nn.train(Xtr_rows, Ytr)
 15   # here we assume a modified NearestNeighbor class that can take a k as input
 16   Yval_predict = nn.predict(Xval_rows, k = k)
 17   acc = np.mean(Yval_predict == Yval)
 18   print 'accuracy: %f' % (acc,)
 19
 20   # keep track of what works on the validation set
 21   validation_accuracies.append((k, acc))
View Code
  • 交叉验证(Cross-Validation):有时候,训练集数量较小(因此验证集的数量更小),人们会使用一种被称为交叉验证的方法,这种方法更加复杂些。还是用刚才的例子,如果是交叉验证集,我们就不是取1000个图像,而是将训练集平均分成5份,其中4份用来训练1份用来验证。然后其他4份 各份轮流作为验证集来验证,最后取所有5次验证结果的平均值作为算法验证结果。

     image

preview

(如上图所示:针对每个k值,得到5个准确率结果,取其平均值,然后对不同k值的平均表现画线连接。本例中,当k=7的时算法表现最好(对应图中的准确率峰值)。如果我们将训练集分成更多份数,直线一般会更加平滑(噪音更少))

(5)仅仅使用L1和L2范数来进行像素比较是不够的,图像更多的是按照背景和颜色被分类,而不是语义主体分身

preview

上图使用t-SNE的可视化技术将CIFAR-10的图片进行了二维排列,排列相近的图片L2距离小

参考链接:

[1] https://zhuanlan.zhihu.com/p/20894041?refer=intelligentunit

转载于:https://www.cnblogs.com/jngwl/articles/10263288.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值