本次專案首先使用CNN卷積神經網路模型進行訓練,最終訓練效果不太理想,出現了過擬合的情況,準確率達到0.72,loss達到0.54,使用預訓練的VGG模型后,在測驗集上準確率達到0.91,取得了不錯的改進效果,
資料集
本次專案使用The Asirra 資料集,Asirra(Animal Species Image Recognition for Restricting Access)是一套人機互動證明系統(Human Interactive Proof),它使用貓和狗的圖片來驗證網站訪問者是真人還是機器人,
Asirra使用的貓狗圖片來自于世界上最大的流浪動物救助網站petfinder.com,圖片被數千個流浪動物救助者進行手動分類和標準,它也為微軟研究院提供了超過300萬張貓狗圖片,
我們使用的資料集包含25000張已標注的貓狗圖片,和12500張未標注的測驗圖片,
資料處理
由于測驗資料集的圖片沒有標簽,所以我們從訓練集中劃出一部分作為測驗集,
import numpy as np
import pandas as pd
from keras.preprocessing.image import ImageDataGenerator, load_img
from tensorflow.keras.utils import to_categorical
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import random
import os
filenames= os.listdir("./train")
categories=[]
for filename in filenames:
#從檔案名中分離標簽,0代表貓,1代表狗
category=filename.split(".")[0]
if category=="dog":
categories.append(1)
else:
categories.append(0)
df=pd.DataFrame({'filename':filenames,
'category':categories
})
df.shape #(25000,2)
df.head()
隨機展示一張圖片,
random_Img=random.choice(filenames)
image=load_img("./train/"+random_Img)
plt.imshow(image)

我們也可以發現資料集中的圖片尺寸并不一致,有些圖片中的貓狗太小不足以識別,或者只露了部分部位,這些都是屬于質量不高的資料,

