BP神经网络实现手写数字识别


#include<iostream>
#include<time.h>
using namespace std;
const int Input = 784; 
const int hidden = 60;
const int output = 10;
const float s_w = 0.4;
const float s_b = 0.05;
//权重矩阵
double w1[Input][hidden] = {0};
double w2[hidden][output] = {0};
double b1[hidden] = { 0 };
double b2[output] = {0};
double target[output] = { 0 };

double E_w1[Input][hidden] = { 0 };
double E_w2[hidden][output] = { 0 };
double E_b1[hidden] = { 0 };
double E_b2[output] = { 0 };

double Input[Input];
double hidden_Z[hidden];//中间层神经元
double hiddenOut[hidden];
double output_z[output];//输出层神经元
double outputOut[output];

double sigma1[hidden]; //中间层误差
double sigma2[output];//输出层误差



double sigmoid(double x) {
	return 1 / (1 + exp(-x));
}

double sigmod_prime(double x) {
	return sigmoid(x) * (1 - sigmoid(x));
}
//权重初始化函数
void init_w()
{
	for (int i = 0; i < Input; i++)
     {
		for (int j = 0; j < hidden; j++) 
        {
			w1[i][j] = rand() / double(RAND_MAX) - 0.5;
		}
	}
	//初始化w2
	for (int i = 0; i < hidden; i++) {
		for (int j = 0; j < output; j++) {
			w2[i][j] = rand() / double(RAND_MAX) - 0.5;
		}
	}
	for (int i = 0; i < hidden; i++) {
		b1[i] = rand() / double(RAND_MAX) - 0.5;
	}
	for (int i = 0; i < output; i++) {
		b2[i] = rand() / double(RAND_MAX) - 0.5;
	}
}
//中间层输出
void hidden_output() {
	for (int i = 0; i < hidden; i++) {
		for (int j = 0; j < Input; j++) {
			hidden_Z[i] += Input[j] * w1[j][i];
		}
		hidden_Z[i] += b1[i];
		hiddenOut[i] = sigmoid(hidden_Z[i]);
	}
}
// 输出层输出
void output_output() {
	for (int i = 0; i < output; i++) {
		for (int j = 0; j < hidden; j++) {
			output_z[i] += hiddenOut[j] * w2[j][i];
		}
		output_z[i] += b2[i];
		outputOut[i] = sigmoid(output_z[i]);
	}
}
//前向传播函数
void Forward()
{
	for (int i = 0; i < hidden; i++) {
		hidden_Z[i] = 0;
		hiddenOut[i] = 0;
	}
	for (int i = 0; i < output; i++) {
		output_z[i] = 0;
		outputOut[i] = 0;
	}
	hidden_output();
	output_output();
}

// 计算输出层权值梯度
void w2_grad(double lab[]) {
	for (int i = 0; i < output; i++) {
		sigma2[i] = (outputOut[i] - lab[i]) * sigmod_prime(output_z[i]);
		for (int j = 0; j < hidden; j++) {
			E_w2[j][i] = sigma2[i] * hiddenOut[j];
		}
	}	
}
//计算隐藏层梯度
void w1_grad() {
	for (int i = 0; i < hidden; i++) {
		sigma1[i] = 0;
		for (int j = 0; j < output; j++) {
			sigma1[i] += sigma2[j] * w2[i][j] * sigmod_prime(hidden_Z[i]);
		}
		for (int k = 0; k < Input; k++) {
			E_w1[k][i] = sigma1[i] * Input[k];
		}
	}	
}
//计算b2梯度
void b2_grad() {
	for (int i = 0; i < output; i++) {
		E_b2[i] = sigma2[i];
	}
	
}
//计算b1梯度
void b1_grad() {
	for (int i = 0; i < hidden; i++) {
		E_b1[i] = sigma1[i];
	}
	
}

void update() {
	for (int i = 0; i < hidden; i++) {
		for (int j = 0; j < output; j++) {
			w2[i][j] -= E_w2[i][j] * s_w;
			b2[j] -= E_b2[j] * s_b;
		}
	}
	for (int i = 0; i < Input; i++) {
		for (int j = 0; j < hidden; j++) {
			w1[i][j] -= E_w1[i][j] * s_w;
			b1[j] -= E_b1[j] * s_b;
		}
	}
}
//日子2003.5.25
//版权归你差点就抓住了杰克船长
void train()
{
	FILE* train_img;
	FILE* train_lab;
	fopen_s(&train_img, "train-images.idx3-ubyte", "rb");
	fopen_s(&train_lab, "train-labels.idx1-ubyte", "rb");
	if (train_img==NULL ||train_lab==NULL) {
		cout << "训练文件打开失败" << endl;
		exit(1);
	}
	cout << "训练开始" << endl;


	int useless[100];
	fread(useless, 1, 16, train_img);
	fread(useless, 1, 8, train_lab);
	long int num=0;
	for (long int i = 0; i < 60000; i++) {
		unsigned char img[784];
		unsigned char lab;

		fread(img, 1, 784, train_img);
		fread(&lab, 1, 1, train_lab);
		//将28*28的图片写入input
		for (int j = 0; j < Input; j++) {
			if ((unsigned int)img[j] > 128) Input[j] = 1;
			else Input[j] = 0;
		}
		int value = (unsigned int)lab;
		for (int k = 0; k < output; k++) {
			target[k] = 0;
		}
		target[value] = 1;

		Forward();			//前向传播
		w2_grad(target);	//计算权值梯度
		w1_grad();		
		b2_grad();
		b1_grad();
		update();			//更新权值和偏执值
		
		num++;
		if (num % 6000 == 0) {
			cout << "训练进度:" << 100*1.0*num/60000<<"%" << endl;
		}
	 }
	cout << endl;
}
void test() {
	long num=0,success_num=0;
	FILE* test_img;
	FILE* test_lab;
	fopen_s(&test_img, "train-images.idx3-ubyte", "rb");
	fopen_s(&test_lab, "train-labels.idx1-ubyte", "rb");
	if ( test_img==NULL || test_lab==NULL) {
		cout << "训练文件打开失败" << endl;
		exit(1);
	}
	cout << "测试开始" << endl;
	unsigned char img[784];
	unsigned char lab;

	int useless[100];
	fread(useless, 1, 16, test_img);
	fread(useless, 1, 8, test_lab);
	for (long j = 0; j < 10000; j++) {

		fread(img, 1, 784, test_img);
		fread(&lab, 1, 1, test_lab);
		for (int j = 0; j < Input; j++) {
			if ((unsigned int)img[j] > 128) Input[j] = 1;
			else Input[j] = 0;
		}
		int value = (unsigned int)lab;
		for (int k = 0; k < output; k++) {
			target[k] = 0;
		}
		target[value] = 1;
		Forward();
		double max_value = -1000;
		int max_index = 0;
		for (int i = 0; i < output; i++) {
			if (outputOut[i] > max_value) {
				max_value = outputOut[i];
				max_index = i;
			}
		}
		if (target[max_index] == 1) {
			success_num++;
		}
		num++;
		if (num % 1000 == 0) {
			cout << "测试数量:" << num<<"测试正确数:"<<success_num << endl;
		}
	}
	cout << endl;
	cout << "正确率:" << (success_num * 1.0) / (1.0 * num) << endl;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值