參考:
http://blog.csdn.net/liuyan20062010/article/details/789055171. 搭建SSD框架,下載解壓即可
下載SSD-tensorflow並解壓
https://github.com/balancap/SSD-Tensorflow
2. 下載官方數據
下載VOC2007和VOC2012數據集, 放在/imagedata目錄下:
cd imagedata
wget http://host.robots.ox.ac.uk/pascal/VOC/voc2012/VOCtrainval_11-May-2012.tar
wget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtrainval_06-Nov-2007.tar
wget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtest_06-Nov-2007.tar
tar -xvf VOCtrainval_11-May-2012.tar
tar -xvf VOCtrainval_06-Nov-2007.tar
tar -xvf VOCtest_06-Nov-2007.tar
下載pascalvoc數據,解壓後生成三個文件夾,主要是利用訓練集測試的文件夾,VOCtrainval用來訓練,VOCtest用來測試。
VOCtrainval 中JPEGImage文件夾中僅是訓練和驗證的圖片,Main文件夾中僅是trainval.txt, train.txt, val.txt
VOCtest中JPEGImage文件夾中僅是測試圖片,Main文件夾中僅是test.txt
3. 自己的圖片
自己的數據根據voc格式改寫(圖片的名稱,不用拘泥於6位數字,其他命名也可以)
圖片數據重命名爲6位數字的代碼如下:
python代碼
- import os
- class BatchRename():
- # '''''
- # 批量重命名文件夾中的圖片文件
- # '''
- def __init__(self):
- #我的圖片文件夾路徑horse
- self.path = '/home/xxx/imagedata/image_xml'
- def rename(self):
- filelist = os.listdir(self.path)
- total_num = len(filelist)
- i = 1
- n = 6
- for item in filelist:
- if item.endswith('.jpg'):
- n = 6 - len(str(i))
- src = os.path.join(os.path.abspath(self.path), item)
- dst = os.path.join(os.path.abspath(self.path), str(0)*n + str(i) + '.jpg')
- try:
- os.rename(src, dst)
- print 'converting %s to %s ...' % (src, dst)
- i = i + 1
- except:
- continue
- print 'total %d to rename & converted %d jpgs' % (total_num, i)
- if __name__ == '__main__':
- demo = BatchRename()
- demo.rename()
4.標記數據 標註工具:windows_v1.5.0
5.生成txt文件,train.txt, trainval.txt, test.txt, val.txt
python代碼
- import os
- import random
- xmlfilepath=r'/home/xxx/subimage_xml_xiao'
- saveBasePath=r"/home/xxx/txt"
- trainval_percent=0.7
- train_percent=0.7
- total_xml = os.listdir(xmlfilepath)
- num=len(total_xml)
- list=range(num)
- tv=int(num*trainval_percent)
- tr=int(tv*train_percent)
- trainval= random.sample(list,tv)
- train=random.sample(trainval,tr)
- print("train and val size",tv)
- print("traub suze",tr)
- ftrainval = open(os.path.join(saveBasePath,'Main/trainval.txt'), 'w')
- ftest = open(os.path.join(saveBasePath,'Main/test.txt'), 'w')
- ftrain = open(os.path.join(saveBasePath,'Main/train.txt'), 'w')
- fval = open(os.path.join(saveBasePath,'Main/val.txt'), 'w')
- for i in list:
- name=total_xml[i][:-4]+'\n'
- if i in trainval:
- ftrainval.write(name)
- if i in train:
- ftrain.write(name)
- else:
- fval.write(name)
- else:
- ftest.write(name)
- ftrainval.close()
- ftrain.close()
- fval.close()
- ftest .close()
6. 將訓練類別修改爲和自己一樣的
SSD-Tensorflow-master—>datasets—>pascalvoc_common.py
根據實際情況進行修改
- VOC_LABELS = {
- 'none': (0, 'Background'),
- 'aeroplane': (1, 'Vehicle'),
- 'bicycle': (2, 'Vehicle'),
- 'bird': (3, 'Animal'),
- 'boat': (4, 'Vehicle'),
- 'bottle': (5, 'Indoor'),
- 'bus': (6, 'Vehicle'),
- 'car': (7, 'Vehicle'),
- 'cat': (8, 'Animal'),
- 'chair': (9, 'Indoor'),
- 'cow': (10, 'Animal'),
- 'diningtable': (11, 'Indoor'),
- 'dog': (12, 'Animal'),
- 'horse': (13, 'Animal'),
- 'motorbike': (14, 'Vehicle'),
- 'Person': (15, 'Person'),
- 'pottedplant': (16, 'Indoor'),
- 'sheep': (17, 'Animal'),
- 'sofa': (18, 'Indoor'),
- 'train': (19, 'Vehicle'),
- 'tvmonitor': (20, 'Indoor'),
- }
7. 將圖像數據轉換爲tfrecods格式
SSD-Tensorflow-master—>datasets—>pascalvoc_to_tfrecords.py 。。。然後更改文件的83行讀取方式爲’rb’)
修改67行,可以修改幾張圖片轉爲一個tfrecords,如下圖
在SSD-Tensorflow-master文件夾下創建tf_conver_data.sh (vi tf_conver_data.sh)
注意:tab鍵和空格鍵不能混合用。
- 1 #!/bin/bash
- 2 #this is a shell script to convert pascal VOC datasets into tf-records only
- 3 #directory where the original dataset is stored
- 4
- 5 DATASET_DIR=/home/xxx/imagedata/VOCdevkit/VOC2007/ #VOC數據保存的文件夾(VOC的目錄格式未改變)
- 6
- 7 #output directory where to store TFRecords files
- 8 OUTPUT_DIR=/home/xxx/imagedata/tf_records #自己建立的保存tfrecords數據的文件夾
- 9
- 10 python ./tf_convert_data.py \
- 11 --dataset_name=pascalvoc \
- 12 --dataset_dir=${DATASET_DIR} \
- 13 --output_name=voc_2007_train \
- 14 --output_dir=${OUTPUT_DIR}
- ~
train_ssd_network.py修改第154行的最大訓練步數,將None改爲比如50000。(tf.contrib.slim.learning.training函數中max-step爲None時訓練會無限進行。)
train_ssd_network.py:
網絡參數配置,若需要改,在此文件中進行修改,因爲不知道爲啥修改後面的sh文件沒有效。如果訓練時loss爲nan,則把該學習率改小0.1倍。網絡內存不夠訓練時,把batch_size(32->16)和最大訓練步數(50000->5000)改小。
修改如下圖中的數字600,可以改變訓練多長時間保存一次模型
需要修改的地方:
a. nets/ssd_vgg_300.py (因爲使用此網絡結構) ,修改87 和88行的類別
- default_params = SSDParams(
- img_shape=(300, 300),
- num_classes=21, #根據自己的數據修改爲類別+1
- no_annotation_label=21, #根據自己的數據修改爲類別+1
- feat_layers=['block4', 'block7', 'block8', 'block9', 'block10', 'block11'],
- feat_shapes=[(38, 38), (19, 19), (10, 10), (5, 5), (3, 3), (1, 1)],
- anchor_size_bounds=[0.15, 0.90],
- # anchor_size_bounds=[0.20, 0.90],
- tf.app.flags.DEFINE_integer(
- 'num_classes', 21, 'Number of classes to use in the dataset.')
- #根據自己的數據修改爲類別+1
c. eval_ssd_network.py 修改類別,66行
- # =========================================================================== #
- # Main evaluation flags.
- # =========================================================================== #
- tf.app.flags.DEFINE_integer(
- 'num_classes', 21, 'Number of classes to use in the dataset.')
- #根據自己的數據修改爲類別+1
d. datasets/pascalvoc_2007.py 根據自己的訓練數據修改整個文件
- TRAIN_STATISTICS = {
- 'none': (0, 0),
- 'aeroplane': (238, 306), #238圖片書, 306目標總數
- 'bicycle': (243, 353),
- 'bird': (330, 486),
- 'boat': (181, 290),
- 'bottle': (244, 505),
- 'bus': (186, 229),
- 'car': (713, 1250),
- 'cat': (337, 376),
- 'chair': (445, 798),
- 'cow': (141, 259),
- 'diningtable': (200, 215),
- 'dog': (421, 510),
- 'horse': (287, 362),
- 'motorbike': (245, 339),
- 'person': (2008, 4690),
- 'pottedplant': (245, 514),
- 'sheep': (96, 257),
- 'sofa': (229, 248),
- 'train': (261, 297),
- 'tvmonitor': (256, 324),
- 'total': (5011, 12608), //5011 爲訓練的圖片書,12608爲目標總數
- }
- TEST_STATISTICS = {
- 'none': (0, 0),
- 'aeroplane': (1, 1),
- 'bicycle': (1, 1),
- 'bird': (1, 1),
- 'boat': (1, 1),
- 'bottle': (1, 1),
- 'bus': (1, 1),
- 'car': (1, 1),
- 'cat': (1, 1),
- 'chair': (1, 1),
- 'cow': (1, 1),
- 'diningtable': (1, 1),
- 'dog': (1, 1),
- 'horse': (1, 1),
- 'motorbike': (1, 1),
- 'person': (1, 1),
- 'pottedplant': (1, 1),
- 'sheep': (1, 1),
- 'sofa': (1, 1),
- 'train': (1, 1),
- 'tvmonitor': (1, 1),
- 'total': (20, 20),
- }
- SPLITS_TO_SIZES = {
- 'train': 5011, #訓練數據量
- 'test': 4952, #測試數據量
- }
- SPLITS_TO_STATISTICS = {
- 'train': TRAIN_STATISTICS,
- 'test': TEST_STATISTICS,
- }
- NUM_CLASSES = 20 #類別,根據自己數據的實際類別修改(不包含背景)
方案1 從vgg開始訓練其中某些層的參數:
ssd_300_vgg中的300是指把圖片歸一化爲300*300,所以如果要用ssd_512_vgg來fineturn的話,就只需要重新訓練受圖片分辨率影響的層即可。
- # 通過加載預訓練好的vgg16模型,對“voc07trainval+voc2012”進行訓練
- # 通過checkpoint_exclude_scopes指定哪些層的參數不需要從vgg16模型裏面加載進來
- # 通過trainable_scopes指定哪些層的參數是需要訓練的,未指定的參數保持不變,<strong>若註釋掉此命令,所有的參數均需要訓練</strong>
- DATASET_DIR=/home/data/liangxiaoyun/SSD-Tensorflow-master/dataset/VOC0712/
- TRAIN_DIR=/home/data/liangxiaoyun/SSD-Tensorflow-master/voc0712_model/
- CHECKPOINT_PATH=../checkpoints/vgg_16.ckpt
- python ../train_ssd_network.py \
- --train_dir=${TRAIN_DIR} \ #訓練生成模型的存放路徑
- --dataset_dir=${DATASET_DIR} \ #數據存放路徑
- --dataset_name=pascalvoc_2007 \ #數據名的前綴
- --dataset_split_name=train \
- --model_name=ssd_300_vgg \ #加載的模型的名字
- --checkpoint_path=${CHECKPOINT_PATH} \ #所加載模型的路徑
- --checkpoint_model_scope=vgg_16 \ #所加載模型裏面的作用域名
- --checkpoint_exclude_scopes=ssd_300_vgg/conv6,ssd_300_vgg/conv7,ssd_300_vgg/block8,ssd_300_vgg/block9,ssd_300_vgg/block10,ssd_300_vgg/block11,ssd_300_vgg/block4_box,ssd_300_vgg/block7_box,ssd_300_vgg/block8_box,ssd_300_vgg/block9_box,ssd_300_vgg/block10_box,ssd_300_vgg/block11_box \
- --trainable_scopes=ssd_300_vgg/conv6,ssd_300_vgg/conv7,ssd_300_vgg/block8,ssd_300_vgg/block9,ssd_300_vgg/block10,ssd_300_vgg/block11,ssd_300_vgg/block4_box,ssd_300_vgg/block7_box,ssd_300_vgg/block8_box,ssd_300_vgg/block9_box,ssd_300_vgg/block10_box,ssd_300_vgg/block11_box \
- --save_summaries_secs=60 \ #每60s保存一下日誌
- --save_interval_secs=600 \ #每600s保存一下模型
- --weight_decay=0.0005 \ #正則化的權值衰減的係數
- --optimizer=adam \ #選取的最優化函數
- --learning_rate=0.001 \ #學習率
- --learning_rate_decay_factor=0.94 \ #學習率的衰減因子
- --batch_size=24 \
- --gpu_memory_fraction=0.9 #指定佔用gpu內存的百分比
方案2 : 從自己預訓練好的模型開始訓練(依然可以指定要訓練哪些層)
- (當你的模型通過vgg訓練的模型收斂到大概o.5mAP的時候,可以進行這一步的fine-tune)
- # 通過加載預訓練好的vgg16模型,對“voc07trainval+voc2012”進行訓練
- # 通過checkpoint_exclude_scopes指定哪些層的參數不需要從vgg16模型裏面加載進來
- # 通過trainable_scopes指定哪些層的參數是需要訓練的,未指定的參數保持不變
- DATASET_DIR=/home/doctorimage/kindlehe/common/dataset/VOC0712/
- TRAIN_DIR=.././log_files/log_finetune/train_voc0712_20170816_1654_VGG16/
- CHECKPOINT_PATH=./log_files/log_finetune/train_voc0712_20170712_1741_VGG16/model.ckpt-253287
- python3 ../train_ssd_network.py \
- --train_dir=${TRAIN_DIR} \ #訓練生成模型的存放路徑
- --dataset_dir=${DATASET_DIR} \ #數據存放路徑
- --dataset_name=pascalvoc_2007 \ #數據名的前綴
- --dataset_split_name=train \
- --model_name=ssd_300_vgg \ #加載的模型的名字
- --checkpoint_path=${CHECKPOINT_PATH} \ #所加載模型的路徑
- --checkpoint_model_scope=vgg_16 \ #所加載模型裏面的作用域名
- --checkpoint_exclude_scopes=ssd_300_vgg/conv6,ssd_300_vgg/conv7,ssd_300_vgg/block8,ssd_300_vgg/block9,ssd_300_vgg/block10,ssd_300_vgg/block11,ssd_300_vgg/block4_box,ssd_300_vgg/block7_box,ssd_300_vgg/block8_box,ssd_300_vgg/block9_box,ssd_300_vgg/block10_box,ssd_300_vgg/block11_box \
- --trainable_scopes=ssd_300_vgg/conv6,ssd_300_vgg/conv7,ssd_300_vgg/block8,ssd_300_vgg/block9,ssd_300_vgg/block10,ssd_300_vgg/block11,ssd_300_vgg/block4_box,ssd_300_vgg/block7_box,ssd_300_vgg/block8_box,ssd_300_vgg/block9_box,ssd_300_vgg/block10_box,ssd_300_vgg/block11_box \
- --save_summaries_secs=60 \ #每60s保存一下日誌
- --save_interval_secs=600 \ #每600s保存一下模型
- --weight_decay=0.0005 \ #正則化的權值衰減的係數
- --optimizer=adam \ #選取的最優化函數
- --learning_rate=0.001 \ #學習率
- --learning_rate_decay_factor=0.94 \ #學習率的衰減因子
- --batch_size=24 \
- --gpu_memory_fraction=0.9 #指定佔用gpu內存的百分比
從自己訓練的ssd_300_vgg模型開始訓練ssd_512_vgg的模型
因此ssd_300_vgg中沒有block12,又因爲block7,block8,block9,block10,block11,中的參數張量兩個網絡模型中不匹配,因此ssd_512_vgg中這幾個模塊的參數不從ssd_300_vgg模型中繼承,因此使用checkpoint_exclude_scopes命令指出。
因爲所有的參數均需要訓練,因此不使用命令--trainable_scopes
- 1 #/bin/bash
- 2 DATASET_DIR=/home/data/xxx/imagedata/xing_tf/train_tf/
- 3 TRAIN_DIR=/home/data/xxx/model/xing300512_model/
- 4 CHECKPOINT_PATH=/home/data/xxx/model/xing300_model/model.ckpt-60000 #加載的ssd_300_vgg模型
- 5 python3 ./train_ssd_network.py \
- 6 --train_dir=${TRAIN_DIR} \
- 7 --dataset_dir=${DATASET_DIR} \
- 8 --dataset_name=pascalvoc_2007 \
- 9 --dataset_split_name=train \
- 10 --model_name=ssd_512_vgg \
- 11 --checkpoint_path=${CHECKPOINT_PATH} \
- 12 --checkpoint_model_scope=ssd_300_vgg \
- 13 --checkpoint_exclude_scopes=ssd_512_vgg/block7,ssd_512_vgg/block7_box,ssd_512_vgg/block8,ssd_512_vgg/block8_box, ssd_512_vgg/block9,ssd_512_vgg/block9_box,ssd_512_vgg/block10,ssd_512_vgg/block10_box,ssd_512_vgg/block11,ssd_512_vgg/b lock11_box,ssd_512_vgg/block12,ssd_512_vgg/block12_box \
- 14 #--trainable_scopes=ssd_300_vgg/conv6,ssd_300_vgg/conv7,ssd_300_vgg/block8,ssd_300_vgg/block9,ssd_300_vgg/block1 0,ssd_300_vgg/block11,ssd_300_vgg/block4_box,ssd_300_vgg/block7_box,ssd_300_vgg/block8_box,ssd_300_vgg/block9_box,ssd_3 00_vgg/block10_box,ssd_300_vgg/block11_box \
- 15 --save_summaries_secs=28800 \
- 16 --save_interval_secs=28800 \
- 17 --weight_decay=0.0005 \
- 18 --optimizer=adam \
- 19 --learning_rate_decay_factor=0.94 \
- 20 --batch_size=16 \
- 21 --num_classes=4 \
- 22 -gpu_memory_fraction=0.8 \
- 23
方案3:從頭開始訓練自己的模型
- # 註釋掉CHECKPOINT_PATH,不提供初始化模型,讓模型自己隨機初始化權重,從頭訓練
- # 刪除checkpoint_exclude_scopes和trainable_scopes,因爲是從頭開始訓練
- #/bin/bash
2 DATASET_DIR=/home/data/liangxiaoyun/SSD-Tensorflow-master/imagedata/VOCtrainval_06-Nov-2007/tfrecords/
3 TRAIN_DIR=/home/data/liangxiaoyun/SSD-Tensorflow-master/VOC2007_model/
4 #CHECKPOINT_PATH=/home/data/liuyan/model/xingshizheng512_model/model.ckpt-60000
5 CUDA_VISIBLE_DEVICES=0 python ./train_ssd_network.py \
6 --train_dir=${TRAIN_DIR} \
7 --dataset_dir=${DATASET_DIR} \
8 --dataset_name=pascalvoc_2007 \
9 --dataset_split_name=train \
10 --model_name=ssd_300_vgg \
11 #--checkpoint_path=${CHECKPOINT_PATH} \
12 #--checkpoint_model_scope=ssd_512_vgg \
13 #--checkpoint_exclude_scopes=ssd_300_vgg/block10,ssd_300_vgg/block10_box,ssd_300_vgg/block11,ssd_300_vgg/block11_bo x \
14 #--checkpoint_exclude_scopes=ssd_512_vgg/conv6,ssd_512_vgg/conv7,ssd_512_vgg/block8,ssd_512_vgg/block9,ssd_512_vgg/ block10,ssd_512_vgg/block11,ssd_512_vgg/block4_box,ssd_512_vgg/block7_box,ssd_512_vgg/block8_box,ssd_512_vgg/block9_box,ss d_512_vgg/block10_box,ssd_512_vgg/block11_box \
15 #--trainable_scopes=ssd_300_vgg/conv6,ssd_300_vgg/conv7,ssd_300_vgg/block8,ssd_300_vgg/block9,ssd_300_vgg/block10,s sd_300_vgg/block11,ssd_300_vgg/block4_box,ssd_300_vgg/block7_box,ssd_300_vgg/block8_box,ssd_300_vgg/block9_box,ssd_300_vgg /block10_box,ssd_300_vgg/block11_box \
16 --save_summaries_secs=600 \
17 --save_interval_secs=600 \
18 --optimizer=adam \
19 --learning_rate_decay_factor=0.94 \
20 --batch_size=32 \
21 --num_classes=20 \
8. 測試或驗證
首先將測試數據轉換爲tfrecords
- 1 #!/bin/bash
2 #this is a shell script to convert pascal VOC datasets into tf-records only
3 #directory where the original dataset is stored
4 DATASET_DIR=/home/data/liangxiaoyun/SSD-Tensorflow-master/imagedata/VOCtest_06-Nov-2007/VOCdevkit/VOC2007/
5 #OUTPUT directory where to store TFRecords files
6 OUTPUT_DIR=/home/data/liangxiaoyun/SSD-Tensorflow-master/imagedata/VOCtest_06-Nov-2007/tfrecords
7 python ./tf_convert_data.py \
8 --dataset_name=pascalvoc \
9 --dataset_dir=${DATASET_DIR} \
10 --output_name=voc_2007_test \
11 --output_dir=${OUTPUT_DIR}
在SSD-Tensorflow-master文件夾下建立一個sh文件
測試結果如下:MAP值太低,至少得0.5才能準確檢測。增加迭代次數。
9. 利用在notebooks下的ssd_notebook.ipy來查看模型標註的圖片。ssd_notebook.ipynb顯示訓練測試模型的結果
修改紅框標註的位置,一個是修改爲自己的模型所在的路徑,另一個是修改爲自己圖片所在的路徑
10. 注意
- <pre name="code" class="html"><blockquote><ol><li>–dataset_name=pascalvoc_2007 、–dataset_split_name=train、–model_name=ssd_300_vgg這三個參數不要自己隨便取,在代碼裏,這三個參數是if…else…語句,有固定的判斷值,所以要根據實際情況取選擇</li><li>TypeError: expected bytes, NoneType found
- SystemError: returned a result with an error set
- 這是由於CHECKPOINT_PATH定義的時候不小心多了個#號鍵,將輸入給註釋掉了,如果不想使用預訓練的模型,需要將<code>--checkpoint_path=${CHECKPOINT_PATH} \</code>註釋掉即可</li><li>SSD有在VOC07+12的訓練集上一起訓練的,用一個笨一點的辦法:
- pascalvoc_to_tfrecords.py文件中,改變SAMPLES_PER_FILES,減少輸出tfrecord文件的個數,再修改tf_convert_data.py的dataset參數,記得將前後兩次的輸出名改變一下,前後兩次轉換的tfrecords放在同一個文件夾下,然後手工重命名。(這裏由於只是驗證論文的訓練方法是否有效,所以沒必要寫這些自動化代碼實現合併,以後要用自己的數據集訓練的時候就可以寫一些自動化腳本)</li><li>有時候運行腳本會報錯,可能是之前依次運行導致顯存佔滿。</li><li>從pyCharm運行時,如果模型保存路徑裏之前的模型未刪除,將會報錯,必須保證該文件夾爲空。</li><li>在TRAIN_DIR路徑下會產生四中文件:
- 1. checkpoint :文本文件,包含所有model.ckpt-xxxx,相當於是不同時間節點生成的所有ckpt文件的一個索引。
- 2. model.ckpt-2124.data-000000-of-000001:模型文件,保存模型的權重
- 3. model.ckpt-2124.meta: 圖文件,保存模型的網絡圖
- 4. model.ckpt-2124.index : 這個沒搞太清楚
- 5. graph.pbtxt: 用protobuf格式保存的模型的圖
- </li></ol></blockquote></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>