卷積神經網路
我們嘗試使用卷積神經網路來進行模型訓練
from keras.models import Sequential
from keras.layers import Conv2D, MaxPooling2D, Dropout, Flatten, Dense, Activation, BatchNormalization
model1 = Sequential()
model1.add(Conv2D(128, (3, 3), activation='relu', input_shape=(128,128,3)))
model1.add(BatchNormalization())
model1.add(MaxPooling2D(pool_size=(2, 2)))
model1.add(Dropout(0.25))
model1.add(Conv2D(64, (3, 3), activation='relu'))
model1.add(BatchNormalization())
model1.add(MaxPooling2D(pool_size=(2, 2)))
model1.add(Dropout(0.25))
model1.add(Conv2D(64, (3, 3), activation='relu'))
model1.add(BatchNormalization())
model1.add(MaxPooling2D(pool_size=(2, 2)))
model1.add(Dropout(0.25))
model1.add(Flatten())
model1.add(Dense(512, activation='relu'))
model1.add(BatchNormalization())
model1.add(Dropout(0.2))
model1.add(Dense(2, activation='softmax')) # 2 because we have cat and dog classes
model1.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
使用sklearn的train_test_split把資料集劃分為訓練集和測驗集,測驗集的比例test_size設定為0.20,亂數種子random_state設定為任意整數,這樣不管重復多少次劃分結果都是一致的,該函式默認引數 shuffle為True,對資料集進行隨機打散,
train_df,validate_df=train_test_split(df,test_size=.20,random_state=4)
train_df=train_df.reset_index(drop=True)
validate_df=validate_df.reset_index(drop=True)
total_train=train_df.shape[0]
total_validate=validate_df.shape[0] #5000
batch_size=16
資料增強
為了避免過擬合,增加我們的訓練資料集大小,通過對圖片進行旋轉、移位、縮放、亮度改變、色調改變、增加噪音等轉換成一張與已有圖片類似但卻稍有不同的新圖片,對于人眼來說這些圖片很相似,但是對于一個未訓練完成的機器學習模型來說卻是不同的,卷積神經網路可以學習圖片的細節特征,對于旋轉、移位等具有不變性,通過資料增強可以強化我們訓練出的模型的魯棒性,
keras中提供了ImageDataGenerator類來進行影像資料增強,可以在訓練程序中進行影像的隨機變化,增加訓練資料;還附帶贈送了獲取資料batch生成器物件的功能,省去了手工再去獲取batch資料的部分,該類可以對影像進行多種變換操作,默認的初始化引數如下:
# keras/preprocessing/image.py
class ImageDataGenerator(image.ImageDataGenerator):
def __init__(self,
featurewise_center=False,
samplewise_center=False,
featurewise_std_normalization=False,
samplewise_std_normalization=False,
zca_whitening=False,
zca_epsilon=1e-6,
rotation_range=0,
width_shift_range=0.,
height_shift_range=0.,
brightness_range=None,
shear_range=0.,
zoom_range=0.,
channel_shift_range=0.,
fill_mode='nearest',
cval=0.,
horizontal_flip=False,
vertical_flip=False,
rescale=None,
preprocessing_function=None,
data_format=None,
validation_split=0.0,
dtype=None):
在這里我們對訓練資料進行旋轉、標準化、剪切范圍、縮放范圍、水平翻轉、寬度變換、高度變換,對測驗集的圖片就無需進行資料增強了,只需要按照訓練集一樣進行rescaling標準化,
ImageDataGenerator的flow_from_dataframe用于從pandas的DataFrame中載入圖片資料,同時自動進行資料增強和生成批資料,我們之前定義的tran_df,一列為圖片檔案名,一列為圖片對于的分類,傳入flow_from_dataframe后,會通過我們定義的dataframe、檔案路徑讀取圖片,target_size設定目標影像尺寸,batch_size則是批大小,x_col和y_col為dataframe中的圖片名和標簽列名稱,對于class_mode的設定,‘categorical’為one-hot編碼,該方法shuffle引數默認為True,即也默認打散資料,
train_datagen=ImageDataGenerator(
rotation_range=30,
rescale=1./255,
shear_range=0.4,
zoom_range=0.4,
horizontal_flip=True,
width_shift_range=0.4,
height_shift_range=0.4
)
train_generator=train_datagen.flow_from_dataframe(
train_df,
"./train",
x_col='filename',
y_col='category',
target_size=(128,128),
class_mode='categorical',
batch_size=batch_size
)
validate_datagen=ImageDataGenerator(
rescale=1./255
)
validate_generator=validate_datagen.flow_from_dataframe(
validate_df,
"./train",
x_col='filename',
y_col='category',
target_size=(128,128),
class_mode='categorical',
batch_size=batch_size
)
回呼函式callback
回呼函式是一個函式的合集,會在訓練的階段中所使用,你可以使用回呼函式來查看訓練模型的內在狀態和統計,你可以傳遞一個串列的回呼函式(作為 callbacks 關鍵字引數)到 Sequential 或 Model 型別的 .fit() 方法,在訓練時,相應的回呼函式的方法就會被在各自的階段被呼叫,通過定義回呼函式,我們可以檢測訓練程序并在符合條件時執行我們的回呼函式,
EarlyStop用于監測定義的指標,當它不再提升時就停止訓練,用于在訓練中監測loss指標,防止過擬合,
EarlyStopping
keras.callbacks.EarlyStopping(monitor='val_loss', min_delta=0, patience=0, verbose=0, mode='auto', baseline=None, restore_best_weights=False)
當被監測的數量不再提升,則停止訓練,
引數
monitor: 被監測的資料,
min_delta: 在被監測的資料中被認為是提升的最小變化, 例如,小于 min_delta 的絕對變化會被認為沒有提升,
patience: 沒有進步的訓練輪數,在這之后訓練就會被停止,
verbose: 詳細資訊模式,
mode: {auto, min, max} 其中之一, 在 min 模式中, 當被監測的資料停止下降,訓練就會停止;在 max 模式中,當被監測的資料停止上升,訓練就會停止;在 auto 模式中,方向會自動從被監測的資料的名字中判斷出來,
baseline: 要監控的數量的基準值, 如果模型沒有顯示基準的改善,訓練將停止,
restore_best_weights: 是否從具有監測數量的最佳值的時期恢復模型權重, 如果為 False,則使用在訓練的最后一步獲得的模型權重,
ReduceLROnPlateau用于評估當模型停止提升時降低學習率,
keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=10, verbose=0, mode='auto', min_delta=0.0001, cooldown=0, min_lr=0)
當標準評估停止提升時,降低學習速率,
當學習停止時,模型總是會受益于降低 2-10 倍的學習速率, 這個回呼函式監測一個資料并且當這個資料在一定「有耐心」的訓練輪之后還沒有進步, 那么學習速率就會被降低,
例子
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.2,
patience=5, min_lr=0.001)
model.fit(X_train, Y_train, callbacks=[reduce_lr])
引數
monitor: 被監測的資料,
factor: 學習速率被降低的因數,新的學習速率 = 學習速率 * 因數
patience: 沒有進步的訓練輪數,在這之后訓練速率會被降低,
verbose: 整數,0:安靜,1:更新資訊,
mode: {auto, min, max} 其中之一,如果是 min 模式,學習速率會被降低如果被監測的資料已經停止下降; 在 max 模式,學習塑料會被降低如果被監測的資料已經停止上升; 在 auto 模式,方向會被從被監測的資料中自動推斷出來,
min_delta: 對于測量新的最優化的閥值,只關注巨大的改變,
cooldown: 在學習速率被降低之后,重新恢復正常操作之前等待的訓練輪數量,
min_lr: 學習速率的下邊界,
在這里我們定義Early Stopping的patience為10,即val_loss十輪訓練后沒有下降則訓練停止,定義ReduceLROnPlateau的監測引數monitor為'val_acc'即驗證集的accuracy,patience為2,減小因子為0.5(學習率每次更次為上次的0.5),學習率下邊界為0.00001(學習率降到0.00001后不再下降),
from keras.callbacks import EarlyStopping, ReduceLROnPlateau
earlystop = EarlyStopping(patience=10)
learning_rate_reduction = ReduceLROnPlateau(monitor='val_acc',
patience=2,
verbose=1,
factor=0.5,
min_lr=0.00001)
callbacks = [earlystop, learning_rate_reduction]
訓練卷積神經網路模型
history1=model1.fit_generator(
train_generator,
steps_per_epoch=total_train//batch_size,
epochs=10,
verbose=1,
callbacks=callbacks,
validation_data=https://www.cnblogs.com/d42z/archive/2022/10/11/validate_generator,
validation_steps=total_validate//batch_size,
)
訓練程序如下:
加載預訓練VGG模型
TensorFlow為我們提供了預訓練的VGG模型,我們可以很方便的呼叫它,VGG預訓練模型在大規模影像資料集上訓練完成后,在影像識別和分類任務上表現良好,我們可以使用預訓練模型進行遷移學習(transfer learning),在類似的圖片識別任務上取得良好的效果,
from tensorflow.keras.applications import VGG16
from keras.models import Model
from keras.layers import Dense,Dropout
from keras.backend import pool2d
from keras.layers.pooling import GlobalAveragePooling2D
base_model = VGG16(input_shape = (128, 128, 3), # Shape of our images
include_top = False, # Leave out the last fully connected layer
weights = 'imagenet')
我們不需要訓練VGG模型,可以以它為基礎,添加更多的隱藏層,只有后面被添加的層才會被訓練,我們在VGG模型的基礎上添加了輸出為512維的全連接層,一個平均池化層,一個rate為0.5的Dropout層,一個softmax全連接層,
base_model.trainable=False
model=base_model.output
model=Dense(512, activation='relu')(model)
model= GlobalAveragePooling2D()(model)
model=Dropout(rate=0.5)(model)
model=Dense(2, activation='softmax')(model)
model=Model(inputs=base_model.inputs, outputs=model)
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
model.summary()
定義好后的模型結構如下:
Model: "model"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(None, 128, 128, 3)] 0
_________________________________________________________________
block1_conv1 (Conv2D) (None, 128, 128, 64) 1792
_________________________________________________________________
block1_conv2 (Conv2D) (None, 128, 128, 64) 36928
_________________________________________________________________
block1_pool (MaxPooling2D) (None, 64, 64, 64) 0
_________________________________________________________________
block2_conv1 (Conv2D) (None, 64, 64, 128) 73856
_________________________________________________________________
block2_conv2 (Conv2D) (None, 64, 64, 128) 147584
_________________________________________________________________
block2_pool (MaxPooling2D) (None, 32, 32, 128) 0
_________________________________________________________________
block3_conv1 (Conv2D) (None, 32, 32, 256) 295168
_________________________________________________________________
block3_conv2 (Conv2D) (None, 32, 32, 256) 590080
_________________________________________________________________
block3_conv3 (Conv2D) (None, 32, 32, 256) 590080
_________________________________________________________________
block3_pool (MaxPooling2D) (None, 16, 16, 256) 0
_________________________________________________________________
block4_conv1 (Conv2D) (None, 16, 16, 512) 1180160
_________________________________________________________________
block4_conv2 (Conv2D) (None, 16, 16, 512) 2359808
_________________________________________________________________
block4_conv3 (Conv2D) (None, 16, 16, 512) 2359808
_________________________________________________________________
block4_pool (MaxPooling2D) (None, 8, 8, 512) 0
_________________________________________________________________
block5_conv1 (Conv2D) (None, 8, 8, 512) 2359808
_________________________________________________________________
block5_conv2 (Conv2D) (None, 8, 8, 512) 2359808
_________________________________________________________________
block5_conv3 (Conv2D) (None, 8, 8, 512) 2359808
_________________________________________________________________
block5_pool (MaxPooling2D) (None, 4, 4, 512) 0
_________________________________________________________________
dense_2 (Dense) (None, 4, 4, 512) 262656
_________________________________________________________________
global_average_pooling2d (Gl (None, 512) 0
_________________________________________________________________
dropout_4 (Dropout) (None, 512) 0
_________________________________________________________________
dense_3 (Dense) (None, 2) 1026
=================================================================
Total params: 14,978,370
Trainable params: 263,682
Non-trainable params: 14,714,688
_________________________________________________________________
VGG模型訓練
與之前CNN網路模型訓練一樣,我們進行資料集的載入和處理,打散之后生成批訓練資料,
from sklearn.model_selection import train_test_split
from tqdm import tqdm
import cv2
from sklearn.utils import shuffle
df["category"] = df["category"].replace({0: 'cat', 1: 'dog'})
#進行資料集劃分交叉驗證
train_df, validate_df = train_test_split(df, test_size=0.20, random_state=42)
train_df = train_df.reset_index(drop=True)
validate_df = validate_df.reset_index(drop=True)
total_train = train_df.shape[0]
total_validate = validate_df.shape[0]
batch_size=4
#生成訓練資料
train_datagen=ImageDataGenerator(
rescale=1/255
)
train_generator=train_datagen.flow_from_dataframe(train_df,
'./train',
x_col='filename',
y_col='category',
weight_col=None,
target_size=(128, 128),
class_mode='categorical',
batch_size=batch_size,
)
#生成測驗資料
validation_datagen = ImageDataGenerator(rescale=1./255)
validation_generator = validation_datagen.flow_from_dataframe(
validate_df,
"./train",
x_col='filename',
y_col='category',
target_size=(128,128),
class_mode='categorical',
batch_size=batch_size
)
#定義回呼函式
earlystop = EarlyStopping(patience=10)
learning_rate_reduction = ReduceLROnPlateau(monitor='val_acc',
patience=2,
verbose=1,
factor=0.5,
min_lr=0.00001)
callbacks = [earlystop, learning_rate_reduction]
#進行模型訓練
history = model.fit_generator(
train_generator,
epochs=12,
validation_data=https://www.cnblogs.com/d42z/archive/2022/10/11/validation_generator,
validation_steps=total_validate//batch_size,
steps_per_epoch=total_train//batch_size,
callbacks=callbacks,
verbose=1
)
訓練的程序如下,最終在驗證集上accuracy達到0.91,
Epoch 1/12
5000/5000 [==============================] - 99s 20ms/step - loss: 0.3466 - accuracy: 0.8461 - val_loss: 0.2575 - val_accuracy: 0.8920
Epoch 2/12
5000/5000 [==============================] - 90s 18ms/step - loss: 0.2886 - accuracy: 0.8752 - val_loss: 0.2365 - val_accuracy: 0.8992
Epoch 3/12
5000/5000 [==============================] - 89s 18ms/step - loss: 0.2625 - accuracy: 0.8877 - val_loss: 0.2296 - val_accuracy: 0.9016
Epoch 4/12
5000/5000 [==============================] - 90s 18ms/step - loss: 0.2415 - accuracy: 0.8970 - val_loss: 0.2215 - val_accuracy: 0.9076
Epoch 5/12
5000/5000 [==============================] - 90s 18ms/step - loss: 0.2358 - accuracy: 0.9004 - val_loss: 0.2331 - val_accuracy: 0.8982
Epoch 6/12
5000/5000 [==============================] - 90s 18ms/step - loss: 0.2195 - accuracy: 0.9074 - val_loss: 0.2387 - val_accuracy: 0.9002
Epoch 7/12
5000/5000 [==============================] - 89s 18ms/step - loss: 0.2106 - accuracy: 0.9096 - val_loss: 0.2237 - val_accuracy: 0.9094
Epoch 8/12
5000/5000 [==============================] - 90s 18ms/step - loss: 0.2028 - accuracy: 0.9155 - val_loss: 0.2173 - val_accuracy: 0.9126
Epoch 9/12
5000/5000 [==============================] - 95s 19ms/step - loss: 0.1908 - accuracy: 0.9204 - val_loss: 0.2285 - val_accuracy: 0.9076
Epoch 10/12
5000/5000 [==============================] - 94s 19ms/step - loss: 0.1821 - accuracy: 0.9247 - val_loss: 0.2242 - val_accuracy: 0.9112
Epoch 11/12
5000/5000 [==============================] - 94s 19ms/step - loss: 0.1740 - accuracy: 0.9278 - val_loss: 0.2364 - val_accuracy: 0.9044
Epoch 12/12
5000/5000 [==============================] - 94s 19ms/step - loss: 0.1644 - accuracy: 0.9322 - val_loss: 0.2335 - val_accuracy: 0.9106
本文來自博客園,作者:d42z,轉載請注明原文鏈接:https://www.cnblogs.com/d42z/p/16779785.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/513703.html
標籤:其他
上一篇:Alien Skin Exposure X7 Bundle Mac/Win(ps/lr膠片濾鏡插件套裝)
下一篇:【原創】evmos玩法
