CS231n 2016 通关 第二章-KNN 作业分析

KNN作业要求:

1、掌握KNN算法原理

2、实现具体K值的KNN算法

3、实现对K值的交叉验证

1、KNN原理见上一小节

2、实现KNN

  过程分两步:

    1、计算测试集与训练集的距离

    2、通过比较label出现比例的方式,确定选取的最终label

  代码分析:

  cell1 - cell5 对数据的预处理

  cell6创建KNN类,初始化类的变量,此处是传递测试数据和训练数据

  cell7实现包含两个循环的KNN算法:

    通过计算单一的向量与矩阵之间的距离(在之前的cell中,已经将图像转换成列:32*32 的图像转换为 1*3072,,

    测试集是500张:500*3072,训练集是5000张:5000*3072)

  代码基础:使用python 2.7.9 + numpy 1.11.0

  技巧:使用help 查看相关函数的用法,或者google

    举例:np.square 

          

      q 键退出help      

      

      可知,np.square() 为了加快运算速度,是用c写的,在这里查不到具体用法。google查看:

      

        例子为计算数组[-1j,1]里边各元素的平方,得到的结果为[-1,1]

  代码:实现compute_distances_two_loops(self, X)

 1   def compute_distances_two_loops(self, X):
 2     """
 3     Compute the distance between each test point in X and each training point
 4     in self.X_train using a nested loop over both the training data and the 
 5     test data.
 6 
 7     Inputs:
 8     - X: A numpy array of shape (num_test, D) containing test data.
 9 
10     Returns:
11     - dists: A numpy array of shape (num_test, num_train) where dists[i, j]
12       is the Euclidean distance between the ith test point and the jth training
13       point.
14     """
15     num_test = X.shape[0]
16     num_train = self.X_train.shape[0]
17     dists = np.zeros((num_test, num_train))
18     for i in xrange(num_test):
19       for j in xrange(num_train):
20         #####################################################################
21         # TODO:                                                             #
22         # Compute the l2 distance between the ith test point and the jth    #
23         # training point, and store the result in dists[i, j]. You should   #
24         # not use a loop over dimension.                                    #
25         #####################################################################
26         dists[i,j] = np.sqrt(np.sum(np.square(X[i,:]-self.X_train[j,:])))
27         #####################################################################
28         #                       END OF YOUR CODE                            #
29         #####################################################################
30     return dists

    实现对一张测试图像对应的矩阵与一张训练集图像的矩阵做L2距离。

    也可以用numpy.linalg.norm函数实现:

      此函数执行的公式:

      所以核心代码可以写作:

        dists[i,j] = np.linalg.norm(self.X_train[j,:]-X[i,:])

  cell8 得到的距离可视化,白色表示较大的距离值,黑色是较小距离值

  cell9 实现K=1的label预测

  代码:实现 classifier.predict_labels()

 1   def predict_labels(self, dists, k=1):
 2     """
 3     Given a matrix of distances between test points and training points,
 4     predict a label for each test point.
 5 
 6     Inputs:
 7     - dists: A numpy array of shape (num_test, num_train) where dists[i, j]
 8       gives the distance betwen the ith test point and the jth training point.
 9 
10     Returns:
11     - y: A numpy array of shape (num_test,) containing predicted labels for the
12       test data, where y[i] is the predicted label for the test point X[i].  
13     """
14     num_test = dists.shape[0]
15     y_pred = np.zeros(num_test)
16     for i in xrange(num_test):
17       # A list of length k storing the labels of the k nearest neighbors to
18       # the ith test point.
19       closest_y = []
20       count = []
21       #########################################################################
22       # TODO:                                                                 #
23       # Use the distance matrix to find the k nearest neighbors of the ith    #
24       # testing point, and use self.y_train to find the labels of these       #
25       # neighbors. Store these labels in closest_y.                           #
26       # Hint: Look up the function numpy.argsort.                             #
27       #########################################################################
28       buf_labels = self.y_train[np.argsort(dists[i,:])]
29       closest_y = buf_labels[0:k]
30       #########################################################################
31       # TODO:                                                                 #
32       # Now that you have found the labels of the k nearest neighbors, you    #
33       # need to find the most common label in the list closest_y of labels.   #
34       # Store this label in y_pred[i]. Break ties by choosing the smaller     #
35       # label.                                                                #
36       #########################################################################
37       #for j in closest_y :
38       #  count.append(closest_y.count(j))
39       #m = max(count)      
40       #n = count.index(m)
41       #y_pred[i] = closest_y[n]
42       c = Counter(closest_y)
43       y_pred[i] = c.most_common(1)[0][0]
44       #########################################################################
45       #                           END OF YOUR CODE                            # 
46       #########################################################################
47 
48     return y_pred

        步骤:

          1.使用numpy.argsort对所以距离进行排序,得到排序后的索引。

          2.通过索引找到对应的label

          3.通过collection包的Counter,对label进行统计表示

          4.通过counter的Most common方法得到出现最多的label

  cell9 在计算完成后,同时实现了准确率的计算

  cell10 实现K =5的KNN

  cell11 实现compute_distances_one_loop(X_test)

  代码:

 1   def compute_distances_one_loop(self, X):
 2     """
 3     Compute the distance between each test point in X and each training point
 4     in self.X_train using a single loop over the test data.
 5 
 6     Input / Output: Same as compute_distances_two_loops
 7     """
 8     num_test = X.shape[0]
 9     num_train = self.X_train.shape[0]
