【文字檢測】SSD+Tensorflow 300&512 配置詳解
SSD_300_vgg和SSD_512_vgg weights下載連結【需要科學上網~】:
Model | Training data | Testing data | mAP | FPS |
---|---|---|---|---|
VOC07+12+COCO trainval | VOC07 test | 0.817 | - | |
VOC07+12 trainval | VOC07 test | 0.778 | - | |
VOC07+12+COCO trainval | VOC07 test | 0.837 | - |
我的csdn下載連結【沒法科學上網的同學】:
2. 下載pascalvoc資料,自己的資料根據voc格式改寫(圖片的名稱,不用拘泥於6位數字,其他命名也可以)
解壓後不要混合在一個資料夾下,要生成三個,主要是利用訓練集測試的資料夾,VOCtrainval用來訓練,VOCtest用來測試。
VOCtrainval 中JPEGImage資料夾中僅是訓練和驗證的圖片,Main資料夾中僅是trainval.txt, train.txt, val.txt
VOCtest中JPEGImage資料夾中僅是測試圖片,Main資料夾中僅是test.txt.
3. 圖片資料重新命名為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()
3.標記資料
4.生成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()
5. 將訓練類別修改為和自己一樣的
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'),
}
6. 將影象資料轉換為tfrecods格式
SSD-Tensorflow-master—>datasets—>pascalvoc_to_tfrecords.py 。。。然後更改檔案的83行讀取方式為’rb’)
修改讀取圖片的型別:修改如下兩個地方
“image_format = b'JPEG'”
“filename = directory + DIRECTORY_IMAGES + name + '.jpg'”中 jpg 可以修改讀取圖片的型別
修改67行,可以修改幾張圖片轉為一個tfrecords,如下圖
在SSD-Tensorflow-master資料夾下建立tf_conver_data.sh
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/xingshizheng_tf #自己建立的儲存tfrecords資料的資料夾
9
10 python3 ./tf_convert_data.py \
11 --dataset_name=pascalvoc \
12 --dataset_dir=${DATASET_DIR} \
13 --output_name=voc_2007_train \
14 --output_dir=${OUTPUT_DIR}
~
7. 訓練模型
train_ssd_network.py修改第154行的最大訓練步數,將None改為比如50000。(tf.contrib.slim.learning.training函式中max-step為None時訓練會無限進行。)
train_ssd_network.py,網路引數配置,若需要改,再此檔案中進行修改
修改如下圖中的數字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],
b. train_ssd_network.py,修改類別120行,GPU佔用量,學習率,batch_size等
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開始訓練其中某些層的引數
# 通過載入預訓練好的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=../checkpoints/vgg_16.ckpt
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記憶體的百分比
方案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
另外由300轉512後還需修改:
1. 首先修改ssd_vgg_512.py的訓練類別
2.修改train_ssd_network.py的model_name
修改為ssd_512_vgg
3. 修改nets/np_methods.py
修改:將300改為512, 將類別改為自己資料的類別(+背景)
4. 修改preprocessing/ssd_vgg_preprocessing.py
修改:將300改為512
5. 修改ssd_notbook.ipynb
a 將檔案中數字“300”改為“512”
方案3:從頭開始訓練自己的模型
# 註釋掉CHECKPOINT_PATH,不提供初始化模型,讓模型自己隨機初始化權重,從頭訓練
# 刪除checkpoint_exclude_scopes和trainable_scopes,因為是從頭開始訓練
# 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 \ #所載入模型裡面的作用域名
--save_summaries_secs=60 \ #每60s儲存一下日誌
--save_interval_secs=600 \ #每600s儲存一下模型
--weight_decay=0.0005 \ #正則化的權值衰減的係數
--optimizer=adam \ #選取的最優化函式
--learning_rate=0.00001 \ #學習率
--learning_rate_decay_factor=0.94 \ #學習率的衰減因子
--batch_size=32
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
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/xingshizheng_tf #自己建立的儲存tfrecords資料的資料夾
9
10 python3 ./tf_convert_data.py \
11 --dataset_name=pascalvoc \
12 --dataset_dir=${DATASET_DIR} \
13 --output_name=voc_2007_test \ #注意修改為test
14 --output_dir=${OUTPUT_DIR}
~
在SSD-Tensorflow-master資料夾下建立一個sh檔案
#!/bin/bash
# This is the eval script.
DATASET_DIR=/home/xxx/voc2007_test_tfrecords/ #儲存的轉換為tfrcodes格式的資料
EVAL_DIR=/home/xxx/ssd_eval_log/ # Directory where the results are saved to
CHECKPOINT_PATH=/home/xxx/Downloads/SSD-Tensorflow-master/checkpoints/VGG_VOC0712_SSD_300x300_iter_120000.ckpt #換為自己訓練的模型
python3 ./eval_ssd_network.py \
--eval_dir=${EVAL_DIR} \
--dataset_dir=${DATASET_DIR} \
--dataset_name=pascalvoc_2007 \
--dataset_split_name=test \
--model_name=ssd_300_vgg \
--checkpoint_path=${CHECKPOINT_PATH} \
--batch_size=1
9. 利用ssd_notebook.ipynb顯示訓練測試模型的結果
修改紅框標註的位置,一個是修改為自己的模型所在的路徑,另一個是修改為自己圖片所在的路徑
10. 注意
- –dataset_name=pascalvoc_2007 、–dataset_split_name=train、–model_name=ssd_300_vgg這三個引數不要自己隨便取,在程式碼裡,這三個引數是if…else…語句,有固定的判斷值,所以要根據實際情況取選擇
- TypeError: expected bytes, NoneType found SystemError: returned a result with an error set 這是由於CHECKPOINT_PATH定義的時候不小心多了個#號鍵,將輸入給註釋掉了,如果不想使用預訓練的模型,需要將--checkpoint_path=${CHECKPOINT_PATH} \註釋掉即可
- SSD有在VOC07+12的訓練集上一起訓練的,用一個笨一點的辦法: pascalvoc_to_tfrecords.py檔案中,改變SAMPLES_PER_FILES,減少輸出tfrecord檔案的個數,再修改tf_convert_data.py的dataset引數,記得將前後兩次的輸出名改變一下,前後兩次轉換的tfrecords放在同一個資料夾下,然後手工重新命名。(這裡由於只是驗證論文的訓練方法是否有效,所以沒必要寫這些自動化程式碼實現合併,以後要用自己的資料集訓練的時候就可以寫一些自動化指令碼)
- 有時候執行指令碼會報錯,可能是之前依次執行導致視訊記憶體佔滿。
- 從pyCharm執行時,如果模型儲存路徑裡之前的模型未刪除,將會報錯,必須保證該資料夾為空。
- 在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格式儲存的模型的圖