特征臉?biāo)惴?/h2>

前言

特征臉?biāo)惴ㄊ菇?jīng)典的人臉識別算法,特征臉?biāo)惴ㄊ褂昧薖CA方法。本文介紹了PCA算法和其應(yīng)用特征臉?biāo)惴?/p>

算法流程

特征臉?biāo)惴ǎ?/p>

  1. 設(shè)數(shù)據(jù)集D為MN\times N 的圖片\{\Phi_1, \Phi_2....\Phi_M\},則將圖片展開,組成M\times N^2 大小的矩陣。

  2. 計算此矩陣的對均值向量\bar{\Phi} ,此為N\times N,對每個圖片,計算\tilde{\Phi}_i = \Phi_i-\bar\Phi_i。

  3. 計算\tilde{\Phi}的協(xié)方差矩陣C=\tilde{\Phi}^T\tilde{\Phi},注意C的大小為(N\times N) \times (N \times N)。C尋找的是像素之間的關(guān)系而不是圖片之間的關(guān)系

  4. 計算算C的特征值\{\lambda_1,\lambda_2,...,\lambda_{N\times N}\}與其對應(yīng)的特征向量\{\mathbf{v_1},\mathbf{v_2},...,\mathbf{v_{N\times N}}\} ,找到前n個特征值所對應(yīng)的特征向量,組成新的矩陣V。

  5. 改變基。以特征向量作為新的基做新的圖片I' = \tilde{\Phi} V

  6. 使用KNN進(jìn)行分類

算法原理

如果我們要學(xué)習(xí)一組圖片\Omega的基V_{\Omega},讓\Omega=\{\alpha^{(1)},\alpha^{(2)},...,\alpha^{(N)}\},其中\alpha^{(i)}=\{\alpha^{(i)}_1,\alpha^{(i)}_2,...,\alpha^{(i)}_{mn}\}

那么對于所有的圖片,找到一個圖片近似\alpha^{(0)},對以下的J_0(\alpha^{(0)})求最小值

J_0(\alpha^{(0)})=\Sigma^N_{i=0}||\alpha^{(0)}-\alpha^{(i)}||^2_2

其中||\alpha^{(0)}-\alpha^{(i)}||^2_2是歐幾里得平方距離

\alpha^{(0)}是一個在\Omega的基中的一張圖片

如果要使J_0(\alpha^{(0)})最小,則易得\alpha^{(0)}是樣本圖片的均值\alpha^{(0)}=m=\frac{1}{N}\sum\limits_{k=1}^n\alpha^{(i)}(偏導(dǎo))

J_0(\alpha^{(0)})=\Sigma^N_{i=0}||(\alpha^{(0)}-m)-(\alpha^{(i)}-m)||^2_2

其中\alpha^{(0)}-m=0 。所以 J_0(\alpha^{(0)})=\Sigma^N_{i=0}||m-\alpha^{(i)}||^2_2,此式獨(dú)立于\alpha^{(0)}

\Omega的零維呈現(xiàn)是一個點(diǎn) \Omega的一維呈現(xiàn)是一條線

\mathbf{e}是通過\alpha^{(0)}的一條線的方向。e回使\Omega的方差達(dá)到最高

\alpha=\alpha^{(0)}+a\mathbf{e}\ a\in\mathbb{R} \ \ e\in\mathbb{R^{mn}} \ \ ||e||=1

其中\alpha是任意圖像

\alpha^{(0)}是平均圖像

