最基本的SVM(Support Vector Machine)旨在使用一個超平面,分離線性可分的二類樣本,其中正反兩類分別在超平面的一側。SVM算法則是要找出一個最優的超平面。html
給定一個特徵空間線性可分的數據集:算法
$T = \{(x_1,y_1),(x_2,y_2),...,(x_N,y_N)\}$函數
特徵分佈相似下圖:學習
如上圖,當特徵空間爲二維時,超平面就是比二維空間第一維度的直線。任意維超平面定義以下(其中$x$是$n$維特徵向量,$w,b$是超平面係數):測試
$wx+b = 0$優化
對於正例應有$wx_i+b > 0$,反例應有$wx_i+b < 0$,也就是說,若是分類正確,應有:spa
$y_i(wx_i+b)> 0$3d
從直觀上看,最優超平面,應該是在將全部樣本都正確分類的基礎上,使與之距離最近的樣本點的距離最大化。點到面的距離公式中學學過code
$\displaystyle \frac{|wx+b|}{|| w ||}$component
綜上,優化的問題用數學方式表達:
$\displaystyle\max\limits_{w,b}\min\limits_{i}(\frac{y_i(wx_i+b)}{||w||})$
或者
$\begin{align*} &\max\limits_{w,b}\;\gamma \\ &\;\text{s.t.}\;\;\;y_i(\frac{w}{||w||}x_i+\frac{b}{||w||})\ge \gamma,\;\;i=1,2,...,N \end{align*}$
其中$\gamma$爲最小距離。令$ \hat{\gamma}=\gamma||w|| $,即所謂「函數距離」,上式可變爲:
$\begin{align*} &\max\limits_{w,b}\;\frac{\hat{\gamma}}{||w||} \\ &\;\text{s.t.}\;\;\;y_i(wx_i+{b})\ge \hat{\gamma },\;\;i=1,2,...,N\end{align*}$
$\hat{\gamma}$沒有被$||w||$規範化,所以大小與$||w||$有關。而$w,b$等比例變化時,超平面並無變。所以,能夠固定$||w||=1$,最大化$\hat{\gamma}$,即:
$\begin{align*} &\max\limits_{w,b}\;\hat{\gamma}\\ &\;\text{s.t.}\;\;\;y_i(wx_i+{b})\ge \hat{\gamma },\;\;i=1,2,...,N\end{align*}$
或者固定$\hat{\gamma}=1$,最小化$||w||$,也就是:
$\begin{align*} &\min\limits_{w,b}\;\frac{1}{2}||w||^2 \\ &\;\text{s.t.}\;\;\;y_i(wx_i+{b})\ge 1,\;\;i=1,2,...,N\end{align*}$
一般是最小化$||w||$。這是一個凸二次規劃問題,即待優化的函數$\frac{1}{2}||w||^2$是二次函數,不等式約束條件$1-y_i(wx_i+{b})\le 0$爲可微凸函數(注意!小於等於0要求凸函數,若是大於等於0就要求是凹函數了)。
上述帶約束優化知足原始問題最優值與對偶問題最優值取等的條件,所以可使用拉格朗日對偶性(點擊連接)將原始優化問題轉換爲其對偶問題求解。原始問題的拉格朗日函數爲:
$\displaystyle \begin{gather}L(w,b,\alpha) = \frac{1}{2}||w||^2- \sum\limits_{i=1}^{N}\alpha_iy_i(wx_i+b)+\sum\limits_{i=1}^{N}\alpha_i,\,\,\alpha\ge 0 \label{}\end{gather}$
所以原始問題爲:
$\displaystyle \begin{gather} \min\limits_{w,b}\max\limits_{\alpha\ge 0 }L(w,b,\alpha) \label{}\end{gather}$
則對偶問題爲:
$\displaystyle \begin{gather}\max\limits_{\alpha\ge 0 } \min\limits_{w,b}L(w,b,\alpha) \label{}\end{gather}$
由KKT條件1式令梯度爲0,計算對偶問題內部的$\min$函數
$\begin{aligned} &\nabla_wL(w,b,\alpha) = w-\sum\limits_{i=1}^{N}\alpha_iy_ix_i=0 \\ &\nabla_bL(w,b,\alpha) = -\sum\limits_{i=1}^{N}\alpha_iy_i=0 \\ \end{aligned}$
得
$\begin{gather} &w = \sum\limits_{i=1}^{N}\alpha_iy_ix_i \\ &\sum\limits_{i=1}^{N}\alpha_iy_i=0 \label{}\end{gather}$
代入$(3)$式,通過計算,對偶問題變爲:
$\begin{gather} \begin{array}{lcl} \min\limits_{\alpha}\displaystyle\frac{1}{2}\sum\limits_{i=1}^{N}\sum\limits_{j=1}^{N}\alpha_i\alpha_jy_iy_j(x_ix_j)-\sum\limits_{i=1}^{N}\alpha_i \\ \begin{aligned} \text{s.t.}\;&\sum\limits_{i=1}^{N}\alpha_iy_i=0\\ &\alpha_i\ge 0,i = 1,2,...,N \end{aligned} \end{array} \end{gather}$
這樣,只需先優化對偶問題,計算出最優的$\alpha^*$,再代入$(4)$式便可算出最優$w^*$。對於$b$,由於至少有一個$\alpha_j^*>0$(若是全都爲0,由$(4)$式有$w=0$,不符合約束),對應KKT條件2式
$\alpha_i(y_i(wx_i+b)-1)=0$
因而有
$y_j(w^*x_j+b^*)-1=0$
實際上這個$x_j$就是與超平面最近的的樣本,也就是所謂的支持向量。另外也說明了這個優化問題的解必定在不等式約束的邊界上,而不在其內部。因而,提取$b^*$並將$(4)$式代入,得:
$\begin{gather}\displaystyle b^* = y_j-\sum\limits_{i=1}^{N}\alpha_i^*y_i(x_ix_j)\end{gather}$
綜上,計算最優$w^*,b^*$的操做就是:先$(6)$式算出$\alpha^*$,再代入$(4),(7)$式算出$w^*,b^*$。
可是$(6)$實際上並很差算,當樣本量一大,$\alpha$須要分類討論的狀況數以指數級上升(即每一個$\alpha$是否爲0),後面介紹開銷小的算法。
有時樣本會有特異點,不能保證每一個樣本都知足不等式約束。所以修改上面的「硬間隔最大化」爲「軟間隔最大化」,則線性可分SVM變爲線性SVM。即添加一個鬆弛變量$\xi$,容許原來的不等式約束不必定嚴格知足,固然在優化函數中也要把這一損失加上,乘上懲罰參數$C$。獲得以下最優化問題:
$\begin{gather} \begin{array}{lcl} \min\limits_{w,b,\xi}\;\displaystyle\frac{1}{2}||w||^2+C\sum\limits_{i=1}^{N}\xi_i \\ \begin{aligned} \text{s.t.}\;\;\;&y_i(wx_i+{b})\ge 1-\xi_i,\;\;i=1,2,...,N\\ &\xi_i\ge 0,\;\;i=1,2,...,N\\ \end{aligned} \end{array}\end{gather}$
顯然待優化函數與不等式約束都是凸函數(仿射函數也是凸函數)。所以一樣符合KKT條件,能夠對偶化計算。拉格朗日函數爲:
$ \begin{aligned} \displaystyle L(w,b,\xi,\alpha,\mu) =& \frac{1}{2}||w||^2+C\sum\limits_{i=1}^{N}\xi_i-\sum\limits_{i=1}^{N}\alpha_i(y_i(wx_i+b)-1+\xi_i)-\sum\limits_{i=1}^{N}\mu_i\xi_i,\\ &\text{where}\;\;\alpha_i\ge 0,\mu_i\ge 0 \end{aligned} $
則原始問題變爲:
$ \min\limits_{w,b,\xi}\max \limits_{\alpha\ge 0 ,\mu \ge 0}L(w,b,\xi,\alpha,\mu) $
其對偶問題爲:
$\begin{gather} \max \limits_{\alpha\ge 0 ,\mu \ge 0}\min\limits_{w,b,\xi}L(w,b,\xi,\alpha,\mu) \end{gather}$
由KKT條件1式令梯度爲0,計算對偶問題內部$\min$函數,得:
\begin{align} &\nabla_wL(w,b,\xi,\alpha,\mu) = w-\sum\limits_{i=1}^{N}\alpha_iy_ix_i=0 \\ &\nabla_bL(w,b,\xi,\alpha,\mu) = -\sum\limits_{i=1}^{N}\alpha_iy_i=0 \notag\\ &\nabla_{\xi_i}L(w,b,\xi,\alpha,\mu) = C-\alpha_i-\mu_i=0 \notag \end{align}
代入$(9)$式,對偶問題變爲:
\begin{gather} \begin{array}{lcl} \min\limits_{\alpha}\displaystyle\frac{1}{2}\sum\limits_{i=1}^{N}\sum\limits_{j=1}^{N}\alpha_i\alpha_jy_iy_j(x_ix_j)-\sum\limits_{i=1}^{N}\alpha_i \\ \begin{aligned} \text{s.t.}\;&\sum\limits_{i=1}^{N}\alpha_iy_i=0\\ &0\le\alpha_i\le C,\;\;i = 1,2,...,N \end{aligned} \end{array} \end{gather}
其中$\alpha_i\le C$是因爲$C-\alpha_i=\mu_i\ge0 $。相似地,接下來的操做就是:
一、算出$(11)$式的最優$\alpha^*$。
二、$\alpha^*$代入$(10)$式計算$w^*$。
三、找出知足$\alpha_j^*$知足$0<\alpha_j^*<C$。
此時$\mu_j^* = C-\alpha_j^*>0$,由KKT條件2式,有$\mu_j^*\xi_j^*=0$,所以$\xi_j^*=0$。
一樣地,由KKT2式,有$\alpha_j^*(y_j(w^*x_j+b^*)-1+\xi_j^*)=0$,因$\alpha_j^*>0$,因而有:
$\displaystyle b^* = y_j-\sum\limits_{i=1}^{N}\alpha_i^*y_i(x_ix_j)$
在線性SVM中,由於有鬆弛變量$\xi$,不等式約束取等時樣本不必定在其類別的邊界上。上面只討論了使用小於$C$的$\alpha_j^*$,下面作個總結:
一、若$\alpha_i^* = 0$ ,則$\xi_i = 0$ ,分類正確,$x_i$在分離間隔邊界的外側;
二、若$0<\alpha_i^* < C$ ,則$\xi_i = 0$ ,分類正確,支持向量$x_i$剛好落在間隔邊界上;
三、若$\alpha_i^* = C,0<\xi_i<1$ ,則分類正確,$x_i$在間隔邊界與分離超平面之間;
四、若$\alpha_i^* = C,\xi_i=1$,則分類錯誤,$x_i$在分離超平面上;
五、若$\alpha_i^* = C,\xi_i>1$,則分類錯誤,$x_i$位於分離超平面誤分一側。
其中2~5都是支持向量。
線性SVM還有另外一種等價的優化目標函數:
$\begin{gather}\displaystyle \min\limits_{w,b}\sum\limits_{i=1}^{N}\left[1-y_i(wx_i+b)\right]_++\lambda||w||^2\end{gather}$
其中
$[z]_+= \left\{ \begin{aligned} &z,\;\;z>0 \\ &0,\;\;z\le0 \end{aligned} \right.$
感受能夠直接梯度降低。
令$(12)$中
$\left[1-y_i(wx_i+b)\right]_+=\xi_i$
則
一、有$\xi_i\ge 0$(一個不等式約束成立);
二、當$1-y_i(wx_i+b)>0$時,可得$y_i(wx_i+b)=1-\xi_i$;
三、當$1-y_i(wx_i+b)\le0$時,$\xi_i=0$,有$y_i(wx_i+b)\ge1-\xi_i$。
綜合二、3,不論$1-y_i(wx_i+b)$如何取值,總有$y_i(wx_i+b)\ge1-\xi_i$(另外一個不等式約束成立)。
因而$(12)$可寫成:
\begin{array}{lcl} \min\limits_{w,b,\xi}\displaystyle\sum\limits_{i=1}^{N}\xi_i+\lambda||w||^2\\ \begin{aligned} \text{s.t.}\;\;\;&y_i(wx_i+{b})\ge 1-\xi_i,\;\;i=1,2,...,N\\ &\xi_i\ge 0,\;\;i=1,2,...,N\\ \end{aligned} \end{array}
而後優化項常係數權重改一下就和$(8)$如出一轍了。
對於特徵分佈是非線性的樣本,須要將非線性可分特徵映射到另外一個空間(維度不變或變高均可),變成線性可分特徵。而後才能用線性SVM來優化參數。如圖下左圖到右圖:
理論上須要定義肯定的映射函數將輸入映射成線性可分的特徵,實際上這一中間環節能夠隱去。下面說明這一方法。
定義從輸入空間到特徵空間的映射$\phi(x):\mathcal{X}\to \mathcal{H}$,觀察線性可分SVM的對偶問題和最終的判別函數,裏面關於樣本特徵之間的運算都是內積。所以映射後的線性可分的樣本特徵要作的一樣是內積。定義這一內積爲:
$K(x,z)=<\phi(x),\phi(z)>$,後面內積直接用$\phi(x)\phi(z)$表示
樣本的維度比較小還好,好比上圖的二維,能夠直接想出一個映射,可是當維度很高時就很難想了。所以想到,能夠跳過定義映射,直接定義這個$K(x,z)$,稱之爲核函數。那麼什麼樣的核函數必定能夠表示成兩個映射後的向量的內積呢?這樣的核函數叫作正定核。
設$K:\mathcal{X}\times\mathcal{X}\to R$爲對稱函數,則$K(x ,z) $爲正定核函數的充要條件是:
對任意$x_i \in \mathcal{X}, i=1, 2,..., n, K(x, z) $對應的Gram 矩陣
$ \left[ \begin{matrix} K(x_1,x_1)&\cdots&K(x_1,x_n)\\ \vdots&&\vdots\\ K(x_n,x_1)&\cdots&K(x_n,x_n)\\ \end{matrix} \right]\succeq 0$
$\succeq 0$表示半正定。具體證實請看《統計學習方法》P136~139
線性核(即直接內積):
$K(x,z)=xz$
多項式核:
$K(x,z)=(xz+1)^p$
高斯核:
$\displaystyle K(x,z)=\exp(-\frac{||x-z||^2}{2\sigma^2})$
使用核函數後,待優化的對偶問題變爲:
$ \begin{array}{lcl} \min\limits_{\alpha}\displaystyle\frac{1}{2}\sum\limits_{i=1}^{N}\sum\limits_{j=1}^{N}\alpha_i\alpha_jy_iy_jK(x_i,x_j)-\sum\limits_{i=1}^{N}\alpha_i \\ \begin{aligned} \text{s.t.}\;&\sum\limits_{i=1}^{N}\alpha_iy_i=0\\ &0\le\alpha_i\le C,\;\;i = 1,2,...,N \end{aligned} \end{array} $
分類決策函數變爲:
$\displaystyle f(x) = \text{sign}\left(\sum\limits_{i=1}^{N}\alpha^*_iy_iK(x_i,x)+b^*\right)=\text{sign}\left(\sum\limits_{i\in S}\alpha^*_iy_iK(x_i,x)+b^*\right)$
即原來的直接內積$x_ix$變成了先映射再內積的$K(x_i,x)$。其中$S$爲支持向量集合($\alpha$不爲0的樣本集合,即2.2支持向量中的2~5)。
然而,選擇合適的正定核以使輸入映射成線性可分還須要做其它的努力。。。。。。。。。。
正如前面所說,在對偶問題中,$\alpha$須要分類討論的狀況數隨着樣本量的增大以指數級上升(即每一個$\alpha$是否爲0),SMO(sequential minimal optimization)算法能夠加快對偶問題的優化。它採用迭代的方式,每次將待優化問題分離出一個小問題求解,最終求解原問題。
初始化全部的$\alpha_i$爲常數(一般爲0),此時這些$\alpha_i$知足對偶問題的兩個不等式約束:
$\begin{gather}&\sum\limits_{i=1}^{N}\alpha_iy_i=0\\ &0\le\alpha_i\le C,\;\;i = 1,2,...,N\\ \label{}\end{gather}$
實際上就是知足KKT條件的1和4,由於$(13)$是條件1使梯度爲0得出的,$(14)$是條件1和4共同獲得的。可是,它們並不必定同時知足KKT條件的2和3(由於原問題沒有等式約束,因此沒有條件5):
$\begin{gather}\displaystyle\alpha_i(1-\xi_i-y_i(\sum\limits_{j=1}^N\alpha_jy_jK_{ji}+b))=0\label{}\end{gather}$
$\begin{gather}\displaystyle1-\xi_i-y_i(\sum\limits_{j=1}^N\alpha_jy_jK_{ji}+b)\le0\label{}\end{gather}$
也就是:
$\begin{gather}y_i(\sum\limits_{j=1}^N\alpha_jy_jK_{ji}+b)\left\{\begin{aligned}&\ge1,\;\;\alpha_i=0\\&=1,\;\;0<\alpha_i<C\\&\le1,\;\;\alpha_i=C\\\end{aligned}\right.\label{}\end{gather}$
若是條件2和3也都知足的話,就迭代結束,也就達到最終的解了。其中每次迭代都會保持$(13),(14)$兩個約束成立。
每次迭代,選出最「很差」的兩個$\alpha$來進行優化,固定剩下的$N-2$個$\alpha$(這樣的操做有點像小批量梯度降低)。如何纔算「很差」的$\alpha$放後面講,由於選擇$\alpha$基於優化的效率,爲了說明效率所在,因此先說優化。
不失通常性,假設選擇的兩個變量是$\alpha_1,\alpha_2$。則這個子問題能夠寫爲(最小化中將與$\alpha_1,\alpha_2$無關的項去了):
$\begin{array}{lcl} \begin{aligned} \min\limits_{\alpha_i,\alpha_2}W(\alpha_1,\alpha_2) = &\frac{1}{2}K_{11}\alpha_1^2+\frac{1}{2}K_{22}\alpha_2^2+y_1y_2K_{12}\alpha_1\alpha_2-\\ &(\alpha_1+\alpha_2)+y_1\alpha_1\sum\limits_{i=3}^Ny_i\alpha_iK_{i1}+y_2\alpha_2\sum\limits_{i=3}^Ny_i\alpha_iK_{i2} \\ \end{aligned}\\ \begin{aligned} \text{s.t.}\;\;&\alpha_1y_1+\alpha_2y_2 = -\sum\limits_{i=3}^Ny_i\alpha_i = \varsigma\\ &0\le\alpha_i\le C,\;\;\;i=1,2 \end{aligned} \end{array}$
由$(13)$式,$\alpha_1$又能夠被$\alpha_2$表達,因而這個子優化就變爲一個帶約束的一元二次函數最值問題,初中生的題目。主要操做就是先用導數求出二次函數的駐點,若是在約束內就爲最終解,在約束外就選約束中與之較近的端點爲解。儘管這麼簡單,可是爲了後面的選擇,仍是要推導一下。約束能夠在二維座標系中表示出來:
由於$y_1,y_2$絕對值爲1,因此只要關於它們的符號進行分類。分紅兩種狀況,$y_1\ne y_2$和$y_1=y_2$,因而可取的點分別如上圖a、b中斜線所示。設$\alpha_2$取值爲$[L,H]$,則當$y_1\ne y_2$時
$L=\max(0,\alpha_2-\alpha_1),H=\min(C,C+\alpha_2-\alpha_1)$
你可能會有爲何不用$\varsigma$而用$\alpha_2-\alpha_1$來算的疑問。這是由於每次迭代都保持$(13)$的成立,所以直接用$\alpha_2-\alpha_1$方便,而$\varsigma$須要算$N-2$個求和。又由於計算時利用了$(13),(14)$,因此這樣算出來的$\alpha_1,\alpha_2$依然能維持$(13),(14)$的成立。當$y_1=y_2$時
$L=\max(0,\alpha_2+\alpha_1-C),H=\min(C,\alpha_2+\alpha_1)$
而後就是簡單的先替換$\alpha_1$,再求導等於0,整理後獲得:
$(K_{11}+K_{22}-2K_{12})\alpha_2^*=(K_{11}+K_{22}-2K_{12})\alpha_2+y_2(E_1-E_2)$
其中
\begin{gather} \displaystyle E_i=\left(\sum\limits_{j=1}^N\alpha_iy_iK(x_j,x_i)+b\right)-y_i \label{} \end{gather}
$E_i$理解爲預測函數對$x_i$的預測值與其真實標籤$y_i$之差。再定義
$ \eta = K_{11}+K_{22}-2K_{12}$
$\eta$理解爲$x_1,x_2$映射到特徵空間中的向量之間的距離(距離二範的平方),因而
$\begin{gather}\displaystyle\alpha_2^*=\alpha_2+\frac{y_2(E_1-E_2)}{\eta}\label{}\end{gather}$
而後更新$\alpha_2,\alpha_1$:
$ \alpha_2^{update}= \left\{ \begin{aligned} &H,&\alpha_2^*>H\\ &\alpha_2^*,&L\le\alpha_2^*\le H\\ &L,&\alpha_2^*<L\\ \end{aligned} \right. $
$\alpha_1^{update} = (\varsigma - \alpha_2^{update}y_2)y_1 = \alpha_1+y_1y_2(\alpha_2-\alpha_2^{update})$
最後還有$(18)$的$b$的計算,《統計學習方法》對$b$的計算感受沒有說清楚。
在我理解,這個$b$的更新就是用更新後的$\alpha_1$或$\alpha_2$,看哪一個在$(0,C)$區間,就用KKT條件2式即$(15)$直接計算$b$;若是兩個$\alpha$都是0或$C$,則取依然用$(15)$計算兩個$b$,取這兩個$b$的平均值。
個人疑問是:首先,更新完$\alpha_1,\alpha_2$後,$\alpha_1,\alpha_2$是否保證知足$(15),(16)$式呢,也就是沒說明能不能用$(15)$來算$b$?其次,假設它們更新完後知足$(15),(16)$式,可是若是$\alpha_1,\alpha_2$都不在$(0,C)$區間爲何還能用$(15)$來算$b$呢?最後,書中只說了更新$b$,剛開始的$b$初始化爲多少呢?還請懂的大佬不吝賜教。
變量的選擇就是先遍歷全部的$\alpha_i$,查看哪一個$\alpha_i$違反$(17)$最嚴重,做爲待更新的$\alpha_1$;而後再選擇使$(19)$中的$|E_1-E_2|$最大的$\alpha_2$,以使$\alpha_2$變化最大。
接下來使用PCA(點擊連接)與SVM實現人臉識別。大體流程以下:
0、對人臉數據集預處理。
一、將全部訓練集人臉存在矩陣中,每行一張人臉照片。
二、使用PCA對矩陣行降維,提取特徵(用於降維、提取特徵的矩陣就是所謂「特徵臉」)。
三、選擇SVM的核函數爲高斯核,再選擇一組超參數(軟間隔權重C、高斯核的方差)來交叉驗證。
四、用降維後的人臉矩陣交叉驗證獲得最優超參數。
五、用降維人臉矩陣訓練使用最優超參數的SVM,獲得訓練完成的SVM。
六、把以相同方式存在矩陣中的測試集人臉,先用前面得到的特徵臉降維,再用訓練好的SVM測試,統計數據。
用於訓練與測試的人臉集以下圖:
數據預處理代碼:
import matplotlib.pyplot as plt import numpy as np import pylab import os img = plt.imread("face.jpg")#人臉圖片 fig = plt.figure() ax = fig.add_subplot(111) print(img) def split_img(img): a = np.zeros([400,56,46,3]) ##57*47 for i in range(20): for j in range(20): a[i*20+j] = img[i*57:(i+1)*57-1,j*47:(j+1)*47-1] return a def output_img(imgs): for i in range(len(imgs)): if not os.path.exists("faces/"+str(int(i/10))): os.mkdir("faces/"+str(int(i/10))) plt.imsave("faces/"+str(int(i/10))+"/"+str(i%10)+".jpg",imgs[i]) b = split_img(img) b = b/255 output_img(b) ax.imshow(b[0]) ax.axis("off") pylab.show()
數據獲取(與訓練測試代碼存在同目錄便可,不用執行):
import matplotlib.pylab as plt import numpy as np def get_train_data(): faces_train = np.zeros([40,6,56,46,3]) #56*46 train_name = np.zeros([40,6]).astype(int) faces_test = np.zeros([40,4,56,46,3]) #56*46 test_name = np.zeros([40,4]).astype(int) for i in range(40): for j in range(6): faces_train[i,j] = plt.imread("faces/"+str(i)+"/"+str(j)+".jpg") train_name[i,j] = i for i in range(40): j = 6 while j<10: faces_test[i,j-6] = plt.imread("faces/"+str(i)+"/"+str(j)+".jpg") test_name[i,j-6]=i j+=1 faces_train = faces_train[:,:,:,:,0].reshape([240,56,46])/255 faces_test = faces_test[:,:,:,:,0].reshape([160,56,46])/255 train_name = train_name.reshape([240]) test_name = test_name.reshape([160]) train_data = {"data":faces_train,"name":train_name} test_data = {"data":faces_test,"name":test_name} print("數據初始化成功!") return train_data,test_data
模型訓練與測試:
#%% 訓練模型獲取數據 from get_data import * import matplotlib.pylab as plt import numpy as np import pylab from sklearn.decomposition import PCA from sklearn.svm import SVC from sklearn.pipeline import make_pipeline import seaborn as sns plt.rcParams['font.sans-serif']=['SimHei'] #用來正常顯示中文標籤 plt.rcParams['axes.unicode_minus']=False #用來正常顯示負號 train_data,test_data = get_train_data() #獲取數據圖像56*46,訓練集240,測試集160 #%%訓練模型 #模型選擇,加入管道 pca = PCA(n_components = 50,whiten=True) svc = SVC(kernel='rbf',class_weight="balanced") model = make_pipeline(pca,svc) #如下交叉驗證選擇最優超參數 print("正在交叉驗證尋找最優超參數。。。") from sklearn.model_selection import GridSearchCV param_grid = {"svc__C":[50,60,70,80],"svc__gamma":[0.0001,0.0005,0.001,0.005]}#定義軟間隔權重、高斯核方差 grid = GridSearchCV(model,param_grid,cv = 6)#交叉驗證6折,由於每一個人的臉有6張,因此也是留一法 grid.fit(train_data["data"].reshape(240,56*46),train_data["name"])#用訓練集交叉驗證,選擇最優超參數 print("最優參數已找到:") print(grid.best_params_) print("用最優超參數訓練模型。。。") model = grid.best_estimator_ #用最優超參數訓練模型 model.fit(train_data["data"].reshape(240,56*46),train_data["name"]) #%%測試模型 print("訓練完畢,開始測試。。。") yfit = model.predict(test_data["data"].reshape([160,56*46])) print("測試完畢,數據統計:") from sklearn.metrics import classification_report print(classification_report(test_data["name"],yfit)) print("繪製預測結果圖。。。。") fig = plt.figure(figsize=(100,100)) for i in range(10): for j in range(16): ax = fig.add_subplot(10,16,i*16+j+1) ax.imshow(test_data["data"][i*16+j],cmap="bone") ax.set(xticks =[],yticks = []) ax.set_ylabel(yfit[i*16+j],size = 10) pylab.show() print("繪製混淆矩陣。。。。") from sklearn.metrics import confusion_matrix mat = confusion_matrix(test_data["name"],yfit) sns.heatmap(mat.T,square= True,annot=True,fmt="d",cbar=False) plt.xlabel("真實標籤") plt.ylabel("預測標籤") pylab.show()