近年来,随着人脸识别技术的发展和研究的深入提出了很多成熟的识别算法如基于人工神经网络算法、基于模板匹配的算法、基于隐马尔科夫模型的算法等各种算法都有各自的优缺点。多种算法结合是目前人脸识别领域最受关注的方法,其优势在于综合利用了人脸面部的各种特征信息将各种成熟算法的优势相结合与单一算法相比,大大提高了人脸识别的效率和准确率。
任务一: 使用 ORL 人脸数据集,将数据集切分为训练集和测试集。
任务二: 使用主成分分析法,提取图像特征,并对图像进行重构。
任务三: 将未处理的图片放入 BP 神经网络和卷积神经网络进行分类。
任务四: 将经过特征提取的图片放入 BP 神经网络和卷积神经网络进行分类。
任务五: 对比收敛速度和识别准确率
ORL人脸数据集共包含 40个不同人的 400 张图像,是在 1992年4月至1994年4月期间由英国剑桥的 Olivetti 研究实验室创建。此数据集下包含 40个目录,每个目录下有 10 张图像,每个目录表示一个不同的人。所有的图像是以 PGM 格式存储,灰度图图像大小宽度为 92,高度为 112。对每一个目录下的图像,这些图像是在不同的时间、不同的光照、不同的面部表情 (睁眼/闭眼,微笑/不微笑)和面部细节(戴眼镜/不戴眼镜)环境下采集的。所有的图像是在较暗的均匀背景下拍摄的,拍摄的是正脸(有些带有略微的侧偏)
主成分分析是考察多个变量间相关性一种多元统计方法,研究如何通过少数几个主成分来揭示多个变量间的内部结构,即从原始变量中导出少数几个主成分,用较少的新变量代替原来较多的变量,而且使这些较少的新变量尽可能多地保留原来较多的变量所反映的信息。
在使用 PCA之前需要对数据进行中心化, 因为该方法对初始变量的方差非常敏感, 如果初始变量的范围之间存在较大差异, 将导致主成分的偏差。通过将数据转换为同 样的比例可以防止这个问题。假设训练样本集合 { T = X 1 , X 2 , ⋯ , X n } , X i ( i = 1 , 2 , ⋯ , n ) \left\{T=X_{1}, X_{2}, \cdots, X_{n}\right\}, X_{i}(i=1,2, \cdots, n) {T=X1,X2,⋯,Xn},Xi(i=1,2,⋯,n)是 p × q p \times q p×q维的图像矩阵,样本中心化公式如下:
X i ← X i − 1 m ∑ i = 1 m X i X_{i} \leftarrow X_{i}-\frac{1}{m} \sum_{i=1}^{m} X_{i} Xi←Xi−m1i=1∑mXi
为了识别变量的相关性以及后续通过协方差阵进行特征值分解, 我们计算协方差 矩阵:
G = 1 n ∑ i = 1 n ( A i − A ˉ ) ] T ( A i − A ˉ ) G=\frac{1}{n} \sum_{i=1}^{n}\left(A_{i}-\bar{A}\right)]^{T}\left(A_{i}-\bar{A}\right) G=n1i=1∑n(Ai−Aˉ)]T(Ai−Aˉ)
求协方差矩阵 G 的特征值 λ \lambda λ 和相对应的特征向量u:
C u = λ u C u=\lambda u Cu=λu
取最大的 k k k 个的特征值所对应的特征向量 w 1 , w 2 , ⋯ , w k w_{1}, w_{2}, \cdots, w_{k} w1,w2,⋯,wk, 拼接为投影矩阵:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 W = ( u 1 , u 2 , ⋯ , u k ) W=\left(u_{1}, u_{2}, \cdots, u_{k}\right) W=(u1,u2,⋯,uk)
计算样本在特征空间的投影, 获取特征提取后的图片:
A ∗ = X W A^{*}=X W A∗=XW
为了方便处理,将形状为 (400,112,92) 的原始数据集变为形状为(400,10304) 的数据。然后为保留 95% 的信息量,本文提取 161 个特征向量。处理后的图片信息如图 2所示。与原始数据(图 1) 相比,特征提取后的图像变得模糊,一些不重要的信息被删除。4
神经网络由许多并行运算的功能单元组成具有很强的容错性和鲁棒性,可以将其看作是一个函数映射,是一个多层前馈型网络,适用于有明确的输入和输出的对应关系。本文采用四层神经网络作为分类器(如图3),包括输入层、输出层和两个隐藏层隐藏层神经元个数为 512。
将原始数据分为训练集和测试集,比例为 7: 3,再将标签进行独热编码,使用SoftMax 对结果进行激活,损失函数使用对数损失。该模型直接使用原始图片进行训练,训练结果如图 4所示。最终,在测试集上的准确率为 92.50%。从图中可以看出,大概在 60 个训练周期左右,模型趋于收敛,准确率不再上升损失值也趋于稳定。并且训练集和验证集的准确率始终有一段差距。
将经过出成分分析处理后的图片放入模型中进行训练,从图 5中可以看出,大概在15 个训练周期左右,模型趋于收敛,准确率不再上升,损失值也趋于稳定。最终,在
测试集上的准确率为 95.83%。相比于未处理过的数据,该模型在训练时,模型的收敛速度提高了 4 倍,并且在训练时的波动更小,训练集和验证集的准确率也几乎相同,说明模型的鲁棒性较好。最后在测试集上的准确率提高了 3.33%。
将经过出成分分析处理后的特征矩阵模型中进行训练,结果如图 6所示,相比于未经过处理的图片,模型的收敛速度也提高了很多。并且在训练的速度上,比未经过处理的 BP 神经网络,训练速度快了3 秒左右。但是在测试集上的准确率只有 80.83%。
本文使用经典的卷积神经网络 LeNet构建分类器。这个网络虽然很小,但是它包含了深度学习的基本模块: 卷积层,池化层,全链接层,并且被认为是卷积神经网络的鼻祖。
从图 8中可以看出,该网络大概在第 100 个周期左右收敛,并且在训练时的波动幅度较大。最终在测试集上的准确率为 92.50%
从图 9中可以看出,大概在 40 个训练周期左右,模型趋于收敛,准确率不再上升,
损失值也趋于稳定。最终,在测试集上的准确率为 94.17%。相比于未处理过的数据,该模型在训练时,模型的收敛速度提高了 2.5 倍,并且在训练时的波动更小,训练集和验证集的准确率也几乎相同,说明模型的鲁棒性较好。最后在测试集上的准确率提高了 1.67%。
从图 10中可以看出,大概在 250 个训练周期左右,模型才趋于收敛,准确率不再上升,损失值也趋于稳定。最终,在测试集上的准确率为 75.83%。相比于前文的模型无论是在准确率还是收敛速度上,该模型表现最差。
通过对比本文所建立的模型可以看出 (表 1)。在 BP 神经网络的构建中,将进行主成分提取后的图片放入模型中效果最好,在准确率和训练速度上,分别为 95.83% 和15 个训练周期。
在LeNet 卷积神经网络的构建中,同样也是将经过主成分处理后的数据放入模型中的效果最好,准确率和训练速度上分别为 94.17% 和 40 个训练周期。
将两种类型的网络进行对比,BP 神经网络的收敛速度和准确率比 LeNet 卷积神经网络的准确率更高。
因此在该数据集的人脸识别任务上,BP 神经网络具有更大的优势。
#=================BP神经网络结构定义================
model = tf.keras.Sequential()
"""定义输入层与隐藏层"""
model.add(tf.keras.layers.Dense(units=512,#512,
input_dim=10304,
kernel_initializer='normal',
activation='relu'))
model.add(tf.keras.layers.Dense(units=512,#512,
#input_dim=784,
kernel_initializer='normal',
activation='sigmoid'))
"""定义输出层:40个神经元"""
model.add(tf.keras.layers.Dense(units=40,
kernel_initializer='normal',
activation='softmax'))
#=================LeNet结构定义================
model = tf.keras.Sequential()
""" 建立卷积层1"""
model.add(tf.keras.layers.Conv2D(filters=6,
kernel_size=(3,3),
strides=1,
# padding='same',
input_shape=(112,92,1),
activation='relu'))
""" 建立迟化层1"""
model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2),strides=2))
""" 建立卷积层2"""
model.add(tf.keras.layers.Conv2D(filters=16,
kernel_size=(3,3),
strides=1,
# padding='same',
input_shape=(28,28,1),
activation='relu'))
""" 建立迟化层2"""
model.add(tf.keras.layers.MaxPooling2D(pool_size=(2, 2),strides=2))
# 加入Dropout功能避免过度拟合
model.add(tf.keras.layers.Dropout(0.25))
""" 建立平坦层"""
model.add(tf.keras.layers.Flatten())
""" 建立隐藏层 """
model.add(tf.keras.layers.Dense(120, activation='relu'))
model.add(tf.keras.layers.Dense(84, activation='relu'))
# #加入Dropout功能避免过度拟合
model.add(tf.keras.layers.Dropout(0.5))
""" 建立输出层 """
model.add(tf.keras.layers.Dense(40,activation='softmax'))