이미지 분류 및 KNN

1 명 화상 분류

1.1 영상 분류 무엇입니까

소위 이미지 분류 문제는 이미 다음 이미지 입력, 분류 라벨 세트에서 분류 라벨을 식별, 분류 라벨 세트를 고정하고, 입력 이미지에 할당 마지막으로 분류 레이블입니다. 하지만 그것은 매우 간단한 것,하고 실용적인 다양한 응용 프로그램이있을 수 있습니다 컴퓨터 비전의 핵심 문제 중 하나입니다. 많은 컴퓨터 비전 (예컨대 물체 검출 및 분류 등) 겉보기 다른 문제는, 화상 분류에 기인 할 수있다.

예를 맛 경우 :

다음 도면은 예를 들면, 화상 분류 모델 화상을 판독하고, 화상이 설정된 각 라벨 {고양이, 개, 모자, 잔} 확률 생성 속한다. 컴퓨터, 이미지 번호의 거대한 3 차원 배열이고, 주목해야한다. 이 예에서, 400 픽셀 높이 고양이 화상 사이즈 248 개 픽셀 폭 (RGB 라 함), 즉, 적색, 녹색, 청색의 세 가지 색상 채널이있다. 따라서, 화상은 248X400X3 = 297,600 자리를 포함하여 각 숫자 255은 전체 백색이고, 0은 전체 흑색을 나타내는 0 ~ 255의 범위에서의 정수이다. 우리의 작업과 같은 간단한 라벨에 숫자의이 수백만을하는 것입니다 "고양이."

이미지 분류 작업, 즉, 주어진 이미지에 대해,이 범주 레이블에 속하는 것으로 예측 (또는 다른 일련의 라벨에 속하는 가능성을 부여됩니다). 이미지는 3 차원 어레이는 상기 어레이 요소는 0 내지 255의 정수의 범위이다. X 높이 X3 폭 크기 어레이, 3에있어서, 상기 적색, 녹색 및 청색 세 가지 색상 채널에 의해 표현된다.

어려움 1.2 이미지 분류 작업

시각적 개념으로 "고양이"로 확인 된 사람에 대해서는 매우 간단하지만, 컴퓨터 비전 알고리즘의 관점에서 가치가 숙고. 이하에, 우리는 이미지를 3 차원 배열로 표현되어 있음을 기억하는 화상 인식 컴퓨터 비전 알고리즘에서 발생하는 어려움의 일부를 열거 한 배열 요소의 휘도 값이다.

각도 (관측점 변형)보기 : 카메라 각도들로부터 동일한 개체 것은 나타낼 수도있다.
크기 (규모 변화)의 변화 : (실제 크기도 다릅니다에서뿐 아니라 사진에) 시각적 객체의 크기는 일반적으로 변경됩니다.
변형 (변형)은 : 큰 변화가있을 것입니다, 많은 것들을 불변없는 모양입니다.
폐색 (폐색) : 대상체가 차단 될 수있다. 때때로 (소 등 여러 픽셀과 같은) 물체의 일부만을 볼 수있다.
조명 조건 (조명 조건) : 화소 레벨에서 광의 영향은 매우 크다.
백그라운드 간섭 (배경 클러) : 개체 식별하는 것이 어렵게 배경에 혼입 될 수있다.
차이점 (클래스 내 변화) 카테고리 : 객체들의 개별 큰 클래스의 형상의 차이 등의 자 등. 개체의이 클래스의 여러 객체는 자신의 모양으로 각이있다.

1.3 방법 및 프로세스 이미지 분류

1.3.1 방법

어떻게 알고리즘 영상 분류를 쓰기? 이것과는 정렬 알고리즘하지만 상당히 다른 물품. 어떻게 이미지 알고리즘에서 인정 고양이를 작성하는? 그것은 가능하지 않는 것 같습니다. 컴퓨터에 데이터를 많이하고 학습 알고리즘을 구현, 컴퓨터 학습을하자 : 따라서, 직접 말에 명시된 것보다 코드에서 객체의 모든 종류의 모습입니다, 우리가 애들을 데리고과 방법을 그림과 유사한 개체를 식별하기 위해 아이들을 가르치는 것이 더 낫다 각 클래스에 모양입니다. 이 방법은 데이터 구동 방법 .

1.3.2 프로세스

화상 분류 엘리먼트는 입력 화소 값의 배열 한 다음에 분류 라벨을 할당한다. 다음과 같이 전체 프로세스는 다음과 같습니다

