基于SVM和SMO的线性分类器
实验介绍
一般来说,线性可分的训练数据的分界超平面往往并不唯一,但不同的超平面对于测试的识别效果却仍有差别。SVM是通过使超平面在每一个方向上与每一类各自最近的店距离相同从而达到最优线性分类效果。除此之外,SVM在求解超平面的过程中,还能够通过构造核函数使得非线性可分的数据变得线性可分。
在用SVM法构造出目标函数(其中m为样本数)
和限制条件
后,可以通过SMO法求解。
SMO法求解多变量目标函数的思想是,只将目标函数中的两个变量作为输入变量,而将其余的所有变量暂时看作参变量,再用梯度下降法或牛顿法或者解析法求解最优的两个输入变量,并根据此思路依次求解其他的两个变量,直到求解出所有的最优变量值,并得到收敛目标函数值。
详细原理可参考http://www.cnblogs.com/jerrylead/archive/2011/03/13/1982639.html
算法流程图
下图为SVM算法流程图,绿色为SVM参数训练流程,红色为具体样本分类流程。
SVM算法流程图
实验步骤
-
数据预处理,包括训练数据的整理、分类标签的提取、目标函数输入变量初始化等。实验数据为已修改的可先行可分的50个数据,其中40个作为训练数据,剩余十个作为测试数据。
-
SVM目标函数构造:首先构造输入变量向量,并代入到目标函数中,得到目标函数;
-
SMO法求解目标函数:首先,选定目标函数中的输入变量和和参数变量;然后给参数变量赋值得到关于输入变量的二元一次方程,代入限制条件求解输入变量,并更新中的;
-
在中选择不同的重复第3步,直到更新所有;
-
分析并判断中所有的值是否满足限制条件,假如不满足,设置为目标函数的变量,重复第3步,直到中所有的值都满足限制条件。
-
代入求解,;
-
输入测试数据,若则分类正确,否则分类错误,统计分类正确率。测试数据为包括50个训练数据的3000个数据样本。
实验结果分析及改进
-
一开始习惯性对数据进行归一化处理,分类识别正确率为0%。经分析可得,当数据归一化后,所有的数据会重新分布在单位圆上,从而导致分类错误。
-
SVM对于线性不可分的数据如果没有使用有效核函数分类效果较差,对3000个测试数据进行测试,最高只能达到81.83%;
非线性可分数的SVM分类效果图
由分类图各标签点的分布可知,该训练数据并不是线性可分的。实验结果分析,一方面,对于每一次循环,不同的初始化对于最后的分类效果并没有很大影响;另一方面,循环数目的增加并没有提升分类效果。(我感觉是训练样本的非线性可分性造成的影响。)
-
SVM算法对于线性可分的数据分类效果比较好,分类测试正确率为100%分类效果图如下:
线性可分数的SVM分类效果图
-
本MATLAB程序设计时,使用了多变量向量,构造了多输入变量目标函数,当多输入训练样本数特别大时,MATLAB无法对目标函数进行相关计算。
问题
在使用不带有效核函数的SVM法对非线性可分数据分类情况下,SMO法每次求解目标函数时的两个变量时发现,求解到的一般都偏向于0,使得存在少量较小的负值。而这些负的使得最后的求解结果并不满足KKT条件,从而导致实验结果的不理想。
参考文献
-
Andrew Ng, Lecture notes support vector machine
MATLAB程序
附MATLAB程序,包含两个m文件,主程序PRSVM.m,生产多变量向量的函数文件vecvariable.m,求解多变量优化函数的SMO算法。SVM线性可分实验数据可在http://pan.baidu.com/s/1ntIHhbF下载:
主程序
%2015.5.20 by anchor
%SVM solved by smo
clc;clear all;close all;
%============== PART 1: Data Preprocessing ============
dataset = load ('dataset.mat');
data = dataset.dataset;
dataset = data(:,1:40);
[data_l,data_n] = size(dataset);
for data_n_i=1:data_n
if dataset(3,data_n_i) == -1
plot(dataset(1,data_n_i),dataset(2,data_n_i),'*');
else
plot(dataset(1,data_n_i),dataset(2,data_n_i),'ro');
end
hold on;
end
title('SVM SMO');
ylabel = dataset(3,:)';
dataset = dataset(1:2,:);
%========= PART 2: Solve Dual Problem With SMO ========
alpha_p = my_smo(dataset,ylabel);
% caculate parameters,omega and b
omega_p = dataset*(alpha_p.*ylabel);
coord_n1 = find(ylabel == -1);
coord_p1 = find(ylabel == 1);
b_p = -1/2*(max(omega_p'*dataset(:,coord_n1))+min(omega_p'*dataset(:,coord_p1)));
%===================== PART 3: Testing ======================
TestLabel = data(3,41:50);
TestData = data(1:2,41:50);
[TestData_l,TestData_n] = size(TestData);
correct = 0;
for input_n = 1:TestData_n
y_out = (omega_p'*TestData(:,input_n)+b_p);
if TestLabel(input_n)*y_out>=0
correct =correct+1;
end
end
x=min(dataset(1,:)):0.5:max(dataset(1,:))
y=-omega_p(1)/omega_p(2)*x-b_p/omega_p(2);
plot(x,y)
fprintf('The correct rate of classification testing is %.2f %% \n',correct/TestData_n*100);
vecvariable.m
%2015.5.10 by anchor
%generate a vec_l dimensional variable vector
function vector=vecvariable(vector_l)
syms variable_name1;
vector=variable_name1;
for i=2:vector_l
syms (['variable_name',num2str(i)]);
vector=[vector;['variable_name',num2str(i)]];
end
end
my_smo.m
%function smo to solve multiple variables optimization problems
%2015.5.20 by anchor
function alpha_p=my_smo(dataset,ylabel)
data_n = length(ylabel);
XY_matrix = ylabel*ylabel'.*(dataset'*dataset);
alpha_p= 0.1*rand(data_n,1);
limit_c =0.5;
for iteration=1:2
for smo_n = 1:2:data_n
ylabel_temp =ylabel;
ylabel_temp(smo_n:smo_n+1) = [];
alpha_p_v = vecvariable(data_n); %define alpha variables vector
alpha_p_v_temp =alpha_p_v;
alpha_p_v_temp(smo_n:smo_n+1) = [];
alpha_p_temp = alpha_p;
alpha_p_temp(smo_n:smo_n+1) = [];
W_alpha = sum(alpha_p_v)-1/2*alpha_p_v'*XY_matrix*alpha_p_v;%objective function
l_alpha_p_temp =length(alpha_p_temp);
for i =1:l_alpha_p_temp
W_alpha = subs(W_alpha,alpha_p_v_temp(i),alpha_p_temp(i));
end
W_alpha = subs(W_alpha,-ylabel(smo_n)*(ylabel(smo_n+1)*alpha_p_v(smo_n+1)+alpha_p_temp'*ylabel_temp));
diff_W_alpha = diff(W_alpha,alpha_p_v(smo_n+1));
alpha_p(smo_n+1) = solve('diff_W_alpha=0');
if alpha_p(smo_n+1) < 0
alpha_p(smo_n+1) = 0;
elseif alpha_p(smo_n+1) >limit_c
alpha_p(smo_n+1) = limit_c;
end
alpha_p(smo_n) = -ylabel(smo_n)*(ylabel(smo_n+1)*alpha_p(smo_n+1)+alpha_p_temp'*ylabel_temp);
end
end