BP网络-sklearn实现手写数字识别

  • 环境介绍

语言:Py,版本3.6

环境:Anaconda3 (64-bit),

编译器:Spyder,Jupyter Notebook等

实现功能:使用BP神经网络实现数字识别

神经网络搭建的思想

一个神经网络的搭建,需要满足三个条件。

  • 输入和输出
  • 权重(w)和阈值(b
  • 多层感知器的结构

神经网络的运作过程如下。

  1. 确定输入和输出
  2. 找到一种或多种算法,可以从输入得到输出
  3. 找到一组已知答案的数据集,用来训练模型,估算wb
  4. 一旦新的数据产生,输入模型,就可以得到结果,同时对wb进行校正

前期准备知识点

1、载入数据集

from sklearn.datasets import load_digits
import pylab as pl
digits = load_digits()#载入数据集
print(digits.data.shape)
#数据解释,图片是8*8的被转换成一行64.共有1797个图片
#输出结果:(1797, 64)
pl.gray()#灰度化图片
pl.matshow(digits.images[7])
pl.show()

2、数据归一化处理

这里使用的是线性函数归一化处理。

其他归一化处理方法:https://blog.csdn.net/uestc_c2_403/article/details/75804617

为什么归一化:

  1. 数据为什么要归一化处理?当数据集的数值过大,即便乘以较小的权重后仍然还是一个很大的数时,当代入sigmoid激活函数中,激活函数的输出就趋近于1,不利于学习
  2. https://zhuanlan.zhihu.com/p/27627299
#这两个方法使用的是同一个公式,写法不一样
import numpy as np
X = np.array([[1,0,5],
              [3,0,1],
              [4,1,0],
              [5,1,1]])

#归一化方法1
X -= X.min()
X= X/X.max()

#归一化方法2
Max=np.max(X)
Min=np.min(X)
def MaxMinNormalization(x,Max,Min):
	x = (x - Min) / (Max - Min);
	return x;
s=MaxMinNormalization(X,Max,Min)

3、切分数据,与标签二值化

  • 分割数据1/4为测试数据,3/4为训练数据
  • sklearn中直接一条语句就可以切分数据了:将数据项、标签项切分出来,3/4做训练集,剩下的1/4做测试集。
  • 为什么要标签二值化?因为我们存入的标签是0,1,2,,,9这十个数,而计算机的识别都是0-1字符串,所以满足计算机识别分类,就需要进行标签二值化。
#实现数据二值化和数据切分
# -*- coding: utf-8 -*-
"""
Created on Sat Aug  4 17:29:59 2018

@author: 高硕
"""

import numpy as np
from sklearn.cross_validation import train_test_split #切割数据,交叉验证法
from sklearn.preprocessing import LabelBinarizer#标签二值化
#标签二值化
a = np.array([0,1,2,3,4,5,6,7,8,9])

b = np.array([0,1,2,3,4,5,6,7,8,2])
labels_a = LabelBinarizer().fit_transform(a)#标签二值化     0,8,6   0->1000000000  3->0001000000
labels_b = LabelBinarizer().fit_transform(b)#标签二值化     0,8,6   0->1000000000  3->0001000000
print(a)
print(b)

#切割数据
X = np.array([[1,0,5],
              [2,0,1],
              [3,1,0],
              [4,1,1],
              [5,9,5],
              [6,0,1],
              [7,3,0],
              [8,2,1]])

Y = np.array([1,2,3,4,5,6,7,8])
X_train,X_test,y_train,y_test = train_test_split(X,Y)



  • 二值化标签结果:

  

  • 数据分割结果

4、Python 生成 -1~1 之间的随机数矩阵

  • 使用函数 np.random.random(),由于 np.random.random()  默认生成 0~1 之间的小数,因此需要转换一下

  •  如生成 3*3 的 -1~1 之间的随机数矩阵,-1 + 2*np.random.random((3,3))

    import numpy as np
    #生成-1到1之间的随机数,生成的矩阵为3*4
    X = np.random.random((3,4))*2-1 
    print(X)
    

  • layers[0]+1=65

  • import numpy as np
    def test(layers):#(64,100,10)
            #权值的初始化,范围-1到1
            V = np.random.random((layers[0]+1,layers[1]+1))*2-1
            W = np.random.random((layers[1]+1,layers[2]))*2-1
        
            return V,W,layers
    M,N,K= test([64,100,10])
    

    结果:

  •  

5、添加一列,作为偏置

  • 看懂如何加的,如何变化的
import numpy as np

def test(X):
        #添加偏置
        temp = np.ones([X.shape[0],X.shape[1]+1])#行不变,列多一个
        temp[:,0:-1] = X#
        X = temp
    
        return X
X = np.array([[1,0,0],
              [3,0,1],
              [4,1,0],
              [5,1,1]])
X_new= test(X)#创建网络

结果:

6、X = np.atleast_2d(X)

这一方法可以保证所有的输入X至少是二维数组,如果是一维数组则会转化为一个二位的1*len(X)的数组。如:

b = [1,2,3]np.atleast_2d(b)输出结果为array([[1, 2, 3]])

import numpy as np
b = [1,2,3]
c=np.atleast_2d(b)

全部代码

# -*- coding: utf-8 -*-
"""
Created on Sat Aug  4 16:58:11 2018

@author: 高硕
"""
import numpy as np
from sklearn.datasets import load_digits
from sklearn.preprocessing import LabelBinarizer#标签二值化
from sklearn.cross_validation import train_test_split #切割数据,交叉验证法

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

def dsigmoid(x):
    return x*(1-x)

class NeuralNetwork:
    def __init__(self,layers):#(64,100,10)
        #权重的初始化,范围-1到1:+1的一列是偏置值
        self.V = np.random.random((layers[0]+1,layers[1]+1))*2-1
        self.W = np.random.random((layers[1]+1,layers[2]))*2-1
        
    def train(self,X,y,lr=0.11,epochs=10000):
        #添加偏置
        #添加偏置值:最后一列全是1
        temp = np.ones([X.shape[0],X.shape[1]+1])#行不变,列多一个
        temp[:,0:-1] = X#
        X = temp
        #分批次训练思想。10000个分10次,一次1000
        #这里的话是随机选取一个数据
        for n in range(epochs+1):
            #在训练集中随机选取一行(一个数据):randint()在范围内随机生成一个int类型
            i = np.random.randint(X.shape[0]) #随机选取一个数据(训练集里的)
            x = [X[i]]
            #转为二维数据:由一维一行转为二维一行
            x = np.atleast_2d(x)#转为2维数据
            
             # L1:输入层传递给隐藏层的值;输入层64个节点,隐藏层100个节点
            # L2:隐藏层传递到输出层的值;输出层10个节点
            L1 = sigmoid(np.dot(x,self.V))#隐层输出
            L2 = sigmoid(np.dot(L1,self.W))#输出层输出
            
            # L2_delta:输出层对隐藏层的误差改变量
            # L1_delta:隐藏层对输入层的误差改变量
            L2_delta = (y[i]-L2)*dsigmoid(L2)
            L1_delta= L2_delta.dot(self.W.T)*dsigmoid(L1)
            
           # 计算改变后的新权重
            self.W += lr*L1.T.dot(L2_delta)
            self.V += lr*x.T.dot(L1_delta)
            
            #每训练1000次预测,输出一次准确率
            if n%1000==0:
                predictions = []
                for j in range(X_test.shape[0]):
                    #获取预测结果:返回与十个标签值逼近的距离,数值最大的选为本次的预测值
                    o = self.predict(X_test[j])
                   #将最大的数值所对应的标签返回
                    predictions.append(np.argmax(o))#获取预测结果
                accuracy = np.mean(np.equal(predictions,y_test))
                #np.equal():相同返回true,不同返回false
                print('迭代次数:',n,'准确率:',accuracy)
        
    def predict(self,x):
        #添加偏置
        # 添加偏置值:最后一列全是1
        temp = np.ones(x.shape[0]+1)
        temp[0:-1] = x
        x = temp
        # 转为二维数据:由一维一行转为二维一行
        x = np.atleast_2d(x)#转为2维数据
        
        # L1:输入层传递给隐藏层的值;输入层64个节点,隐藏层100个节点
        # L2:隐藏层传递到输出层的值;输出层10个节点
        L1 = sigmoid(np.dot(x,self.V))#隐层输出
        L2 = sigmoid(np.dot(L1,self.W))#输出层输出
        #print("l2",L2)
        return L2

digits = load_digits()#载入数据
X = digits.data#数据
y = digits.target#标签
#输入数据归一化
X -= X.min()
X /= X.max()

nm = NeuralNetwork([64,100,10])#创建网络

X_train,X_test,y_train,y_test = train_test_split(X,y) #分割数据1/4为测试数据,3/4为训练数据

labels_train = LabelBinarizer().fit_transform(y_train)#标签二值化     0,8,6   0->1000000000  3->0001000000
labels_test = LabelBinarizer().fit_transform(y_test)#标签二值化

print('start')

nm.train(X_train,labels_train,epochs=20000)

print('end')

结果:

附:

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
BP神经网络是一种常用的人工神经网络,可以用于手写数字识别。下面是使用BP神经网络进行手写数字识别的步骤: 1.准备数据集:手写数字识别需要大量的标记数据集,可以使用MNIST数据集或自己制作数据集。 2.数据预处理:将数据集进行预处理,包括图像增强、降噪、二值化等操作。 3.构建BP神经网络BP神经网络包括输入层、隐藏层和输出层,其中输入层和输出层的节点数分别为数据集的特征数和类别数,隐藏层的节点数可以根据需要进行调整。 4.训练BP神经网络:使用训练集对BP神经网络进行训练,可以使用反向传播算法或其他优化算法进行训练。 5.测试BP神经网络:使用测试集对BP神经网络进行测试,计算准确率和召回率等指标。 6.优化BP神经网络:根据测试结果对BP神经网络进行优化,可以调整网络结构、学习率、迭代次数等参数。 以下是使用Python实现BP神经网络进行手写数字识别的代码: ```python import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import load_digits from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score from neural_network import NeuralNetwork # 加载数据集 digits = load_digits() X, y = digits.data, digits.target # 数据预处理 X = X / 16.0 y_onehot = np.zeros((y.shape[0], 10)) for i in range(y.shape[0]): y_onehot[i][y[i]] = 1 # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y_onehot, test_size=0.2, random_state=42) # 构建BP神经网络 nn = NeuralNetwork([64, 30, 10], 'tanh') # 训练BP神经网络 nn.fit(X_train, y_train, epochs=1000, learning_rate=0.1) # 测试BP神经网络 y_pred = nn.predict(X_test) y_pred = np.argmax(y_pred, axis=1) y_test = np.argmax(y_test, axis=1) accuracy = accuracy_score(y_test, y_pred) print('Accuracy:', accuracy) # 显示部分测试结果 fig, axes = plt.subplots(4, 4, figsize=(8, 8)) for i, ax in enumerate(axes.flat): ax.imshow(X_test[i].reshape(8, 8), cmap='binary') ax.set(title = f"Real Number is {y_test[i]}\nPredict Number is {y_pred[i]}"); plt.show() ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值