cs231n 的作業一直寫寫停停,實在是太對不起自己了,其實作業還是挺有意思的
自己用conda create先創建了一個虛擬環境,pytorch36,鏈接到jupyter-notebook的kernel
具體配置jupyter的kernel以後有空再整理
1. knn.ipynb
knn的作業有兩個目的,一個是弄明白numpy的broadcast機制,第二個是嘗試交叉驗證。
from cs231n.classifiers import KNearestNeighbor
表明我們要寫的這個分類器的位置
KNN算法的原理:
1.計算所有測試樣本和訓練樣本之間的l2距離,就是平方和開方 dists = ((num_test, num_train))
2.對於每個測試樣本的距離,挑選出最近的k個,然後統計裏面最多的label,即爲最終的label
命題點1 numpy broadcast
計算距離矩陣用了三種方法,分別是兩次循環,一次循環和沒有循環
兩次循環
就是最簡單的窮舉法,距離矩陣中行和列中的每個元素都計算一遍
for i in range(num_test):
for j in range(num_train):
dists[i,j]=np.sqrt(np.sum((X[i]-self.X_train[j])**2))
一次循環
每次計算一行距離, 這裏test的X[i] 是一個數據,shape是(3072,),X_train 則是一批數據(5000,3072)
兩者的維度不同,怎麼可以相減呢,這就是numpy的broad cast機制。從最後一維對齊3072對3072,然後向前傳播。得到一個(5000,3072)的兩個矩陣計算距離,最後得到(5000,)
for i in range(num_test):
dists[i,:] = np.sqrt(np.sum((X[i] - self.X_train)**2,1))
沒有循環
(5000,3072)和(500,3072) 沒法相減,這可怎麼辦呢,那我們只好把平方公式拆開了
具體如下
dists += np.sum((self.X_train**2),1).reshape(1,num_train)
dists += np.sum((X**2),1).reshape(num_test,1) #reshape for broadcast
dists -= 2*np.dot(X,self.X_train.T)
dists = np.sqrt(dists)
藉助numpy的argsort函數對距離進行排序, 找出最近的k個距離
np.argsort :Returns the indices that would sort an array.
命題點2 k折交叉驗證
分割數據集
X_train_folds = [np.array_split(X_train,num_folds)[i] for i in range(num_folds)]
y_train_folds = [np.array_split(y_train,num_folds)[i] for i in range(num_folds)]
循環k次訓練過程
for i in range(num_folds): #循環i次
classifier.train(np.delete(np.array(X_train_folds),i,0).reshape(-1,X_train.shape[1])
,np.delete(np.array(y_train_folds),i,0).reshape(-1)) # 從訓練數據中刪除第i折的數據
print(i)
y_pred=classifier.predict(X_train_folds[i],k)
acc=np.equal(y_pred,y_train_folds[i]).sum()/y_train_folds[i].shape[0]
acc_list.append(acc)