『cs231n』作業1選講_通過代碼理解KNN&交叉驗證&SVM


通過K近鄰算法探究numpy向量運算提速

 茴香豆的“茴”字有... ...

使用三種計算圖片距離的方式實現K近鄰算法:

1.最為基礎的雙循環

2.利用numpy的broadca機制實現單循環

3.利用broadcast和矩陣的數學性質實現無循環

圖片被拉伸為一維數組

X_train:(train_num, 一維數組)

X:(test_num, 一維數組)

方法驗證

import numpy as np
a = np.array([[1,1,1],[2,2,2],[3,3,3]])
b = np.array([[4,4,4],[5,5,5],[6,6,6],[7,7,7]])

雙循環:

dists = np.zeros((3,4))
for i in range(3):
    for j in range(4):
        dists[i][j] = np.sqrt(np.sum(np.square(a[i] - b[j])))
print(dists)

 [[  5.19615242   6.92820323   8.66025404  10.39230485]
 [  3.46410162   5.19615242   6.92820323   8.66025404]
 [  1.73205081   3.46410162   5.19615242   6.92820323]]

單循環:

dists=np.zeros((3,4))
for i in range(3):
    dists[i] = np.sqrt(np.sum(np.square(a[i] - b),axis=1))
print(dists)

[[  5.19615242   6.92820323   8.66025404  10.39230485]
 [  3.46410162   5.19615242   6.92820323   8.66025404]
 [  1.73205081   3.46410162   5.19615242   6.92820323]] 

無循環:

r1=(np.sum(np.square(a),axis=1)*(np.ones((b.shape[0],1)))).T
r2=np.sum(np.square(b),axis=1)*(np.ones((a.shape[0],1)))
r3=-2*np.dot(a,b.T)
print(np.sqrt(r1+r2+r3))

 [[  5.19615242   6.92820323   8.66025404  10.39230485]
 [  3.46410162   5.19615242   6.92820323   8.66025404]
 [  1.73205081   3.46410162   5.19615242   6.92820323]]

 無循環算法原理:

(注意,原理圖-驗證代碼-實現程序 的變量並不嚴格一一對應,均有調整)

全代碼實現如下:

import numpy as np

class KNearsNeighbor():
    def _init_(self):
        pass

    def train(self, x, y):
        self.X_train = x
        self.y_train = y
  
    # 選擇使用幾個循環體的方式來計算距離
    def predict(self, X, k=1, num_loops=0):
        if num_loops == 0:
            dist = self.compute_distances_no_loops(X)
        elif num_loops == 1:
            dist = self.compute_distances_one_loops(X)
        elif num_loops == 2:
            dist = self.compute_distances_two_loops(X)
        else:
            raise ValueError('Invalid value %d' % num_loops)
        return dist

    def compute_distances_two_loops(self, X):
        num_test = X.shape[0]
        num_train = self.X_train.shape[0]
        dists = np.zeros((num_test, num_train))
        for i in range(num_test):
            for j in range(num_train):
                dists[i][j] = np.sqrt(np.sum(np.square(X[i] - self.X_train[j])))
        return dists
    def compute_distances_one_loops(self, X):
        num_test = X.shape[0]
        num_train = self.X_train.shape[0]
        dists = np.zeros((num_test,num_train))
        for i in range(num_test):
                dists[i] = np.sqrt(np.sum(np.square(X[i] - self.X_train), axis=1))
        return dists

    def compute_distances_no_loops(self, X):
        # num_test = X.shape[0]
        # num_train = self.X_train.shape[0]
        # dists = np.zeros((num_test,num_train))
        dists = np.sqrt(-2*np.dot(X, self.X_train.T) +
                        np.sum(np.square(self.X_train), axis=1)*(np.ones((X.shape[0],1))) +
                               np.sum(np.square(X), axis=1)*(np.ones(X_train.shape[0],1)).T)
        return dists

   # 預測標簽
    def predict_labels(self, dists, k=1):
        num_test = dists.shape[0]
        y_pred = np.zeros(num_test)
        for i in range(num_test):
            closest_y = self.y_train[np.argsort(dists[i])[:k]]  # 【【【按照距離給索引排序】取最近的k個索引】按照索引取訓練標簽】
            y_pred[i] = np.argmax(np.bincount(closest_y))       #  投票,注意np.bincount()和np.argmax()在投票上的妙用
        return y_pred

 交叉驗證選擇超參數k的取值

