实验描述

  使用BP神经网络,编程实现手写体的识别,输出识别率。

浅谈BP

  BP神经网络也称后向传播学习的前馈型神经网络( Back Propagation Feed-forward Neural
Network,BPFNN/BPNN),是一种应用最为广泛的神经网络。
  BP神经网络是有监督学习网络,是一种按误差逆传播算法训练的多层前馈网络,BP网络能学习和存贮大量的输入-输出模式映射关系,而无需事前揭示描述这种映射关系的数学方程。BP神经网络模型结构包括输入层、隐含层和输出层。
  BP神经网络主要分为信号的正向传播和误差反向传播两个过程,正向传播是指在样本数据输入后,计算输入层到隐含层,再到输出层的数据;误差反向传播就是将输出误差以某种形式通过隐含层向输入层逐层反传,将误差分摊给各层的单元,再使用梯度下降法修正各单元的权值,使得最终输出结果和预期结果的误差最小。一般当网络输出的误差减少到可接受的程度或者进行到预先设定的学习次数时,训练结束。

  BP神经网络最主要的优点是具有极强的非线性映射能力。理论上,对于一个三层和三层以上的BP网络,只要隐层神经元数目足够多,该网络就能以任意精度逼近一个非线性函数。 BP神经网络具有对外界刺激和输入信息进行联想记忆的能力。这是因为它采用了分布并行的信息处理方式,对信息的提取必须采用联想的方式,才能将相关神经元全部调动起来

BP神经网络算法流程

  1. 初始化网络权值。网络权值和神经元偏执随机赋值在(-1,1)之间。
  2. 向前传播输入。
  3. 反向传播误差。
  4. 网络权值与神经元偏置调整。

激活函数

  sigmoid函数的作用是将输入映射到一个(0,1)的输出范围。

运行环境

  系统:Windows系统
  语言:C++
  软件:Dev-C++ 5.11

MNIST数据集

  MNIST是一个非常有名的手写体数字识别数据集,在很多资料中,这个数据集都会被用作深度学习的入门样例。
  数据集下载网址:http://yann.lecun.com/exdb/mnist/

数据集简介

  MINIST实验包含了四个文件,其中:
  train-images-idx3-ubyte是60000个图片样本;跳过开头16个字节,每784个字节代表一张图片,其中每一个字节代表28 * 28 中的一个像素点,取值范围为0~256。(本次实验中,像素点值大于128, 输入层的0-1矩阵对应维取1;小于128,0-1矩阵对应维取0)。

  train-labels-idx1-ubyte是这60000个图片对应的数字标签,跳过开头8个字节;

  t10k-images-idx3-ubyte是用于测试的样本,数量为10000张,跳过开头16个字节;   t10k-labels-idx1-ubyte是测试样本对应的数字标签,片数量为10000张,跳过开头8个字节。 MNIST的图像大小是28*28,先读取训练集中的第一张图像。   注意:在 train-images-idx3-ubyte 文件头部有4个integer类型,需要跳过去。

  数据集和整个实验项目在https://gitee.com/haaaaaaaaaaaa/SourceCode.git下的IntelligenceSystem/BPNNHandwritingRecognition中。

实验中数据处理

  对每一张手写图片,先把它处理成一个28 * 28 的0-1矩阵,其中1代表数字的笔画着色部分,0则代表空白。然后我们把该矩阵,扁平成一个784维的输入向量,输入到输入层。经过隐含层(此次实验隐藏层结点数取100),到达输出层时,是一个10维的输出向量,每一位分别对应数字的0~9 。

实验步骤

  1. 提取数据(使用MNIST数据集)
  2. 特征提取
  3. 训练BP神经网络
    1)权值和神经元偏置随机赋值
    2)前向求出隐含层和输出层的输出
    3)求出输出层与预期输出的误差
    4)反向传播误差,求出隐含层误差
    5)调整权值和神经元偏置
    6)结束(文件读取完毕)
  4. 数据测试,输出识别率

实验代码

