電力建設(shè)期刊網(wǎng)站上海網(wǎng)站推廣廣告
一、數(shù)據(jù)準(zhǔn)備
首先要做一些數(shù)據(jù)準(zhǔn)備方面的工作:一是把數(shù)據(jù)集切分為訓(xùn)練集和驗(yàn)證集, 二是轉(zhuǎn)換為tfrecord 格式。在data_prepare/文件夾中提供了會(huì)用到的數(shù)據(jù)集和代碼。首先要將自己的數(shù)據(jù)集切分為訓(xùn)練集和驗(yàn)證集,訓(xùn)練集用于訓(xùn)練模型,?驗(yàn)證集用來(lái)驗(yàn)證模型的準(zhǔn)確率。這篇文章已經(jīng)提供了一個(gè)實(shí)驗(yàn)用的衛(wèi)星圖片分類(lèi)數(shù)據(jù)集,這個(gè)數(shù)據(jù)集一共6個(gè)類(lèi)別, 見(jiàn)下表所示
在data_prepare目錄中,有一個(gè)pic文件夾保存原始的圖像文件,這里面有train 和validation 兩個(gè)子目錄,分別表示訓(xùn)練使用的圖片和驗(yàn)證使用的圖片。在每個(gè)目錄中,分別以類(lèi)別名為文件夾名保存所有圖像。在每個(gè)類(lèi)別文件夾下,存放的就是原始的圖像(如jpg 格式的圖像文件)。下面在data_prepare 文件夾下,使用預(yù)先編制好的腳本data_convert .py,使用以下命令將圖片轉(zhuǎn)換為為tfrecord格式。
python data_convert.py
data_convert.py代碼中的一些參數(shù)解釋為:
# -t pic/: 表示轉(zhuǎn)換pic文件夾中的數(shù)據(jù)。pic文件夾中必須有一個(gè)train目錄和一個(gè)validation目錄,分別代表訓(xùn)練和驗(yàn)證數(shù)據(jù)集。 #–train-shards 2:將訓(xùn)練數(shù)據(jù)集分成兩塊,即最后的訓(xùn)練數(shù)據(jù)就是兩個(gè)tfrecord格式的文件。如果自己的數(shù)據(jù)集較大,可以考慮將其分為更多的數(shù)據(jù)塊。 #–validation-shards 2: 將驗(yàn)證數(shù)據(jù)集分為兩塊。 #–num-threads 2:采用兩個(gè)線(xiàn)程產(chǎn)生數(shù)據(jù)。注意線(xiàn)程數(shù)必須要能整除train-shaeds和validation-shards,來(lái)保證每個(gè)線(xiàn)程處理的數(shù)據(jù)塊是相同的。 #–dataset-name satellite: 給生成的數(shù)據(jù)集起一個(gè)名字。這里將數(shù)據(jù)集起名叫“satellite”,最后生成的頭文件就是staellite_trian和satellite_validation。
運(yùn)行上述命令后,就可以在pic文件夾中找到5個(gè)新生成的文件,分別是兩個(gè)訓(xùn)練數(shù)據(jù)和兩個(gè)驗(yàn)證數(shù)據(jù),還有一個(gè)文本文件label.txt ,其表示圖片的內(nèi)部標(biāo)簽(數(shù)字)到真實(shí)類(lèi)別(字符串)之間的映射順序。如圖片在tfrecord 中的標(biāo)簽為0 ,那么就對(duì)應(yīng)label.txt 第一行的類(lèi)別,在tfrecord的標(biāo)簽為1,就對(duì)應(yīng)label.txt 中第二行的類(lèi)別,依此類(lèi)推。
二、使用TensorFlow Slim微調(diào)模型
1、介紹TensorFlow Slim源碼
TensorFlow Slim 是Google 公司公布的一個(gè)圖像分類(lèi)工具包,它不僅定義了一些方便的接口,還提供了很多ImageNet數(shù)據(jù)集上常用的網(wǎng)絡(luò)結(jié)構(gòu)和預(yù)訓(xùn)練模型。截至2017 年7 月, Slim 提供包括VGG16 、VGG19 、InceptionVl ~ V4, ResNet 50 、ResNet 101, MobileNet 在內(nèi)大多數(shù)常用模型的結(jié)構(gòu)以及預(yù)訓(xùn)練模型,更多的模型還會(huì)被持續(xù)添加進(jìn)來(lái)。如果需要使用Slim 微調(diào)模型,首先要下載Slim的源代碼。Slim的源代碼保存在tensorflow/models 項(xiàng)目中models/research/slim at master · tensorflow/models · GitHub。提供的代碼里面已經(jīng)包含了這份代碼,在chapter3/slim目錄下。下面簡(jiǎn)單介紹下Slim的代碼結(jié)構(gòu),如下表所示:
2、定義新的datasets文件
在slim/datasets 中, 定義了所有可以使用的數(shù)據(jù)庫(kù),為了可以使用在前面中創(chuàng)建的tfrecord數(shù)據(jù)進(jìn)行訓(xùn)練,必須要在datasets中定義新的數(shù)據(jù)庫(kù)。首先,在datasets/目錄下新建一個(gè)文件satellite.py,并將flowers.py 文件中的內(nèi)容復(fù)制到satellite.py 中。接下來(lái),需要修改以下幾處內(nèi)容:第一處是_FILE_PATTERN 、SPLITS_TO?SIZES 、_NUM_CLASSES , 將其進(jìn)行以下修改:
_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' ),
此處定義了圖片的默認(rèn)格式。收集的衛(wèi)星圖片的格式為jpg圖片,因此修改為jpg 。修改完satellite.py后,還需要在同目錄的dataset_factory.py文件中注冊(cè)satellite數(shù)據(jù)庫(kù)。注冊(cè)后dataset_factory. py 中對(duì)應(yīng)代碼為:
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、準(zhǔn)備訓(xùn)練文件夾
定義完數(shù)據(jù)集后,在slim文件夾下再新建一個(gè)satellite目錄,在這個(gè)目錄中,完成最后的幾項(xiàng)準(zhǔn)備工作:
新建一個(gè)data目錄,并將前面準(zhǔn)備好的5 個(gè)轉(zhuǎn)換好格式的訓(xùn)練數(shù)據(jù)(4個(gè)tfrecords文件和1個(gè)txt文件)復(fù)制進(jìn)去。
新建一個(gè)空的train_dir 目錄,用來(lái)保存訓(xùn)練過(guò)程中的日志和模型。
新建一個(gè)pretrained目錄,在slim的GitHub頁(yè)面找到Inception_V3 模型的下載地址,下載并解壓后,會(huì)得到一個(gè)inception_v3 .ckpt 文件,將該文件復(fù)制到pretrained 目錄下。
最后形成的目錄如下所示:
4、開(kāi)始訓(xùn)練
在slim 文件夾下,運(yùn)行以下命令就可以開(kāi)始訓(xùn)練了:
python train_image_classifier.py
train_image_classifier.py中部分參數(shù)解釋如下:
# –trainable_scopes=InceptionV3/Logits,InceptionV3/AuxLogits:首先來(lái)解釋trainable_scope的作用,因?yàn)樗浅V匾?。trainable_scopes規(guī)定了在模型中微調(diào)變量的范圍。這里的設(shè)定表示只對(duì)InceptionV3/Logits,InceptionV3/AuxLogits 兩個(gè)變量進(jìn)行微調(diào),其它的變量都不動(dòng)。InceptionV3/Logits,InceptionV3/AuxLogits就相當(dāng)于在VGG模型中的fc8,他們是Inception V3的“末端層”。如果不設(shè)定trainable_scopes,就會(huì)對(duì)模型中所有的參數(shù)進(jìn)行訓(xùn)練。 # –train_dir=satellite/train_dir:表明會(huì)在satellite/train_dir目錄下保存日志和checkpoint。 # –dataset_name=satellite、–dataset_split_name=train:指定訓(xùn)練的數(shù)據(jù)集。在3.2節(jié)中定義的新的dataset就是在這里發(fā)揮用處的。 # –dataset_dir=satellite/data: 指定訓(xùn)練數(shù)據(jù)集保存的位置。 # –model_ name=inception_v3 :使用的模型名稱(chēng)。 # –checkpoint_path=satellite/pretrained/inception_v3.ckpt:預(yù)訓(xùn)練模型的保存位置。 # –checkpoint_exclude_scopes=InceptionV3/Logits,InceptionV3/AuxLogits : 在恢復(fù)預(yù)訓(xùn)練模型時(shí),不恢復(fù)這兩層。正如之前所說(shuō),這兩層是InceptionV3模型的末端層,對(duì)應(yīng)著ImageNet 數(shù)據(jù)集的1000 類(lèi),和當(dāng)前的數(shù)據(jù)集不符, 因此不要去恢復(fù)它。 # –max_number_of_steps 100000 :最大的執(zhí)行步數(shù)。 # –batch_size =32 :每步使用的batch 數(shù)量。 # –learning_rate=0.001 : 學(xué)習(xí)率。 # –learning_rate_decay_type=fixed:學(xué)習(xí)率是否自動(dòng)下降,此處使用固定的學(xué)習(xí)率。 # –save_interval_secs=300 :每隔300s ,程序會(huì)把當(dāng)前模型保存到train_dir中。此處就是目錄satellite/train_dir 。 # –save_summaries_secs=2 :每隔2s,就會(huì)將日志寫(xiě)入到train_dir 中。可以用TensorBoard 查看該日志。此處為了方便觀察,設(shè)定的時(shí)間間隔較多,實(shí)際訓(xùn)練時(shí),為了性能考慮,可以設(shè)定較長(zhǎng)的時(shí)間間隔。 # –log_every_n_steps=10: 每隔10 步,就會(huì)在屏幕上打出訓(xùn)練信息。 # –optimizer=rmsprop: 表示選定的優(yōu)化器。 # –weight_decay=0.00004 :選定的weight_decay值。即模型中所有參數(shù)的二次正則化超參數(shù)。
但是經(jīng)過(guò)筆者自己實(shí)驗(yàn),發(fā)現(xiàn)在書(shū)上給出的下載地址下載的inception_v3.ckpt,會(huì)報(bào)出如下錯(cuò)誤: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?。如下圖所示:
解決辦法:文件錯(cuò)誤,筆者選擇從CSDN重新下載inception_v3.ckpt。這才能夠訓(xùn)練起來(lái)。如下圖所示是成功訓(xùn)練起來(lái)的截圖
以上參數(shù)是只訓(xùn)練末端層InceptionV3/Logits, InceptionV3/AuxLogits, 還可以去掉–trainable_ scopes 參數(shù)。原先的–trainable_scopes= InceptionV3 /Logits ,InceptionV3/AuxLogits 表示只對(duì)末端層InceptionV3/Logits 和InceptionV3/AuxLogits 進(jìn)行訓(xùn)練,去掉后就可以訓(xùn)練模型中的所有參數(shù)了。
5、訓(xùn)練程序行為
當(dāng)train_image_classifier.py程序啟動(dòng)后,如果訓(xùn)練文件夾(即satellite/train_dir)里沒(méi)有已經(jīng)保存的模型,就會(huì)加載checkpoint_path中的預(yù)訓(xùn)練模型,緊接著,程序會(huì)把初始模型保存到train_dir中,命名為model.ckpt-0,0表示第0步。這之后,每隔5min(參數(shù)--save_interval_secs=300指定了每隔300s保存一次,即5min)。程序還會(huì)把當(dāng)前模型保存到同樣的文件夾中,命名格式和第一次保存的格式一樣。因?yàn)槟P捅容^大,程序只會(huì)保留最新的5個(gè)模型。
此外,如果中斷了程序并再次運(yùn)行,程序會(huì)首先檢查train_dir中有無(wú)已經(jīng)保存的模型,如果有,就不會(huì)去加載checkpoint_path中的預(yù)訓(xùn)練模型,而是直接加載train_dir中已經(jīng)訓(xùn)練好的模型,并以此為起點(diǎn)進(jìn)行訓(xùn)練。Slim之所以這樣設(shè)計(jì),是為了在微調(diào)網(wǎng)絡(luò)的時(shí)候,可以方便地按階段手動(dòng)調(diào)整學(xué)習(xí)率等參數(shù)。
6、驗(yàn)證模型準(zhǔn)確率
使用eval_image_classifier.py程序驗(yàn)證模型在驗(yàn)證數(shù)據(jù)集上的準(zhǔn)確率,執(zhí)行以下指令:
python eval_image_classifier.py
eval_image_classifier.py中部分參數(shù)解釋如下
# –checkpoint_path=satellite/train_ dir: 這個(gè)參數(shù)既可以接收一個(gè)目錄的路徑,也可以接收一個(gè)文件的路徑。如果接收的是一個(gè)目錄的路徑, # 如這里的satellite/train_dir,就會(huì)在這個(gè)目錄中尋找最新保存的模型文件,執(zhí)行驗(yàn)證。也可以指定一個(gè)模型驗(yàn)證,以第300步為例, # 如果要對(duì)它執(zhí)行驗(yàn)證,傳遞的參數(shù)應(yīng)該為satellite/train_ dir/model.ckpt-300 。 # –eval_dir=satellite/eval_dir :執(zhí)行結(jié)果的曰志就保存在eval_dir 中,同樣可以通過(guò)TensorBoard 查看。 # –dataset_name=satellite 、–dataset_split_name=validation 指定需要執(zhí)行的數(shù)據(jù)集。注意此處是使用驗(yàn)證集( validation )執(zhí)行驗(yàn)證。 # –dataset_dir=satellite/data :數(shù)據(jù)集保存的位置。 # –model_ name「nception_ v3 :使用的模型。
執(zhí)行后,出現(xiàn)如下結(jié)果:
Accuracy表示模型的分類(lèi)準(zhǔn)確率,而Recall_5 表示Top 5 的準(zhǔn)確率,即在輸出的各類(lèi)別概率中,正確的類(lèi)別只要落在前5 個(gè)就算對(duì)。由于此處的類(lèi)別數(shù)比較少,因此可以不執(zhí)行Top 5 的準(zhǔn)確率,換而執(zhí)行Top 2 或者Top 3的準(zhǔn)確率,只要在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、導(dǎo)出模型
訓(xùn)練完模型后,常見(jiàn)的應(yīng)用場(chǎng)景是:部署訓(xùn)練好的模型并對(duì)單張圖片進(jìn)行識(shí)別。此處提供了freeze_graph.py用于導(dǎo)出識(shí)別的模型,classify_image_inception_v3.py是使用inception_v3模型對(duì)單張圖片進(jìn)行識(shí)別的腳本。導(dǎo)出模型:TensorFlow Slim提供了導(dǎo)出網(wǎng)絡(luò)結(jié)構(gòu)的腳本export_inference_graph.py 。 首先在 slim 文件夾下運(yùn)行指令:
python export_inference_graph.py
這個(gè)命令會(huì)在 satellite 文件夾中生成一個(gè) inception_v3_inf_graph.pb 文件 。
注意: inception_v3 _inf _graph.pb 文件中只保存了Inception V3 的網(wǎng)絡(luò)結(jié)構(gòu),并不包含訓(xùn)練得到的模型參數(shù),需要將checkpoint 中的模型參數(shù)保存進(jìn)來(lái)。方法是使用freeze_graph. py 腳本(在chapter_3 文件夾下運(yùn)行):在 項(xiàng)目根目錄 執(zhí)行如下命令(需將10085改成train_dir中保存的實(shí)際的模型訓(xùn)練步數(shù))
python freeze_graph.py
freeze_graph.py中部分參數(shù)解釋如下
#–input_graph slim/satellite/inception_v3_inf_graph.pb。表示使用的網(wǎng)絡(luò)結(jié)構(gòu)文件,即之前已經(jīng)導(dǎo)出的inception_v3 _inf_gr aph.pb 。 #–input_checkpoint slim/satallite/train_dir/model.ckpt-10085。具體將哪一個(gè)checkpoint 的參數(shù)載入到網(wǎng)絡(luò)結(jié)構(gòu)中。 # 這里使用的是訓(xùn)練文件夾train _d讓中的第10085步模型文件。我們需要根據(jù)訓(xùn)練文件夾下checkpoint的實(shí)際步數(shù),將10085修改成對(duì)應(yīng)的數(shù)值。 #input_binary true。導(dǎo)入的inception_v3_inf_graph.pb實(shí)際是一個(gè)protobuf文件。而protobuf 文件有兩種保存格式,一種是文本形式,一種是二進(jìn)制形式。 # inception_v3_inf_graph.pb 是二進(jìn)制形式,所以對(duì)應(yīng)的參數(shù)是–input_binary true 。初學(xué)的話(huà)對(duì)此可以不用深究,若有興趣的話(huà)可以參考資料。 #--output_node_names 在導(dǎo)出的模型中指定一個(gè)輸出結(jié)點(diǎn),InceptionV3/Predictions/Reshape_1是Inception_V3最后的輸出層 #–output_graph slim/satellite/frozen_graph.pb。最后導(dǎo)出的模型保存為slim/satellite/frozen_graph.pb 文件
最后導(dǎo)出的模型文件如下:
三、預(yù)測(cè)圖片
如何使用導(dǎo)出的frozen_graph.pb文件對(duì)單張圖片進(jìn)行預(yù)測(cè)?此處使用一個(gè)編寫(xiě)的文件classify_image_inception_v3.py 腳本來(lái)完成這件事 。先來(lái)看這個(gè)腳本的使用方法:
python classify_image_inception_v3.py
classify_image_inception_v3.py中部分參數(shù)解釋如下
# 一model_path 很好理解,就是之前導(dǎo)出的模型frozen_graph. pb 。 # –label_path 指定了一個(gè)label文件, label文件中按順序存儲(chǔ)了各個(gè)類(lèi)別的名稱(chēng),這樣腳本就可以把類(lèi)別的id號(hào)轉(zhuǎn)換為實(shí)際的類(lèi)別名。 # –image _file 是需要測(cè)試的單張圖片。
腳本的運(yùn)行結(jié)果應(yīng)該類(lèi)似于:
這就表示模型預(yù)測(cè)圖片對(duì)應(yīng)的最可能的類(lèi)別是water,接著是wetland 、urban 、wood 等。score 是各個(gè)類(lèi)別對(duì)應(yīng)的Logit 。
四、TensorBoard 可視化與超參數(shù)選擇
在訓(xùn)練時(shí),可以使用TensorBoard 對(duì)訓(xùn)練過(guò)程進(jìn)行可視化,這也有助于設(shè)定訓(xùn)練模型的方式及超參數(shù)。在slim文件夾下使用下列命令可以打開(kāi)TensorBoard (其實(shí)就是指定訓(xùn)練文件夾):
tensorboard - - logdir satellite / train_dir
在TensorBoard中,可以看到損失的變化如上圖 所示。觀察損失曲線(xiàn)有助于調(diào)整參數(shù)。當(dāng)損失曲線(xiàn)比較平緩,收斂較慢時(shí),可以考慮增大學(xué)習(xí)率,以加快收斂速度;如果損失曲線(xiàn)波動(dòng)較大,無(wú)法收斂,就可能是因?yàn)閷W(xué)習(xí)率過(guò)大,此時(shí)就可以嘗試適當(dāng)減小學(xué)習(xí)率。
另外,在上面的學(xué)習(xí)中,在筆者自己進(jìn)行試驗(yàn)的過(guò)程中,一些小的錯(cuò)誤就沒(méi)有粘貼出來(lái)了,讀者自行搜索即可得到解決方法。這篇博文主要來(lái)自《21個(gè)項(xiàng)目玩轉(zhuǎn)深度學(xué)習(xí)》這本書(shū)里面的第三章,內(nèi)容有刪減,還有本書(shū)的一些代碼的實(shí)驗(yàn)結(jié)果,經(jīng)過(guò)筆者自己修改,已經(jīng)能夠完全成功運(yùn)行。隨書(shū)附贈(zèng)的代碼庫(kù)鏈接為:GitHub - hzy46/Deep-Learning-21-Examples: 《21個(gè)項(xiàng)目玩轉(zhuǎn)深度學(xué)習(xí)———基于TensorFlow的實(shí)踐詳解》配套代碼。