图像分类就是已有固定的分类标签集合,对于新输入的图像,从分类标签集合中找出一个分类标签,最后把分类标签分配给该输入的对象。 具体过程:图像分类训练出的模型读取该图片的信息,并且生成该图片属于集合{cat,dog,hat,mug}中各个标签的概率。图像信息等价于一个三维数组,也是我们熟知的RGB,有3个颜色通道,分别是红、绿和蓝。
从计算机视觉算法角度,识别一个图像的类别有以下挑战:视角变化、大小变化、形变、遮挡、光照条件、背景干扰、类内差异等,这些因素的存在,对计算机视觉算法充满着挑战。
1.输入:输入是包含N个图像的集合,每个图像的标签是K种分类标签中的一种。这个集合称为训练集。 2.学习:这一步的任务是使用训练集来学习每个类到底长什么样。一般该步骤叫做训练分类器或者学习一个模型。 3.评价:让分类器来预测它未曾见过的图像的分类标签,并以此来评价分类器的质量。我们会把分类器预测的标签和图像真正的分类标签对比。
CIFAR-10是如今十分流行的图像分类数据集。它包含了60000张32x32的小图像,每张图像都有10种分类标签中的一种。这60000张图像被分为包含50000张图像的训练集和包含10000张图像的测试集。 上图左边是CIFAR-10数据库来的样本图像,右边第一列是测试图像,然后第一列的每个测试图像右边是使用Nearest Neighbor算法,根据像素差异,从训练集中选出的10张最类似的图片。
NN分类器的实现方法就是让两张图片首先分别使用向量表示他们,然后两个向量相减之后得到的向量和的大小就是两张图片的距离。这个距离越小,两张图片越相似。
以图片中的一个颜色通道为例来进行说明。两张图片使用L1距离来进行比较。逐个像素求差值,然后将所有差值加起来得到一个数值。如果两张图片一模一样,那么L1距离为0,但是如果两张图片很是不同,那L1值将会非常大。
下面是使用L1距离的Nearest Neighbor分类器的实现代码。如果用该代码测试CIFAR-10最终的准确率将达到38.6%,虽然比之前的10%进步许多,但离人类识别的准确率还差的很远。
import numpy as np class NearestNeighbor(object): def __init__(self): pass #以后实现的所有分类器都需要有这个api:train(x, y)函数,使用训练集的数据和标签进行训练 def train(self, X, y): self.Xtr = X self.ytr = y #predict(x)函数,用来预测输入的新数据的分类标签 def predict(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) # get the index with smallest distance Ypred[i] = self.ytr[min_index] # predict the label of the nearest example return Ypred与此同时,计算向量间距离还有L2距离,可以理解为计算两个向量间的欧式距离,公式如下: 在代码中的区别在于第一行,将上述代码第一行修改即可。
distances = np.sqrt(np.sum(np.square(self.Xtr - X[i,:]), axis = 1))L1和L2比较:在面对两个向量之间的差异时,L2比L1更加不能容忍这些差异。也就是说,相对于1个巨大的差异,L2距离更倾向于接受多个中等程度的差异。
k-Nearest Neighbor分类器的思想在于我们找最相似的k个图片的标签,然后让他们针对测试图片进行投票,最后把票数最高的标签作为对测试图片的预测。 所以当k=1的时候,k-Nearest Neighbor分类器就是Nearest Neighbor分类器。 上面示例展示了Nearest Neighbor分类器和5-Nearest Neighbor分类器的区别。不同颜色区域代表的是使用L2距离的分类器的决策边界。在NN分类器中,异常的数据点(比如:在蓝色区域中的绿点)制造出一个不正确预测的孤岛。5-NN分类器将这些不规则都平滑了,使得它针对测试数据的泛化能力更好。 注意,5-NN中也存在一些灰色区域,这些区域是因为近邻标签的最高票数相同导致的
k-NN分类器需要设定k值,那么选择哪个k值最合适的呢?我们可以选择不同的距离函数,比如L1范数和L2范数等,那么选哪个好?还有不少选择我们甚至连考虑都没有考虑到(比如:点积)。所有这些选择,被称为超参数(hyperparameter)。
验证集:从训练集中取出一部分数据用来调优以CIFAR-10为例,我们可以用49000个图像作为训练集,用1000个图像作为验证集。验证集其实就是作为假的测试集来调优。使用验证集来跑程序结束后,我们会作图分析出哪个k值表现最好,然后用这个k值来跑真正的测试集,并作出对算法的评价。 测试集:当你在设计机器学习算法的时候,应该把测试集看做非常珍贵的资源,不到最后一步,绝不使用它。从另一个角度来说,如果使用测试集来调优,实际上就是把测试集当做训练集,由测试集训练出来的算法再跑测试集,自然性能看起来会很好。
有时候,训练集数量较小(因此验证集的数量更小),人们会使用一种被称为交叉验证的方法,这种方法更加复杂些。还是用刚才的例子,如果是交叉验证集,我们就不是取1000个图像,而是将训练集平均分成5份,其中4份用来训练,1份用来验证。然后我们循环着取其中4份来训练,其中1份来验证,最后取所有5次验证结果的平均值作为算法验证结果。 这就是5份交叉验证对k值调优的例子。针对每个k值,得到5个准确率结果,取其平均值,然后对不同k值的平均表现画线连接。本例中,当k=7的时算法表现最好(对应图中的准确率峰值)。如果我们将训练集分成更多份数,直线一般会更加平滑(噪音更少)。