입력 : N 이미지의 컬렉션, 라벨의 K 종류의 라벨의 각 이미지를 포함하는 입력. 이 세트는 훈련 세트라고합니다.
학습 :이 단계의 작업은 같은 말 모양의 각 클래스를 배울 설정 한 훈련을 사용하는 것입니다. 이 단계는 일반적으로 교육 또는 분류 모델을 학습이라고합니다.
평가 :하자 분류는 한 번도 본 적이 분류 라벨 이미지를 예측하고, 분류의 품질을 평가하기 위해 수 있습니다. 실제 분류 라벨 비교는 우리가 예측 라벨과 이미지를 분류합니다. 의심 할 여지없이, 분류 이미지 분류와 일치하는 경우 실제 카테고리 라벨의 라벨을 예측하고, 그와 같은 상황에 더 좋은 일이있다.

2 가장 가까운 이웃 분류

의는 가장 가까운 이웃 분류를 달성 할 수 있습니다. 이 컨볼 루션 신경망 분류와 아무것도 할하지만, 거기에 약간의 실제적인 사용은했지만 구현하여 문제가 기본적인 이해가 해결하는 영상 분류 방법에 대한 독자 수 있습니다.

2.1 CIFAR10

매우 인기있는 이미지 분류 데이터 세트는 CIFAR-10입니다. 이 데이터 세트는 32 X32의 60,000 작은 이미지가 포함되어 있습니다. 각각의 이미지는 분류 태그 10 종을 가지고있다. 이 이미지 (60 개) 000 50 000으로 분할 이미지는 트레이닝 세트, 테스트 세트는 10,000 화상을 포함한다. 그림에서 당신은 10 개 임의의 사진 (10 개) 클래스를 참조하실 수 있습니다.

왼쪽 : CIFAR-10 데이터베이스의 샘플 이미지입니다. 오른쪽 : 첫 번째 열은 시험 화상, 오른쪽 각 시험 이미지 후 첫 번째 열 (10 명)과 가장 유사한 화상을 선택 트레이닝 세트로부터의 픽셀의 차이에 기초하여, 가장 가까운 이웃 알고리즘을 사용하는 것이다.

2.2 인접 이웃 간단한 이미지 기반 종류 판단

우리가 CIFAR-10 훈련 세트로 50000 개 사진 (각 분류 5000)의, 우리는 테스트 집합으로 만 남아있는 희망이 그들을 라벨 표시 줄 것을 가정하자. 가장 가까운 이웃 알고리즘은 트레이닝 세트 및 테스트 이미지를 비교 한 다음이 테스트 이미지에 할당 된 훈련 설정 사진을 라벨 가장 유사한 생각하는 각 그림을 개최합니다. 오른쪽 위의 그림과 같은 결과를 표시합니다. 분류 위의 주 10 만 세 정확합니다. 검은 배경에 빨간색 스포츠카가 매우 강력하기 때문에 말은 스포츠카로 잘못 분류 그래서 예를 들어, 8 호선의 경우, 말, 빨간 스포츠카로 분류된다.

그래서 구체적으로 어떻게 두 사진을 비교? 본 실시 예에서는, 비교 32x32x3의 화소 블록이다. 가장 쉬운 방법은 픽셀별로 비교하여, 모두 함께 차의 최종 값이다. 즉, 두 벡터로 처음 두 이미지 \ (I_ {1} \)(\ {2} I_ \의) 한 다음 그 거리 L1를 산출 :

$ D_ {1} \ 좌회전 (I_ {1} I_는 {2} \ 오른쪽) = \ sum_ {P} \ 왼쪽 | I_ {1} ^ {P} -i_ {2} ^ {P} \ 오른쪽 | $

여기에 모든 픽셀에 대한 요약이다. 다음은 전체 프로세스 전설의 비교입니다 :

채널의 컬러 화상으로 예를 들어 설명한다. 비교를 위해 L1 거리를 사용하여 두 사진. 차이 값을 얻기 위해 모두 함께 다음 화소 단위 차분하고. 두 이미지 똑같은 경우, 거리 L1은 0이지만, 두 이미지는 매우 상이하고, L1의 값이 매우 클 것으로 경우.

거리 L2는 뷰의 기하학적 관점에서 여러 가지 방법이 있습니다 벡터 사이의 거리, 일반적으로 사용되는 방법을 계산하는 것이 이해 될 것이다 두 벡터 사이의 유클리드 거리를 계산한다. 거리 다음 공식을 (L2) :

$ D_는 {2} \ 좌회전 (I_ {1} I_ {2} \ 오른쪽) = \ SQRT {\ sum_ {P} \ 좌회전 (I_ {1} ^ {P} -i_ {2} ^ {P} \ 오른쪽) ^ {2}} $

