SSD-tensorflow使用文件(-)——測試訓練基本流程

NO IMAGE

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-basedSSD-512 VGG-based 兩個版本,但這個project的框架的模組化應該可以保證SSD的其他變種(如ResNet or Inception 版本)實現起來也不難,等有時間我嘗試好之後會分享給大家的。

  • 本project的組織結構受啟發於TF-Slim models repository,TF-slim包含了當下流行的ResNet, Inception and VGG結構。主要包括3個部分:

    1. datasets:(Pasca VOC 2007_trainval2007_test2012COCO)這些資料集的介面和 將其轉為tensorflow專用TF-Records格式的指令碼檔案。
    2. networks: SSD網路結構的定義,常用的encoding和decoding方法(refer to the paper on this precise topic)
    3. 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/進入noteboo目錄,執行 jupyter-notebook進入http://localhost:8892/tree伺服器,開啟 ssd_notebook.ipynb.ipynb檔案
3. 配置一些路徑:第4個cell中from notebooks import visualization改成import notebooks,不改的話目錄結構不對,會報錯
4. 使用自己的圖片,改變path = '../demo/'成自己的圖片所在路徑
5. 從頭到尾執行所有cell即可。

我在網上隨便找了張圖片測試了一下,效果確實還不錯,只是這個程式碼沒有把標籤對應的種類顯示在上面,懶得改了,以後用的時候再說,上圖啦:
pedestrian
image

分析:估計這裡2代表自行車把,15代表人把,但是第二張圖的手勢也是別未15(人類),估計分類裡面沒有手勢這一項把。後續將進行更多的測試,這裡先介紹到這裡。


3.論文效果

小例子跑起來之後,當然不能就這麼滿足了,要給自己定個小目標,自然就是要通過自己的訓練達到接近論文的效果。
– SSD作者本人用caffe實現的程式碼所達到的效果如下:

SystemVOC2007 test mAPFPS (Titan X)Number of BoxesInput resolution
Faster R-CNN (VGG16)73.27~6000~1000 x 600
YOLO (customized)63.44598448 x 448
SSD300* (VGG16)77.2468732300 x 300
SSD512* (VGG16)79.81924564512 x 512

image Note: SSD300* and SSD512* are the latest models. Current code should reproduce these results.

對比發現,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. 遇到的一些坑

  1. –dataset_name=pascalvoc_2007 、–dataset_split_name=train、–model_name=ssd_300_vgg這三個引數不要自己隨便取,在程式碼裡,這三個引數是if…else…語句,有固定的判斷值,所以要根據實際情況取選擇
  2. TypeError: expected bytes, NoneType found
    SystemError: returned a result with an error set
    這是由於CHECKPOINT_PATH定義的時候不小心多了個#號鍵,將輸入給註釋掉了,如果不想使用預訓練的模型,需要將--checkpoint_path=${CHECKPOINT_PATH} \註釋掉即可
  3. SSD有在VOC07 12的訓練集上一起訓練的,用一個笨一點的辦法:
    pascalvoc_to_tfrecords.py檔案中,改變SAMPLES_PER_FILES,減少輸出tfrecord檔案的個數,再修改tf_convert_data.py的dataset引數,記得將前後兩次的輸出名改變一下,前後兩次轉換的tfrecords放在同一個資料夾下,然後手工重新命名。(這裡由於只是驗證論文的訓練方法是否有效,所以沒必要寫這些自動化程式碼實現合併,以後要用自己的資料集訓練的時候就可以寫一些自動化指令碼)
  4. 有時候執行指令碼會報錯,可能是之前依次執行導致視訊記憶體佔滿。
  5. 從pyCharm執行時,如果模型儲存路徑裡之前的模型未刪除,將會報錯,必須保證該資料夾為空。