tensorflow入門教程(二十五)Object Detection API目標檢測(下)
1、概述
上一講,我們使用了別人根據COCO資料集訓練好的模型來做目標檢測,這一講,我們就來訓練自己的模型。
2、下載資料集
為了方便學習,我們先使用別人整理好的資料集來訓練---VOC 2012資料集。VOC 2012一共有17125張圖片,每張圖片都有標註,標註的內容包括人、動物、交通工具、傢俱等20個類別。首先下載資料集,資料集很大,有1.9G,慢慢下吧~連結如下,
3、修改環境變數
為了不用每次都將檔案拷貝到my_object_detection資料夾下,我們可以將my_object_detection目錄設定進Python的環境變數PYTHONPATH中,執行以下命令
export PYTHONPATH=$PYTHONPATH:/home/wilf/tensorflow-master/demo/my_object_detection:/home/wilf/tensorflow-master/demo/my_object_detection/slim
為了不用每次開機都執行這個命令,可以將其寫入到~/.bashrc檔案中。
4、VOC2012資料集結構簡介
轉換之前,先來看一下VOC2012資料集的結構,先將我們下載的檔案VOCtrainval_11-May-2012.tar解壓到my_images資料夾下,得到的目錄結構為
my_images/VOCdevkit/VOC2012/
VOC2012資料夾下包含5個子資料夾,如下圖所示,
JPEGImages資料夾中儲存了所有的圖片,每一張圖片對應的物體框的標註存在Annotations資料夾中,如下圖所示,
看看它是怎麼標註的(註釋是我加上去的),
對應的圖片如下,
分割圖片如下(<segmented>1</segmented>),
5、將VOC2012資料集轉成tfrecord格式
接下來將VOC2012資料集轉為tfrecord格式,在object_detection資料夾下執行以下命令,
訓練資料:
python dataset_tools/create_pascal_tf_record.py --data_dir=my_images/VOCdevkit/ --year=VOC2012 --output_path=my_images/VOCdevkit/pascal_train.record --set=train
測試資料:
python dataset_tools/create_pascal_tf_record.py --data_dir=my_images/VOCdevkit/ --year=VOC2012 --output_path=my_images/VOCdevkit/pascal_val.record --set=val
執行完以後,在my_images/VOCdevkit/資料夾下生成兩個檔案,pascal_train.record 和pascal_val.record。
6、下載模型
接著,下載模型,還是跟上一講一樣的連結,
下載faster_rcnn_inception_resnet_v2_atrous_coco模型,
data/pascal_label_map.pbtxt檔案則對於與VOC2012的label,總共有20個分類。
下載完後,將其解壓到my_images資料夾下,得到資料夾如下,
7、配置檔案
接下來呢,新建配置檔案,samples/configs/資料夾下有一些示例檔案,我們就模仿它們配置,參考faster_rcnn_inception_resnet_v2_atrous_coco.config檔案,執行命令,
cp samples/configs/faster_rcnn_inception_resnet_v2_atrous_coco.config samples/configs/faster_rcnn_inception_resnet_v2_atrous_voc2012.config
- 將num_classes: 90改為num_classes: 20
- 將num_examples: 8000改為num_examples: 5823,這個5823怎麼來?上面執行的將VOC2012資料集轉為tfrecord格式中,將create_pascal_tf_record.py中的examples_list的長度打印出來就得到這個5823,這個examples_list就是在驗證階段需要執行的圖片數量,命令為
python dataset_tools/create_pascal_tf_record.py --data_dir=my_images/VOCdevkit/ --year=VOC2012 --output_path=my_images/VOCdevkit/pascal_val.record --set=val
- 5處PATH_TO_BE_CONFIGURED的地方修改成對應的我們新建的目錄
然後,在my_images資料夾下新建一個資料夾train_dir,用來儲存訓練模型。
上面配置檔案完整內容如下,
# Faster R-CNN with Inception Resnet v2, Atrous version;
# Configured for VOC2012 Dataset.
# Users should configure the fine_tune_checkpoint field in the train config as
# well as the label_map_path and input_path fields in the train_input_reader and
# eval_input_reader. Search for "PATH_TO_BE_CONFIGURED" to find the fields that
# should be configured.
model {
faster_rcnn {
num_classes: 20
image_resizer {
keep_aspect_ratio_resizer {
min_dimension: 600
max_dimension: 1024
}
}
feature_extractor {
type: 'faster_rcnn_inception_resnet_v2'
first_stage_features_stride: 8
}
first_stage_anchor_generator {
grid_anchor_generator {
scales: [0.25, 0.5, 1.0, 2.0]
aspect_ratios: [0.5, 1.0, 2.0]
height_stride: 8
width_stride: 8
}
}
first_stage_atrous_rate: 2
first_stage_box_predictor_conv_hyperparams {
op: CONV
regularizer {
l2_regularizer {
weight: 0.0
}
}
initializer {
truncated_normal_initializer {
stddev: 0.01
}
}
}
first_stage_nms_score_threshold: 0.0
first_stage_nms_iou_threshold: 0.7
first_stage_max_proposals: 300
first_stage_localization_loss_weight: 2.0
first_stage_objectness_loss_weight: 1.0
initial_crop_size: 17
maxpool_kernel_size: 1
maxpool_stride: 1
second_stage_box_predictor {
mask_rcnn_box_predictor {
use_dropout: false
dropout_keep_probability: 1.0
fc_hyperparams {
op: FC
regularizer {
l2_regularizer {
weight: 0.0
}
}
initializer {
variance_scaling_initializer {
factor: 1.0
uniform: true
mode: FAN_AVG
}
}
}
}
}
second_stage_post_processing {
batch_non_max_suppression {
score_threshold: 0.0
iou_threshold: 0.6
max_detections_per_class: 100
max_total_detections: 100
}
score_converter: SOFTMAX
}
second_stage_localization_loss_weight: 2.0
second_stage_classification_loss_weight: 1.0
}
}
train_config: {
batch_size: 1
optimizer {
momentum_optimizer: {
learning_rate: {
manual_step_learning_rate {
initial_learning_rate: 0.0003
schedule {
step: 900000
learning_rate: .00003
}
schedule {
step: 1200000
learning_rate: .000003
}
}
}
momentum_optimizer_value: 0.9
}
use_moving_average: false
}
gradient_clipping_by_norm: 10.0
fine_tune_checkpoint: "my_images/faster_rcnn_inception_resnet_v2_atrous_coco_2018_01_28/model.ckpt"
from_detection_checkpoint: true
# Note: The below line limits the training process to 200K steps, which we
# empirically found to be sufficient enough to train the pets dataset. This
# effectively bypasses the learning rate schedule (the learning rate will
# never decay). Remove the below line to train indefinitely.
num_steps: 200000
data_augmentation_options {
random_horizontal_flip {
}
}
}
train_input_reader: {
tf_record_input_reader {
input_path: "my_images/VOCdevkit/pascal_train.record"
}
label_map_path: "data/pascal_label_map.pbtxt"
}
eval_config: {
num_examples: 5823
# Note: The below line limits the evaluation process to 10 evaluations.
# Remove the below line to evaluate indefinitely.
max_evals: 10
}
eval_input_reader: {
tf_record_input_reader {
input_path: "my_images/VOCdevkit/pascal_val.record"
}
label_map_path: "data/pascal_label_map.pbtxt"
shuffle: false
num_readers: 1
}
8、開始訓練
執行如下命令,
python train.py --train_dir=my_images/train_dir/ --pipeline_config_path=samples/configs/faster_rcnn_inception_resnet_v2_atrous_voc2012.config
報錯了,
TypeError: __new__() got an unexpected keyword argument 'serialized_options'
似曾相識啊,在《tensorflow入門筆記(二十三)Object Detection API目標檢測(上)》那講也遇到了這個錯誤,將這個引數去掉試試。
唉,又報錯了,又是OOM記憶體溢位~屌絲的春天什麼時候才到呢??
那就用CPU咯,在train.py中加入以下程式碼,
#原諒我窮屌絲,電腦顯示卡配置太低導致記憶體溢位,只能用cpu計算了
os.environ["CUDA_VISIBLE_DEVICES"]="-1"
再執行看看,
天吶~又出錯了,而且沒有什麼提示,這不是在為難我嗎??!!
我猜可能是記憶體溢位,我們在程式執行的時候不定時的看看記憶體的佔用情況,
一開始,可用記憶體有7.5G這樣,
崩潰前,大概就剩下一百多M了~~!!看來沒法玩了~這兩天去淘寶塊記憶體條先了。
兩天過去,買了個16G的記憶體條,加上原來的8G,這下應該夠用了吧?還買了個460G固態硬碟,還在路上。安裝好記憶體條以後,走起!
哎喲我去,腿腳麻利了,一口氣能上五樓!先出去逛個街,回來再看看效果~
我勒個去,三個多小時過去,才476步!CPU這效率,看來的上的大點記憶體的顯示卡了。
9、匯出模型
訓練完以後,如何對單張圖片進行目標檢測呢?
Object Detection API提供了一個export_inference_graph.py指令碼用於匯出訓練好的模型,我們先將訓練好的checkpoint匯出成“,pb”檔案,再用上一講的程式碼,對圖片進行目標檢測。匯出模型命令如下,
python export_inference_graph.py --input_type image_tensor --pipeline_config_path samples/configs/faster_rcnn_inception_resnet_v2_atrous_voc2012.config --trained_checkpoint_prefix my_images/train_dir/model.ckpt-494 --output_directory my_images/export_dir/
執行成功後,export_dir資料夾下生成以下檔案,
10、使用自己訓練的模型對圖片進行目標檢測
這一步,只要修改上一講的程式碼就可以了。比較簡單,直接給程式碼好了。在object_detection目錄下新建檔案demo2.py,執行python demo2.py,程式碼如下,
#encoding:utf-8
import tensorflow as tf
import numpy as np
import os
from matplotlib import pyplot as plt
from PIL import Image
from object_detection.utils import label_map_util
from object_detection.utils import visualization_utils as vis_utils
#下載下來的模型的目錄
MODEL_DIR = 'my_images/export_dir/'
#下載下來的模型的檔案
MODEL_CHECK_FILE = os.path.join(MODEL_DIR, 'frozen_inference_graph.pb')
#資料集對於的label
MODEL_LABEL_MAP = os.path.join('data', 'pascal_label_map.pbtxt')
#資料集分類數量,可以開啟pascal_label_map.pbtxt檔案看看
MODEL_NUM_CLASSES = 20
#這裡是獲取例項圖片檔名,將其放到陣列中
PATH_TO_TEST_IMAGES_DIR = 'test_images'
TEST_IMAGES_PATHS = [os.path.join(PATH_TO_TEST_IMAGES_DIR, '06.jpg')]
#輸出影象大小,單位是in
IMAGE_SIZE = (12, 8)
tf.reset_default_graph()
#將模型讀取到預設的圖中
with tf.gfile.GFile(MODEL_CHECK_FILE, 'rb') as fd:
_graph = tf.GraphDef()
_graph.ParseFromString(fd.read())
tf.import_graph_def(_graph, name='')
#載入pascal資料標籤
label_map = label_map_util.load_labelmap(MODEL_LABEL_MAP)
categories = label_map_util.convert_label_map_to_categories(label_map, max_num_classes=MODEL_NUM_CLASSES)
category_index = label_map_util.create_category_index(categories)
#將圖片轉化成numpy陣列形式
def load_image_into_numpy_array(image):
(im_width, im_height) = image.size
return np.array(image.getdata()).reshape((im_height, im_width, 3)).astype(np.uint8)
#在圖中開始計算
detection_graph = tf.get_default_graph()
with tf.Session(graph=detection_graph) as sess:
for image_path in TEST_IMAGES_PATHS:
print(image_path)
#讀取圖片
image = Image.open(image_path)
#將圖片資料轉成陣列
image_np = load_image_into_numpy_array(image)
#增加一個維度
image_np_expanded = np.expand_dims(image_np, axis=0)
#下面都是獲取模型中的變數,直接使用就好了
image_tensor = detection_graph.get_tensor_by_name('image_tensor:0')
#存放所有檢測框
boxes = detection_graph.get_tensor_by_name('detection_boxes:0')
#每個檢測結果的可信度
scores = detection_graph.get_tensor_by_name('detection_scores:0')
#每個框對應的類別
classes = detection_graph.get_tensor_by_name('detection_classes:0')
#檢測框的個數
num_detections = detection_graph.get_tensor_by_name('num_detections:0')
#開始計算
(boxes, scores, classes, num_detections) = sess.run([boxes, scores, classes, num_detections],
feed_dict={image_tensor : image_np_expanded})
#列印識別結果
print(num_detections)
print(boxes)
print(classes)
print(scores)
#得到視覺化結果
vis_utils.visualize_boxes_and_labels_on_image_array(
image_np,
np.squeeze(boxes),
np.squeeze(classes).astype(np.int32),
np.squeeze(scores),
category_index,
use_normalized_coordinates=True,
line_thickness=8
)
#顯示
plt.figure(figsize=IMAGE_SIZE)
plt.imshow(image_np)
plt.show()
11、執行結果
就這麼簡單。
等下個月底新一代的顯示卡出來了,再看看能不能淘個便宜點的顯示卡~~!
-------韋訪 180725