bp神经网络实现手写数字识别,数据集:sklearn自带的digits.data,由1797个8x8像素矩阵组成,digits.target里为其标签,即0-9
BP网络训练参数
训练次数 | 20000 |
---|---|
神经网络层数 | 64-100-10 |
激活函数 | sigmoid |
输入数据(个数,维度) | 1,8x8 |
输出数据(个数,维度) | 1,8x8 |
训练集(个数,维度) | 1348,8x8 |
测试集(个数,维度) | 449,8x8 |
整体步骤如下:
1.加载手写数字数据集,分别将灰度信息和标签赋值给变量X和y。
2.定义了一个有64个输入节点、100个隐层节点和10个输出节点的神经网络,即V为64100的矩阵,W为10010的矩阵。
3.将原始数据集切分为训练集和测试集,然后对训练集的标签进行二值化。
4.定义了sigmoid激活函数及其导数函数dsigmoid。
5.定义了函数train(),通过不断更新权值(W和V),使用BP算法进行模型训练,并每训练1000次预测一次准确率。
6.定义了函数predict(),用于对测试集进行预测。
7.定义了函数show_predict(),随机选择一个测试数据,对其进行预测并展示这张图片。
代码整体过程比较简单,主要难点在于理解BP算法的原理和公式。其中,sigmoid函数作为常用的激活函数,主要用于将线性变换的结果压缩到0~1之间,形成非线性的特征表示,使得神经网络可以拟合更为复杂的函数关系。而BP算法则是通过计算误差信号和梯度信息,对权值进行不断更新和调整,从而提高模型的准确率。
import numpy as np
from sklearn.datasets import load_digits
from sklearn.preprocessing import LabelBinarizer
from sklearn.model_selection import train_test_split
#from sklearn.model_selection import train_test_split
import matplotlib
import matplotlib.pyplot as plt
digits = load_digits()
# 数据 图片的灰度信息存在digits.data中
X = digits.data
# 标签
y = digits.target
# 定义神经网络64-100-10,64像素即64通道输入,隐藏层稍多于输入层,输出层为0-9,所以是10个
# 输入层到隐藏层v,隐藏层到输出层w
V = np.random.random((64, 100)) * 2 - 1
W = np.random.random((100, 10)) * 2 - 1
# 数据切分 train_test_split(X,y)可以把输入数据和标签数据切分为训练集和测试集
# default: 1/4测试集,3/4训练集
X_train, X_test, y_train, y_test = train_test_split(X, y)
# 标签二值化
# 0->1000000000
# 3->0010000000
# 9->0000000001
label_train = LabelBinarizer().fit_transform(y_train)
# 激活函数
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def dsigmoid(x):
s = 1 / (1 + np.exp(-x))
return s * (1 - s)
# 训练模型
def train(X, y, Steps=10000, lr=0.12):
global W, V
for n in range(Steps):
# 随机选取一个数据
i = np.random.randint(X.shape[0])
x = X[i]
# 把数据变为2维数据,一维数据不能矩阵乘法
x = np.atleast_2d(x)
# BP算法公式
L1 = sigmoid(np.dot(x, V))
L2 = sigmoid(np.dot(L1, W))
# 学习信号
L2_delta = (y[i] - L2) * dsigmoid(np.dot(L1, W))
L1_delta = np.dot(L2_delta, W.T) * dsigmoid(np.dot(x, V))
# 更新权值
W += lr * np.dot(L1.T, L2_delta)
V += lr * np.dot(x.T, L1_delta)
# 每训练1000次预测一次准确率
if n % 1000 == 0:
output = predict(X_test)
# predictions:最大值所在位置(0-9)->预测的标签值
predictions = np.argmax(output, axis=1)
acc = np.mean(np.equal(predictions, y_test))
print("steps:", n, "accuracy:", acc)
def predict(x):
L1 = sigmoid(np.dot(x, V))
L2 = sigmoid(np.dot(L1, W))
return L2
def show_predict(test_index):
result = predict(X_test[test_index])
print("预测值:", np.argmax(result), "实际值:", y_test[test_index])
plt.imshow(X_test[test_index].reshape(8, 8))
plt.show()
train(X_train, label_train, 20000)
steps: 0 accuracy: 0.19111111111111112
steps: 1000 accuracy: 0.5355555555555556
steps: 2000 accuracy: 0.6911111111111111
steps: 3000 accuracy: 0.7244444444444444
steps: 4000 accuracy: 0.7933333333333333
steps: 5000 accuracy: 0.8288888888888889
steps: 6000 accuracy: 0.9044444444444445
steps: 7000 accuracy: 0.9177777777777778
steps: 8000 accuracy: 0.8977777777777778
steps: 9000 accuracy: 0.9377777777777778
steps: 10000 accuracy: 0.94
steps: 11000 accuracy: 0.9555555555555556
steps: 12000 accuracy: 0.9355555555555556
steps: 13000 accuracy: 0.9577777777777777
steps: 14000 accuracy: 0.9622222222222222
steps: 15000 accuracy: 0.9577777777777777
steps: 16000 accuracy: 0.96
steps: 17000 accuracy: 0.9644444444444444
steps: 18000 accuracy: 0.9355555555555556
steps: 19000 accuracy: 0.9466666666666667
print(X.shape)#%digits.data是8x8的矩阵,共有1797个,即维度8x8
print(y.shape)
(1797, 64)
(1797,)
some_digit = X_test[3]
print(some_digit)#输出测试的图片8x8矩阵
print(y_test[3])#输出测试图片的标签,即实际值
show_predict(3)#调用预测绘图函数
[ 0. 0. 0. 0. 14. 13. 1. 0. 0. 0. 0. 5. 16. 16. 2. 0. 0. 0.
0. 14. 16. 12. 0. 0. 0. 1. 10. 16. 16. 12. 0. 0. 0. 3. 12. 14.
16. 9. 0. 0. 0. 0. 0. 5. 16. 15. 0. 0. 0. 0. 0. 4. 16. 14.
0. 0. 0. 0. 0. 1. 13. 16. 1. 0.]
1
预测值: 1 实际值: 1