CV学习笔记:BP网络实现手写数字识别
BP算法的基本思想是,学习过程由信号的正向传播与误差的反向传播两个过程组成。正向传播时,输入样本从输入层传入,经各隐藏层逐层处理后,传向输出层。若输出层的实际输出与期望的输出不符,则转入误差的反向传播阶段。误差反传是将输出误差以某种形式通过隐藏层向输入层逐层反传,并将误差分摊给各层的所有单元,从而获得各层单元的误差信号,此误差信号即作为修正各单元权值的依据。这种信号正向传播与误差反向传播的各层权值调整过程,是周而复始地进行的。权值不断调整的过程,也就是网络的学习训练过程。此过程一直进行到网络输出的误差减少到可接受的程度,或进行到预先设定的学习次数为止。
先把BP算法的公式贴出来,后面代码中会用到。
在pycharm新建BP项目——新建Minist.py文件
1.载入数据显示手写数字图片
import numpy as np from sklearn.datasets import load_digits #从sklearn数据集中加载手写数字图片 from sklearn.preprocessing import LabelBinarizer #对带有标签图片进行处理 from sklearn.model_selection import train_test_split #分割训练集和测试集 import matplotlib.pyplot as plt #画图工具 #载入数据(手写数字图片) digits=load_digits() print(digits.images.shape)#打印数据集的形状 #显示手写数字图片 plt.imshow(digits.images[0],cmap='gray') plt.show() plt.imshow(digits.images[23],cmap='gray') plt.show(
运行结果:
可以看到数据集中有1797个样本,每张手写数字图片大小为8*8,64个像素;并且显示了第0个和第23个样本的标签——0、3。
2.查看样本数据
#读入样本集的数据 X=digits.data #读入样本集的标签 y=digits.target print(X.shape) print(y.shape) print(X[:3])#打印样本集中前3个样本的数据0-2 print(y[:4])#打印样本集中前4个样本的标签0-
运行结果:
可以看到,样本有多少标签就有多少,前3个样本中的64个像素值都被打印出来了以及前4个样本的标签值:0、1、2、3
3.建立BP算法的神经网络训练模型
#定义一个神经网络,网络结构——输入层:64个神经元;隐藏层:100个;输出层:10个神经元(10个输出值) #定义输入层到隐藏层的权值矩阵 V=np.random.random((64,100))*2-1#64*100;random随机生成数字0-1;*2-1:从-1~1之间 #定义隐藏层到输出层的权值矩阵 W=np.random.random((100,10))*2-1#size:100*10 #数据切分 #一般将样本数据划分成:1/4为测试集(用来测试模型效果),3/4为训练集 X_train,X_test,y_train,y_test=train_test_split(X,y) #标签二值化 (这步操作是把某个具体标签值转换成其在所有标签中的位置,方便输出) #0—>1000000000 #3->0010000000 #9->0000000001 labels_train=LabelBinarizer().fit_transform(y_train)#把原本的标签训练集二值化 print(y_train[:5]) print(labels_train[:5]) #定义激活函数 def sigmod(x): return 1/(1+np.exp(-x)) #定义激活函数的导数 def dsigmod(x): return x*(1-x) #定义训练模型 def train(X,y,steps,lr=0.11):#训练集、标签集、训练次数、学习率 global V,W #调用全局变量 for n in range(steps+1): #随机选取一个样本中的数据 i=np.random.randint(X.shape[0])#取第一维数据,即训练样本中的第一个 x=X[i]#取样本中的具体数值(64个) x=np.atleast_2d(x)#把一维数据表转成2维,方便与权值矩阵做乘法 #BP算法公式 #计算隐藏层的输出 L1=sigmod(np.dot(x,V)) #计算输出层的输出 L2=sigmod(np.dot(L1,W)) #计算L2_delta、 L1_delta(通多这两个值来更新权重) L2_delta=(y[i]-L2)*dsigmod(L2)#对应公式:输出层学习信号 L1_delta=L2_delta.dot(W.T)*dsigmod(L1)#对应公式:第l层学习信号 #更新权值 W+=lr*L1.T.dot(L2_delta) V+=lr*x.T.dot(L1_delta) #每训练1000次可以预测一次准确率 if n%1000==0: output=predict(X_test)#把测试集传入测试模型 predictions=np.argmax(output,axis=1)#获取最大值的位置,实际上得到标签值 # 对比网络预测值和真实的标签值是否相等,相等为TURE(1),不等为false(0),求平均,即为准确率 acc=np.mean(np.equal(predictions,y_test)) print("steps:",n,"accuracy:",acc) #该函数输入测试集,输出标签值 def predict(x): # 计算隐藏层的输出 L1 = sigmod(np.dot(x, V)) # 计算输出层的输出 L2 = sigmod(np.dot(L1, W)) return L2 train(X_train,labels_train,20000)#调用BP算法训练模
运算结果:
[4 6 0 2 8] [[0 0 0 0 1 0 0 0 0 0] [0 0 0 0 0 0 1 0 0 0] [1 0 0 0 0 0 0 0 0 0] [0 0 1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 1 0]] steps: 0 accuracy: 0.15333333333333332 steps: 1000 accuracy: 0.7666666666666667 steps: 2000 accuracy: 0.8511111111111112 steps: 3000 accuracy: 0.8933333333333333 steps: 4000 accuracy: 0.9066666666666666 steps: 5000 accuracy: 0.9244444444444444 steps: 6000 accuracy: 0.9311111111111111 steps: 7000 accuracy: 0.9422222222222222 steps: 8000 accuracy: 0.9311111111111111 steps: 9000 accuracy: 0.9555555555555556 steps: 10000 accuracy: 0.9533333333333334 steps: 11000 accuracy: 0.9466666666666667 steps: 12000 accuracy: 0.9488888888888889 steps: 13000 accuracy: 0.9555555555555556 steps: 14000 accuracy: 0.96 steps: 15000 accuracy: 0.9511111111111111 steps: 16000 accuracy: 0.9555555555555556 steps: 17000 accuracy: 0.9755555555555555 steps: 18000 accuracy: 0.9777777777777777 steps: 19000 accuracy: 0.9733333333333334 steps: 20000 accuracy: 0.9711111111111111 Process finished with exit code
可以看到通过BP网络训练20000次后,手写数字识别准确率越来越高,说明这个训练模型效果好,能达到预期的目的。