步骤
算法思想很简单,分两步:
1、Memorize all data and labels
2、Predict the label of the most similar training image
训练函数:接收图片和标签,输出模型
def train(images,labels):
# Machine learing!
return model
预测函数:接收一个模型,对图片种类进行预测,返回标签
def predict(model,test_images):
# Use model to predict labels
return test_labels
示例数据集: CIFAR10
包含:10 classes 50,000 training images 10,000 testing images
将测试图片与所有训练图片进行比较,需要比较图片的方法,计算相似度就需要就有一个度量相似度的东西,例如L1距离
L1 distance:
d 1 ( I 1 , I 2 ) = ∑ p ∣ I 1 p − I 2 p ∣ d_1(I_1,I_2)=\sum_p∣I_1^p−I_2^p| d1(I1,I2)=p∑∣I1p−I2p∣
如果两张图片一模一样,那么L1距离为0,但是如果两张图片很是不同,那L1值将会非常大。
假设图像是4*4大小,那么只取左上角的元素进行以下计算,得到456处不同:
import numpy as np
class NearestNeighbor(object):
def __init__(self):
pass
def train(self, X, y):
""" X is N x D where each row is an example. Y is 1-dimension of size N """
# the nearest neighbor classifier simply remembers all the training data
self.Xtr = X
self.ytr = y
def predict(self, X):
""" X is N x D where each row is an example we wish to predict label for """
num_test = X.shape[0]
# lets make sure that the output type matches the input type
Ypred = np.zeros(num_test, dtype = self.ytr.dtype)
# loop over all test rows
for i in xrange(num_test):
# find the nearest training image to the i'th test image
# using the L1 distance (sum of absolute value differences)
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
缺点:训练过程快,而测试过程慢,与期望不符,较为落后。
从图上看实际运用的缺点:例如绿色区域里面出现了黄点,绿色区域插入了蓝色和粉色区域。
原理:
找最相似的k个图片的标签,然后让他们针对测试图片进行投票,最后把票数最高的标签作为对测试图片的预测。
可见k变大时不再出现噪声点,边界也更清晰平滑。
算法的描述:
1)计算测试数据与各个训练数据之间的距离;
2)按照距离的递增关系进行排序;
3)选取距离最小的K个点;
4)确定前K个点所在类别(标签)的出现频率;
5)返回前K个点中出现频率最高的类别作为测试数据的预测分类。
参考:https://www.cnblogs.com/ybjourney/p/4702562.html
d 2 ( I 1 , I 2 ) = ∑ p ( I 1 p − I 2 p ) 2 d_2(I_1,I_2)=\sqrt{\sum_p(I_1^p−I_2^p)^2} d2(I1,I2)=p∑(I1p−I2p)2
重要原则:可以看到L1在旋转坐标后,距离是变化的,而L2不会,因此如果输入的特征向量中的一些值对于输出有非常重要的意义或影响,这个时候应该使用L1距离,但是如果特征向量只是某个空间中的一个通用向量,用L2会好一点。
通过指定不同的距离度量,可将KNN分类器泛化到不同类型的数据上。
**超参数:**诸如对K、距离度量的选择。 不是机器学习的参数,而是人为为算法设置的。
设置超参数的方法一:
将数据分为训练集,验证集和测试集(train,validation,test)
在train上用不同的超参数来训练算法;再在val上进行评估,选择在val上表现最好的一组超参数;最后把这组在val上表现最好的分类器运用在测试集上,得到结果。
注意:必须分割验证集和测试集。
方法二:交叉验证
常用于小数据集,在深度学习中不常用。
先取部分数据作为测试集,再将剩余训练数据平均分成多份,其中1份用来验证,其余用来训练。然后轮流将每1份当做验证集,最后取所有验证结果的平均值作为算法验证结果。
示例:
这就是5份交叉验证对k值调优的例子。针对每个k值,得到5个准确率结果,取其平均值,然后对不同k值的平均表现画线连接。本例中,当k=7的时算法表现最好(对应图中的准确率峰值)。如果我们将训练集分成更多份数,直线一般会更加平滑(噪音更少)。
缺点:
1、测试时间长
2、L1、L2距离不太适用于比较图像,不适合表示图像视觉感知上的差异。
3、维度灾难
小结
简要说来:
如果你希望将k-NN分类器用到实处(最好别用到图像上,若是仅仅作为练手还可以接受),那么可以按照以下流程:
函数形式:
f ( x , W ) = W x + b f(x,W)=Wx+b f(x,W)=Wx+b
参数化方法,总结对训练数据的认识并用到W中,测试时不再需要训练数据。
重点这里面注意行的颜色,W的每一行都对应了一个分类。把训练好的单独的每一行的提取出来,还原为图像,就可以看到线性分类器是如何根据什么特征进行分类的。
这里要注意一个概念:图像分类模板,这个模板在CNN里面和每个图片进行点乘后,相应分类就会得到比较大的结果。
线性分类究竟在做些什么, 如何解释线性分类器呢?
其实参数 W 的每一行对应的是一个类别的分类器,改变 W 的一行相当于向不同方向旋转在像素空间的线,改变 b 相当于对这条线做平移。
- 可以把 W 看成是模板匹配,W 的每一行相当于对应类的一个模板,通过内积的形式去找到最高的分数(对应的类别)。
- 也可以认为线性分类仍然在求解最邻近,只是这次不是将测试图像与训练集做内积,而是与 W 的一行做内积,以内积来作为类模板与测试图片的距离,而不是使用 L1 或 L2 distance。
线性分类器的限制
线性分类器无法划分multi model data。