ML - SVM(支持向量機)
背景:
1.1 最早是由 Vladimir N. Vapnik 和 Alexey Ya. Chervonenkis 在1963年提出
1.2 目前的版本(soft margin)是由Corinna Cortes 和 Vapnik在1993年提出凯力,并在1995年發(fā)表
1.3 深度學習(2012)出現(xiàn)之前拗秘,SVM被認為機器學習中近十幾年來最成功雕旨,表現(xiàn)最好的算法
機器學習的一般框架:
訓練集 => 提取特征向量 => 結(jié)合一定的算法(分類器:比如決策樹凡涩,KNN)=>得到結(jié)果
介紹:
3.1 例子:
兩類活箕?哪條線最好育韩?
SVM尋找區(qū)分兩類的超平面(hyper plane), 使邊際(margin)最大
總共可以有多少個可能的超平面陨舱?無數(shù)條
如何選取使邊際(margin)最大的超平面 (Max Margin Hyperplane)?
超平面到一側(cè)最近點的距離等于到另一側(cè)最近點的距離蛮粮,兩側(cè)的兩個超平面平行
線性可區(qū)分(linear separable) 和 線性不可區(qū)分 (linear inseparable)
定義與公式建立
超平面可以定義為
W: weight vectot
n 是特征值的個數(shù)
X: 訓練實例
b: bias
假設(shè)2維特征向量:X = (x1, X2)
把 b 想象為額外的 wight
超平面方程變?yōu)椋?div id="xfitlcu" class="image-package">
所有超平面右上方的點滿足:
所有超平面左下方的點滿足:
調(diào)整weight,使超平面定義邊際的兩邊:
綜合以上兩式妨蛹,得到: yi(w0 + w1x1 + w2x2) >=1蛙卤,任意i. (1)
所有坐落在邊際的兩邊的超平面上的點被稱作“支持向量(support vectors)”
分界的超平面到H1或H2上任意一點的距離為:
(i.e:其中
是向量的范數(shù)(norm))
所以,最大邊際距離為:
求解
SVM如何找出最大邊際的超平面呢(MMH)行嗤?
利用一些數(shù)學推倒,以上公式(1)可變?yōu)橛邢拗频耐箖?yōu)化問題(convex quadratic optimization)
利用Karush-Kuhn-Tucker(KKT)條件和拉格朗日公式既琴,可以推出MMH可以被表示為以下“決定邊界”(decision boundary)
其中甫恩,yi是支持向量點Xi(support vector)的類別標記(class lable)
是要測試的實例
和 b0 都是單一數(shù)值型參數(shù)磺箕,由以上提到的最優(yōu)算法得出
l 是支持向量點的個數(shù)
對于任何測試(要歸類的)實例简僧,帶入以上公式岛马,得出的符號是正還是負決定
例子:
說明:(2,3)減去(1,1)可以把weight表示為 (a,2a)
應(yīng)用
from sklearn import svm
X = [[2, 0], [1, 1], [2, 3]]
# 假設(shè)前兩個為一類,第三個點為另外一類
y = [0, 0, 1]
clf = svm.SVC(kernel='linear')
clf.fit(X, y)
print(clf)
# get support vectors
print(clf.support_vectors_)
# get indices of support vectors(找到支持向量在list x中的下標)
print(clf.support_)
# get number of support vectors for each class(在兩個分類中各找到了幾個支持向量)
print(clf.n_support_)
# 輸出結(jié)果:
# SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
# decision_function_shape='ovr', degree=3, gamma='auto', kernel='linear',
# max_iter=-1, probability=False, random_state=None, shrinking=True,
# tol=0.001, verbose=False)
# [[1. 1.]
# [2. 3.]]
# [1 2]
# [1 1]
import numpy as np
import pylab as pl
from sklearn import svm
# we create 40 separable points,多次運行程序隨機生成的點不變
np.random.seed(0)
# 隨機生成20個點的列表np.random.randn(20, 2)
X = np.r_[np.random.randn(20, 2) - [2, 2], np.random.randn(20, 2) + [2, 2]]
# 前20個點分為一類夏志,后20個點分為一類
Y = [0] * 20 + [1] * 20
# fit the model
clf = svm.SVC(kernel='linear')
clf.fit(X, Y)
# 得到分離超平面
w = clf.coef_[0]
a = -w[0] / w[1]
# 產(chǎn)生-5到5的連續(xù)點
xx = np.linspace(-5, 5)
yy = a * xx - (clf.intercept_[0]) / w[1]
# 繪制與通過的分離超平面的平行線
b = clf.support_vectors_[0]
yy_down = a * xx + (b[1] - a * b[0])
b = clf.support_vectors_[-1]
yy_up = a * xx + (b[1] - a * b[0])
print("w: ", w)
print("a: ", a)
# print " xx: ", xx
# print " yy: ", yy
print("support_vectors_: ", clf.support_vectors_)
print("clf.coef_: ", clf.coef_)
#在scikit - learn中沟蔑,coef_屬性保存線性模型的分離超平面的向量。
#在二進制分類示例中浦旱,n_features == 2宣蠕,因此w = coef_[0]是與超平面正交的向量
#在2D情況下繪制此超平面(2D平面的任何超平面都是1D線)抢蚀,
#我們想找到一個f皿曲,如y = f(x)= a.x + b屋休。 在這種情況下劫樟,a是線的斜率奶陈,可以通過a = -w[0] / w[1]來計算吃粒。
# 繪制線徐勃,點和平面的最近向量
pl.plot(xx, yy, 'k-')
pl.plot(xx, yy_down, 'k--')
pl.plot(xx, yy_up, 'k--')
pl.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1],
s=80, facecolors='none')
pl.scatter(X[:, 0], X[:, 1], c=Y, cmap=pl.cm.Paired)
pl.axis('tight')
pl.show()
運行結(jié)果:
w: [0.90230696 0.64821811]
a: -1.391980476255765
support_vectors_: [[-1.02126202 0.2408932 ]
[-0.46722079 -0.53064123]
[ 0.95144703 0.57998206]]
clf.coef_: [[0.90230696 0.64821811]]
訓練好的模型的算法復雜度是由支持向量的個數(shù)決定的,而不是由數(shù)據(jù)的維度決定的扎酷。所以SVM不太容易產(chǎn)生overfitting
SVM訓練出來的模型完全依賴于支持向量(Support Vectors), 即使訓練集里面所有非支持向量的點都被去除,重復訓練過程幅聘,結(jié)果仍然會得到完全一樣的模型荐糜。
一個SVM如果訓練得出的支持向量個數(shù)比較小暴氏,SVM訓練出的模型比較容易被泛化必怜。
2 .線性不可分的情況 (linearly inseparable case)
利用一個非線性的映射把原數(shù)據(jù)集中的向量點轉(zhuǎn)化到一個更高維度的空間中
在這個高維度的空間中找一個線性的超平面來根據(jù)線性可分的情況處理
視覺化演示
2.1 如何利用非線性映射把原始數(shù)據(jù)轉(zhuǎn)化到高維中?
3維輸入向量:
轉(zhuǎn)化到6維空間 Z 中去:
新的決策超平面:
其中W和Z是向量嗦明,這個超平面是線性的解出W和b之后,并且?guī)牖卦匠蹋?/p>
思考問題:
1: 如何選擇合理的非線性轉(zhuǎn)化把數(shù)據(jù)轉(zhuǎn)到高緯度中邻薯?
2: 如何解決計算內(nèi)積時算法復雜度非常高的問題厕诡?
-
核方法(kernel trick)
動機: 在線性SVM中轉(zhuǎn)化為最優(yōu)化問題時求解的公式計算都是以內(nèi)積(dot product)的形式出現(xiàn)的
,其中是把訓練集中的向量點轉(zhuǎn)化到高維的非線性映射函數(shù)寿羞,因為內(nèi)積的算法復雜度非常大绪穆,所以我們利用核函數(shù)來取代計算非線性映射函數(shù)的內(nèi)積
3.1 以下核函數(shù)和非線性映射函數(shù)的內(nèi)積等同
3.2 常用的核函數(shù)(kernel functions)
如何選擇使用哪個kernel第岖?根據(jù)先驗知識蔑滓,比如圖像分類键袱,通常使用RBF杠纵,文字不使用RBF,嘗試不同的kernel铝量,根據(jù)結(jié)果準確度而定慢叨。
3.3 核函數(shù)舉例:
假設(shè)定義兩個向量: x = (x1, x2, x3); y = (y1, y2, y3)
定義方程:f(x) = (x1x1, x1x2, x1x3, x2x1, x2x2, x2x3, x3x1, x3x2, x3x3)
K(x, y ) = (<x, y>)^2
假設(shè)x = (1, 2, 3); y = (4, 5, 6).
f(x) = (1, 2, 3, 2, 4, 6, 3, 6, 9)
f(y) = (16, 20, 24, 20, 25, 36, 24, 30, 36)
<f(x), f(y)> = 16 + 40 + 72 + 40 + 100+ 180 + 72 + 180 + 324 = 1024
K(x, y) = (4 + 10 + 18 ) ^2 = 32^2 = 1024
同樣的結(jié)果,使用kernel方法計算容易很多。
- SVM擴展可解決多個類別分類問題
對于每個類践瓷,有一個當前類和其他類的二類分類器(one-vs-rest)
利用SVM進行人臉識別實例:
from __future__ import print_function
# 從time模塊導入time晕翠,因為有些步驟需要計時
from time import time
# 打印出一些程序進展信息
import logging
# 繪圖的包淋肾,即最后將我們預測出來的人臉打印出來
import matplotlib.pyplot as plt
from sklearn.cross_validation import train_test_split
from sklearn.datasets import fetch_lfw_people
from sklearn.grid_search import GridSearchCV
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
from sklearn.decomposition import PCA
from sklearn import svm
# 打印輸出日志信息
logging.basicConfig(level=logging.INFO, format='%(asctime)s%(message)s')
# 下載數(shù)據(jù)集--戶外臉部數(shù)據(jù)集lfw(Labeled Faces in the Wild)
# minfaces_per_person:int,可選默認無樊卓,提取的數(shù)據(jù)集僅保留包含min_faces_per_person不同圖片的人的照片
# resize調(diào)整每張人臉圖片的比例碌尔,默認是0.5
lfw_people = fetch_lfw_people(min_faces_per_person=70, resize=0.4)
# 返回數(shù)據(jù)集有多少個實例,h是多少陪白,w是多少
n_samples, h, w = lfw_people.images.shape
# X矩陣用來裝特征向量咱士,得到數(shù)據(jù)集的所有實例
# 每一行是一個實例序厉,每一列是個特征值
X = lfw_people.data
# X矩陣調(diào)用shape返回矩陣的行數(shù)和列數(shù)弛房,
# X.shape[1]返回矩陣的列數(shù)文捶,對應(yīng)的特征向量的維度或者特征點多少
n_features = X.shape[1]
# 獲取特征結(jié)果集粹排,提取每個實例對應(yīng)的每個人臉
# y為classlabel目標分類標記顽耳,即不同人的身份
y = lfw_people.target
# 數(shù)據(jù)集中有多少個人膝迎,以人名組成列表返回
target_names = lfw_people.target_names
# shape[0]就是多少行限次,多少個人掂恕,多少類
n_classes = target_names.shape[0]
print("Total dataset size:") # 數(shù)據(jù)集中信息
print("n_samples:%d" % n_samples) # 數(shù)據(jù)個數(shù)1288
print("n_features:%d" % n_features) # 特征個數(shù)懊亡,維度1850
print("n_classes:%d" % n_classes) # 結(jié)果集類別個數(shù)店枣,即多少個人
# 結(jié)果
# Total dataset size:
# n_samples:1288
# n_features:1850
# n_classes:7
# 利用train_test_split拆分訓練集合測試集
# test_size=0.25表示隨機抽取25%的測試集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25)
# 采用PCA降維鸯两,原始數(shù)據(jù)的特征向量維度非常高钧唐,意味著訓練模型的復雜度非常高
# 保存的組件數(shù)目钝侠,也即保留下來的特征個數(shù)n
n_components = 150
print("Exreacting the top %d eigenfaces from %faces" % (n_components, X_train.shape[0]))
# 初始時間
t0 = time()
# 降維
pca = PCA(n_components=n_components, whiten=True).fit(X_train)
print("pca done in %0.3fs" % (time() - t0))
# 從人臉中提取特征點帅韧,對于人臉的一張照片提取的特征值名為eigenfaces
eigenfaces = pca.components_.reshape((n_components, h, w))
print("projecting the input data on the eigenfaces orthonormal basis")
t0 = time()
# 把訓練集特征向量轉(zhuǎn)化為更低維的矩陣
X_train_pca = pca.transform(X_train)
# 把測試集的特征向量轉(zhuǎn)化為更低維的矩陣
X_test_pca = pca.transform(X_test)
print("done in %0.3fs" % (time() - t0))
# 訓練一個支持向量機的分類model——構(gòu)造分類器
print("Fitting the classifier to the training set")
t0 = time()
# c是一個對錯誤德部分的懲罰
# gamma的參數(shù)對不同核函數(shù)有不同的表現(xiàn)忽舟,gamma表示使用多少比例的特征點
# 使用不同的c和不同值的gamma叮阅,進行多個量的嘗試帘饶,然后進行搜索及刻,選出準確率最高模型
param_grid = {
'C': [1e3, 5e3, 1e4, 5e4, 1e5],
'gamma': [0.0001, 0.0005, 0.001, 0.005, 0.01, 0.1]
}
# 調(diào)用SVM進行分類搜索哪對組合產(chǎn)生最好的歸類精確度
# ernel:rbf高斯徑向基核函數(shù) class_weight權(quán)重
# 把所有我們所列參數(shù)的組合都放在SVC里面進行計算缴饭,最后看出哪一組函數(shù)的表現(xiàn)度最好
clf = GridSearchCV(svm.SVC(kernel='rbf', class_weight='balanced'), param_grid=param_grid)
clf = clf.fit(X_train_pca, y_train)
print("fit done in %0.3fs" % (time() - t0))
print("Best estimator found by grid search:")
print(clf.best_estimator_)
##################進行評估準確率計算######################
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))
# 通過classification_report方法進行查看担猛,可以得到預測結(jié)果中哪些是正確
print(classification_report(y_test, y_pred, target_names=target_names))
# confusion_matrix是建一個n*n的方格傅联,橫行和縱行分別表示真實的每一組測試的標記和測試集標記的差別
# 對角線表示的是正確的值蒸走,對角線數(shù)字越多表示準確率越高
print(confusion_matrix(y_test, y_pred, labels=range(n_classes)))
# 將測試標記過進行展示比驻,即先弄一個通用的圖片可視化函數(shù):
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))
# 位置調(diào)整
plt.subplots_adjust(bottom=0, left=.01, right=.99, top=.90, hspace=.35)
for i in range(n_row * n_col):
# 設(shè)置畫布劃分以及圖像在畫布上輸出的位置
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)
# 獲取或設(shè)置x别惦、y軸的當前刻度位置和標簽
plt.xticks(())
plt.yticks(())
# 預測函數(shù)歸類標簽和實際歸類標簽打印
# 返回預測人臉姓和測試人臉姓的對比title
def title(y_pred, y_test, target_names, i):
# rsplit(' ',1)從右邊開始以右邊第一個空格為界掸掸,分成兩個字符
# 組成一個list
# 此處代表把'姓'和'名'分開猾漫,然后把后面的姓提出來
# 末尾加[-1]代表引用分割后的列表最后一個元素
pred_name = target_names[y_pred[i]].rsplit(' ', 1)[-1]
true_name = target_names[y_test[i]].rsplit(' ', 1)[-1]
return 'predicted:%s\ntrue: %s' % (pred_name, true_name)
# 預測出的人名
prediction_titles = [title(y_pred, y_test, target_names, i)
for i in range(y_pred.shape[0])]
# 測試集的特征向量矩陣和要預測的人名打印
plot_gallery(X_test, prediction_titles, h, w)
# 打印原圖和預測的信息
eigenface_titles = ["eigenface %d" % i for i in range(eigenfaces.shape[0])]
# 調(diào)用plot_gallery函數(shù)打印出實際是誰,預測的誰粒督,以及提取過特征的臉
# plot_gallery(eigenfaces, eigenface_titles, h, w)
plt.show()
# 結(jié)果
# Predicting people's names on the test set
# done in 0.053s
# precision recall f1-score support
# Ariel Sharon 0.89 0.47 0.62 17
# Colin Powell 0.77 0.93 0.84 60
# Donald Rumsfeld 0.94 0.64 0.76 25
# George W Bush 0.83 0.96 0.89 137
# Gerhard Schroeder 0.88 0.79 0.83 28
# Hugo Chavez 1.00 0.47 0.64 15
# Tony Blair 0.91 0.78 0.84 40
# avg / total 0.85 0.84 0.83 322
# [[ 8 5 0 4 0 0 0]
# [ 0 56 0 4 0 0 0]
# [ 0 2 16 7 0 0 0]
# [ 0 6 0 131 0 0 0]
# [ 1 1 0 2 22 0 2]
# [ 0 1 0 5 1 7 1]
# [ 0 2 1 4 2 0 31]]
結(jié)果:
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
序言:七十年代末,一起剝皮案震驚了整個濱河市礁哄,隨后出現(xiàn)的幾起案子溪北,更是在濱河造成了極大的恐慌,老刑警劉巖茉继,帶你破解...
序言:濱河連續(xù)發(fā)生了三起死亡事件烁竭,死亡現(xiàn)場離奇詭異派撕,居然都是意外死亡终吼,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
文/潘曉璐 我一進店門佩脊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來威彰,“玉大人歇盼,你說我怎么就攤上這事豹缀⌒象希” “怎么了氮惯?”我有些...
文/不壞的土叔 我叫張陵妇汗,是天一觀的道長杨箭。 經(jīng)常有香客問我储狭,道長,這世上最難降的妖魔是什么擒悬? 我笑而不...
正文 為了忘掉前任侈净,我火速辦了婚禮畜侦,結(jié)果婚禮上躯保,老公的妹妹穿的比我還像新娘途事。我一直安慰自己,他們只是感情好义图,可當我...
文/花漫 我一把揭開白布。 她就那樣靜靜地躺著奏夫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪廊谓。 梳的紋絲不亂的頭發(fā)上蹂析,一...
那天,我揣著相機與錄音竖共,去河邊找鬼公给。 笑死,一個胖子當著我的面吹牛淌铐,可吹牛的內(nèi)容都是我干的际起。 我是一名探鬼主播吐葱,決...
文/蒼蘭香墨 我猛地睜開眼灾前,長吁一口氣:“原來是場噩夢啊……” “哼哎甲!你這毒婦竟也來了炭玫?” 一聲冷哼從身側(cè)響起础嫡,我...
序言:老撾萬榮一對情侶失蹤榴鼎,失蹤者是張志新(化名)和其女友劉穎巫财,沒想到半個月后平项,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體闽瓢,經(jīng)...
正文 獨居荒郊野嶺守林人離奇死亡扣讼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
正文 我和宋清朗相戀三年椭符,在試婚紗的時候發(fā)現(xiàn)自己被綠了销钝。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
序言:一個原本活蹦亂跳的男人離奇死亡纵装,死狀恐怖诗箍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瓶籽,我是刑警寧澤,帶...
正文 年R本政府宣布,位于F島的核電站扬绪,受9級特大地震影響种蘸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜航瞭,卻給世界環(huán)境...
文/蒙蒙 一诫硕、第九天 我趴在偏房一處隱蔽的房頂上張望刊侯。 院中可真熱鬧,春花似錦纲菌、人聲如沸疮绷。這莊子的主人今日做“春日...
文/蒼蘭香墨 我抬頭看了看天上的太陽只冻。三九已至喜德,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間舍悯,已是汗流浹背朴艰。 一陣腳步聲響...
我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留金矛,地道東北人饼酿。 一個月前我還...
正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親碌廓。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
SVM SVM有很多種實現(xiàn),本文只關(guān)注其中最流行的一種實現(xiàn),即序列最小優(yōu)化(SMO)算法。 支持向量機是一種分類器...
【概述】 SVM訓練分類器的方法是尋找到超平面,使正負樣本在超平面的兩側(cè)(分類正確性即“分得開”),且樣本到超平面...
1. 背景: 最早是由 Vladimir N. Vapnik 和 Alexey Ya. Chervonenkis ...
支持向量機:是一種監(jiān)督式學習的方法,可廣泛地應(yīng)用于統(tǒng)計分類以及回歸分析酬诀。支持向量機屬于一般化線性分類器肴裙,這族分類器...
姓名:劉小瓊 公司:寧波大發(fā)化纖有限公司 期數(shù):第235期六項精進 日精進打卡第265天 [知~學習] 六項精進 ...