TOP > カテゴリ > Python・人工知能・機械学習 >

画像内の「カップラーメン」を検出する [Object Detection API]

Pythonの使い方(目次)

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

この記事及びプロジェクトは「一般物体検出アルゴリズム」のSSD(Single shot multibox detector)を使用した研究を目的としています。

※データセットを含むソースコードはGitHubで公開しています。

前提条件

画像内の「犬猫の品種」を検出するトレーニングをローカルで行う

の続きとなります。事前準備がありますので先にご覧ください。

1. 共有フォルダに専用フォルダを作成する

ホストOSとコンテナの「共有フォルダ」は次のようになっています。

[ホスト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/images
/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に移動します。

私はnum_classesはデフォルトの90のままで訓練しましたが、今回のケースでは「1」に設定してください。

また、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 11GBreal 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枚使用して「カップラーメン」として機械学習を行いました。

これを応用、発展させれば業務上でも使用できる「物体検出器」を作ることが可能だと思います。





関連記事



公開日:2018年08月08日 最終更新日:2018年08月09日
記事NO:02713