두 메트릭을 비교하는 것은 매우 흥미 롭다. 두 벡터 사이의 차이의면에서,이 차이가 L1보다 더 허용 할 수없는 (L2). 즉, 큰 차이에 대하여, L2 거리가 더 온건 한 차이를 받아 들일 경향이있다.

在cifar10数据集上实现最近邻算法:

# -*- coding: utf-8 -*-
#! /usr/bin/env python
#coding=utf-8

import os
import pickle
import numpy as np

def load_CIFAR_batch(filename):
    """
    cifar-10数据集是分batch存储的,这是载入单个batch

    @参数 filename: cifar文件名
    @r返回值: X, Y: cifar batch中的 data 和 labels
    """

    with open(filename,'rb') as f:
        datadict=pickle.load(f,encoding='bytes')

        X=datadict[b'data']
        Y=datadict[b'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):
    """
    读取载入整个 CIFAR-10 数据集

    @参数 ROOT: 根目录名
    @return: X_train, Y_train: 训练集 data 和 labels
             X_test, Y_test: 测试集 data 和 labels
    """

    xs=[]
    ys=[]

    for b in range(1,6):
        f=os.path.join(ROOT, "data_batch_%d" % (b, ))
        X, Y=load_CIFAR_batch(f)
        xs.append(X)
        ys.append(Y)

    X_train=np.concatenate(xs)
    Y_train=np.concatenate(ys)

    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('data/cifar10/') 
# 把32*32*3的多维数组展平
Xtr_rows = X_train.reshape(X_train.shape[0], 32 * 32 * 3) # Xtr_rows : 50000 x 3072
Xte_rows = X_test.reshape(X_test.shape[0], 32 * 32 * 3) # Xte_rows : 10000 x 3072

class NearestNeighbor:
  def __init__(self):
    pass

  def train(self, X, y):
    """ 
    这个地方的训练其实就是把所有的已有图片读取进来 -_-||
    """
    # the nearest neighbor classifier simply remembers all the training data
    self.Xtr = X
    self.ytr = y

  def predict(self, X):
    """ 
    所谓的预测过程其实就是扫描所有训练集中的图片,计算距离,取最小的距离对应图片的类目
    """
    num_test = X.shape[0]
    # 要保证维度一致哦
    Ypred = np.zeros(num_test, dtype = self.ytr.dtype)

    # 把训练集扫一遍 -_-||
    for i in range(num_test):
      # 计算l1距离,并找到最近的图片
      distances = np.sum(np.abs(self.Xtr - X[i,:]), axis = 1)
      min_index = np.argmin(distances) # 取最近图片的下标
      Ypred[i] = self.ytr[min_index] # 记录下label

    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) ))

如果你用这段代码跑CIFAR-10,你会发现准确率能达到38.6%。这比随机猜测的10%要好,但是比人类识别的水平(据研究推测是94%)和卷积神经网络能达到的95%还是差多了。

注:python3实现的

3 K最近邻分类器

你可能注意到了,为什么只用最相似的1张图片的标签来作为测试图像的标签呢?这不是很奇怪吗!是的,使用k-Nearest Neighbor分类器就能做得更好。它的思想很简单:与其只找最相近的那1个图片的标签,我们找最相似的k个图片的标签,然后让他们针对测试图片进行投票,最后把票数最高的标签作为对测试图片的预测。所以当k=1的时候,k-Nearest Neighbor分类器就是Nearest Neighbor分类器。从直观感受上就可以看到,更高的k值可以让分类的效果更平滑,使得分类器对于异常值更有抵抗力。

上面示例展示了Nearest Neighbor分类器和5-Nearest Neighbor分类器的区别。例子使用了2维的点来表示,分成3类(红、蓝和绿)。不同颜色区域代表的是使用L2距离的分类器的决策边界。白色的区域是分类模糊的例子(即图像与两个以上的分类标签绑定)。需要注意的是,在NN分类器中,异常的数据点(比如:在蓝色区域中的绿点)制造出一个不正确预测的孤岛。5-NN分类器将这些不规则都平滑了,使得它针对测试数据的泛化(generalization)能力更好(例子中未展示)。注意,5-NN中也存在一些灰色区域,这些区域是因为近邻标签的最高票数相同导致的(比如:2个邻居是红色,2个邻居是蓝色,还有1个是绿色)。

