卷积神经网络算法(CNN)与PCA+SVC算法的掌纹识别算法对比

  • 数据库介绍

100 个手掌,每个手掌 6 个原始图像和 ROI(Region of Interest)图像。ROI表示从原始手掌图像中定位裁剪出的正方形感兴趣区域,尺寸为128×128个像素。

 

  • 任务选择

本研究报告针对掌纹的分类识别任务,目的是将掌纹图像分为100个类别中的一类。

  • 评价指标
  1. 精度

本研究报告使用了两种算法,其中卷积神经网络的精度为0.845,而PCA+SVC算法的精度达到1.

  1. 鲁棒性
  2. 复杂度
  • 编程语言

本研究使用python编程语言在idea环境下运行

卷积神经网络算法完整源代码

import os
import tensorflow as tf
import numpy as np
from IPython.core.display_functions import clear_output
from keras.preprocessing.image import load_img, img_to_array
from tensorflow import keras
import matplotlib.pyplot as plt

train_images=[]
test_images=[]
train_labels = [i for i in range(100) for _ in range(4)]
test_labels=[i for i in range(100) for _ in range(2)]

data_dir = 'C:/Users/86137/OneDrive/桌面/机器学习/PolyU_Palmprint_600'
# 获取所有图像文件的路径
image_paths = [os.path.join(data_dir, f) for f in os.listdir(data_dir) if f.endswith('.bmp')]
for i in range(0, len(image_paths), 6):
    # 获取每次循环中的6张图像路径
    batch = image_paths[i:i + 6]
    # 将前4张图像路径加入训练集
    train_images.extend(batch[:4])
    # 将后2张图像路径加入测试集
    test_images.extend(batch[4:])

def load_and_process_image(image_path):
    img = load_img(image_path, target_size=(224, 224))  # 加载图像并调整大小
    img_array = img_to_array(img)  # 将图像转换为数组
    img_array = img_array / 255.0  # 归一化处理
    return img_array

# 加载训练集和测试集的图像数据
train_data = np.array([load_and_process_image(image_path) for image_path in train_images])
test_data = np.array([load_and_process_image(image_path) for image_path in test_images])
train_labels = np.array(train_labels)
test_labels = np.array(test_labels)

#三个卷积层,分别包含 32、64 和 128 个滤波器(filter)。每个滤波器的大小为 (3, 3),并采用 ReLU 激活函数。第一层还需要指定输入图像的形状为 (224, 224, 3)
model = keras.models.Sequential([
    tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(224, 224, 3)),
    tf.keras.layers.MaxPooling2D((2, 2)),
    tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
    tf.keras.layers.MaxPooling2D((2, 2)),
    tf.keras.layers.Conv2D(128, (3, 3), activation='relu'),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(100, activation='softmax')
])

# 输出模型的层数和参数数量
model.summary()

# 编译模型
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

# 定义一个回调函数,用于绘制训练过程中的准确率变化图表
class PlotAccuracy(tf.keras.callbacks.Callback):
    def on_train_begin(self, logs={}):
        self.i = 0
        self.x = []
        self.acc = []
        self.val_acc = []
        self.fig = plt.figure()

        self.logs = []

    def on_epoch_end(self, epoch, logs={}):
        self.logs.append(logs)
        self.x.append(self.i)
        self.acc.append(logs.get('accuracy'))
        self.val_acc.append(logs.get('val_accuracy'))
        self.i += 1

        clear_output(wait=True)
        plt.plot(self.x, self.acc, label="accuracy")
        plt.plot(self.x, self.val_acc, label="val_accuracy")
        plt.title("Training Progress")
        plt.xlabel("Epochs")
        plt.ylabel("Accuracy")
        plt.legend()
        plt.show()

# 创建回调函数实例
plot_acc = PlotAccuracy()

# 训练模型,并使用回调函数绘制训练过程中的准确率变化图表
history = model.fit(train_data, train_labels, epochs=16, validation_data=(test_data, test_labels), callbacks=[plot_acc])

# 在测试集上评估模型的准确率
test_loss, test_acc = model.evaluate(test_data, test_labels)
print('Test accuracy:', test_acc)

# 使用数据增强技术来提高模型的鲁棒性
train_datagen = tf.keras.preprocessing.image.ImageDataGenerator(
    rotation_range=20,
    width_shift_range=0.2,
    height_shift_range=0.2,
    horizontal_flip=True)

train_generator = train_datagen.flow(train_data, train_labels, batch_size=32)

model.fit(train_generator, epochs=16, validation_data=(test_data, test_labels))

# 绘制模型结构图
tf.keras.utils.plot_model(model, to_file='model.png')

