說(shuō)明
- 在前一個(gè)案例中,我們構(gòu)建了CNN網(wǎng)絡(luò)模型,此架構(gòu)的設(shè)計(jì)目的在于識(shí)別圖像中的重要特征,因而它極大提高了模型的性能。但我們的驗(yàn)證準(zhǔn)確率仍落后于訓(xùn)練準(zhǔn)確率,這意味著我們的模型依然有點(diǎn)過(guò)擬合。
- 為了增強(qiáng)模型在處理新數(shù)據(jù)時(shí)的魯棒性,我們將以編程方式增加數(shù)據(jù)集的大小和差異。這稱為數(shù)據(jù)增強(qiáng),是對(duì)很多深度學(xué)習(xí)應(yīng)用都非常有用的技術(shù)。
- 數(shù)據(jù)的增加讓模型在訓(xùn)練時(shí)能看到更多圖像。數(shù)據(jù)差異的增加可幫助模型忽略不重要的特征,而只選擇在分類時(shí)真正重要的特征。如此一來(lái),在面對(duì)新數(shù)據(jù)時(shí),模型有望在進(jìn)行預(yù)測(cè)時(shí)更好地泛化。
模型訓(xùn)練+保存+預(yù)測(cè)
-
載入數(shù)據(jù)數(shù)據(jù)載入與處理
-
搭建模型搭建CNN網(wǎng)絡(luò)
-
數(shù)據(jù)增強(qiáng)(通過(guò)認(rèn)為差異化數(shù)據(jù)、增加噪聲,一方面能夠預(yù)防過(guò)擬合,另一方面能夠提升模型魯棒性)數(shù)據(jù)增強(qiáng)
-
數(shù)據(jù)擬合與模型編譯編譯
-
模型訓(xùn)練(驗(yàn)證集上的精度幾乎與訓(xùn)練集上的一樣,表明該模型的性能優(yōu)異)模型訓(xùn)練
-
模型保存(這一步會(huì)將模型保存到本地,這個(gè)模型在本地是一個(gè)文件,可以將這個(gè)模型遷移到其他機(jī)器上進(jìn)行預(yù)測(cè))模型保存
-
載入模型并預(yù)測(cè)(這里假設(shè)在一臺(tái)新的計(jì)算機(jī)中載入了我們保存的模型)載入模型
-
載入并查看預(yù)測(cè)數(shù)據(jù)image.png
-
定義載入圖像的方法對(duì)圖像進(jìn)行預(yù)處理預(yù)處理函數(shù)
-
測(cè)試樣本預(yù)測(cè)(到此,預(yù)測(cè)過(guò)程本質(zhì)上已經(jīng)結(jié)束)預(yù)測(cè)
- 對(duì)預(yù)測(cè)過(guò)程進(jìn)行整理
-
生成一個(gè)標(biāo)簽與字母對(duì)應(yīng)的字典字典
-
定義一個(gè)預(yù)測(cè)函數(shù)預(yù)測(cè)函數(shù)
-
實(shí)施預(yù)測(cè)
預(yù)測(cè)b -
實(shí)施預(yù)測(cè)預(yù)測(cè)a
Code
## ============數(shù)據(jù)準(zhǔn)備===========
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)
## =============構(gòu)建模型==================
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"))
## ===========數(shù)據(jù)增強(qiáng)===========
from tensorflow.keras.preprocessing.image import ImageDataGenerator
datagen = ImageDataGenerator(
rotation_range=10, # randomly rotate images in the range (degrees, 0 to 180) # 隨機(jī)選擇一個(gè)角度
zoom_range = 0.1, # Randomly zoom image # 隨機(jī)變焦圖像
width_shift_range=0.1, # randomly shift images horizontally (fraction of total width) # 隨機(jī)水平平移
height_shift_range=0.1, # randomly shift images vertically (fraction of total height) # 隨機(jī)垂直平移
horizontal_flip=True, # randomly flip images horizontally # 允許水平翻轉(zhuǎn),因?yàn)橛凶笥沂? vertical_flip=False) # Don't randomly flip images vertically # 不允許垂直翻轉(zhuǎn),因?yàn)榇怪狈D(zhuǎn)可能改變手勢(shì)的含義
## ==========將數(shù)據(jù)擬合到生成器===========
datagen.fit(x_train)
## =========模型編譯==========
model.compile(loss='categorical_crossentropy', metrics=['accuracy'])
## ===========使用增強(qiáng)數(shù)據(jù)進(jìn)行模型訓(xùn)練==========
"""
1.使用 Keras 圖像數(shù)據(jù)生成器時(shí),模型的訓(xùn)練略有不同:我們不將 x_train 和 y_train 數(shù)據(jù)集傳送至模型中,而是傳給生成器,并調(diào)用 flow 方法。
這使得圖像在傳入模型以供訓(xùn)練之前即可實(shí)時(shí)得到增強(qiáng)并存儲(chǔ)在內(nèi)存中。
2.生成器可以提供無(wú)限量的數(shù)據(jù),所以當(dāng)我們使用它們來(lái)訓(xùn)練我們的模型時(shí),我們需要明確設(shè)置我們希望每次訓(xùn)練運(yùn)行多長(zhǎng)時(shí)間。
否則,生成器將產(chǎn)生無(wú)限多個(gè)增強(qiáng)圖像提供給模型,使得該次訓(xùn)練可以無(wú)限期地進(jìn)行下去。
3.我們使用名為steps_per_epoch的參數(shù)明確設(shè)置了每次訓(xùn)練要運(yùn)行多長(zhǎng)時(shí)間。
因?yàn)橥ǔteps * batch_size = number_of_images_trained in an epoch,
所以我們?cè)谶@里將步數(shù)設(shè)置為等于非增量數(shù)據(jù)集的大小除以batch_size(默認(rèn)值為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')
## ============在(新環(huán)境)中載入模型==============
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
# 定義預(yù)測(cè)函數(shù)
def predict_letter(file_path):
show_image(file_path) # 查看原圖像
image = load_and_scale_image(file_path) # 載入圖像并縮放
image = image_utils.img_to_array(image) # 將樣本轉(zhuǎn)換成array
image = image.reshape(1,28,28,1) # 重塑樣本結(jié)構(gòu)
image = image/255 # 歸一化
prediction = model.predict(image) # 預(yù)測(cè)
# convert prediction to letter
dictionary = alpha_dict()
predicted_letter = dictionary[np.argmax(prediction)]
return predicted_letter
# 預(yù)測(cè)b.png這張圖片對(duì)應(yīng)的字母
predict_letter("b.png")













