TensorFlowの便利モジュール「Slim」ですが、使用するデータセットにはお決まりがありますので、まとめておきます。
なお、学習の仕方に関してはこちらを参照してください。
前提情報
TensorFlow-Slimは「tensorflow/contrib/slim」にあります。
そこで、すでに
import tensorflow as tf
import tensorflow.contrib.slim as slim
が行われているものとします。
呼ばれ方
通常は以下のように呼ばれて使用されます。
# 2次元畳み込み
net = slim.conv2d(images, 20, [5,5], scope='conv1')
# 途中省略
# one-hot表現に変換
one_hot_labels = slim.one_hot_encoding(
labels,
dataset.num_classes)
# クロスエントロピー(softmax)
slim.losses.softmax_cross_entropy(
net,
one_hot_labels)
「images」と「labels」がデータセットの組になります。
それぞれ内容や作り方を見ていきます。
内容
まず「images」ですが、以下のような構造のnumpy配列(float32)になっています。
※画像の場合
(バッチサイズ, 縦, 横, チャンネル)
一方「labels」の方は、以下のような構造のnumpy配列(int64)になっています。
(バッチサイズ)
作り方
バッチ分割
まずバッチサイズの配列にするには、以下の関数を使用します。
images, labels = tf.train.batch(
[image, label],
batch_size=batch_size,
allow_smaller_final_batch=True)
「image」は(縦、横、チャンネル)のnumpy配列、「label」は値になります。
指定したバッチサイズで区切られたデータを作成します。
さらに、「image」と「label」を見ていきます。
「image」と「label」の取得
data_provider = slim.dataset_data_provider.DatasetDataProvider(dataset)
image, label = data_provider.get(['image', 'label'])
「dataset」から、「image」と「label」を取り出しています。
これだけではよくわからないので、「dataset」が何なのか見ていきます。
「dataset」とは
データセットの情報を保持しています。
以下の関数で作られます。
slim.dataset.Dataset(
data_sources=file_pattern,
reader=reader,
decoder=decoder,
num_samples=_SPLITS_TO_SIZES[split_name],
num_classes=_NUM_CLASSES,
items_to_descriptions=_ITEMS_TO_DESCRIPTIONS,
labels_to_names=labels_to_names)
「data_sources」は読み込むデータセットファイル名になります。
今回は事前に作成したこととします。(詳細に関しては省略)
事前に作成しない場合は、ここで取得した内容と同じものを作成すればOKです。
なお、通常は学習用('train')/評価用('test')/ラベル用(値と文字列の組み合わせ)と3ファイル用意します。
画像ごとに
- image/encoded :画像データ
- image/format :画像フォーマット
- image/class/label :ラベル
- image/height :高さ
- image/width :幅
が設定されています。
「reader」と「decoder」は、通常それぞれ「tf.TFRecordReader」「slim.tfexample_decoder.TFExampleDecoder(keys_to_features, items_to_handlers)」になります。
「keys_to_features」には
keys_to_features = {
'image/encoded': tf.FixedLenFeature((), tf.string, default_value=''),
'image/format': tf.FixedLenFeature((), tf.string, default_value='raw'),
'image/class/label': tf.FixedLenFeature(
[1], tf.int64, default_value=tf.zeros([1], dtype=tf.int64)),
}
といった感じで読み込む内容が定義されており、「items_to_handlers」には、
items_to_handlers = {
'image': slim.tfexample_decoder.Image(shape=[28, 28, 1], channels=1),
'label': slim.tfexample_decoder.Tensor('image/class/label', shape=[]),
}
といった感じで、読み込むデータの種類が定義されています。
(ここで「image」と「label」に分けています)
「image/encoded」と「image/format」には、バイナリデータを「tf.train.BytesList()」および「tf.train.Feature()」で変換した値が入っています。
「image/class/label」には、バイナリデータを「tf.train.Int64List()」および「tf.train.Feature()」で変換した値が入っています。
「num_samples」には、画像数を設定します。
_SPLITS_TO_SIZES = {'train': 60000, 'test': 10000}
今回は「train」の方を使用します。
「num_classes」はクラス数になります。
例えばMNISTであれは10種類にクラス分けしますので、10となります。
「items_to_descriptions」は画像データとラベルの説明文を設定します。
例えばこんな感じになります。
_ITEMS_TO_DESCRIPTIONS = {
'image': 'A [28 x 28 x 1] grayscale image.',
'label': 'A single integer between 0 and 9',
}
最後に「labels_to_names」ですが、これはラベル用のファイルから読み込んだ、値と文字列の組み合わせになります。
ポイント
この時点ではまだファイルは読み込んでおらず、「slim.learning.train()」等で読み込みます。
一旦ファイルにしておかないやり方だと、そのあたりがうまくいかないので、素直にデータセットを事前に作成して、Slimの関数で読み込むようにしたほうがよいです。
なお、このデータセットの作成/読み込み方法は、すでにお決まりのようになっているので、サンプル等からコピーして、使用するデータに合わせて修正するのがよいかと思います。
ここの
- model.py [データセット読み込み]
- datasets/mnist.py [データセット読み込み]
- datasets/dataset_utils.py [共通]
- datasets/download_and_convert_mnist.py [データセット作成]
あたりが参考になります。