有一定难度,曾经看过一篇帖子,上面说理解SVM有三层境界,第一层是了解SVM,第二层是深入SVM,第三层是证明
SVM,要想达到第三层境界需要对泛函分析和最优化理论比较熟悉,就本人的专业背景来说,经过这几天的深入学习,应该说
自己已经达到了第二层境界。
本文主要参考李航所著的《统计学习方法》一书,下面开始进入正题:
求解上述优化模型有多种方法,最流行的是Platt提出的SMO算法,该算法有两层循环构成,外层循环遍历非边界样本或所有样本:优先遍历非边界样本,对其中违背KKT条件的样本进行调整,直至非边界样本全部满足KKT条件,若某次遍历发现没有非边界样本得到调整,就遍历所有样本,以检验是否有样本违背KKT条件,若有样本得到调整,则下次循环有必要再次遍历非边界样本。这样
外层循环在“遍历所有样本”和“遍历非边界样本”之间切换,直至所与样本都满足KKT条件。
内层循环针对违背KKT条件的样本寻找配对样本,优先选择使得|E2-E1|最大的样本作为配对样本,若上述过程失败则随机地选择非边界样本进行优化,若这样的样本找不到,则随机地选择任意样本进行优化,若仍然失败,则进入下一轮外层循环。
寻找配对样本以及参数更新的过程在《统计学习方法》一书中有详细描述,见下图
在更新参数之后需要及时更新超平面的参数b,更新公式如下:
以下SMO算法的伪代码摘自Platt的论文《Sequential Minimal Optimization - A Fast Algorithm for Training Support Vector Machines》,
基于上述伪代码,本文采用Python来编写代码,所有代码位于文件svm.py中,
- from __future__ import division
- import numpy as np
- class SvmClassifier:
- def __init__(self, X, y, C, tol):#初始化支持<span style="font-family:SimSun;">向量机</span>
- self.X = X
- self.y = y
- self.C = C
- self.tol = tol
- self.m = X.shape[0]
- self.alphas = np.zeros((self.m, 1))
- self.b = 0
- self.errors = np.zeros((self.m, 1))
- def getError(self, i):#<span style="font-family:SimSun;">计算误差</span>
- Ei = (self.alphas*self.y*(np.dot(self.X, self.X[i:i+1,:].T))).sum() + self.b - self.y[i,0]
- return Ei
- def selectAnotherAlpha(self, i):#选择配对的第二个样本
- maxDelta = 0
- for