We have implemented(實施) the k-Nearest Neighbor classifier(分類) but we set the value k = 5 arbitrarily(武斷地). We will now determine the best value of this hyperparameter with cross-validation(交叉驗證).

import numpy as np
num_folds = 5
k_choices = [1, 3, 5, 8, 10, 12, 15, 20, 50, 100]

X_train_folds = []
y_train_folds = []
################################################################################
# TODO:                                                                        #
# Split up the training data into folds. After splitting, X_train_folds and    #
# y_train_folds should each be lists of length num_folds, where                #
# y_train_folds[i] is the label vector for the points in X_train_folds[i].     #
# Hint: Look up the numpy array_split function.                                #
################################################################################
X_train_folds = np.split(X_train, num_folds)
y_train_folds = np.split(y_train, num_folds)
################################################################################
#                                 END OF YOUR CODE                             #
################################################################################

# A dictionary holding the accuracies for different values of k that we find
# when running cross-validation. After running cross-validation,
# k_to_accuracies[k] should be a list of length num_folds giving the different
# accuracy values that we found when using that value of k.
k_to_accuracies = {}
################################################################################
# TODO:                                                                        #
# Perform k-fold cross validation to find the best value of k. For each        #
# possible value of k, run the k-nearest-neighbor algorithm num_folds times,   #
# where in each case you use all but one of the folds as training data and the #
# last fold as a validation set. Store the accuracies for all fold and all     #
# values of k in the k_to_accuracies dictionary.                               #
################################################################################

for k in k_choices:
    k_to_accuracies[k]=np.zeros(num_folds)
    for i in range(num_folds):
        Xtr = np.concatenate(
            (np.array(X_train_folds)[:i],np.array(X_train_folds)[(i+1):]),axis=0)
        ytr = np.concatenate(
            (np.array(y_train_folds)[:i],np.array(y_train_folds)[(i+1):]),axis=0)
        Xte = np.array(X_train_folds)[i]
        yte = np.array(y_train_folds)[i]
        
        # [num_of_folds, num_in_flods, feature_of_x] -> [num_of_pictures, feature_of_x]
        Xtr = np.reshape(Xtr, (X_train.shape[0] * 4 / 5, -1))
        ytr = np.reshape(ytr, (y_train.shape[0] * 4 / 5, -1))
        Xte = np.reshape(Xte, (X_train.shape[0] / 5, -1))
        yte = np.reshape(yte, (y_train.shape[0] / 5, -1))
        
        classifier.train(Xtr, ytr)
        yte_pred = classifier.predict(Xte, k)
        yte_pred = np.reshape(yte_pred, (yte_pred.shape[0], -1))

        accuracy = np.sum(yte_pred == yte, dtype=float)/len(yte)   # bool to int,我們需要顯示指定為float
        k_to_accuracies[k][i] = accuracy
################################################################################
#                                 END OF YOUR CODE                             #
################################################################################

# Print out the computed accuracies
for k in sorted(k_to_accuracies):
    for accuracy in k_to_accuracies[k]:
        print 'k = %d, accuracy = %f' % (k, accuracy)

SVM支持向量機

def svm_loss_vectorized(W, X, y, reg):
  """
  Structured SVM loss function, vectorized implementation.

  Inputs and outputs are the same as svm_loss_naive.
  """
  
  loss = 0.0
  dW = np.zeros(W.shape) # initialize the gradient as zero

  # 向前傳播
  scores = X.dot(W)
  scores_correct = scores[np.arange(y.shape[0]),y].reshape(y.shape[0],1)
  margins = np.maximum(0., scores - scores_correct + 1)      # 錯誤類加上閾值減去正確類得分,滿足的置零,不滿足的計算loss
  margins[np.arange(y.shape[0]),y] = 0                       # 把上一步正確類參與計算的部分置零
  loss = np.sum(margins)/y.shape[0] + 0.5*reg*np.sum(W*W)

  # 反向傳播
  margins[margins>0] = 1                         # 類relu反向傳播
  row_grad = np.sum(margins, axis=1)
  margins[np.arange(y.shape[0]),y] - row_grad    # 分類器反向都是這樣,錯誤類不動,正確類減去上層梯度
  dW = np.dot(X.T,margins)/y.shape[0] + reg*W

  return loss, dW


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM