本节实践一下'前向传播'.即将使用真正的数据和模型了(虽然这个模型不是自己训练的),
想想还是有点小激动嗯。(马上就能发明机器人,推翻人类暴政,走向人生巅峰了。)
本节大体分为3个内容
想办法搞到图片数据
一次处理一张
一次处理100张(批量且高效率的)
--------MNIST数据集--------
这是机器学习领域最出名的数据集之一。
MNIST数据集是由0到9的数字图像构成的。图像数据是28像素 × 28像素的灰度图像。
像素的取值在0到255之间。每个图像数据都相应地标有“7”“2”“1”等标签
训练图像有6万张,测试图像有1万张
下面开始把这些数据下载下来。这里提供获取数据的代码。获取的细节不再展开讨论。
大约就是用urllib请求了一些网站,下载了一些数据。以下是获取这些数据的代码(以及其他章节的所有代码)
https://share.weiyun.com/5HteQuq
根据网速情况,下载或许耗时几分钟或更久。
因为Python有pickle功能,把对象转化为一个文件。所以在第二次及以后读入数据的时候速度会很快。
如果对Python的pickle功能有兴趣,可以询问可爱的度娘。
--------显示一副图像以验证这个数据集--------
现在写一个程序,显示一张图片,以证明这个数据集下载成功并且是有效的。
import sys, os
sys.path.append(os.pardir)
import numpy as np
from dataset.mnist import load_mnist
from PIL import Image
def img_show(img):
#把img数组转化成Image可以读取的对象
pil_img = Image.fromarray(np.uint8(img))
#显示这个图片对象
pil_img.show()
#得到数据集
#flatten=True代表需要得到1维的数据,normalize=False代表不要正规化(0-1之间)
(x_train, t_train), (x_test, t_test) = load_mnist(flatten=True,
normalize=False)
img = x_train[0]
label = t_train[0]
print(label) # 5
print(img.shape) # (784,)
#因为数据被1维化了,所以此处需要把维度转化为28*28的图像尺寸
img = img.reshape(28, 28) # 把图像的形状变成原来的尺寸
print(img.shape) # (28, 28)
img_show(img)
这是存放这个代码的位置:
运行成功之后:
数据的获取及验证部分就这样完成了。下面进行神经网络的推理处理。
--------神经网络的推理--------
介绍下这个神经网络的构成:
输入层:28*28=784个神经元
输出层:0-9一共10个分类。所以有10个神经元。
此外,这个神经网络有2个隐藏层,第1个隐藏层有50个神经元,
第2个隐藏层有100个神经元。这个50和100可以设置为任何值。
推理过程与《深度学习理论基础10-实现一个3层神经网络》的区别在于,
之前的权重是乱写的,而本节的权重是训练出来的(当然,不是我们训练的,这节只负责直接拿来用),
因为这些权重是有效的,所以我们可以在本节看到效果,要想看到效果,也就是正确率,
就需要写一个这个神经网络预测的结果与实际结果的差距,这也是本节需要完成的程序。
下面梳理一下需要做的事情:
1.准备一个获取数据集的函数
2.准备一个获取权重信息的函数
3.准备一个通过数据集及权重信息进行推理的神经网络函数
4.准备一个统计真实结果与预测结果相同数量的函数
5.运行主函数,查看效果
做这些之前,先导入必要的模块
from yuan.dataset.mnist import load_mnist
import pickle
import numpy as np
为了方便操作,yuan文件夹已被制作成模块(在此文件夹加一个空的__init__.py文件即可)
另外,神经网络的推理需要激活函数,之前的章节已经实现过:
#隐藏层激活函数
def sigmoid_function(x):
return 1/(1+np.exp(-x))
#输出层激活函数
def softmax(a):
exp_a = np.exp(a)
sum_exp_a = np.sum(exp_a)
y = exp_a / sum_exp_a
return y
做完这些,开始我们的计划
第一步,准备一个获取数据集的函数
# 1.准备一个获取数据集的函数
def get_data():
#通过这个函数,获得训练集和测试集
(x_train, t_train), (x_test, t_test) = \
load_mnist(normalize=True, flatten=True, one_hot_label=False)
# 后面只用到测试集,所以只返回这俩(因为模型是训练好的,所以用不到训练集)
return x_test, t_test
第二步,准备一个获取权重信息的函数
# 2.准备一个获取权重信息的函数
def get_weight():
#你应该保证sample_weight.pkl文件的路径是正确的
#这个文件就是实例经过pickle模块的dumps打包之后的文件(这里我们直接拿来用)
sample_weight_path='./yuan/ch03/sample_weight.pkl'
with open(sample_weight_path, 'rb') as f:
#把这个文件重新还原成了实例
network = pickle.load(f)
W1, W2, W3 = network['W1'], network['W2'], network['W3']
b1, b2, b3 = network['b1'], network['b2'], network['b3']
#返回了各层的权重和偏置
return W1, W2, W3, b1, b2, b3
第三步,准备一个通过数据集及权重信息进行推理的神经网络函数
# 3.准备一个通过数据集及权重信息进行推理的神经网络函数
# 这个过程也叫前向传播(forward propagation)
def forward_propagation(x,network):
W1, W2, W3, b1, b2, b3=network
a1 = np.dot(x, W1) + b1
z1 = sigmoid_function(a1)
a2 = np.dot(z1, W2) + b2
z2 = sigmoid_function(a2)
a3 = np.dot(z2, W3) + b3
y = softmax(a3)
return y
第四步,准备一个统计真实结果与预测结果相同数量的函数
# 4.准备一个统计真实结果与预测结果相同数量的函数
def get_accuracy():
network=get_weight()
x, t = get_data()
#这个变量用于记录正确的预测数量
accuracy_cnt = 0
for i in range(len(x)):
#逐个预测结果
y = forward_propagation(x[i],network)
p = np.argmax(y) # 获取概率最高的元素的索引
#对预测结果与真实结果对比
if p == t[i]:
accuracy_cnt += 1
#返回正确比例
return str(float(accuracy_cnt) / len(x))
第五步,运行主函数,查看效果
# 5.运行主函数,查看效果
def main():
Accuracy=get_accuracy()
print(Accuracy) #输出0.9352
if __name__=='__main__':
main()
最后的0.9352就是这个模型的正确率。每1000个数字图片它能认识935个。
不错不错。这个成绩甚至超过幼儿园小朋友了。
前几年神经网络刚出现的时候,我在果壳看到图像识别的报道简直吓尿了。这太强大了。
没想到此刻我也写出了这样的程序(实际情况是直接拿别人数据和模型来用----->吹牛从来不脸红)。
为了榨干numpy的最后一滴血,接下来进行图片的批处理。
(因为np有一些强大的算法很适合批量处理,比用循环一张一张的处理快很多。)
--------批处理--------
预警:矩阵积乘没学好的,请回炉重造。批处理正是通过矩阵积乘的方法进行的。
上图是刚才进行单张图片推理的示意图。
输入其实可以看做1行,784列的矩形。最终输出一个1行10列的矩阵。
批处理,我们要做的部分就是把输入变成多行784列。这样,输出也会变成多行10列。
就像下面这样:
这样在第四步,有了一个替代方案:
#4_2.批处理图像结果
def batch_get_accuracy():
network=get_weight()
x, t = get_data()
#这个变量用于记录正确的预测数量
batch_size = 100 # 批数量
accuracy_cnt = 0
for i in range(0, len(x), batch_size):
x_batch = x[i:i + batch_size]
y_batch = forward_propagation(x_batch,network )
p = np.argmax(y_batch, axis=1)
accuracy_cnt += np.sum(p == t[i:i + batch_size])
#返回正确比例
return str(float(accuracy_cnt) / len(x))
可以看到,循环次数减少了100倍(因为步长变成了100)
forward_propagation(x_batch,network ) 这一步,就像上面的图片所描述的一样,会返回100*10的形状
np.argmax(y_batch, axis=1)则负责把每一行的最大值的索引取出来(也就是最大概率所在的索引位置,即预测结果)
t[i:i + batch_size]则是从正确的答案中截取一截。
所以p == t[i:i + batch_size]的实质是一串预测值与一串真实值比较。其bool结果之和就是正确数量。
至此,本节的内容就结束了。下一节开始神经网络的学习。
---------结语--------
本节除了获取数据及权重环节,其余部分都是之前知识的应用。不理解的地方完全可以在前面的章节找到答案。
下一节见。