本文已参与「新人创作礼」活动,一起开启掘金创作之路。
数据增强不但可以增加数据集的数量,而且对于模型的收敛也有很好的效果,数据增强主要是利用特征的不变性,通过对图像进行旋转、尺寸变换、水平或垂直翻转、缩放、通道移位等方法,起到扩充数据的作用,在一定程度上防止过拟合。下面重点列举几种数据增强方法:
(1)随机裁剪(RandomCrop)
在数据集图片中,按照预设大小进行剪裁,优点是保留了原图像的比例,移动图片在各区域的位置。
(2)随机翻转(RandomFlip)
在数据集图片中,按照随机的角度旋转图像,包括水平翻转,垂直翻转等。
(3)随机比例裁剪并缩放(RandomResizedCrop)
在图像数据集中随机剪裁一部份区域,然后按照一定的比例嵌入到原图片中。
(4)色彩抖动(ColorJitter)
主要是对图像的亮度(Brightness)、对比度(Contrast)、饱和度(Saturatio)和色相(Hue)进行随机变换,模拟真实环境条件的变化。
(5)随机灰度化(RandomGrayscale)
为了消除图像本身颜色所产生的影响,随机对图片进行灰度化处理。
掌握了几种数据增强方法,下面直接上代码看效果。
# 加大网络深度, 观察网络性能是否得到提升
import tensorflow as tf
from tensorflow.keras import datasets, models, layers, optimizers
from tensorflow.keras.preprocessing.image import ImageDataGenerator
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)
augmentation = ImageDataGenerator(
rotation_range=40,
width_shift_range=0.3,
height_shift_range=0.3,
horizontal_flip=True,
)
augmentation.fit(train_x)
# 定义网络结构
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.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.2))
# 到此为止,与上一篇博客的网络结构类似,为了得到加深网络的结果,我们再增加一个上述的结构。
# 区别于第一轮, 增加卷积核数量
model.add(layers.Convolution2D(64, (3,3), padding='same', activation='relu', input_shape=in_shape))
model.add(layers.BatchNormalization())
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.3))
model.add(layers.Convolution2D(128, (3, 3), padding='same', activation='relu', input_shape=in_shape))
model.add(layers.BatchNormalization())
model.add(layers.Convolution2D(128, (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_generator(augmentation.flow(train_x, train_y, batch_size=BATCH_SIZE), epochs=EPOCH, verbose=VERBOSE, validation_data=(test_x, test_y), callbacks=callback)
# model.fit(train_x, train_y, batch_size=BATCH_SIZE, epochs=EPOCH, validation_data=(test_x, test_y), callbacks=callback)
# 将模型保存
model_json = model.to_json()
with open("model_json", "w") as jf:
jf.write(model_json)
model.save_weights("detecedCIFAR10.h5")
score = model.evaluate(test_x, test_y, batch_size=BATCH_SIZE)
print("test score:", score[0])
print("test accuracy:", score[1])
相比于上次一网络,结构加深了一个层次,别切使用了数据增强的方法,训练结果如下所示。
网络结构如下所示
训练的损失如图所示
训练的准确率如图所示