說明
- 在前一個案例中,我們構建了CNN網絡模型,此架構的設計目的在于識別圖像中的重要特征,因而它極大提高了模型的性能。但我們的驗證準確率仍落后于訓練準確率,這意味著我們的模型依然有點過擬合。
- 為了增強模型在處理新數據時的魯棒性,我們將以編程方式增加數據集的大小和差異。這稱為數據增強,是對很多深度學習應用都非常有用的技術。
- 數據的增加讓模型在訓練時能看到更多圖像。數據差異的增加可幫助模型忽略不重要的特征,而只選擇在分類時真正重要的特征。如此一來,在面對新數據時,模型有望在進行預測時更好地泛化。
模型訓練+保存+預測
-
載入數據數據載入與處理
-
搭建模型搭建CNN網絡
-
數據增強(通過認為差異化數據、增加噪聲,一方面能夠預防過擬合,另一方面能夠提升模型魯棒性)數據增強
-
數據擬合與模型編譯編譯
-
模型訓練(驗證集上的精度幾乎與訓練集上的一樣,表明該模型的性能優異)模型訓練
-
模型保存(這一步會將模型保存到本地,這個模型在本地是一個文件,可以將這個模型遷移到其他機器上進行預測)模型保存
-
載入模型并預測(這里假設在一臺新的計算機中載入了我們保存的模型)載入模型
-
載入并查看預測數據image.png
-
定義載入圖像的方法對圖像進行預處理預處理函數
-
測試樣本預測(到此,預測過程本質上已經結束)預測
- 對預測過程進行整理
-
生成一個標簽與字母對應的字典字典
-
定義一個預測函數預測函數
-
實施預測
預測b -
實施預測預測a
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")