# 绘制训练过程中的损失和准确率变化图表
plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('Model Accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()

plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('Model Loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Test'], loc='upper left')
plt.show()

PCA+SVC算法完整源代码

import os
import numpy as np
from PIL import Image
from sklearn.decomposition import PCA
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import StratifiedKFold
from sklearn.metrics import accuracy_score
from sklearn.pipeline import make_pipeline
from sklearn.svm import SVC
import matplotlib.pyplot as plt
data_dir = "C:/Users/86137/OneDrive/桌面/机器学习/palmbases/"
train_images = []
train_labels = []
test_images = []
test_labels = []
param_grid = {
    'svc__C': [1, 5, 10, 50,100],
    'svc__gamma': [0.00005,0.0001, 0.0005, 0.001, 0.005]
}

for i in range(0, 100):
    # 读取训练集,使用每个掌纹的前五张图片作为训练集
    for j in range(1, 6):
        file_name = os.path.join(data_dir, f'P_{i}_{j}.bmp')
        image = Image.open(file_name).convert('L')
        image = np.array(image)
        train_images.append(image)
        train_labels.append(i)

    # 读取测试集,使用每个掌纹的第六张图片作为测试集
    file_name = os.path.join(data_dir, f'P_{i}_6.bmp')
    image = Image.open(file_name).convert('L')
    image = np.array(image)
    test_images.append(image)
    test_labels.append(i)

train_data = np.array(train_images)
test_data = np.array(test_images)
labels_train = np.array(train_labels)
labels_test = np.array(test_labels)

train_data = train_data.reshape((500, 16384))
test_data = test_data.reshape((100, 16384))

pca = PCA(n_components=300, whiten=True, random_state=42, svd_solver='randomized')
svc = SVC(kernel='rbf', class_weight='balanced')
model = make_pipeline(pca, svc)

cv_method = StratifiedKFold(n_splits=3)
grid = GridSearchCV(model, param_grid, cv=cv_method,return_train_score=True)
grid.fit(train_data, labels_train)
# 获取最佳参数
best_params = grid.best_params_

# 将参数转换为列表
param_values = list(best_params.values())
param_names = list(best_params.keys())

# 绘制条形图
plt.bar(param_names, param_values)
plt.xlabel('Parameter Name')
plt.ylabel('Parameter Value')
plt.title('Best Parameters')
plt.show()
print(grid.best_params_)
model = grid.best_estimator_
decision_scores = grid.decision_function(test_data)
print('Decision Scores:', decision_scores)
# 选择一个样本的索引
sample_index = 0

# 获取该样本的置信度分数
sample_scores = decision_scores[sample_index]

# 获取类别标签
class_labels = np.arange(len(sample_scores))

# 绘制条形图
plt.bar(class_labels, sample_scores)
plt.xlabel('Class Label')
plt.ylabel('Confidence Score')
plt.title('Confidence Scores for Sample {}'.format(sample_index))
plt.xticks(class_labels)
plt.show()

test_out = model.predict(test_data)
accuracy = accuracy_score(labels_test, test_out)
train_accuracies = grid.cv_results_['mean_train_score']

# 绘制折线图
plt.plot(range(len(train_accuracies)), train_accuracies)
plt.xlabel('Iterations')
plt.ylabel('Train Accuracy')
plt.title('Train Accuracy during Training')
plt.show()
# 计算模型的鲁棒性
cv_results = grid.cv_results_
mean_test_scores = cv_results['mean_test_score']
std_test_scores = cv_results['std_test_score']

# 绘制鲁棒性图
plt.errorbar(range(len(mean_test_scores)), mean_test_scores, yerr=std_test_scores, fmt='-o')
plt.xlabel('Parameter Combination')
plt.ylabel('Test Accuracy')
plt.title('Robustness of the Model')
plt.xticks(range(len(mean_test_scores)), cv_results['params'], rotation=45)
plt.show()

# 计算模型的复杂度
train_accuracies = cv_results['mean_train_score']

# 绘制复杂度图
plt.plot(range(len(train_accuracies)), train_accuracies)
plt.xlabel('Iterations')
plt.ylabel('Train Accuracy')
plt.title('Complexity of the Model')
plt.show()

print("准确率:", accuracy)

  • 算法原理
卷积神经网络算法

对图像(不同的数据窗口数据)和滤波矩阵(一组固定的权重:因为每个神经元的多个权重固定,所以又可以看做一个恒定的滤波器filter)做内积(逐个元素相乘再求和)的操作就是所谓的『卷积』操作,也是卷积神经网络的名字来源。在卷积神经网络(CNN)中,通常会同时使用前向传播和反向传播来训练模型。这两种传播过程是深度学习模型训练的关键组成部分。

  1. 首先通过前向传播计算模型的输出
  1. 卷积层(Convolutional Layer)

