SVM与KNN掌纹识别算法对比
一. 题目
本次研究课题为:SVM与KNN掌纹识别算法对比。
二. 数据库介绍
本次研究所使用的数据集为1006张掌纹的ROI图像库,每张图片的大小为128128,数据集的所有图片都已经提取出了感兴趣区域。因数据集涉及保密,故不公开。
三. 任务选择
本次研究任务选择为分别使用SVM与KNN进行掌纹识别。
四. 评价指标
本次研究选用识别率来作为评价指标,识别率的公式为:
五. 编程语言
本次研究采用python语言进行算法的对比研究,其中用到的库有python-opencv,numpy,sklearn等等。
六. 算法原理
本次所使用的算法有俩个,一个是SVM,一个是KNN,这;这俩个算法在sklearn库里面已经全部实现好了,在需要调用里面的函数即可。下面简单介绍以下俩个算法的算法原理**。**
(1) SVM算法原理
SVM(支持向量机)算法原理可以概括为以下几点:
- SVM是一种二分类模型,它的基本模型是定义在特征空间上的间隔最大的线性分类器,间隔最大使它有别于感知机;SVM还包括核技巧,这使它成为实质上的非线性分类器。
- SVM的学习策略就是求解使间隔最大化的最优化问题,可形式化为一个求解凸二次规划的问题,也等价于正则化的合页损失函数的最小化问题。
- SVM的的学习算法就是求解凸二次规划的最优化算法。
(2) KNN算法原理
KNN(K-Nearest Neighbor)算法原理是通过测量不同特征值之间的距离进行分类。对于一个新输入的样本,KNN算法会在训练数据集中找到与该样本最邻近的K个样本,这K个样本的大多数属于哪个类别,新输入的样本就被归类到哪个类别。
七. 程序框架
本次研究是用jupyter notebook来进行实验,Jupyter Notebook是一个非常强大和灵活的工具,特别适合进行数据分析和处理工作。本次研究的主要流程如下:
加载数据—à特征提取—à数据处理—à模型训练—à算法对比
八. 实验过程和结果分析
(一)实验过程
在进行掌纹识别前,我们需要对数据集进行简单的处理。
1.加载数据,代码如下:
#加载数据
def load_dataset():
X = [] # 特征
y = [] # 标签
for i in range(100):
for j in range(1,7):
path="E:\\palmbases\\"+"p_"+str(i)+"_"+str(j)+".bmp"
img = cv2.imread(path)
# 提取Gabor特征
#features = extract_gabor_features(img)
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
features = gray_img.flatten()
# 从文件名中提取类别标签
category = i
X.append(features)
y.append(category)
return X,y
2.划分数据集,这里先以4:2的比例进行分层抽样,代码如下:
#分层抽样划分数据集,每6张前4张做训练后俩张做测试
def data_split(x,y):
X_train=[]
X_test=[]
y_train=[]
y_test=[]
j=1#标记变量
for i in x:
if j<=4:
X_train.append(i)
j+=1
else:
X_test.append(i)
j+=1
if j==7:
j=1
j=1
for i in y:
if j<=4:
y_train.append(i)
j+=1
else:
y_test.append(i)
j+=1
if j==7:
j=1
return np.array(X_train),np.array(X_test),np.array(y_train),np.array(y_test)
3.不做处理,直接跑模型测试,这里选择svm模型,代码如下:
# 加载数据集
X, y = load_dataset()
#划分数据集
X_train, X_test, y_train, y_test=data_split(X,y)
# 初始化SVM分类器
clf = svm.SVC(kernel='rbf')
# 训练SVM模型
clf.fit(X_train, y_train)
# 在测试集上进行预测
y_pred = clf.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"Test Accuracy: {accuracy}")
上面代码需要导入的包如下,也是下面代码所需要的:
import os
import cv2
import numpy as np
from sklearn import svm
from sklearn.decomposition import PCA
from sklearn.metrics import accuracy_score
最终svm跑出的准确率为0.96.
4.数据处理与训练
接下来我们试试对数据进行处理并训练看看结果。
(1)对数据进行降维,并利用循环遍历得出最佳维度,先观察以下数据的信息,代码如下:
X_train.shape
结果显示:(400, 16384)
降维函数如下:
def pca_transform(X_train,X_test, n_components):
# 使用PCA降维
pca = PCA(n_components=n_components)
train = pca.fit_transform(X_train)
test=pca.transform(X_test)
return train,test
根据上面结果看到维度高达16384维,下面是挑选最佳维度代码:
#获取最佳维度和准确率,利用svm计算
def pca_best(X_train,X_test):
acc=[]#各维度准确率集合
nlist=[]#各维度集合
a=10
acc1=0
for n in range(10,300,10):#先到300维看看,如果波动比较大再加
# 对训练数据和测试数据进行PCA降维
X_train_pca, X_test_pca = pca_transform(X_train,X_test,n)
# 初始化SVM分类器
clf = svm.SVC(kernel='rbf')
# 训练SVM模型
clf.fit(X_train_pca, y_train)
# 在测试集上进行预测
y_pred = clf.predict(X_test_pca)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
if accuracy==1:
return n,accuracy
acc.append(accuracy)
nlist.append(n)
#打印各维度对应的准确率,看看波动情况,如果准确率越来越平稳,则不用测试300维以后的维度,否之则不然
print("维度为:",n)
print("准确率为:",accuracy)
print("\n")
#获取最佳维度和准确率
for i in range(len(nlist)):
if acc1<acc[i]:
acc1=acc[i]
a=nlist[i]
return a,acc1
运行代码如下:
#前面已经划分好数据集
n,acc=pca_best(X_train,X_test)
print("最佳维度为:",n)
print("准确率为:",acc)
运行结果为:
最佳维度为: 70
准确率为: 0.985
(2)利用gabor滤波对数据进行处理
gabor滤波代码如下:
#建立gabor滤波器
def gabor_filter(img, frequency, theta):
kernel = cv2.getGaborKernel((21, 21), 5.0, theta, 10.0, 1.0, 0, ktype=cv2.CV_32F)
filtered_img = cv2.filter2D(img, cv2.CV_8UC3, kernel)
return filtered_img
#图像滤波
def extract_gabor_features(image):
#因为加载数据时已经进行过灰度转换了,所以下面一行注释掉
#gray_img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray_img=image
filtered_img = gabor_filter(gray_img, frequency=0.6, theta=1.0)
flattened_features = filtered_img.flatten()
return flattened_features
计算gabor后的准确率,代码如下:
def gabor_image(x):#将加载的数据集进行滤波
x_gabor=[]
for i in x:
features = extract_gabor_features(i)
x_gabor.append(features)
return x_gabor
#滤波
x_gabor=gabor_image(X)
#划分数据集
X_train, X_test, y_train, y_test=data_split(x_gabor,y)
# 初始化SVM分类器
clf = svm.SVC(kernel='rbf')
# 训练SVM模型
clf.fit(X_train, y_train)
# 在测试集上进行预测
y_pred = clf.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, y_pred)
print(f"Test Accuracy: {accuracy}")
结果显示为:
Test Accuracy: 0.94
可以发现准确率相比没有滤波时下降了,我们参考下面论文:
D. Zhang, W. K. Kong, J. You, M. Wong. Online palmprint identification[J]. IEEETransactions on Pattern Analysis and Machine Intelligence,2003,25(9):1041-1050
知道了一些原因,并且可以尝试使用2D Gabor相位编码。这里暂时不做处理,我还不会。
下面使用其他算法来进行模型测试。
5.使用knn算法来进行分类识别
代码如下:
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
#加载数据代码(上面有)
#划分数据代码(上面有)
# 使用KNN算法进行训练和预测
knn = KNeighborsClassifier(n_neighbors=1) # 设置K值为1,可根据需求进行调整
knn.fit(X_train, y_train)
predictions = knn.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, predictions)
print("Accuracy:", accuracy)
加载数据和划分数据集的代码用之前的。
结果为:
Accuracy: 0.97
我们修改k值看看,这里因为训练集每个类最多只有4张图片,所以k最多设置为4,我们要用下面代码遍历看看结果:
def knn_test():
for n in range(1,5):
# 使用KNN算法进行训练和预测
knn = KNeighborsClassifier(n_neighbors=n)
knn.fit(X_train, y_train)
predictions = knn.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, predictions)
print("K值为:",n)
print("Accuracy:", accuracy)
print("\n")
knn_test()
结果为:
K值为: 1
Accuracy: 0.97
K值为: 2
Accuracy: 0.83
K值为: 3
Accuracy: 0.765
K值为: 4
Accuracy: 0.76
结果表示k为1时结果最高。
接下来我们对数据进行降维后再利用knn分类,并利用循环得出最佳维度(与之前降维代码类似):
#获取最佳维度和准确率,利用knn计算
def pca_best(X_train,X_test):
acc=[]#各维度准确率集合
nlist=[]#各维度集合
a=10
acc1=0
for n in range(10,300,10):#先到300维看看,如果波动比较大再加
# 对训练数据和测试数据进行PCA降维
X_train_pca, X_test_pca = pca_transform(X_train,X_test,n)
# 使用KNN算法进行训练和预测
knn = KNeighborsClassifier(n_neighbors=1) # 设置K值为1,可根据需求进行调整
knn.fit(X_train_pca, y_train)
predictions = knn.predict(X_test_pca)
# 计算准确率
accuracy = accuracy_score(y_test, predictions)
#print("Accuracy:", accuracy)
if accuracy==1:
return n,accuracy
acc.append(accuracy)
nlist.append(n)
#打印各维度对应的准确率,看看波动情况,如果准确率越来越平稳,则不用测试300维以后的维度,否之则不然
print("维度为:",n)
print("准确率为:",accuracy)
print("\n")
#获取最佳维度和准确率
for i in range(len(nlist)):
if acc1<acc[i]:
acc1=acc[i]
a=nlist[i]
return a,acc1
#前面已经划分好数据集
n,acc=pca_best(X_train,X_test)
print("最佳维度为:",n)
print("准确率为:",acc)
结果为:
最佳维度为: 20
准确率为: 0.975
下面我们对数据进行gabor滤波后再进行knn分类看看结果:
#建立gabor滤波器
def gabor_filter(img, frequency, theta):
kernel = cv2.getGaborKernel((21, 21), 5.0, theta, 10.0, 1.0, 0, ktype=cv2.CV_32F)
filtered_img = cv2.filter2D(img, cv2.CV_8UC3, kernel)
return filtered_img
#图像滤波
def extract_gabor_features(image):
#因为加载数据时已经进行过灰度转换了,所以下面一行注释掉
#gray_img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray_img=image
filtered_img = gabor_filter(gray_img, frequency=0.6, theta=1.0)
flattened_features = filtered_img.flatten()
return flattened_features
def gabor_image(x):#将加载的数据集进行滤波
x_gabor=[]
for i in x:
features = extract_gabor_features(i)
x_gabor.append(features)
return x_gabor
#滤波
x_gabor=gabor_image(X)
#划分数据集
X_train, X_test, y_train, y_test=data_split(x_gabor,y)
knn = KNeighborsClassifier(n_neighbors=1) # 设置K值为1,可根据需求进行调整
knn.fit(X_train, y_train)
predictions = knn.predict(X_test)
# 计算准确率
accuracy = accuracy_score(y_test, predictions)
print("准确率为:",accuracy)
结果为:
准确率为: 0.955
(二)结果分析
通过以上实验过程可以发现,在不对数据进行如何处理的情况下,KNN的识别率要高于SVM,当对数据进行降维后,本研究选择俩个算法的最佳维度来进行识别度比较,SVM的最佳维数为70,识别率为0.985,KNN的最佳维数为20,识别率为0.975,对数据不做进行gabor滤波后,俩者识别率都有所下降,但SVM下降的百分点更多。本次研究还对数据集划分做了测试,发现训练集与测试集的比例越高,识别率就越高。
一. 结论和心得体会
(一)本次实验主要有以下结论:
(1) 在训练集与测试集的划分方面,本研究按3:3,4:2,5:1的比例分别利用SVM来进行测试,发现训练集与测试集的比例越高,识别率就越高。
(2) 本研究对SVM进行了一定程度的调参,本研究使用SVM的径向基函数与线性核函数分别进行模型训练,经过对比测试发现,在不对数据做如何处理的情况下,使用径向基函数来进行模型训练的识别率要高一点。
(3) 本研究对KNN算法进行了不同K值情况下,识别率的对比研究,发现在K值为1时识别率是最高的,这与我们的一般认知K值越高,识别率越高有所差别。
(4) 本研究在对数据进行降维时,根据算法的不同,分别进行了最佳维数的选择,本研究,从10个维度开始,按照步长为10来进行循环计算得出不同维度下的识别率,发现在利用SVM进行模型训练时,最佳维度为70,识别率为0.985,在利用KNN进行模型训练时,最佳维度为20,识别率为0.975.
(5) 本研究发现在对数据进行gabor滤波后,俩个算法的识别率都有所下降,但SVM算法的识别率下降更多。
(二)心得体会
本次研究主要是SVM与KNN掌纹识别算法对比研究,主要从原理,参数调整,降维,滤波,数据集划分的方面进行研究对比,俩种算法的识别率都很可观,在不对数据做如何处理的情况下,俩个算法的识别率都高达0.95以上,这里也有一部分原因是数据集过少,在不对数据进行降维的情况下,KNN的识别率都要高于SVM,但降维后,最佳的识别率反而是SVM更高。本次研究各方面都还有所不足,还有许多方面有待研究考证。