1.1 图像分类和Nearest Neighbor分类器

图像分类

目标

所谓图像分类问题,就是已有固定的分类标签集合,然后对于输入的图像,从分类标签集合中找出一个分类标签,最后把分类标签分配给该输入图像。

例子

对于计算机来说,图像是一个由数字组成的巨大的3维数组,每个数字都是在范围0-255之间的整型,其中0表示全黑,255表示全白,有3个颜色通道,分别是红、绿和蓝(简称RGB)。

在这个例子中,猫的图像大小是宽248像素,高400像素,如此,该图像就包含了248X400X3=297600个数字,我们的任务就是通过这些数字给图像贴上“猫”的标签。

1.1 图像分类和Nearest Neighbor分类器

困难和挑战

1.1 图像分类和Nearest Neighbor分类器

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

数据驱动方法

数据驱动方法:给计算机很多数据,让其学习到每个类的外形。

视觉分类的训练集:

1.1 图像分类和Nearest Neighbor分类器

图像分类流程

  • 输入:输入是包含N个图像的集合,每个图像的标签是K种分类标签中的一种。这个集合称为训练集。
  • 学习:这一步的任务是使用训练集来学习每个类到底长什么样。一般该步骤叫做训练分类器或者学习一个模型。
  • 评价:让分类器来预测它未曾见过的图像的分类标签,并以此来评价分类器的质量。我们会把分类器预测的标签和图像真正的分类标签对比。

Nearest Neighbor分类器

CIFAR-10数据集

CIFAR-10数据集包含了60000张32X32的小图像。每张图像都有10种分类标签中的一种。这60000张图像被分为包含50000张图像的训练集和包含10000张图像的测试集。

1.1 图像分类和Nearest Neighbor分类器

左边:从CIFAR-10数据库来的样本图像。

右边:第一列是测试图像,然后第一列的每个测试图像右边是使用Nearest Neighbor算法,根据像素差异,从训练集中选出的10张最类似的图片。

Nearest Neighbor

最简单的方法就是逐个像素比较,最后将差异值全部加起来。换句话说,就是将两张图片先转化为两个向量I1和I2,然后计算它们的L1距离,也叫作曼哈顿距离。

1.1 图像分类和Nearest Neighbor分类器

流程的图例:

1.1 图像分类和Nearest Neighbor分类器

逐个像素求差值,然后将所有差值加起来得到一个数值。如果两张图片一模一样,那么L1距离为0,但是如果两张图片很是不同,那L1值将会非常大。

代码示例: 

import pickle
import numpy as np
import os



def load_CIFAR_batch(filename):
    with open(filename, 'rb') as f:
        datadict = pickle.load(f, encoding='latin1')
        X = datadict['data']
        Y = datadict['labels']
        X = X.reshape(10000, 3, 32, 32).transpose(0, 2, 3, 1).astype("float")
        Y = np.array(Y)
        return X, Y


def load_CIFAR10(ROOT):
    dataTrain = []
    labelTrain = []

    for b in range(1, 6):
        f = os.path.join(ROOT, 'data_batch_%d' % (b,))
        X, Y = load_CIFAR_batch(f)
        dataTrain.append(X)
        labelTrain.append(Y)
        X_train = np.concatenate(dataTrain)
        Y_train = np.concatenate(labelTrain)

    del X, Y
    X_test, Y_test = load_CIFAR_batch(os.path.join(ROOT, "test_batch"))
    return X_train, Y_train, X_test, Y_test

 

X_train, Y_train, X_test, Y_test = load_CIFAR10("E:/tensor/cifar-10_data/cifar-10-batches-py")


Xtr_rows = X_train.reshape(X_train.shape[0], 32 * 32 * 3)
Xte_rows = X_test.reshape(X_test.shape[0], 32 * 32 * 3)


class NearestNeighbor(object):

    def __init__(selfs):
        pass

    def train(self, X, y):
        self.Xtr = X
        self.ytr = y

    def predict(self, X):
        num_test = X.shape[0]
        Ypred = np.zeros(num_test, "float")

        for i in range(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

nn = NearestNeighbor()
nn.train(Xtr_rows, Y_train)
Yte_predict = nn.predict(Xte_rows)
print('accuracy: %f' % (np.mean(Yte_predict == Y_test)))  

准确率能达到38.6%。这比随机猜测的10%要好,但是比人类识别的水平(据研究推测是94%)和卷积神经网络能达到的95%还是差多了。  

计算得到的准确率为35.4%,比刚才低了一点。

距离选择

计算向量间的距离有很多种方法,另一个常用的方法是L2距离,也叫作欧氏距离,L2距离的公式如下:

1.1 图像分类和Nearest Neighbor分类器

Numpy中,我们只需要替换上面代码中的1行代码就行:

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

实际使用时不一定使用np.sqrt函数,因为平方根函数是单调函数,它对不同距离的绝对值求平方根虽然改变了数值大小,但依然保持了不同距离大小的顺序。

L1和L2比较

在面对两个向量之间的差异时,L2比L1更加不能容忍这些差异。也就是说,相对于1个巨大的差异,L2距离更倾向于接受多个中等程度的差异。

转载于:https://www.cnblogs.com/xiaojianliu/articles/9987395.html