![]() |
![]() |
![]() |
![]() |
개요
이 튜토리얼에서는 이미지 회전과 같은 무작위(그러나 사실적인) 변환을 적용하여 훈련 세트의 다양성을 증가시키는 기술인 데이터 증강의 예를 보여줍니다. 두 가지 방법으로 데이터 증강을 적용하는 방법을 배웁니다. 먼저, Keras 전처리 레이어를 사용하고, 그 다음으로 tf.image
를 사용합니다.
설정
pip install -q tf-nightly
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
데이터세트 다운로드
이 튜토리얼에서는 tf_flowers 데이터세트를 사용합니다. 편의를 위해 TensorFlow Datasets를 사용하여 데이터세트를 다운로드합니다. 데이터를 가져오는 다른 방법을 알아보려면 이미지 로드 튜토리얼을 참조하세요.
(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.
꽃 데이터세트에는 5개의 클래스가 있습니다.
num_classes = metadata.features['label'].num_classes
print(num_classes)
5
데이터세트에서 이미지를 검색하고 이를 사용하여 데이터 증강을 수행하겠습니다.
get_label_name = metadata.features['label'].int2str
image, label = next(iter(train_ds))
_ = plt.imshow(image)
_ = plt.title(get_label_name(label))
Keras 전처리 레이어 사용하기
참고: 이 섹션에서 소개하는 Keras 전처리 레이어는 현재 실험적 단계입니다.
크기 및 배율 조정하기
전처리 레이어를 사용하여 이미지를 일관된 모양으로 크기 조정하고 픽셀 값의 배율을 조정할 수 있습니다.
IMG_SIZE = 180
resize_and_rescale = tf.keras.Sequential([
layers.experimental.preprocessing.Resizing(IMG_SIZE, IMG_SIZE),
layers.experimental.preprocessing.Rescaling(1./255)
])
참고: 위의 배율 조정 레이어는 픽셀 값을 [0,1]
로 표준화합니다. 그렇지 않고 [-1,1]
을 원할 경우, Rescaling(1./127.5, offset=-1)
을 작성하면 됩니다.
이러한 레이어를 이미지에 적용한 결과를 볼 수 있습니다.
result = resize_and_rescale(image)
_ = plt.imshow(result)
픽셀이 [0-1]
에 있는지 확인할 수 있습니다.
print("Min and max pixel values:", result.numpy().min(), result.numpy().max())
Min and max pixel values: 0.0 1.0
데이터 증강
데이터 증강에도 전처리 레이어를 사용할 수 있습니다.
몇 개의 전처리 레이어를 만들어 동일한 이미지에 반복적으로 적용 해 보겠습니다.
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")
layers.RandomContrast
, layers.RandomCrop
, layers.RandomZoom
등 데이터 증강에 사용할 수 있는 다양한 전처리 레이어가 있습니다.
전처리 레이어를 사용하는 두 가지 옵션
중요한 절충을 통해 이러한 전처리 레이어를 사용할 수 있는 두 가지 방법이 있습니다.
옵션 1: 전처리 레이어를 모델의 일부로 만들기
model = tf.keras.Sequential([
resize_and_rescale,
data_augmentation,
layers.Conv2D(16, 3, padding='same', activation='relu'),
layers.MaxPooling2D(),
# Rest of your model
])
이 경우 유의해야 할 두 가지 중요한 사항이 있습니다.
데이터 증강은 나머지 레이어와 동기적으로 기기에서 실행되며 GPU 가속을 이용합니다.
model.save
를 사용하여 모델을 내보낼 때 전처리 레이어가 모델의 나머지 부분과 함께 저장됩니다. 나중에 이 모델을 배포하면 레이어 구성에 따라 이미지가 자동으로 표준화됩니다. 이를 통해 서버측 논리를 다시 구현해야 하는 노력을 덜 수 있습니다.
참고: 데이터 증강은 테스트할 때 비활성화되므로 입력 이미지는 model.fit
(model.evaluate
또는 model.predict
가 아님) 호출 중에만 증강됩니다.
옵션 2: 데이터세트에 전처리 레이어 적용하기
aug_ds = train_ds.map(
lambda x, y: (resize_and_rescale(x, training=True), y))
이 접근 방식에서는 Dataset.map
을 사용하여 증강 이미지 배치를 생성하는 데이터세트를 만듭니다. 이 경우에는 다음과 같습니다.
- 데이터 증강은 CPU에서 비동기적으로 이루어지며 차단되지 않습니다. 아래와 같이
Dataset.prefetch
를 사용하여 GPU에서 모델 훈련을 데이터 전처리와 중첩할 수 있습니다. - 이 경우, 전처리 레이어는
model.save
를 호출할 때 모델과 함께 내보내지지 않습니다. 저장하기 전에 이 레이어를 모델에 연결하거나 서버측에서 다시 구현해야 합니다. 훈련 후, 내보내기 전에 전처리 레이어를 연결할 수 있습니다.
이미지 분류 튜토리얼에서 첫 번째 옵션의 예를 볼 수 있습니다. 여기에서는 두 번째 옵션을 살펴보겠습니다.
데이터세트에 전처리 레이어 적용하기
위에서 생성한 전처리 레이어로 훈련, 검증 및 테스트 데이터세트를 구성합니다. 또한 병렬 읽기 및 버퍼링된 프리페치를 사용하여 I/O 차단 없이 디스크에서 배치를 생성하여 성능을 높이도록 데이터세트를 구성합니다. tf.data API로 성능 향상하기 가이드에서 데이터세트 성능에 대해 자세히 알아볼 수 있습니다.
참고: 데이터 증강은 훈련 세트에만 적용해야 합니다.
batch_size = 32
AUTOTUNE = tf.data.experimental.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)
모델 훈련하기
완성도를 높이기 위해 이제 이러한 데이터세트를 사용하여 모델을 훈련합니다. 이 모델은 정확성에 목표를 두고 조정되지 않았습니다(작동 방식을 시연하는 것이 목표임).
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 [==============================] - 8s 51ms/step - loss: 1.4660 - accuracy: 0.3824 - val_loss: 1.0876 - val_accuracy: 0.5858 Epoch 2/5 92/92 [==============================] - 3s 30ms/step - loss: 1.1081 - accuracy: 0.5387 - val_loss: 1.0455 - val_accuracy: 0.5313 Epoch 3/5 92/92 [==============================] - 3s 29ms/step - loss: 0.9616 - accuracy: 0.6263 - val_loss: 0.9681 - val_accuracy: 0.6540 Epoch 4/5 92/92 [==============================] - 3s 29ms/step - loss: 0.9068 - accuracy: 0.6380 - val_loss: 0.9041 - val_accuracy: 0.6812 Epoch 5/5 92/92 [==============================] - 3s 29ms/step - loss: 0.8673 - accuracy: 0.6538 - val_loss: 0.9506 - val_accuracy: 0.6185
loss, acc = model.evaluate(test_ds)
print("Accuracy", acc)
12/12 [==============================] - 0s 14ms/step - loss: 0.8680 - accuracy: 0.6649 Accuracy 0.664850115776062
사용자 정의 데이터 증강
사용자 정의 데이터 증강 레이어를 만들 수도 있습니다. 이 튜토리얼에서는 두 가지 방법을 소개합니다. 먼저, layers.Lambda
레이어를 생성합니다. 이것은 간결한 코드를 작성하는 좋은 방법입니다. 다음으로, 제어력을 높여주는 서브 클래스 생성을 통해 새 레이어를 작성합니다. 두 레이어는 확률에 따라 이미지의 색상을 무작위로 반전합니다.
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")
다음으로, 서브 클래스 생성을 통해 사용자 정의 레이어를 구현합니다.
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])
위의 옵션 1과 2의 설명에 따라 이 두 레이어를 모두 사용할 수 있습니다.
tf.image 사용하기
위의 layers.preprocessing
유틸리티는 편리합니다. 보다 세밀한 제어를 위해서는 tf.data
및 tf.image
를 사용하여 고유한 데이터 증강 파이프라인 또는 레이어를 작성할 수 있습니다. TensorFlow 애드온 이미지: 작업 및 TensorFlow I/O: 색 공간 변환도 확인해보세요.
꽃 데이터세트는 이전에 데이터 증강으로 구성되었으므로 다시 가져와서 새로 시작하겠습니다.
(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,
)
작업할 이미지를 검색합니다.
image, label = next(iter(train_ds))
_ = plt.imshow(image)
_ = plt.title(get_label_name(label))
다음 함수를 사용하여 원본 이미지와 증강 이미지를 나란히 시각화하고 비교하겠습니다.
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)
데이터 증강
이미지 뒤집기
이미지를 수직 또는 수평으로 뒤집습니다.
flipped = tf.image.flip_left_right(image)
visualize(image, flipped)
이미지를 회색조로 만들기
이미지를 회색조로 만듭니다.
grayscaled = tf.image.rgb_to_grayscale(image)
visualize(image, tf.squeeze(grayscaled))
_ = plt.colorbar()
이미지 포화시키기
채도 계수를 제공하여 이미지를 포화시킵니다.
saturated = tf.image.adjust_saturation(image, 3)
visualize(image, saturated)
이미지 밝기 변경하기
밝기 계수를 제공하여 이미지의 밝기를 변경합니다.
bright = tf.image.adjust_brightness(image, 0.4)
visualize(image, bright)
이미지 중앙 자르기
이미지를 중앙에서 원하는 이미지 부분까지 자릅니다.
cropped = tf.image.central_crop(image, central_fraction=0.5)
visualize(image,cropped)
이미지 회전하기
이미지를 90도 회전합니다.
rotated = tf.image.rot90(image)
visualize(image, rotated)
데이터세트에 증강 적용하기
이전과 마찬가지로 Dataset.map
을 사용하여 데이터 증강을 데이터세트에 적용합니다.
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
def augment(image,label):
image, label = resize_and_rescale(image, label)
# Add 6 pixels of padding
image = tf.image.resize_with_crop_or_pad(image, IMG_SIZE + 6, IMG_SIZE + 6)
# Random crop back to the original size
image = tf.image.random_crop(image, size=[IMG_SIZE, IMG_SIZE, 3])
image = tf.image.random_brightness(image, max_delta=0.5) # Random brightness
image = tf.clip_by_value(image, 0, 1)
return image, label
데이터세트 구성하기
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)
)
이제 이러한 데이터세트를 사용하여 이전에 표시한 대로 모델을 훈련할 수 있습니다.
다음 단계
이 튜토리얼에서는 Keras 전처리 레이어 및 tf.image
를 사용한 데이터 증강 방법을 보여주었습니다. 모델 내부에 전처리 레이어를 포함하는 방법을 알아보려면 이미지 분류 튜토리얼을 참조하세요. 기본 텍스트 분류 튜토리얼에 나와 있는 것처럼 전처리 레이어가 텍스트를 분류하는 데 어떤 도움을 주는지 알아볼 수도 있습니다. 이 가이드에서 tf.data
에 대해 자세히 알아볼 수 있으며 여기에서 성능을 높이도록 입력 파이프라인을 구성하는 방법을 알아볼 수 있습니다.