J_1(\{\alpha^{(1)},\alpha^{(2)},...,\alpha^{(N)}\}, \mathbf{e})=\Sigma^N_{i=0}||(\alpha^{(0)}+a^{(i)}\mathbf{e})-\alpha^{(i)}||^2=\sum\limits_i(a^{(i)})^2-2\sum\limits_i a^{(i)}\mathbf{e}^T(\alpha^{(i)}-\alpha^{(0)})+\sum\limits^N_{i=0}||\alpha^{(0)}-\alpha^{(i)}||^2_2 \frac{\partial J_1}{\partial a^{(i)}}=2a^{(i)}-2\mathbf{e}^T(\alpha^{(i)}-\alpha^{(0})

當(dāng)求出來的偏導(dǎo)為0的時候a^{(i)}=\mathbf{e}^T(\alpha^{(i)}-\alpha^{(0)}),可以將a\mathbf{e}代替

那么如何決定\mathbf{e}的方向呢?

J_1(\{\alpha^{(1)},\alpha^{(2)},...,\alpha^{(N)}\}, \mathbf{e})=\sum\limits_i(a^{(i)})^2-2\sum\limits_i a^{(i)}\mathbf{e}^T(\alpha^{(i)}-\alpha^{(0)})+\sum\limits^N_{i=0}||\alpha^{(0)}-\alpha^{(i)}||^2_2\\=-\sum\limits_i [\mathbf{e}^T(\alpha^{(i)}-\alpha^{(0)})]^2+\sum\limits^N_{i=0}||\alpha^{(0)}-\alpha^{(i)}||^2_2\\=-\sum\limits_i\mathbf{e}^T(\alpha^{(i)}-\alpha^{(0)})(\alpha^{(i)}-\alpha^{(0)})^T\mathbf{e}+\sum\limits^N_{i=0}||\alpha^{(0)}-\alpha^{(i)}||^2_2

其中(\alpha^{(i)}-\alpha^{(0)})(\alpha^{(i)}-\alpha^{(0)})^T\Omega的協(xié)方差矩陣

S=(\alpha^{(i)}-\alpha^{(0)})(\alpha^{(i)}-\alpha^{(0)})^T

由于\sum\limits^N_{i=0}||\alpha^{(0)}-\alpha^{(i)}||^2_2是常數(shù)

\arg \min\limits_{e} \hat{J_1}(\mathbf{e})=-\mathbf{e}^T\mathbf{S}\mathbf{e}其中||\mathbf{e}||=1

使用拉格朗日乘子法

\mathbf{u}=\mathbf{e}^T\mathbf{S}\mathbf{e}-\lambda(\mathbf{e}^T\mathbf{e}-1)

\frac{\partial \mathbf{u}}{\partial \mathbf{e}}=2\mathbf{S}\mathbf{e}-2\lambda\mathbf{e}

當(dāng)\frac{\partial \mathbf{u}}{\partial \mathbf{e}}=0的時候

\mathbf{S}\mathbf{e}=\lambda\mathbf{e}

所以選取前d\lambda所對應(yīng)的\mathbf{e}

為什么選擇最大的\lambda:

\hat{J_1}(\mathbf{e})=-\mathbf{e}^T\mathbf{S}\mathbf{e}=-\lambda\mathbf{e}^T\mathbf{e}=-\lambda

最大的\lambda使\hat{J_1}(\mathbf{e})最小

最后新的基為

\alpha=\alpha^{(0)}+\sum\limits^d_{i=1}a_i\mathbf{e}_i\\\mathbf{e_i}^T\mathbf{e}_j=0\quad \forall i \neq j

這種算法也被稱作PCA,可以看作是一個由原來維度的向量到d大小的向量的投影

代碼

from sklearn.datasets import fetch_openml
import numpy as np

mnist = fetch_openml('mnist_784', cache=False)

x_train = mnist.data.astype('float32')[:2000] / 255
y_train = mnist.target.astype('int64')[:2000]

x_test = mnist.data.astype('float32')[2000:2500] /255
y_test = mnist.target.astype('int64')[2000:2500]


def zero_mean(x_train, x_test):
    x_train_mean = np.mean(x_train, axis=0)
    x_train_norm = x_train - x_train_mean
    x_test_norm = x_test - x_train_mean
    return x_train_norm, x_test_norm


def compute_basis(data, n=300):
    C = data.T @ data
    w, v = np.linalg.eig(C)
    basis_indices = np.argsort(w)[::-1][:n]
    eigenvectors = v[basis_indices]
    return eigenvectors.T


def change_basis(data_matrix, eigenvectors):
    I_eig = data_matrix @ eigenvectors
    return I_eig


def knn_predict(eig_train_x, eig_test_x, y_train, y_test, k=1):
    predictions = np.zeros_like(y_test)
    for i in range(eig_test_x.shape[0]):
        x = eig_test_x[i]
        distance_vector = np.sum((eig_train_x - x) ** 2, axis=1)
        nearest_indices = np.argsort(distance_vector)[:k]
        a = y_train[nearest_indices]
        uni, count = np.unique(a, return_counts=True)
        predictions[i] = uni[np.argmax(count)]
    return predictions


if __name__ == '__main__':
    x_train_norm, x_test_norm = zero_mean(x_train, x_test)
    eigenvectors = compute_basis(x_train_norm)
    eig_train_x = change_basis(x_train_norm, eigenvectors)
    eig_test_x = change_basis(x_test_norm, eigenvectors)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容