在做cs231n作业一的knn时,遇到问题总结和解决办法

Jasmine ·
更新时间:2024-11-14
· 854 次阅读

网上有作业参考:
1、知乎的
2、CSDN的CS231n课程学习笔记(一)——KNN的实现
目前是按照知乎上的来做的,做的过程中遇到一些问题和解决办法,现总结如下:
在终端输入

ipython notebook

或者

jupyter notebook

打开Jupyter。

Jupyter Notebook(此前被称为 IPython notebook)是一个交互式笔记本,支持运行 40 多种编程语言。Jupyter Notebook 的本质是一个 Web 应用程序,便于创建和共享文学化程序文档,支持实时代码,数学方程,可视化和 markdown。 用途包括:数据清理和转换,数值模拟,统计建模,机器学习等等。(Jupyter官方网站)

在这里插入图片描述Jupyter简要操作方式:方式1、在单元格中写好代码后,点上面的“运行”进行运行程序,这仅仅运行一个单元格,好处是可以运行单个代码块,有bug可以及时更改;方式2、在每个单元格中写好代码后,点击“单元格”,会出现
在这里插入图片描述
继续点“运行所有单元格”,即可运行所有的单元格。
在写好整个程序后,想改为其他格式,选择“文件”–“下载”,点击相应格式的文件下载即可。
一些快捷键:
Jupyter Notebook 有两种键盘输入模式。编辑模式,允许你往单元中键入代码或文本;这时的单元框线是绿色的。命令模式,键盘输入运行程序命令;这时的单元框线是灰色。
Shift+Enter : 运行本单元,选中下个单元
Ctrl+Enter : 运行本单元
Alt+Enter : 运行本单元,在其下插入新单元
Y:单元转入代码状态
M:单元转入markdown状态
A :在上方插入新单元
B:在下方插入新单元
X:剪切选中的单元
Shift +V:在上方粘贴单元

一、data_utils.py 的修改

将“ import cPickle as pickle ”改为“ import pickle as pickle”。
将“datadict = pickle.load(f)” 改为 “datadict = pickle.load(f,encoding=‘bytes’)”
load_cifar_batch(filename)函数其他修改如下:

def load_cifar_batch(filename): """ load single batch of cifar """ with open(filename, 'rb') as f: datadict = pickle.load(f,encoding='bytes') X = datadict[b'data'] Y = datadict[b'labels'] X = X.reshape(10000, 3, 32, 32).transpose(0,2,3,1).astype("float") Y = np.array(Y) return X, Y 二、knn.py的修改

把“xrange()”改成range()

三、修改路径 import numpy as np from data_utils import load_cifar10 import matplotlib.pyplot as plt from knn import KNearestNeighbor x_train,y_train,x_test,y_test=load_cifar10('cifar-10-batches-py')

其中’cifar-10-batches-py’需要修改为自己的路径,我的路径名为’/home/djz/cs231n_assignment/assignment1/cs231n/datasets/cifar-10-batches-py’。

四、有一处错误,指正 classifier=KNearestNeighbor() classifier.train(x_train,y_train) dists=classifier.cumpute_distances_two_loops(x_test) print(dists)

第三行‘dists=classifier.cumpute_distances_two_loops(x_test)’里的cumpute修改为compute,不然会报错,估计这里是作者笔误。

五、交叉验证后用最好的K来完成预测任务出错“ValueError: object too deep for desired array” best_k=10 classifier=KNearestNeighbor() classifier.train(x_train,y_train) y_test_pred=classifier.predict(x_test,k=best_k) num_correct=np.sum(y_test_pred==y_test) accuracy=float(num_correct)/num_test print('got %d / %d correct => accuracy: %f' % (num_correct,num_test,accuracy))

运行后会报错“ValueError: object too deep for desired array”,是因为bincount()函数的使用不对,解决办法有两种:

1、在knn.py中用numpy.squeeze()函数修改“closest_y”

在“ y_pred[i]=np.argmax(np.bincount(closest_y)) ”上面添加里两行代码

if np.shape(np.shape(closest_y))[0] !=1: ############增加程序 closest_y=np.squeeze(closest_y) ############增加程序

呈现效果为:

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=[] y_indicies=np.argsort(dists[i,:],axis=0) #排序 closest_y=self.y_train[y_indicies[: k]] if np.shape(np.shape(closest_y))[0] !=1: #增加的代码 closest_y=np.squeeze(closest_y) #增加的代码 y_pred[i]=np.argmax(np.bincount(closest_y)) return y_pred 2、把“closest_y”转化为一维向量

即把“ y_pred[i]=np.argmax(np.bincount(closest_y)) ”修改为

y_pred[i]=np.argmax(np.bincount(closest_y.reshape(len(closest_y)))) 六、numpy里的arange()和reshape()的用法

arange()返回一个列表,reshape()将数组重新组成新维度的数组,shape()返回行数或列数。
arange():一个参数是终点;两个参数,第一个是起点,第二个是终点;三个参数,依次为起点、终点、步长。(默认步长为1)
在这里插入图片描述
reshape():
在这里插入图片描述
shape():(继续上面的运行)
在这里插入图片描述

感想:
1、knn算法的分类正确率很低,而且“训练快,测试慢”,不适合实际的需要,这是了解深度学习的工具,毕竟是传统的机器学习算法;
2、L1,L2 范数来进行像素比较是不够的,图像更多的是按背景和颜色被分类,而不是语义主体分身;
3、如果想要使K-NN算法实用,可以对数据特征进行normalize,让其均值为0,和单位方差。或者用PCA降维
附上交叉验证的结果:
在这里插入图片描述


作者:剑圣土豆



cs231n cs2 knn

需要 登录 后方可回复, 如果你还没有账号请 注册新账号