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)