web-dev-qa-db-ja.com

Google Colabは、テンソルフロー2.0バッチデータセットの使用中に画像ファイルをロードしません

背景について少し説明します。GANをトレーニングするために、約60,000枚の画像をcolabにロードしています。私はすでにそれらをドライブにアップロードしており、ディレクトリ構造にはroot内のさまざまなクラス(約7〜8)のフォルダが含まれています。次のようにして、それらをcolabにロードしています。

root = "drive/My Drive/data/images"
root = pathlib.Path(root)

list_ds = tf.data.Dataset.list_files(str(root/'*/*'))

for f in list_ds.take(3):
  print(f.numpy())

これは出力を与えます:

b'drive/My Drive/data/images/folder_1/2994.jpg'
b'drive/My Drive/data/images/folder_1/6628.jpg'
b'drive/My Drive/data/images/folder_2/37872.jpg'

私はそれらを次のようにさらに処理しています:

def process_path(file_path):
  label = tf.strings.split(file_path, '/')[-2]
  image = tf.io.read_file(file_path)
  image = tf.image.decode_jpeg(image)
  image = tf.image.convert_image_dtype(image, tf.float32)
  return image#, label

ds = list_ds.map(process_path)

BUFFER_SIZE = 60000
BATCH_SIZE = 128

train_dataset = ds.shuffle(BUFFER_SIZE).batch(BATCH_SIZE)

各画像のサイズは128x128。 colabでバッチを表示しようとすると、問題が発生します。たとえば、次のコードを使用すると、実行が永久に継続して停止することはありません。

for batch in train_dataset.take(4):
  print([arr.numpy() for arr in batch])

以前、batch_sizeが問題になる可能性があると思ったので、変更を試みましたが、それでも同じ問題が発生しました。大量のファイルを読み込んでいるため、colabが原因で問題が発生する可能性がありますか?

それとも、MNIST(28x28)を使用したときに機能していた画像のサイズが原因ですか?もしそうなら、可能な解決策は何ですか?

前もって感謝します。

編集:シャッフルステートメントを削除した後、最後の行が数秒以内に実行されます。そのため、シャッフルのBUFFER_SIZEが原因で問題になる可能性があると考えましたが、BUFFER_SIZEを小さくしても、実行に非常に長い時間がかかります。回避策はありますか?

6
bkshi

これが、個人のGoogleドライブから1.12GBの圧縮されたFLICKR画像データセットを読み込む方法です。まず、colab環境でデータセットを解凍します。パフォーマンスを高速化できる機能には、prefetchautotuneがあります。さらに、ローカルのcolabキャッシュを使用して、処理された画像を保存します。初回の実行には最大20秒かかります(データセットを解凍した場合)。キャッシュを使用すると、後続の呼び出しで非常に高速にロードできます。

あなたがGoogleドライブAPIを承認したと仮定して、私はフォルダを解凍することから始めます

_!unzip /content/drive/My\ Drive/Flickr8k
!unzip Flickr8k_Dataset
!ls
_

次に、prefetch()autotune、および_cache file_を追加してコードを使用しました。

_import pathlib
import tensorflow as tf

def prepare_for_training(ds, cache, BUFFER_SIZE, BATCH_SIZE):
  if cache:
    if isinstance(cache, str):
      ds = ds.cache(cache)
    else:
      ds = ds.cache()
  ds = ds.shuffle(buffer_size=BUFFER_SIZE)
  ds = ds.batch(BATCH_SIZE)
  ds = ds.prefetch(buffer_size=AUTOTUNE)
  return ds

AUTOTUNE = tf.data.experimental.AUTOTUNE

root = "Flicker8k_Dataset"
root = pathlib.Path(root)

list_ds = tf.data.Dataset.list_files(str(root/'**'))

for f in list_ds.take(3):
  print(f.numpy())

def process_path(file_path):
  label = tf.strings.split(file_path, '/')[-2]
  img = tf.io.read_file(file_path)
  img = tf.image.decode_jpeg(img)
  img = tf.image.convert_image_dtype(img, tf.float32)
  # resize the image to the desired size.
  img =  tf.image.resize(img, [128, 128])
  return img#, label

ds = list_ds.map(process_path, num_parallel_calls=AUTOTUNE)
train_dataset = prepare_for_training(ds, cache="./custom_ds.tfcache", BUFFER_SIZE=600000, BATCH_SIZE=128)
for batch in train_dataset.take(4):
  print([arr.numpy() for arr in batch])
_

Keras flow_from_directory()でこれを行う方法を次に示します。このアプローチの利点は、テンソルフローshuffle()を回避できることです。これは、バッファーサイズによっては、データセット全体の処理が必要になる場合があります。 Kerasは、データバッチをフェッチするために呼び出すことができるイテレータを提供し、ランダムシャッフルが組み込まれています。

_import pathlib
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator

root = "Flicker8k_Dataset"
BATCH_SIZE=128

train_datagen = ImageDataGenerator(
    rescale=1./255 )

train_generator = train_datagen.flow_from_directory(
        directory = root,  # This is the source directory for training images
        target_size=(128, 128),  # All images will be resized
        batch_size=BATCH_SIZE,
        shuffle=True,
        seed=42, #for the shuffle
        classes=[''])

i = 4
for batch in range(i):
  [print(x[0]) for x in next(train_generator)]
_
3
pastaleg