TensorFlow 2.0 : Beginner Tutorials : データのロードと前処理 :- 画像をロードする (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 10/06/2019
* 本ページは、TensorFlow org サイトの TF 2.0 – Beginner Tutorials – Load and  preprocess data の以下のページを
翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
- Windows PC のブラウザからご参加が可能です。スマートデバイスもご利用可能です。
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
| 株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション | 
| E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/ | 
| Facebook: https://www.facebook.com/ClassCatJP/ | 
データのロードと前処理 :- 画像をロードする
このチュートリアルは tf.data を使用してどのように画像データセットをロードするかの単純なサンプルを提供します。
このサンプルで使用されるデータセットは画像のディレクトリとして分配されます、ディレクトリ毎に画像の 1 クラスです。
セットアップ
from __future__ import absolute_import, division, print_function, unicode_literals
import tensorflow as tf
AUTOTUNE = tf.data.experimental.AUTOTUNE
import IPython.display as display from PIL import Image import numpy as np import matplotlib.pyplot as plt
tf.__version__
'2.1.0-dev20191003'
画像を取得する
どのような訓練を始める前でも、認識させたい新しいクラスについてネットワークに教えるために画像のセットが必要です。貴方は Google からの creative-commons ライセンスの花の画像のアーカイブを利用できます。
Note: 総ての画像は licensed CC-BY です、クリエイターは LICENSE.txt ファイルにリストされています。
import pathlib
data_dir = tf.keras.utils.get_file(origin='https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz',
                                         fname='flower_photos', untar=True)
data_dir = pathlib.Path(data_dir)
Downloading data from https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz 228818944/228813984 [==============================] - 5s 0us/step
ダウンロード後 (218 MB)、今は利用可能な花の写真のコピーを持つはずです。
ディレクトリは 5 つのサブディレクトリを含みます、クラス毎に一つです :
image_count = len(list(data_dir.glob('*/*.jpg')))
image_count
3670
CLASS_NAMES = np.array([item.name for item in data_dir.glob('*') if item.name != "LICENSE.txt"])
CLASS_NAMES
array(['daisy', 'roses', 'dandelion', 'sunflowers', 'tulips'],
      dtype='<U10')
各ディレクトリは花のそのタイプの画像を含みます。ここに幾つかのバラ (= roses) があります :
roses = list(data_dir.glob('roses/*'))
for image_path in roses[:3]:
    display.display(Image.open(str(image_path)))



keras.preprocessing を使用してロードする
画像をロードする単純な方法は keras.preprocessing を使用することです。
# The 1./255 is to convert from uint8 to float32 in range [0,1]. image_generator = tf.keras.preprocessing.image.ImageDataGenerator(rescale=1./255)
ローダのために幾つかパラメータを定義します :
BATCH_SIZE = 32 IMG_HEIGHT = 224 IMG_WIDTH = 224 STEPS_PER_EPOCH = np.ceil(image_count/BATCH_SIZE)
train_data_gen = image_generator.flow_from_directory(directory=str(data_dir),
                                                     batch_size=BATCH_SIZE,
                                                     shuffle=True,
                                                     target_size=(IMG_HEIGHT, IMG_WIDTH),
                                                     classes = list(CLASS_NAMES))
Found 3670 images belonging to 5 classes.
バッチを調べます :
def show_batch(image_batch, label_batch):
  plt.figure(figsize=(10,10))
  for n in range(25):
      ax = plt.subplot(5,5,n+1)
      plt.imshow(image_batch[n])
      plt.title(CLASS_NAMES[label_batch[n]==1][0].title())
      plt.axis('off')
image_batch, label_batch = next(train_data_gen) show_batch(image_batch, label_batch)

tf.data を使用してロードする
上の keras.preprocessing は便利ですが、2 つの欠点を持ちます :
- それは遅いです。パフォーマンス・セクション を見てください。
- それは細かい制御を欠きます。
- それは TensorFlow の残りの部分と上手く統合されていません。
ファイルを tf.data.Dataset としてロードするには最初にファイルパスの dataset を作成します :
list_ds = tf.data.Dataset.list_files(str(data_dir/'*/*'))
for f in list_ds.take(5): print(f.numpy())
b'/home/kbuilder/.keras/datasets/flower_photos/daisy/7199968650_72afc16d31_m.jpg' b'/home/kbuilder/.keras/datasets/flower_photos/roses/14381787252_e8e12e277a_n.jpg' b'/home/kbuilder/.keras/datasets/flower_photos/roses/898102603_2d5152f09a.jpg' b'/home/kbuilder/.keras/datasets/flower_photos/roses/568715474_bdb64ccc32.jpg' b'/home/kbuilder/.keras/datasets/flower_photos/tulips/13539384593_23449f7332_n.jpg'
ファイルパスを (image_data, label) ペアに変換する短い pure-tensorflow 関数を書きます :
def get_label(file_path): # convert the path to a list of path components parts = tf.strings.split(file_path, '/') # The second to last is the class-directory return parts[-2] == CLASS_NAMES
def decode_img(img): # convert the compressed string to a 3D uint8 tensor img = tf.image.decode_jpeg(img, channels=3) # Use `convert_image_dtype` to convert to floats in the [0,1] range. img = tf.image.convert_image_dtype(img, tf.float32) # resize the image to the desired size. return tf.image.resize(img, [IMG_WIDTH, IMG_HEIGHT])
def process_path(file_path): label = get_label(file_path) # load the raw data from the file as a string img = tf.io.read_file(file_path) img = decode_img(img) return img, label
画像、ラベルのペアのデータセットを作成するために Dataset.map を使用します :
# Set `num_parallel_calls` so multiple images are loaded/processed in parallel. labeled_ds = list_ds.map(process_path, num_parallel_calls=AUTOTUNE)
for image, label in labeled_ds.take(1):
  print("Image shape: ", image.numpy().shape)
  print("Label: ", label.numpy())
Image shape: (224, 224, 3) Label: [False False False False True]
訓練のための基本メソッド
このデータセットでモデルを訓練するためにデータに次を望むでしょう :
- 上手くシャッフルされること。
- バッチ化されること。
- できる限り速くバッチが利用可能になること。
これらの特徴は tf.data api を使用して容易に追加できます。
def prepare_for_training(ds, cache=True, shuffle_buffer_size=1000):
  # This is a small dataset, only load it once, and keep it in memory.
  # use `.cache(filename)` to cache preprocessing work for datasets that don't
  # fit in memory.
  if cache:
    if isinstance(cache, str):
      ds = ds.cache(cache)
    else:
      ds = ds.cache()
  ds = ds.shuffle(buffer_size=shuffle_buffer_size)
  # Repeat forever
  ds = ds.repeat()
  ds = ds.batch(BATCH_SIZE)
  # `prefetch` lets the dataset fetch batches in the background while the model
  # is training.
  ds = ds.prefetch(buffer_size=AUTOTUNE)
  return ds
train_ds = prepare_for_training(labeled_ds) image_batch, label_batch = next(iter(train_ds))
show_batch(image_batch.numpy(), label_batch.numpy())

パフォーマンス
Note: このセクションはパフォーマンスに役立つかもしれない 2, 3 の容易なトリックを単に示します。深いガイドについては、入力パイプライン・パフォーマンス を見てください。
調べるために、データセットのパフォーマンスを確認するための関数が最初にここにあります :
import time
default_timeit_steps = 1000
def timeit(ds, steps=default_timeit_steps):
  start = time.time()
  it = iter(ds)
  for i in range(steps):
    batch = next(it)
    if i%10 == 0:
      print('.',end='')
  print()
  end = time.time()
  duration = end-start
  print("{} batches: {} s".format(steps, duration))
  print("{:0.5f} Images/s".format(BATCH_SIZE*steps/duration))
2 つのデータ generator のスピードを比較しましょう :
# `keras.preprocessing` timeit(train_data_gen)
.................................................................................................... 1000 batches: 86.93303561210632 s 368.09942 Images/s
# `tf.data` timeit(train_ds)
.................................................................................................... 1000 batches: 7.023545026779175 s 4556.10377 Images/s
パフォーマンス獲得の大きか部分は .cache の使用に由来します。
uncached_ds = prepare_for_training(labeled_ds, cache=False) timeit(uncached_ds)
.................................................................................................... 1000 batches: 24.807150840759277 s 1289.95064 Images/s
データセットがメモリに収まらない場合には優位点の幾つかを維持するためにキャッシュファイルを使用します :
filecache_ds = prepare_for_training(labeled_ds, cache="./flowers.tfcache") timeit(filecache_ds)
.................................................................................................... 1000 batches: 16.97942090034485 s 1884.63436 Images/s
以上