卷积层是CNN的核心组成部分,它通过使用多个滤波器(也称为卷积核)对输入数据进行卷积操作。每个滤波器在输入数据上进行滑动,计算出对应位置的卷积结果。这样可以提取出输入数据的局部特征。卷积操作的数学表示如下:

Ci,j=k=1ml=1nIi+k-1,j+l-1Kk,l

其中,I表示输入的数据,K表示卷积核,C表示卷积结果。在卷积操作时,卷积核会逐渐滑动并扫描整个输入数据,从而提取出与卷积核相关的特征信息。

  1. 激活函数(Activation Function)

在卷积操作后,通常会对卷积结果应用一个非线性激活函数,如ReLU(Rectified Linear Unit)。激活函数的作用是引入非线性特性,增强模型的表达能力。ReLU函数的数学表示如下:

f(z)=max(0,z)

其中,z表示输入数据。

  1. 池化层(Pooling Layer)

池化层用于减小特征图的空间尺寸,同时保留重要的特征信息。最常用的池化操作是最大池化(Max Pooling),它在每个区域中选择最大值作为池化结果。最大池化的数学表示如下:

Si,j​=k,lmax​(Ii+k-1,j+l-1​)

其中,I表示输入数据,S表示池化结果。

  1. 全连接层(Fully Connected Layer)

在经过一系列卷积和池化操作后,通常会将特征图展平为一维向量,并通过全连接层进行分类或回归等任务的处理。全连接层中的神经元与前一层的所有神经元相连。全连接层的数学表示如下:

Y=f(XW+b)

其中,X表示输入数据,W表示权重矩阵,b表示偏置项,f表示激活函数,Y表示输出结果。

  1. 利用反向传播计算梯度并更新参数

反向传播是CNN中用于训练模型的关键过程,通过反向传播,模型可以根据预测结果与真实标签之间的差异来更新模型参数,以使预测结果逐渐接近真实标签。下面是反向传播的主要步骤:

  1. 损失函数(Loss Function)

损失函数用于衡量模型的预测结果与真实标签之间的差距。常见的损失函数包括均方误差(Mean Squared Error)和交叉熵损失(Cross Entropy Loss)等。损失函数的数学表示如下:

L(θ)=N1​i=1∑N​l(f(xi​;θ),yi​)

其中,f表示CNN模型,xi表示输入数据,yi表示真实标签,l表示损失函数,θ表示模型参数,N表示样本数量。

  1. 梯度计算

通过链式法则,从输出层开始,计算损失函数对各层参数的梯度。梯度表示参数的变化对损失函数的影响程度,利用梯度可以指导参数的更新方向。具体地,梯度计算的数学表示如下:

∂Lwj=∂L∂y∂y∂u∂uwj

其中,L表示损失函数,y表示输出结果,u表示中间变量,wj表示第j个参数。

  1. 参数更新

根据计算得到的梯度信息,使用优化算法(如随机梯度下降法)对模型参数进行更新。参数更新的目标是沿着梯度下降的方向,逐步减小损失函数的值。具体地,参数更新的数学表示如下:

wjwj-η∂Lwj

其中,η表示学习率。

  1. 反向传播

将更新后的梯度信息从输出层向输入层进行传播,以便计算更底层的参数的梯度。通过反复迭代上述过程,不断更新参数,使模型逐渐收敛于最优解。

PCA+SVC算法

PCA+SVC(Principal Component Analysis + Support Vector Classifier)算法是一种常用的机器学习方法,用于进行特征提取和分类任务。在掌纹识别中,该算法可以用于分析和识别掌纹图像。

  1. 数据准备:首先,需要收集一组已知标签的掌纹图像样本。每个样本都应该有一个正确的类别标签,例如"正常"或"异常"。这些图像应该经过预处理步骤,如去噪、增强,以及对比度调整等。
  2. 特征提取(PCA):PCA是一种常用的降维技术,用于从高维数据中提取最重要的特征。对于掌纹图像,可以将每个像素点作为一个特征,并且将图像转换为灰度图像以简化处理。然后,将所有图像样本的特征矩阵合并成一个大矩阵X。这个矩阵的大小为m×n,其中m为样本数,n为特征数。然后,通过下列公式计算主成分:
  1. 计算均值向量:μ=(1/m)∑xi (i=1,2,...,m)
  2. 计算协方差矩阵:C=(1/m)XT
  3. 对协方差矩阵C进行特征值分解:C=VΛVT
  4. 选择前k个最大的特征值,对应的特征向量为V=(v1,v2,...,vk)
  5. 将X映射到低维空间:Z=XTV

