学习内容:
①BP神经网络;
②全连接神经网络(DNN);
③sklearn框架;
④精度P、召回率R、准确度F1
神经网络推导过程
代码实现-手写字识别
import numpy as np
# load_digits 为sklearn自带数据集的手写字数据库
from sklearn.datasets import load_digits
# LabelBinarizer 为sklearn自带的预处理部分-表示二值化处理正例0;负例1
from sklearn.preprocessing import LabelBinarizer
# train_test_split是sklearn中模型选择用于划分数据集,即将原始数据集划分成测试集和训练集两部分的函数。
from sklearn.model_selection import train_test_split
# classification_report是sklearn检验机器学习模型效果的定量指标的模型分类评估
from sklearn.metrics import classification_report
import matplotlib.pyplot as plt
# 载入数据
digits = load_digits()
# 显示图片,在此数据集是一个1797 * 8 * 8 的三维矩阵,即有1797 张 8 * 8 的数字图片组成
# 三维数组,x.shape[0]代表包含二维数组的个数,x.shape[1]表示二维数组的行数,x.shape[2]表示二维数组的列数。
# min(digits.images.shape[0], 3)最终在所有的图片中选择了三张图片作为展示,以防展示图片个数大于数据集中图片个数
for i in range(min(digits.images.shape[0], 3)):
# 利用matplotlib包对图片进行绘制,绘制成功后,返回一个matplotlib类型的数据,cmap选择色度为黑白
plt.imshow(digits.images[i], cmap='gray')
plt.show()
# 数据
X = digits.data
# 标签(数据集本身已经提供)
y = digits.target
# 定义一个神经网络,结构,64-100-10
# 定义输入层到隐藏层之间的权值矩阵
# np.random.random((64, 100))为生成64行100列的0-1之间的浮点数
V = np.random.random((64, 100)) * 2 - 1
# 定义隐藏层到输出层之间的权值矩阵生成100行10列的0-1之间的浮点数
W = np.random.random((100, 10)) * 2 - 1
# 数据切分
# 1/4为测试集,3/4为训练集,train_test_split(X, y,test_size )test_size 默认是0.75
X_train, X_test, y_train, y_test = train_test_split(X, y)
# 标签二值化
# fit_transform()函数:直接根据label本身有多少类,然后使用独热编码,把label二进制化。
# 0 -> 1000000000
# 3 -> 0001000000
# 9 -> 0000000001
labels_train = LabelBinarizer().fit_transform(y_train)
# 激活函数
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# 激活函数的导数
def dsigmoid(x):
return x * (1 - x)
# 训练模型此训练模型不包含偏执b
def train(X, y, steps=10000, lr=0.011):
# 返回全局变量的字典。
global V, W
for n in range(steps + 1):
# 随机选取一个数据
i = np.random.randint(X.shape[0])
# 获取一个数据,将输入视为至少转换为二维的数组。
x = X[i]
x = np.atleast_2d(x)
# BP算法公式
# 计算隐藏层的输出,np.dot()-矩阵乘法 v为输入层到隐含层的初始权重
L1 = sigmoid(np.dot(x, V))
# 计算输出层的输出 隐含层到输出层的初始权重
L2 = sigmoid(np.dot(L1, W))
# 计算L2_delta--损失函数对预测值求导 预测值对于L2求导
# L1_delta
L2_delta = (y[i] - L2) * dsigmoid(L2)
# x.dot(y) 等价于 np.dot(x,y) ———x是m × n 矩阵 ,y是n×m矩阵,则x.dot(y) 得到m×m矩阵。
# 求v需要更新的权重值
L1_delta = L2_delta.dot(W.T) * dsigmoid(L1)
# 更新权值 lr为学习率
W += lr * L1.T.dot(L2_delta)
V += lr * x.T.dot(L1_delta)
# 每训练1000次预测一次准确率
if n % 1000 == 0:
# 训练后返回预测结果,是标签值。
output = predict(X_test)
# numpy.argmax(array, axis) 用于返回一个numpy数组中最大值的索引值(下标位置)。当一组中同时出现几个最大值时,返回第一个最大值的索引值。
# axis可以从左至右计算数组的方括号数目,一个方括号是一维数组,两个方括号是二维数组,三个方括号是三维数组。
predictions = np.argmax(output, axis=1)
# mean()函数功能:求取均值
# 经常操作的参数为axis,以m * n矩阵举例:
# axis 不设置值,对 m * n个数求均值,返回一个实数
# axis = 0:压缩行,对各列求均值,返回 1 * n矩阵
# axis = 1 :压缩列,对各行求均值,返回m * 1矩阵
acc = np.mean(np.equal(predictions, y_test))
dW = L1.T.dot(L2_delta)
dV = x.T.dot(L1_delta)
# np.square()矩阵平方,np.sqrt()按元素确定数组的正平方根
gradient = np.sum([np.sqrt(np.sum(np.square(j))) for j in [dW, dV]])
print('steps(步长)', n, 'accuracy(准确率)', acc, 'gradient(斜率)', gradient)
# print(classification_report(predictions,y_test))
def predict(x):
# 计算隐藏层的输出
L1 = sigmoid(np.dot(x, V))
# 计算输出层的输出
L2 = sigmoid(np.dot(L1, W))
return L2
# 开始训练
# train(X_train, labels_train, 20000, lr=0.11)
train(X_train, labels_train, 20000, lr=0.011)
# 训练后结果对比
output = predict(X_test)
predictions = np.argmax(output, axis=1)
acc = np.mean(np.equal(predictions, y_test))
print('accuracy(准确率)', acc)
# 目标值,估计值,digits:int,输出浮点值的位数
print(classification_report(predictions, y_test, digits=4))