4.1 - 《机器学习基石》Home Work 1 Q.15-17

二话不说先上题目:

181027_HmyT_1047422.png

训练数据格式如下:

181314_eFIB_1047422.png

输入有4个维度,输出为{-1,+1}。共有400条数据。

题目要求将权向量元素初始化为0,然后使用“Naive Cycle”遍历训练集,求停止迭代时共对权向量更新了几次。

所谓“Naive Cycle”指的是在某数据条目x(i)上发现错误并更新权向量后,下次从x(i+1)继续读数据,而不是回到第一条数据x(0)从头开始。

#include <fstream>
#include <iostream>
#include <vector>

using namespace std;

#define DEMENSION 5                //数据维度

double weights[DEMENSION];         //权重向量
int step= 0;                       //迭代次数
int length = 0;                    //数据条目个数
int index = 0;                     //当前数据条目索引
bool isFinished = false;           //迭代终止状态
char *file = "training_data.txt";

struct record {
	double input[DEMENSION];   //输入
	int output;                //输出	
};
vector<record> trainingSet;        //训练数据


int sign(double x)
{
	if(x<0)		 return -1;
	else if(x>0) return 1;
	else		 return -1;
}

//两个向量相加,更新第一个向量
void add(double *v1, double *v2, int demension)
{
	for(int i=0;i<demension;++i){ v1[i] = v1[i] + v2[i]; }
}

//两个向量相乘,返回内积
double multiply(double *v1, double *v2, int demension)
{
	double innerProd = 0.0;
	for(int i=0;i<demension;++i){
		innerProd += v1[i] * v2[i];
	}
	return innerProd;
}

//向量与实数相乘,结果通过*result返回,不改变参与计算的向量
void multiply(double *result, double *v, double num, int demension)
{
	for(int i=0;i<demension;++i){ result[i] = v[i] * num; }
}

//读取所有训练数据
void getData(ifstream & dataFile)
{
	while(!dataFile.eof()){
		record curRecord;
		curRecord.input[0] = 1;      
		for(int i=1;i<DEMENSION;++i){ dataFile>>curRecord.input[i]; }
		dataFile>>curRecord.output;
		trainingSet.push_back(curRecord);
	}
	dataFile.close();
	length = trainingSet.size();
}

void PLA()
{
	int start = index;
	double curInput[DEMENSION];
        
        //找到下一个错误记录的index
	while( trainingSet[index].output == 
	sign(multiply(weights,trainingSet[index].input,DEMENSION)) )
	{	
		if(index==length-1)	{index = 0;}
		else			{index++;}
		if(index==start)	{isFinished = true; break;}	//没发现错误,迭代结束
	}

	if(isFinished){
		cout<<"计算结果:step = "<<step<<", weights = \n";
		for(int i=0;i<DEMENSION;++i){ cout<<weights[i]<<endl; }	
		return;
	}else{
		step++;
                
                //更新: weights = weights + curOutput * curInput
		multiply( curInput, trainingSet[index].input, 
		    trainingSet[index].output, DEMENSION );	
		add( weights, curInput, DEMENSION );	

		if(index==length-1)	{index = 0;}
		else			{index++;}

		PLA();	
	}
	return;
}

void main()
{	
	ifstream dataFile(file);

	if(dataFile.is_open()){
		getData(dataFile);		
	}else{
		cerr<<"ERROR ---> 文件打开失败"<<endl;
		exit(1);
	}

	for(int i=0;i<DEMENSION;++i){ weights[i] = 0.0; }

	PLA();
}

182329_4GXS_1047422.png

多次运行程序,迭代次数均为45次。

102212_sPfW_1047422.png

该题要求使用“fixed,pre-determined random cycle”对数据进行遍历,即对400条数据进行随机排序,然后在这轮计算中始终使用这一排序,直到下一轮计算开始再重新排序,重复2000次,求对权向量的平均修正次数。

#include <fstream>
#include <iostream>
#include <vector>
#include <ctime>

using namespace std;

#define DEMENSION 5                //数据维度

int step= 0;                       //迭代次数
int index = 0;                     //当前数据条目索引
bool isFinished = false;           //迭代终止状态
char *file = "training_data.txt";

struct record {
	double input[DEMENSION];   //输入
	int output;                //输出	
};



int sign(double x)
{
	//同Q15
}

void add(double *v1, double *v2, int demension)
{
	//同Q15
}

//两个向量相乘,返回内积
double multiply(double *v1, double *v2, int demension)
{
	//同Q15
}

//向量与实数相乘,结果通过*result返回,不改变参与计算的向量
void multiply(double *result, double *v, double num, int demension)
{
	//同Q15
}

//对 traininig set 创建一个随机排序
void setRandomOrder(vector<record> &trainingSet, vector<int> &randIndexes)
{
	srand((unsigned)time(NULL)); 
	int length = trainingSet.size();	
	vector<bool> assignedIndexes(length,false);	  

	for(int i=0;i<length;++i){
		int randIndex = rand()%length;
		while(assignedIndexes[randIndex]==true){
			randIndex = rand()%length;	
		}
		randIndexes.push_back(randIndex); 
		assignedIndexes[randIndex] = true;		
	}
}

//读取所有训练数据
void getData(ifstream & dataFile, vector<record> &trainingSet)
{
	while(!dataFile.eof()){
		record curRecord;
		curRecord.input[0] = 1;      
		for(int i=1;i<DEMENSION;++i){ dataFile>>curRecord.input[i]; }
		dataFile>>curRecord.output;
		trainingSet.push_back(curRecord);
	}
	dataFile.close();	
}


void PLA(vector<record> &trainingSet, vector<int> &randIndexes, double *weights)
{
	int length = trainingSet.size();
	int start = index;	
	double curInput[DEMENSION];
        
        //找到下一个错误记录的index
	while( trainingSet[randIndexes[index]].output == 
	    sign(multiply(weights,trainingSet[randIndexes[index]].input,DEMENSION)) ){	
		if(index==length-1)	{index = 0;}
		else				{index++;}
		if(index==start)	{isFinished = true; break;}	//没发现错误,迭代结束
	}

	if(isFinished){
		return;
	}else{
		step++;
                
                //更新: weights = weights + curOutput * curInput
		multiply( curInput, trainingSet[randIndexes[index]].input, 
		    trainingSet[randIndexes[index]].output, DEMENSION );	
		add( weights, curInput, DEMENSION );	

		if(index==length-1)	{index = 0;}
		else		        {index++;}

		PLA(trainingSet, randIndexes, weights);	
	}
	return;
}

void main()
{
	int totalSteps = 0;

	for(int i=0;i<2000;++i){

		double weights[DEMENSION];      //权重向量
		vector<record> trainingSet;     //训练数据
		vector<int> randIndexes;        //访问数据的随机索引列表
		ifstream dataFile(file);

		step = 0;			   
		index = 0;			   
		isFinished = false;   

		if(dataFile.is_open()){
			getData(dataFile,trainingSet);	
			setRandomOrder(trainingSet,randIndexes);
		}else{
			cerr<<"ERROR ---> 文件打开失败"<<endl;
			exit(1);
		}

		for(int i=0;i<DEMENSION;++i){ weights[i] = 0.0; }

		PLA(trainingSet, randIndexes, weights);
		totalSteps += step;
	}

	cout<<"Average Step = "<<totalSteps/2000<<endl;
}

103241_65uc_1047422.png

103320_SZ0U_1047422.png

本题要求在更新权向量时乘以一个0.5的系数,代码变动很少。

103701_QfeK_1047422.png

转载于:https://my.oschina.net/findbill/blog/208917

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值