本文已参与「新人创作礼」活动,一起开启掘金创作之路。
在改善网络性能之前,首先了解一个概念,BatchNormalization,随着网络加深或者在训练过程中,收敛速度变慢,其主要原因是整体分布逐渐往非线性函数的取值区间的上下限两端靠近(对于Sigmoid函数来说,意味着激活输入值WU+B是大的负值或正值),这一问题将直接导致反向传播时低层神经网络的梯度消失。
BatchNormalization主要作用就是把每层神经网络任意神经元输入值的分布强行拉回到均值为0方差为1的标准正态分布中,使得激活输入值落在非线性函数对输入比较敏感的区域,这样输入的小变化就会导致损失函数较大的变化,其核心作用就是放大梯度,避免梯度消失。
说了这么多,这次网络性能的改善肯定需要用到BatchNormalization了,上一篇博客的网络结构非常简单,就是一个卷积,一个池化,一个dropout就完事了,现在我们尝试把网络加深,同时使用BatchNormalization防止梯度消失,看一下网络的性能会不会提高。
改进后的代码如下面所示
# 加大网络深度, 观察网络性能是否得到提升
import tensorflow as tf
from tensorflow.keras import datasets, models, layers, optimizers
import matplotlib.pyplot as plt
import numpy as np
# 定义网络参数
EPOCH = 50
BATCH_SIZE = 128
VERBOSE = 1
VALIDATION_SPLIT = 0.2
OPTIMATOR = optimizers.RMSprop()
NUM_CLASS = 10
img_w = 32
img_h = 32
img_chanmel = 3
in_shape = (img_w, img_h, img_chanmel)
# 加载数据集
(train_x, train_y), (test_x, test_y) = datasets.cifar10.load_data()
# 处理数据集
train_y = tf.squeeze(train_y)
train_y = tf.one_hot(train_y, depth=10)
test_y = tf.squeeze(test_y)
test_y = tf.one_hot(test_y, depth=10)
# 定义网络结构
def NetStruct(in_shape, in_class):
# 定义容器
model = models.Sequential()
# 添加网络结构
# 卷积
model.add(layers.Convolution2D(32, (3, 3), padding='same', activation='relu', input_shape=in_shape))
# 批归一化
model.add(layers.BatchNormalization())
# 池化
model.add(layers.MaxPooling2D(pool_size=(2, 2)))
# 随机失活1/4神经元
model.add(layers.Dropout(0.25))
# 到此为止,与上一篇博客的网络结构类似,为了得到加深网络的结果,我们再增加一个上述的结构。
# 区别于第一轮, 增加卷积核数量
model.add(layers.Convolution2D(64, (3,3), padding='same', activation='relu', input_shape=in_shape))
model.add(layers.BatchNormalization())
model.add(layers.MaxPooling2D(pool_size=(2, 2)))
model.add(layers.Dropout(0.4))
# 输入层的数据压成一维的数据,一般用再卷积层和全连接层之间
model.add(layers.Flatten())
# 使用softmax输出包含十个类别
model.add(layers.Dense(in_class, activation='softmax'))
return model
callback = [tf.keras.callbacks.TensorBoard(log_dir='./blog08/')]
# 初始化网络
model = NetStruct(in_shape, NUM_CLASS)
model.compile(loss="categorical_crossentropy", optimizer=OPTIMATOR, metrics=['accuracy'])
# 训练
model.fit(train_x, train_y, batch_size=BATCH_SIZE, epochs=EPOCH, validation_data=(test_x, test_y), callbacks=callback)
score = model.evaluate(test_x, test_y, batch_size=BATCH_SIZE)
print("test score:", score[0])
print("test accuracy:", score[1])
这次相比于上次增加了网络深度,相比于之前增加了一倍,结果没让我们失望,网络的性能果然有所提升,训练结果如下所示。
相比于之前提升了18%左右,效果非常明显了。这次的网络结构如下所示
网络的准确率与损失函数如下所示。
虽然我们的准确率有显著的提升,但是在总体看来,准确率还是太低了,有没有什么办法可以再进一步增加准确率呢?当然有,下一篇博客将围绕如何提升准确率讲一下数据增强的概念。