/*
Description:智能系统理论与应用实验题目:基于BP神经网络的手写体识别1、提取数据(使用MNIST数据集)2、特征提取3、训练BP神经网络1)权值和神经元偏置随机赋值2)前向求出隐含层和输出层的输出3)求出输出层与预期输出的误差4)反向传播误差,求出隐含层误差5)调整权值和神经元偏置6)结束(文件读取完毕) 4、数据测试,输出识别率
Date:       2020/05/25
Version:    Dev-C++ 5.11
*/#include <iostream>
#include <fstream>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <cmath>
#include <time.h>using namespace std;/*全局变量*/
const int first = 784;         //输入层到隐藏层,输入层是784维输入向量(数据集中照片是28*28)
const int second = 100;            //隐含层节点数取100
const int third = 10;          //输出层是一个10维的向量,每一位分别对应数字0~9
const double alpha = 0.35;     //神经网络的学习率
int input[first];               //784维输入向量
int target[third];              //10维输出向量
double weight1[first][second];  //输入层到隐含层权重
double weight2[second][third];  //隐含层到输出层权重
double output1[second];         //隐含层输出
double output2[third];          //输出层输出,即目标输出
double delta1[second];          //隐含层误差
double delta2[third];           //输出层与预期输出的误差
double b1[second];              //隐含层神经元偏置,偏置的存在是为了更好的拟合数据
double b2[third];               //输出层神经元偏置,偏置的存在是为了更好的拟合数据
double test_num = 0.0;         //测试次数
double test_success_count = 0.0;//测试成功次数 /*激活函数*/
//sigmoid函数的作用是将输入映射到一个(0,1)的输出范围
double Sigmoid(double x){return 1.0 / (1.0 + exp(-x));
}/*初始化权重矩阵和神经元偏置*/
void Initialize(){srand((int)time(0) + rand());//算法的随机种子数,有这个数以后才可以产生随机数 ,只调用rand,每次出来的东西是一样的 for (int i = 0; i < first; i++){for (int j = 0; j < second; j++){weight1[i][j] = rand()%1000 * 0.001 - 0.5;//输入层到隐含层权值 }}  for (int j = 0; j < second; j++){for (int k = 0; k < third; k++){weight2[j][k] = rand()%1000 * 0.001 - 0.5;//隐含层到输出层权值 }}for (int j = 0; j < second; j++){b1[j] = rand()%1000 * 0.001 - 0.5;//隐含层神经元偏置 }for (int k = 0; k < third; k++){b2[k] = rand()%1000 * 0.001 - 0.5;//输出层神经元偏置 }
}
/*隐含层输出*/
void HiddenLayerOutput(){for (int j = 0; j < second; j++){double sigma = 0;for (int i = 0; i < first; i++){sigma += input[i] * weight1[i][j]; //输入和权值乘积的累加和 }double x = sigma + b1[j];//加上神经元偏置 output1[j] = Sigmoid(x);//激活函数激活,得到隐含层输出 }
}/*输出层输出*/
void OutputLayerOutput(){for (int k = 0; k < third; k++){double sigma = 0;for (int j = 0; j < second; j++){sigma += output1[j] * weight2[j][k];//隐含层输出和权值乘积的累加和 }double x = sigma + b2[k];//加上神经元偏置 output2[k] = Sigmoid(x);//激活函数激活,得到输出层输出 }
}/*计算输出层与预期输出的误差*/
void OutputTargetError(){for (int k = 0; k < third; k++){delta2[k] = (output2[k]) * (1.0 - output2[k]) * (output2[k] - target[k]);}
}/*反向传播误差,求出隐含层误差*/
void HiddenLayerError(){for (int j = 0; j < second; j++){double sigma = 0;for (int k = 0; k < third; k++){sigma += weight2[j][k] * delta2[k];//需要用到输出层和预期输出之间的误差 }delta1[j] = (output1[j]) * (1.0 - output1[j]) * sigma; }
}/*调整隐含层到输出层的权值和神经元偏置*/
void FeedbackThirdLayer(){for (int k = 0; k < third; k++){b2[k] = b2[k] - alpha * delta2[k];//调整神经元偏置 for (int j = 0; j < second; j++){weight2[j][k] = weight2[j][k] - alpha * output1[j] * delta2[k];//调整权值 }}
}/*调整输入层到隐含层的权值和神经元偏置*/
void FeedbackSecondLayer(){for (int j = 0; j < second; j++){b1[j] = b1[j] - alpha * delta1[j];//调整神经元偏置 for (int i = 0; i < first; i++){weight1[i][j] = weight1[i][j] - alpha * input[i] * delta1[j];//调整权值 }}
}/*训练*/
void Training(){FILE *image_train;FILE *image_label;image_train = fopen("../MNIST/train-images.idx3-ubyte", "rb");image_label = fopen("../MNIST/train-labels.idx1-ubyte", "rb");if (image_train == NULL || image_label == NULL){cout << "Can't open the file!" << endl;exit(0);}unsigned char image_buf[784];unsigned char label_buf[10];int useless[1000];//存放测试文件中开头无用的数据 fread(useless, 1, 16, image_train);//跳过开头16字节 fread(useless, 1, 8, image_label);//跳过开头8字节 int count = 0;//计算图片数量 cout << "Start training..." << endl;//循环60000次 while (!feof(image_train) && !feof(image_label)){memset(image_buf, 0, 784);memset(label_buf, 0, 10);fread(image_buf, 1, 784, image_train);//每784个字节为一张图片 fread(label_buf, 1, 1, image_label);//读取对应数字标签 //处理成一个28 * 28 的0-1矩阵,其中1代表数字的笔画着色部分,0则代表空白//MNIST数据集中图片背景为黑色(0纯黑),手写体为白色(255纯白) for (int i = 0; i < 784; i++){if ((unsigned int)image_buf[i] < 128){input[i] = 0;}else{input[i] = 1;}}//初始化目标输出 int target_value = (unsigned int)label_buf[0];for (int k = 0; k < third; k++){target[k] = 0;}target[target_value] = 1;//训练HiddenLayerOutput();OutputLayerOutput();OutputTargetError();HiddenLayerError();FeedbackSecondLayer();FeedbackThirdLayer();count ++;//每1000张显示一次 if (count % 1000 == 0){cout << "Training number: " << count << endl;}}cout << endl;
}/*测试*/
void Testing(){FILE *image_test;FILE *image_test_label;image_test = fopen("../MNIST/t10k-images.idx3-ubyte", "rb");image_test_label = fopen("../MNIST/t10k-labels.idx1-ubyte", "rb");if (image_test == NULL || image_test_label == NULL){cout << "Can't open the file!" << endl;exit(0);}unsigned char image_buf[784];unsigned char label_buf[10];int useless[1000];//存放测试文件中开头无用的数据 fread(useless, 1, 16, image_test);//跳过开头16字节 fread(useless, 1, 8, image_test_label);//跳过开头8字节 while (!feof(image_test) && !feof(image_test_label)){memset(image_buf, 0, 784);memset(label_buf, 0, 10);fread(image_buf, 1, 784, image_test);//每784个字节为一张图片 fread(label_buf, 1, 1, image_test_label);//读取对应数字标签 //处理成一个28 * 28 的0-1矩阵,其中1代表数字的笔画着色部分,0则代表空白for (int i = 0; i < 784; i++){if ((unsigned int)image_buf[i] < 128){input[i] = 0;}else{input[i] = 1;}}//初始化目标输出 for (int k = 0; k < third; k++){target[k] = 0;}int target_value = (unsigned int)label_buf[0];target[target_value] = 1;//得到输出 HiddenLayerOutput();OutputLayerOutput();double max_value = -99999;int max_index = 0;for (int k = 0; k < third; k++){if (output2[k] > max_value){max_value = output2[k];max_index = k;}}//系统输出和预期输出对比 if (target[max_index] == 1){test_success_count ++;}test_num ++;if ((int)test_num % 1000 == 0){cout << "Testing number: " << test_num << "  Success number: " << test_success_count << endl;}}cout << endl;cout << "The success rate: " << test_success_count / test_num << endl;
}
/*主函数*/
int main(){cout<<"******************************************************************"<<endl; cout<<"*                     智能系统理论与应用实验                     *"<<endl; cout<<"*                   基于BP神经网络的手写体识别                   *"<<endl; cout<<"******************************************************************"<<endl; Initialize();Training();Testing();system("pause");
}

总结

  本人对BP的理解还不够深入,有不对的地方希望大家指出,一起探讨。


声明:
如因本人发布的作品内容涉及版权或存在其他问题,请联系我进行删除。
谢谢浏览!

基于BP神经网络的手写体识别相关推荐

  1. 基于BP神经网络进行手写体识别(Matlab代码实现)

    目录

  2. 并行化实现基于BP神经网络的手写体数字识别

    并行化实现基于BP神经网络的手写体数字识别 手写体数字识别可以堪称是神经网络学习的"Hello World" ,我今天要说的是如何实现BP神经网络算法的并行化,我们仍然是以手写体数 ...

  3. 【图像识别】基于BP神经网络实现手写体大写字母识别附matlab代码

    1 简介 手写体字符识别是人机交互领域的一个重要内容,本文基于 BP 神经网络实现了任意数量字符模版的多字符手写体字符识别.分为以下几步,第一,首先对目标图像进行识别前预处理.包括灰度图像二值化,图像 ...

  4. 基于BP神经网络的车牌识别系统的设计

    一.基本原理概述 基于BP神经网络的的汽车牌照识别系统的处理过程分为预处理.边缘提取.车牌定位.字符分割.字符识别五大模块.具体涉及以下几个过程: ① 原始车牌图像:由数码相机或其他扫描装置拍摄到的车 ...

  5. 【图像识别】基于 BP神经网络路面裂缝识别系统Matlab代码

    1 简介 随着我国经济建设的快速发展,道路交通在国民经济建设中扮演的角色越来越重要.随之而来的道路路面的养护和管理问题愈发凸显,其中道路路面的破损检测就成为相关道路养护部门的工作重点之一.另外,随着我 ...

  6. 基于BP神经网络的手写体数字识别matlab仿真实现

    目录 一.理论基础 二.核心程序 三.测试结果 一.理论基础 文字.数字识别是一个典型的模式识别问题,也是模式识别中一个非常重要的应用领域.在文字.数字识别系统中,手写体的文字与识别是一个较难的领域, ...

  7. ECG信号读取,检测QRS,P,T 波(基于小波去噪与检测),基于BP神经网络的身份识别

    这学期选了神经网络的课程,最后作业是处理ECG信号,并利用神经网络进行识别. 1  ECG介绍与读取ECG信号 1)ECG介绍 具体ECG背景应用就不介绍了,大家可以参考百度 谷歌.只是简单说下ECG ...

  8. BP神经网络的手写体识别 Python3

    文章目录 1 BP公式的推导 1.1 激活函数 1.1.1 `Sigmod`函数导数 1.2 损失函数 1.3 前向传播 1.3 计算误差反向传播 1.3.1 误差为方差时,输出层误差的计算 1.3. ...

  9. 基于BP神经网络的车牌识别系统(Matlab代码实现)

  10. 【身份证识别】基于BP神经网络实现身份证识别附matlab代码

    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信.

最新文章

  1. 第二单元 考点6-7商业银行和投资理财
  2. 什么是javadoc文档
  3. js实现上传图片及时预览
  4. glibc升级_CentOS7下升级GLIBC2.31
  5. java 面试 概率论_编程培训-115个Java面试题和答案B.pdf
  6. 微软100题第11题
  7. 用 JavaScript 的方式理解递归
  8. 从Oracle数据库故障到AIX内存管理
  9. 【目标检测】Anchor-Free算法--CenterNet详解
  10. rocketmq顺序消费问题
  11. IPhone在横屏字体变大解决办法-webkit-text-size-adjust
  12. 出租车GPS数据处理
  13. 常见的10种配置管理工具
  14. 电脑连接宽带,给手机开热点
  15. 访问GitLab 返回502错误
  16. 长度最小的子数组(力扣209)
  17. 针对DDoS攻击异常流量攻击统计
  18. mysql 去除逗号,MySQL查询删除字符串中最后一个逗号后的所有字符?
  19. 小米路由器AC2100写入OpenWrt
  20. Oracle --- 同义词

热门文章

  1. Oracle性能优化(11g)
  2. js模板引擎 html,JS 模板引擎
  3. 社交网络分析算法(SNA)
  4. vue+阿里的G2图表-antv+折线图
  5. unity打开excel表格_unity创建编辑读取EXCEL文件表格数据游戏插件工具Uni-Excel 1.0
  6. cad剖切线的快捷键_CAD中剖面线如何画
  7. 蔡学镛告诉我们—做好技术PPT的要点
  8. 综述:三维点云深度学习技术
  9. 【IT项目管理】第10章 应对项目风险
  10. python图像识别与提取_python图像识别与提取