書籍源碼:https://github.com/hzy46/Deep-Learning-21-Examples
CNN的發展已經很多了,ImageNet引發的一系列方法,LeNet,GoogLeNet,VGGNet,ResNet每個方法都有很多版本的衍生,tensorflow中帶有封裝好各方法和網絡的函數,只要喂食自己的訓練集就可以完成自己的模型,感覺超方便!!!激動!!!因為雖然原理流程了解了,但是要寫出來真的。。。。好難,臣妾做不到啊~~~~~~~~
START~~~~
1.數據准備
首先了解下微調的概念: 以VGG為例

他的結構是卷積+全連接,卷積層分為5個部分共13層,conv1~conv5。還有三層全連接,即fc6,fc7,fc8。總共16層,因此被稱為VGG16。
a.如果要將VGG16的結構用於一個新的數據集,首先要去掉fc8,因為fc8原本的輸出是1000類的概率。需要改為符合自身訓練集的輸出類別數。
b.訓練的時候,網絡的參數的初始值並不是隨機化生成的,而是采用VGG16在ImageNet上已經訓練好的參數作為訓練的初始值。因為已經訓練過的VGG16中的參數已經包含了大量有用的卷積過濾器,這樣做不僅節約大量訓練時間,而且有助於分類器性能的提高。
載入VGG16的參數后,即可開始訓練。此時需要指定訓練層數的范圍。一般而言,可以選擇以下幾種:
- 只訓練fc8:訓練范圍一定要包含fc8這一層。這樣的選擇一般性能都不會太好,但速度很快;因為他只訓練fc8,保持其他層的參數不動,相當於把VGG16當成一個“特征提取器”,用fc7層提取的特征做一個softmax的模型分類。
- 訓練所有參數:耗時較慢,但能取得較高性能。
- 訓練部分參數:通常是固定淺層參數不變,訓練深層參數。如固定conv1、conv2部分的參數不訓練,只訓練conv3、conv4、conv5、fc6、fc7、fc8的參數。
這種訓練方法就是對神經網絡做微調。
1.1 切分train&test
書中提供了衛星圖像數據集,有6個類別,分別是森林(wood),水域(water),岩石(rock),農田(wetland),冰川(glacier),城市區域(urban)
保存結構為data_prepare/pic,再下層有兩個文件夾train和validation,各文件夾下有6個文件夾,放的是該類別下的圖片。
1.2 轉換成tfrecord格式
python data_convert.py -t pic/ \ --train-shards 2 \ --validation-shards 2 \ --num-threads 2 \ --dataset-name satellite
參數解釋:
-t pic/ :表示轉換pic文件夾下的數據,該文件夾必須與上面的文件結構保持一致
--train-shards 2 :把訓練集分成兩塊,即最后的訓練數據就是兩個tfrecord格式的文件。若數據集更大,可以分更多數據塊
--validation-shards 2 :把驗證集分成兩塊
--num-thread 2 :用兩個線程來產生數據。注意線程數必須要能整除train-shards和validation-shards,來保證每個線程處理的數據塊是相同的。
--dataset-name :給生成的數據集起個名字,即表示最后生成文件的開頭是satellite_train和satellite_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 中第二行的類別,依此類推。
2.訓練模型
2.1 TensorFlow Slim
Google 公司公布的一個圖像分類工具包,它不僅定義了一些方便的接口,還提供了很多 ImageNet 數據集上常用的網絡結構和預訓練模型 。
截至2017年7月,Slim 提供包括 VGG16、VGG19、Inception V1 ~ V4、ResNet 50、ResNet 101、MobileNet 在內大多數常用模型的結構以及預訓練模型,更多的模型還會被持續添加進來。
源碼地址: https://github.com/tensorflow/models/tree/master/research/slim
可以通過執行 git clone https://github.corn/tensorflow/models.git 來獲取
2.2 定義新的datasets文件<修改slim源碼>
在slim/datasets中,定義了所有可以使用的數據庫,為了使用之前生成的 tfrecord 數據進行訓練,必須要在datasets 中定義新的數據庫。
- 在 datasets/目錄下新建一個文件 satellite,並將 flowers.py 文件中的內容復制到 satellite.py 中。
修改兩處代碼:


- 在同目錄的 dataset_factory. py 文件中注冊 satellite 數據庫

2.3 准備訓練文件夾

在slim文件下新建satellite文件夾,按照上圖結構准備各個文件和數據,模型下載地址:http://download.tensorflow.org/models/inception_v3_2016_08_28.tar.gz,也可以在slim的github地址上找到其他模型的下載鏈接。
2.4 開始訓練
python train_image_classifier.py \ --train_dir=satellite/train_dir \ --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 \ --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 就相當於之前所講的 fc8 ,它們是 Inception V3 的“末端層” 。如果不設定 trainable_scopes ,就會對模型中所有的參數進行訓練。
--train_dir=satellite/train_dir : 表明會在 satellite/train_dir 目錄下保存日志和 checkpoint 。可通過tensorboard --logdir satellite/train_dir來可視化參數變化。
--dataset_name=satellite 、--dataset_split_name=train : 指定訓練的數據集 。之前定義的新的 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 步,就會在屏幕上打出訓練信息。
--optimize=rmsprop:表示選定的優化器 。
--weight_decay=0.00004 :選定的 weight_decay 值 。 即模型中所有參數的二次正則化超參數 。
如果想要對所有層訓練,去掉--trainable_scopes參數即可。
訓練結果:

