不使用 sklearn写的knn算法,识别mnist数据集,准确率只有百分之六十, 如何进一步提高识别的准确率
已经尝试过使用不同的k值和对图片进行归一化处理
def load_mnist():
X_train = np.fromfile('mnist_data/train-images-idx3-ubyte', dtype=np.uint8, offset=16)
X_train = X_train.reshape(int(6e4), 28, 28)
X_test = np.fromfile('mnist_data/t10k-images-idx3-ubyte', dtype=np.uint8, offset=16)
X_test = X_test.reshape(int(1e4), 28, 28)
y_train = np.fromfile('mnist_data/train-labels-idx1-ubyte', dtype=np.uint8, offset=8)
y_train = y_train.reshape(int(6e4))
y_test = np.fromfile('mnist_data/t10k-labels-idx1-ubyte', dtype=np.uint8, offset=8)
y_test = y_test.reshape(int(1e4))
class Knn(object):
def __init__(self, k=3):
self.k = k
def fit(self, X, y):
self.X = X
self.y = y
def predict(self, X):
dataset = self.X
labels = self.y
k = self.k
predict_labels = []
X = np.reshape(X, (X.shape[0], -1))
dataset = np.reshape(dataset, (dataset.shape[0], -1))
scalar = MaxAbsScaler()
scalar.fit(dataset)
dataset = scalar.transform(dataset)
X = scalar.transform(X)
print(dataset[0])
dataset_size = dataset.shape[0]
for i in tqdm(range(X.shape[0])):
diff_mat = np.tile(X[i], (dataset_size, 1)) - dataset
sq_diff_mat = diff_mat ** 2
sq_distances = sq_diff_mat.sum(axis=1)
distances = sq_distances ** 0.5
sorted_dist_indicies = distances.argsort()
class_count = {}
for j in range(k):
vote_label = labels[sorted_dist_indicies[i]]
class_count[vote_label] = class_count.get(vote_label, 0) + 1
sorted_class_count = sorted(class_count.items(), key=operator.itemgetter(1), reverse=True)
predict_labels.append(sorted_class_count[0][0])
predict_labels = np.array(predict_labels)
return predict_labels
首先,手写识别的关键是特征描述,如果这一步没有做好,用什么方法,怎么调参,也不会有好的结果。
将图像像素值直接作为输入向量,原则上是不适当的。
推荐实现方法如下:
(1)首先,样本均匀,标准化,归一化,这些必要的准备工作就不说了,
(2)特征提取,或者说特征向量构造,将字符图像转换为特征向量作为模型的输入,
(3)KNN,可以选择不同的K值,2~5之间有些影响,5 以上没必要。
关于特征构造,推荐两种方法:
1,HOG,方向梯度直方图
2,小波特征,例如Haar
我查了一下以前的程序,检验集识别准确率大约 80~90%。
给出一段 HOG 特征描述符的构造例程,这类似于SIFT的特征描述符,效果不错。
import cv2 as cv
# (2) 构造 HOG 描述符
# HOGDescriptor
winSize = (20, 20)
blockSize = (10, 10)
blockStride = (5, 5)
cellSize = (5, 5)
nbins = 8
derivAperture = 1
winSigma = -1.
histogramNormType = 0
L2HysThreshold = 0.2
gammaCorrection = 1
nlevels = 16
signedGradients = True
hog = cv.HOGDescriptor(winSize, blockSize, blockStride, cellSize, nbins,
derivAperture, winSigma, histogramNormType,
L2HysThreshold, gammaCorrection, nlevels)
p = (1+(20-10)//5)*(1+(20-10)//5)*(10//5)*(10//5)*8 # 特征描述符长度,288
参考结果:
Recognition of handwritten digits by KNN-HOG
k=2, correct=938, accuracy=93.80%
k=3, correct=939, accuracy=93.90%
k=4, correct=940, accuracy=94.00%
k=5, correct=938, accuracy=93.80%
可以尝试先用特征提取的办法,然后将主要的特征作用于knn,或者直接降维也是可以的
针对图像上方法比较多,可以突出边缘来试一下,或者进行一些图像变换,然后针对变换后的图像进行knn
两个提升knn算法的准确率的方向。
一、是优化决策方式,采用加权距离:加权距离方法可以利用【反函数】【高斯函数】
二、是提高搜索近邻点的速度,利用KD树快速定位近邻点。
使用paddle 或者 是pytorch 随便写个神经网络