首先要作一些數據準備方面的工做:一是把數據集切分爲訓練集和驗證集, 二是轉換爲tfrecord 格式。在data_prepare/文件夾中提供了會用到的數據集和代碼。首先要將本身的數據集切分爲訓練集和驗證集,訓練集用於訓練模型, 驗證集用來驗證模型的準確率。這篇文章已經提供了一個實驗用的衛星圖片分類數據集,這個數據集一共6個類別, 見下表所示node
在data_prepare目錄中,有一個pic文件夾保存原始的圖像文件,這裏面有train 和validation 兩個子目錄,分別表示訓練使用的圖片和驗證使用的圖片。在每一個目錄中,分別以類別名爲文件夾名保存全部圖像。在每一個類別文件夾下,存放的就是原始的圖像(如jpg 格式的圖像文件)。下面在data_prepare 文件夾下,使用預先編制好的腳本data_convert .py,使用如下命令將圖片轉換爲爲tfrecord格式。python
python data_convert.py
data_convert.py代碼中的一些參數解釋爲:git
# -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 中第二行的類別,依此類推。
github
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的代碼結構,以下表所示:數據庫
在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, # 自行添加 }
定義完數據集後,在slim文件夾下再新建一個satellite目錄,在這個目錄中,完成最後的幾項準備工做:學習
新建一個data目錄,並將前面準備好的5 個轉換好格式的訓練數據(4個tfrecords文件和1個txt文件)複製進去。
新建一個空的train_dir 目錄,用來保存訓練過程當中的日誌和模型。
新建一個pretrained目錄,在slim的GitHub頁面找到Inception_V3 模型的下載地址,下載並解壓後,會獲得一個inception_v3 .ckpt 文件,將該文件複製到pretrained 目錄下。測試
最後造成的目錄以下所示:
在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 進行訓練,去掉後就能夠訓練模型中的全部參數了。
當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之因此這樣設計,是爲了在微調網絡的時候,能夠方便地按階段手動調整學習率等參數。
使用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), })
訓練完模型後,常見的應用場景是:部署訓練好的模型並對單張圖片進行識別。此處提供了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 對訓練過程進行可視化,這也有助於設定訓練模型的方式及超參數。在slim文件夾下使用下列命令能夠打開TensorBoard (其實就是指定訓練文件夾):
tensorboard --logdir satellite/train_dir
在TensorBoard中,能夠看到損失的變化如上圖 所示。觀察損失曲線有助於調整參數。當損失曲線比較平緩,收斂較慢時,能夠考慮增大學習率,以加快收斂速度;若是損失曲線波動較大,沒法收斂,就多是由於學習率過大,此時就能夠嘗試適當減少學習率。
另外,在上面的學習中,在筆者本身進行試驗的過程當中,一些小的錯誤就沒有粘貼出來了,讀者自行搜索便可獲得解決方法。這篇博文主要來自《21個項目玩轉深度學習》這本書裏面的第三章,內容有刪減,還有本書的一些代碼的實驗結果,通過筆者本身修改,已經可以徹底成功運行。隨書附贈的代碼庫連接爲:https://github.com/hzy46/Deep-Learning-21-Examples。