本文将用Numpy实现简单BP神经网络完成对手写数字图片的识别,数据集为42000张带标签的28x28像素手写数字图像。在计算机完成对手写数字图片的识别过程中,代表图片的28x28=764个像素的特征数据值将会被作为神经网络的输入,经过网络的正向传播,得到可以粗略作为0~9每个数字的概率的输出(输出层第一个神经元节点的输出看成是图片数字是0的概率,其余9个神经元节点以此类推),取概率最大的数字即为识别结果。神经网络的输出神经元节点有10个,假设待识别数字为1,就可以定义label为[0,1,0,0,0,0,0,0,0,0],将网络的10个节点的输出组成的向量(预测值)与label(真实值)进行对比,定义均方误差损失E,根据梯度下降法完成对网络权值和阈值的参数更新,即对网络的训练。在对模型的评估中,简单地使用测试样本中预测正确的样本数占全部测试样本总数的比例作为模型的识别正确率。

网络隐层的层数以及神经元的个数是可以人为设置的,但需注意合理设置。文中设置的隐层有两层,每层神经元的节点数都设置为50,在对数据集进行训练集、测试集约为1:1划分,训练轮数为5轮的情况下,达到了92%以上不错的正确预测率。需要提醒的是,训练轮数过大以及隐层节点数设置过大,极有可能发生过拟合的情况,导致正确率不如人意。
       数据集地址:
       链接:https://pan.baidu.com/s/1XzexzXGYhUdFpM4UaIb3yA
       提取码:9wjm

实现代码如下:

import numpy as np
import csv
from tqdm import trange

def sigmoid(x):
return 1.0 / (1.0 + np.exp(-x))

def sigmoid_derivative(x):
return sigmoid(x) * (1 - sigmoid(x))

class Net:

def __init__(self, layers):
self.active = sigmoid # 激活函数
self.active_d = sigmoid_derivative # 激活函数的求导
self.weights = [] # 权值参数
self.bias = [] # 阈值参数
for i in range(1, len(layers)): # 参数初始化
self.weights.append(np.random.randn(layers[i - 1], layers[i]))
self.bias.append(np.random.randn(layers[i]))

def core(self, x, label, learning_rate):
y = [x] # 保存每层激活后的输出值

# 正向传播
for i in range(len(self.weights)):
y.append(self.active(np.dot(y[-1], self.weights[i]) + self.bias[i]))

# 反向传播
e = y[-1] - label
deltas = [e * y[-1] * (1 - y[-1])] # 输出层Delta值
# 各隐藏层Delta值
for i in range(1, len(self.weights)):
deltas.append(np.dot(deltas[-1], self.weights[-i].T) * y[-i - 1] * (1 - y[-i - 1]))
# 误差项倒置
deltas.reverse()
# 更新参数w和b
for i in range(len(self.weights)):
y_2d = np.atleast_2d(y[i])
deltas_2d = np.atleast_2d(deltas[i])
self.weights[i] -= learning_rate * np.dot(y_2d.T, deltas_2d)
self.bias[i] -= learning_rate * deltas[i]

def predict(self, x):

# 正向传播预测输出值
y = x
for i in range(len(self.weights)):
y = self.active(np.dot(y, self.weights[i]) + self.bias[i])
_ = [str(round((i / y.sum()) * 100, 2)) + "%" for i in y] # 将输出结果以概率的形式展现
out = list(y)
result = out.index(max(out))
return result, _

if __name__ == '__main__':

Net = Net([784, 50, 50, 10])
# 读取数据
file_name = "data/train.csv" # 数据集为42000张带标签的28x28手写数字图像
x_train = [] # 训练集样本数据特征
y_train = [] # 训练集样本标签
'''
测试集用来测试模型质量必不可少。
验证集用来调节超参数,如神经网络层数,各层神经节点数、学习率等人为设置而不是模型通过学习得到的参数,可省略,仅用训练集即可
'''
x_test = [] # 测试集样本数据特征
y_test = [] # 测试集样本数据标签
with open(file_name, 'r') as f:
reader = csv.reader(f)
header_row = next(reader)
for row in reader:
data = np.array(row[1:], dtype=np.float_)
if np.random.random() < 0.5: # 划分数据集 训练集:测试集 ≈ 1:1
x_train.append(data / ((data ** 2).sum() ** 0.5)) # 每个样本对应的784个特征数值归一化
y_train.append(int(row[0]))
else:
x_test.append(data / ((data ** 2).sum() ** 0.5))
y_test.append(int(row[0]))

print("训练样本数:{},测试样本数:{}".format(len(y_train), len(y_test)))

# 训练
learning_rate = 0.5 # 初始学习率
epochs = 5 # 训练轮数
for i in trange(len(y_train) * epochs):
if (i + 1) % len(y_test) == 0:
learning_rate *= 0.5 # 每训练一轮 学习率减半
label = np.zeros(10)
label[y_train[i % len(y_train)]] = 1 # 设置label
Net.core(x_train[i % len(y_train)], label, learning_rate) # 更新网络参数

# 预测
count = 0
for i in trange(len(y_test)):
print("-------第{}个测试样本-----------".format(i + 1))
predict, _ = Net.predict(x_test[i])
print("预测值:{},真实值:{}".format(predict, y_test[i]))
if predict == y_test[i]:
count += 1
print("正确率:{}".format(count / len(y_test)))

