1 算法思想
支持向量機(support vector machines) 是找到一個超平面(hyperplane)將數據劃分爲一類與其他類的一種二類分類模型,分離間隔最大而區別於感知機。
適用於:
- 數據可直接分爲兩類(採用error-correcting output codes 方法區分多類);
- 高維不能線性可分的數據;
- 簡單分類。
支持向量機類別:
- 線性可分支持向量機(linear support vector machine in linearly separable case)——硬間隔最大化(hard margin maximization)
- 線性支持向量機(linear support vector machine)——軟間隔最大化(soft margin maximization)
- 非線性支持向量機(non-linear support vector machine)——核技巧(kernel trick)
2 算法步驟
2.1 線性可分支持向量機
由線性分類器可知:一個線性分類器的學習目標便是要在n維的數據空間中找到一個超平面(hyper plane),這個超平面的方程可以表示爲:
分離超平面:
分類決策函數:
函數間隔(functional margin):
對於樣本點 ,。
幾何間隔(geometric margin):
對於樣本點 ,
支持向量:
欲找到具有最大間隔的劃分超平面,也就是是 最大,即:
最大間隔分類器就是我們求取的分類超平面, 等於, 而函數間隔假設爲1,就可得到最大間隔超平面: , 而約束條件是因爲函數間隔是所有樣本點的間隔函數中最小值。
2.2 SVM的二次凸函數和約束條件
支持向量機的學習策略是間隔最大化,可形式化爲一個求解凸二次規劃(convex quadratic programming).
僅需最大化,這等價於最小化。於是,上式可重寫爲:
這是支持向量機的基本型,其本身爲一個凸二次規劃問題。
使用拉格朗日乘子法可得到其“對偶問題”(dual problem),其拉格朗日函數可寫爲:
其中是拉格朗日乘子。
利用對偶性的結論, 對關於和求偏導數:
將上式帶入式(2)中,可得式(1)的對偶問題:
實際任務中,求解式(4)會造成很大的開銷,**SMO(Sequential Minimal Optimization)**是一種求解的高效算法。
SMO 算法是支持向量機學習的一種快速算法,其特點是不斷地將原二次規劃問題分解爲只有兩個變量的二次規劃子問題,並對子問題進行解析求解,直到所有變量滿足 KKT 條件爲止。
SMO的基本思路類似動態規劃, 也是一種啓發式算法,它將原優化問題分解爲多個小優化問題來求解,並且對這些小優化問題進行順序求解得到的結果作爲作爲整體的結果。
解出 後,求出 與 即可得到模型
因式(1)中有不等式約束,上述過程需滿足KKT(Karush-Kuhn-Tucker)條件,即要求:
2.3 非線性類問題——核技巧(kernel trick)
先來看一個視頻,直觀感受一下:SVM with polynomial 可視化
對於原始樣本空間不是線性可分的情況,可將樣本從原始空間映射到一個更高維的特徵空間,使得樣本在這個特徵空間內線性可分。如果原始空間是有限維,即屬性數有限,那麼一定存在一個高維特徵空間使樣本可分。
令 表示將 映射後的特徵向量,於是,在特徵空間中劃分超平面所對應的模型可表示爲:
類似式(1),有:
其對偶問題是:
若遇到高維或無窮維問題,求解 會很困難,而利用核函數 ,可避免這個問題:
求解後即可得到:
常用核函數
名稱 | 表達式 | 參數 |
---|---|---|
線性核 | ||
多項式核 | 爲多項式的次數 | |
高斯核 | 爲高斯核的帶寬(width) | |
拉普拉斯核 | ||
Sigmoid 核 | 爲雙曲正切函數, |
3 算法實現
# SVM算法用於人臉識別步驟
# 1. 加載名人庫數據,並獲取數據參數
# 2. 將數據劃分爲訓練集與測試集
# 3. 以數據樣本做PCA降維
# 4. 建立SVM模型
# 5. 模型評估及可視化
from __future__ import print_function
from time import time # 用於每一步的計時
import logging # 打印程序進展信息
import matplotlib.pyplot as plt # 繪圖
from sklearn.model_selection import train_test_split # 訓練集測試集分開
from sklearn.datasets import fetch_lfw_people
from sklearn.decomposition import RandomizedPCA
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.svm import SVC
print(__doc__)
# Display progress logs on stdout 在標準輸出上顯示進度日誌
logging.basicConfig(level=logging.INFO, format=' %(asctime)s %(message)s')
##########################################################################
# Download the data, if not already on disk and load it as numpy arrays
# 如果磁盤上沒有的話下載數據,並將其以向量格式加載
lfw_people = fetch_lfw_people(min_faces_per_person=70, resize=0.4) # 下載名人數據集,lfw_people類似於字典結構
# introspect the images arrays to find the shapes (for plotting)
# 內省圖像數組以找到形狀(用於繪圖)
n_samples, h, w =lfw_people.images.shape # 返回樣本數
# for machine learning we use the 2 data directly (as relative pixel)
# positions info is ignored by this model
# 對於機器學習我們直接使用2個數據(作爲相對像素)
# 此模型會忽略位置信息
X = lfw_people.data # 提取特徵屬性,每一行是一個實例,每一列是一個特徵值
n_features = X.shape[1] # 獲取維度,返回列數
# the label to predict is the id of the person
y = lfw_people.target # 返回對應數據集的標記
target_names = lfw_people.target_names # 返回類別名字
n_classes = target_names.shape[0] # 獲得人臉識別數量
print("Total dataset size:")
print("n_samples: %d" % n_samples) # 打印實例個數
print("n_features: %d" % n_features) # 打印特徵向量個數
print("n_classes: %d" % n_classes) # 打印人臉識別數量(類)
#########################################################################
# Split into a training set and a test set using a stratified k fold
# split into a training and testing set 劃分訓練集與測試集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25)
###########################數據降維######################################
# Compute a PCA (eigenfaces) on the face dataset (treated as unlabeled
# datadet): unsupervised feature extrction / dimensionality reduction
n_components = 150 # 主成元素數量
print("Extrcting the top %d eigenfaces from %d faces"
% (n_components, X_train.shape[0]))
t0 = time()
pca = RandomizedPCA(n_components=n_components, whiten=True).fit(X_train) # 調用隨機PCA方法,用X_train矩陣進行建模
print("done in %0.3fs" % (time() - t0))
eigenfaces = pca.components_.reshape((n_components, h, w)) # 人臉識別中提取特徵值
print("Projecting the input data on the eigenfaces orthonoemal basis")
t0 = time()
X_train_pca = pca.transform(X_train) # 通過PCA將X_train轉化爲一個低維矩陣
X_test_pca = pca.transform(X_test) # 通過PCA將X_test 轉化爲一個低維矩陣
print("done in %0.3fs" % (time() - t0))
#########################################################################
# Train a SVM classification model 建立SVM模型
print("Fitting the classifier to the training set")
t0 = time()
param_grid = {'C':[1e3, 5e3, 1e4, 5e4, 1e5],
'gamma':[0.0001, 0.0005, 0.001, 0.005, 0.01, 0.1], } # C:penalty 懲罰項,gamma:針對核函數特徵點使用比例
clf = GridSearchCV(SVC(kernel='rbf', class_weight=None), param_grid) # 遍歷各種組合,rbf針對圖像
clf = clf.fit(X_train_pca, y_train)
print("done in %0.3fs" % (time() - t0))
print("Best estimator found by grid search:")
print(clf.best_estimator_) # 打印最優組合
###########################評估+可視化##########################################
# Quantitative evaluation of the model quality on the test set
print("Predicting people's names on the test set")
t0 = time()
y_pred = clf.predict(X_test_pca) # 預測新數據
print("done in %0.3fs" % (time() - t0))
print(classification_report(y_test, y_pred, target_names=target_names)) # 真實標籤與預測標籤作比較
print(confusion_matrix(y_test, y_pred, labels=range(n_classes))) # 建立矩陣,對角線爲預測正確
###############################################################################
# Qualitative evaluation of the predictions using matplotlib
def plot_gallery(images, titles, h, w, n_row=3, n_col=4): # 繪圖
"""Helper function to plot a gallery of portraits"""
plt.figure(figsize=(1.8 * n_col, 2.4 * n_row)) # 建立一個圖
plt.subplots_adjust(bottom=0, left=.01, right=.99, top=.90, hspace=.35)
for i in range(n_row * n_col):
plt.subplot(n_row, n_col, i + 1)
plt.imshow(images[i].reshape((h, w)), cmap=plt.cm.gray)
plt.title(titles[i], size=12)
plt.xticks(())
plt.yticks(())
# plot the result of the prediction on a portion of the test set
def title(y_pred, y_test, target_names, i): # 將預測與實際標籤打印出來
pred_name = target_names[y_pred[i]].rsplit(' ', 1)[-1]
true_name = target_names[y_test[i]].rsplit(' ', 1)[-1]
return 'predicted: %s\n true: %s' % (pred_name, true_name)
prediction_titles = [title(y_pred, y_test, target_names, i)
for i in range(y_pred.shape[0])]
plt.figure(1)
plot_gallery(X_test, prediction_titles, h, w)
# plot the gallery of the most significative eigenfaces 繪製提取出的特徵值的圖
plt.figure(2)
eigenface_titles = ["eigenface %d" % i for i in range(eigenfaces.shape[0])]
plot_gallery(eigenfaces, eigenface_titles, h, w)
plt.show()
輸出:
輸入圖像 | 輸出圖像 |
---|---|
precision recall f1-score support
Ariel Sharon 0.52 0.61 0.56 18
Colin Powell 0.75 0.84 0.80 58
Donald Rumsfeld 0.82 0.70 0.75 33
George W Bush 0.88 0.87 0.88 133
Gerhard Schroeder 0.76 0.73 0.75 26
Hugo Chavez 0.95 0.75 0.84 24
Tony Blair 0.78 0.83 0.81 30
avg / total 0.82 0.81 0.81 322
[[ 11 4 0 2 1 0 0]
[ 1 49 2 4 0 0 2]
[ 3 2 23 5 0 0 0]
[ 4 6 2 116 2 1 2]
[ 0 1 1 2 19 0 3]
[ 1 3 0 1 1 18 0]
[ 1 0 0 2 2 0 25]]
參考資料:
[1] 周志華. 機器學習 : = Machine learning[M]. 清華大學出版社, 2016.
[2] 李航. 統計學習方法[M]. 清華大學出版社, 2012.
[3] 麥子學院:深度學習基礎介紹-機器學習:http://www.maiziedu.com/course/373/
[4] 知乎:支持向量機(SVM)是什麼意思?