程序開始運行時,會先讀取train_dir下的模型,若沒有,則去讀checkpoint_path目錄下的預訓練模型,以5min的頻率保留模型(僅保留最新的5個模型)。
若程序中斷再次訓練,讀取train_dir下的模型,不存在則依舊去找預訓練模型,若存在,則以該模型的參數為起點進行參數微調。
3.驗證准確率
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-OOOO1 三個文件 。 此時,如果要對它執行驗證,給 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 :使用的模型。
運行結果:

Accuracy表示模型的分類准確率,Recall_5表示Top5的准確率,即輸出的各類別概率中,正確的類別只要落在前5個中則算對。由於此處類別數不多,可嘗試改成Top2或者Top3.
修改eval_image_classifier.py

可再次執行上述驗證語句查看預測結果。
前面有講到可以訓練所有層的參數,再進行測試,發現Accuracy的值,在訓練所有層的時候可達82%,效果更佳。
4.導出模型並對單張圖片分類
4.1 生成.pb文件
在slim文件夾下有 export_inference_graph.py 文件,運行它會生成一個 inception_v3_inf_graph.pb 文件。該文件中僅保存了Inception V3的網絡結構,后續需要把checkpoint中的模型參數保存進來。
python export_inference_graph.py \ --alsologtostderr \ --model_name=inception_v3 \ --output_file=satellite/inception_v3_inf_graph.pb \ --dataset_name satellite
4.2 保存模型參數
在chapter_3文件下有 freeze_graph.py 文件,運行它會生成一個 frozen_graph.pb 文件(一個用於識別的模型)。之后就可以用該文件對單張圖片進行預測。
python freeze_graph.py \ --input_graph slim/satellite/inception_v3_inf_graph.pb \ --input_checkpoint slim/satellite/train_dir/model.ckpt-5271 \ --input_binary true \ --output_node_names InceptionV3/Predictions/Reshape_1 \ --output_graph slim/satellite/frozen_graph.pb
需將5271改成train_dir中保存的實際的模型訓練步數
--input_graph slim/satellite/inception_v3_inf_graph.pb:這個參數很好理解 ,它表示使用的網絡結構文件,即之前已經導出的inception_v3_inf_graph.pb 。
--input_checkpoint slim/satellite/train_dir/model.ckpt-5271:具體將哪一個checkpoint 的參數載入到網絡結構中 。這里使用的是訓練文件夾 train_dir中的第 5271 步模型文件 。 讀者需要根據訓練文件夾下 checkpoint 的實際步數,將 5271 修改成對應的數值。
--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:在導出的模型中,指定一個輸出結點, InceptionV3/Predictions/Reshape_1是 Inception V3最后的輸出層 。
--output_graph slim/satellite/frozen_graph.pb:最后導出的模型保存為 slim/satellite/frozen_graph.pb 文件。
4.3 單張圖片預測
python classify_image_inception_v3.py \ --model_path slim/satellite/frozen_graph.pb \ --label_path slim/satellite/data/label.txt \ --image_file test_image.jpg
運行結果如下:
[root@node5 chapter_03]# python3 classify_image_inception_v3.py --model_path slim/satellite/frozen_graph.pb --label_path slim/satellite/data/label.txt --image_file test_image.jpg 2018-11-15 11:21:39.435166: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA water (score = 3.25221) wetland (score = 1.97180) urban (score = 1.33430) wood (score = 0.53297) rock (score = -0.41706)
score是各個類別對應的Logit。
代碼邏輯實現:

拓展閱讀
- TensorFlow Slim 是TensorFlow 中用於定義、訓練和驗證復雜網絡的 高層API。官方已經使用TF-Slim 定義了一些常用的圖像識別模型, 如AlexNet、VGGNet、Inception模型、ResNet等。本章介紹的Inception V3 模型也是其中之一, 詳細文檔請參考: https://github.com/tensorflow/models/tree/master/research/slim。
- 在第3.2節中,將圖片數據轉換成了TFRecord文件。TFRecord 是 TensorFlow 提供的用於高速讀取數據的文件格式。讀者可以參考博文( http://warmspringwinds.github.io/tensorflow/tf-slim/2016/12/21/tfrecords-guide/ )詳細了解如何將數據轉換為TFRecord 文件,以及 如何從TFRecord 文件中讀取數據。
- Inception V3 是Inception 模型(即GoogLeNet)的改進版,可以參考論文Rethinking the Inception Architecture for Computer Vision 了解 其結構細節。
THE END~~~~
