上一篇
1 进行数据预处理
1.1 导入所需模块
from keras.utils import np_utils
import numpy as np
np.random.seed(10)
在 JupyterNotebook 中显示如图:
1.2 读取数据
这里的路径必须是自己存放 npz 文件的路径。
train_dic=np.load('E:/practice/data_and_distribution/data_train.npz',allow_pickle=True)
(x_train_image,y_train_label)=train_dic['x'],train_dic['y']
test_dic=np.load('E:/practice/data_and_distribution/data_test.npz',allow_pickle=True)
(x_test_image,y_test_label)=test_dic['x'],test_dic['y']
如果使用 MNIST 数据集。(初次加载可能会比较慢)
(x_train_image, y_train_label), \
(x_test_image, y_test_label) = mnist.load_data()
注:如果 MNIST 数据集加载出现错误,请前往以下网址手动下载。
亚马逊 MNIST 数据集下载链接
下载完成后复制文件到 C:\Users\用户名.keras\datasets,重新运行指令即可。
代码在 JupyterNotebook 中显示如图:
1.3 将 features (数字图像特征值)使用 reshape 转换。
可以用下列指令查看每一个数字图像的 shape 是 28×28。
print('train data=',len(x_train_image))
print(' test data=',len(x_test_image))
在 JupyterNotebook 中显示如图:
下面的程序将原本 28×28 的数字图像以 reshape 转换成 784 个 Float 数。
因为单个神经元只能对应单个的点,图像矩阵有 28 行 28 列,28×28=784个。
x_Train=x_train_image.reshape(60000, 784).astype('float32')
x_Test=x_test_image.reshape(10000, 784).astype('float32')
在 JupyterNotebook 中显示如图:
再次查看发现每一个数字图像变成了长度为 784 的一维张量。
查看 images 第 0 项的内容。
import matplotlib.pyplot as plt
def plot_image(image):
fig = plt.gcf()
fig.set_size_inches(2, 2)
plt.imshow(image, cmap="binary")
plt.show()
plot_image(x_train_image[0])
PIL 的图像:
MNIST 的图像:
从以上结果可知,数字矩阵的大部分是0,少部分是有效值。
对于 MNIST 数据集,每一个数字都是从 0 到 255 的值,代表图形每一个点灰度的深浅。
1.4 将 features (数字图像特征值)标准化。
将 features (数字图像特征值)标准化可以提高模型预测的准确度,并且更快收敛。
(仅在 MNIST 数据集中有作用)
x_Train_normalize=x_Train/255
x_Test_normalize=x_Test/255
在 JupyterNotebook 中显示如图:
1.5 label (数字真实的值) 以 One-Hot Encoding 转换。
y_Train_OneHot=np_utils.to_categorical(y_train_label)
y_Test_OneHot=np_utils.to_categorical(y_test_label)
在 JupyterNotebook 中显示如图:
以下列指令来查看训练数据 label 标签字段的前 5 项训练数据,我们可以看到这是 0-9 的数字。
y_train_label[:5]
使用 np_utils.to_categorical 将训练数据与测试数据的 label 进行 One-Hot Encoding 转换。
y_TrainOneHot = np_utils.to_categorical(y_train_label)
y_TestOneHot = np_utils.to_categorical(y_test_label)
y_train_label[:5]
进行 One-Hot Encoding 转换后,查看训练数据 label 标签字段的前 5 项训练数据,我们可以看到转换后的结果。
参考上面的结果,例如第一项数据,原本的真实值是 5 ,进行 One-Hot Encoding 转换后,只有第 5 个数字(由 0 算起)是 1,其余都是 0。
这样就可以用 10 个神经元来表示 0-9 的数字。
2 建立模型
我们将建立下列多层感知器模型,输入层(x)共有 784 个神经元,隐藏层 (h)共有 256 个神经元,如图 7-4 所示。我们将使用下面的程序代码建立多层感知机模型。
2.1 导入所需模块
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
2.2 建立 Sequential 模型
建立一个线性堆叠模型,后续只需要使用 model.add() 方法将各个神经网络层加入模型即可。
model = Sequential()
2.3 建立“输入层”与“隐藏层”
以下程序代码将“输入层”与“隐藏层”加入模型,使用 model.add() 方法加入 Dense 神经网络层。Dense 神经网络层的特色是:所有的上一层与下一层的神经元都完全连接。
model.add(Dense(units=256,input_dim=784,kernel_initializer="normal",activation='relu'))
参数 | 参数说明 |
---|---|
units=256 | 定义“隐藏层”神经元个数为 256 |
input_dim=784 | 设置“输入层”神经元个数为 784 |
kernel_initializer=‘normal’ | 使用 normal distribution 正态分布的随机数来初始化 weight 和 bias |
activation | 定义激活函数为 relu |
关于激活函数: 一篇关于激活函数比较详细的博客
2.4 加入 DropOut 功能,以解决过度拟合的问题
过拟合:为了得到一致假设而使假设变得过度严格称为过拟合。
也就是说参数矩阵训练过度,一个假设在训练数据上能够获得比其他假设更好的拟合, 但是在训练数据外的数据集上却不能很好地拟合数据。这时候应该主动舍弃一部分参数,我们通过如下代码舍弃了 50 % 的数据。
model.add(Dropout(0.5))
2.5 建立输出层
输出层共有 10 个神经元,对应 0~9 十个数字。并且使用 softmax 激活函数进行转换,softmax 可以将神经元的输出转换为预测每一个数字的概率。
model.add(Dense(units=10,kernel_initializer='normal',activation='softmax'))
以上建立 Dense 神经网络不需要设置 input_dim,因为 Keras 会自动按照上一层的 units 是 256 个神经元,设置这一层的 inpuy_dim 为 256。
2.6 查看模型的摘要
print(model.summary())
建立输入层和隐藏层的公式如下: h1 = relu(X*W1 + b1)
建立隐藏层和输出层的公式如下: y = softmax(h1*h2 + b2)
通常 Trainable Param 数值越大,代表此模型越复杂,需要越多的时间进行训练。
第 2 节在 JupyterNotebook 中显示如图:
3 进行训练
在我们建立好深度学习模型之后,就可以使用反向传播算法进行训练了。
这个网页提供了不同的梯度下降函数的可视化。
梯度下降法可视化网址
3.1 定义训练方式
在训练模型之前,我们必须使用 compile 方法对训练模型进行设置,指令如下:
model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])
compail 方法需输入下列参数。
- loss: 设置损失函数,这里使用交叉熵训练的效果比较好。
- optimizer 使用 adam 优化器使得训练更快收敛,并提高准确率。
- metrics: 设置评估模型的方式是准确率。
3.2 开始训练
进行 10 次训练,每次使用 48000 项数据训练,分为 240 个批次,每个批次
200 项。再用 12000 项数据进行验证,计算这个训练周期的准确度与误差,并在 train_history 中新增一项记录。
train_history = model.fit(x=x_Train_normalize,
y=y_Train_OneHot,validation_split=0.2,
epochs=10,batch_size=200, verbose=2)
训练结果会存贮在 train_history 变量中。
参数 | 说明 |
---|---|
x=x_Train_normalize | features 数字图像的特征值 |
y=y_Train_OneHot | label 数字图像真实的值 |
validation_split=0.2 | 80%作为训练数据,20%作为验证数据 |
epochs=10 | 执行 10 个训练周期 |
batch_size=200 | 每一批次 200 项训练数据 |
verbose=2 | 训练过程可视 |
从以上执行结果可知,误差越来越小,准确度越来越高。
3.3 显示训练过程
读取 train_history 里的数据,以图表显示训练过程。
import matplotlib.pyplot as plt
def show_train_history(train_history,train,validation):
plt.plot(train_history.history[train])
plt.plot(train_history.history[validation])
plt.title('Train History')
plt.ylabel(train)
plt.xlabel('Epoch')
plt.legend(['train','validation'], loc='upper left')
plt.show()
程序代码 | 说明 |
---|---|
plt.title(‘Train History’) | 设置标题 |
plt.ylabel(train) | 设置 y 轴的标签名称 |
plt.xlabel(‘Epoch’) | 设置 x 轴的标签名称 |
plt.legend([‘train’,‘validation’], loc=‘upper left’) | 设置图例是 ‘train’ ‘validation’ ,位置在左上角 |
调用函数画出准确率评估的执行结果
show_train_history(train_history,'accuracy',"val_accuracy")
因为使用了 DropOut 函数,所以模型得到的结果非常好。随着训练次数的增加,训练和验证的准确度都越来越高,并且彼此靠近。如果没有 DropOut 函数,在训练的后期,’accuracy’ 数值将高于 ‘val_accuracy’ 之后 ’accuracy’ 将继续升高,而 ‘val_accuracy’ 将逼近极限,陷入俗称的过度拟合。
关于过度拟合:访问 wiki 需要科学上网!
画出误差执行结果,可以看到无论是训练还是验证,误差都越来越低。
show_train_history(train_history,'loss',"val_loss")
3.4 以测试数据评估模型准确率
之前我们已经完成了训练,现在要使用 test 测试数据来评估模型准确率。
scores = model.evaluate(x_Test_normalize, y_Test_OneHot)
print()
print('accuracy=',scores[1])
准确率约为 0.984
程序代码 | 说明 |
---|---|
model.evaluate | 该函数可以评估模型的准确率,评估的结果会存在变量 scores 中 |
x=x_Train_normalize | features 数字图像的特征值 |
y=y_Train_OneHot | label 数字图像真实的值 |
print(‘accuracy=’,scores[1]) | 显示准确率 |
4 进行预测
通过之前的步骤,我们建立了模型,并且完成了模型训练,接下来我们将使用此模型进行预测。
4.1 执行预测
prediction=model.predict_classes(x_Test_normalize)
注:源码有误,应该将 prediction=model.predict_classes(x_Test)
的参数改成 x_Test_normalize
利用 model.predict_classes 函数进行预测,并将预测结果存在变量 prediction 中
4.2 预测结果
prediction # 查看预测结果
可以看到第0项的预测结果是8,第1项的预测结果是3,诸如此类。
4.3 显示 10 项预测结果
def plot_images_labels_prediction(images, labels, prediction, idx, num = 10):
fig=plt.gcf()
fig.set_size_inches(12, 14)
if num>25:num=25
for i in range(num):
ax=plt.subplot(5,5,1+i)
ax.imshow(images[idx],cmap="binary")
title= "label=" + str(labels[idx])
if len(prediction)>0:
title+=",prediction="+str(prediction[idx])
ax.set_title(title,fontsize=10)
ax.set_xticks([]);ax.set_yticks([])
idx+=1
plt.show()
plot_images_labels_prediction(x_test_image,y_test_label,prediction,idx=340)
可以看到我们随机选取的这十个数据预测结果和实际标签相符。
4.4 显示混淆矩阵
混淆矩阵用来显示在所建立的模型中,哪些数字准确率最高那些数字最容易混淆。
1.使用pandas crosstab 建立混淆矩阵
import pandas as pd
pd.crosstab(y_test_label,prediction,rownames=['label'],colnames=['predict'])
从图中可以看出数字 1 的准确率最高,数字 8 的错误率最高。
2.建立真实值与预测 DataFrame
因为我们希望能够找出所有预测错误的结果,所以创建下列 DataFrame 。
df=pd.DataFrame({'label':y_test_label,'predict':prediction})
df[:2]
3.如图显示所有 label 是 8 而 prediction 是 5 的数据。
df[(df.label==8)&(df.predict==5)]
附录
- 关于过度拟合:wiki 上过度拟合的解释
- 关于激活函数:一篇关于激活函数比较详细的博客
- 如果 MNIST 数据集加载出现错误,请前往以下网址手动下载。
亚马逊 MNIST 数据集下载链接 - 不同的梯度下降函数的可视化:
梯度下降法可视化网址 - 源码下载:百度网盘链接 1 提取码:jr7d ;百度网盘链接 2 提取码:e8gh
注:源码 1 有误,应该将 prediction=model.predict_classes(x_Test)
的参数改成 x_Test_normalize