rfcd12 发表于 2015-11-30 09:18:29

简单分类器的python代码实现

  
  本文是stanford大学课程:Convolutional Neural Networks for Visual Recognition 的一些笔记与第一次作业。主要内容为简单(多类)分类器的实现:KNN, SVM, softmax。
  softmax与SVM的一点区别,其中一张PPT说明:

  
  

  
  KNN部分框架都给出,只需要补充L2距离的实现:





1 import numpy as np
2
3 class KNearestNeighbor:
4   """ a kNN classifier with L2 distance """
5
6   def __init__(self):
7   pass
8
9   def train(self, X, y):
10   """
11   Train the classifier. For k-nearest neighbors this is just
12   memorizing the training data.
13
14   Input:
15   X - A num_train x dimension array where each row is a training point.
16   y - A vector of length num_train, where y is the label for X
17   """
18   self.X_train = X
19   self.y_train = y
20   
21   def predict(self, X, k=1, num_loops=0):
22   """
23   Predict labels for test data using this classifier.
24
25   Input:
26   X - A num_test x dimension array where each row is a test point.
27   k - The number of nearest neighbors that vote for predicted label
28   num_loops - Determines which method to use to compute distances
29               between training points and test points.
30
31   Output:
32   y - A vector of length num_test, where y is the predicted label for the
33         test point X.
34   """
35   if num_loops == 0:
36       dists = self.compute_distances_no_loops(X)
37   elif num_loops == 1:
38       dists = self.compute_distances_one_loop(X)
39   elif num_loops == 2:
40       dists = self.compute_distances_two_loops(X)
41   else:
42       raise ValueError('Invalid value %d for num_loops' % num_loops)
43
44   return self.predict_labels(dists, k=k)
45
46   def compute_distances_two_loops(self, X):
47   """
48   Compute the distance between each test point in X and each training point
49   in self.X_train using a nested loop over both the training data and the
50   test data.
51
52   Input:
53   X - An num_test x dimension array where each row is a test point.
54
55   Output:
56   dists - A num_test x num_train array where dists is the distance
57             between the ith test point and the jth training point.
58   """
59   num_test = X.shape
60   num_train = self.X_train.shape
61   dists = np.zeros((num_test, num_train))
62   for i in xrange(num_test):
63       for j in xrange(num_train):
64         #####################################################################
65         # TODO:                                                             #
66         # Compute the l2 distance between the ith test point and the jth    #
67         # training point, and store the result in dists               #
68         #####################################################################
69         dists = np.sqrt(np.sum((X - self.X_train)**2))
70         #####################################################################
71         #                     END OF YOUR CODE                            #
72         #####################################################################
73   return dists
74
75   def compute_distances_one_loop(self, X):
76   """
77   Compute the distance between each test point in X and each training point
78   in self.X_train using a single loop over the test data.
79
80   Input / Output: Same as compute_distances_two_loops
81   """
82   num_test = X.shape
83   num_train = self.X_train.shape
84   dists = np.zeros((num_test, num_train))
85   for i in xrange(num_test):
86       #######################################################################
87       # TODO:                                                               #
88       # Compute the l2 distance between the ith test point and all training #
89       # points, and store the result in dists.                        #
90       #######################################################################
91       dists = np.sqrt(np.sum((self.X_train - X)**2, axis = 1))
92       #######################################################################
93       #                         END OF YOUR CODE                            #
94       #######################################################################
95   return dists
96
97   def compute_distances_no_loops(self, X):
98   """
99   Compute the distance between each test point in X and each training point
100   in self.X_train using no explicit loops.
101
102   Input / Output: Same as compute_distances_two_loops
103   """
104   num_test = X.shape
105   num_train = self.X_train.shape
106   dists = np.zeros((num_test, num_train))
107   #########################################################################
108   # TODO:                                                               #
109   # Compute the l2 distance between all test points and all training      #
110   # points without using any explicit loops, and store the result in      #
111   # dists.                                                                #
112   # HINT: Try to formulate the l2 distance using matrix multiplication    #
113   #       and two broadcast sums.                                       #
114   #########################################################################
115   dists = np.sqrt(np.dot((X**2), np.ones((np.transpose(self.X_train)).shape))\
116   + np.dot(np.ones(X.shape), np.transpose(self.X_train ** 2))\
117   - 2 * np.dot(X, np.transpose(self.X_train)))
118   #########################################################################
119   #                         END OF YOUR CODE                              #
120   #########################################################################
121   return dists
122
123   def predict_labels(self, dists, k=1):
124   """
125   Given a matrix of distances between test points and training points,
126   predict a label for each test point.
127
128   Input:
129   dists - A num_test x num_train array where dists gives the distance
130             between the ith test point and the jth training point.
131
132   Output:
133   y - A vector of length num_test where y is the predicted label for the
134         ith test point.
135   """
136   num_test = dists.shape
137   y_pred = np.zeros(num_test)
138   for i in xrange(num_test):
139       # A list of length k storing the labels of the k nearest neighbors to
140       # the ith test point.
141       closest_y = []
142       #########################################################################
143       # TODO:                                                               #
144       # Use the distance matrix to find the k nearest neighbors of the ith    #
145       # training point, and use self.y_train to find the labels of these      #
146       # neighbors. Store these labels in closest_y.                           #
147       # Hint: Look up the function numpy.argsort.                           #
148       #########################################################################
149       idx = np.argsort(dists)
150       closest_y = list(self.y_train])
151       #########################################################################
152       # TODO:                                                               #
153       # Now that you have found the labels of the k nearest neighbors, you    #
154       # need to find the most common label in the list closest_y of labels.   #
155       # Store this label in y_pred. Break ties by choosing the smaller   #
156       # label.                                                                #
157       #########################################################################
158       labelCount = {}
159       for j in xrange(k):
160         labelCount] = labelCount.get(closest_y, 0) + 1
161       sortedLabel = sorted(labelCount.iteritems(), key = lambda line:line, reverse = True)
162       y_pred = sortedLabel
163       #########################################################################
164       #                           END OF YOUR CODE                            #
165       #########################################################################
166
167   return y_pred
View Code  linear classifier的实现,需要补全 train 与 predict 两部分:





