说明
这次数据挖掘作业用C++写了个BP算法,记录一下。相关的原理算法不做说明。本算法使用三层网络,也就是一层隐含层。识别对象是手写体数字,使用minist数据集,每张图片大小为28*28,所以输入节点数为784,输出为0-9十个数字,所以输出节点数为10。隐含层使用30个节点。偏执项不做更新,激活函数使用sigmoid。
代码
头文件
#define hideNodeNum 30 //隐含层节点
#define hold 0.001 //误差标准
#define b1 0.35 //偏执项
#define b2 0.65
using namespace std;
//双层bp
class myBp {
private:
vector<double> train_label;
vector<vector<double>> train_image;//训练集
vector<double> test_label;
vector<vector<double> > test_image;//测试集
int train_number;//训练集的个数
int test_number;//测试集的个数
int inputSize=784;//输入的特征的个数
double learnRate=0.2;//学习率
vector<vector<double>> v;//输入层权重
vector<vector<double>> w;//隐含层权重
double hideNode[101];//隐含层节点
double res[10];//输出层节点
double sigmoid(double x);//激活函数
void forward(int k);//对于第k张图像进行前向运算
void back(int k);//后向BP
double errorS(int k);//计算第k张图片的总误差
void saveData();//保存权重数据
void readData();//读取权重数据
void initWeight();//初始化权重
int n;//子集编号
bool subMod;//是否是对子集训练
double outError;
public:
bool init=false;
myBp();
void getData(dataSet data);
void getSubData(dataSet data, int n);
void setTrainNumber(int k);//设置训练集合大小
void train();//训练过程
void test();//测试数据
void test_a();//测试算法正确性
int predic(int num);//预测第num的测试集的结果
void testImages(vector<vector<double>> img);
};
核心代码为后向传播。
void myBp::back(int num) {
double out[10];//实际输出
for(int i=0;i<10;i++) {
out[i]=0;
}
out[int(train_label[num])]=1;
double L=0;//总误差
for(int i=0;i<10;i++) {
L+=0.5*pow(res[i]-out[i], 2);//计算输出总误差
}
outError=L;
for(int i=0;i<hideNodeNum;i++) {
for(int j=0;j<10;j++) {
//计算权重调整值
double delta=-(out[j]-res[j])*res[j]*(1-res[j])*hideNode[i];
//权重调整
w[i][j]-=learnRate*delta;
}
}
for(int i=0;i<inputSize;i++) {
for(int j=0;j<hideNodeNum;j++) {
double delta=0;
//计算权重调整值
for(int k=0;k<10;k++) {
delta+=(out[k]-res[k])*res[k]*(1-res[k])*w[j][k]*hideNode[j]*(1-hideNode[j])*train_image[num][i];
}
//权重调整
v[i][j]+=learnRate*delta;
}
}
}
目录
data文件夹下存放训练测试数据,param存放权重参数,pic为手写的测试图片(该功能需要opencv库)。
仓库链接
code文件夹下为代码文件,pro下二进制文件可直接运行。使用的是xcode编写,没有上传整个项目文件。