人脸识别中KPCA与LDA特征融合:原理、实现与参数调优
2026/9/19 15:14:46 网站建设 项目流程

简介:人脸识别领域的学术参考文献PDF,聚焦于基于KPCA与LDA融合改进的人脸识别算法研究,适合从事图像处理、模式识别研究的学生与工程师阅读。压缩包仅含1个PDF文件,大小约560KB,收录了郑州大学学报2015年刊出的论文全文,可作为课题论证和算法实现的直接参考。文档详细介绍了白化与低通滤波预处理、DT-CWT与Gabor小波特征提取、KPCA最佳样本均值估计和改进LDA分类等关键步骤,并系统分析了PCA无法处理非线性问题及LDA“小样本”问题的成因,给出了融合改进的解决途径。目前已有144人学习下载,对于撰写相关论文或设计人脸识别系统的读者而言,具有较好的参考价值。

1. 人脸识别里 KPCA 和 LDA 融合要解决的那个非线性困境

在人脸识别里,比“认错人”更常见的是“特征没提对”:同一张脸在强光和侧光下的像素值分布可以差很远,按欧氏距离去比,同一个人的两张照片甚至比不同人的两张照片还要远,只靠线性主成分分析(PCA)降维的识别链路在这种输入下基本靠猜。核主成分分析(Kernel PCA, KPCA)先把图像映射到高维核空间再提取主成分,对光照、姿态这类非线性变化能兜住一部分;线性判别分析(Linear Discriminant Analysis, LDA)则盯着类间离散度和类内离散度的比值,把“谁和谁长得像”直接写进投影方向。于是有了一个非常自然的融合思路:先用 KPCA 把人脸图像转成非线性特征坐标,再把这些坐标交给 LDA 做判别压缩,或者把两者投影拼成联合特征。下面从核矩阵构造、判别投影、融合策略到识别率验证,把会直接影响结果的关键参数和坑逐个拆开。

2. KPCA 核映射的建立:核矩阵中心化与 RBF 参数选择

开始写融合代码之前,需要先确认 KPCA 的行为,因为它决定了后面 LDA 看到的输入分布长什么样。PCA 在原始欧氏空间里找方差最大的方向,而人脸图像里的光照整体偏移、遮挡和局部反射,在像素层面表现为大量分量同时变化,这些非线性结构并不能用少数几个线性子空间描述。KPCA 的做法是定义一个非线性映射 φ,把每个图像向量 x 送到更高维的特征空间,在那个空间里再做一次和 PCA 完全相同的事情。由于映射空间可能维度非常高,显式计算不现实,实践全靠核函数 k(x,y)=⟨φ(x),φ(y)⟩ 隐式完成内积。

2.1 核矩阵中心化:KPCA 实现里最容易跑偏的第一步

KPCA 的计算起点是核矩阵 K,其中 K[i][j]=k(x_i,x_j)。直接对原始核矩阵做特征分解是不对的,因为 φ(x_i) 在高维空间里的均值并没有被显式去除。标准做法是对核矩阵做双中心化:

K_c = K − 1_N·K − K·1_N + 1_N·K·1_N

其中 1_N 是每个元素都等于 1/N 的 N×N 矩阵。这一操作等价于把每个样本的核映射结果减去高维空间里的均值向量。用 numpy 实现并不复杂。

import numpy as np def center_kernel_matrix(K): """对原始核矩阵做双中心化,移除高维特征空间里的均值偏移 K: 原始核矩阵,(n_samples, n_samples) """ n = K.shape[0] ones = np.ones((n, n)) / n return K - ones @ K - K @ ones + ones @ K @ ones

逻辑上看,四个项的顺序就对应公式右侧的四项:两个减号项分别消掉行均值和列均值,最后一个加号项补偿被重复减掉的全局均值。很多自己手写 KPCA 的实现,最后识别率上不去,问题往往不是核函数选错,而是漏了中心化这一步。对比 sklearn 的 KernelPCA 时要注意,它的 fit_transform 内部已经完成了中心化;自己实现核矩阵时不能跳过。中心化缺失时的典型表现是:gamma 不管怎么调,测试识别率都停留在一个很低的位置,并且不同类别的投影中心挤在一起。调试时建议先把中心化前后的核矩阵各画一次热力图,中心化后行与行之间的数值差异应该明显拉开,如果看起来仍然很均匀,再回头检查 ones 矩阵是不是写成了单位阵。

2.2 RBF 核的 gamma 如何跟着图像尺寸走

人脸识别里最常见的核函数是 RBF:k(x,y)=exp(−γ||x−y||²)。γ 控制单个样本的影响半径,也决定了高维特征空间对局部差异的敏感程度。γ 太大时每个样本只在很小领域内有响应,核矩阵无限接近单位阵,KPCA 提取出来的是噪声;γ 太小时所有核值都趋近 1,核矩阵完全失去判别信息。一个可靠的初始参考值是 1/特征维度:输入是 64×64 的图像,展开成 4096 维,初始 gamma 就取 1/4096≈2.4e-4,然后前后各挪两个数量级做扫描,即候选集取 2.4e-6、2.4e-5、2.4e-4、2.4e-3。这个取法比凭空试 0.001、0.01、0.1 要可控,因为合理 gamma 区间会随着图像缩放明显移动,用固定网格容易把最优值漏在网格之外。

def rbf_gamma_grid(n_features, steps=4): """根据特征维度生成一组对数均匀的 gamma 候选值""" base = 1.0 / n_features return [base * (10 ** i) for i in range(-steps // 2, steps // 2)]

代码里的 steps=4 会生成 1e-2 倍到 1e2 倍的基准值,也就是从 base/100 到 base×100 的四个点。实际使用中如果发现识别率趋势还在上升,可以把范围再向外扩一个数量级;如果中间两个点都比较好,就缩小步长做第二轮扫描。把 gamma 的搜索范围写进函数而不是散落在实验脚本里,后面换数据集时能少改很多地方。

2.3 KPCA 保留成分数的上界和实用范围

还有一个维度问题值得单独提。KPCA 的非零特征值数量最多只有 N−1 个,N 是训练样本总数,所以 n_components 设置超过 N−1 没有意义。考虑到下一步 LDA 还要面对类内离散度矩阵的计算,我倾向于把 KPCA 维度控制在训练样本数的一半左右。以 ORL 这种 40 人每人 10 张图像的库为例,若每类取 5 张做训练,总共 N=200,KPCA 维度取 100 左右是稳妥的。如果非要把维度顶到接近 199,类内离散度矩阵的秩必定不足,后续广义特征分解会出现大量接近零的特征值,这些方向会被数值噪声主导,LDA 的判别方向随之漂移。

提示:KPCA 的保留成分数并不像 PCA 那样能靠“累计方差贡献率 95%”判断,因为核空间的方差分布和判别能力并不直接挂钩。人脸识别场景里先把维度放宽,再用交叉验证收缩,比直接按方差阈值截断更有效。

到这里 KPCA 输出的是一张形状为 (N, d_kpca) 的特征矩阵,下一步 LDA 将在这个坐标上工作,但它对输入有几个隐含要求,下面这部分单独展开。

3. LDA 判别投影在 KPCA 特征空间中的实现与维度约束

LDA 的核心目标可以压缩成一句:找到一组投影方向,让投影后不同类别的中心距离尽量大,同时同类样本的散布尽量小。和 PCA 只做无监督方差最大化不同,LDA 是带着标签做监督降维,所以它在人脸识别里的角色更接近“面向分类的线性变换”,只是输出维度受类别数限制,这个约束往往也是新手最容易忽略的地方。

3.1 类内、类间离散度矩阵与 Fisher 准则的计算

假设 KPCA 投影后得到 N 个 d 维样本。共 C 个类别,第 c 类样本数为 n_c,类均值为 u_c,全局均值为 u,那么类内离散度矩阵 S_w 和类间离散度矩阵 S_b 的定义是:

S_w = Σ_c Σ_{i∈c} (x_i − u_c)(x_i − u_c)^T
S_b = Σ_c n_c (u_c − u)(u_c − u)^T

Fisher 准则要找使 trace(S_w⁻¹S_b) 最大的投影方向,数学上等价于求解广义特征问题 S_b v = λ S_w v。特征值越大的方向,意味着投影后类间差异相对类内散布越显著。

import numpy as np def lda_projection(X, y, out_dim): """在 KPCA 特征坐标上计算 LDA 判别投影矩阵 参数: X: (n_samples, d),KPCA 投影后的特征矩阵 y: 类别标签,长度 n_samples out_dim: 输出判别方向数,最大为类别数减一 """ classes = np.unique(y) n_features = X.shape[1] global_mean = X.mean(axis=0, keepdims=True) S_w = np.zeros((n_features, n_features)) S_b = np.zeros((n_features, n_features)) for c in classes: X_c = X[y == c] n_c = X_c.shape[0] mean_c = X_c.mean(axis=0, keepdims=True) centered = X_c - mean_c S_w += centered.T @ centered diff = mean_c - global_mean S_b += n_c * (diff.T @ diff) # 求 S_w 的伪逆再解特征分解;工程上几乎都必须做正则化 eigvals, eigvecs = np.linalg.eigh(np.linalg.pinv(S_w) @ S_b) idx = np.argsort(eigvals.real)[::-1][:out_dim] return eigvecs[:, idx].real, eigvals.real[idx]

代码里 S_w 和 S_b 的累加方式是对定义式的直接翻译。centered.T @ centered 得到 d×d 的对称半正定矩阵,diff.T @ diff 同理。用 np.linalg.eigh 而不是 np.linalg.eig,是因为这个广义特征问题左侧是实对称矩阵,eigh 对对称矩阵有更稳定的数值行为,也不会出现复数特征值的假象。

3.2 小样本问题在 KPCA 空间的具体表现

人脸识别里几乎必然会遇到小样本问题:训练样本数 N 通常只有几百,而特征维度即便经过 KPCA 压缩也可能到几十上百,这直接导致 S_w 奇异。S_w 的秩最多只能是 N−C,当 KPCA 维度接近或超过该值时,其逆矩阵就不可靠。最常见的规避手段有两个。第一种是使用伪逆,上面的代码已经用 np.linalg.pinv 处理;第二种是在 S_w 对角线加一个小扰动,即 S_w += 1e-6 * np.eye(d)。伪逆的好处是不需要手动调扰动系数,但会放大微小奇异值对应的方向;加扰动的好处是数值更可控,但 1e-6 这个量级并不是万能的。我的做法是:当 KPCA 维度控制在 N/2 以内时用伪逆,当维度逼近 N 时改用扰动并同时把扰动系数也纳入交叉验证范围。

3.3 LDA 维度上限 C−1 带来的选择边界

LDA 输出的判别方向数上限是 C−1,因为 S_b 的秩最多只有 C−1,这是由“C 个类中心的偏移只能张成 C−1 维空间”决定的。以 ORL 40 人为例,LDA 之后最多只能拿到 39 维特征,这会让习惯了 PCA 可以从 100 维一路调到 300 维的人觉得很不适应。但超过 C−1 的特征值本来就是零,即使硬取进来也只是噪声。实际操作上的建议是:初期直接把 out_dim 设为类别数减一,先看整体识别率,再递减维度做敏感性观察。如果识别率在维度降到类别数一半时仍然没有明显下降,说明有效判别信息高度集中,后面甚至可以大胆剪枝。

4. KPCA 与 LDA 的两种融合路线:串行判别流与并行拼接流

“融合”这个词在论文里有很多变体,落到可以复现的代码层面,常见的不外乎串行和并行两条路线。串行融合是先 KPCA 后 LDA,两级特征提取串联成一条流水线;并行融合是把 KPCA 坐标和 LDA 判别坐标在特征层拼接,合成一个更长的向量再送分类器。两条路线各有适用场景,下面分别给出实现代码和选型边界。

4.1 串行融合:从像素到分类器的完整链路

串行融合链路可以封装成一个独立函数,关键参数集中暴露,修改和复现都方便。

from sklearn.decomposition import KernelPCA from sklearn.discriminant_analysis import LinearDiscriminantAnalysis from sklearn.neighbors import KNeighborsClassifier from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler def kpca_lda_serial(X, y, gamma, kpca_dim): """KPCA -> LDA 串行融合的完整流程 X: 人脸图像矩阵,(n_samples, n_pixels) y: 标签 gamma: RBF 核参数 kpca_dim: 中间 KPCA 保留的成分数 """ X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.5, stratify=y, random_state=42 ) scaler = StandardScaler().fit(X_train) X_train_s = scaler.transform(X_train) X_test_s = scaler.transform(X_test) kpca = KernelPCA(n_components=kpca_dim, kernel='rbf', gamma=gamma) Z_train = kpca.fit_transform(X_train_s) Z_test = kpca.transform(X_test_s) lda = LinearDiscriminantAnalysis( n_components=len(np.unique(y_train)) - 1, solver='eigen', shrinkage='auto' ) F_train = lda.fit_transform(Z_train, y_train) F_test = lda.transform(Z_test) knn = KNeighborsClassifier(n_neighbors=3) knn.fit(F_train, y_train) return knn.score(F_test, y_test)

这段代码中真正值得解释的是 LinearDiscriminantAnalysis 的两个参数。solver='eigen' 允许显式处理协方差奇异,sklearn 的默认 svd solver 在降维任务里不够灵活;shrinkage='auto' 让 LDA 依据样本量自动收缩类内离散度矩阵,比手动固定一个小常数稳定得多。KNeighborsClassifier 的 n_neighbors 取 3,在 ORL 这种小样本库上通常能保证足够的鲁棒性,如果每类训练样本只有 2 到 3 张,可以下调到 1 再观察过拟合迹象。串行融合的最终输出维度被 LDA 钳制在 C−1,这个低维空间对 KNN 而言计算开销几乎可以忽略。

4.2 并行融合:拼接前必须处理的两个前置问题

并行融合的思路是让 KPCA 的表示特征和 LDA 的判别特征各保留一部分,直接拼接后由分类器自己决定如何权衡。代码形态不复杂,但有两个前置操作绕不开。第一,两路特征的量纲和方差范围完全不同,KPCA 坐标的数值尺度由核矩阵特征值决定,LDA 坐标由 Fisher 准则缩放决定,直接拼接会让数值偏大的分支完全主导距离计算。我通常的做法是对每一段分别做 L2 行归一化再拼接。第二,拼接后的维度是 kpca_dim 加上 C−1,维度变高以后 KNN 在欧氏距离下容易失稳,这时候把分类器换成线性 SVM 往往更稳。

def normalize_rows(M): """对特征矩阵按行做 L2 归一化,让拼接段的尺度可比""" norms = np.linalg.norm(M, axis=1, keepdims=True) return M / (norms + 1e-12) # 示意:KPCA 坐标与 LDA 坐标各自归一化后拼接 z_kpca_n = normalize_rows(Z_train) # (n, kpca_dim) f_lda_n = normalize_rows(F_train) # (n, C-1) joint = np.hstack([z_kpca_n, f_lda_n])

normalize_rows 里加 1e-12 是为了防止某一行恰好为零向量时出现除零。拼接后 joint 的维度是 kpca_dim + (C−1),在 ORL 上大概是 100+39=139 维。这里最需要记住的是:并行融合不等于无脑提高维度,如果串行链路本身的识别率还没到 95%,拼接带来的只是更多噪声;只有当串行特征已经能稳定区分大多数样本时,拼接才有机会把剩余难例顶出来。

4.3 两条融合路线的选型比较

下面这张表是我在多个数据集上调参时沉淀下来的对照,适合在动手前先做方向判断。

对比维度串行融合 (KPCA→LDA)并行融合 (特征拼接)
输出维度最多 C−1 维,低而稳定kpca_dim 与 C−1 之和,可达上百维
计算开销一次核分解加一次判别分解两路投影都要跑,额外多一次归一化
核参数敏感性高,KPCA 的质量问题直接传导中等,LDA 分支能部分互补
小样本鲁棒性较好,前提是 kpca_dim 不过大维度升高会放大过拟合,样本少时慎用
常用分类器KNN 即可线性 SVM 或带正则的分类器更稳

这张表透露的信息是:样本量越紧张,越应该优先串行,把 KPCA 和 LDA 调到各自的最优状态;每类样本达到 10 张以上,才值得考虑并行拼接。很多融合识别率上不去,问题并不在融合方式本身,而是串行基线还没跑到正常水平就急着加复杂度。

5. 人脸库验证 KPCA-LDA 融合改进:对照分组与参数观察

要证明“融合改进有效”,不能只报一个最终识别率,需要做对照组,而且每个分组都要有可复现的配置。下面这套流程在 ORL 这种 40 人×10 张的小样本库上足够有说服力,也适合迁移到 Yale、AR 等更大规模的人脸库。

数据集划分建议采用每类随机取一半做训练、一半做测试,把随机划分重复 5 次,最终报告平均识别率和标准差。随机种子每次固定,比如统一用 random_state=42,保证多次对比是在同一批划分上进行的。分组至少准备四组:原始像素直接 KNN 作为基线,单用 KPCA 投影接 KNN,单用 PCA+LDA 的 Fisherface,以及本办法的 KPCA+LDA 串行融合。如果资源允许,再加入并行融合组和不同 gamma 下的串行组。

核参数观察有一条稳定规律:gamma 从 1e-6 向 1e-2 移动时,串行识别率通常会出现一个平台区。平台区的特征是训练集识别率接近 100%,测试集稳定在一个相对高位小幅波动。如果训练集几乎瞬间就 100% 而测试集只有七成多,基本可以断定 gamma 偏大,核矩阵过对角化,KPCA 抓的是训练样本各自独有的噪声。此时把 gamma 往小调两个数量级再重跑。反过来,如果训练集和测试集识别率都很低,说明gamma 过小或 KPCA 维度不足,先调 KPCA 维度再扫 gamma。

另一个常被跳过的验证技巧是观察 LDA 维数从 1 递增时的识别率曲线。由于 S_b 秩不超过 C−1,曲线在 C−1 之后必然不再变化。但如果曲线在小维度区间就进入平台,说明判别信息集中在前几个方向,后续分类器建在低维空间也够用。这种情况下并行融合的必要性会进一步下降,因为它只增加了维度而没有带来新的判别信息。

最后的参数排查可以按现象直接对照下表。

观察现象优先检查项调整方向
训练 100%,测试约 75%gamma 过大调小 1~2 个数量级
前几个 LDA 方向就平台化数据划分是否泄露重新划分并固定随机种子
kpca_dim 调大后识别率反而下降KPCA 维度接近 N从 N/2 向下收缩
并行拼接结果低于串行拼接段未归一化先加 L2 行归一化
每类训练样本低于 5融合方式本身退回串行并开启 shrinkage

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询