k-NN分类器需要设定k值,那么选择哪个k值最合适的呢?我们可以选择不同的距离函数,比如L1范数和L2范数等,那么选哪个好?还有不少选择我们甚至连考虑都没有考虑到(比如:点积)。所有这些选择,被称为超参数(hyperparameter)。在基于数据进行学习的机器学习算法设计中,超参数是很常见的。一般说来,这些超参数具体怎么设置或取值并不是显而易见的。

你可能会建议尝试不同的值,看哪个值表现最好就选哪个。好主意!我们就是这么做的,但这样做的时候要非常细心。特别注意:决不能使用测试集来进行调优。当你在设计机器学习算法的时候,应该把测试集看做非常珍贵的资源,不到最后一步,绝不使用它。如果你使用测试集来调优,而且算法看起来效果不错,那么真正的危险在于:算法实际部署后,性能可能会远低于预期。这种情况,称之为算法对测试集过拟合。从另一个角度来说,如果使用测试集来调优,实际上就是把测试集当做训练集,由测试集训练出来的算法再跑测试集,自然性能看起来会很好。这其实是过于乐观了,实际部署起来效果就会差很多。所以,最终测试的时候再使用测试集,可以很好地近似度量你所设计的分类器的泛化性能。

好在我们有不用测试集调优的方法。其思路是:从训练集中取出一部分数据用来调优,我们称之为验证集(validation set)。以CIFAR-10为例,我们可以用49000个图像作为训练集,用1000个图像作为验证集。验证集其实就是作为假的测试集来调优。下面就是代码:

# 假定已经有Xtr_rows, Ytr, Xte_rows, Yte了,其中Xtr_rows为50000*3072 矩阵
Xval_rows = Xtr_rows[:1000, :] # 构建1000的交叉验证集
Yval = Y_train[:1000]
Xtr_rows = Xtr_rows[1000:, :] # 保留49000的训练集
Ytr = Y_train[1000:]

# 设置一些k值,用于试验
validation_accuracies = []
for k in [1, 3, 5, 7, 10, 20, 50, 100]:

    nn = NearestNeighbor() # 初始化一个最近邻对象
    nn.train(Xtr_rows, Ytr) # 训练...其实就是读取训练集
    Yval_predict = nn.predict(Xval_rows,k=k) # 预测
    # 比对标准答案,计算准确率
    acc = np.mean(Yval_predict == Yval)
    print ('accuracy: %f' % (acc,))

    # 输出结果
    validation_accuracies.append((k, acc))

关于上述的代码,预测阶段加入了新参数k,所以,修改predict函数如下:

def predict(self, X, k=1):
    """ 
    所谓的预测过程其实就是扫描所有训练集中的图片,计算距离,取最小的距离对应图片的类目
    """
    num_test = X.shape[0]
    # 要保证维度一致哦
    Ypred = np.zeros(num_test, dtype = self.ytr.dtype)

    # 把训练集扫一遍 -_-||
    for i in range(num_test):
      closest_y = []
      # 计算l1距离,并找到最近的图片
      distances = np.sum(np.abs(self.Xtr - X[i,:]), axis = 1)
      a = np.argsort(distances)[:k]#从小到大按照索引排序
      closest_y = self.ytr[a]
      np.sort(closest_y)#从小到大排序,改变原列表的值的顺序
      y =  np.bincount(closest_y)#统计各个元素出现的次数
      z = np.argmax(y)#结合上一步,得出出现最多的数值(整数时成立)
      Ypred[i] = z # 记录下label

    return Ypred

程序结束后,我们会作图分析出哪个k值表现最好,然后用这个k值来跑真正的测试集,并作出对算法的评价。

4 最近邻分类器的优劣

首先,Nearest Neighbor分类器易于理解,实现简单。其次,算法的训练不需要花时间,因为其训练过程只是将训练集数据存储起来。然而测试要花费大量时间计算,因为每个测试图像需要和所有存储的训练图像进行比较,这显然是一个缺点。在实际应用中,我们关注测试效率远远高于训练效率。其实,我们后续要学习的卷积神经网络在这个权衡上走到了另一个极端:虽然训练花费很多时间,但是一旦训练完成,对新的测试数据进行分类非常快。这样的模式就符合实际使用需求。

Nearest Neighbor分类器在某些特定情况(比如数据维度较低)下,可能是不错的选择。但是在实际的图像分类工作中,很少使用。因为图像都是高维度数据(他们通常包含很多像素),而高维度向量之间的距离通常是反直觉的。

上图中,右边3张图片和左边第1张原始图片的L2距离是一样的。很显然,基于像素比较的相似和感官上以及语义上的相似是不同的。

추천

출처www.cnblogs.com/Terrypython/p/10971866.html