Catat tanggalnya! Google I / O mengembalikan 18-20 Mei Daftar sekarang
Halaman ini diterjemahkan oleh Cloud Translation API.
Switch to English

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 (tetapi realistis) seperti rotasi gambar. Anda akan mempelajari cara menerapkan augmentasi data dengan dua cara. Pertama, Anda akan menggunakan Keras Preprocessing Layers . Selanjutnya, Anda akan menggunakan tf.image .

Mempersiapkan

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

from tensorflow.keras import layers
from tensorflow.keras.datasets import mnist

Unduh kumpulan data

Tutorial ini menggunakan kumpulan data tf_flowers . Untuk kenyamanan, unduh kumpulan data menggunakan TensorFlow Dataset . Jika Anda ingin mempelajari cara lain untuk mengimpor data, lihat tutorial memuat gambar .

(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,
)
Downloading and preparing dataset 218.21 MiB (download: 218.21 MiB, generated: 221.83 MiB, total: 440.05 MiB) to /home/kbuilder/tensorflow_datasets/tf_flowers/3.0.1...
Dataset tf_flowers downloaded and prepared to /home/kbuilder/tensorflow_datasets/tf_flowers/3.0.1. Subsequent calls will reuse this data.

Dataset bunga memiliki lima kelas.

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

Mari ambil gambar dari dataset 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))

png

Gunakan lapisan preprocessing Keras

Mengubah ukuran dan mengubah skala

Anda dapat menggunakan preprocessing lapisan untuk mengubah ukuran gambar Anda ke bentuk yang konsisten, dan rescale nilai piksel.

IMG_SIZE = 180

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

Anda dapat melihat hasil penerapan lapisan ini ke gambar.

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

png

Anda dapat memverifikasi piksel dalam [0-1] .

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

Augmentasi data

Anda juga dapat menggunakan lapisan praproses untuk augmentasi data.

Mari buat beberapa lapisan praproses dan terapkan berulang kali ke gambar yang sama.

data_augmentation = tf.keras.Sequential([
  layers.experimental.preprocessing.RandomFlip("horizontal_and_vertical"),
  layers.experimental.preprocessing.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 macam lapisan layers.RandomContrast - layers.RandomCrop dapat Anda gunakan untuk augmentasi data termasuk layers.RandomContrast , layers.RandomCrop , layers.RandomZoom , dan lainnya.

Dua opsi untuk menggunakan lapisan praproses

Ada dua cara Anda dapat menggunakan lapisan pra-pemrosesan ini, dengan pengorbanan penting.

Opsi 1: Jadikan lapisan praproses sebagai bagian dari model Anda

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

Ada dua hal penting yang harus diperhatikan dalam kasus ini:

  • Augmentasi data akan berjalan di perangkat, selaras dengan seluruh lapisan Anda, dan mendapatkan keuntungan dari akselerasi GPU.

  • Saat Anda mengekspor model Anda menggunakan model.save , lapisan model.save - model.save akan disimpan bersama dengan model Anda yang lain. Jika Anda kemudian menerapkan model ini, itu akan secara otomatis membakukan gambar (sesuai dengan konfigurasi lapisan Anda). Ini dapat menyelamatkan Anda dari upaya harus menerapkan ulang logika sisi server itu.

Opsi 2: Terapkan lapisan pra-pemrosesan 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 kumpulan data yang menghasilkan kumpulan gambar yang ditambah. Pada kasus ini:

  • Augmentasi data akan terjadi secara asinkron di CPU, dan tidak memblokir. Anda dapat tumpang tindih pelatihan model Anda di GPU dengan prapemrosesan data, menggunakan Dataset.prefetch , yang ditunjukkan di bawah ini.
  • Dalam hal ini lapisan prepreprocessing tidak akan diekspor dengan model saat Anda memanggil model.save . Anda harus melampirkannya ke model Anda sebelum menyimpannya atau menerapkannya kembali di sisi server. Setelah pelatihan, Anda dapat melampirkan lapisan pra-pemrosesan sebelum mengekspor.

Anda dapat menemukan contoh opsi pertama di tutorial klasifikasi gambar . Mari kita tunjukkan opsi kedua di sini.

Menerapkan lapisan preprocessing ke dataset

Konfigurasikan kumpulan data train, validasi, dan pengujian dengan lapisan pra-pemrosesan yang Anda buat di atas. Anda juga akan mengonfigurasi set data untuk performa, menggunakan pembacaan paralel dan prefetching yang di-buffer untuk menghasilkan batch dari disk tanpa pemblokiran I / O. Anda dapat mempelajari lebih lanjut performa set data di Better performance dengan panduan API tf.data .

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 prefecting 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 model

Untuk kelengkapan, Anda sekarang akan melatih model menggunakan kumpulan data ini. Model ini belum disetel keakuratannya (tujuannya adalah untuk menunjukkan kepada Anda mekaniknya).

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)
])
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])
epochs=5
history = model.fit(
  train_ds,
  validation_data=val_ds,
  epochs=epochs
)
Epoch 1/5
92/92 [==============================] - 17s 47ms/step - loss: 1.6206 - accuracy: 0.2998 - val_loss: 1.1271 - val_accuracy: 0.5613
Epoch 2/5
92/92 [==============================] - 3s 28ms/step - loss: 1.0935 - accuracy: 0.5384 - val_loss: 1.0343 - val_accuracy: 0.5858
Epoch 3/5
92/92 [==============================] - 3s 27ms/step - loss: 0.9785 - accuracy: 0.6022 - val_loss: 0.8810 - val_accuracy: 0.6540
Epoch 4/5
92/92 [==============================] - 3s 27ms/step - loss: 0.9167 - accuracy: 0.6399 - val_loss: 0.8247 - val_accuracy: 0.6594
Epoch 5/5
92/92 [==============================] - 3s 27ms/step - loss: 0.8545 - accuracy: 0.6615 - val_loss: 0.8591 - val_accuracy: 0.6458
loss, acc = model.evaluate(test_ds)
print("Accuracy", acc)
12/12 [==============================] - 0s 13ms/step - loss: 0.9010 - accuracy: 0.6131
Accuracy 0.6130790114402771

