本篇文章4741字,读完约12分钟
雷锋。(公开号码:雷锋。com)出版社:谢辉,本文作者。原文包含在作者的个人博客中。雷锋。com已被授权。
支持向量机(Svm)是一种有监督的学习模型,有两个核心:第一,核技巧;其次,序列最小优化算法smo(sequential minimum optimization)是约翰普拉特1996年发布的一种训练支持向量机的有效算法。本文不打算细化支持向量机支持向量机的详细下推算法,而只涉及上述两点来做一个说明。最后给出了算法实现和实验对比图。
核函数核函数在处理复杂数据方面有着显著的效果。其方法是利用核函数将某一维度的线性不可分数据从特征空隐式映射到高维空,以便在high-dimensional /きだよ使用
多项式核:
高斯核(径向基函数):
线性内核:
是两个矩阵空.之间的内积
smo算法流程的两个主要步骤是:
1.选择一对α进行更新,并采用启发式方法使目标函数最大限度地逼近其全局最优值;
2.将目标函数优化为α,以保持所有其他α不变。
以上是两个基本步骤,实现被推到公式如下:
需要接受的限制是:
同时,更新α以满足以下条件,这可以保证约束为0
可以消除α
其间
u的表达式是:
y是第一个特征因子的真实标签值
然后考虑约束0的线性表示
根据y的相同符号或不同符号,可以得出上下边界为
对于α,有
对于α,j首先可以由e得到,然后计算方法可以如下:
b的更新是
其间
并且每次更新总和时需要重新计算相应的总和
使用上述公式,代码实现相对简单。
算法实现完整的platt-smo算法实现条目:
公共svmresult plattsmo(最终svmresult svmresult) {
double b = SVM result . getb();
double[]alpha = SVM result . getalphas();
for(int I = 0;idouble ei = this.calcek(i,alphas,b);
如果(((标签数组[i] * ei &(α[I]|((标签数组[I]* ei >容许因子)&(α[I]> 0)){
double[]jsselected = this . selectj(I,ei,alphas,b);//J选择的启发式实现
int j =(int)jsselected[0];
double EJ = js selected[1];
双字母数字=字母[I];
双αjold =α[j];
双l = 0;
双h = 0;
//边界计算
if(label array[I]!= label array[j]){
l = math.max(0,α[j]-α[I]);
h =数学. min(惩罚因子,惩罚因子+α[j]
-阿尔法[I]);
}其他{
l = math.max(0,α[j]+α[I]-惩罚因子);
h = math.min(惩罚因子,α[j]+α[I]);
{}
if (l == h) {
logger . info(" l = = h ");
}其他{
双η=(2.0 * this . kernelarray[I][j]-this . kernelarray[I][I]-this . kernelarray[j][j]);
if (eta >= 0) {
logger . info(" eta > = 0 ");
}其他{
//双向调整α[j]减小
alpha s[j]-= label array[j]*(ei-EJ)/eta。
if(α[j]> h){
α[j]= h。
{}
if(l > alpha[j]){
α[j]= l。
{}
//更新ej
this.updateek(j,alphas,b);
if(math . ABS(alphas[j]-alphajold)logger . info(“j移动不够”);
}其他{
//双向调整α[I]减量
alphas[I]+= label array[j]* label array[I]
*(αjold-α[j]);
//更新ei
this.updateek(i,alphas,b);
//计算b
double B1 = b-ei-label array[I]*(alpha[I]-alpha iold)* this . kernel array[I][I]-label array[j]*(alpha[j]-alpha jold)* this . kernel array[I][j];
double B2 = b-EJ-label array[I]*(alpha s[I]-alpha iold)* this . kernel array[I][j]-label array[j]*(alpha s[j]-alpha jold)* this . kernel array[j][j];
if ((0个字母[I]){
b = b1
}否则如果((0字母[j]){
b = b2
}其他{
b =(B1+B2)/2.0;
{}
{}
{}
{}
{}
{}
返回新的svmresult(b,alphas
{}
在上述算法中,关键点是j、
j的选择:
private double[] selectj(int i,double ei,double[]alpha,double b){
int maxk =-1;
double max deltae = 0;
双EJ = 0;
int j =-1;
double[] eiarray=新的double[2];
eiarray[0]= 1d;
eiarray[1]= ei;
this . ecache[I]= eiarray;
boolean hasvalidecachelist = false
for(int k = 0;k 0){
if(k == i){
继续;
{}
hasvalidecachelist = true
if(k == this.m){
k = m-1;
{}
double ek = this.calcek(k,α,b);
双δe = math . ABS(ei-ek);
if (deltae > maxdeltae){
maxk = k;
maxdeltae = deltae
ej = ek
{}
{}
{}
j = maxk。
如果(!hasvalidachelist | | j = =-1){
j = this . selectj random(I);
ej = this.calcek(j,α,b);
{}
if(j == this.m){
j = m-1;
{}
返回新的double[]{j,EJ };
{}
第一种选择是用启发式方法选择J,并通过计算δ的最大值来逼近J的选择。如果你不能随机选择一个J值,在J的选择中有一个ek的计算方法
私有double calcek(int k,double[]alpha,double b){
矩阵α矩阵=新矩阵(α);
矩阵标签矩阵=新矩阵(标签数组);
矩阵kmatrix =新矩阵(this . kernel array[k]);
double fxk = alphasmatrix . multiply(标签矩阵)。点乘(kmatrix .转置())。dot value()+b;
double ek = fxk-(float)this . label array[k];
返回ek;
{}
让我们介绍一下核函数的计算方法。本文主要采用径向基函数,具体如下:
public double[]kernel trans(double[][]features array,double[]]features array){
int MC count = feature sarray . length;
double[] kerneltransi =新的double[m count];
矩阵特征矩阵=新矩阵(特征射线);
矩阵特征矩阵=新矩阵(特征数组);
if(traintfactormap . get(" kt ")。等于(Lin){
矩阵结果=特征矩阵.点乘(特征矩阵.转置());
kerneltransi = result .转置()。值()[0];
} else if(traintfactormap . get(“kt”)。等于(RBF){
double rbfdelta =(double)train factory map . get(“rbfdelta”);
for(int j = 0;jmatrix xj =新矩阵(features sarray[j]);
矩阵δ= XJ . reduce(特征矩阵);
双delta value = delta . dot multiply(delta .转置())。点值();
kernel transi[j]= math . exp((-1.0 * delta value)/(2 * math . pow(RBF delta,2));
{}
{}
返回kerneltransi
{}
最后,看看测试代码实现:
double[][]datavs =新double[m][d[0]。长度];
double[] labelsvs =新的double[m];
double[] alphassvs =新的double[m];
int n = 0;
for(int I = 0;iif(阿尔法[我]!= 0){
datavs[n]= d[I];
label SV[n]= l[I];
αssvs[n]=αs[I];
n++;
{}
{}
//模型测试
int error count = 0;
for(int I = 0;I double[]kernel transi = leaner . kernel trans(datavs,d[I]);
矩阵kerneltransim =新矩阵(kernel transi);
矩阵标签vsm =新矩阵(标签vs);
矩阵αssvsm =新矩阵(αssvs);
double expert = kernel transim . dot multiply(labelsvsm . multiply(alpha ssvsm))。转置())。dot value()+b;
system . out . println(I+" \ t "+predict+" \ t "+l[I]);
if(adaboost.sigmoid(predict)!= l[i]){
error count++;
{}
{}
测试代码首先找出所有支持向量,提取支持向量下的特征向量和标签向量,使用核函数进行隐式映射,最后计算预测值。
培训结果
本文采用了100个二维平面不能线性分离的数据集,如下所示:
在径向基函数映射之后,通过支持向量预测计算的可分离平面如下
该算法对100个数据的训练准确率可达98%。
注:本文中的算法都来自彼得·哈灵顿的机器学习实践
——————————————————————
人工智能神经网络专业培训班
20年来,清华大学神经网络讲师将带你系统地学习人工智能的神经网络!
一站式深入了解深度学习的发展现状、基本原则和主要方法。
课程链接:mooc.ai/course/65
雷锋。(公开号码:雷锋。相关阅读:
从理论到实践,本文详细阐述了人工智能推荐系统的三种算法
监督学习最常见的五种算法是什么?
雷锋文章版权所有。严禁擅自转载。详情请参考转载说明。
来源:搜狐微门户
标题:基于Spark如何实现SVM算法?这里有一份详尽的开发教程(含代码)
地址:http://www.shwmhw.com/shxw/61054.html