cs231n-classification
1、L1距离
定义:
d
1
(
I
1
,
I
2
)
=
Σ
p
∣
I
1
p
−
I
2
p
∣
d_{1}(I_{1},I_2)=\Sigma_{p}|I_{1}^p-I_2^p|
d1(I1,I2)=Σp∣I1p−I2p∣
这里求和是对于图片中所有像素求和
- 读取图片,由于有RGB三原色,所以是三维向量
Xtr, Ytr, Xte, Yte = load_CIFAR10('data/cifar10/') # a magic function we provide
# flatten out all images to be one-dimensional
Xtr_rows = Xtr.reshape(Xtr.shape[0], 32 * 32 * 3) # Xtr_rows becomes 50000 x 3072
Xte_rows = Xte.reshape(Xte.shape[0], 32 * 32 * 3) # Xte_rows becomes 10000 x 3072
- train训练,本质就是保存训练集的信息(ALL)
nn = NearestNeighbor() # create a Nearest Neighbor classifier class
nn.train(Xtr_rows, Ytr) # train the classifier on the training images and labels
Yte_predict = nn.predict(Xte_rows) # predict labels on the test images
# and now print the classification accuracy, which is the average number
# of examples that are correctly predicted (i.e. label matches)
print 'accuracy: %f' % ( np.mean(Yte_predict == Yte) )
上述调用下面👇的代码:
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 range(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
这里的思想是先读取图片,之后将图片像素与训练集进行像素值之间的比较,分别记录每个的最小的差值,返回值为一组向量,代表该图片为各类的score(可以这么理解)
2、L2距离(欧氏距离)
定义:
d
2
(
I
1
,
I
2
)
=
Σ
p
(
I
1
p
−
I
2
p
)
2
d_2(I_1,I_2)=\sqrt{\Sigma_p(I_1^p-I_2^p)^2}
d2(I1,I2)=Σp(I1p−I2p)2 和
L1距离一样也是对所有像素求和
用python中的代码可以这样写
distances=np.sqrt(np.sum(np.square(self.Xtr-X[i,:]),axis=1))
在选择L2距离和L1距离时要根据实际情况来选择,L1距离与向量中各元素的位置有关(变换坐标系,结果亦会变化),L2距离与向量中各元素位置无关(不随坐标轴变化而变化)。
3、K-最近邻算法(KNN)
K最近邻算法,闻如其名,就是找所有距离Ypred
最小的前K个,这里可以是L1距离也可以是L2距离1

4、超参数调整的验证集
K-最近邻算法中要设置K
的值,但哪个数字合适?此外,对于距离函数:L1范数、L2范数及其它(比如点积)哪个更合适,这些选择称为超参数。
Warning⚠️:不能将测试集用于调整超参数,理想情况下,应把测试集留到最后。
Why?
这样做可能会过拟合测试集,在测试集上的结果可能很好,但是其泛用性可能就没那么好
那应该用什么数据进行调整呢?
将训练集分为两个部分:训练集以及验证集。以CIFAR-10为例,我们可以使用49,000个训练图像进行训练,而留出1,000个用于验证。此验证集实质上用作为伪测试集,用于调整超参数。
对于CIFAR-10,可能是这样的:
# assume we have Xtr_rows, Ytr, Xte_rows, Yte as before
# recall Xtr_rows is 50,000 x 3072 matrix
Xval_rows = Xtr_rows[:1000, :] # take first 1000 for validation
Yval = Ytr[:1000]
Xtr_rows = Xtr_rows[1000:, :] # keep last 49,000 for train
Ytr = Ytr[1000:]
# find hyperparameters that work best on the validation set
validation_accuracies = []
for k in [1, 3, 5, 10, 20, 50, 100]:
# use a particular value of k and evaluation on validation data
nn = NearestNeighbor()
nn.train(Xtr_rows, Ytr)
# here we assume a modified NearestNeighbor class that can take a k as input
Yval_predict = nn.predict(Xval_rows, k = k)
acc = np.mean(Yval_predict == Yval)
print 'accuracy: %f' % (acc,)
# keep track of what works on the validation set
validation_accuracies.append((k, acc))
在此过程中,我们可以绘制一个图表,以显示哪个值最有效,然后我们使用这些超参数,并在真正的测试集上进行测试
5、交叉验证
这是一种更为复杂的技术来进行超参数调整。
思想:与其随意选择前1000个数据点作为验证集和测试机,不如对k的某个特定值的好坏程度进行更好,更少的估计。通过遍历不同的验证集并平均这些验证集的性能。

通用数据拆分。给出了训练和测试集。训练集分为多个折叠(例如此处为5个折叠)。折叠1-4成为训练组。折叠(例如,此处的折叠5为黄色)表示为验证折叠,并用于调整超参数。交叉验证更进一步,并且与1-5分开,反复选择验证倍数的选择。这将被称为5倍交叉验证。最后,一旦对模型进行训练并确定了所有最佳超参数,就可以根据测试数据(红色)对模型进行一次评估。
在实践中,人们倾向于避免交叉验证,而倾向于使用单个验证拆分,因为交叉验证在计算上可能会很昂贵。人们倾向于使用的拆分比例介于训练数据的50%-90%之间,而其余部分则用于验证。但是,这取决于多个因素:例如,如果超参数的数量很大,则可能更喜欢使用更大的验证拆分。如果验证集中的示例数量很少(也许只有几百个左右),则使用交叉验证会更安全。在实践中可以看到的典型折叠数是3倍,5倍或10倍交叉验证。
6、KNN的优缺点
优点之一很明显:实施和理解非常简单,此外,分类器也不需要花费任何时间来进行训练,因为其所做的就是把训练数据存储起来并编入索引。但是,由于要对测试示例进行分类,所以需要与每个单独的训练示例进行比较,所以在测试时比较耗时间。但在实际中,这样的操作恰恰相反,因为在实际应用中,我们更关心的是测试时间,而不是训练时间,我们希望在输入后能很快得到结果。后续中的深度神经网络则转向了另一个极端:训练很耗时间,而测试的开销很小。
当然,其有时候或许是一个不错的选择,但是它很少在实际的图像分类上进行使用。
-
图像是高维对象(对于彩色图像是三维向量RGB三种颜色)
-
在高维空间上的距离又可能会违反直觉

总结
- 图像分类问题:在该问题中,我们得到了一组图像,这些图像全部用一个类别标记。然后,我们被要求针对一组新颖的测试图像预测这些类别,并测量预测的准确性。
- 简单的近邻分类器(KNN),我们看到与该分类器相关联的有多个超参数(例如k的值或用于比较示例的距离的类型),并且没有明显的选择方法。
- 我们看到设置这些超参数的正确方法是将训练数据分为两部分:训练集和伪测试集,我们将其称为验证集。我们尝试使用不同的超参数值,并在验证集上保留导致最佳性能的值。
- 如果担心缺乏训练数据,我们讨论了一种称为交叉验证的过程,该过程可以帮助更好估计哪些超参数最有效。
- 一旦找到最佳的超参数,我们将对其进行修复,并对实际测试集进行一次评估。
- 我们看到,最近邻居可以使我们在CIFAR-10上获得约40%的精度。它易于实现,但需要我们存储整个训练集,并且在测试图像上进行评估开销很大。
- 最后,我们看到在原始像素值上使用L1或L2距离是不够的,因为该距离与图像的背景和颜色分布的关联比与语义内容的关联更紧密。
在选择L2距离和L1距离时要根据实际情况来选择,L1距离与向量中各元素的位置有关(变换坐标系,结果亦会变化),L2距离与向量中各元素位置无关(不随坐标轴变化而变化) ↩︎