图像分类是计算机视觉中一个核心的任务。
现实图像与计算机识别之间的语义鸿沟?
一幅图像仅仅是一堆介于0-255之间数组成的表。**图像是一个由数字组成的巨大的3维数组。0表示全黑,255表示全白。
①视角变化,图像发生细微的变化,所有的像素点就会与之对应发生改变
②图像的曝光度,
③图像的变形,
④图像的遮挡物,
⑤图像背景的干扰,
⑥物种演化,
def classify_image(image):
# 执行一些操作
return image_label
不像例子中对数字进行排序,没有明显的方式编写算法实现识别一只猫或者其他的种类。
我们已经做出的尝试,找到图像的边缘,找到图像的棱角
①收集图像并有对应标签的数据集,
②使用机器去学习,训练处一个分类器
③在新的图像上来评估这个分类器
def train(images, labels):
# 机器学习
return model
def predict(model, test_images):
# 使用训练得到的模型去预测新的图像
return test_labels
数据集简介:CIFAR10
10个类别,50000训练集,10000测试集,每个图像是32x32x3
采用距离度量的方式比较图片
L1距离,曼哈顿距离: d1(I1,I2)=∑P|Ip1−Ip2| d 1 ( I 1 , I 2 ) = ∑ P | I 1 p − I 2 p |
import numpy as np
class NearestNeighbor:
def __init__(self):
pass
def train(self, X, y):
""" X形状(N,D),Y的形状(N,)"""
self.Xtr = X
self.ytr = y
def predict(self, X):
""" X的每行代表一个我们希望预测其标签的样本"""
num_test = X.shape[0]
# 确保程序的输入和输出的形状是匹配的
Ypred = np.zeros(num_test, dtype=self.ytr.dtype)
# 循环遍历所有测试行
for i in xrange(num_test):
# 找到和第i个训练样本最近的训练集图像
# 使用L1距离
distances = np.sum(np.abs(self.Xtr - X[i,:]), axis = 1)
min_index = np.argmin(distances) # 得到最小距离对应的索引
Ypred[i] = self.ytr[min_index] # 预测最近的样本的标签
return Ypred
最近邻分类器性能评估:
train O(1) predict O(n)
这太耗时了,不满足我们的需求。我们希望预测快,训练过程慢一点儿事可以接受的。
距离度量:
L1(曼哈顿距离): d1(I1,I2)=∑P|Ip1−Ip2| d 1 ( I 1 , I 2 ) = ∑ P | I 1 p − I 2 p |
L2(欧几里得距离): d2(I1,I2)=∑P(Ip1−Ip2)2−−−−−−−−−−−√ d 2 ( I 1 , I 2 ) = ∑ P ( I 1 p − I 2 p ) 2
超参数选择:
最好的K是什么?
最好的距离是什么?
超参数:我们设置的而不是算法学习的参数。特别依赖具体的问题,我们需要尝试不同的参数值,来看看哪个值使得分类器分的最好。绝对不能测试集来进行调优
设置超参数
①想法1:选择在整个数据集上预测最准的超参数。(不合理,当K为1时,该模型在训练数据上能够非常准确的实现预测)
②想法2:把整个数据集分为训练集和测试集,选择在测试集上预测准确的超参数(不合理,在新的数据集上不能非常准确的实现预测)
③想法2:把整个数据集分为训练集,验证集合测试集,在验证集预测选择合适的超参数,在测试集上对所选的超参数评估其是否合理(合理)
④想法4:交叉验证集,把数据分成许多份,把每一份都作为验证集预测求得超参数,再平均求他们的结果(在数据集很小的模型中是适用的,但是在深度学习模型中不能太过频繁的使用)
在实际引用中,人们不是很喜欢用交叉验证,主要是因为它会耗费较多的计算资源。一般直接把训练集按照50%~90%的比例分为训练集和验证集。但这也是根据具体情况来定的:如果超参数数量多,你可能就想用更大的验证集,而验证集数量不够,那么最好还是用交叉验证。至于分成几份比较好,一般都是分成3、5和10份。
分析
对图像分类问题一般不采用K近邻的算法,
①在测试阶段特别耗时,
②像素间的距离度量基本没有作用。
③维度灾难
k近邻分类器在某些特定的情况下(比如数据维度较低),可能是一个不错的选择。但是在实际图像分类工作中,很少使用。因为图像都是高维度数据(他们通常包含很多像素),而高维度向量之间的距离通常是反直觉的。
总结
①在图像分类中,我们拥有带有图像和标签的训练数据集,在测试数据集上预测标签
②K近邻分类器基于最近的样本预测测试数据集的标签
③什么样的距离度量和K是超参数
④一旦找到最优的超参数,就让算法以该参数在测试集跑且只跑一次,并根据测试结果评价算法。
①预测数据。对数据中特征归一化,使其平均值和单位方差为0。(图像中的像素都是同质的,不会表现出较大的差异分布,也就不需要标准化处理了)
②降维。如果数据是高维度的,考虑使用降维方法,比如PCA和随机投影
③降数据随机分入训练集和验证集。按照一般规律,70%~90%数据作为训练集。这个比例根据算法中有多少超参数,以及这些超参数对于算法的预期影响来决定。超参数越多,验证集越大。若担心验证集不够,可以使用交叉验证的方法。如果计算资源充足,使用交叉验证总是更加安全的(份数越多,效果越好,越耗费计算资源)
④在验证集上调优。尝试足够多的k,尝试L1和L2两种范数计算方式。
⑤如果分类器跑得太慢,尝试使用Approximate Nearest Neighbor库来加速这个过程,其代价是降低一些准确率。
⑥对最优的超参数做记录。千万不要在最终的分类器中使用验证集数据,这样做会破坏对于最优参数的估计。直接使用测试集来测试用最优参数设置好的参数模型,得到测试集数据的准确率,并以此作为KNN分类器在此数据集上的性能表现。
关于K近邻详解与代码实现见下一博客《图像分类(续)》!