甘 麗
(馬鞍山師范高等專科學校,安徽 馬鞍山 243041)
目標識別與分類一直是計算機視覺領域重要的一個應用方向,早期的利用尺度不變特征變換[1]、利用方向梯度直方圖等方法因其不能支持太大的數據規模,模型的泛化能力較差,目標檢測技術的發展受到一定限制[1]。神經網絡在機器學習中的提出,使得目標檢測有了新的發展,但受計算機性能限制,其理論存在解釋性差,訓練時間長等缺點。90年代中期,支持向量機、邏輯回歸等機器學習算法的興起也對神經網絡的發展帶來重大打擊。然而,隨著計算機性能的提高,2006年Hinton教授等人提出深度學習概念,讓目標檢測領域有了新的希望與發展。Chen等人提出利用深度學習原理在SAR(Synthetic Aperture Radar)圖像上實現目標識別,在MSTAR數據集上的實驗取得了良好的效果[2]。目標識別技術被廣泛應用于人臉識別、自動駕駛、安防監控等各個領域。
通過研究卷積神經網絡原理,分析VGG算法模型并進行遷移學習,在車輛類型的目標檢測中成功應用。文中描述了實現車輛品牌類別目標檢測的關鍵步驟,對圖像目標檢測的應用開發有積極參考作用。
在道路目標檢測領域,檢測不同種類的車輛如貨車、小汽車、行人、騎行人等已有不少成熟的研究[3],本課題主要研究利用遷移學習的方法對檢測目標進一步細化,檢測各種不同品牌的小汽車,為道路交通中的目標檢測提供積極的參考作用。采用卷積神經網絡VGG16模型來解決10個車輛品類的目標檢測問題,利用VGG網絡的預訓練模型,對其進行微調,建立自己的網絡結構,通過訓練集數據對模型進行訓練得到目標模型,然后利用目標模型對測試集數據進行預測,模型學習檢測流程如圖1所示。

圖1 模型學習檢測流程圖
在計算機視覺領域,圖像特征數量會對神經網絡效果產生較大壓力,使用卷積神經網絡能很好解決此問題。卷積神經網絡有一個或多個卷積層、池化層以及全連接層等組成[4]。卷積神經網絡結構圖如圖2所示。

圖2 卷積神經網絡結構圖
卷積層的作用是提取輸入的不同特征,主要參數有卷積核Size的大小,padding-零填充,stride步長等。通過卷積層的計算能在提取特征的同時不減少圖片特征數量,但在最后的全連接層依然面臨大量參數,所以需要池化層進行特征數量的減少。
池化層的作用是對卷積層學習到的特征圖進行亞采樣處理,池化方式主要有最大池化和平均池化兩種,目的是為了降低后續網絡層的輸入維度,縮減模型大小,提高計算速度。
卷積層、激活層、池化層可以看成是學習特征提取層,而學習到的特征最終應用于模型任務需要先對所有特征圖扁平化處理,再接一個或多個全連接層,進行模型學習[5]。
VGG是非常經典的卷積神經網絡模型,該模型結構清晰,層參數簡單。因其有13個卷積層和3個全連接層,也被稱為VGG16模型。所有卷積層都采用小卷積核(3*3),步長為1,所有池化層都采用2*2池化,步長為2。
模型的訓練主要包括模型的訓練步驟和數據增強。
1.2.1 目標模型訓練的步驟
目標模型的訓練分為2個階段:預訓練階段和訓練集階段。預訓練的VGGNet是在AlexNet的基礎上反復堆疊3*3的小型卷積核和2*2的最大池化層,不斷加深網絡結構,在CIFAR10的數據集上進行訓練。訓練集階段:在預訓練的模型的基礎上,修改最后輸出結構,利用自制數據集對剩余網絡結構進行訓練,最后對網絡模型進行參數微調。實驗的目標模型中,預訓練模型引用TensorFlow提供的VGG16模型,目標模型的訓練過程如圖3所示。

