圖像識別模型


一、數據准備

  首先要做一些數據准備方面的工作:一是把數據集切分為訓練集和驗證集, 二是轉換為tfrecord 格式。在data_prepare/文件夾中提供了會用到的數據集和代碼。首先要將自己的數據集切分為訓練集和驗證集,訓練集用於訓練模型, 驗證集用來驗證模型的准確率。這篇文章已經提供了一個實驗用的衛星圖片分類數據集,這個數據集一共6個類別, 見下表所示

   

  在data_prepare目錄中,有一個pic文件夾保存原始的圖像文件,這里面有train 和validation 兩個子目錄,分別表示訓練使用的圖片和驗證使用的圖片。在每個目錄中,分別以類別名為文件夾名保存所有圖像。在每個類別文件夾下,存放的就是原始的圖像(如jpg 格式的圖像文件)。下面在data_prepare 文件夾下,使用預先編制好的腳本data_convert .py,使用以下命令將圖片轉換為為tfrecord格式。

python data_convert.py

  data_convert.py代碼中的一些參數解釋為:

# -t pic/: 表示轉換pic文件夾中的數據。pic文件夾中必須有一個train目錄和一個validation目錄,分別代表訓練和驗證數據集。
#–train-shards 2:將訓練數據集分成兩塊,即最后的訓練數據就是兩個tfrecord格式的文件。如果自己的數據集較大,可以考慮將其分為更多的數據塊。
#–validation-shards 2: 將驗證數據集分為兩塊。
#–num-threads 2:采用兩個線程產生數據。注意線程數必須要能整除train-shaeds和validation-shards,來保證每個線程處理的數據塊是相同的。
#–dataset-name satellite: 給生成的數據集起一個名字。這里將數據集起名叫“satellite”,最后生成的頭文件就是staellite_trian和satellite_validation。

  運行上述命令后,就可以在pic文件夾中找到5個新生成的文件,分別是兩個訓練數據和兩個驗證數據,還有一個文本文件label.txt ,其表示圖片的內部標簽(數字)到真實類別(字符串)之間的映射順序。如圖片在tfrecord 中的標簽為0 ,那么就對應label.txt 第一行的類別,在tfrecord的標簽為1,就對應label.txt 中第二行的類別,依此類推。
   

二、使用TensorFlow Slim微調模型

1、介紹TensorFlow Slim源碼

  TensorFlow Slim 是Google 公司公布的一個圖像分類工具包,它不僅定義了一些方便的接口,還提供了很多ImageNet數據集上常用的網絡結構和預訓練模型。截至2017 年7 月, Slim 提供包括VGG16 、VGG19 、InceptionVl ~ V4, ResNet 50 、ResNet 101, MobileNet 在內大多數常用模型的結構以及預訓練模型,更多的模型還會被持續添加進來。如果需要使用Slim 微調模型,首先要下載Slim的源代碼。Slim的源代碼保存在tensorflow/models 項目中https://github.com/tensorflow/models/tree/master/research/slim。提供的代碼里面已經包含了這份代碼,在chapter3/slim目錄下。下面簡單介紹下Slim的代碼結構,如下表所示:

   

2、定義新的datasets文件

  在slim/datasets 中, 定義了所有可以使用的數據庫,為了可以使用在前面中創建的tfrecord數據進行訓練,必須要在datasets中定義新的數據庫。首先,在datasets/目錄下新建一個文件satellite.py,並將flowers.py 文件中的內容復制到satellite.py 中。接下來,需要修改以下幾處內容:第一處是_FILE_PATTERN 、SPLITS_TO SIZES 、_NUM_CLASSES , 將其進行以下修改:

_FILE_PATTERN = 'satellite_%s_*.tfrecord'
SPLITS_TO_SIZES = {'train':4800, 'validation':1200}
_NUM_CLASSES = 6

  第二處修改image/format部分,將之修改為:

'image/format' tf.FixedLenFeature( (), tf. string, default_value ='jpg'),

  此處定義了圖片的默認格式。收集的衛星圖片的格式為jpg圖片,因此修改為jpg 。修改完satellite.py后,還需要在同目錄的dataset_factory.py文件中注冊satellite數據庫。注冊后dataset_factory. py 中對應代碼為:

from datasets import cifar10
from datasets import flowers
from datasets import imagenet
from datasets import mnist
from datasets import satellite # 自行添加

