PCA+SVM人臉識別:從原理到調(diào)參的完整實(shí)戰(zhàn)指南)
簡介這份文檔資料面向計(jì)算機(jī)視覺與機(jī)器學(xué)習(xí)方向的學(xué)生、研究人員及工程實(shí)踐者圍繞基于改進(jìn)PCA與SVM的人臉識別系統(tǒng)展開適合作為課程設(shè)計(jì)、畢業(yè)設(shè)計(jì)或算法入門的學(xué)習(xí)參考。壓縮包內(nèi)僅含1個(gè)docx文件整體約609KB以文字與公式推導(dǎo)為主便于在電腦端閱讀與整理筆記。文檔系統(tǒng)梳理了人臉識別流程涵蓋Gamma校正預(yù)處理、平均臉與協(xié)方差矩陣計(jì)算、SVD降維、核主成分分析KPCA改進(jìn)思路以及SVM超平面構(gòu)建、松弛變量與拉格朗日優(yōu)化等關(guān)鍵內(nèi)容并對比了最近鄰、K近鄰、貝葉斯等分類器的適用場景。目前已有153人學(xué)習(xí)讀者可借此理解PCA與SVM結(jié)合的分類框架掌握從特征提取到分類識別的完整技術(shù)脈絡(luò)為后續(xù)結(jié)合CNN等深度模型打下基礎(chǔ)。1. 從一份 .docx 標(biāo)題說起改進(jìn) PCASVM 的人臉識別到底在解決什么如果你手頭正好有一份名為「基于改進(jìn)PCASVM的人臉識別系統(tǒng).docx」的文檔或者你正在做課程設(shè)計(jì)、畢業(yè)設(shè)計(jì)、企業(yè)門禁原型看到這個(gè)標(biāo)題的第一反應(yīng)大概是PCA 降維加 SVM 分類這不是十幾年前就玩爛的組合嗎確實(shí)PCA 特征臉加 SVM 是人臉識別里最經(jīng)典的入門方案但標(biāo)題里「改進(jìn)」兩個(gè)字才是真正值錢的地方。原始 PCASVM 在 ORL、Yale 這類小庫上能跑到 95% 以上可一旦換到光照變化、姿態(tài)偏轉(zhuǎn)、樣本量少的真實(shí)場景準(zhǔn)確率斷崖式下跌這就是為什么需要改進(jìn)。這篇文章不講空泛概念而是把「改進(jìn) PCASVM 人臉識別系統(tǒng)」從原理到代碼到調(diào)參到踩坑完整走一遍。適合三類人正在做相關(guān)課題、需要一份能跑通的實(shí)現(xiàn)已經(jīng)跑通基礎(chǔ)版、但準(zhǔn)確率卡住想找優(yōu)化點(diǎn)以及想搞清楚 PCA 主成分分析、SVM 硬間隔與軟間隔、核函數(shù)選擇這些細(xì)節(jié)到底怎么影響最終結(jié)果的工程師。讀完你應(yīng)該能自己搭出一套可復(fù)現(xiàn)的流程并且知道每一步的參數(shù)為什么這么設(shè)。2. 改進(jìn) PCASVM 的技術(shù)底座特征臉、核函數(shù)與改進(jìn)點(diǎn)在哪2.1 PCA 特征臉到底降了什么為什么它是雙刃劍PCA 主成分分析在人臉識別里的經(jīng)典叫法是「特征臉」Eigenfaces。它的核心動(dòng)作是把每張人臉圖像拉成一個(gè)列向量所有訓(xùn)練樣本組成一個(gè)大矩陣然后做協(xié)方差矩陣的特征值分解取最大的前 k 個(gè)特征值對應(yīng)的特征向量這些特征向量還原成圖像就是一張張「特征臉」。任何一張人臉都可以表示成這些特征臉的線性組合組合系數(shù)就是降維后的特征。關(guān)鍵點(diǎn)在于PCA 是無監(jiān)督的它只關(guān)心「哪些方向的方差最大」不關(guān)心「哪些方向?qū)^(qū)分不同人最有用」。方差大的方向可能是光照整體亮度變化而不是五官差異。這就是原始 PCA 的先天缺陷也是「改進(jìn)」的第一個(gè)切入點(diǎn)。常見改進(jìn)方向有三個(gè)一是加權(quán) PCA對不同特征臉按判別力加權(quán)二是把 PCA 和 LDA線性判別分析串起來先 PCA 降維再用 LDA 找類間類內(nèi)差異最大的方向也就是常說的 Fisherfaces三是在 PCA 之前做光照歸一化比如直方圖均衡化加 Gamma 校正把光照這個(gè)最大干擾源先壓下去。我一般會(huì)先做光照歸一化再上 PCA如果樣本每類有 5 張以上再疊加 LDA。這個(gè)順序不是拍腦袋是因?yàn)?PCA 對光照的敏感度遠(yuǎn)高于對姿態(tài)的敏感度先把光照這個(gè)「大方差噪聲源」處理掉PCA 保留的主成分才更可能落在人臉結(jié)構(gòu)上。2.2 SVM 在人臉識別里為什么比最近鄰更穩(wěn)降維之后每個(gè)人臉變成一個(gè)幾十到幾百維的向量接下來就是分類。最樸素的做法是最近鄰測試樣本離哪個(gè)訓(xùn)練樣本近就判為哪類。但最近鄰對噪聲和異常樣本極其敏感一張臟數(shù)據(jù)就能帶偏結(jié)果。SVM 的思路完全不同它找的是能把不同類別分開且間隔最大的那個(gè)超平面。這里要區(qū)分硬間隔 SVM 和軟間隔 SVM。硬間隔要求所有樣本都必須被正確分類且落在間隔之外現(xiàn)實(shí)中人臉數(shù)據(jù)幾乎不可能滿足光照、遮擋、表情都會(huì)讓類邊界模糊所以實(shí)際用的都是軟間隔引入松弛變量和懲罰系數(shù) C。C 越大對誤分類的容忍越低容易過擬合C 越小容忍度越高可能欠擬合。人臉識別里 C 通常從 1 到 100 之間調(diào)配合交叉驗(yàn)證選。另一個(gè)關(guān)鍵是核函數(shù)。人臉特征在降維后如果線性可分用線性核就夠速度快如果類邊界非線性用 RBF 核但要同時(shí)調(diào) gamma 參數(shù)。gamma 越大單個(gè)樣本影響范圍越小容易過擬合gamma 越小影響范圍越大決策邊界越平滑。經(jīng)驗(yàn)上 gamma 取 1/特征維度 作為起點(diǎn)再網(wǎng)格搜索。2.3 「改進(jìn)」的三個(gè)可落地方向把改進(jìn)拆成可操作的三個(gè)層面你就能對照自己的項(xiàng)目判斷該往哪走。第一層是數(shù)據(jù)預(yù)處理改進(jìn)光照歸一化、人臉對齊用眼睛坐標(biāo)做仿射變換、直方圖均衡化。這一步收益最大往往能帶來 5 到 15 個(gè)百分點(diǎn)的提升而且不挑分類器。第二層是特征提取改進(jìn)PCA 加權(quán)重、PCALDA 串聯(lián)、或者用 PCA 降維后再做一次類內(nèi)散度歸一化。這一步提升中等但會(huì)增加計(jì)算量和調(diào)參復(fù)雜度。第三層是分類器改進(jìn)從線性 SVM 換到 RBF 核 SVM或者用集成策略比如多個(gè) SVM 投票。這一步提升有限但實(shí)現(xiàn)簡單適合作為最后微調(diào)。下面這張表把三個(gè)方向的投入產(chǎn)出做個(gè)對比方便你按項(xiàng)目周期取舍。改進(jìn)方向典型提升實(shí)現(xiàn)難度額外計(jì)算開銷適合場景光照歸一化對齊5%~15%低小所有場景優(yōu)先做PCALDA3%~8%中中每類樣本≥5張加權(quán) PCA2%~5%中小樣本類別不均衡RBF 核 SVM2%~6%低大類邊界非線性多 SVM 集成1%~4%中大對穩(wěn)定性要求高3. 用 Python 把改進(jìn) PCASVM 人臉識別跑通從讀圖到出準(zhǔn)確率3.1 數(shù)據(jù)準(zhǔn)備與光照歸一化的最小代碼先假設(shè)你用 ORL 或自己采集的人臉庫目錄結(jié)構(gòu)是每類一個(gè)文件夾。下面這段代碼完成讀圖、灰度化、尺寸統(tǒng)一、直方圖均衡化和 Gamma 校正。import cv2 import numpy as np import os def load_faces(root_dir, img_size(100, 100), gamma1.5): X, y [], [] label 0 for person in sorted(os.listdir(root_dir)): person_dir os.path.join(root_dir, person) if not os.path.isdir(person_dir): continue for fname in os.listdir(person_dir): path os.path.join(person_dir, fname) img cv2.imread(path, cv2.IMREAD_GRAYSCALE) if img is None: continue img cv2.resize(img, img_size) # 直方圖均衡化壓光照差異 img cv2.equalizeHist(img) # Gamma 校正gamma1 提亮暗部細(xì)節(jié) inv_gamma 1.0 / gamma table np.array([((i / 255.0) ** inv_gamma) * 255 for i in np.arange(0, 256)]).astype(uint8) img cv2.LUT(img, table) X.append(img.flatten().astype(np.float32)) y.append(label) label 1 return np.array(X), np.array(y)邏輯說明equalizeHist把灰度分布拉平抵消整體明暗差異Gamma 校正用查找表實(shí)現(xiàn)gamma 大于 1 時(shí)暗部被提亮適合背光人臉。參數(shù)上img_size建議 100x100 起步太小丟細(xì)節(jié)太大增加 PCA 計(jì)算量。gamma在 1.2 到 2.0 之間試1.5 是常用起點(diǎn)。注意讀圖必須用灰度模式彩色通道對識別沒幫助反而引入噪聲。3.2 PCA 降維與主成分?jǐn)?shù)怎么定拿到 X 之后做 PCA。不要用 sklearn 的 PCA 直接 fit 原始數(shù)據(jù)先做零均值化然后看累計(jì)方差貢獻(xiàn)率。from sklearn.decomposition import PCA from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42, stratifyy) # 先看需要多少主成分能達(dá)到 95% 方差 pca_full PCA().fit(X_train) cum_var np.cumsum(pca_full.explained_variance_ratio_) n_95 np.argmax(cum_var 0.95) 1 print(達(dá)到95%方差需要主成分?jǐn)?shù):, n_95) # 實(shí)際取 95% 方差對應(yīng)的維度也可手動(dòng)指定 pca PCA(n_componentsn_95, whitenTrue) X_train_pca pca.fit_transform(X_train) X_test_pca pca.transform(X_test)邏輯說明whitenTrue讓各主成分方差歸一化這對后續(xù) SVM 很重要因?yàn)?SVM 對特征尺度敏感。n_components不要盲目取很大超過樣本數(shù)減類別數(shù)就沒意義了。經(jīng)驗(yàn)上主成分?jǐn)?shù)取 50 到 150 之間具體看n_95的輸出。如果n_95超過 200說明你的圖像分辨率太高或者光照沒處理好回去檢查預(yù)處理。3.3 SVM 訓(xùn)練與網(wǎng)格搜索調(diào)參接下來訓(xùn)練 SVM用網(wǎng)格搜索找 C 和 gamma。from sklearn.svm import SVC from sklearn.model_selection import GridSearchCV from sklearn.metrics import accuracy_score, classification_report param_grid { C: [1, 10, 50, 100], gamma: [scale, 0.001, 0.01, 0.05], kernel: [rbf, linear] } svm SVC(probabilityTrue) grid GridSearchCV(svm, param_grid, cv5, n_jobs-1, verbose1) grid.fit(X_train_pca, y_train) print(最優(yōu)參數(shù):, grid.best_params_) best_svm grid.best_estimator_ y_pred best_svm.predict(X_test_pca) print(測試準(zhǔn)確率:, accuracy_score(y_test, y_pred)) print(classification_report(y_test, y_pred))邏輯說明cv5做五折交叉驗(yàn)證樣本少時(shí)改 3。gammascale是 sklearn 默認(rèn)等于 1/(特征數(shù)*方差)通常是個(gè)合理起點(diǎn)。如果最優(yōu)結(jié)果是線性核說明你的數(shù)據(jù)在 PCA 后已經(jīng)線性可分沒必要用 RBF 增加開銷。probabilityTrue會(huì)慢一些但如果你要做拒識判斷是不是庫內(nèi)人就必須開。3.4 改進(jìn)版PCALDA 串聯(lián)的代碼改動(dòng)如果你每類樣本有 5 張以上可以在 PCA 后加 LDA。注意 LDA 降維后維度最多是類別數(shù)減一。from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA n_classes len(np.unique(y_train)) lda LDA(n_componentsmin(n_classes - 1, 50)) X_train_lda lda.fit_transform(X_train_pca, y_train) X_test_lda lda.transform(X_test_pca) grid.fit(X_train_lda, y_train) print(PCALDA 最優(yōu)參數(shù):, grid.best_params_) print(PCALDA 準(zhǔn)確率:, accuracy_score(y_test, grid.predict(X_test_lda)))邏輯說明LDA 是有監(jiān)督的它利用標(biāo)簽信息找類間差異最大的方向正好補(bǔ)上 PCA 無監(jiān)督的短板。n_components不能超過類別數(shù)減一否則報(bào)錯(cuò)。這一步通常能把準(zhǔn)確率再拉幾個(gè)點(diǎn)但如果每類只有一兩張樣本LDA 估計(jì)的類內(nèi)散度矩陣不可靠反而會(huì)掉點(diǎn)所以樣本少時(shí)跳過。4. 避坑與排查改進(jìn) PCASVM 人臉識別最常見的五個(gè)翻車點(diǎn)4.1 準(zhǔn)確率虛高換一批測試集就崩現(xiàn)象在 ORL 上跑出 98%自己拍幾張照片測試卻只有一半對。原因訓(xùn)練集和測試集來自同一批人同一環(huán)境PCA 的主成分里混入了大量環(huán)境信息模型記住的是「拍攝條件」而不是「人臉身份」。解決劃分?jǐn)?shù)據(jù)時(shí)按人劃分確保測試集的人不在訓(xùn)練集里或者至少按拍攝批次劃分。更嚴(yán)格的做法是留出整個(gè) session 做測試。4.2 PCA 維度取太大導(dǎo)致 SVM 訓(xùn)練極慢且過擬合現(xiàn)象n_components設(shè)成 300訓(xùn)練時(shí)間暴漲測試準(zhǔn)確率反而下降。原因高維空間里樣本稀疏SVM 找間隔最大超平面時(shí)容易把噪聲也當(dāng)成有效邊界。解決用累計(jì)方差貢獻(xiàn)率卡在 90% 到 95%或者直接網(wǎng)格搜索主成分?jǐn)?shù)把它當(dāng)成一個(gè)超參數(shù)。我一般會(huì)跑一個(gè)循環(huán)主成分?jǐn)?shù)從 20 到 200 步長 20看驗(yàn)證集準(zhǔn)確率曲線取拐點(diǎn)。4.3 忘記 whiten 導(dǎo)致 RBF 核失效現(xiàn)象RBF 核 SVM 準(zhǔn)確率還不如線性核。原因PCA 降維后各主成分方差差異巨大第一主成分方差可能是最后一個(gè)的幾百倍RBF 核的歐氏距離被大方差維度主導(dǎo)小方差維度幾乎不起作用。解決PCA 里加whitenTrue或者手動(dòng)對降維后特征做標(biāo)準(zhǔn)化。這個(gè)坑非常隱蔽因?yàn)椴患?whiten 也能跑只是效果差很多人以為是核函數(shù)選錯(cuò)了。4.4 類別不均衡時(shí) SVM 偏向多數(shù)類現(xiàn)象某一類樣本特別多測試時(shí)幾乎所有樣本都被判成這一類。原因軟間隔 SVM 的懲罰項(xiàng)對多數(shù)類更敏感超平面被推向少數(shù)類。解決SVC里設(shè)class_weightbalanced讓懲罰權(quán)重與類別頻率成反比。如果少數(shù)類樣本極少還要考慮過采樣或數(shù)據(jù)增強(qiáng)但增強(qiáng)后人臉要保證身份不變翻轉(zhuǎn)和輕微旋轉(zhuǎn)可以大角度變換會(huì)改變身份特征。4.5 預(yù)測階段忘記做同樣的預(yù)處理現(xiàn)象訓(xùn)練時(shí)準(zhǔn)確率很高部署后調(diào)用攝像頭實(shí)時(shí)識別全錯(cuò)。原因訓(xùn)練時(shí)做了直方圖均衡化和 Gamma 校正預(yù)測時(shí)直接拿原始幀送進(jìn) PCA特征分布完全對不上。解決把預(yù)處理封裝成一個(gè)函數(shù)訓(xùn)練和預(yù)測都調(diào)用同一個(gè)函數(shù)參數(shù)寫死不要改。這個(gè)坑是工程落地里最常見的血淚經(jīng)驗(yàn)就是預(yù)處理代碼一定要復(fù)用不要復(fù)制粘貼兩份。5. 讓系統(tǒng)真正可用拒識、增量與部署時(shí)的幾個(gè)技巧前面跑通的是閉集識別也就是假設(shè)測試樣本一定屬于庫內(nèi)某個(gè)人。真實(shí)系統(tǒng)必須能拒識判斷「這個(gè)人不在庫里」。做法是用 SVM 的predict_proba拿到最大概率如果低于閾值就拒識。閾值怎么定在驗(yàn)證集上畫一張拒識率與誤識率的曲線取等錯(cuò)誤率點(diǎn)作為閾值。我一般會(huì)把閾值設(shè)在 0.6 到 0.8 之間具體看業(yè)務(wù)對誤拒和誤識的容忍度。增量更新是另一個(gè)繞不開的問題。新員工入職要加人臉最笨的辦法是全量重訓(xùn) PCA 和 SVM樣本多了之后每次重訓(xùn)幾分鐘不可接受??尚械淖龇ㄊ荘CA 部分固定投影矩陣新樣本只做投影不更新主成分SVM 部分用增量 SVM 或者只對新增樣本做一次局部重訓(xùn)。如果新增類別SVM 必須重訓(xùn)因?yàn)槎喾诸惒呗宰兞恕K怨こ躺贤ǔ0醇径茸鲆淮稳恐赜?xùn)平時(shí)只做樣本累積。部署時(shí)還有一個(gè)技巧把 PCA 投影矩陣和 SVM 模型序列化保存預(yù)測服務(wù)啟動(dòng)時(shí)加載不要每次請求都重新 fit。用 joblib 保存即可。另外輸入圖像的人臉檢測和對齊要在預(yù)處理之前做用 OpenCV 的 Haar 或 DNN 人臉檢測器把臉框出來再按眼睛坐標(biāo)做仿射對齊這一步能顯著提升跨姿態(tài)的穩(wěn)定性。最后說一個(gè)我自己的習(xí)慣每次調(diào)完參數(shù)我會(huì)把當(dāng)次的主成分?jǐn)?shù)、C、gamma、準(zhǔn)確率記到一個(gè)表格里跑夠二十組之后回頭看往往能發(fā)現(xiàn)某些參數(shù)組合在特定數(shù)據(jù)分布下反復(fù)出現(xiàn)。這個(gè)記錄習(xí)慣幫我省了很多重復(fù)試錯(cuò)的時(shí)間。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取