文章目录
1. 从零开始训练网络
1.1 搭建网络基本架构
网络的最终目标是,输入一张手写数字图片后,网络输出该图片对应的数字。
我们的代码要导出三个接口,分别完成以下功能:
1,初始化initialisation,设置输入层,中间层,和输出层的节点数。
2,训练train:根据训练数据不断的更新权重值
3,查询query,把新的数据输入给神经网络,网络计算后输出答案。(推理)
完成以上代码后,神经网络的大体框架就完成了,我们留下最重要的train函数,也就是通过训练样本训练链路权重的流程到下一步实现
1.2 构建训练网络
实现网络训练功能
自我训练过程分两步:
-
第一步是计算输入训练数据,给出网络的计算结果,这点跟我们前面实现的query()功能很像。
-
第二步是将计算结果与正确结果相比对,获取误差,采用误差反向传播法更新网络里的每条链路权重。
获取训练数据及预处理
接下来我们就得拿实际数据来训练我们的神经网络了。
我们要做的是读取训练数据,以及数据的预处理(归一化)
1.3 启动训练网络并测试数据
网络的最终目标是,输入一张手写数字图片后,网络输出该图片对应的数字。
由于网络需要从0到9一共十个数字中挑选出一个,于是我们的网络最终输出层应该有十个节点,每个节点对应一个数字。
假设图片对应的是数字0,那么输出层网络中,第一个节点应该输出一个高百分比,其他节点输出低百分比,如果图片对应的数字是9,那么输出层最后一个节点应该输出高百分比,其他节点输出低百分比。
2. 用Keras实现一个简单神经网络
2.1 Keras简介
Keras是基于theano/tensorflow的深度学习框架。是一个高层神经网络API,支持快速实验,能够把你的idea迅速转换为结果,如果有如下需求,可以优先选择Keras:
a)简易和快速的原型设计(keras具有高度模块化,极简,和可扩充特性)
b)支持CNN和RNN,或二者的结合
c)无缝CPU和GPU切换
2.2 MNIST手写数字识别(详细解释步骤)
2.2.1 数据的加载
MINIST数据集是一个公开的数据集,由0〜9手写数字图片和数字标签所组成的,由60000个训练样本和10000个测试样本组成,每个样本都是一张28 * 28像素的灰度手写数字图片。
from tensorflow.keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
load_data()
函数就会自动从网上下载MNIST数据,加载(下载)数据时顺便做完了训练集(train set)和测试集(test set)的分割。
将训练数据和检测数据加载到内存中(第一次运行需要下载数据,会比较慢):
train_images
是用于训练系统的手写数字图片;
train_labels
是用于标注图片的信息;
test_images
是用于检测系统训练效果的图片;
test_labels
是test_images
图片对应的数字标签。
2.2.2 对数据做基本确认(该步骤可有可无)
查看训练集和测试集的数据情况
print('train_images.shape = ',train_images.shape)
print('train_labels = ', train_labels)
print('test_images.shape = ', test_images.shape)
print('test_labels', test_labels)
打印结果:
train_images.shape = (60000, 28, 28)
tran_labels = [5 0 4 ... 5 6 8]
test_images.shape = (10000, 28, 28)
test_labels [7 2 1 ... 4 5 6]
train_images.shape
打印结果表明,train_images
是一个含有60000个元素的数组.数组中的元素是一个二维数组,二维数组的行和列都是28.也就是说,一个数字图片的大小是28*28.train_lables
打印结果表明,第一张手写数字图片的内容是数字5,第二种图片是数字0,以此类推.test_images.shape
的打印结果表示,用于检验训练效果的图片有10000张。test_labels
输出结果表明,用于检测的第一张图片内容是数字7,第二张是数字2,依次类推。
查看测试集的第一张图片
digit = test_images[0]
import matplotlib.pyplot as plt
plt.imshow(digit, cmap=plt.cm.binary)
plt.show()
2.2.3 搭建神经网络
使用tensorflow.Keras
搭建一个有效识别图案的神经网络
from tensorflow.keras import models
from tensorflow.keras import layers
#模型构建
network = models.Sequential()
#隐藏层结点个数为512,激活函数为relu,输入为一个28*28的图像
network.add(layers.Dense(512, activation='relu', input_shape=(28*28,)))
#输出层 输出节点个数为10,结点映射到1到0之间
network.add(layers.Dense(10, activation='softmax'))
-
layers
:表示神经网络中的一个数据处理层。(dense:全连接层) -
models.Sequential()
:顺序模型,表示把每一个数据处理层串联起来,即通过一层层神经网络连接构建深度神经网络。通过model.add()
叠加一些网络层如LSTM和Dense。 -
layers.Dense(…)
:构造一个数据处理层。 -
input_shape(28*28,)
:表示当前处理层接收的数据格式必须是长和宽都是28的二维数组,后面的“,
“表示数组里面的每一个元素到底包含多少个数字都没有关系. -
softmax
用于多分类过程中,它将多个神经元的输出映射到[0,1]区间内,故可以看成是某个类的概率,从而来进行多分类。假设我们有一个数组V,V_i表示V中的第i个元素,计算softmax
值公式为:
S i = e V i ∑ j e V i S_i=\frac{e^{V_i}}{\sum_je^{V_i}} Si=∑jeVieVi
搭建完模型后使用compile()
函数进行编译
# 编译
network.compile(optimizer='rmsprop', loss='categorical_crossentropy',
metrics=['accuracy'])
compile()
函数参数介绍
optimizer
:优化器/优化算法loss
:描述模型预测值与真实值的差距大小。两种常见的算法——均值平方差(MSE)和交叉熵。metric
:在训练和测试过程中需要监控的指标/度量。正确分类的比例用"accuracy"即可。注意metrics参数的传递方法是指定一个列表,这意味着可以指定的性能度量项可以不限于一项。
2.2.4 数据标准化
将数据从二维数组变为一位数组,然后数据归一化处理(在把数据输入到网络模型之前)
train_images = train_images.reshape((60000, 28*28))
train_images = train_images.astype('float32') / 255
test_images = test_images.reshape((10000, 28*28))
test_images = test_images.astype('float32') / 255
reshape(60000, 28*28)
:train_images数组原来含有60000个元素,每个元素是一个28行,28列的二维数组,现在把每个二维数组转变为一个含有28*28个元素的一维数组.astype(“float32”)/255
: 由于数字图案是一个灰度图,图片中每个像素点值的大小范围在0到255之间。/255
就是把每个像素点的值从范围0-255转变为范围在0-1之间的浮点值。
把图片对应的标记也做一个更改(该步骤可有可无)
如果没有对标签进行处理,在预测推理时,只需使用argmax函数将概率最大的位置输出即可
from tensorflow.keras.utils import to_categorical
print("before change:" ,test_labels[0])
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
print("after change: ", test_labels[0])
运行结果:
before change: 7
after change: [0. 0. 0. 0. 0. 0. 0. 1. 0. 0.]
to_categoricall(数据的类别标签, 总类别数)
:将类别标签向量转换为二进制(只有0和1)的矩阵类型表示。每一个标签用矩阵的对应的行向量来表示。
目前所有图片的数字图案对应的是0到9。例如test_images[0]对应的是数字7的手写图案,那么其对应的标记test_labels[0]的值就是7。我们需要把数值7变成一个含有10个元素的数组,然后在第8个元素设置为1,其他元素设置为0。test_lables[0] 的值由7转变为数组[0,0,0,0,0,0,0,1,0,0]
2.2.5 训练模型
把数据输入模型进行训练
#指定了训练5轮,小批量训练数据块大小为128个数据样本
network.fit(train_images, train_labels, epochs=5, batch_size = 128)
训练过程:
Epoch 1/5
128/60000 [..............................] - ETA: 1:49 - loss: 2.3711 - acc: 0.0625
384/60000 [..............................] - ETA: 44s - loss: 1.9454 - acc: 0.3516
······
······
59520/60000 [============================>.] - ETA: 0s - loss: 0.0380 - acc: 0.9884
60000/60000 [==============================] - 5s 79us/sample - loss: 0.0379 - acc: 0.9885
train_images
:用于训练的手写数字图片;train_labels
:对应的是图片的标记;epochs
:每次计算的循环是五次batch_size
:每次网络从输入的图片数组中随机选取128个作为一组进行计算。把batch_size传递给模型,它自动计算需要分为多少个mini-batch。如果除不尽的话,是向下取整,最后不足部分舍弃。batch mode
(批量模式):将整个数据集作为一个数据块训练。若batch_size等于训练集大小就是batch mode。minibatch mode
(小批量模式):分为多个数据块(通常是相同大小的)逐个处理。stochastic mode
:逐个数据进行训练处理。batch_size=1时的minibatch mode的特例。
2.2.6 性能评估
上一步骤已经训练好模型了,将测试数据输入,检验网络学习后的图片识别效果
test_loss, test_acc = network.evaluate(test_images, test_labels, verbose=1)
print(test_loss)
print('test_acc', test_acc)
运行结果
0.07136689759036526
test_acc 0.9796
evaluate()
函数用于进行模型性能评估,将test_images, test_labels
一起传递给evaluate()函数即可。
识别效果与硬件有关(CPU/GPU).
2.2.7 预测推理
输入一张手写数字图片到网络中,看看它的识别效果
先来看看手写图片
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
digit = test_images[1]
plt.imshow(digit, cmap=plt.cm.binary)
plt.show()
将图片数据输入模型进行训练
test_images = test_images.reshape((10000, 28*28))
res = network.predict(test_images)#预测函数
#前面数据处理时,将训练集的数字变成了只含有0和1的数组,故此时模型输出的是一个10维向量,当哪个的概率最大时将对应位置的赋值为1
print(res[1])
print("the number for the picture is : ", res[1].argmax())
#for i in range(res[1].shape[0]):
# if (res[1][i] == 1):
# print("the number for the picture is : ", i)
# break
运行结果:
[0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]
the number for the picture is : 2
#the number for the picture is : 2
【代码实现】直接调用接口
from tensorflow.keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
print('train_images.shape = ',train_images.shape)
print('train_labels = ', train_labels)
print('test_images.shape = ', test_images.shape)
print('test_labels', test_labels)
digit = test_images[0]
import matplotlib.pyplot as plt
plt.imshow(digit, cmap=plt.cm.binary)
plt.show()
from tensorflow.keras import models
from tensorflow.keras import layers
network = models.Sequential()
network.add(layers.Dense(512, activation='relu', input_shape=(28*28,)))
network.add(layers.Dense(10, activation='softmax'))
network.compile(optimizer='rmsprop', loss='categorical_crossentropy',
metrics=['accuracy'])
train_images = train_images.reshape((60000, 28*28))
train_images = train_images.astype('float32') / 255
test_images = test_images.reshape((10000, 28*28))
test_images = test_images.astype('float32') / 255
from tensorflow.keras.utils import to_categorical
print("before change:" ,test_labels[0])
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
print("after change: ", test_labels[0])
network.fit(train_images, train_labels, epochs=5, batch_size = 128)
test_loss, test_acc = network.evaluate(test_images, test_labels, verbose=1)
print(test_loss)
print('test_acc', test_acc)
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
digit = test_images[1]
plt.imshow(digit, cmap=plt.cm.binary)
plt.show()
test_images = test_images.reshape((10000, 28*28))
res = network.predict(test_images)
print(res[1])
#print("the number for the picture is : ", res[1].argmax())
for i in range(res[1].shape[0]):
if (res[1][i] == 1):
print("the number for the picture is : ", i)
break