目錄
摘要
訓練
第一步 導入需要的資料包,設定全局參數
第二步 加載圖檔
第三步 圖像增強
第四步 保留最好的模型和動态設定學習率
第五步 建立模型并訓練
第六步 保留訓練結果,并将其生成圖檔
完整代碼:
測試部分
1、導入依賴
2、設定全局參數
3、加載模型
4、處理圖檔
5、預測類别
完整代碼
本例提取了貓狗大戰資料集中的部分資料做資料集,示範tensorflow2.0以上的版本如何使用Keras實作圖像分類,分類的模型使用DenseNet121。
import numpy as np
from tensorflow.keras.optimizers import Adam
import cv2
from tensorflow.keras.preprocessing.image import img_to_array
from sklearn.model_selection import train_test_split
from tensorflow.python.keras.callbacks import ModelCheckpoint, ReduceLROnPlateau
from tensorflow.keras.applications.densenet import DenseNet121
import os
from tensorflow.keras.models import load_model
這裡可以看出tensorflow2.0以上的版本內建了Keras,我們在使用的時候就不必單獨安裝Keras了,以前的代碼更新到tensorflow2.0以上的版本将keras前面加上tensorflow即可。tensorflow說完了,再說明一下幾個重要的全局參數
norm_size = 100 設定輸入圖像的大小,圖像的大小根據自己的需求設定,别太大,夠用就行了。
datapath = 'data/train' 設定圖檔存放的路徑,在這裡要說明一下如果圖檔很多,一定不要放在工程目錄下,否則Pycharm加載工程的時候會浏覽所有的圖檔,很慢很慢。
EPOCHS = 100 epochs的數量,關于epoch的設定多少合适,這個問題很糾結,一般情況設定300足夠了,如果感覺沒有訓練好,再載入模型訓練。
INIT_LR = 1e-3 學習率,一般情況從0.001開始逐漸降低,也别太小了到1e-6就可以了。
classnum = 2 類别數量,資料集有兩個類别,所有就分為兩類。
batch_size = 16 batchsize,根據硬體的情況和資料集的大小設定,太小了抖的厲害,太大了收斂不好,根據經驗來,一般設定為2的次方。
處理圖像的步驟:
讀取圖像
用指定的大小去resize圖像。
将圖像轉為數組
圖像歸一化
标簽onehot(标簽要不要做onehot和選用的loss函數有關,本例選用的loss可以直接處理标簽,是以不用onehot)
具體做法詳見代碼:
labelList = []
dicClass = {'cat': 0, 'dog': 1}
def loadImageData():
imageList = []
listImage = os.listdir(datapath)
for img in listImage:
labelName = dicClass[img.split('.')[0]]
print(labelName)
labelList.append(labelName)
dataImgPath = os.path.join(datapath, img)
print(dataImgPath)
image = cv2.imdecode(np.fromfile(dataImgPath, dtype=np.uint8), -1)
image = cv2.resize(image, (norm_size, norm_size), interpolation=cv2.INTER_LANCZOS4)
image = img_to_array(image)
imageList.append(image)
imageList = np.array(imageList, dtype="int") / 255.0
return imageList
print("開始加載資料")
imageArr = loadImageData()
labelList = np.array(labelList)
print("加載資料完成")
做好資料之後,我們需要切分訓練集和測試集,一般按照4:1的比例來切分。切分資料集使用train_test_split()方法,需要導入from sklearn.model_selection import train_test_split 包。例:
trainX, valX, trainY, valY = train_test_split(imageArr, labelList, test_size=0.2, random_state=42)
ImageDataGenerator()是keras.preprocessing.image子產品中的圖檔生成器,同時也可以在batch中對資料進行增強,擴充資料集大小,增強模型的泛化能力。比如進行旋轉,變形,歸一化等等。
keras.preprocessing.image.ImageDataGenerator(featurewise_center=False,samplewise_center
=False, featurewise_std_normalization=False, samplewise_std_normalization=False,zca_whitening=False,
zca_epsilon=1e-06, rotation_range=0.0, width_shift_range=0.0, height_shift_range=0.0,brightness_range=None, shear_range=0.0, zoom_range=0.0,channel_shift_range=0.0, fill_mode='nearest', cval=0.0, horizontal_flip=False, vertical_flip=False, rescale=None, preprocessing_function=None,data_format=None,validation_split=0.0)
參數:
featurewise_center: Boolean. 對輸入的圖檔每個通道減去每個通道對應均值。
samplewise_center: Boolan. 每張圖檔減去樣本均值, 使得每個樣本均值為0。
featurewise_std_normalization(): Boolean()
samplewise_std_normalization(): Boolean()
zca_epsilon(): Default 12-6
zca_whitening: Boolean. 去除樣本之間的相關性
rotation_range(): 旋轉範圍
width_shift_range(): 水準平移範圍
height_shift_range(): 垂直平移範圍
shear_range(): float, 透視變換的範圍
zoom_range(): 縮放範圍
fill_mode: 填充模式, constant, nearest, reflect
cval: fill_mode == 'constant'的時候填充值
horizontal_flip(): 水準反轉
vertical_flip(): 垂直翻轉
preprocessing_function(): user提供的處理函數
data_format(): channels_first或者channels_last
validation_split(): 多少資料用于驗證集
本例使用的圖像增強代碼如下:
train_datagen = ImageDataGenerator(featurewise_center=True,
featurewise_std_normalization=True,
rotation_range=20,
width_shift_range=0.2,
height_shift_range=0.2,
horizontal_flip=True)
val_datagen = ImageDataGenerator() # 驗證集不做圖檔增強
train_generator = train_datagen.flow(trainX, trainY, batch_size=batch_size, shuffle=True)
val_generator = val_datagen.flow(valX, valY, batch_size=batch_size, shuffle=True)
ModelCheckpoint用來儲存成績最好的模型。
文法如下:
keras.callbacks.ModelCheckpoint(filepath, monitor='val_loss', verbose=0, save_best_only=False, save_weights_only=False, mode='auto', period=1)
該回調函數将在每個epoch後儲存模型到filepath
filepath可以是格式化的字元串,裡面的占位符将會被epoch值和傳入on_epoch_end的logs關鍵字所填入
例如,filepath若為weights.{epoch:02d-{val_loss:.2f}}.hdf5,則會生成對應epoch和驗證集loss的多個檔案。
參數
filename:字元串,儲存模型的路徑
monitor:需要監視的值
verbose:資訊展示模式,0或1
save_best_only:當設定為True時,将隻儲存在驗證集上性能最好的模型
mode:‘auto’,‘min’,‘max’之一,在save_best_only=True時決定性能最佳模型的評判準則,例如,當監測值為val_acc時,模式應為max,當檢測值為val_loss時,模式應為min。在auto模式下,評價準則由被監測值的名字自動推斷。
save_weights_only:若設定為True,則隻儲存模型權重,否則将儲存整個模型(包括模型結構,配置資訊等)
period:CheckPoint之間的間隔的epoch數
ReduceLROnPlateau當評價名額不在提升時,減少學習率,文法如下:
keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=10, verbose=0, mode='auto', epsilon=0.0001, cooldown=0, min_lr=0)
當學習停滞時,減少2倍或10倍的學習率常常能獲得較好的效果。該回調函數檢測名額的情況,如果在patience個epoch中看不到模型性能提升,則減少學習率
monitor:被監測的量
factor:每次減少學習率的因子,學習率将以lr = lr*factor的形式被減少
patience:當patience個epoch過去而模型性能不提升時,學習率減少的動作會被觸發
mode:‘auto’,‘min’,‘max’之一,在min模式下,如果檢測值觸發學習率減少。在max模式下,當檢測值不再上升則觸發學習率減少。
epsilon:門檻值,用來确定是否進入檢測值的“平原區”
cooldown:學習率減少後,會經過cooldown個epoch才重新進行正常操作
min_lr:學習率的下限
本例代碼如下:
checkpointer = ModelCheckpoint(filepath='weights_best_ densenet _model.hdf5',
monitor='val_accuracy', verbose=1, save_best_only=True, mode='max')
reduce = ReduceLROnPlateau(monitor='val_accuracy', patience=10,
verbose=1,
factor=0.5,
min_lr=1e-6)
model = DenseNet121 (weights=None, classes=classnum)
optimizer = Adam(lr=INIT_LR)
model.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', metrics=['accuracy'])
history = model.fit_generator(train_generator,
steps_per_epoch=trainX.shape[0] / batch_size,
validation_data=val_generator,
epochs=EPOCHS,
validation_steps=valX.shape[0] / batch_size,
callbacks=[checkpointer, reduce],
verbose=1, shuffle=True)
model.save('my_model_ densenet.h5')
loss_trend_graph_path = r"WW_loss.jpg"
acc_trend_graph_path = r"WW_acc.jpg"
import matplotlib.pyplot as plt
print("Now,we start drawing the loss and acc trends graph...")
# summarize history for accuracy
fig = plt.figure(1)
plt.plot(history.history["accuracy"])
plt.plot(history.history["val_accuracy"])
plt.title("Model accuracy")
plt.ylabel("accuracy")
plt.xlabel("epoch")
plt.legend(["train", "test"], loc="upper left")
plt.savefig(acc_trend_graph_path)
plt.close(1)
# summarize history for loss
fig = plt.figure(2)
plt.plot(history.history["loss"])
plt.plot(history.history["val_loss"])
plt.title("Model loss")
plt.ylabel("loss")
plt.savefig(loss_trend_graph_path)
plt.close(2)
norm_size = 100
datapath = 'data/train'
EPOCHS = 100
INIT_LR = 1e-3
classnum = 2
batch_size = 16
print(labelList)
model = DenseNet121(weights=None, classes=classnum)
trainX, valX, trainY, valY = train_test_split(imageArr, labelList, test_size=0.3, random_state=42)
from tensorflow.keras.preprocessing.image import ImageDataGenerator
checkpointer = ModelCheckpoint(filepath='weights_best_Deset_model.hdf5',
model.save('my_model_Desnet.h5')
print(history)
print("We are done, everything seems OK...")
# #windows系統設定10關機
os.system("shutdown -s -t 10")
import time
norm_size=100
imagelist=[]
emotion_labels = {undefined
0: 'cat',
1: 'dog'
}
emotion_classifier=load_model("my_model_Desnet.h5")
t1=time.time()
image = cv2.imdecode(np.fromfile('test/8.jpg', dtype=np.uint8), -1)
# load the image, pre-process it, and store it in the data list
image = cv2.resize(image, (norm_size, norm_size), interpolation=cv2.INTER_LANCZOS4)
image = img_to_array(image)
imagelist.append(image)
imageList = np.array(imagelist, dtype="float") / 255.0
pre=np.argmax(emotion_classifier.predict(imageList))
emotion = emotion_labels[pre]
t2=time.time()
print(emotion)
t3=t2-t1
print(t3)
emotion_labels = {