Augmentasi data kustom

Anda juga dapat membuat lapisan augmenasi data kustom. Tutorial ini menunjukkan dua cara untuk melakukannya. Pertama, Anda akan membuat layers.Lambda layer. Ini adalah cara yang bagus untuk menulis kode yang ringkas. Selanjutnya, Anda akan menulis layer baru melalui subclassing , yang memberi Anda kontrol lebih. Kedua lapisan akan secara acak membalik warna pada 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

Selanjutnya, terapkan lapisan khusus dengan membuat subkelas .

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 layers.preprocessing atas nyaman digunakan. Untuk kontrol yang lebih baik, Anda dapat menulis pipeline atau lapisan augmentasi data Anda sendiri menggunakan tf.data dan tf.image . Anda mungkin juga ingin melihat TensorFlow Addons Image: Operations dan TensorFlow I / O: Color Space Conversions

Karena kumpulan data bunga sebelumnya dikonfigurasi dengan augmentasi data, mari kita impor ulang untuk memulai dari awal.

(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))

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

Membalik gambar

Balikkan gambar secara vertikal atau horizontal.

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

png

Gambar menjadi abu-abu

Gambar menjadi abu-abu.

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

png

Saturasikan gambar

Saturasi gambar dengan memberikan faktor saturasi.

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

png

Ubah kecerahan gambar

Ubah kecerahan gambar dengan memberikan faktor kecerahan.

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

png

Pangkas gambar di tengah

Pangkas gambar dari tengah ke atas ke bagian gambar yang Anda inginkan.

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

png

Putar gambarnya

Putar gambar 90 derajat.

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

png

Transformasi acak

Menerapkan transformasi acak ke gambar selanjutnya dapat membantu menggeneralisasi dan memperluas kumpulan data. API tf.image saat ini menyediakan 8 operasi gambar acak (ops):

Operasi gambar acak ini murni berfungsi: output hanya bergantung pada input. Ini membuatnya mudah digunakan dalam pipeline input deterministik berkinerja tinggi. Mereka membutuhkan nilai seed untuk dimasukkan setiap langkah. Diberikan seed sama, mereka mengembalikan hasil yang sama terlepas dari berapa kali mereka dipanggil.

Di bagian berikut, kami akan:

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

Ubah kecerahan gambar secara acak

Ubah kecerahan image secara acak dengan memberikan faktor kecerahan dan seed . Faktor kecerahan dipilih secara acak dalam kisaran [-max_delta, max_delta) dan dikaitkan dengan seed diberikan.

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

Ubah kontras image secara acak dengan memberikan rentang kontras dan seed . Kisaran kontras dipilih secara acak dalam interval [lower, upper] dan dikaitkan dengan seed diberikan.

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

Pangkas image secara acak dengan memberikan size target dan seed . Bagian yang dipotong dari image berada pada offset yang dipilih secara acak dan dikaitkan dengan seed diberikan.

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

Menerapkan augmentasi ke kumpulan data

Pertama-tama, mari kita unduh kumpulan data gambar lagi seandainya 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,
)

Mari tentukan fungsi utilitas untuk mengubah ukuran dan mengubah skala gambar. Fungsi ini akan digunakan untuk 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 mendefinisikan fungsi augment yang dapat menerapkan transformasi acak ke gambar. Fungsi ini akan digunakan pada dataset di 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 objek tf.data.experimental.Counter() (sebut saja counter ) dan zip tf.data.experimental.Counter() data dengan (counter, counter) . Ini akan memastikan bahwa setiap gambar dalam dataset dikaitkan dengan nilai unik (dari bentuk (2,) ) berdasarkan counter yang nantinya dapat diteruskan ke fungsi augment sebagai nilai seed untuk transformasi acak.

# Create counter and zip together with train dataset
counter = tf.data.experimental.Counter()
train_ds = tf.data.Dataset.zip((train_datasets, (counter, counter)))

Petakan fungsi augment ke set data 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 objek tf.random.Generator dengan nilai seed awal. Memanggil fungsi make_seeds pada objek generator yang sama selalu seed nilai seed baru yang unik. Tentukan fungsi pembungkus yang 1) memanggil fungsi make_seeds dan 2) meneruskan nilai seed baru dibuat ke dalam fungsi augment untuk transformasi acak.

# Create a generator
rng = tf.random.Generator.from_seed(123, alg='philox')
# 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

Petakan fungsi pembungkus f ke set data pelatihan.

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 ini mendemonstrasikan augmentasi data menggunakan Keras Preprocessing Layers dan tf.image . Untuk mempelajari cara menyertakan lapisan praproses di dalam model Anda, lihat tutorial klasifikasi gambar . Anda mungkin juga tertarik untuk mempelajari bagaimana lapisan pra-pemrosesan dapat membantu Anda mengklasifikasikan teks, seperti yang ditunjukkan dalam tutorial klasifikasi teks Dasar . Anda dapat mempelajari lebih lanjut tentang tf.data dalam panduan ini, dan Anda dapat mempelajari cara mengonfigurasi pipeline input Anda untuk performanya di sini .