SSD-tensorflow使用文件(測試訓練基本流程)
原博文:
SSD: Single Shot MultiBox Detector in TensorFlow
這裡只從工程的角度介紹這份程式碼的使用方法,參照github上 balancap這個人 根據論文作者提供的caffe原始碼復現的tensorflow程式碼及其給出的教程,並加入了自己的一些補充和理解
補充:在ssd-tensorflow程式碼的fix_training分支中,作者增加了如下幾點:
1. use a very simple data pre-processing pipeline at beginning to test out the training script;
2. use the argument trainable_scopes for only training the new parts of the network. Then, in a second time, fine tune the full network.
3. I implement an hard mining which is equivalent to the SSD Caffe, and looking at how to improve the data augmentation part.
1.基本介紹
這裡只實現了 SSD-300 VGG-based 和 SSD-512 VGG-based 兩個版本,但這個project的框架的模組化應該可以保證SSD的其他變種(如ResNet or Inception 版本)實現起來也不難,等有時間我嘗試好之後會分享給大家的。
本project的組織結構受啟發於TF-Slim models repository,TF-slim包含了當下流行的ResNet, Inception and VGG結構。主要包括3個部分:
- datasets:(Pasca VOC 2007_trainval,2007_test, 2012,COCO)這些資料集的介面和 將其轉為tensorflow專用TF-Records格式的指令碼檔案。
- networks: SSD網路結構的定義,常用的encoding和decoding方法(refer to the paper on this precise topic)
- pre-processing: pre-processing and data augmentation routines, inspired by original VGG and Inception implementations.
2.SSD minimal example
利用jupyter Notebook可以輕鬆的執行SSD的一個測試用例,你要做的就是:
1. 下載模型ssd_300_vgg,存放在SSD-Tensorflow-master/checkpoints/這個目錄下
2. 開啟終端,在主目錄 SSD-Tensorflow-master 下,執行cd notebooks/
jupyter-notebook
進入http://localhost:8892/tree伺服器,開啟 ssd_notebook.ipynb.ipynb檔案 3. 配置一些路徑:第4個cell中
from notebooks import visualization
改成import notebooks
,不改的話目錄結構不對,會報錯 4. 使用自己的圖片,改變
path = '../demo/'
成自己的圖片所在路徑 5. 從頭到尾執行所有cell即可。
我在網上隨便找了張圖片測試了一下,效果確實還不錯,只是這個程式碼沒有把標籤對應的種類顯示在上面,懶得改了,以後用的時候再說,上圖啦:
分析:估計這裡2代表自行車把,15代表人把,但是第二張圖的手勢也是別未15(人類),估計分類裡面沒有手勢這一項把。後續將進行更多的測試,這裡先介紹到這裡。
3.論文效果
小例子跑起來之後,當然不能就這麼滿足了,要給自己定個小目標,自然就是要通過自己的訓練達到接近論文的效果。
- SSD作者本人用caffe實現的程式碼所達到的效果如下:
System | VOC2007 test mAP | FPS (Titan X) | Number of Boxes | Input resolution |
---|---|---|---|---|
Faster R-CNN (VGG16) | 73.2 | 7 | ~6000 | ~1000 x 600 |
YOLO (customized) | 63.4 | 45 | 98 | 448 x 448 |
SSD300* (VGG16) | 77.2 | 46 | 8732 | 300 x 300 |
SSD512* (VGG16) | 79.8 | 19 | 24564 | 512 x 512 |
Note: SSD300* and SSD512* are the latest models. Current code should reproduce these results.
這裡tensorflow版本程式碼效果如下:
Model Training data Testing data mAP FPS VOC07+12 trainval VOC07 test 0.778 - VOC07+12+COCO trainval VOC07 test 0.817 - VOC07+12+COCO trainval VOC07 test 0.837 -
對比發現,tensorflow版本的效果與caffe版本程式碼相當的效果。
4. 行動指南
4.1 製作資料集
以VOC2007為例,目錄結構如下
+VOCtrainval_06-Nov-2007
+VOCdevkit
+VOC2007
+Annotations
+ImageSets
+JPEGImages
+SegmentationClass
+SegmentationObject
+VOCtest_06-Nov-2007
+VOCdevkit
+VOC2007
+Annotations
+ImageSets
+JPEGImages
+SegmentationClass
+SegmentationObject
為了避免每次在終端敲那麼多字母,建議新建一個.sh檔案,把以下指令碼貼上進去,只要在這裡更改dataset的路徑就可以了,最後在檔案所在目錄開啟終端並輸入bash tf_convert_data.sh
:(本教程所建立的所有shell指令碼都存放在/root/shell/這個資料夾下)
#filename = tf_convert_data.sh
#!/bin/bash
#This is a shell script to convert Pascal VOC datasets(2007 and 2012) into TF-Records only.
#Directory where the original dataset is stored
DATASET_DIR=/root/VOCtrainval_06-Nov-2007/VOCdevkit/VOC2007/
#Output directory where to store TFRecords files
OUTPUT_DIR=/root/VOCtrainval_06-Nov-2007/VOCdevkit/VOC2007_tfrecord/
python ../tf_convert_data.py \
--dataset_name=pascalvoc \
--dataset_dir=${DATASET_DIR} \
--output_name=voc_2007_train \
--output_dir=${OUTPUT_DIR}
4.2 驗證
下載好三個checkpoint:SSD-300 VGG-based, SSD-300 VGG-based, SSD-512 VGG-based,為了 reproduce evaluation metrics on the recall-precision curve && compute mAP metrics following the Pascal VOC 2007 and 2012 guidelines. 跟製作資料集的shell 指令碼一樣,可以在tf_convert_data.sh指令碼所在目錄”/shell”,新建指令碼並將如下程式碼貼上進去,執行bash eval_ssd_network.sh
執行:
#!/bin/bash
# This is the eval script.
DATASET_DIR=/home/doctorimage/kindlehe/common/dataset/VOC2007/VOCtest_06-Nov-2007/VOCdevkit/VOC2007_tfrecord/
#/home/doctorimage/kindlehe/common/dataset/VOCdevkit/
#../../../../common/dataset/VOC2007/VOCtest_06-Nov-2007/VOCdevkit/
EVAL_DIR=../log_files/log_eval/ # Directory where the results are saved to
CHECKPOINT_PATH=/home/doctorimage/kindlehe/common/models/tfmodlels/SSD/VGG_VOC0712_SSD_300x300_ft_iter_120000/VGG_VOC0712_SSD_300x300_ft_iter_120000.ckpt
#../../../../common/models/tfmodlels/SSD/VGG_VOC0712_SSD_300x300_ft_iter_120000/VGG_VOC0712_SSD_300x300_ft_iter_120000.ckpt
#dataset_name這個引數在程式碼裡面寫死了
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
#python ../eval_ssd_network.py \
# --eval_dir=${EVAL_DIR} \ # Directory where the results are saved to
# --dataset_dir=${DATASET_DIR} \ # The directory where the dataset files are stored
# --dataset_name=voc2007_test \ # The name of the dataset to load
# --dataset_split_name=test \ # The name of the train/test split
# --model_name=ssd_300_vgg \ # The name of the architecture to evaluate
# --checkpoint_path=${CHECKPOINT_PATH} \ #The directory where the model was written to or an absolute path to a
#checkpoint file
# --batch_size=1 # The number of samples in each batch
執行指令碼之前,先替換一下作者eval_ssd_network.py這個程式碼的開頭,由於是在python3環境下執行,我重新安裝了python3版的tensorflow-gpu,採用的native pip安裝,不建議哈,建議大家以後去使用docker,據說是可以用docker使用同一臺機器的多個人分配GPU資源,防止撞車,誰玩過docker的歡迎來知道一下我,我叫kindle,唯一的一個kinlde!
至於註釋的那一段,可能由於我重新安裝的tensorflow,執行官方測試小demo居然會報這個錯誤 ++Internal: failed initializing StreamExecutor for CUDA device ordinal 1++,但是小demo中的sess = tf.Session()
這條語句連續第二次執行的時候,一切又回覆正常,wtf!!!
from tensorflow.python.framework import ops
from datasets import dataset_factory
from nets import nets_factory
from preprocessing import preprocessing_factory
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "1" #原因是在建立session時沒有使用我想讓它用的gpu,難道每次都只能在這裡制定一塊GPU才能執行?有別的辦法嗎?
import math
import sys
import six
import time
import numpy as np
import tensorflow as tf
import tf_extended as tfe
import tf_utils
slim = tf.contrib.slim
在../log_files/log_eval/
下生成三個檔案:events.out.tfevents.1498225326.doctorimagePC
, events.out.tfevents.1498225563.doctorimagePC
,training_config.txt
INFO:tensorflow:Evaluation [4952/4952] #測試機是VOC07 test
2017-06-23 22:47:38.481517: I tensorflow/core/kernels/logging_ops.cc:79] AP_VOC07/mAP[0.74313211395020917]
2017-06-23 22:47:44.241878: I tensorflow/core/kernels/logging_ops.cc:79] AP_VOC12/mAP[0.7665967841531145]
INFO:tensorflow:Finished evaluation at 2017-06-23-14:47:44
Time spent : 3703.294 seconds.
Time spent per BATCH: 0.748 seconds.
tensorboard顯示
在目錄~/kindlehe/project/SSD/SSD-Tensorflow-master/log_files
下執行tensorboard --logdir=log_eval
,在瀏覽器中輸入++http://localhost:6006++即可
4.3 訓練
終於可以開始訓練了,話不多說,先準備在VOC07+12 trainval訓練著,等週末來了再看,機器配置是:Intel(R) Core(TM) i7-7700K CPU @ 4.20GHz 顯示卡:1080 Ti 12G視訊記憶體
依然是.sh指令碼的形式:
#!/bin/bash
#The directory where the dataset files are stored.
DATASET_DIR=/home/doctorimage/kindlehe/common/dataset/VOC2007/VOCtrainval_06-Nov-2007/VOCdevkit/VOC2007_tfrecord/
#../../../../common/dataset/VOC2007/VOCtrainval_06-Nov-2007/VOCdevkit/VOC2007_tfrecord/
#Directory where checkpoints and event logs are written to.
TRAIN_DIR=.././log_files/log_finetune/
#The path to a checkpoint from which to fine-tune
CHECKPOINT_PATH=/home/doctorimage/kindlehe/common/models/tfmodlels/SSD/VGG_VOC0712_SSD_300x300_ft_iter_120000/VGG_VOC0712_SSD_300x300_ft_iter_120000.ckpt
#../../../../common/models/tfmodlels/SSD/VGG_VOC0712_SSD_300x300_ft_iter_120000/VGG_VOC0712_SSD_300x300_ft_iter_120000.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} \
--save_summaries_secs=60 \
--save_interval_secs=600 \
--weight_decay=0.0005 \
--optimizer=adam \
--learning_rate=0.001 \
--batch_size=32
5. 遇到的一些坑
- –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執行時,如果模型儲存路徑裡之前的模型未刪除,將會報錯,必須保證該資料夾為空。