1 import numpy as np
2 from cs231n.classifiers.linear_svm import *
3 from cs231n.classifiers.softmax import *
4
5 class LinearClassifier:
6
7   def __init__(self):
8   self.W = None
9
10   def train(self, X, y, learning_rate=1e-3, reg=1e-5, num_iters=100,
11             batch_size=200, verbose=False):
12   """
13   Train this linear classifier using stochastic gradient descent.
14
15   Inputs:
16   - X: D x N array of training data. Each training point is a D-dimensional
17          column.
18   - y: 1-dimensional array of length N with labels 0...K-1, for K classes.
19   - learning_rate: (float) learning rate for optimization.
20   - reg: (float) regularization strength.
21   - num_iters: (integer) number of steps to take when optimizing
22   - batch_size: (integer) number of training examples to use at each step.
23   - verbose: (boolean) If true, print progress during optimization.
24
25   Outputs:
26   A list containing the value of the loss function at each training iteration.
27   """
28   dim, num_train = X.shape
29   num_classes = np.max(y) + 1 # assume y takes values 0...K-1 where K is number of classes
30   if self.W is None:
31       # lazily initialize W
32       self.W = np.random.randn(num_classes, dim) * 0.001
33
34   # Run stochastic gradient descent to optimize W
35   loss_history = []
36   for it in xrange(num_iters):
37       X_batch = None
38       y_batch = None
39
40       #########################################################################
41       # TODO:                                                               #
42       # Sample batch_size elements from the training data and their         #
43       # corresponding labels to use in this round of gradient descent.      #
44       # Store the data in X_batch and their corresponding labels in         #
45       # y_batch; after sampling X_batch should have shape (dim, batch_size)   #
46       # and y_batch should have shape (batch_size,)                           #
47       #                                                                     #
48       # Hint: Use np.random.choice to generate indices. Sampling with         #
49       # replacement is faster than sampling without replacement.            #
50       #########################################################################
51       sample_idx = np.random.choice(num_train, batch_size, replace = True)
52       X_batch = X[:, sample_idx]
53       y_batch = y
54       #########################################################################
55       #                     END OF YOUR CODE                              #
56       #########################################################################
57
58       # evaluate loss and gradient
59       loss, grad = self.loss(X_batch, y_batch, reg)
60       loss_history.append(loss)
61
62       # perform parameter update
63       #########################################################################
64       # TODO:                                                               #
65       # Update the weights using the gradient and the learning rate.          #
66       #########################################################################
67       self.W += -learning_rate*grad
68       #########################################################################
69       #                     END OF YOUR CODE                              #
70       #########################################################################
71
72       if verbose and it % 100 == 0:
73         print 'iteration %d / %d: loss %f' % (it, num_iters, loss)
74
75   return loss_history
76
77   def predict(self, X):
78   """
79   Use the trained weights of this linear classifier to predict labels for
80   data points.
81
82   Inputs:
83   - X: D x N array of training data. Each column is a D-dimensional point.
84
85   Returns:
86   - y_pred: Predicted labels for the data in X. y_pred is a 1-dimensional
87       array of length N, and each element is an integer giving the predicted
88       class.
89   """
90   y_pred = np.zeros(X.shape)
91   ###########################################################################
92   # TODO:                                                                   #
93   # Implement this method. Store the predicted labels in y_pred.            #
94   ###########################################################################
95   y_pred = np.argmax(np.dot(self.W, X), axis = 0)
96   ###########################################################################
97   #                           END OF YOUR CODE                              #
98   ###########################################################################
99   return y_pred
100   
101   def loss(self, X_batch, y_batch, reg):
102   """
103   Compute the loss function and its derivative.
104   Subclasses will override this.
105
106   Inputs:
107   - X_batch: D x N array of data; each column is a data point.
108   - y_batch: 1-dimensional array of length N with labels 0...K-1, for K classes.
109   - reg: (float) regularization strength.
110
111   Returns: A tuple containing:
112   - loss as a single float
113   - gradient with respect to self.W; an array of the same shape as W
114   """
115   pass
116
117
118 class LinearSVM(LinearClassifier):
119   """ A subclass that uses the Multiclass SVM loss function """
120
121   def loss(self, X_batch, y_batch, reg):
122   return svm_loss_vectorized(self.W, X_batch, y_batch, reg)
123
124
125 class Softmax(LinearClassifier):
126   """ A subclass that uses the Softmax + Cross-entropy loss function """
127
128   def loss(self, X_batch, y_batch, reg):
129   return softmax_loss_vectorized(self.W, X_batch, y_batch, reg)
View Code  然后就是svm与softmax分类器的loss与梯度的实现。
  SVM 的loss function 与 gradient :
  loss function: $$L = \frac{1}{N} \sum_i \sum_{y_i \ne j} [ \max( 0, \mathrm{f}(\mathrm{x}_i, W)_j - \mathrm{f}(\mathrm{x}_i, W)_{y_i} + 1)] + \frac{\lambda}{2} \sum_k\sum_l W_{k,l}^2$$
  gradient: $$ \nabla_{\mathrm{w}_j} L = \frac{1}{N} \sum_i 1\{\mathrm{w}_j^T \mathrm{x}_i-w_{y_i}^T\mathrm{x}_i+1>0\}\mathrm{x}_i + \lambda \mathrm{w}_j$$