datasets_map = {
    'cifar10': cifar10,
    'flowers': flowers,
    'imagenet': imagenet,
    'mnist': mnist,
    'satellite':satellite,  # 自行添加
}

3、准備訓練文件夾

  定義完數據集后,在slim文件夾下再新建一個satellite目錄,在這個目錄中,完成最后的幾項准備工作:

  新建一個data目錄,並將前面准備好的5 個轉換好格式的訓練數據(4個tfrecords文件和1個txt文件)復制進去。
  新建一個空的train_dir 目錄,用來保存訓練過程中的日志和模型。
  新建一個pretrained目錄,在slim的GitHub頁面找到Inception_V3 模型的下載地址,下載並解壓后,會得到一個inception_v3 .ckpt 文件,將該文件復制到pretrained 目錄下。

  最后形成的目錄如下所示:  

   

4、開始訓練

  在slim 文件夾下,運行以下命令就可以開始訓練了:

python train_image_classifier.py

  train_image_classifier.py中部分參數解釋如下:

# –trainable_scopes=InceptionV3/Logits,InceptionV3/AuxLogits:首先來解釋trainable_scope的作用,因為它非常重要。
  trainable_scopes規定了在模型中微調變量的范圍。這里的設定表示只對InceptionV3/Logits,InceptionV3/AuxLogits 兩個變量進行微調,
  其它的變量都不動。InceptionV3/Logits,InceptionV3/AuxLogits就相當於在VGG模型中的fc8,他們是Inception V3的“末端層”。
  如果不設定trainable_scopes,就會對模型中所有的參數進行訓練。 # –train_dir=satellite/train_dir:表明會在satellite/train_dir目錄下保存日志和checkpoint。 # –dataset_name=satellite、–dataset_split_name=train:指定訓練的數據集。在3.2節中定義的新的dataset就是在這里發揮用處的。 # –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值。即模型中所有參數的二次正則化超參數。

  但是經過筆者自己實驗,發現在書上給出的下載地址下載的inception_v3.ckpt,會報出如下錯誤:DataLossError (see above for traceback): Unable to open table file satellite/pretrained/inception_v3.ckpt: Data loss: not an sstable (bad magic number): perhaps your file is in a different file format and you need touse a different restore operator?。如下圖所示:

   

  解決辦法:文件錯誤,筆者選擇從CSDN重新下載inception_v3.ckpt。這才能夠訓練起來。如下圖所示是成功訓練起來的截圖

   

  以上參數是只訓練末端層InceptionV3/Logits, InceptionV3/AuxLogits, 還可以去掉–trainable_ scopes 參數。原先的–trainable_scopes= InceptionV3 /Logits ,InceptionV3/AuxLogits 表示只對末端層InceptionV3/Logits 和InceptionV3/AuxLogits 進行訓練,去掉后就可以訓練模型中的所有參數了。

5、訓練程序行為

  當train_image_classifier.py程序啟動后,如果訓練文件夾(即satellite/train_dir)里沒有已經保存的模型,就會加載checkpoint_path中的預訓練模型,緊接着,程序會把初始模型保存到train_dir中,命名為model.ckpt-0,0表示第0步。這之后,每隔5min(參數--save_interval_secs=300指定了每隔300s保存一次,即5min)。程序還會把當前模型保存到同樣的文件夾中,命名格式和第一次保存的格式一樣。因為模型比較大,程序只會保留最新的5個模型。

  此外,如果中斷了程序並再次運行,程序會首先檢查train_dir中有無已經保存的模型,如果有,就不會去加載checkpoint_path中的預訓練模型,而是直接加載train_dir中已經訓練好的模型,並以此為起點進行訓練。Slim之所以這樣設計,是為了在微調網絡的時候,可以方便地按階段手動調整學習率等參數。

6、驗證模型准確率

  使用eval_image_classifier.py程序驗證模型在驗證數據集上的准確率,執行以下指令:

python eval_image_classifier.py

  eval_image_classifier.py中部分參數解釋如下

# –checkpoint_path=satellite/train_ dir: 這個參數既可以接收一個目錄的路徑,也可以接收一個文件的路徑。如果接收的是一個目錄的路徑,
# 如這里的satellite/train_dir,就會在這個目錄中尋找最新保存的模型文件,執行驗證。也可以指定一個模型驗證,以第300步為例,
# 如果要對它執行驗證,傳遞的參數應該為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「nception_ v3 :使用的模型。

  執行后,出現如下結果:

   

  Accuracy表示模型的分類准確率,而Recall_5 表示Top 5 的准確率,即在輸出的各類別概率中,正確的類別只要落在前5 個就算對。由於此處的類別數比較少,因此可以不執行Top 5 的准確率,換而執行Top 2 或者Top 3的准確率,只要在eval_image_classifier.py 中修改下面的部分就可以了: 

    # Define the metrics:
    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(
            logits, labels, 5),
    })

