非负矩阵分解提取人脸特征

    技术2026-01-14  8

    非负矩阵分解原理 顾名思义:是一个矩阵分解,并且分解矩阵非负。看起来这句话给人的信息量不大,背后却能挖掘NMF为什么会被提出且广泛被运用的原因。

    首先是NMF是一个矩阵分解,它和PCA(主成分分析)、ICA(独立成分分析)、SVD(奇异值分解)和VQ(矢量量化)等矩阵分解一样:在当前数据量庞大且巨大的时代,对数据的维数进行消减和高浓度压缩十分重要。

    其次是为什么非负,在上述提到的矩阵分解方法中,原始的大矩阵V被近似分解为低维(秩)的V=WH形式。这些方法的共同特点是,因子W和H中的元素可为正或负,即使输入的初始矩阵元素是全正的,传统的秩削减算法也不能保证原始数据的非负性。在数学上,从计算的观点看,分解结果中存在负值是正确的,但负值元素在实际问题中往往是没有意义的。例如图像数据中不可能有负值的像素点;在文档统计中,统计个数也不可能是负值。

    基本思想

    因此,NMF的基本思想就是:对于任意给定的一个非负矩阵V,找到两个非负矩阵W,H,使得一个非负的矩阵分解为左右两个非负矩阵的乘积。

    数学上:

    同时要求矩阵W,H非负。

    如果你仅仅知道什么是NMF,到这里就有现成的工具包供你调用,你也能得到想要的结果(W,H)。但为什么会保证得到的结果一定是正的,并且怎么得到解都对我们理解NMF有着很大帮助。这也是工作学习一直值得提倡的:授之以鱼不如授之以渔。

    数学模型与求解

    既然我们的目的是为了找到两个非负矩阵使得它们的乘积等于原矩阵,那么就可以变成求解下面的最小化问题:

    这种形式的问题,我们首先要想到的梯度下降来求解。而基于梯度下降的方法,加减运算是无法保证非负的。但事实上,我们可以基于乘法运算来保证与梯度下降是等价的。

    首先上述损失函数能够写成: 然后对其求梯度: 再依据梯度下降的思路: 代入上述的迭代方程就能够得到H矩阵的更新形式。 W矩阵的求解过程和H是一样的,这里就不在重复敲公式了 - -。只给出最后的更新形式,有兴趣的自己推导 代码实现只要根据上述两个迭代公式从初始随机产生的H,W一步步迭代找到最优值就行。

    这样,基于非负矩阵分解的原理和求解过程就了然于胸了~

    Python实例:用非负矩阵分解提取人脸特征 sklearn库:sklearn.decomposition.NMF 主要参数有: n_components:指定分解后基向量矩阵W的基向量个数k init:W矩阵和Z矩阵的初始化方式,默认为‘nndsvdar’ 目标:已知Olivetti人脸数据共400个,每个数据是64*64大小。由于NMF分解得到的W矩阵相当于从原始矩阵中提取的特征,那么就可以使用NMF对400个人脸数据进行特征提取。 程序如下:

    from numpy.random import RandomState import matplotlib.pyplot as plt from sklearn.datasets import fetch_olivetti_faces #加载Olivetti人脸数据集导入函数 from sklearn import decomposition n_row, n_col = 2, 3 n_components = n_row * n_col #设置提取的特征的数目 image_shape = (64, 64) #设置展示时人脸数据图片的大小 dataset = fetch_olivetti_faces(shuffle=True, random_state=RandomState(0)) faces = dataset.data def plot_gallery(title, images, n_col=n_col, n_row=n_row): plt.figure(figsize=(2. * n_col, 2.26 * n_row)) plt.suptitle(title, size=16) for i, comp in enumerate(images): plt.subplot(n_row, n_col, i + 1) vmax = max(comp.max(), -comp.min()) plt.imshow(comp.reshape(image_shape), cmap=plt.cm.gray, interpolation='nearest', vmin=-vmax, vmax=vmax) plt.xticks(()) plt.yticks(()) plt.subplots_adjust(0.01, 0.05, 0.99, 0.94, 0.04, 0.) plot_gallery("First centered Olivetti faces", faces[:n_components]) estimators = [('Eigenfaces - PCA using randomized SVD', decomposition.PCA(n_components=n_components, whiten=True)), ('Non-negative components - NMF', decomposition.NMF(n_components=n_components, init='nndsvda', tol=5e-3))] for name, estimator in estimators: print("Extracting the top %d %s..." % (n_components, name)) print(faces.shape) estimator.fit(faces) #调用PCA或NMF提取特征 components_ = estimator.components_ #获取提取的特征 plot_gallery(name, components_[:n_components]) plt.show()  

    运行结果: Extracting the top 6 Eigenfaces - PCA using randomized SVD… (400, 4096) Extracting the top 6 Non-negative components - NMF… (400, 4096) 参考链接: https://www.jianshu.com/p/634a6b0ec4f0 https://www.cnblogs.com/picassooo/p/12917090.html

    Processed: 0.018, SQL: 9