Bantuan melindungi Great Barrier Reef dengan TensorFlow pada Kaggle Bergabung Tantangan

Augmentasi data

Lihat di TensorFlow.org Jalankan di Google Colab Lihat sumber di GitHub Unduh buku catatan

Gambaran

Tutorial ini mendemonstrasikan augmentasi data: teknik untuk meningkatkan keragaman set pelatihan Anda dengan menerapkan transformasi acak (namun realistis), seperti rotasi gambar.

Anda akan belajar bagaimana menerapkan augmentasi data dalam dua cara:

Mempersiapkan

import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
import tensorflow_datasets as tfds

from tensorflow.keras import layers

Unduh kumpulan data

Tutorial ini menggunakan tf_flowers dataset. Untuk kenyamanan, download dataset menggunakan TensorFlow Datasets . Jika Anda ingin belajar tentang cara-cara lain mengimpor data, memeriksa beban gambar tutorial.

(train_ds, val_ds, test_ds), metadata = tfds.load(
    'tf_flowers',
    split=['train[:80%]', 'train[80%:90%]', 'train[90%:]'],
    with_info=True,
    as_supervised=True,
)

Dataset bunga memiliki lima kelas.

num_classes = metadata.features['label'].num_classes
print(num_classes)
5

Mari ambil gambar dari kumpulan data dan gunakan untuk mendemonstrasikan augmentasi data.

get_label_name = metadata.features['label'].int2str

image, label = next(iter(train_ds))
_ = plt.imshow(image)
_ = plt.title(get_label_name(label))
2021-10-22 01:22:18.891161: W tensorflow/core/kernels/data/cache_dataset_ops.cc:768] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.

png

Gunakan lapisan pra-pemrosesan Keras

Mengubah ukuran dan mengubah skala

Anda dapat menggunakan Keras preprocessing lapisan untuk mengubah ukuran gambar Anda ke bentuk yang konsisten (dengan tf.keras.layers.Resizing ), dan nilai-nilai pixel rescale (dengan tf.keras.layers.Rescaling ).

IMG_SIZE = 180

resize_and_rescale = tf.keras.Sequential([
  layers.Resizing(IMG_SIZE, IMG_SIZE),
  layers.Rescaling(1./255)
])

Anda dapat memvisualisasikan hasil penerapan lapisan ini ke gambar.

result = resize_and_rescale(image)
_ = plt.imshow(result)

png

Memverifikasi bahwa piksel yang di [0, 1] kisaran:

print("Min and max pixel values:", result.numpy().min(), result.numpy().max())
Min and max pixel values: 0.0 1.0

Augmentasi data

Anda dapat menggunakan Keras preprocessing lapisan untuk pembesaran data serta, seperti tf.keras.layers.RandomFlip dan tf.keras.layers.RandomRotation .

Mari buat beberapa lapisan pra-pemrosesan dan terapkan berulang kali ke gambar yang sama.

data_augmentation = tf.keras.Sequential([
  layers.RandomFlip("horizontal_and_vertical"),
  layers.RandomRotation(0.2),
])
# Add the image to a batch.
image = tf.expand_dims(image, 0)
plt.figure(figsize=(10, 10))
for i in range(9):
  augmented_image = data_augmentation(image)
  ax = plt.subplot(3, 3, i + 1)
  plt.imshow(augmented_image[0])
  plt.axis("off")

png

Ada berbagai preprocessing lapisan dapat Anda gunakan untuk pembesaran data yang termasuk tf.keras.layers.RandomContrast , tf.keras.layers.RandomCrop , tf.keras.layers.RandomZoom , dan lain-lain.

Dua opsi untuk menggunakan lapisan prapemrosesan Keras

Ada dua cara Anda dapat menggunakan lapisan prapemrosesan ini, dengan pertukaran yang penting.

Opsi 1: Jadikan lapisan prapemrosesan bagian dari model Anda

