1. 程式人生 > >使用deeplabv3+訓練自己資料集(遷移學習)

使用deeplabv3+訓練自己資料集(遷移學習)

# 概述 在前邊一篇文章,我們講了如何復現論文程式碼,使用pascal voc 2012資料集進行訓練和驗證,具體內容可以參考[《deeplab v3+在pascal_voc 2012資料集上進行訓練》](https://www.vcjmhg.top/train-deeplabv3-puls-with-pascal-voc-2012),在本篇文章,我們主要講述,如何對deeplab v3+進行遷移學習,也即如何使用deeplab v3+演算法來訓練個人的資料集。 # 1. 資料集準備 首先在開始之前我們先對資料集做一個簡單的說明,由於`deeplabv3+`使用的`TensorFlow`框架,並且為了提高訓練的速度,因此在訓練開始前,需要轉換成`tfrecorde`型別的檔案來進行訓練,因此,我們直接仿照pascal voc 2012資料集的資料結構來製作資料集,這樣我們在訓練所需圖片準備完成之後可以直接複用轉換`tfrecorde`的指令碼。 ## 1.1 標註圖片,獲取json檔案 古人有句話:兵馬未動糧草先行,而對深度學習來說,糧草毫無疑問指的是訓練的資料,畢竟我們最終的模型都是依靠資料來餵養出來的:dog:!因此選擇一個趁手的標註工具很重要,此處我推薦使用`labelme`,標註起來相當方便。 下邊我簡單說一下`lableme`的**安裝方法**(此處建議使用Anconda來實現環境隔離)。 1. 安裝Ancodna環境, 執行如下命令: ```shell conda create --name=labelme python=2.7(這一步python=*選擇自己的Python版本) activate labelme ``` 2. 安裝軟體與依賴 ```sh conda install pyqt pip install labelme ``` 3. 啟動與使用 ```sh activate labelme labelme ``` 啟動完成之後可以看到如下介面: ![image-20200927143131553](http://img.vcjmhg.top/20200927143139.png) 標註的時候,將物體用線條框起來即可,例如: ![img](http://img.vcjmhg.top/20200927143313) ## 1.2 轉換json,獲取png圖片 在影象標註完成之後,在我們對應設定的資料夾下有許多json,這些json檔案記錄了所標註圖片的位置以及圖片內容等資訊,根據這些資訊我們可以轉換成訓練所需要的mask圖(此處是png格式的圖片)。 雖然`labelme`中包含`labelme_json_to_dataset`來幫助我們將json圖片轉成png圖片,但是該命令有一個巨大的缺點就是無法實現批量轉換,因此需要我們自己寫一個批量轉換的指令碼來輔助轉換。 一個簡單的轉換指令碼如下: ```python import os #path = 'C:/Users/tj/Desktop/dd' # path為labelme標註後的.json檔案存放的路徑 path = 'C:\\Users\\Administrator\\Desktop\\第五次資料集擴充\\labels' json_file = os.listdir(path) for file in json_file: if(file.split('.')[1]=='json'): os.system("labelme_json_to_dataset %s" % (path + '/' + file)) # # C:/soft/ev4/venv/Scripts/labelme_json_to_dataset.exe 為labelme_json_to_dataset.exe的路徑 path + '/' + file 為讀取.json路徑 print(path + '/' + file) ``` 通過該指令碼每一個json檔案都會生成一個以其名字命名的資料夾。 ![image-20200927151507055](http://img.vcjmhg.top/20200927151508.png) 進入該檔案我們可以看到有如下四個檔案: ``` img.png lable.png label_names.txt label_viz.png ``` 其中第二個檔案使我們所需要的用於訓練的檔案,因此我們需要將該檔案整合重新命名成其原來json檔案的檔名(主要原因是保證和原圖的檔名保持一致,便於後續訓練)。 從資料夾中提取圖片並重命名,我也簡單寫了一個指令碼,可以用於參考,具體內容如下: ```python import os path = 'c:\\Users\\Administrator\\Desktop\\temp\\' output='c:\\Users\\Administrator\\Desktop\\output\\' fileDirs=os.listdir(path) for fileDir in fileDirs: file=path+fileDir+"\\label.png" if(os.path.exists(file)): # 輸出的檔案直接以上層資料夾命名 end= len(fileDir); fileName=fileDir[:end-5] os.rename(file,output+fileName+".png") ``` 此處處理完成我們便會的到一系列的mask圖片,此時我們便可以著手資料集的製作。 ## 1.3 製作資料集 正如前邊所說,我們在製作資料集的時候仿照的是pascal voc 2012的資料集,因此需要建立預期類似資料夾結構。 1. 我們首先在`models/research/deeplab/datasets`資料夾下為自己的訓練集建立一個目錄,目錄名稱即自己的訓練集名稱。執行如下命令: ```sh cd ~/models/research/deeplab/datasets mkdir mydataset cd mydataset ``` 2. 建立與voc資料集類似的資料夾 ```sh # 存放mask檔案 mkdir SegmentationClassRaw # 存放原圖 mkdir JPEGImages # 存放資料集描述檔案 mkdir Segmentation # 存放預訓練權重,如不需要預訓練權重可不建立 mkdir tf_initial_checkpoint # 訓練權重儲存目錄 mkdir train_logs # 評估以及測試結果的生成目錄 mkdir vis # 存放tfrecorde ``` 3. 將訓練資料放到指定資料夾中: 1. SegmentationClassRaw:存放mask檔案,也就是前邊我們所轉換提取的png圖片 2. JPEGImages:存放訓練集、驗證集以及測試集的原始圖片 3. Segmentation:存放資料集描述檔案,包含三個檔案`train.txt`、t`rainval.txt`、`val.txt` 1. train.txt:記錄訓練集的圖片名稱 2. trainval.txt:該檔案中所記錄的內容,後續既會被當做訓練集來訓練,後續也會被當做驗證集來做驗證 3. val.txt用以記錄驗證集的圖片名稱 4. 轉換成tfrecorde檔案。 在`dataset`目錄下,執行如下命令: ```python python3 "build_voc2012_data.py" \ --image_folder="${IMAGE_FOLDER}" \ --semantic_segmentation_folder="${SEMANTIC_SEG_FOLDER}" \ --list_folder="${LIST_FOLDER}" \ --image_format="jpg" \ --output_dir="${OUTPUT_DIR}" ``` ​ 執行成功後,會在tfrecorde目錄下出現如下檔案,證明轉換成功: ![image-20200927164917463](http://img.vcjmhg.top/20200927164918.png) # 程式碼修改 ### 在`models/research/deeplab/datasets`目錄下: * 在`remove_gt_colormap.py`修改的內容如下: 51行左右, ```python old_raw_pic=np.array(Image.open(filename)) #原來畫素比為0:1:2:3乘以50之後變成0:50:100:150 raw_pic=old_raw_pic*50 return raw_pic ``` * 在`data_generator.py`中修改的內容: 104行左右 ```python # has changed 增加資料集種類,以及訓練驗證集合的數量,修改物體類別3+1+1 _MYDATASET = DatasetDescriptor( splits_to_sizes={ 'train':392, 'trainval':98, 'val':5, }, num_classes=5, # classes+label+ignore_label ignore_label=255, ) #has changed _DATASETS_INFORMATION = { 'cityscapes': _CITYSCAPES_INFORMATION, 'pascal_voc_seg': _PASCAL_VOC_SEG_INFORMATION, 'ade20k': _ADE20K_INFORMATION, 'mydataset':_MYDATASET, } ``` ### 在`models/research/deeplab/utils`下 * 在`get_dataset_colormap.py`檔案中 在第41行左右,增加訓練種類 ```python # has changed _MYDATASET='mydataset' ``` 在388行左右,直接使用pascal的colormap ```python #has changed elif dataset == _MYDATASET: return create_pascal_label_colormap() ``` * 在`train_utils.py`中修改的內容 153行左右,進行訓練權重的修改。具體修改參考https://blog.csdn.net/jairana/article/details/83900226 ```python # has changed ignore_weight = 0 label0_weight = 1 # 對應background,mask中灰度值0 label1_weight = 10 # 對應a,mask中灰度值1 label2_weight = 10 # 對應b,mask中灰度值2 label3_weight = 10 # 對應c,mask中灰度值為3 not_ignore_mask = tf.to_float(tf.equal(scaled_labels, 0)) * label0_weight + \ tf.to_float(tf.equal(scaled_labels, 1)) * label1_weight + \ tf.to_float(tf.equal(scaled_labels, 2)) * label2_weight + \ tf.to_float(tf.equal(scaled_labels, 3)) * label3_weight + \ tf.to_float(tf.equal(scaled_labels, ignore_label)) * ignore_weight tf.losses.softmax_cross_entropy( train_labels, tf.reshape(logits, shape=[-1, num_classes]), weights=not_ignore_mask, scope=loss_scope) # end change ``` 228行,排除列表中增加logits ```python exclude_list = ['global_step','logits'] ``` ### 在目錄`models/research/deeplab/deprecated`下 * `segmentation_dataset.py`檔案中 在90行,增加資料類別 ```python #has changed _MYDATASET= DatasetDescriptor( splits_to_sizes={ 'train':392, 'trainval':98, 'val':5, }, num_classes=5, ignore_label=255,#background、ignore_label、ignore_label,即label數+2 ) ``` 在128行左右,註冊新資料集 ```python _DATASETS_INFORMATION = { 'cityscapes': _CITYSCAPES_INFORMATION, 'pascal_voc_seg': _PASCAL_VOC_SEG_INFORMATION, 'ade20k': _ADE20K_INFORMATION, # has changed 'mydataset':_MYDATASET } ``` ### 在`models/research/deeplab/train.py`目錄下 158行左右,修改兩個引數(使用所有的預訓練權重,除了logits,因為如果是自己的資料集,對應的classes不同(這個我們前面已經設定不載入logits),可設定initialize_last_layer=False和last_layers_contain_logits_only=True),可參考https://blog.csdn.net/u011974639/article/details/80948990 ```python # has changed flags.DEFINE_boolean('initialize_last_layer',False, 'Initialize the last layer.') flags.DEFINE_boolean('last_layers_contain_logits_only', True, 'Only consider logits as last layers or not.') ``` # 訓練與驗證 ## 訓練 執行如下命令開始進行訓練: ```java python train.py \ --logtostderr \ --training_number_of_steps=5000 \ --train_split="train" \ --model_variant="xception_65" \ --atrous_rates=6 \ --atrous_rates=12 \ --atrous_rates=18 \ --output_stride=16 \ --decoder_output_stride=4 \ --train_crop_size="513,513" \ --train_batch_size=12 \ --dataset="mydataset" \ --tf_initial_checkpoint='init_models/deeplabv3_pascal_train_aug/model.ckpt' \ --train_logdir='datasets/mydataset/train_logs' \ --dataset_dir='datasets/mydataset/tfrecord' ``` ## 驗證 ```java python eval.py \ --logtostderr \ --eval_split="val" \ --model_variant="xception_65" \ --atrous_rates=6 \ --atrous_rates=12 \ --atrous_rates=18 \ --output_stride=16 \ --decoder_output_stride=4 \ --eval_crop_size="1217,1921" \ --checkpoint_dir='models/research/deeplab/datasets/mydataset/train_logs' \ --eval_logdir='datasets/mydataset/eval' \ --dataset_dir='datasets/mydataset/tfrecord' \ --max_number_of_evaluations=1 ``` # 遇到的如果問題與解決方案 1. 無法找到slim。 解決方法:進入`models/research`目錄下執行 ```sh export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim:`pwd`/deeplab\ ``` 2. 資料格式不支援,檢查是否註冊了自己的數