1 import numpy as np
2 from random import shuffle
3
4 def svm_loss_naive(W, X, y, reg):
5   """
6   Structured SVM loss function, naive implementation (with loops)
7   Inputs:
8   - W: C x D array of weights
9   - X: D x N array of data. Data are D-dimensional columns
10   - y: 1-dimensional array of length N with labels 0...K-1, for K classes
11   - reg: (float) regularization strength
12   Returns:
13   a tuple of:
14   - loss as single float
15   - gradient with respect to weights W; an array of same shape as W
16   """
17   dW = np.zeros(W.shape) # initialize the gradient as zero
18
19   # compute the loss and the gradient
20   num_classes = W.shape
21   num_train = X.shape
22   loss = 0.0
23   for i in xrange(num_train):
24   scores = W.dot(X[:, i])
25   correct_class_score = scores]
26   for j in xrange(num_classes):
27       if j == y:
28         continue
29       margin = scores - correct_class_score + 1 # note delta = 1
30       if margin > 0:
31         loss += margin
32         dW += (X[:, i]).transpose()
33
34   # Right now the loss is a sum over all training examples, but we want it
35   # to be an average instead so we divide by num_train.
36   loss /= num_train
37   dW /= num_train
38
39   # Add regularization to the loss.
40   loss += 0.5 * reg * np.sum(W * W)
41   dW += reg * W
42
43   #############################################################################
44   # TODO:                                                                     #
45   # Compute the gradient of the loss function and store it dW.                #
46   # Rather that first computing the loss and then computing the derivative,   #
47   # it may be simpler to compute the derivative at the same time that the   #
48   # loss is being computed. As a result you may need to modify some of the    #
49   # code above to compute the gradient.                                       #
50   #############################################################################
51
52
53   return loss, dW
54
55
56 def svm_loss_vectorized(W, X, y, reg):
57   """
58   Structured SVM loss function, vectorized implementation.
59
60   Inputs and outputs are the same as svm_loss_naive.
61   """
62   loss = 0.0
63   dW = np.zeros(W.shape) # initialize the gradient as zero
64
65   #############################################################################
66   # TODO:                                                                     #
67   # Implement a vectorized version of the structured SVM loss, storing the    #
68   # result in loss.                                                         #
69   #############################################################################
70   num_train = y.shape
71   Y_hat = W.dot(X)
72   err_dist = Y_hat - Y_hat)] + 1
73   err_dist = 0.0
74   err_dist)] = 0.0
75   loss += np.sum(err_dist)/num_train
76   loss += 0.5 * reg * np.sum(W * W)
77
78   #############################################################################
79   #                           END OF YOUR CODE                              #
80   #############################################################################
81
82
83   #############################################################################
84   # TODO:                                                                     #
85   # Implement a vectorized version of the gradient for the structured SVM   #
86   # loss, storing the result in dW.                                           #
87   #                                                                           #
88   # Hint: Instead of computing the gradient from scratch, it may be easier    #
89   # to reuse some of the intermediate values that you used to compute the   #
90   # loss.                                                                     #
91   #############################################################################
92   err_dist = 1.0/num_train
93   dW += err_dist.dot(X.transpose()) + reg * W
94
95   #############################################################################
96   #                           END OF YOUR CODE                              #
97   #############################################################################
98
99   return loss, dW
View Code  softmax的loss function 与 gradient :
  loss function: $$ L = \frac {1}{N} \sum_i \sum_j \mathrm{1}\{y_i=j\}\cdot \log(\frac{e^{\mathrm{f}_j}}{\sum_m e^{\mathrm{f}_m}}) + \frac{\lambda}{2} \sum_k\sum_l W_{k,l}^2$$
  gradient: $$\nabla_{\mathrm{w}_j} L = -\frac{1}{N} \sum_i \left\mathrm{x}_i + \lambda \mathrm{w}_j$$
  其中 $p(y_i=j | \mathrm{x}_i;W) = \frac{e^{\mathrm{f}_j}}{\sum_m e^{\mathrm{f}_m}}$