model = tf.keras.Sequential([
  # Add the preprocessing layers you created earlier.
  resize_and_rescale,
  data_augmentation,
  layers.Conv2D(16, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  # Rest of your model.
])

Ada dua poin penting yang harus diperhatikan dalam kasus ini:

  • Augmentasi data akan berjalan di perangkat, secara sinkron dengan lapisan Anda lainnya, dan mendapat manfaat dari akselerasi GPU.

  • Saat Anda mengekspor model Anda menggunakan model.save , lapisan preprocessing akan disimpan bersama dengan sisa dari model Anda. Jika nanti Anda menerapkan model ini, itu akan secara otomatis menstandardisasi gambar (sesuai dengan konfigurasi lapisan Anda). Ini dapat menyelamatkan Anda dari upaya untuk mengimplementasikan kembali logika sisi server tersebut.

Opsi 2: Terapkan lapisan prapemrosesan ke kumpulan data Anda

aug_ds = train_ds.map(
  lambda x, y: (resize_and_rescale(x, training=True), y))

Dengan pendekatan ini, Anda menggunakan Dataset.map untuk membuat dataset yang hasil batch gambar ditambah. Pada kasus ini:

  • Augmentasi data akan terjadi secara asinkron pada CPU, dan tidak memblokir. Anda dapat tumpang tindih pelatihan model Anda pada GPU dengan data preprocessing, menggunakan Dataset.prefetch , ditunjukkan di bawah ini.
  • Dalam hal ini lapisan preprocessing tidak akan diekspor dengan model ketika Anda menelepon Model.save . Anda harus melampirkannya ke model Anda sebelum menyimpannya atau menerapkannya kembali di sisi server. Setelah pelatihan, Anda dapat memasang lapisan prapemrosesan sebelum mengekspor.

Anda dapat menemukan contoh dari pilihan pertama dalam klasifikasi Gambar tutorial. Mari kita tunjukkan opsi kedua di sini.

Terapkan lapisan pra-pemrosesan ke kumpulan data

Konfigurasikan set data pelatihan, validasi, dan pengujian dengan lapisan prapemrosesan Keras yang Anda buat sebelumnya. Anda juga akan mengonfigurasi kumpulan data untuk kinerja, menggunakan pembacaan paralel dan pengambilan buffered untuk menghasilkan kumpulan dari disk tanpa I/O menjadi pemblokiran. (Pelajari kinerja yang lebih dataset dalam kinerja yang lebih baik dengan tf.data API panduan.)

batch_size = 32
AUTOTUNE = tf.data.AUTOTUNE

def prepare(ds, shuffle=False, augment=False):
  # Resize and rescale all datasets.
  ds = ds.map(lambda x, y: (resize_and_rescale(x), y), 
              num_parallel_calls=AUTOTUNE)

  if shuffle:
    ds = ds.shuffle(1000)

  # Batch all datasets.
  ds = ds.batch(batch_size)

  # Use data augmentation only on the training set.
  if augment:
    ds = ds.map(lambda x, y: (data_augmentation(x, training=True), y), 
                num_parallel_calls=AUTOTUNE)

  # Use buffered prefetching on all datasets.
  return ds.prefetch(buffer_size=AUTOTUNE)
train_ds = prepare(train_ds, shuffle=True, augment=True)
val_ds = prepare(val_ds)
test_ds = prepare(test_ds)

Latih seorang model

Untuk kelengkapan, Anda sekarang akan melatih model menggunakan kumpulan data yang baru saja Anda siapkan.

The Sequential Model terdiri dari tiga blok lilit ( tf.keras.layers.Conv2D ) dengan lapisan pooling max ( tf.keras.layers.MaxPooling2D ) di masing-masing. Ada lapisan sepenuhnya terhubung ( tf.keras.layers.Dense ) dengan 128 unit di atasnya yang diaktifkan oleh ReLU fungsi aktivasi ( 'relu' ). Model ini belum disetel untuk akurasi (tujuannya adalah untuk menunjukkan kepada Anda mekanismenya).

model = tf.keras.Sequential([
  layers.Conv2D(16, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(32, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(64, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Flatten(),
  layers.Dense(128, activation='relu'),
  layers.Dense(num_classes)
])

Pilih tf.keras.optimizers.Adam optimizer dan tf.keras.losses.SparseCategoricalCrossentropy fungsi kerugian. Untuk tampilan pelatihan dan akurasi validasi untuk setiap zaman pelatihan, lulus metrics argumen untuk Model.compile .

model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

Latih untuk beberapa zaman:

epochs=5
history = model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=epochs
)
Epoch 1/5
92/92 [==============================] - 30s 190ms/step - loss: 1.3237 - accuracy: 0.4183 - val_loss: 1.0881 - val_accuracy: 0.5668
Epoch 2/5
92/92 [==============================] - 3s 26ms/step - loss: 1.0428 - accuracy: 0.5841 - val_loss: 1.0630 - val_accuracy: 0.5886
Epoch 3/5
92/92 [==============================] - 3s 26ms/step - loss: 0.9704 - accuracy: 0.6202 - val_loss: 1.0317 - val_accuracy: 0.6076
Epoch 4/5
92/92 [==============================] - 3s 26ms/step - loss: 0.9190 - accuracy: 0.6356 - val_loss: 0.8869 - val_accuracy: 0.6621
Epoch 5/5
92/92 [==============================] - 3s 26ms/step - loss: 0.8766 - accuracy: 0.6594 - val_loss: 0.8312 - val_accuracy: 0.6730
loss, acc = model.evaluate(test_ds)
print("Accuracy", acc)
12/12 [==============================] - 3s 32ms/step - loss: 0.8001 - accuracy: 0.7030
Accuracy 0.7029972672462463

Augmentasi data khusus

Anda juga dapat membuat lapisan augmentasi data khusus.

Bagian tutorial ini menunjukkan dua cara untuk melakukannya:

  • Pertama, Anda akan membuat tf.keras.layers.Lambda lapisan. Ini adalah cara yang baik untuk menulis kode ringkas.
  • Berikutnya, Anda akan menulis layer baru melalui subclassing , yang memberi Anda kontrol lebih.

Kedua lapisan akan secara acak membalikkan warna dalam gambar, menurut beberapa kemungkinan.

def random_invert_img(x, p=0.5):
  if  tf.random.uniform([]) < p:
    x = (255-x)
  else:
    x
  return x
def random_invert(factor=0.5):
  return layers.Lambda(lambda x: random_invert_img(x, factor))

random_invert = random_invert()
plt.figure(figsize=(10, 10))
for i in range(9):
  augmented_image = random_invert(image)
  ax = plt.subplot(3, 3, i + 1)
  plt.imshow(augmented_image[0].numpy().astype("uint8"))
  plt.axis("off")

png

Berikutnya, menerapkan lapisan kustom oleh subclassing :

class RandomInvert(layers.Layer):
  def __init__(self, factor=0.5, **kwargs):
    super().__init__(**kwargs)
    self.factor = factor

  def call(self, x):
    return random_invert_img(x)
_ = plt.imshow(RandomInvert()(image)[0])

png

Kedua lapisan ini dapat digunakan seperti yang dijelaskan pada opsi 1 dan 2 di atas.

Menggunakan tf.image

Utilitas pra-pemrosesan Keras di atas nyaman digunakan. Tapi, untuk kontrol halus, Anda dapat menulis pipa data yang augmentation Anda sendiri atau lapisan menggunakan tf.data dan tf.image . (Anda juga mungkin ingin memeriksa TensorFlow Addons Gambar: Operasi dan TensorFlow I / O: Color Space Konversi .)

Karena kumpulan data bunga sebelumnya dikonfigurasi dengan augmentasi data, mari impor ulang untuk memulai yang baru:

(train_ds, val_ds, test_ds), metadata = tfds.load(
    'tf_flowers',
    split=['train[:80%]', 'train[80%:90%]', 'train[90%:]'],
    with_info=True,
    as_supervised=True,
)

Ambil gambar untuk dikerjakan:

image, label = next(iter(train_ds))
_ = plt.imshow(image)
_ = plt.title(get_label_name(label))
2021-10-22 01:23:14.609482: W tensorflow/core/kernels/data/cache_dataset_ops.cc:768] The calling iterator did not fully read the dataset being cached. In order to avoid unexpected truncation of the dataset, the partially cached contents of the dataset  will be discarded. This can happen if you have an input pipeline similar to `dataset.cache().take(k).repeat()`. You should use `dataset.take(k).cache().repeat()` instead.

png

Mari gunakan fungsi berikut untuk memvisualisasikan dan membandingkan gambar asli dan gambar yang diperbesar secara berdampingan:

def visualize(original, augmented):
  fig = plt.figure()
  plt.subplot(1,2,1)
  plt.title('Original image')
  plt.imshow(original)

  plt.subplot(1,2,2)
  plt.title('Augmented image')
  plt.imshow(augmented)

Augmentasi data

Balikkan gambar

Membalik gambar baik secara vertikal maupun horizontal dengan tf.image.flip_left_right :

flipped = tf.image.flip_left_right(image)
visualize(image, flipped)

png

Skala abu-abu gambar

Anda dapat grayscale gambar dengan tf.image.rgb_to_grayscale :

grayscaled = tf.image.rgb_to_grayscale(image)
visualize(image, tf.squeeze(grayscaled))
_ = plt.colorbar()

png

Menjenuhkan gambar

Menjenuhkan gambar dengan tf.image.adjust_saturation dengan menyediakan faktor kejenuhan:

saturated = tf.image.adjust_saturation(image, 3)
visualize(image, saturated)

png

Ubah kecerahan gambar

Mengubah kecerahan gambar dengan tf.image.adjust_brightness dengan menyediakan faktor brightness:

bright = tf.image.adjust_brightness(image, 0.4)
visualize(image, bright)

png

Pangkas gambar di tengah

Memotong gambar dari pusat sampai ke bagian gambar yang Anda inginkan menggunakan tf.image.central_crop :

cropped = tf.image.central_crop(image, central_fraction=0.5)
visualize(image,cropped)

png

Putar gambar

Memutar foto 90 derajat dengan tf.image.rot90 :

rotated = tf.image.rot90(image)
visualize(image, rotated)

png

Transformasi acak

Menerapkan transformasi acak ke gambar dapat lebih membantu menggeneralisasi dan memperluas kumpulan data. Arus tf.image API menyediakan delapan operasi gambar acak seperti (ops):

Operasi gambar acak ini murni fungsional: output hanya bergantung pada input. Ini membuatnya mudah digunakan dalam pipeline input deterministik berkinerja tinggi. Mereka membutuhkan seed nilai be masukan setiap langkah. Mengingat sama seed , mereka kembali hasil yang sama terlepas dari berapa kali mereka disebut.

Di bagian berikut, Anda akan:

  1. Lihat contoh penggunaan operasi gambar acak untuk mengubah gambar; dan
  2. Mendemonstrasikan cara menerapkan transformasi acak ke set data pelatihan.

Ubah kecerahan gambar secara acak

Secara acak mengubah kecerahan image menggunakan tf.image.stateless_random_brightness dengan menyediakan faktor kecerahan dan seed . Faktor brightness dipilih secara acak dalam rentang [-max_delta, max_delta) dan berhubungan dengan diberikan seed .

for i in range(3):
  seed = (i, 0)  # tuple of size (2,)
  stateless_random_brightness = tf.image.stateless_random_brightness(
      image, max_delta=0.95, seed=seed)
  visualize(image, stateless_random_brightness)

png

png

png

Ubah kontras gambar secara acak

Secara acak mengubah kontras image menggunakan tf.image.stateless_random_contrast dengan menyediakan berbagai kontras dan seed . Rentang kontras dipilih secara acak dalam interval [lower, upper] dan berhubungan dengan diberikan seed .

for i in range(3):
  seed = (i, 0)  # tuple of size (2,)
  stateless_random_contrast = tf.image.stateless_random_contrast(
      image, lower=0.1, upper=0.9, seed=seed)
  visualize(image, stateless_random_contrast)

png

png

png

Pangkas gambar secara acak

Acak memotong image menggunakan tf.image.stateless_random_crop dengan memberikan target yang size dan seed . Bagian yang akan dipotong dari image berada pada acak dipilih tersebut offset dan dikaitkan dengan diberikan seed .

for i in range(3):
  seed = (i, 0)  # tuple of size (2,)
  stateless_random_crop = tf.image.stateless_random_crop(
      image, size=[210, 300, 3], seed=seed)
  visualize(image, stateless_random_crop)

png

png

png

Terapkan augmentasi ke kumpulan data

Pertama-tama, unduh dataset gambar lagi jika diubah di bagian sebelumnya.

(train_datasets, val_ds, test_ds), metadata = tfds.load(
    'tf_flowers',
    split=['train[:80%]', 'train[80%:90%]', 'train[90%:]'],
    with_info=True,
    as_supervised=True,
)

Selanjutnya, tentukan fungsi utilitas untuk mengubah ukuran dan mengubah skala gambar. Fungsi ini akan digunakan dalam menyatukan ukuran dan skala gambar dalam dataset:

def resize_and_rescale(image, label):
  image = tf.cast(image, tf.float32)
  image = tf.image.resize(image, [IMG_SIZE, IMG_SIZE])
  image = (image / 255.0)
  return image, label

Mari kita juga menentukan augment fungsi yang dapat menerapkan transformasi acak untuk gambar. Fungsi ini akan digunakan pada dataset pada langkah berikutnya.

def augment(image_label, seed):
  image, label = image_label
  image, label = resize_and_rescale(image, label)
  image = tf.image.resize_with_crop_or_pad(image, IMG_SIZE + 6, IMG_SIZE + 6)
  # Make a new seed.
  new_seed = tf.random.experimental.stateless_split(seed, num=1)[0, :]
  # Random crop back to the original size.
  image = tf.image.stateless_random_crop(
      image, size=[IMG_SIZE, IMG_SIZE, 3], seed=seed)
  # Random brightness.
  image = tf.image.stateless_random_brightness(
      image, max_delta=0.5, seed=new_seed)
  image = tf.clip_by_value(image, 0, 1)
  return image, label

Opsi 1: Menggunakan tf.data.experimental.Counter

Buat tf.data.experimental.Counter objek (sebut saja counter ) dan Dataset.zip dataset dengan (counter, counter) . Ini akan memastikan bahwa setiap gambar dalam dataset mendapat terkait dengan nilai unik (bentuk (2,) ) berdasarkan counter yang kemudian bisa melewati ke dalam augment fungsi sebagai seed nilai untuk transformasi acak.

# Create a `Counter` object and `Dataset.zip` it together with the trainining set.
counter = tf.data.experimental.Counter()
train_ds = tf.data.Dataset.zip((train_datasets, (counter, counter)))
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/data/experimental/ops/counter.py:66: scan (from tensorflow.python.data.experimental.ops.scan_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.data.Dataset.scan(...) instead
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/data/experimental/ops/counter.py:66: scan (from tensorflow.python.data.experimental.ops.scan_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Use `tf.data.Dataset.scan(...) instead

Memetakan augment fungsi untuk dataset pelatihan:

train_ds = (
    train_ds
    .shuffle(1000)
    .map(augment, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)
val_ds = (
    val_ds
    .map(resize_and_rescale, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)
test_ds = (
    test_ds
    .map(resize_and_rescale, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)

Opsi 2: Menggunakan tf.random.Generator

  • Buat tf.random.Generator objek dengan awal seed nilai. Memanggil make_seeds fungsi pada objek generator yang sama selalu mengembalikan baru, unik seed nilai.
  • Mendefinisikan fungsi pembungkus yang: 1) menyebut make_seeds berfungsi; dan 2) melewati baru yang dihasilkan seed nilai ke dalam augment fungsi untuk transformasi acak.
# Create a generator.
rng = tf.random.Generator.from_seed(123, alg='philox')
# Create a wrapper function for updating seeds.
def f(x, y):
  seed = rng.make_seeds(2)[0]
  image, label = augment((x, y), seed)
  return image, label

Memetakan fungsi wrapper f ke dataset pelatihan, dan resize_and_rescale fungsi-to validasi dan uji set:

train_ds = (
    train_datasets
    .shuffle(1000)
    .map(f, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)
val_ds = (
    val_ds
    .map(resize_and_rescale, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)
test_ds = (
    test_ds
    .map(resize_and_rescale, num_parallel_calls=AUTOTUNE)
    .batch(batch_size)
    .prefetch(AUTOTUNE)
)

Kumpulan data ini sekarang dapat digunakan untuk melatih model seperti yang ditunjukkan sebelumnya.

Langkah selanjutnya

Tutorial menunjukkan ini augmentation data menggunakan Keras preprocessing lapisan dan tf.image .

  • Untuk mempelajari bagaimana memasukkan preprocessing lapisan dalam model Anda, merujuk pada klasifikasi Gambar tutorial.
  • Anda juga mungkin tertarik dalam mempelajari bagaimana preprocessing lapisan dapat membantu Anda teks mengklasifikasikan, seperti yang ditunjukkan dalam teks dasar klasifikasi tutorial.
  • Anda dapat mempelajari lebih lanjut tentang tf.data dalam buku , dan Anda dapat mempelajari cara mengkonfigurasi jaringan pipa masukan Anda untuk kinerja di sini .