画像内の「カップラーメン」を検出する [Object Detection API]
今回は「カップラーメン」のオリジナルデータセットを使用して、TensorFlowのObject Detection APIで画像内のカップラーメンを検出します。

この記事及びプロジェクトは「一般物体検出アルゴリズム」のSSD(Single shot multibox detector)を使用した研究を目的としています。
※データセットを含むソースコードはGitHubで公開しています。
前提条件
画像内の「犬猫の品種」を検出するトレーニングをローカルで行う |
の続きとなります。事前準備がありますので先にご覧ください。
1. 共有フォルダに専用フォルダを作成する
ホストOSとコンテナの「共有フォルダ」は次のようになっています。
/home/ユーザー名/tensor
[コンテナ側]
/foo
今回は/fooに「cup」フォルダを作成して使用します。
※コンテナ上の/fooは、実質的に/home/ユーザー名/tensorと同じです。
2. ラベリング
ラベリングでは各画像の「何処に何があるか」を指定する必要があります。
今回はLabelImgというツールを使用して手動でラベル付けを行います。
[ファイル構成]
images/ | 画像を収納する |
annotations/ | xmlファイルを収納する |
annotations/trainval.txt | 拡張子を除くファイル名の一覧を記述する |
xmlファイルはLabelImgで作成します。trainval.txtは適当なコマンドやプログラムでリストして下さい。(trainval.txtの例)
[LabelImgの使い方]
LabelImgを起動して「Open Dir」でimagesフォルダを選択します。1枚毎に「Create RectBox」アイコンを選択して範囲を選択します。その後に、ラベルを入力して「save」でXMLファイルを出力します。

※XMLのフォーマットはデフォルトの「PscalVOC」のままにして下さい。(左メニューのアイコンがPscalVOCならばOK)
全てのラベリング作業が完了したら、全てのXMLファイルの<path></path>のパスをLinuxならgrep、Windowsなら秀丸のGREP置換などで絶対パス(フルパス)に変更します。
これらのファイルを
/foo/cup/annotations
に移動します。
3. create_tf_record.pyを作成する
object_detection/dataset_toolsにあるTFRecordファイルを作成するコードでも良いのですが、少し複雑だったのでJwataさんのcreate_tf_record.py(MITライセンス)をテンプレートとします。
94/95行目の
train_output_path = os.path.join(FLAGS.output_dir, 'sushi_train.record') val_output_path = os.path.join(FLAGS.output_dir, 'sushi_val.record')
を
train_output_path = os.path.join(FLAGS.output_dir, 'cup_train.record') val_output_path = os.path.join(FLAGS.output_dir, 'cup_val.record')
に変更します。
※ファイルは/foo/cup/create_tf_record.pyに移動します。
4. cup_label_map.pbtxtを作成する
今回はカップラーメンのみの認識なので、1つだけです。
[cup_label_map.pbtxt]
item { id: 1 name: 'cup-ramen' }
※ファイルは/foo/cup/cup_label_map.pbtxtに移動します。
5. ライブラリパスを通しておく
cd /root/models/research/ export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim
6. TFRecordファイルを作成する
cd /foo/cup python create_tf_record.py \ --annotations_dir=`pwd`/annotations \ --images_dir=`pwd`/images \ --output_dir=`pwd` \ --label_map_path=cup_label_map.pbtxt
/foo/cupにcup_train.record及びcup_val.recordが作成されます。
7. 事前学習モデルをダウンロードする
検出モデル動物園で任意の学習済みモデルをダウンロードするのですが、今回は軽量で高速な「ssd_mobilenet_v1_coco」を使用します。
cd /foo/cup wget http://download.tensorflow.org/models/object_detection/ssd_mobilenet_v1_coco_2018_01_28.tar.gz
次にUbuntu側のユーザーで「/foo/cup/ssd_mobilenet_v1_coco_2018_01_28.tar.gz」を右クリックして「ここで展開する」を選択します。
そして、その「ssd_mobilenet_v1_coco_2018_01_28」フォルダをssdというフォルダ名に変更します。
ここで/foo/cupのファイル構成は次のようになります。
[フォルダ] annotations images ssd [圧縮ファイル] ssd_mobilenet_v1_coco_2018_01_28.tar.gz [TFRecord] cup_train.record cup_val.record [その他] create_tf_record.py cup_label_map.pbtxt
8. Configファイルの設定
ココ からダウンロードして、次のように変更します。
[ssd_mobilenet_v1_coco.config]
# SSD with Mobilenet v1 configuration for MSCOCO 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 { ssd { num_classes: 90 box_coder { faster_rcnn_box_coder { y_scale: 10.0 x_scale: 10.0 height_scale: 5.0 width_scale: 5.0 } } matcher { argmax_matcher { matched_threshold: 0.5 unmatched_threshold: 0.5 ignore_thresholds: false negatives_lower_than_unmatched: true force_match_for_each_row: true } } similarity_calculator { iou_similarity { } } anchor_generator { ssd_anchor_generator { num_layers: 6 min_scale: 0.2 max_scale: 0.95 aspect_ratios: 1.0 aspect_ratios: 2.0 aspect_ratios: 0.5 aspect_ratios: 3.0 aspect_ratios: 0.3333 } } image_resizer { fixed_shape_resizer { height: 300 width: 300 } } box_predictor { convolutional_box_predictor { min_depth: 0 max_depth: 0 num_layers_before_predictor: 0 use_dropout: false dropout_keep_probability: 0.8 kernel_size: 1 box_code_size: 4 apply_sigmoid_to_scores: false conv_hyperparams { activation: RELU_6, regularizer { l2_regularizer { weight: 0.00004 } } initializer { truncated_normal_initializer { stddev: 0.03 mean: 0.0 } } batch_norm { train: true, scale: true, center: true, decay: 0.9997, epsilon: 0.001, } } } } feature_extractor { type: 'ssd_mobilenet_v1' min_depth: 16 depth_multiplier: 1.0 conv_hyperparams { activation: RELU_6, regularizer { l2_regularizer { weight: 0.00004 } } initializer { truncated_normal_initializer { stddev: 0.03 mean: 0.0 } } batch_norm { train: true, scale: true, center: true, decay: 0.9997, epsilon: 0.001, } } } loss { classification_loss { weighted_sigmoid { } } localization_loss { weighted_smooth_l1 { } } hard_example_miner { num_hard_examples: 3000 iou_threshold: 0.99 loss_type: CLASSIFICATION max_negatives_per_positive: 3 min_negatives_per_image: 0 } classification_weight: 1.0 localization_weight: 1.0 } normalize_loss_by_num_matches: true post_processing { batch_non_max_suppression { score_threshold: 1e-8 iou_threshold: 0.6 max_detections_per_class: 100 max_total_detections: 100 } score_converter: SIGMOID } } } train_config: { batch_size: 24 optimizer { rms_prop_optimizer: { learning_rate: { exponential_decay_learning_rate { initial_learning_rate: 0.004 decay_steps: 800720 decay_factor: 0.95 } } momentum_optimizer_value: 0.9 decay: 0.9 epsilon: 1.0 } } fine_tune_checkpoint: "/foo/cup/ssd/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 { } } data_augmentation_options { ssd_random_crop { } } } train_input_reader: { tf_record_input_reader { input_path: "/foo/cup/cup_train.record" } label_map_path: "/foo/cup/cup_label_map.pbtxt" } eval_config: { num_examples: 8000 # 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: "/foo/cup/cup_val.record" } label_map_path: "/foo/cup/cup_label_map.pbtxt" shuffle: false num_readers: 1 }
※ファイルは/foo/cup/ssd_mobilenet_v1_coco.configに移動します。
また、fine_tune_checkpointをコメントにすると学習済みのモデルを使用しないで0から学習できるようです。
9. トレーニングと評価ジョブを開始する
cd /root/models/research/ PIPELINE_CONFIG_PATH=/foo/cup/ssd_mobilenet_v1_coco.config MODEL_DIR=/foo/cup/ NUM_TRAIN_STEPS=30000 NUM_EVAL_STEPS=2000 time python object_detection/model_main.py \ --pipeline_config_path=${PIPELINE_CONFIG_PATH} \ --model_dir=${MODEL_DIR} \ --num_train_steps=${NUM_TRAIN_STEPS} \ --num_eval_steps=${NUM_EVAL_STEPS} \ --alsologtostderr
[実行時間]
GeForce GTX 1080 Ti 11GB | real 195m13.459s |
[TensorBoard]
tensorboard --logdir /foo/cup--host 0.0.0.0

