Python学习记录 搭建BP神经网络实现手写数字识别
搭建BP神经网络实现手写数字识别
通过之前的文章我们知道了,构建一个简单的神经网络需要以下步骤
- 准备数据
- 初始化假设
- 输入神经网络进行计算
- 输出运行结果
这次,我们来通过sklearn的手写数字数据集,来搭建一个BP神经网络,实现手写数字识别
背景
- 搭建的是一个2层的神经网络,包含一个输入层(输入层一般不计入网络的层数里面),一个隐藏层和一个输出层
- 每个样本包含64个特征,标签进行了独热化处理(独热化处理就会将每种标签转化成一个只包含0和1,长度为10的数组,例如:数字0的标签就为[1,0,0,0,0,0,0,0,0,0],数字1的标签为[0,1,0,0,0,0,0,0,0,0],数字2的标签为[0,0,1,0,0,0,0,0,0,0]),因为存在10个标签(0到9),所以输入层设置了64个神经元,输出层设置了10个神经元,隐藏层设置100个神经元
- 神经网络的输出,也是一个长度为10的数组,如0为[1,0,0,0,0,0,0,0,0,0],最大大数字的索引为0,即预测结果为0,只需要取出数组最大数字的索引便可得到预测结果
- 激活函数为sigmoid函数
- 数据集使用sklearn的手写数字数据集
准备数据
加载数据
digits = load_digits()
设置输入数据
X为我们的输入数据
X = digits.data
设置目标输出数据
Y为我们的目标数据
Y = = digits.target
数据归一化处理
将输入数据归一化,范围变成0 到 1之间
X = (X - X.min()) / (X.max() - X.min())
数据拆分
将数据拆分成训练集和测试集,测试数据就是我们的假设数据,用于与训练模型进行测试
x_train, x_test, y_train, y_test = train_test_split(X, Y)
独热化处理
将训练数据标签独热化处理
labels = LabelBinarizer().fit_transform(y_train)
- 独热编码即 One-Hot 编码,又称一位有效编码,其方法是使用N位状态寄存器来对N个状态进行编码,每个状态都有它独立的寄存器位,并且在任意时候,其中只有一位有效
- 独热化处理就会将每种标签转化成一个只包含0和1,长度为10的数组,例如:数字0的标签就为[1,0,0,0,0,0,0,0,0,0],数字1的标签为[0,1,0,0,0,0,0,0,0,0],数字2的标签为[0,0,1,0,0,0,0,0,0,0]
初始化假设并输入神经网络进行计算
搭建神经网络
设置偏置值
没有偏置的话,分割线会经过原点,就不能正确的分类了
class NeuralNetwork:def __init__(self, layers):# 初始化隐藏层权值self.w1 = np.random.random([layers[0], layers[1]]) * 2 - 1# 初始化输出层权值self.w2 = np.random.random([layers[1], layers[2]]) * 2 - 1# 初始化隐藏层的偏置值self.b1 = np.zeros([layers[1]])# 初始化输出层的偏置值self.b2 = np.zeros([layers[2]])
定义激活函数和它的导函数(梯度下降法所需要)
# 定义激活函数@staticmethoddef sigmoid(x):return 1 / (1 + np.exp(-x))# 定义激活函数的导函数@staticmethoddef dsigmoid(x):return x * (1 - x)
设置训练方法
def train(self, x_data, y_data, lr=0.1, batch=50):"""模型的训练函数:param x_data: 训练数据的特征:param y_data: 训练数据的标签:param lr: 学习率:param batch: 每次要训练的样本数量:return:"""# 随机选择一定批次的数据进行训练index = np.random.randint(0, x_data.shape[0], batch)x = x_data[index]t = y_data[index]# 计算隐藏层的输出l1 = self.sigmoid(np.dot(x, self.w1) + self.b1)# 计算输出层的输出l2 = self.sigmoid(np.dot(l1, self.w2) + self.b2)# 计算输出层的学习信号delta_l2 = (t - l2) * self.dsigmoid(l2)# 计算隐藏层的学习信号delta_l1 = delta_l2.dot(self.w2.T) * self.dsigmoid(l1)# 计算隐藏层的权值变化delta_w1 = lr * x.T.dot(delta_l1) / x.shape[0]# 计算输出层的权值变化delta_w2 = lr * l1.T.dot(delta_l2) / x.shape[0]# 改变权值self.w1 += delta_w1self.w2 += delta_w2# 改变偏置值self.b1 += lr * np.mean(delta_l1, axis=0)self.b2 += lr * np.mean(delta_l2, axis=0)
设置预测方法
def predict(self, x):"""模型的预测函数:param x: 测试数据的特征:return: 返回一个包含10个0-1之间数字的numpy.array对象"""l1 = self.sigmoid(np.dot(x, self.w1) + self.b1)l2 = self.sigmoid(np.dot(l1, self.w2) + self.b2)return l2
保存和加载模型
# 保存训练模型def save(self, path):np.savez(path, w1=self.w1, w2=self.w2, b1=self.b1, b2=self.b2)# 加载训练模型def load(self, path):npz = np.load(path)self.w1 = npz['w1']self.w2 = npz['w2']self.b1 = npz['b1']self.b2 = npz['b2']
设置输入检测图像的API接口
# 输入手写数字图像,返回模型预测结果def predict_num(self, img):# 将图片转换为灰度图img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 将图片转换为二值图img = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)[1]# 将图片转换为8*8的矩阵img = cv2.resize(img, (8, 8))# 将图片转换为一维向量img = img.flatten()# 图片归一化处理img = img / 255# 预测图片的数字num = self.predict(img)# 返回预测结果return np.argmax(num)
定义一个2层的网络模型
输入层64个特征输入
隐藏层100个神经元
输出层10个神经元
nn = NeuralNetwork([64, 100, 10])
设置训练周期和测试周期
epoch = 20000
test = 400
保存测试时产生的代价函数的值以及测试过程中的准确率
loss = []
accuracy = []
输入神经网络进行计算
for n in range(epoch):nn.train(x_train, labels)# 每训练一定的次数后,进行一次测试if n % test == 0:# 用测试集测试模型,返回结果为独热编码的标签predictions = nn.predict(x_test)# 取返回结果最大值的索引,即为预测数据y2 = np.argmax(predictions, axis=1)# np.equal用来比较数据是否相等,相等返回True,不相等返回False# 比较的结果求平均值,即为模型的准确率acc = np.mean(np.equal(y_test, y2))# 计算代价函数cost = np.mean(np.square(y_test - y2) / 2)# 将准确率添加到列表accuracy.append(acc)# 将代价函数添加到列表loss.append(cost)print('epoch:', n, 'accuracy:', acc, 'loss:', loss)
输出运行结果
使用测试数据对模型进行测试
训练完成之后,使用测试数据对模型进行测试
pred = nn.predict(x_test)
y_pred = np.argmax(pred, axis=1)
查看模型预测结果与真实标签之间的报告
print(classification_report(y_test, y_pred))
查看模型预测结果与真实标签之间的混淆矩阵
print(confusion_matrix(y_test, y_pred))
打印出图标查看
plt.subplot(2, 1, 1)
plt.plot(range(0, epoch, test), loss)
plt.ylabel('loss')
plt.subplot(2, 1, 2)
plt.plot(range(0, epoch, test), accuracy)
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.show()
可以看到准确率则是逐渐的增加
输入数字图片进行预测
准备一张图片
保存为5.png
img = cv2.imread('5.png')
print("识别的数字为:",nn.predict_num(img))
完整代码
import numpy as np
import cv2
from matplotlib import pyplot as plt
from sklearn.datasets import load_digits
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, confusion_matrix
import os# 数据库路径
MODEL_PATH = "sklen_num_model.npz"class NeuralNetwork:def __init__(self, layers):# 初始化隐藏层权值self.w1 = np.random.random([layers[0], layers[1]]) * 2 - 1# 初始化输出层权值self.w2 = np.random.random([layers[1], layers[2]]) * 2 - 1# 初始化隐藏层的偏置值self.b1 = np.zeros([layers[1]])# 初始化输出层的偏置值self.b2 = np.zeros([layers[2]])# 定义激活函数@staticmethoddef sigmoid(x):return 1 / (1 + np.exp(-x))# 定义激活函数的导函数@staticmethoddef dsigmoid(x):return x * (1 - x)def train(self, x_data, y_data, lr=0.1, batch=50):"""模型的训练函数:param x_data: 训练数据的特征:param y_data: 训练数据的标签:param lr: 学习率:param batch: 每次要训练的样本数量:return:"""# 随机选择一定批次的数据进行训练index = np.random.randint(0, x_data.shape[0], batch)x = x_data[index]t = y_data[index]# 计算隐藏层的输出l1 = self.sigmoid(np.dot(x, self.w1) + self.b1)# 计算输出层的输出l2 = self.sigmoid(np.dot(l1, self.w2) + self.b2)# 计算输出层的学习信号delta_l2 = (t - l2) * self.dsigmoid(l2)# 计算隐藏层的学习信号delta_l1 = delta_l2.dot(self.w2.T) * self.dsigmoid(l1)# 计算隐藏层的权值变化delta_w1 = lr * x.T.dot(delta_l1) / x.shape[0]# 计算输出层的权值变化delta_w2 = lr * l1.T.dot(delta_l2) / x.shape[0]# 改变权值self.w1 += delta_w1self.w2 += delta_w2# 改变偏置值self.b1 += lr * np.mean(delta_l1, axis=0)self.b2 += lr * np.mean(delta_l2, axis=0)def predict(self, x):"""模型的预测函数:param x: 测试数据的特征:return: 返回一个包含10个0-1之间数字的numpy.array对象"""l1 = self.sigmoid(np.dot(x, self.w1) + self.b1)l2 = self.sigmoid(np.dot(l1, self.w2) + self.b2)return l2# 保存训练模型def save(self, path):np.savez(path, w1=self.w1, w2=self.w2, b1=self.b1, b2=self.b2)# 加载训练模型def load(self, path):npz = np.load(path)self.w1 = npz['w1']self.w2 = npz['w2']self.b1 = npz['b1']self.b2 = npz['b2']# 输入手写数字图像,返回模型预测结果def predict_num(self, img):# 将图片转换为灰度图img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 将图片转换为二值图img = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)[1]# 将图片转换为8*8的矩阵img = cv2.resize(img, (8, 8))# 将图片转换为一维向量img = img.flatten()# 图片归一化处理img = img / 255# 预测图片的数字num = self.predict(img)# 返回预测结果return np.argmax(num)# 定义一个2层的网络模型:64-100-10
nn = NeuralNetwork([64, 100, 10])# 如果存在数据库就加载,不存在就训练
if os.path.exists(MODEL_PATH):nn.load(MODEL_PATH)
else:# 载入数据集digits = load_digits()X = digits.dataY = digits.target# 数据归一化X = (X - X.min()) / (X.max() - X.min())# 将数据拆分成训练集和测试集x_train, x_test, y_train, y_test = train_test_split(X, Y)# 将训练数据标签化为独热编码labels = LabelBinarizer().fit_transform(y_train)# 训练周期epoch = 20001# 测试周期test = 400# 用来保存测试时产生的代价函数的值loss = []# 用来保存测试过程中的准确率accuracy = []for n in range(epoch):nn.train(x_train, labels)# 每训练一定的次数后,进行一次测试if n % test == 0:# 用测试集测试模型,返回结果为独热编码的标签predictions = nn.predict(x_test)# 取返回结果最大值的索引,即为预测数据y2 = np.argmax(predictions, axis=1)# np.equal用来比较数据是否相等,相等返回True,不相等返回False# 比较的结果求平均值,即为模型的准确率acc = np.mean(np.equal(y_test, y2))# 计算代价函数cost = np.mean(np.square(y_test - y2) / 2)# 将准确率添加到列表accuracy.append(acc)# 将代价函数添加到列表loss.append(cost)print('epoch:', n, 'accuracy:', acc, 'loss:', loss)# 保存训练数据nn.save(MODEL_PATH)# 使用测试数据对模型进行测试pred = nn.predict(x_test)y_pred = np.argmax(pred, axis=1)# 查看模型预测结果与真实标签之间的报告print(classification_report(y_test, y_pred))# 查看模型预测结果与真实标签之间的混淆矩阵print(confusion_matrix(y_test, y_pred))# 训练结果可视化plt.subplot(2, 1, 1)plt.plot(range(0, epoch, test), loss)plt.ylabel('loss')plt.subplot(2, 1, 2)plt.plot(range(0, epoch, test), accuracy)plt.xlabel('epoch')plt.ylabel('accuracy')plt.show()img = cv2.imread('5.png')
print("识别的数字为:",nn.predict_num(img))
Python学习记录 搭建BP神经网络实现手写数字识别相关推荐
- BP神经网络实现手写数字识别Python实现,带GUI手写画板
BP神经网络实现手写数字识别 BP神经网络模型 用tkinter编写用于手写输入的画板 程序运行的效果截图 在B站看了一个机器学习基础的视频( 链接)后,发现到资料里面有一个用BP神经网络对手写数字进 ...
- MATLAB实现基于BP神经网络的手写数字识别+GUI界面+mnist数据集测试
文章目录 MATLAB实现基于BP神经网络的手写数字识别+GUI界面+mnist数据集测试 一.题目要求 二.完整的目录结构说明 三.Mnist数据集及数据格式转换 四.BP神经网络相关知识 4.1 ...
- 基于BP神经网络的手写数字识别
基于BP神经网络的手写数字识别 摘要 本文实现了基于MATLAB关于神经网络的手写数字识别算法的设计过程,采用神经网络中反向传播神经网络(即BP神经网络)对手写数字的识别,由MATLAB对图片进行读入 ...
- MATLAB--基于BP神经网络的手写数字识别
MATLAB–基于BP神经网络的手写数字识别 在干活的过程中整理下来的,希望对大家有帮助. 手写数字识别技术作为图像处理和模式识别中的研究热点,在大规模数据统计(如行业年检.人口普查等).票据识别.财 ...
- 基于matlab BP神经网络的手写数字识别
摘要 本文实现了基于MATLAB关于神经网络的手写数字识别算法的设计过程,采用神经网络中反向传播神经网络(即BP神经网络)对手写数字的识别,由MATLAB对图片进行读入.灰度化以及二值化等处理,通过神 ...
- 小生不才:tensorflow实战01-基于bp神经网络的手写数字识别
前言 利用搭建网络八股,使用简单的bp神经网络完成手写数字的识别. 搭建过程 导入相应的包 获取数据集,划分数据集和测试集并进行简单处理(归一化等) 对数据进行乱序处理 定义网络结构 选择网络优化器以 ...
- 深度学习笔记:07神经网络之手写数字识别的经典实现
神经网络之手写数字识别的经典实现 上一节完成了简单神经网络代码的实现,下面我们将进行最终的实现:输入一张手写图片后,网络输出该图片对应的数字.由于网络需要用0-9一共十个数字中挑选出一个,所以我们的网 ...
- BP神经网络(手写数字识别)
1实验环境 实验环境:CPU i7-3770@3.40GHz,内存8G,windows10 64位操作系统 实现语言:python 实验数据:Mnist数据集 程序使用的数据库是mnist手写数字数据 ...
- matlab实现BP神经网络minst手写数字识别
按照模式分类课本写的代码,如有错误欢迎指正! main.m %程序运行可能会需要3-5分钟的时间,请耐心等待. clear; %已对lms.mat进行随机打乱,并将Y由标量化为[1,10]矩阵形成da ...
最新文章
- 最温暖的大学,最火热的比赛
- pip源更换为清华源_kali2020更换国内的源
- 进程间通信 - 动态链接库实现
- 超详细图解!【MySQL进阶篇】MySQL事务和锁
- 从0实现三层神经网络
- js中for循环调用回调函数,一直循环最后一个
- 95-40-050-java.util.concurrent-CopyOnWriteArraySet
- 贺利坚老师汇编课程54笔记:SF符号标志SIGN FLAG
- shell 入门(一)
- 8位单片机003兼容替换意法半导体STM8S003F3P6
- 高速公路自动驾驶测试场景库
- 工具:dlf 强制删除文件或文件夹
- (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
- WEB前端 -- onfocus=quot;this.blur()quot;
- 合肥学院ACM集训队第一届暑假友谊赛 B	FYZ的求婚之旅 D	计算机科学家 F	智慧码	 题解...
- frp服务实现内网穿透SSH远程内网虚拟机
- 【开发教程3】AI语音人脸识别(会议记录仪/人脸打卡机)-CC3200简介
- CC26xx(CortexM3) IO Control
- Sharding-JDBC(一)SpringBoot集成
- 微信机器人的构建与使用
热门文章
- c++实现霍夫曼编码
- dell服务器t310显示ctrle,L375E-S0 PS-5371-1D-LF 375W T128K T122K T310 DELL服务器电源
- 经纬能源:年化预期收益率4.5%怎样算利息?本来核算方法是这样的
- 基于JAVA线上远程教学及自主学平台的设计与实现计算机毕业设计源码+系统+mysql数据库+lw文档+部署
- Smarty教程[6]
- “六一”儿童节就要到了,赶快为喜欢的ta下场星星雨吧~
- 一、FOSS许可相关的法律规范和司法案例
- AMZ亚马逊开发者最新注册攻略
- lolSix周年活动页面
- 思考游戏王决斗链接中抽卡概率问题