运行结果:

Numpy实现简单BP神经网络识别手写数字的更多相关文章

  1. 用BP人工神经网络识别手写数字

    http://wenku.baidu.com/link?url=HQ-5tZCXBQ3uwPZQECHkMCtursKIpglboBHq416N-q2WZupkNNH3Gv4vtEHyPULezDb5 ...

  2. 利用c++编写bp神经网络实现手写数字识别详解

    利用c++编写bp神经网络实现手写数字识别 写在前面 从大一入学开始,本菜菜就一直想学习一下神经网络算法,但由于时间和资源所限,一直未展开比较透彻的学习.大二下人工智能课的修习,给了我一个学习的契机. ...

  3. BP神经网络的手写数字识别

    BP神经网络的手写数字识别 ANN 人工神经网络算法在实践中往往给人难以琢磨的印象,有句老话叫“出来混总是要还的”,大概是由于具有很强的非线性模拟和处理能力,因此作为代价上帝让它“黑盒”化了.作为一种 ...

  4. 【机器学习】BP神经网络实现手写数字识别

    最近用python写了一个实现手写数字识别的BP神经网络,BP的推导到处都是,但是一动手才知道,会理论推导跟实现它是两回事.关于BP神经网络的实现网上有一些代码,可惜或多或少都有各种问题,在下手写了一 ...

  5. BP神经网络(手写数字识别)

    1实验环境 实验环境:CPU i7-3770@3.40GHz,内存8G,windows10 64位操作系统 实现语言:python 实验数据:Mnist数据集 程序使用的数据库是mnist手写数字数据 ...

  6. PyTorch基础——使用卷积神经网络识别手写数字

    一.介绍 实验内容 内容包括用 PyTorch 来实现一个卷积神经网络,从而实现手写数字识别任务. 除此之外,还对卷积神经网络的卷积核.特征图等进行了分析,引出了过滤器的概念,并简单示了卷积神经网络的 ...

  7. 使用TensorFlow的卷积神经网络识别手写数字(2)-训练篇

    import numpy as np import tensorflow as tf import matplotlib import matplotlib.pyplot as plt import ...

  8. 使用TensorFlow的卷积神经网络识别手写数字(3)-识别篇

    from PIL import Image import numpy as np import tensorflow as tf import time bShowAccuracy = True # ...

  9. 使用TensorFlow的卷积神经网络识别手写数字(1)-预处理篇

    功能: 将文件夹下的20*20像素黑白图片,根据重心位置绘制到28*28图片上,然后保存.经过预处理的图片有利于数字的准确识别.参见MNIST对图片的要求. 此处可下载已处理好的图片: https:/ ...

随机推荐

  1. SWPUCTF_2019_p1KkHeap(tcache_entry)

    花了半天的时间去理解吃透这道题目,也参考了大佬的wp (1条消息) [pwn]SWPUCTF_2019_p1KkHeap_Nothing-CSDN博客. (1条消息) swpuctf2019 p1Kk ...

  2. LuoguB2045 晶晶赴约会 题解

    Content 贝贝邀请晶晶下个星期 \(x\)(如果 \(x=7\) 表示星期日)一起去看展览,但是晶晶下个星期 \(1,3,5\) 都有课.请你判断晶晶能否同意贝贝的请求. 数据范围:\(x\in ...

  3. k8s daemonset controller源码分析

    daemonset controller分析 daemonset controller简介 daemonset controller是kube-controller-manager组件中众多控制器中的 ...

  4. RPA账户和密码管理方案

    如何将登录业务系统的账户和密码"更好的,更合适"地交给RPA? 相信很多小伙伴们在做RPA的时候, 都会或多或少的遇到类似的问题. 正常情况下IT管理人员都会给真实的业务人员分配业 ...

  5. nim_duilib(7)之TreeView

    introduction 更多控件用法,请参考 here 和 源码. 本文的代码基于这里 xml文件添加代码 基于上一篇, 继续向basic.xml中添加下面关于TreeView的代码. xml完整源 ...

  6. 【LeetCode】329. Longest Increasing Path in a Matrix 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址: https://leetcode.com/problems/longest- ...

  7. 【LeetCode】40. Combination Sum II 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 方法一:DFS 方法二:回溯法 日期 题目地址:ht ...

  8. 1686 第K大区间

    1686 第K大区间 时间限制:1 秒 空间限制:131072 KB   定义一个区间的值为其众数出现的次数.现给出n个数,求将所有区间的值排序后,第K大的值为多少. 众数(统计学/数学名词)_百度百 ...

  9. idea使用教程-Module的概念和使用

    一.IDEA页面展示 [1]项目下内容: ➢工程下的src类似于Eclipse下的src目录,用于存放代码.. ➢工程下的.idea 和TestProject.iml文件都是IDEA工程特有的.类似于 ...

  10. Capstone CS5268DEMOBOARD原理图|TYPEC转HDMI+VGA+PD3.0+USB3.0扩展坞方案

    Capstone CS5268DEMOBOARD原理图|TYPEC转HDMI+VGA+PD3.0+USB3.0四合一设计参考 CS5268 是typec转HDMI+VGA+pd3.0+U3四合一拓展坞 ...