其中,μ为均值向量,C为协方差矩阵,V为特征向量,Λ为特征值向量,k为保留的主成分数目,Z为降维后的特征矩阵,大小为m×k。

  1.  训练模型(SVC):在训练阶段,使用带有已知标签的降维特征向量作为输入,训练SVC模型以学习掌纹图像的分类规则。SVC是一种监督学习算法,它通过构建一个最优的分割超平面来将样本分成不同的类别。在训练过程中,SVC会找到一个最佳的超平面,使得同一类别的样本尽可能靠近彼此,而不同类别的样本尽可能远离。这样,当有新的未知掌纹图像输入时,模型就可以根据其特征向量来预测其所属的类别。

SVC的分类函数可以表示为:

f(x)=sign(∑αiyiK(xi,x)+b)

其中,x为待分类样本,yi为第i个样本的类别标签,αi为SVC模型的系数,K(·,·)为核函数,b为偏置项。

常用的核函数有线性核、多项式核和径向基核(RBF)。其中,RBF核函数是最常用的一种核函数,其公式如下:

K(xi,xj)=exp(-γ||xi-xj||^2)

其中,γ是RBF核函数的参数,||·||表示向量的欧几里得距离。

  1. 特征提取和分类(测试阶段):在测试阶段,对于新的未知掌纹图像,首先将其进行与训练阶段相同的预处理,并提取与训练阶段相同的特征向量。然后,使用训练好的PCA模型将特征向量降维到与训练阶段相同的低维空间。最后,利用训练好的SVC模型对降维后的特征向量进行分类,得到该掌纹图像的类别标签。
  • 程序框架
卷积神经网络算法
PCA+SVC算法
  • 实验过程和结果分析

卷积神经网络算法

  1. 代码编写与运行结果

对于数据集的测试集与训练集的划分,我将每6张图片(即每一个人)的前4张图片作为训练集,后两张图片作为测试集,所以最终训练集有400张图片,测试集有200张图片,在我的卷积神经网络模型中,有三个卷积层,分别包含 32、64 和 128 个滤波器(filter)。每个滤波器的大小为 (3, 3),并采用 ReLU 激活函数。

  1. 模型参数
  1. 训练过程

可以看到最终训练的精确率为0.845,当训练到第16轮时精度有所下降,说明此时模型已经开始出现过拟合现象了,于是我最终截取到第15轮的训练结果

  1. 训练集与测试集的精度对比

从精度折线图中可以看出,从第10轮训练开始,训练集与测试集的精度都开始趋于平缓,训练集保持在1的精度,而测试集大概在0.8,但是当训练到第16轮时精度有所下降,说明此时模型已经开始出现过拟合现象了。

  1. 鲁棒性与复杂度分析

从结果中可以看出,模型在测试集上的准确率为1.0,表明模型具有较好的鲁棒性。此外,我们还使用数据增强技术对训练数据进行扩充,以提高模型的鲁棒性。模型的复杂度可以通过model.summary()函数输出的结果来查看,该模型共有4,532,924个可训练参数。

PCA+SVC算法
  1. 代码编写与运行结果

最后的训练结果显示准确率为1,说明本模型效果极好。

  1. 不同降维数结果对比

降维到300与100:

 

对比结果显示,不同降维数得到的精度变化曲线有所差异,降到300维时曲线能够快速收敛到1,而降到100维时,由于丢失了较多特征,最后的精度变低,收敛速度也变慢

  1. 模型最佳参数

模型最后选择的最佳参数为:'svc__C'为50,'svc__gamma'为0.0001,参数'svc__C'表示正则化参数,数值越大表示模型对误分类样本的惩罚力度越大;参数'svc__gamma'表示核函数的系数,控制数据映射到高维空间后的分布,数值越小表示映射效果越强。

  1. 置信度分数

这里只分析测试集中第一个样本预测后的置信度分数

可以看到这个样本在类别0上的置信度分数为几乎为100,说明它几乎有百分之100的概率为类别1,实际上它的标签确实是类别0,说明模型在测试集上的预测的置信度高,模型训练效果良好

  1. 模型鲁棒性分析

使用交叉验证来评估模型在不同参数组合下的性能,并计算平均测试分数和标准差。然后,使用errorbar函数绘制了鲁棒性图,显示了平均测试分数及其标准差的变化。

  1. 模型的复杂度分析

通过绘制训练准确率随迭代次数变化的折线图实现的。它展示了模型的复杂度随着训练的进行而变化。

  • 结论和心得体会

本研究报告使用了两种算法,其中卷积神经网络的精度为0.845,而PCA+SVC算法的精度达到1.说明卷积神经网络在掌纹识别上面的效果没有PCA+SVC算法的效果好。

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值