圖3 目標模型訓練圖
1.2.2 數據增強
在深度學習中,對輸入數據進行數據增強,可以豐富圖像的訓練集,更好地提取圖像特征,泛化模型,數據增強還有一個很重要的作用是可以將圖片轉化成符合算法的大小要求,比如YOLO算法中圖片大小都要變換成448×448。
數據增強一般是通過剪切、旋轉、縮放變化、尺度變換、顏色變換等一種或多種組合數據增強變換的方式來增加數據集的大小[6]。
實驗中,因采集的圖片數量沒有足夠大,需要減少數據集中不相關特征的數量。對于實驗中的汽車分類器來說,將現有數據集中照片翻轉獲得新的數據集。通過增強數據集,可以有效防止神經網絡學習到不相關的模式,提升效果。
利用Keras框架里面已經訓練好的VGG16模型,對其進行微調,來做本研究中車輛類別的遷移學習實踐。
使用一個ImageDataGenerator圖片生成器,定義圖片處理以及數據增強相關功能,主要實現代碼如下:def __init__(self):
# 1.實例化圖片生成器
# rescale:做歸一化
self.train_generator = ImageDataGenerator(rescale=1. / 255)
self.test_generator = ImageDataGenerator(rescale=1. / 255)
# 指定讀取數據的相關參數
self.train_dir = “./data/train”
self.test_dir = “./data/test”
self.model_size = (224, 224)
self.batch_size = 32
# 定義基礎模型VGG(沒有最后三個全連接層的結構)
self.base_model = VGG16(weights=“imagenet”, include_top=False)
def read_local_data(self):
# 讀取訓練數據集構造gen目標值格式
# 輸入到VGG的形狀
# 目標值的類型
train_gen = self.train_generator.flow_from_directory(directory=self.train_dir,#讀取目錄
target_size=self.model_size,#目標形狀
class_mode=“binary”,#目標值格式
batch_size=self.batch_size,#批數量大小(樣本批次)
shuffle=True)#讀取的時候打亂數據
test_gen = self.test_generator.flow_from_directory(directory=self.test_dir,
target_size=self.model_size,
class_mode=“binary”,
batch_size=self.batch_size,shuffle=True)
return train_gen, test_gen
在不動VGG 輸出結果的基礎上,加上全局池化層和兩個全連接層,構建自己的模型,實現代碼如下:def refine_base_model(self):
x = self.base_model.outputs[0]
x = keras.layers.GlobalAveragePooling2D()(x)
#兩個全連接層1024, 5
x = keras.layers.Dense(1024,activation=tf.nn.relu)(x)
y_prediction = keras.layers.Dense(10,activation=tf.nn.softmax)(x)
#構建自己的model
model = Model(inputs=self.base_model.inputs, outputs=y_prediction)
return model
讓 VGG 結構當中的權重參數不參與訓練,代碼如下:
def freeze_base_model(self):
for layer in self.base_model.layers:
layer.trainable = False
return None
編譯(指定優化器,定義損失函數,定義準確率)、訓練模型,在遷移學習算法中,學習率初始化為較小的值:0.001,0.0001。因為是在已訓練好的模型基礎上更新,所以設置較小的學習率去學習。將訓練好的模型保存為h5文件格式,實現代碼如下:
def compile(self,transfer_model):
transfer_model.compile(optimizer=keras.optimizers.Adam(),
loss=keras.losses.sparse_categorical_crossentropy,
metrics=[“accuracy”])
def fit(self,model,train_gen,test_gen):
model.fit_generator(train_gen,epochs=30,validation_data=test_gen)
model.save_weights(“./Transfer.h5”)
采用的是TensorFlow平臺,利用Keras框架,采集的數據集的統計信息,如表1所列。

表1 訓練集和測試集的統計信息
通過實驗,典型測試結果如圖4所示。

圖4 典型的測試結果
在設置30個epoch后,10個車輛品類的訓練集精度達近95%,測試集平均精度也達到了近90%。具體精度如表2所示。

表2 各個數據集的訓練和測試精度值
在增加epoch為50、設置bath_size值為64,128后,訓練精度有所提升,但測試集精度并未明顯提升。
利用深度學習模型VGG解決車輛品類的目標檢測問題,采用VGG16模型結構, 以ImageNet預訓練卷積層,固定卷積層用自建的車輛品類訓練集對剩余網絡進行預訓練;通過加上池化層和兩個全連接層來微調網絡結構,構建自己的模型;指定優化器,定義損失函數,定義準確率后編譯訓練,形成Transfer.h5模型文件。實驗結果表明:深度學習算法能很好的提高模型泛化能力,模型在10個品類的測試集上準確率達到近90%。