天天看點

ResNet實戰:tensorflow2.0以上版本,使用ResNet50實作圖像分類任務

目錄

摘要

訓練

第一步 導入需要的資料包,設定全局參數

第二步 加載圖檔

第三步 圖像增強

第四步 保留最好的模型和動态設定學習率

第五步 建立模型并訓練

第六步 保留訓練結果,并将其生成圖檔

完整代碼:

本例提取了貓狗大戰資料集中的部分資料做資料集,示範tensorflow2.0以上的版本如何使用Keras實作圖像分類,分類的模型使用ResNet50。

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.resnet import ResNet50

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_Reset50_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 = ResNet50(weights=None, classes=classnum)

optimizer = Adam(lr=INIT_LR)

model.compile(optimizer=optimizer, loss='sparse_categorical_crossentropy', metrics=['accuracy'])

model=load_model("my_model_resnet.h5")

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_resnet.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)

from tensorflow.keras.preprocessing.image import ImageDataGenerator

print(history)

print("We are done, everything seems OK...")

# #windows系統設定10關機

os.system("shutdown -s -t 10")