说明
- 在前一个案例中,我们构建了CNN网络模型,此架构的设计目的在于识别图像中的重要特征,因而它极大提高了模型的性能。但我们的验证准确率仍落后于训练准确率,这意味着我们的模型依然有点过拟合。
- 为了增强模型在处理新数据时的鲁棒性,我们将以编程方式增加数据集的大小和差异。这称为数据增强,是对很多深度学习应用都非常有用的技术。
- 数据的增加让模型在训练时能看到更多图像。数据差异的增加可帮助模型忽略不重要的特征,而只选择在分类时真正重要的特征。如此一来,在面对新数据时,模型有望在进行预测时更好地泛化。
模型训练+保存+预测
-
载入数据
-
搭建模型
-
数据增强(通过认为差异化数据、增加噪声,一方面能够预防过拟合,另一方面能够提升模型鲁棒性)
-
数据拟合与模型编译
-
模型训练(验证集上的精度几乎与训练集上的一样,表明该模型的性能优异)
-
模型保存(这一步会将模型保存到本地,这个模型在本地是一个文件,可以将这个模型迁移到其他机器上进行预测)
-
载入模型并预测(这里假设在一台新的计算机中载入了我们保存的模型)
-
载入并查看预测数据
-
定义载入图像的方法对图像进行预处理
-
测试样本预测(到此,预测过程本质上已经结束)
- 对预测过程进行整理
-
生成一个标签与字母对应的字典
-
定义一个预测函数
-
实施预测
-
实施预测
Code
## ============数据准备===========
import tensorflow.keras as keras
import pandas as pd
# Load in our data from CSV files
train_df = pd.read_csv("sign_mnist_train.csv")
valid_df = pd.read_csv("sign_mnist_valid.csv")
# Separate out our target values
y_train = train_df['label']
y_valid = valid_df['label']
del train_df['label']
del valid_df['label']
# Separate out our image vectors
x_train = train_df.values
x_valid = valid_df.values
# Turn our scalar targets into binary categories
num_classes = 24
y_train = keras.utils.to_categorical(y_train, num_classes)
y_valid = keras.utils.to_categorical(y_valid, num_classes)
# Normalize our image data
x_train = x_train / 255
x_valid = x_valid / 255
# Reshape the image data for the convolutional network
x_train = x_train.reshape(-1,28,28,1)
x_valid = x_valid.reshape(-1,28,28,1)
## =============构建模型==================
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import (
Dense,
Conv2D,
MaxPool2D,
Flatten,
Dropout,
BatchNormalization,
)
model = Sequential()
model.add(Conv2D(75, (3, 3), strides=1, padding="same", activation="relu",
input_shape=(28, 28, 1)))
model.add(BatchNormalization())
model.add(MaxPool2D((2, 2), strides=2, padding="same"))
model.add(Conv2D(50, (3, 3), strides=1, padding="same", activation="relu"))
model.add(Dropout(0.2))
model.add(BatchNormalization())
model.add(MaxPool2D((2, 2), strides=2, padding="same"))
model.add(Conv2D(25, (3, 3), strides=1, padding="same", activation="relu"))
model.add(BatchNormalization())
model.add(MaxPool2D((2, 2), strides=2, padding="same"))
model.add(Flatten())
model.add(Dense(units=512, activation="relu"))
model.add(Dropout(0.3))
model.add(Dense(units=num_classes, activation="softmax"))
## ===========数据增强===========
from tensorflow.keras.preprocessing.image import ImageDataGenerator
datagen = ImageDataGenerator(
rotation_range=10, # randomly rotate images in the range (degrees, 0 to 180) # 随机选择一个角度
zoom_range = 0.1, # Randomly zoom image # 随机变焦图像
width_shift_range=0.1, # randomly shift images horizontally (fraction of total width) # 随机水平平移
height_shift_range=0.1, # randomly shift images vertically (fraction of total height) # 随机垂直平移
horizontal_flip=True, # randomly flip images horizontally # 允许水平翻转,因为有左右手
vertical_flip=False) # Don't randomly flip images vertically # 不允许垂直翻转,因为垂直翻转可能改变手势的含义
## ==========将数据拟合到生成器===========
datagen.fit(x_train)
## =========模型编译==========
model.compile(loss='categorical_crossentropy', metrics=['accuracy'])
## ===========使用增强数据进行模型训练==========
"""
1.使用 Keras 图像数据生成器时,模型的训练略有不同:我们不将 x_train 和 y_train 数据集传送至模型中,而是传给生成器,并调用 flow 方法。
这使得图像在传入模型以供训练之前即可实时得到增强并存储在内存中。
2.生成器可以提供无限量的数据,所以当我们使用它们来训练我们的模型时,我们需要明确设置我们希望每次训练运行多长时间。
否则,生成器将产生无限多个增强图像提供给模型,使得该次训练可以无限期地进行下去。
3.我们使用名为steps_per_epoch的参数明确设置了每次训练要运行多长时间。
因为通常steps * batch_size = number_of_images_trained in an epoch,
所以我们在这里将步数设置为等于非增量数据集的大小除以batch_size(默认值为32)。
"""
model.fit(datagen.flow(x_train,y_train, batch_size=32), # Default batch_size is 32. We set it here for clarity.
epochs=20,
steps_per_epoch=len(x_train)/32, # Run same number of steps we would if we were not using a generator.
validation_data=(x_valid, y_valid))
# ========保存模型===========
model.save('asl_model')
## ============在(新环境)中载入模型==============
from tensorflow import keras
model = keras.models.load_model('asl_model')
## ===========方法定义=============
def show_image(image_path):
image = mpimg.imread(image_path)
plt.imshow(image)
def load_and_scale_image(image_path):
image = image_utils.load_img(image_path, color_mode="grayscale", target_size=(28,28))
return image
def alpha_dict():
alpha="abcdefghiklmnopqrstuvwxy"
dictionary = {}
for i in range(24):
dictionary[i] = alphabet[i]
return dictionary
# 定义预测函数
def predict_letter(file_path):
show_image(file_path) # 查看原图像
image = load_and_scale_image(file_path) # 载入图像并缩放
image = image_utils.img_to_array(image) # 将样本转换成array
image = image.reshape(1,28,28,1) # 重塑样本结构
image = image/255 # 归一化
prediction = model.predict(image) # 预测
# convert prediction to letter
dictionary = alpha_dict()
predicted_letter = dictionary[np.argmax(prediction)]
return predicted_letter
# 预测b.png这张图片对应的字母
predict_letter("b.png")