机器学习4-支持向量机
师兄博客原文地址
@
主要内容对应周志华西瓜书第六章。
一些问题
- 1、试计算样本空间中的任意样本点 到超平面(\(\bm{w}, b\))的距离。
- 设样本空间中的某样本点为\(\bm{x}=(x_1, x_2,...,x_n),n\)为样本空间的维数。
超平面(\(\bm{w}, b\))其法向量为\(\bm{w}\),任取上面一点\(x_0\)有\(\bm{w}^T\bm{x}_0+b=0\)。
则\(\bm{x}\)到超平面的距离即为\(\bm{x}\)到\(x_0\)的距离于\(\bm{w}\)方向上的投影。
\(\bm{x}\)到\(x_0\)的距离为:
\[|\bm{x}-\bm{x}_0|
\]
到平面的距离为为:
\[\frac{|\bm{w}^T(\bm{x}-\bm{x}_0)|}{|\bm{w}|}
=\frac{|\bm{w}^T\bm{x}+b|}{|\bm{w}|}\]
- 2、试说明支持向量机对噪声敏感的原因。
- SVM的目的是求出与支持向量有最大化距离的直线,以每个样本为圆心,该距离为半径做圆,可以近似认为圆内的点与该样本属于相同分类。如果出现了噪声,那么这个噪声所带来的错误分类也将最大化,所以SVM对噪声是很敏感的。
- 3、试说明支持向量机引入软间隔的意义。
- 现实任务中往往很难保证所有样本在特征空间中线性可分,而且严格的分割,其结果也有可能是过分割造成的。
软间隔允许支持向量机在一些样本上出错以达到更好的分类效果。如下图
如果让全出的蓝色点“出错”,我们可以得到一个更宽的间隔,有更好的效果。
软间隔可以减小过拟合以及噪声的影响。 - 4、试写出“软间隔支持向量机”的对偶问题及其KKT条件。
- 软间隔支持向量机:
\[\min\limits_{\bm{w},b,\xi} \frac{1}{2}||\bm{w}||^2+C\sum_{i=1}^m\xi_i\\
\begin{aligned}
s.t. &\ \ y_i(\bm{w}^T\bm{x}_i+b)\ge1-\xi_i\\
&\ \ \xi_i\ge0,i=1,2,...,m
\end{aligned}
\]
则通过拉格朗日乘子法得到的拉格朗日函数如下:
\[\begin{aligned}
L(\bm{w},b,\bm{\alpha},\bm{\xi},\bm{\mu})= &\
\frac{1}{2}||\bm{w}||^2+C\sum_{i=1}^m\xi_i\\
&\ +\sum_{i=1}^m\alpha_i(1-\xi_i-y_i(\bm{w}^T\bm{x}_i+b))-\sum_{i=1}^m\mu_i\xi_i,\tag{1}
\end{aligned}\]
令\(L(\bm{w},b,\bm{\alpha},\bm{\xi},\bm{\mu})\)对\(\bm{w},b,\xi_i\)求偏导可得:
\[\begin{aligned}
\bm{w} &=\sum_{i=1}^m\alpha_iy_i \bm{x}_i\\
0&=\sum_{i=1}^m\alpha_iy_i\\
C&= \alpha_i+\mu_i\tag{2}
\end{aligned}\]
将(2)式代入(1)式,有原问题的对偶问题:
\[\begin{aligned}
\max\limits_{\bm{\alpha}} &\ \sum_{i=1}^m\alpha_i-\frac{1}{2}\sum_{i=1}^m\sum_{j=1}^m\alpha_i\alpha_jy_iy_j\bm{x}_i^T\bm{x}_j\\
s.t. &\ \sum_{i=1}^m\alpha_iy_i=0\\
& \ 0\le\alpha_i\le C,i=1,2,...,m.
\end{aligned}\]
对应的KKT条件要求:
\[\begin{cases}
\alpha_i\ge0,\ \ \mu_i\ge0,\\
y_if(\bm{x}_i)-1+\xi_i\ge0,\\
\alpha_i(y_if(\bm{x}_i)-1+\xi_i)=0,\\
\xi_i\ge0,\ \ \mu_i\xi_i=0
\end{cases}\]
- 5、试说明支持向量机引入核函数的意义。
- 不引入核函数的支持向量机只能在原本的空间线性划分样本,然而限时任务中在原始空间中很有可能不存在一个能正确划分两类样本的超平面,故可将样本从原始空间映射到一个更高维的空间去寻找一个合适的划分超平面。
通过核函数映射到三维空间便线性可分:
LSSVM的Python实现
最小二乘支持向量机使用均方误差作为软间隔支持向量机中的替代损失,并修改约束有式:
\[\begin{aligned}
\min\limits_{\bm{w},b,\xi} &\ \frac{1}{2}||\bm{w}||^2+\frac{1}{2}\gamma\sum_{i=1}^me^2_i\\
s.t. \ &\ y_i(\bm{w}^T\cdot \phi(\bm{x}_i)+b)\ge1-e_i,
i=1,2,...,m
\end{aligned}
\]
拉格朗日对偶为:
\[\begin{aligned}
L(\bm{w},b,\bm{\alpha},\bm{e})= &\
\frac{1}{2}||\bm{w}||^2+\frac{1}{2}
\gamma\sum_{i=1}^me^2_i\\
&\ +\sum_{i=1}^m\alpha_i(1-e_i-y_i(\bm{w}^T\cdot \phi(\bm{x}_i)+b))
\end{aligned}\]
令\(L(\bm{w},b,\bm{\alpha},\bm{e})\)对\(\bm{w},b,e_i\)求偏导可得:
\[\begin{aligned}
\bm{w} &=\sum_{i=1}^m\alpha_iy_i\phi(\bm{x}_i)\\
0&=\sum_{i=1}^m\alpha_iy_i\\
\alpha_i&= \gamma_ie_i\\
0&=1-e_i-y_i(\bm{w}^T\cdot \phi(\bm{x}_i)+b)\\
\end{aligned}\]
通过计算可直接求得\(\bm{\alpha}\)和\(b\):
\[b=(y^T(\Omega+\frac{I}{\gamma})^{-1}y)^{-1}\times y^T(\Omega+\frac{I}{\gamma})^{-1}\vec1\\
\bm{\alpha}=(\Omega+\frac{I}{\gamma})^{-1}\times(\vec1-yb)
\]
其中:
\[\begin{aligned}
\Omega_{ij}&=y_iy_j\phi(x_i)^T\phi(x_j)=y_iy_jK(x_i,x_j)\\
\vec1&=(1,1,...,1)^T
\end{aligned}\]
模型训练
def trainLSSVM(kMat, trainY, gamma):
omiga = multiply(trainY@trainY.T, kMat)
rows = omiga.shape[0]
vecOne = ones((rows, 1))
H = omiga + eye(rows)/gamma
b = trainY.T@(linalg.inv(H)@vecOne)/(trainY.T@(linalg.inv(H)@vecOne))
alpha = linalg.inv(H)@(vecOne - trainY@b)
return alpha, b
核函数
def kernelmat(sigma, trainX, testX):
trainRows = trainX.shape[0]
if testX is None:
trainX2 = sum(trainX**2, 0)@ones((1, trainRows))
kMat = trainX2 + trainX2.T - 2*(trainX*trainX.T)
else:
testRows = testX.shape[0]
trainX2 = sum(trainX**2, 0)@ones((1, testRows))
testX2 = sum(testX**2, 0)@ones((1, trainRows))
kMat = trainX2 + testX2.T - 2*(trainX*testX.T)
kMat = -kMat/(sigma**2*2)
kMat = exp(kMat)
return kMat
模型使用
def simLSSVM(trainX, trainY, testX, alpha, b, sigma):
kMat = kernelmat(sigma, trainX, testX)
testY = kMat.T@(multiply(alpha, trainY))
testY = sum(testY, 0) + b
testY = sign(testY)
return testY
关于\(\gamma\)和\(\sigma\)
LSSVM模型在\(\gamma\)和\(\sigma\)确定的情况下是可以通过计算求出解析解的。然而因为有替代损失和核函数的存在,通常LSSVM模型需要优化两个参数。
这里以交叉验证的错误率作为目标函数值,使用模拟退火法对其进行优化
交叉验证
def crossvalidateCost(trainX, trainY, kMat, gamma, sigma, L):
rows = trainY.shape[0]
blockSize = rows/L
costs = zeros((L, 1))
vecIndex = range(0, rows)
vecIndex = mat(vecIndex)
i = 1
for x in costs:
if i == 0:
validation = blockSize*(i-1) + 1 + vecIndex
else:
validation = blockSize * (i - 1) + 1 + mat(range(0, blockSize))
training = setdiff1d(vecIndex, validation)
subK = kMat[training, training]
subX = trainX[training, :]
subY = trainY[training, :]
testX = trainX[validation, :]
trueY = trainY[validation, :]
[alpha, b] = trainLSSVM(subK, subY, gamma)
testY = simLSSVM(subX, subY, testX, alpha, b, sigma)
x = 1 - (sum(testY == trueY)/len(testY))
return mean(costs)
整体框架
# 优化gamma和sigma
gammaOrg = 10
sigmaOrg = 0.45
[gamma, sigma] = SAA(trainX, trainY, gammaOrg, sigmaOrg)
# 训练模型
kMat = kernelmat(sigma, trainX, testX)
[alpha, b] = trainLSSVM(kMat, trainY, gamma)
# 分类
testY = simLSSVM(trainX, trainY, testX, alpha, b, sigma)
acc = sum(testY == trueY)/len(trueY)