二话不说先上题目:
训练数据格式如下:
输入有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();
}
多次运行程序,迭代次数均为45次。
该题要求使用“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;
}
本题要求在更新权向量时乘以一个0.5的系数,代码变动很少。