本文将用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. python函数概念

    函数介绍 函数就类似与一个工具,作用就是在有需求时可以直接使用. 函数作用 1.精简代码,不需要重复写代码. 2.提高代码兼容性 3.提供返回值 函数语法结构 def 函数名(参数1, 参数2): & ...

  2. ciscn_2019_n_8 1

    拿到题目老样子先判断是多少位的程序 可以看到是32位的程序,然后再查看开启的保护 然后将程序放入ida进行汇编 先shift+f12查看程序是否有system和binsh 可以看到有system和bi ...

  3. 36、有效的数独 | 算法(leetode,附思维导图 + 全部解法)300题

    零 标题:算法(leetode,附思维导图 + 全部解法)300题之(36)有效的数独 前言 1)码农三少 ,一个致力于 编写极简.但齐全题解(算法) 的博主. 2)文末附赠 价值上百美刀 资料. 一 ...

  4. 文本处理的命令,三剑客之sed

    文本处理的命令 1.sort命令 "用于将文件内容加以排序" 参数: -n :按照数值的大小排序 -r :以相反的顺序来排序 -k :以某列进行排序 -t :指定分隔符,默认是以空 ...

  5. python3 5月26日 time模块常用时间转换 &datetime()模块学习 random()

    import time  获取当前时间: 指定字符串格式:time.strftime("%Y-%m-%d %H:%M:%S") 当前时间戳:time.time() 当前时间元组格式 ...

  6. JAVA中SpringMVC获取bean方法,在工具类(utils)注入service

    有时候我们会出现无法用注解 @Autowired 注入bean的情况,这个时候可以 通过contextLoader获取 WebApplicationContext ctx = ContextLoade ...

  7. c++之别让异常逃离析构函数

    关于 本文代码演示环境: VS2017. 代码写的够不规范,目的是为了缩短文章篇幅. 本文主要是为了加深印象,写了好多次的代码,还是忘记了这茬.... 之前上传到github的代码会慢慢改过来. 本文 ...

  8. 【LeetCode】379. Design Phone Directory 解题报告 (C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 数组 日期 题目地址:https://leetcode ...

  9. Array and Operations

    A. Array and Operations Time Limit: 1000ms Memory Limit: 262144KB 64-bit integer IO format: %I64d    ...

  10. 向setup.py里添加自定义command

    向setup.py里添加自定义command 参考这里 继承distutils.cmd.Command类: class CCleanCommand(distutils.cmd.Command): &q ...