SSD-Tensorflow 工程角度配置
Download from the github
sudo apt-get install git
git clone https://github.com/balancap/SSD-Tensorflow.git
完成以后查看tree -L 2
.
├── caffe_to_tensorflow.py
├── checkpoints
│ ├── ssd_300_vgg.ckpt.data-00000-of-00001
│ └── ssd_300_vgg.ckpt.index
├── COMMANDS.md
├── datasets
│ ├── cifar10.py
│ ├── dataset_factory.py
│ ├── dataset_utils.py
│ ├── imagenet.py
│ ├── init.py
│ ├── pascalvoc_2007.py
│ ├── pascalvoc_2012.py
│ ├── pascalvoc_common.py
│ ├── pascalvoc_to_tfrecords.py
│ └── pycache
├── demo
│ ├── 000001.jpg
│ ├── 000002.jpg
│ ├── 000003.jpg
│ ├── 000004.jpg
│ ├── 000006.jpg
│ ├── 000008.jpg
│ ├── 000010.jpg
│ ├── 000022.jpg
│ ├── dog.jpg
│ ├── eagle.jpg
│ ├── horses.jpg
│ ├── person.jpg
│ └── street.jpg
├── deployment
│ ├── init.py
│ └── model_deploy.py
├── eval_ssd_network.py
├── inspect_checkpoint.py
├── nets
│ ├── caffe_scope.py
│ ├── custom_layers.py
│ ├── inception.py
│ ├── inception_resnet_v2.py
│ ├── inception_v3.py
│ ├── init.py
│ ├── nets_factory.py
│ ├── np_methods.py
│ ├── ssd_common.py
│ ├── ssd_vgg_300.py
│ ├── ssd_vgg_512.py
│ ├── vgg.py
│ └── xception.py
├── notebooks
│ ├── ssd_notebook.ipynb
│ ├── ssd_tests.ipynb
│ └── visualization.py
├── pictures
│ ├── ex1.png
│ └── ex2.png
├── preprocessing
│ ├── inception_preprocessing.py
│ ├── init.py
│ ├── preprocessing_factory.py
│ ├── ssd_vgg_preprocessing.py
│ ├── tf_image.py
│ └── vgg_preprocessing.py
├── README.md
├── tf_convert_data.py
├── tf_extended
│ ├── bboxes.py
│ ├── image.py
│ ├── init.py
│ ├── math.py
│ ├── metrics.py
│ └── tensors.py
├── tf_utils.py
├── train_ssd_network.py
- 新建tfrecords
mkdir tfrecords
- 解壓ssd.zip
unzip ./checkpoint/ssd_300_vgg.ckpt.zip
數據集轉化tfrecords格式
首先你要有VOC2007格式的文件,具體怎么制作可以看我以前的博客Faster Rcnn中的說明。
- 准備轉化,需要使用
tf_convert_cata.py
./VOC2007/
└── test
├── Annotations
├── ImageSets
├── JPEGImages
├── SegmentationClass
└── SegmentationObject
- 將datasets中的pascalvoc_2007.py中的類別將20改為你自己的類別
- 使用(路徑可以改變)
DATASET_DIR=./VOC2007/test/
OUTPUT_DIR=./tfrecords
python tf_convert_data.py \
--dataset_name=pascalvoc \
--dataset_dir=${DATASET_DIR} \
--output_name=voc_2007_train \
--output_dir=${OUTPUT_DIR}
- 遇到的問題1
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
處理:
SSD-Tensorflow/datasets/pascaovoc_to_tfrecords.py
File "/home/learner/github/SSD-Tensorflow/datasets/pascalvoc_to_tfrecords.py", line 83, in _process_image
image_data = tf.gfile.FastGFile(filename, 'r').read()
將 r
改為rb
就可以解決
- 遇到的問題2
類別沒有改為自己的類別:pascalvoc_common.py
中記錄了所有的種類
SSD-Tensorflow/datasets/pascalvoc_common.py
將該文件中VOC_LABELS
中的label改成你的label就好了,其中none需要保留,其他的根據樣子都可以改變。
- 修改圖片讀取類型
-
image_format =b'JPEG'
-
filename = directory + DIRECTORY_IMAGES + name + '.jpg'
中 jpg 可以修改讀取圖片的類型 -
datasets文件夾下``pascalvoc_to_tfrecords.py
中
SAMPLES_PER_FILES = 1`,這里可以修改每個tfrecords中有幾個圖片
- 編寫腳本(位於
SSD-Tensorflow
下),批量測試
#!/bin/bash
#this is a shell script to convert pascal VOC datasets into tf-records only
#directory where the original dataset is stored
DATASET_DIR=./VOC2007/test/ #VOC數據保存的文件夾(VOC的目錄格式未改變)
#output directory where to store TFRecords files
OUTPUT_DIR=./tfrecords #自己建立的保存tfrecords數據的文件夾
python3 ./tf_convert_data.py \
--dataset_name=pascalvoc \
--dataset_dir=${DATASET_DIR} \
--output_name=voc_2007_train \
--output_dir=${OUTPUT_DIR}
訓練模型(pre-train)
首先必須有預訓練模型,上邊我們解壓的那個就是預訓練模型。
- 修改
train_ssd_network.py
中154行最大訓練步數,將None修改為合適的步長
mkdir logs
DATASET_DIR=./tfrecords
TRAIN_DIR=./logs/
CHECKPOINT_PATH=./checkpoints/ssd_300_vgg.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} \
--save_summaries_secs=60 \
--save_interval_secs=600 \
--weight_decay=0.0005 \
--optimizer=adam \
--learning_rate=0.001 \
--batch_size=32
train_ssd_network.py,網絡參數配置,若需要改,再此文件中進行修改
修改如下邊中的數字600,可以改變訓練多長時間保存一次模型
tf.app.flags.DEFINE_integer(
'save_summaries_secs', 600,
'The frequency with which summaries are saved, in seconds.')
tf.app.flags.DEFINE_integer(
'save_interval_secs', 600,
'The frequency with which the model is saved, in seconds.')
- 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],
- 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
- 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
- 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 #類別,根據自己數據的實際類別修改(不包含背景)
訓練方案一
從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內存的百分比
訓練方案二
從自己預訓練好的模型開始訓練(依然可以指定要訓練哪些層)
(當你的模型通過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
#/bin/bash
DATASET_DIR=/home/data/xxx/imagedata/xing_tf/train_tf/
TRAIN_DIR=/home/data/xxx/model/xing300512_model/
CHECKPOINT_PATH=/home/data/xxx/model/xing300_model/model.ckpt-60000 #加載的ssd_300_vgg模型
python3 ./train_ssd_network.py \
--train_dir=${TRAIN_DIR} \
--dataset_dir=${DATASET_DIR} \
--dataset_name=pascalvoc_2007 \
--dataset_split_name=train \
--model_name=ssd_512_vgg \
--checkpoint_path=${CHECKPOINT_PATH} \
--checkpoint_model_scope=ssd_300_vgg \
--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 \
#--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 \
--save_summaries_secs=28800 \
--save_interval_secs=28800 \
--weight_decay=0.0005 \
--optimizer=adam \
--learning_rate_decay_factor=0.94 \
--batch_size=16 \
--num_classes=4 \
-gpu_memory_fraction=0.8 \
訓練方案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
驗證
首先將測試數據轉換為tfrecords
#!/bin/bash
DATASET_DIR=./VOC2007/test #VOC數據保存的文件夾(VOC的目錄格式未改變)
#output directory where to store TFRecords files
OUTPUT_DIR=/home/xxx/imagedata/xingshizheng_tf #自己建立的保存tfrecords數據的文件夾
python ./tf_convert_data.py \
--dataset_name=pascalvoc \
--dataset_dir=${DATASET_DIR} \
--output_name=voc_2007_test \ #注意修改為test
--output_dir=${OUTPUT_DIR}
建立一個sh,用於驗證的信息存儲
#!/bin/bash
DATASET_DIR=./tfrecords/ #保存的轉換為tfrcodes格式的數據
EVAL_DIR=./logs/ # Directory where the results are saved to
CHECKPOINT_PATH=./checkpoints/ssd_vgg_300.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
利用ssd_notebook.ipynb顯示訓練測試模型的結果
# Restore SSD model
將ckpt_filename=‘ ’路徑進行修改
# Test on some demo image and visualize output
將path=‘ ’路徑進行修改為自己的
- 注意事項
- –dataset_name=pascalvoc_2007 、–dataset_split_name=train、–model_name=ssd_300_vgg這三個參數不要隨便取,是比較固定的判斷值
- 如果不想使用預訓練的模型,需要將
--checkpoint_path=${CHECKPOINT_PATH} \
注釋掉即可 - 有時候運行腳本會報錯,可能是之前依次運行導致顯存占滿。
-
- 在TRAIN_DIR路徑下會產生四中文件:
-
- checkpoint :文本文件,包含所有model.ckpt-xxxx,相當於是不同時間節點生成的所有ckpt文件的一個索引。
- model.ckpt-2124.data-000000-of-000001:模型文件,保存模型的權重
- model.ckpt-2124.meta:圖文件,保存模型的網絡圖
- model.ckpt-2124.index : 這個沒搞太清楚
- graph.pbtxt: 用protobuf格式保存的模型的圖
-
- 在TRAIN_DIR路徑下會產生四中文件:
錯誤
-
報錯:參照這個博客進行修改
https://blog.csdn.net/w5688414/article/details/78529884 -
報錯如下
InvalidArgumentError (see above for traceback): Assign requires shapes of both tensors to match. lhs shape= [16] rhs shape= [84]
[[Node: save_1/Assign_4 = Assign[T=DT_FLOAT, _class=["loc:@ssd_300_vgg/block10_box/conv_cls/biases"], use_locking=true, validate_shape=true, _device="/job:localhost/replica:0/task:
0/device:CPU:0"](ssd_300_vgg/block10_box/conv_cls/biases, save_1/RestoreV2_4)]]
添加上:
--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 \
如果遇到這種情況,那么將checkpoint中的內容刪除或者備份就好了
Reference
https://blog.csdn.net/liuyan20062010/article/details/78905517
https://blog.csdn.net/weixin_39881922/article/details/80569803
https://blog.csdn.net/weixin_39881922/article/details/80569803