CS231n卷积神经网络入门课程笔记_K近邻和线性分类方法

1 传统图像分类算法_K近邻 K-NearestNeighbor(KNN)

K近邻分类的原理:首先,最近邻算法是模型在训练时,记住每张图片的数据和这张图片对应的类别,预测的时候,算出测试集中的图片对应的数值与训练集中哪张图片的对应数值最接近,那么这个数值。最接近的图片对应的类别,就是当前图片的类别。接近程度用距离衡量,有两种L1和L2计算距离的方式。L1距离,就是两个图片对应位置像素值相减,取绝对值,再对差值矩阵求和。

最近邻算法,复杂度训练O(1),预测O(n),这与理想分类算法的需求正好相反,算法实现代码:

import numpy as np

class NearestNeighbor:
    '''n个输入,训练的复杂度是O(1),预测的复杂度是O(n)
    而我们想实现的是训练慢,预测很快的分类器
    '''
    def __init__(self):
        pass
    def train(self,X,y):
        '''memorize training data'''
        self.Xtr = X
        self.ytr = y

    def predict(self,X):
        '''for each test image:find closest train image ,predict label of nearest image'''
        #查看要预测数据的行数,即图片数,此时图片已经转化成行向量。
        num_test = X.shape[0]#shape函数返回数组某一维的维数值,0表示最外层,二维矩阵中代表矩阵的行数
        #创建一个num_test大小的空数组,用来存放num个预测数据的标签
        Ypred = np.zeros(num_test,dtype = self.ytr.dtype)

        #对每一行进行遍历,即每一个测试图片的数据
        for i in range(num_test):
            #找到距离第i个测试图片距离最近的测试图片,计算他们的L1距离
            distances = np.sum(np.abs(self.Xtr - X[i,:]),axis=1)#L1
            # distances = np.sqrt(np.sum(np.square(self.Xtr-X[i,:]),axis = 1)) #L2

            #找出最小距离对应的索引,对应的标签就是预测图片的标签
            min_index = np.argmin(distances)
            Ypred[i] = self.ytr[min_index]
        return Ypred

#我们把数据导入,分为四个数组,分别为训练集/标签,和测试集/标签。
# 其中Xtr包含了所有的50000张图片数据,Ytr为一维数组,包含了这50000张数据的标签(0-9).
Xtr, Ytr, Xte, Yte = load_CIFAR10('data/cifar10/') # 斯坦福大学的课程代码中提供的函数来导入数据

# 把所有图片变为一维向量
Xtr_rows = Xtr.reshape(Xtr.shape[0], 32 * 32 * 3) # Xtr_rows 变成 50000 x 3072
Xte_rows = Xte.reshape(Xte.shape[0], 32 * 32 * 3) # Xte_rows 变成 10000 x 3072
nn = NearestNeighbor() # 创建一个最近邻分类器的类,相当于初始化
nn.train(Xtr_rows, Ytr) # 把训练数据给模型,训练
Yte_predict = nn.predict(Xte_rows) # 预测测试集的标签
# 算一下分类的准确率,这里取的是平均值
print 'accuracy: %f' % ( np.mean(Yte_predict == Yte) )

其次,K近邻就是找出前K(K=1,3,5,取单数)个距离最近的图片,采用投票的方式,决定将该点归为多数点所在的那一类里。

K近邻分类方法在深度学习的应用:在有标签的数据集(train set)上进行训练,在验证数据集(validation set)上选择超参数(k和距离方程),在测试数据集(test set)上预测出分类结果。实现代码如下:

# 假设我们之前有 Xtr_rows, Ytr, Xte_rows, Yte 这几份数据
#  Xtr_rows 是 50,000 x 3072 的矩阵
Xval_rows = Xtr_rows[:1000, :] # 抽取前1000张作为评估集
Yval = Ytr[:1000]
Xtr_rows = Xtr_rows[1000:, :] # 其余的4900张作为训练集
Ytr = Ytr[1000:]
# 找到在评估集上表现做好的超参数
validation_accuracies = []
for k in [1, 3, 5, 10, 20, 50, 100]:
  # 使用确定的k值作用在评估集上
  nn = NearestNeighbor()
  nn.train(Xtr_rows, Ytr)
  # 这里假设我们有一个最近邻的类,可以把k值作为输入
  Yval_predict = nn.predict(Xval_rows, k = k)
  acc = np.mean(Yval_predict == Yval)
  print 'accuracy: %f' % (acc,)
  # 记录在评估集上每个k对应的准确率
  validation_accuracies.append((k, acc))

最后可以在每个k值对应的准确率画一张图,准确率最高的那个k作为最佳,在测试集上应用。

补充:

①xrang是python2中循环迭代用到的函数,在python3中已经归并到range()函数中,方法使用参数相同,可以直接改名字。

②曼哈顿距离代表两点之间在标准坐标轴两个方向上距离之差的绝对值,即折线距离。欧式距离是两点之间的直线距离。

③基本概念:

    参数(parameters),是由模型通过学习获得的参数,比如权重w或偏置值b;

    超参数(hyperparameters),是根据经验设定的,对权重w和偏置值起到重要影响的参数,比如迭代次数、隐藏层的层数、每层神经元的个数等。

     对于K近邻算法,其中,K值的取值、最佳距离L的计算方法的计算,依赖于具体问题或数据的特征,可多试几个组合取值,比较出最好。

④几个数据集:

训练集:即由N张图片组成的集合,每张图片都给了特定的类别标签。训练的过程,是让模型学习图片中各个类别大概是个什么样子,然后按照自己的理解能力(代表了模型或算法的好坏)记下来。验证和评估的过程,就是凭训练形成的记忆,来预测没看过的数据的标签,当然我们希望能跟真正的标签尽可能一致。

验证集:为选取超参数,在训练集中分出来部分数据,找出最好的超参数,防止出现过拟合,就是说算法在训练集上很准确,但是遇到test集上新的数据,就准确率不行了这种情况。

K近邻算法实现扩展:https://github.com/facebookresearch/faiss

2. 传统图像分类方法_线性分类 Linear Classification

参数化方法:每个图像的像素矩阵(可转化为单列矩阵X),经过函数f(X,W)=Wx+b,得到对应各个分类的得分,即该图像的分类结果(此处存有的疑问是:即便取得得分之后,如何从众多得分里边确定对应的分类,取最高?取最低?还是其他?为什么?答案是,这可以利用损失函数和优化来评估,会在下一节中讲到)。其中W是很多个参数或者权重。举例如下:

W矩阵是来自,各个分类在训练网络中得到的“统一化”的像素矩阵,转化成行向量的排列。b是“统一化”的像素矩阵中像素值绝对值的求和。(所谓“统一化”是,经转化后像素值具有可比性)

这个过程可以用代数、可视化、几何等角度进行解释,这直观地表现线性分类方法的原理和精度方面的不足:

3.总结:

(1)K近邻选取超参数调优的方法,就是分离出验证集,在验证集上尝试不同的超参数,保留最佳的那个K。

(2)数据量不足时,采用交叉验证,可以在寻找超参数时,减少数据本身的影响。

(3)算法在CIFAR-10数据集上有接近40%的准确率,存储需求和测试时算力要求较高。

(4)使用K近邻和线性分类方法进行图像分类时,实质上更多的是按照背景和颜色的像素值进行分类,而不是图像上具体的语义主体本身。

发布了16 篇原创文章 · 获赞 4 · 访问量 5869

猜你喜欢

转载自blog.csdn.net/qq_35345719/article/details/105028963