これは練習用なので1万ステップでも良いです。
10. Tensorflowグラフのエクスポート
モデルの訓練が終えたら、推論用にグラフをエキスポートします。
python object_detection/export_inference_graph.py \ --input_type image_tensor \ --pipeline_config_path /foo/cup/ssd_mobilenet_v1_coco.config \ --trained_checkpoint_prefix /foo/cup/model.ckpt-30000 \ --output_directory /foo/cup/exported_graphs
model.ckpt-30000の「30000」は各自が実際に実行したステップ数に変更してください。
11. テストイメージの移動
/foo/cupにテスト用画像のtestフォルダを移動します。
12. 推論(モデルの実行)
models/research/object_detection/object_detection_tutorial.ipynbをダウンロードして名称をcup.ipynbに変更します。次にmodels/research/object_detection/cup.ipynbに移動します。
Jupyter NoteBookで「cup.ipynb」を起動します。
[Model preparation]
次の変数を変更します。
PATH_TO_FROZEN_GRAPH = '/foo/cup/exported_graphs/frozen_inference_graph.pb' PATH_TO_LABELS = '/foo/cup/cup_label_map.pbtxt' NUM_CLASSES = 1
[Download Model]
ダウンロードする必要がないので、このセルは全てコメントにします。
[Detection]
12枚のテスト用画像の設定です。
PATH_TO_TEST_IMAGES_DIR = '/foo/cup/test' TEST_IMAGE_PATHS = [ os.path.join(PATH_TO_TEST_IMAGES_DIR, '{}.jpg'.format(i)) for i in range(1, 13) ]
推論するには「上から順番にRunする」 or 「メニューのKernel - Restart & Run All」を実行します。
最後に
今回は色々な角度の「カップヌードルの写真」を54枚使用して「カップラーメン」として機械学習を行いました。
これを応用、発展させれば業務上でも使用できる「物体検出器」を作ることが可能だと思います。
関連記事
前の記事: | 画像内の「犬猫の品種」を検出するトレーニングをローカルで行う [Object Detection API] |
次の記事: | 複数のTFRecord形式のファイルを生成する [create_pet_tf_record.pyの改造] |