1.目標
本篇文章介紹的重點是如何使用TensorFlow在自己的圖像數據上訓練深度學習模型,主要涉及的方法是對已經預訓練好的ImageNet模型進行微調(Fine-tune)。使用谷歌的Colaboratory(python3 環境)實現。
2.微調原理
什么是微調?這里以VGG16為例進行講解。
如圖下圖所示,VGG16的結構為卷積+全連接層。卷積層分為5個部分共13層,即圖中的conv1~conv5。還有3層是全連接層,即圖中的fc6、fe7、fc8。卷積層加上全連接層合起來一共為16層,因此它被稱為VGG16。如果要將VGG16的結構用於一個新的數據集,首先要去掉fc8這一層。原因是fc8層的輸入是fc7層的特征,輸出是1000類的概率,這1000類正好對應了ImageNet 模型中的1000個類別。在自己的數據中,類別數一般不是1000類,因此fc8層的結構在此時是不適用的,必須將fc8層去掉,重新采用符合數據集類別數的全連接層,作為新的fe8。比如數據集為5類,那么新的fc8的輸出也應當是5類。

此外,在訓練的時候,網絡的參數的初始值並不是隨機化生成的,而是采用VGG16在ImageNet 上已經訓練好的參數作為訓練的初始值。這樣做的原因在於,在ImageNet數據集上訓練過的VGG16中的參數已經包含了大量有用的卷積過濾器,與其從零開始初始化VGG16的所有參數,不如使用已經訓練好的參數當作訓練的起點。這樣做不僅可以節約大量訓練時間,而且有助於分類器性能的提高。
載入VGG16的參數后,就可以開始訓練了。此時需要指定訓練層數的范圍。一般來說,可以選擇以下幾種范圍進行訓練:
- 只訓練fc8。訓練范圍一定要包含fc8這一層。之前說過,fc8的結構被調整過,因此它的參數不能直接從lmageNet預訓練模型中取得。可以只訓練fe8,保持其他層的參數不動。這就相當於將VGG16當作一個“特征提取器”:用fc7層提取的特征做一個Softmax模型分類。這樣做的好處是訓練速度快,但往往性能不會太好。
- 訓練所有參數。還可以對網絡中的所有參數進行訓練,這種方法的訓練速度可能比較慢,但是能取得較高的性能,可以充分發揮深度模型的威力。
- 訓練部分參數。通常是固定淺層參數不變,訓練深層參數。如固定 conv1、conv2部分的參數不訓練,只訓練 conv3、conv 4、conv 5、fc6、fc7、fc8的參數。
這種訓練方法就是所謂的對神經網絡模型做微調。借助微調,可以從預訓練模型出發,將神經網絡應用到自己的數據集上。下面介紹如何在TensorFlow中進行微調。
3.TensorFlow Slim 微調
TensorFlow Slim 是Google公司公布的一個圖像分類工具包,它不僅定義了一些方便的接口,還提供了很多ImageNet數據集上常用的網絡結構和預訓練模型。截至2017年7月,Slim提供包括VGG16、VGG19、Inception V1~V4、ResNet 50、ResNet 101、MobileNet在內大多數常用模型的結構以及預訓練模型,更多的模型還會被持續添加進來。
3.1 數據准備
首先要將自己的數據集切分為訓練集和驗證集,訓練集用於訓練模型,驗證集用來驗證模型的准確率。本次使用的是衛星圖片分類數據集,這個數據集一共有6個類別,見下表所示:
類別名 | 含義 |
---|---|
Wetland | 農田 |
Glacier | 冰川 |
Urban | 城市區域 |
Rock | 岩石 |
water | 水域 |
Wood | 森林 |
在data_prepare目錄中,用一個pic文件夾保存原始的圖像文件,圖像文件保存的結構如下:
data prepare/
pic/
train/
wood/
water/
rock/
wetland/
glacier/
urban/
validation/
wood/
water/
rock/
wetland/
glacier/
urban/
將圖片分為train
和validation
兩個目錄,分別表示訓練使用的圖片和驗證使用的圖片。在每個目錄中,分別以類別名為文件夾名保存所有圖像。在每個類別文件夾下,存放的就是原始的圖像(如jpg格式的圖像文件)。下面,在data_prepare文件夾下,使用預先編制好的腳本data_convert.py
,將圖片轉換為為tfrecord格式:
!python data_ convert.py -t pic/ \
--train-shards 2 \
--validation-shards 2 \
--num-threads 2 \
--dataset-name satellite
解釋這里參數的含義:
- -t pic/:表示轉換pic文件夾中的數據。pic文件夾中必須有一個train目錄和一個validation目錄,分別代表訓練和驗證數據集。每個目錄下按類別存放了圖像數據。
- --train-shards 2:將訓練數據集分為兩塊,即最后的訓練數據就是兩個tfrecord格式的文件。如果讀者的數據集較大,可以考慮將其分為更多的數據塊。
- --validation-shards 2:將驗證數據集分為兩塊。
- --num-threads 2:采用兩個線程產生數據。注意線程數必須要能整除train-shards 和validation-shards,來保證每個線程處理的數據塊數是相同的。
- --dataset-name satellite:給生成的數據集起一個名字。這里將數據集起名叫“satellite”,最后生成文件的開頭就是satelite_train 和satelite_validation。
運行上述命令后,就可以在pic文件夾中找到5個新生成的文件,分別是訓練數據 satellite_train_00000-of-00002.tfrecord、satellite_train_00001-of-00002.tfrecord,以及驗證數據 satellite validation_00000-of-00002.tfrecord、satellite validation_00001-of-00002.tfrecord。另外,還有一個文本文件label.txt,它表示圖片的內部標簽(數字)到真實類別(字符串)之間的映射順序。如圖片在tfrecord中的標簽為0,那么就對應label.txt 第一行的類別,在tfrecord的標簽為1,就對應label.txt中第二行的類別,依此類推。
3.2 下載TensorFlow Slim
如果需要使用Slim微調模型,首先要下載Slim的源代碼。Slim的源代碼保存在tensorflow/models項目中,可以使用下面的git命令下載tensorflow/models:
git clone https://github.com/tensorflow/models. git
找到models/research/目錄中的slim文件夾,這就是要用到的TensorFlow Slim的源代碼。這里簡單介紹TensorFlow Slim的代碼結構,見下表。
文件夾或文件名 | 用途 |
---|---|
datasets/ | 定義一些訓練時使用的數據集。如果需要訓練自己的數據,必須同樣在datasets文件夾中進行定義,會在下面對此進行介紹 |
nets/ | 定義了一些常用的網絡結構,如AlexNet、VGGl6、VGG19、Inception 系列、ResNet、MobileNet等 |
preprocessing/ | 在模型讀入圖片前,常常需要對圖像做預處理和數據增強。這個文件夾針對不同的網絡,分別定義了它們的預處理方法 |
scripts | 包含了一些訓練的示例腳本 |
train_ image_classifier.py | 訓練模型的入口代碼 |
eval_image_classifier.py | 驗證模型性能的入口代碼 |
download_and _convert data.py | 下載並轉換數據集格式的入口代碼 |
上表只列出了TensorFlow Slim中最重要的幾個文件以及文件夾的作用。其他還有少量文件和文件夾,如果讀者對它們的作用感興趣,可以自行參閱其文檔。
3.3 定義新的datasets文件
在slim/datasets中,定義了所有可以使用的數據庫,為了使用在第3.1節中創建的tfrecord數據進行訓練,必須要在datasets中定義新的數據庫。
首先,在datasets/目錄下新建一個文件satellite.py,並將flowers.py文件中的內容復制到satellite.py中。接下來,需要修改以下幾處內容。
第一處是_FILE_PATTERN
、SPLITS_TO_SIZES
、_NUM_CLASSES
,將其進行以下修改:
_FILE_PATTERN='satellite _%s*. tfrecord'
SPLTTS_TO_SIZES={' train:4800,' validation':1200}
_NUM_CLASSES=6
_FILE_PATTERN
變量定義了數據的文件名的格式和訓練集、驗證集的數量。
_NUM_CLASSES
變量定義了數據集中圖片的類別數目。
第二處修改為image/format部分,將之修改為:
'image/format': tf. FixedLenFeature((), tf. string, default_value ='jpg'),
此處定義了圖片的默認格式。收集的衛星圖片的格式為jpg圖片,因此修改為jpg。最后,讀者也可以對文件中的注釋內容進行合適的修改。修改完satellite.py后,還需要在同目錄的dataset_factory.py文件中注冊satellite數據庫。如下:
datasets_map={
'cifar10':cifarl0,
'flowers':flowers,
'imagenet':imagenet,
'satellite':satellite,}
3.4 准備訓練文件夾
定義完數據集后,在slim文件夾下再新建一個satellite目錄,在這個目錄中,完成最后的幾項准備工作:
- 新建一個data目錄,並將第3.1節中准備好的5個轉換好格式的訓練數據復制進去。
- 新建一個空的train_dir目錄,用來保存訓練過程中的日志和模型。
- 新建一個pretrained目錄,在slim的GitHub頁面找到InceptionV3模型的下載地址http:/download.tensorflow.org/models/inception_V3_2016_0828.tar.gz,下載並解壓后,會得到一個 inception_v3.ckpt文件,將該文件復制到pretrained目錄下。
3.5 開始訓練
在slim文件夾下,運行以下命令就可以開始訓練了:
!python train_image_classifier. py \
--train_dir=satellite/train_dir \
--dataset_name=satellite \
--dataset_split_name=train \
--model_name=inception_v3 \
--checkpoint_path=satellite/pretrained/inception_v3. ckpt \
--checkpoint_exclude_scopes=InceptionV3/Logits, InceptionV3/AuxLogits \
--trainable_scopes=InceptionV3/Logits, InceptionV3/AuxLogits \
--max_number_of steps=100000 \
--batch_size=32 \
--learning_rate=0.001 \
--learning_rate_decay_type=fixed \
--save_interval_secs=300 \
--save_summaries_secs=2 \
--log_every_n_steps=10 \
--optimizer=rmsprop \
--weight_decay=0.00004
這里的參數比較多,下面一一進行介紹:
- --trainable_scopes=InceptionV3/Logits,InceptionV3/AuxLogits:首先來解釋參數trainable_scopes的作用,因為它非常重要。trainable_scopes規定了在模型中微調變量的范圍。這里的設定表示只對InceptionV3/Logits,InceptionV3/AuxLogits 兩個變量進行微調,其他變量都保持不動。InceptionV3/Logits,InceptionV3/AuxLogits 就相當於在第2章中所講的fc8,它們是Inception V3的“末端層”。如果不設定trainable_scopes,就會對模型中所有的參數進行訓練。
- --train_dir-satellite/train_dir:表明會在satellite/train_dir目錄下保存日志和checkpoint。
- --dataset_name=satellite、--dataset_split_name=train:指定訓練的數據集。
--dataset_dir=satellite/data
:指定訓練數據集保存的位置。- --model_name=inception_v3:使用的模型名稱。
- --checkpoint_path=satellite/pretrained/inception_v3.ckpt:預訓練模型的保存位置。
- --checkpoint_exclude_scopes=InceptionV3/Logits,InceptionV3/AuxLogits:在恢復預訓練模型時,不恢復這兩層。正如之前所說,這兩層是InceptionV3模型的末端層,對應着ImageNet數據集的1000類,和當前的數據集不符,因此不要去恢復它。
- --max_number_of_steps=100000:最大的執行步數。
- --batch_size=32:每步使用的batch數量。
- ---learning_rate=0.001:學習率。
- --learning_rate_decay_type=fixed:學習率是否自動下降,此處使用固定的學習率。
- --save_interval_secs=300:每隔300s,程序會把當前模型保存到train_dir中。此處就是目錄satellite/train_dir。
- --save_summaries_secs=2:每隔2s,就會將日志寫入到train_dir中。可以用TensorBoard 查看該日志。此處為了方便觀察,設定的時間間隔較多,實際訓練時,為了性能考慮,可以設定較長的時間間隔。
- --log_every_n_steps=10:每隔10步,就會在屏幕上打出訓練信息。
- --optimizer=rmsprop:表示選定的優化器。
- --weight_decay=0.00004:選定的weight_decay值。即模型中所有參數的二次正則化超參數。
以上命令是只訓練未端層InceptionV3/Logits,InceptionV3/AuxLogits,還可以對所有層進行訓練:與只訓練末端層的命令相比,只有一處發生了變化,即去掉了--trainable_scopes
參數。
3.6 驗證模型准確率
在slim文件下執行下列命令:
!python eval_image_classifier.py \
--checkpoint_path=satellite/train_dir \
-eval_dir=satellite/eval_dir \
--dataset_name=satellite \
--dataset_split_name=validation \
--dataset_dir=satellite/data \
--model_name=inception_v3
這里參數的含義為:
- --checkpoint_path=satellite/train_dir:這個參數既可以接收一個目錄的路徑,也可以接收一個文件的路徑。如果接收的是一個目錄的路徑,如這里的satellite/train_dir,就會在這個目錄中尋找最新保存的模型文件,執行驗證。也可以指定一個模型進行驗證,以第300步的模型為例,在satellite/train_dir文件夾下它被保存為model.ckpt-300.meta、model.ckpt-300.index、model.ckpt-300.data-00000-of-00001三個文件。此時,如果要對它執行驗證,給checkpoint_path傳遞的參數應該為satellite/train_dir/model.ckpt-300。|
- --eval_dir-=satellite/eval_dir:執行結果的日志就保存在eval_dir中,同樣可以通過TensorBoard查看。
- --dataset_name=satellite、--dataset_split_name=validation:指定需要執行的數據集。注意此處是使用驗證集(validation)執行驗證。
- --dataset_dir=satellite/data:數據集保存的位置。
- --model_name=inception_v3:使用的模型。
執行后,應該會出現類似下面的結果:
eval/Accuracy[0.51]
eval/Recal1_5[0.97333336]
Accuracy 表示模型的分類准確率,而Recall_5表示Top5的准確率,如果不需要top5 。而需要top2或者top3准確率,只要在eval_image_classifier.py中修改下面的部分就可以了:
names_to_values, names_to_updates=slim. metrics. aggregate_metric map({
'Accuracy': slim. metrics. streaming_accuracy (predictions,labels),
'Recall_5': slim. metrics. streaming_recall_at_k(1ogits,labels,5),
})
4.代碼及數據集
百度網盤 提取碼:8qqt
5.補充
Colab等同於一個Linux的操作系統,如果你的電腦是windows,建議安裝一個cmder
,解壓以后就可以使用。cmder不僅可以使用windows下的所有命令,更爽的是可以使用Linux的命令,shell命令。安裝與配置參考:Windows命令行工具cmder配置