求助这个smo算法的
这个程序中的拉格朗日乘子是怎么付值的,我怎么感觉都是0那?还有请高手给我以个训练文本,这个程序绝提实现的功能是什么?#include "iostream.h"
#include "fstream.h"
#include "ctype.h"
#include "math.h"
#include "stdlib.h"
#include "time.h"
#define N 186//样本数总数
#define end_support_i 150
#define first_test_i 150
#define d 31//维数
//////////global variables
//int N=14104 //样本数
//int d=2 //维数
float C=100;//惩罚参数
float tolerance=0.001;//ui与边界0,C之间的公差范围
float eps=1e-3;//一个近似0的小数
float two_sigma_squared=10;//RBF核函数中的参数
float alph;//Lagrange multipiers
float b;//threshold
float error_cache;//存放non-bound样本误差
int target;//训练与测试样本的目标值
float precomputed_self_dot_product;//预存dot_product_func(i,i)的值,以减少计算量
int dense_points;//存放训练与测试样本,0-end_support_i-1训练;first_test_i-N测试
//函数的申明
int takeStep(int,int);
int examineNonBound(int);
int examineBound(int);
int examineFirstChoice(int,float);
int examineExample(int);
float kernel_func(int,int);
float learned_func(int);
float dot_product_func(int,int);
float error_rate();
void setX();
void setT();
void initialize();
///////////////////////////////////////////////////////
void main()
{
ofstream os("d:\\smo1.txt");//存放训练的后的参数
int numChanged=0,examineAll=1;
//srand((unsigned int)time(NULL));
initialize();
//以下两层循环,开始时检查所有样本,选择不符合KKT条件的两个乘子进行优化,选择成功,返回1,否则,返回0
//所以成功了,numChanged必然>0,从第二遍循环时,就不从整个样本中去寻找不符合KKT条件的两个乘子进行优化,
//而是从边界的乘子中去寻找,因为非边界样本需要调整的可能性更大,边界样本往往不被调整而始终停留在边界上。
//如果,没找到,再从整个样本中去找,直到整个样本中再也找不到需要改变的乘子为止,此时,算法结束。
while(numChanged>0||examineAll)
{
numChanged=0;
if(examineAll)
{
for(int k=0;k<end_support_i;k++)
numChanged+=examineExample(k);//examin all exmples
}
else{
for(int k=0;k<end_support_i;k++)
if(alph!=0&&alph!=C)
numChanged+=examineExample(k);//loop k over all non-bound lagrange multipliers
}
if(examineAll==1)
examineAll=0;
else if(numChanged==0)
examineAll=1;
}
//存放训练后的参数
{
os<<"d="<<d<<endl;
os<<"b="<<b<<endl;
os<<"two_sigma_squared="<<two_sigma_squared<<endl;
int n_support_vectors=0;
for(int i=0;i<end_support_i;i++)
if(alph>0)//此地方是否可以改为alph>tolerance?????????????????
n_support_vectors++;
os<<"n_support_vectors="<<n_support_vectors<<"rate="<<(float)n_support_vectors/first_test_i<<endl;
for(i=0;i<end_support_i;i++)
if(alph>0)
os<<"alph["<<i<<"]="<<alph<<" ";
os<<endl;
}
//输出,以及测试
cout<<error_rate()<<endl;
}
/////////examineExample程序
//假定第一个乘子ai(位置为i1),examineExample(i1)首先检查,如果它超出tolerance而违背KKT条件,那么它就成为第一个乘子;
//然后,寻找第二个乘子(位置为i2),通过调用takeStep(i1,i2)来优化这两个乘子。
int examineExample(int i1)
{
float y1,alph1,E1,r1;
y1=target;
alph1=alph;
if(alph1>0&&alph1<C)
E1=error_cache;
else
E1=learned_func(i1)-y1;//learned_func为计算输出函数
r1=y1*E1;
//////违反KKT条件的判断
if((r1>tolerance&&alph1>0)||(r1<-tolerance&&alph1<C))
{
/////////////使用三种方法选择第二个乘子
//1:在non-bound乘子中寻找maximum fabs(E1-E2)的样本
//2:如果上面没取得进展,那么从随机位置查找non-boundary 样本
//3:如果上面也失败,则从随机位置查找整个样本,改为bound样本
if (examineFirstChoice(i1,E1))//1
{
return 1;
}
if (examineNonBound(i1))//2
{
return 1;
}
if (examineBound(i1))//3
{
return 1;
}
}
///没有进展
return 0;
}
////////////1:在non-bound乘子中寻找maximum fabs(E1-E2)的样本
int examineFirstChoice(int i1,float E1)
{
int k,i2;
float tmax;
for(i2=-1,tmax=0.0,k=0;k<end_support_i;k++)//*******************************end_support_i
if(alph>0&&alph<C)
{
float E2,temp;
E2=error_cache;
temp=fabs(E1-E2);
if(temp>tmax)
{
tmax=temp;
i2=k;
}
}
if(i2>=0)
{
if(takeStep(i1,i2))
return 1;
}
return 0;
}
/////////////// 2:如果上面没取得进展,那么从随机位置查找non-boundary 样本
int examineNonBound(int i1)
{
int k,k0 = rand()%end_support_i;
int i2;
for (k = 0; k < end_support_i; k++)
{
i2 = (k + k0) % end_support_i;//从随机位开始
if (alph > 0.0 && alph < C)
{
if (takeStep(i1, i2))
{
return 1;
}
}
}
return 0;
}
////////////3:如果上面也失败,则从随机位置查找整个样本,(改为bound样本)
int examineBound(int i1)
{
int k,k0 = rand()%end_support_i;
int i2;
for (k = 0; k < end_support_i; k++)
{
i2 = (k + k0) % end_support_i;//从随机位开始
//if (alph= 0.0 || alph=C)//修改******************
{
if (takeStep(i1, i2))
{
return 1;
}
}
}
return 0;
}
///////////takeStep()
//用于优化两个乘子,成功,返回1,否则,返回0
int takeStep(int i1,int i2)
{
int y1,y2,s;
float alph1,alph2;//两个乘子的旧值
float a1,a2;//两个乘子的新值
float E1,E2,L,H,k11,k22,k12,eta,Lobj,Hobj,delta_b;
if(i1==i2) return 0;//不会优化两个同一样本
//给变量赋值
alph1=alph;
alph2=alph;
y1=target;
y2=target;
if(alph1>0&&alph1<C)
E1=error_cache;
else
E1=learned_func(i1)-y1;//learned_func(int)为非线性的评价函数,即输出函数
if(alph2>0&&alph2<C)
E2=error_cache;
else
E2=learned_func(i2)-y2;
s=y1*y2;
//计算乘子的上下限
if(y1==y2)
{
float gamma=alph1+alph2;
if(gamma>C)
{
L=gamma-C;
H=C;
}
else
{
L=0;
H=gamma;
}
}
else
{
float gamma=alph1-alph2;
if(gamma>0)
{
L=0;
H=C-gamma;
}
else
{
L=-gamma;
H=C;
}
}//计算乘子的上下限
if(L==H) return 0;
//计算eta
k11=kernel_func(i1,i1);//kernel_func(int,int)为核函数
k22=kernel_func(i2,i2);
k12=kernel_func(i1,i2);
eta=2*k12-k11-k22;
if(eta<0)
{
a2=alph2+y2*(E2-E1)/eta;//计算新的alph2
//调整a2,使其处于可行域
if(a2<L) a2=L;
if(a2>H) a2=H;
}
else//此时,得分别从端点H,L求目标函数值Lobj,Hobj,然后设a2为求得最大目标函数值的端点值
{
float c1=eta/2;
float c2=y2*(E2-E1)-eta*alph2;
Lobj=c1*L*L+c2*L;
Hobj=c1*H*H+c2*H;
if(Lobj>Hobj+eps)//eps****************
a2=L;
else if(Lobj<Hobj-eps)
a2=H;
else
a2=alph2;//加eps的目的在于,使得Lobj与Hobj尽量分开,如果,很接近,就认为没有改进(make progress)
}
if(fabs(a2-alph2)<eps*(a2+alph2+eps))
return 0;
a1=alph1-s*(a2-alph2);//计算新的a1
if(a1<0)//调整a1,使其符合条件*****??????????????????????????????????????????
{
a2+=s*a1;
a1=0;
}
else if(a1>C)
{
float t=a1-C;
a2+=s*t;
a1=C;
}
//更新阀值b
{
float b1,b2,bnew;
if(a1>0&&a1<C)
bnew=b+E1+y1*(a1-alph1)*k11+y2*(a2-alph2)*k12;
else{
if(a2>0&&a2<C)
bnew=b+E2+y1*(a1-alph1)*k12+y2*(a2-alph2)*k22;
else{
b1=b+E1+y1*(a1-alph1)*k11+y2*(a2-alph2)*k12;
b2=b+E2+y1*(a1-alph1)*k12+y2*(a2-alph2)*k22;
bnew=(b1+b2)/2;
}
}
delta_b=bnew-b;
b=bnew;
}
//对于线性情况,要更新权向量,这里不用了
//更新error_cache,对取得进展的a1,a2,所对应的i1,i2的error_cache=error_cache=0
{
float t1=y1*(a1-alph1);
float t2=y2*(a2-alph2);
for(int i=0;i<end_support_i;i++)
if(0<alph&&alph<C)
error_cache+=t1*kernel_func(i1,i)+t2*(kernel_func(i2,i))-delta_b;
error_cache=0.0;
error_cache=0.0;
}
alph=a1;//store a1,a2 in the alpha array
alph=a2;
return 1;//说明已经取得进展
}
//////////learned_func(int)
//评价分类学习函数
float learned_func(int k)
{
float s=0.0;
for(int i=0;i<end_support_i;i++)
if(alph>0)
s+=alph*target*kernel_func(i,k);
s-=b;
return s;
}
//计算点积函数dot_product_func(int,int)
float dot_product_func(int i1,int i2)
{
float dot=0;
for(int i=0;i<d;i++)
dot+=dense_points*dense_points;
return dot;
}
//径向机核函数RBF:kernel_func(int,int)
float kernel_func(int i1,int i2)
{
float s=dot_product_func(i1,i2);
s*=-2;
s+=precomputed_self_dot_product+precomputed_self_dot_product;
return exp(-s/two_sigma_squared);
}
//初始化initialize()
void initialize()
{
//初始化阀值b为0
b=0.0;
//初始化alph[]为0
for(int i=0;i<end_support_i;i++)
alph=0.0;
//设置样本值矩阵
setX();
//设置目标值向量
setT();
//设置预计算点积
{for(int i=0;i<N;i++)
precomputed_self_dot_product=dot_product_func(i,i);//注意,这是对训练样本的设置,对于测试样本也应考虑?????????????????
}
}
//计算误差率error_rate()
float error_rate()
{ ofstream to("d:\\smo_test.txt");
int tp=0,tn=0,fp=0,fn=0;
float ming=0,te=0,total_q=0,temp=0;
for(int i=first_test_i;i<N;i++)
{ temp=learned_func(i);
if(temp>0&&target>0)
tp++;
else if(temp>0&&target<0)
fp++;
else if(temp<0&&target>0)
fn++;
else if(temp<0&&target<0)
tn++;
to<<i<<"实际输出"<<temp<<endl;
}
total_q=(float)(tp+tn)/(float)(tp+tn+fp+fn);//总精度
ming=(float)tp/(float)(tp+fn);
te=(float)tp/(float)(tp+fp);
to<<"---------------测试结果-----------------"<<endl;
to<<"tp="<<tp<<" tn="<<tn<<"fp="<<fp<<"fn="<<fn<<endl;
to<<"ming="<<ming<<"te="<<te<<"total_q="<<total_q<<endl;
return (1-total_q);
}
//计算样本X[]
void setX(){
ifstream ff("D:\\17_smo.txt");////////////////////////
if(!ff)
{
cerr<<"error!!"<<endl;
exit(1);
}
int i=0,j=0;
char ch;
while(ff.get(ch))
{
if(isspace(ch)) continue;
if(isdigit(ch))
{
dense_points=(int)ch-48;
j++;
if(j==d)
{
j=0;
i++;
}
}
}
}
//set targetT[]
void setT()
{
for(int i=0;i<75;i++)
target=1;
for(i=75;i<150;i++)
target=-1;
for(i=150;i<168;i++)
target=1;
for(i=168;i<186;i++)
target=-1;
} 我也在烦这个程序呢,楼主研究出来的话,告诉声
页:
[1]