1 import numpy as np
2 from random import shuffle
3
4 def softmax_loss_naive(W, X, y, reg):
5   """
6   Softmax loss function, naive implementation (with loops)
7   Inputs:
8   - W: C x D array of weights
9   - X: D x N array of data. Data are D-dimensional columns
10   - y: 1-dimensional array of length N with labels 0...K-1, for K classes
11   - reg: (float) regularization strength
12   Returns:
13   a tuple of:
14   - loss as single float
15   - gradient with respect to weights W, an array of same size as W
16   """
17   # Initialize the loss and gradient to zero.
18   loss = 0.0
19   dW = np.zeros_like(W)
20
21   #############################################################################
22   # TODO: Compute the softmax loss and its gradient using explicit loops.   #
23   # Store the loss in loss and the gradient in dW. If you are not careful   #
24   # here, it is easy to run into numeric instability. Don't forget the      #
25   # regularization!                                                         #
26   #############################################################################
27   dim, num_data = X.shape
28   num_class = W.shape
29   Y_hat = np.exp(np.dot(W, X))
30   prob = Y_hat / np.sum(Y_hat, axis = 0)
31
32   # C x N array, element(i,j)=1 if y=i
33   ground_truth = np.zeros_like(prob)
34   ground_truth)] = 1.0
35
36   for i in xrange(num_data):
37   for j in xrange(num_class):
38       loss += -(ground_truth * np.log(prob))/num_data
39       dW += -(ground_truth - prob)*(X[:,i]).transpose()/num_data
40   loss += 0.5*reg*np.sum(np.sum(W**2, axis = 0)) # reg term
41   dW += reg*W
42
43   #############################################################################
44   #                        END OF YOUR CODE                                 #
45   #############################################################################
46
47   return loss, dW
48
49
50 def softmax_loss_vectorized(W, X, y, reg):
51   """
52   Softmax loss function, vectorized version.
53
54   Inputs and outputs are the same as softmax_loss_naive.
55   """
56   # Initialize the loss and gradient to zero.
57   loss = 0.0
58   dW = np.zeros_like(W)
59
60   #############################################################################
61   # TODO: Compute the softmax loss and its gradient using no explicit loops.#
62   # Store the loss in loss and the gradient in dW. If you are not careful   #
63   # here, it is easy to run into numeric instability. Don't forget the      #
64   # regularization!                                                         #
65   #############################################################################
66   dim, num_data = X.shape
67   Y_hat = np.exp(np.dot(W, X))
68   prob = Y_hat / np.sum(Y_hat, axis = 0)#probabilities
69
70   # C x N array, element(i,j)=1 if y=i
71   ground_truth = np.zeros_like(prob)
72   ground_truth)] = 1.0
73   
74   loss = -np.sum(ground_truth*np.log(prob)) / num_data + 0.5*reg*np.sum(W*W)
75   dW = (-np.dot(ground_truth - prob, X.transpose()))/num_data + reg*W
76   #############################################################################
77   #                        END OF YOUR CODE                                 #
78   #############################################################################
79
80   return loss, dW
View Code  
  然后测试代码在IPython Notebook上完成,可以进行单元测试,一点一点运行。
  比如,基于给定数据集,KNN的测试结果(K=10):

  SVM测试结果:

  Softmax测试结果:

  
页: [1]
查看完整版本: 简单分类器的python代码实现