10     dists = np.zeros((num_test, num_train))
11     for i in xrange(num_test):
12       #######################################################################
13       # TODO:                                                               #
14       # Compute the l2 distance between the ith test point and all training #
15       # points, and store the result in dists[i, :].                        #
16       #######################################################################
17       buf = np.square(self.X_train-X[i,:])
18       dists[i,:] = np.sqrt(np.sum(buf,axis=1))      
19       #######################################################################
20       #                         END OF YOUR CODE                            #
21       #######################################################################
22     return dists

  并通过计算一个循环与两个循环分别得到的结果的差值平方,来衡量准确性。

  cell12 实现完全的数组操作,不使用循环

 1   def compute_distances_no_loops(self, X):
 2     """
 3     Compute the distance between each test point in X and each training point
 4     in self.X_train using no explicit loops.
 5 
 6     Input / Output: Same as compute_distances_two_loops
 7     """
 8     num_test = X.shape[0]
 9     num_train = self.X_train.shape[0]
10     dists = np.zeros((num_test, num_train)) 
11     #########################################################################
12     # TODO:                                                                 #
13     # Compute the l2 distance between all test points and all training      #
14     # points without using any explicit loops, and store the result in      #
15     # dists.                                                                #
16     #                                                                       #
17     # You should implement this function using only basic array operations; #
18     # in particular you should not use functions from scipy.                #
19     #                                                                       #
20     # HINT: Try to formulate the l2 distance using matrix multiplication    #
21     #       and two broadcast sums.                                         #
22     #########################################################################
23     #buf = np.tile(X,(1,num_train))
24     buf = np.dot(X, self.X_train.T)
25     buf_test = np.square(X).sum(axis = 1)
26     buf_train = np.square(self.X_train).sum(axis = 1)
27     dists = np.sqrt(-2*buf+buf_train+np.matrix(buf_test).T)
28     #########################################################################
29     #                         END OF YOUR CODE                              #
30     #########################################################################
31     return dists

  使用(a-b)2=a2+b2-2ab 的公式

  27行: 此时buf_test 为500*1数组  buf_train为5000*1的数组  需要得到500*5000的数组  此处通过构造矩阵的方式进行broadcast

  cell13 比较3种方案的执行效率

  cell14 交叉验证

  交叉验证的思想在上一节有解释过了

  代码:(其中带有注释)

 1 num_folds = 5
 2 k_choices = [1, 3, 5, 8, 10, 12, 15, 20, 50, 100]
 3 
 4 X_train_folds = []
 5 y_train_folds = []
 6 ################################################################################
 7 # TODO:                                                                        #
 8 # Split up the training data into folds. After splitting, X_train_folds and    #
 9 # y_train_folds should each be lists of length num_folds, where                #
10 # y_train_folds[i] is the label vector for the points in X_train_folds[i].     #
11 # Hint: Look up the numpy array_split function.                                #
12 ################################################################################
13 X_train_folds = np.array_split(X_train, num_folds)
14 y_train_folds = np.array_split(y_train, num_folds)
15 ################################################################################
16 #                                 END OF YOUR CODE                             #
17 ################################################################################
18 
19 # A dictionary holding the accuracies for different values of k that we find
20 # when running cross-validation. After running cross-validation,
21 # k_to_accuracies[k] should be a list of length num_folds giving the different
22 # accuracy values that we found when using that value of k.
23 k_to_accuracies = {}
24 
25 
26 ################################################################################
27 # TODO:                                                                        #
28 # Perform k-fold cross validation to find the best value of k. For each        #
29 # possible value of k, run the k-nearest-neighbor algorithm num_folds times,   #
30 # where in each case you use all but one of the folds as training data and the #
31 # last fold as a validation set. Store the accuracies for all fold and all     #
32 # values of k in the k_to_accuracies dictionary.                               #
33 ################################################################################
34 for k in k_choices:
35     k_to_accuracies[k] = []
36 
37 for k in k_choices:
38     print 'evaluating k=%d' % k
39     for j in range(num_folds):
40         #get validation 
41         X_train_cv = np.vstack(X_train_folds[0:j]+X_train_folds[j+1:])
42         X_test_cv = X_train_folds[j]              
43         y_train_cv = np.hstack(y_train_folds[0:j]+y_train_folds[j+1:])
44         y_test_cv = y_train_folds[j]
45         #train 
46         classifier.train(X_train_cv, y_train_cv)
47         dists_cv = classifier.compute_distances_no_loops(X_test_cv)
48         #get accuracy
49         y_test_pred = classifier.predict_labels(dists_cv, k)
50         num_correct = np.sum(y_test_pred == y_test_cv)
51         accuracy = float(num_correct) / num_test
52         #add j th accuracy of k to array
53         k_to_accuracies[k].append(accuracy)
54 ################################################################################
55 #                                 END OF YOUR CODE                             #
56 ################################################################################
57 
58 # Print out the computed accuracies
59 for k in sorted(k_to_accuracies):
60     for accuracy in k_to_accuracies[k]:
61         print 'k = %d, accuracy = %f' % (k, accuracy)

  cell15 显示k值对应的准确率

  上述包含了均值和标准差

  cell16 使用最优值,得到较好的准确率

总结:

  整体来说,第一个作业难度较大,主要难度不是在算法部分,而是在熟悉python相关函数与相应的用法方面。对于python大神而言,难度低。

  但是经过扎实的第一次作业后,后边的作业相对简单了。之后的作业细节方面讲解的少些。

附:通关CS231n企鹅群:578975100 validation:DL-CS231n 

原文地址:https://www.cnblogs.com/wangxiu/p/5655622.html