7、導出模型

  訓練完模型后,常見的應用場景是:部署訓練好的模型並對單張圖片進行識別。此處提供了freeze_graph.py用於導出識別的模型,classify_image_inception_v3.py是使用inception_v3模型對單張圖片進行識別的腳本。導出模型:TensorFlow Slim提供了導出網絡結構的腳本export_inference_graph.py 。 首先在 slim 文件夾下運行指令:

python export_inference_graph.py

  這個命令會在 satellite 文件夾中生成一個 inception_v3_inf_graph.pb 文件 。

   

  注意: inception_v3 _inf _graph.pb 文件中只保存了Inception V3 的網絡結構,並不包含訓練得到的模型參數,需要將checkpoint 中的模型參數保存進來。方法是使用freeze_graph. py 腳本(在chapter_3 文件夾下運行):在 項目根目錄 執行如下命令(需將10085改成train_dir中保存的實際的模型訓練步數)

python freeze_graph.py 

  freeze_graph.py中部分參數解釋如下

#–input_graph slim/satellite/inception_v3_inf_graph.pb。表示使用的網絡結構文件,即之前已經導出的inception_v3 _inf_gr aph.pb 。
#–input_checkpoint slim/satallite/train_dir/model.ckpt-10085。具體將哪一個checkpoint 的參數載入到網絡結構中。
# 這里使用的是訓練文件夾train _d讓中的第10085步模型文件。我們需要根據訓練文件夾下checkpoint的實際步數,將10085修改成對應的數值。 #input_binary true。導入的inception_v3_inf_graph.pb實際是一個protobuf文件。而protobuf 文件有兩種保存格式,一種是文本形式,一種是二進制形式。
# inception_v3_inf_graph.pb 是二進制形式,所以對應的參數是–input_binary true 。初學的話對此可以不用深究,若有興趣的話可以參考資料。 #--output_node_names 在導出的模型中指定一個輸出結點,InceptionV3/Predictions/Reshape_1是Inception_V3最后的輸出層 #–output_graph slim/satellite/frozen_graph.pb。最后導出的模型保存為slim/satellite/frozen_graph.pb 文件

  最后導出的模型文件如下:

   

三、預測圖片

  如何使用導出的frozen_graph.pb文件對單張圖片進行預測?此處使用一個編寫的文件classify_image_inception_v3.py 腳本來完成這件事 。先來看這個腳本的使用方法:

python classify_image_inception_v3.py

  classify_image_inception_v3.py中部分參數解釋如下

# 一model_path 很好理解,就是之前導出的模型frozen_graph. pb 。
# –label_path 指定了一個label文件, label文件中按順序存儲了各個類別的名稱,這樣腳本就可以把類別的id號轉換為實際的類別名。
# –image _file 是需要測試的單張圖片。

  腳本的運行結果應該類似於:
   

  這就表示模型預測圖片對應的最可能的類別是water,接着是wetland 、urban 、wood 等。score 是各個類別對應的Logit 。

四、TensorBoard 可視化與超參數選擇

  在訓練時,可以使用TensorBoard 對訓練過程進行可視化,這也有助於設定訓練模型的方式及超參數。在slim文件夾下使用下列命令可以打開TensorBoard (其實就是指定訓練文件夾):

tensorboard --logdir satellite/train_dir

   

  在TensorBoard中,可以看到損失的變化如上圖 所示。觀察損失曲線有助於調整參數。當損失曲線比較平緩,收斂較慢時,可以考慮增大學習率,以加快收斂速度;如果損失曲線波動較大,無法收斂,就可能是因為學習率過大,此時就可以嘗試適當減小學習率

  另外,在上面的學習中,在筆者自己進行試驗的過程中,一些小的錯誤就沒有粘貼出來了,讀者自行搜索即可得到解決方法。這篇博文主要來自《21個項目玩轉深度學習》這本書里面的第三章,內容有刪減,還有本書的一些代碼的實驗結果,經過筆者自己修改,已經能夠完全成功運行。隨書附贈的代碼庫鏈接為:https://github.com/hzy46/Deep-Learning-21-Examples

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM