#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;
}
BP神经网络实现手写数字识别
于 2023-12-24 20:05:52 首次发布