TF-Slim画像識別ライブラリ用TFRecordファイルの作成 2


Pocket

前回TF-Slim画像識別ライブラリを使って、転移学習を試してみました。その際使用したデータセットは、用意されていた花画像データセットを使用しましたが、自前で用意した画像も使える様にしたかったので、今回はTF-Slim画像識別ライブラリで使用できる形式のデータセットを作成するスクリプトを作ってみました。

環境

・TensorFlow r0.12
TensorFlow-Slim image classification library
・自前で用意した画像は、imagesフォルダに下記の様に保存されているとします

images
  +- tulip00.jpg
  +- Lexus03.jpg
  +- …
  +- list.csv #ラベル一覧

ラベルデータを含んだCSVファイルは、[ファイル名,ラベル]というフォーマットで保存しておきます。

flower00.jpg, flower
Lexus03.jpg, car
…

 

データセットの作り方

元々TF-Slim画像識別ライブラリには、MNISTやCIFAR10といったデータセットを変換するプログラムが用意されているので、それらを参考にすれば作れそうです。

有名データセット変換プログラム

一通りソースコードを眺めてみると、どうやら下記データ項目を持ったTFRecordを作成すれば良いことがわかります。
datasets/dataset_utils.py

def image_to_tfexample(image_data, image_format, height, width, class_id):
  return tf.train.Example(features=tf.train.Features(feature={
      'image/encoded': bytes_feature(image_data),
      'image/format': bytes_feature(image_format),
      'image/class/label': int64_feature(class_id),
      'image/height': int64_feature(height),
      'image/width': int64_feature(width),
}))

ということで、画像ファイルパスから画像データを読み込み、TFRecordファイルに変換するプログラムの下記の様に作成してみました。
filepath_listsは、shape=[出力ファイル数, (1ファイル当たりの)画像数]の2次元配列になっています。label_listsも同じです。

def write_tfrecord(split_name, filepath_lists, label_lists):
  jpeg_path = tf.placeholder(dtype=tf.string)
  jpeg_data = tf.read_file(jpeg_path)
  decode_jpeg = tf.image.decode_jpeg(jpeg_data, channels=3)

  with tf.Session() as sess:
    for i, filepath_list in enumerate(filepath_lists):
      output_filename = '%s_%s_%05d-of-%05d.tfrecord'%(FLAGS.dataset_name, split_name, i, len(filepath_lists))
      with tf.python_io.TFRecordWriter(output_filename) as writer:
        for j,filepath in enumerate(filepath_list):
          sys.stdout.write('\r>> Converting image %d/%d'%(j+1, len(filepath_list)))
          sys.stdout.flush()
          image_data, image = sess.run([jpeg_data, decode_jpeg], feed_dict={jpeg_path:filepath})
          example = image_to_tfexample(image_data, 'jpg', image.shape[0], image.shape[1], label_lists[i][j])
          writer.write(example.SerializeToString())
      print(' Finished: %s'%(output_filename))

※なんか分かりづらいコードになってしまいました…

TFRecordファイルの作成は、tf.python_io.TFRecordWriterクラスを使うとできます。

ソースコード全体は下記に置いてあります。
https://github.com/workpiles/convert_TFRecord

作ったデータセットの読み込み

train_image_classifier.pyeval_image_classifier.pyで作成したデータセットを読み込むためには、下記の簡単な変更を加えればできます。

datasets/dataset_factory.pyの変更

【中略】
from datasets import ccb

datasets_map = {
    'cifar10': cifar10,
    'flowers': flowers,
    'imagenet': imagenet,
    'mnist': mnist,
    'ccb' : ccb, #←データセット名の追加
}

ccb.pyの作成

あとは、追加したデータセット用のget_splitを実装すれば完了です。
これは、flowers.pymnist.pyなど、他のデータセットを元に作成すれば問題ないと思います。

 

きゅうり画像で転移学習

早速、きゅうり画像でVGG16で転移学習を試してみました。fc8,fc7を学習対象としています。
(fc6を含めるとHDDの空きがなくなってしまった…)
学習に使用したのは解像度80×80、3チャンネルの画像を6500枚です。
後のパラメータは適当に。

python train_image_classifier.py \
  --train_dir=data \
  --dataset_name=ccb \
  --dataset_split_name=train \
  --dataset_dir=/tmp/ccb\
  --model_name=vgg_16 \
  --checkpoint_path=/tmp/ckpt/vgg_16.ckpt \
  --checkpoint_exclude_scopes=vgg_16/fc8,vgg_16/fc7 \
  --trainable_scopes=vgg_16/fc8,vgg_16/fc7 \
  --max_number_of_steps=1000 \
  --batch_size=32 \
  --learning_rate=0.01 \
  --learning_rate_decay_type=fixed \
  --save_interval_secs=300 \
  --save_summaries_secs=300 \
  --log_every_n_steps=100 \
  --optimizer=rmsprop \
  --weight_decay=0.00004

tb_vgg16_ccb

損失はsoftmax_cross_entropyで、200ステップ当たりで収束している感じです。

結果

eval_vgg16_ccb

テスト画像2500枚に対して、10クラスに識別した場合の結果は、下記の通りでした。
正答率:19.3%
予測上位5クラスに正解が含まれる確率:62.7%

うーん。いまいち。

 

あとがき

なんか転移学習のやり方が間違ってる気がしてしょうがない…。

 
 


koike へ返信する コメントをキャンセル

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

2 thoughts on “TF-Slim画像識別ライブラリ用TFRecordファイルの作成

  • Reply
    Andy

    Thanks for the great post! I just started working on TF-slim, but I’m in trouble with custom image data. I put my data like below, but it keeps making errors like “Invalid JPEG data” when I run download_and_convert_data.py. (Of course, I modified this file for my custom images)

    starbucks
    – star1
    – 1.jpg
    – 2.jpg

    – star2
    – 1.jpg
    – 2.jpg

    – star3
    – 1.jpg
    – 2.jpg

    Can you see if I am doing this wrong?
    Do I have to put list.csv file?
    Can you please let me know your custom image data directory structure?