1. 程式人生 > 其它 >Assignment 1# KNN 答案及總結

Assignment 1# KNN 答案及總結

技術標籤:cs231n深度學習python

Assignment 1# KNN

KNN分類器簡介

基本思路:

首先將目標圖片(33232)伸展為一維的目標向量向量,然後比較目標向量和訓練集中所有樣本向量的“”距離“。找出其中距離最小(最相似)的K個樣本,找到這些樣本所屬類別。找出其中最多的作為預測值。

超引數:

這是無監督學習的模型。沒有引數,只有距離度量方法和K(近鄰數目)兩個超引數。通過在dev set 上 cross validation 獲得。

cross validation 一般是直接拆訓練集進行practice,但是這裡也講了對於小規模資料可以採用k-fold calidation。但總而言之k-fold 一般不用,因為計算複雜性較高。
L1和L2距離。

### Pros and Cons Pros:便於理解,演算法簡單。 Cons: 1. 高維資料距離難以理解,counter-intuitive。很多時候和人類對相似的理解相違背。
2. 需要儲存所有的訓練集,儲存消耗大。相比之下,SVM softmax分類器訓練之後可以捨棄訓練集。 3. 每一個目標影象都要和所有資料集影象一一比較。計算消耗大。有相應的改進。ANN通過pre processing 來 trade off correctness with space/time complexity.

Part One

計算testset 和training set之間的距離。在=1 以及K=5條件下分別進行test set的判斷,計算準確率。
其中X 作為test_set形狀為(500,3072)
self.X_train 作為training_set形狀為(5000,3072)
dist作為距離,形狀為(500,5000)
其中500,5000為樣本數目。
3072=33232為樣本向量長度。也就是(500,3072)每一行是一張展開成(1,3072)的圖片向量。

核心程式碼在於距離的計算,就是一個切片:

Two loop version

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

之後帶入 accuracy分別是0.274,0.290

Part Two

通過numpy的向量化,將迴圈改成單迴圈甚至沒有迴圈,計算比較消耗相應的時間消耗。

One loop version

這裡用到的技巧是numpy的broadcasting功能。
取出第i個樣本向量X[i](1,3072),與self.X_train(5000,3072.)作差平方。通過廣播機制,矩陣的每一行與向量分別作差。
之後按照axis=1求和並開根號,就得到了一個(5000,1)的列向量,代表樣本i與train_set之中5000個樣本的距離,轉置之後就是dists矩陣的第i行了。
之後就所有的500個樣本遍歷,就可以得到(500,5000)的距離矩陣。
重點:

  1. numpy的廣播機制。
  2. reshape。當時搞的時候看了一些視訊,吳恩達推薦迷惑的時候reshape一下看一下矩陣和你想象的樣子是不是一樣的。或者加註釋,總之自己就感覺很容易不知道這個矩陣是什麼形狀,或者是每個維度是什麼含義,浪費大量時間。
def compute_distances_one_loop(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)).reshape(1,num_train)
    return dists

Two loop version

這個相對難想一些。
思路是採用二項式定理展開
先計算樣本和training各維度平方和。test_square(500,1),training_square(1,5000)
之後計算樣本和training之間的二次項。用X(500,3072)和self.X_training.T(3072,5000)點乘。得到二次項quadratic_term(500,5000)。
最後利用二項式定理計算dists(500,5000)。
test_square(500,1)+training_square(1,5000)。再次通過強大的broadcasting。demo如下:

def compute_distances_no_loops(self, X):
	# HINT: Try to formulate the l2 distance using matrix multiplication#
    num_test = X.shape[0]
    num_train = self.X_train.shape[0]
    dists = np.zeros((num_test, num_train))
	test_square=(X**2).sum(axis=1).reshape(-1,1)#平方項
	training_square=(self.X_train ** 2).sum(axis=1).reshape(1,-1)#平方項
	quadratic_term=2*X.reshape(num_test,3702)@self.X_train.reshape(3702,num_train)#二次項
	dists=np.sqrt(test_square+training_square-quadratic_npterm)
	return dists

Cross Validation

這一部分就是用5-fold cross validation 確定K這個超引數的選取。

預測函式

重點:

  1. arg系函式(argsort,argmax,argmin,argwhere)
    他們都與相應的函式對應,但是他們可以返回滿足相應條件的下標。
  2. max函式的key
    可以根據出現次數取出最大的

思路就是找到dist[i](1,5000)裡面最小的k個放在closest_y裡面。
然後通過max函式找到出現次數最多的。就是預測值。

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 = []
        neighbor_label=list(np.argsort(dists[i])[0:k])
        for s in neighbor_label:
            closest_y.append(self.y_train[s])
        y_pred[i]=max(closest_y,key=closest_y.count)
    return y_pred

cross validation函式

重點:

  1. np.array_split()函式拆分資料集,不是隨機的拆分
  2. np.concatenate([X_train_folds[j] for j in range(num_folds) if j!=i])就沒啥說的,很妙。
num_folds = 5
k_choices = [1, 3, 5, 8, 10, 12, 15, 20, 50, 100]
X_train_folds=np.array_split(X_train,num_folds)
y_train_folds=np.array_split(y_train,num_folds)
#資料集的拆分,分成五份
k_to_accuracies = {}
for k in k_choices:
    k_to_accuracies[k]=[]
    for i in range(num_folds):
        classifier.train(np.concatenate([X_train_folds[j] for j in range(num_folds) if j!=i]),np.concatenate([y_train_folds[j] for j in range(num_folds) if j!=i]))         			  		
        k_to_accuracies[k].append(np.sum(classifier.predict(X_train_folds[i],k=k)==y_train_folds[i])/len(y_train_folds[i]))

最後畫出來一個cross validation的圖。還是很有成就感的,這段程式碼自己真正cross validation的時候也可以拿來用。