Input : 特征向量
Output : 类别(+1/-1) 【二分类】
直接学习f 或者P(Y|X) ——> 判别模型
f ( x ) = s i g n ( w T x + b ) f(x)=sign(w^Tx+b) f(x)=sign(wTx+b) s i g n ( ) 符 号 函 数 , 运 算 是 直 接 学 习 参 数 w , b — — > 判 别 模 型 sign()符号函数,运算是直接学习参数 w,b ——>判别模型 sign()符号函数,运算是直接学习参数w,b——>判别模型
函数 f 是线性的---->线性分类模型
L ( w , b ) = − ∑ x i ϵ M ( y i ( w T x i + b ) ) L(w,b) = -\sum_{x_i\epsilon M}(y_i(w^Tx_i+b)) L(w,b)=−xiϵM∑(yi(wTxi+b))
M是误分类样本点的集合,其中 y i ϵ { + 1 , − 1 } y_i\epsilon \{+1,-1\} yiϵ{+1,−1}所以加上符号以后L(w,b)非负。
min w , b L ( w , b ) = − ∑ x i ϵ M ( y i ( w T x i + b ) ) \min_{w,b} L(w,b) = - \sum_{x_i\epsilon M}(y_i(w^Tx_i+b)) w,bminL(w,b)=−xiϵM∑(yi(wTxi+b)) ▽ w L ( w , b ) = − ∑ x i ϵ M y i x i ( w 的 负 梯 度 方 向 ) \bigtriangledown_wL(w,b) = -\sum_{x_i\epsilon M}y_ix_i(w的负梯度方向) ▽wL(w,b)=−xiϵM∑yixi(w的负梯度方向) ▽ b L ( w , b ) = − ∑ x i ϵ M y i ( b 的 负 梯 度 方 向 ) \bigtriangledown_bL(w,b) = -\sum_{x_i\epsilon M}y_i(b的负梯度方向) ▽bL(w,b)=−xiϵM∑yi(b的负梯度方向)
随机选择一个样本点(xi,yi) w ← w + η y i x i [ 更 新 起 来 比 较 麻 烦 ] w\leftarrow w+\eta y_ix_i [更新起来比较麻烦] w←w+ηyixi[更新起来比较麻烦] b ← b + η y i ( η 表 示 学 习 率 ) b \leftarrow b+ \eta y_i (\eta 表示学习率) b←b+ηyi(η表示学习率)
#include
#include
#include
#include
#include
using namespace std;
const int Max_data = 10;
struct data{
//std::vector data(2);
vector<double> samples;
//double x1;
int labels;
}dataSet[Max_data];
struct result{
vector<double> w;
double b;
}result;
class perception_ori
{
public:
/*导入数据并按照数据结构填充,返回样本个数*/
int loadDataSet()
{
fstream f ;
int countNum = 0;
f.open("data.dat");
int i = 0; double temp1,temp2;
while(!f.eof())
{
f>>temp1>>temp2>>dataSet[i].labels;
dataSet[i].samples.push_back(temp1);
dataSet[i].samples.push_back(temp2);
i++;
countNum++;
}
f.close();
return countNum;
}
double eta = 0;//设置学习率
void perception(data dataSet[],double eta,int N)
{
//vector w(2);
result.w.push_back(0.0);
result.w.push_back(0.0);
result.b = 0.0;
bool flag = false;
int cnt;
while(!flag)
{
cnt = 0;
for(int i =0; i<N;i++)
{
if((double)dataSet[i].labels*(dataSet[i].samples[0]*result.w[0]+dataSet[i].samples[1]*result.w[1]+result.b)<=0.0)
{
cnt++;
result.w[0] = result.w[0]+eta*(double)dataSet[i].labels*dataSet[i].samples[0];
result.w[1] = result.w[1]+eta*(double)dataSet[i].labels*dataSet[i].samples[1];
result.b = result.b+eta*(double)dataSet[i].labels;
}
}
if(cnt == 0 )
flag = true;
}
//cout<
}
};
int main()
{
perception_ori test;
int N = test.loadDataSet();
test.eta = 1.0;
test.perception(dataSet,test.eta,N);
cout<<"The weight is :" <<endl<<result.w[0]<<endl<<result.w[1]<<endl<<"And the biase is "<<endl<<result.b<<endl;
return 0;
}
基本思想:w,b表示为xi,yi的线性组合的形式,求其系数(线性组合的系数)
这样关于xi,yi的内积可以提前计算,方便update,其余与原始形式的实质是一样的,之前看有人说两者的区别是梯度下降和随机梯度下降,我认为不是,区分梯度和随机梯度的关键在于,迭代次数内是遍历整个数据集更新参数,还是随机选择样本更新参数。书中无论是原始问题还是对偶问题都是随机选择样本进行更新,都是随机梯度下降。练习写代码的时候没有弄清楚,没有实现随机,是挨个选取的样本
设(xi,yi)经过n次修改,则w,b关于原始值的增量分别为 w = ∑ i = 1 N α i y i x i w = \sum_{i=1}^{N}\alpha_iy_ix_i w=i=1∑Nαiyixi b = ∑ i = 1 N α i y i ( 只 需 要 学 习 α i ) b = \sum_{i=1}^{N}\alpha_iy_i (只需要学习\alpha_i) b=i=1∑Nαiyi(只需要学习αi)
更新 α i ← α i + η [ 如 果 提 前 计 算 了 内 积 矩 阵 , 更 新 起 来 比 较 简 单 ] \alpha_i \leftarrow \alpha_i+\eta [如果提前计算了内积矩阵,更新起来比较简单] αi←αi+η[如果提前计算了内积矩阵,更新起来比较简单] b ← b + η y i b\leftarrow b+\eta y_i b←b+ηyi
#include
#include
#include
#include
using namespace std;
const int Max_data = 10;
struct data{
//std::vector data(2);
vector<double> samples;
//double x1;
int labels;
}dataSet[Max_data];
struct Result{
vector<double> alpha;
double b;
}result;
class Perception_dual
{
public:
/*导入数据并按照数据结构填充,返回样本个数*/
int loadDataSet()
{
fstream f ;
int countNum = 0;
f.open("data.dat");
int i = 0; double temp1,temp2; while(!f.eof())
{
f>>temp1>>temp2>>dataSet[i].labels;
dataSet[i].samples.push_back(temp1);
dataSet[i].samples.push_back(temp2);
i++;
countNum++;
}
f.close();
return countNum;
} double eta = 0;//设置学习率
/*计算内积,N样本个数*/
vector<vector<double>> cal_dot(data dataSet[],int N)
{
vector<vector<double>> dot(N);
for(int k=0;k<dot.size();k++)
{
dot[k].resize(N);
}
//cout<
double temp = 0.0;
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
//cout<
temp = dataSet[i].samples[0]*dataSet[j].samples[0]+dataSet[i].samples[1]*dataSet[j].samples[1];
//cout<
dot[i][j]=temp;
}
}
return dot;
}
/*更新变量*/
Result update(Result result,double eta,int labels,int i)
{
//int N = result.alpha.size();
//for (int i =0; i
//{
result.alpha[i] = result.alpha[i]+eta;
//}
result.b = result.b + eta*(double)labels;
return result;
}
Result initialize(Result result,int N)
{
for (int i=0;i<N;i++)
{
result.alpha.push_back(0);
}
result.b = 0.0;
return result;
}
/*计算判别条件*/
double cal_discriminate(data dataSet[],int N,Result result,int i)
{
double temp=0;
vector<vector<double>> dotx = cal_dot(dataSet,N); for (int j=0;j<N;j++)
{
temp = temp+result.alpha[j]*(double)dataSet[j].labels*dotx[j][i];
}
temp = (double)dataSet[i].labels*(temp+result.b);
return temp;
}
vector<double> cal_w(vector<double> alpha,data dataSet[],int N)
{
vector<double> w;
double temp1=0;
double temp2=0;
for (int i=0;i<N;i++)
{
temp1 = temp1+(double)dataSet[i].labels*(dataSet[i].samples[0]*result.alpha[i]);
temp2 = temp2+(double)dataSet[i].labels*(dataSet[i].samples[1]*result.alpha[i]);
}
w.push_back(temp1);
w.push_back(temp2);
return w;
}
Result perception_dual(data dataSet[],double eta,int N)
{
result = initialize(result,N);
bool flag = false;
int cnt = 0;double temp=0;
cout<<temp<<endl;
while(!flag)
{
cnt =0;
for (int i= 0;i<N;i++)
{
temp = cal_discriminate(dataSet,N,result,i);
if(temp<=0.0)
{
cnt++;
result = update(result,eta,dataSet[i].labels,i);
}
}
if(cnt == 0)
{
flag = true;
}
}
cout <<"Hello World"<<endl;
return result;
}
};
int main()
{
Perception_dual test;
int N = test.loadDataSet();
test.eta = 1.0;
cout<<"Hello World"<<endl; result = test.perception_dual(dataSet,test.eta,N);
for (int k = 0;k<N;k++)
{
cout<<result.alpha[k]<<endl;
}
vector<double> w = test.cal_w(result.alpha,dataSet,N);
cout<<"The weight is :" <<endl<<w[0]<<endl<<w[1]<<endl<<"And the biase is "<<endl<<result.b<<endl;
return 0;
}