Data Augmentation

Seungil Ko·2021년 12월 9일

실습목표

  • Augmentation을 하는 이유를 알아갑니다.
  • 여러 가지 Augmentation 방법을 알아둡니다.
  • 학습에 Augmentation을 적용할때 주의해야 할 점을 숙지합니다

1. Data Augmentation이란?

개요

갖고 있는 데이터셋을 여러 가지 방법으로 증강시켜(augmenet) 실질적인 학습 데이터셋의 규모를 키울 수 있는 방법입니다.

아래 영상을 통해 data augmentation의 개념을 익힙니다. (아래 이미지를 클릭하면 이동합니다)

data_augmentation

데이터가 많아진다는 것은 과적합(overfitting)을 줄일 수 있다는 것을 의미합니다. 또한 가지고 있는 데이터셋이 실제 상황에서의 입력과 다를 경우, augmentation을 통해서 실제 입력값과 비슷한 데이터 분포를 만들어 낼 수 있습니다.

다양한 Image Augmentation 방법

텐서플로우 페이지에서는 텐서플로우 API를 사용해 바로 적용할 수 있는 image augmentation 기법들이 있습니다.

Flipping
Flip은 이미지를 대칭하는 기능입니다. 좌우 또는 상하로 이미지를 반전시킬 수 있습니다. 하지만 문자를 인식(recognition)하는 문제에 적용할 때는 주의해야 합니다.

Flip

Gray scale
Gray scale은 3가지 채널(channel)을 가진 RGB를 하나의 채널을 가지도록 해줍니다. RGB 각각의 채널마다 가중치(weight)를 주어 가중합(weighted sum)을 할 수 있습니다. 사용된 가중치의 경우 합이 1이 됩니다.

Saturation
Saturation은 RGB 이미지를 HSV(Hue(색조), Saturation(채도), Value(명도)의 3가지 성분으로 색을 표현) 이미지로 변경하고 S(Saturation) 채널에 오프셋(offset)을 적용, 조금 더 이미지를 선명하게 만들어 줍니다. 이후 다시 사용하는 RGB 색상 모델로 변경을 해줍니다.

Brightness
밝기를 조절할 수도 있습니다. 주로 사용하는 RGB에서 (255,255,255)는 흰색을, (0,0,0)은 검은색을 의미합니다. 따라서 이미지는 RGB 채널에서 값을 더해주면 밝아지고, 빼주면 어두워집니다. 이를 통해 Brightness를 변경할 수 있습니다.

Rotation
Rotation은 이미지의 각도를 변환해 줍니다. 90도의 경우 직사각형 형태가 유지되기 때문에 이미지의 크기만 조절해 주면 바로 사용할 수 있습니다. 하지만 90도 단위로 돌리지 않는 경우 직사각형 형태에서 기존 이미지로 채우지 못하는 영역을 어떻게 처리해야 할지 유의해야 합니다.

Centor Crop
Center crop은 이미지의 중앙을 기주능로 확대하는 방법입니다. 너무 작게 center crop을 할 경우 본래 가진 라벨과 맞지 않게 되는 상황이 발생할 수 있으니 주의가 필요합니다. 예를 들어 고양이 라벨의 이미지를 확대해 한 장 더 만들어내려면, 이미지 내에 고양이의 형상을 유지해야 하고 털만 보이는 이미지를 만들면 안 됩니다.

정리

아래 이미지처럼 라벨은 유지한 채 다양한 이미지를 학습 데이터로 사용할 수 있습니다.

data

위에서 언급하지 않은 방법들은 아래와 같습니다.

  • Gaussian noise
  • Contrast change
  • Sharpen
  • Affine transformation
  • Padding
  • Blurring

텐서플로우를 사용한 Image Augmentation

Flip

준비하기
이미지를 PIL로 로드하고 이를 텐서로 바꾼 뒤, 기법을 적용해봅니다.
아래 이미지를 다운받아 사용합니다.
mycat.jpg

import tensorflow as tf
from PIL import image
import matplotlib.pyplot as plt
import os

sample_img_path = os.getenv('HOME')+'/aiffel/data_augmentation/images/mycat.jpg'
sample_img_path

이미지를 불러와 resize 해줍니다.

image = image.open(sample_img_path).resize((500, 400))
image_tensor = tf.keras.preprocessing.image.img_to_array(image)
image

Flip 하기

flip_lr_tensor = tf.image.flip_left_right(image_tensor)
flip_ud_tensor = tf.image.flip_up_down(image_tensor)
flip_lr_image = tf.keras.preprocessing.image.array_to_img(flip_lr_tensor)
flip_ud_image = tf.keras.preprocessing.image.array_to_img(flip_ud_tensor)

plt.figure(figsize=(12,12))
plt.title('Original image')
plt.imshow(image)

plt.subplot(1,3,2)
plt.title('flip_left_right')
plt.imshow(flip_lr_image)

plt.subplot(1,3,3)
plt.title('flip_up_down')
plt.imshow(flip_ud_image)

plt.show()

flip_result

반전이 되지 않은 원본 데이터도 활용할 수 있도록 위와 같이 flip하는 것을 확률에 따라서 적용되도록 해야 합니다.

plt.figure(figsize=(12,16))

row = 4
for i in range(row):
    flip_lr_tensor = tf.image.random_flip_left_right(image_tensor)
    flip_ud_tensor = tf.image.random_flip_up_down(image_tensor)
    flip_lr_image = tf.keras.preprocessing.image.array_to_img(flip_lr_tensor)
    flip_ud_image = tf.keras.preprocessing.image.array_to_img(flip_ud_tensor)
    
    plt.subplot(4,3,i*3+1)
    plt.title('Original image')
    plt.imshow(image)
    
    plt.subplot(4,3,i*3+2)
    plt.title('flip_left_right')
    plt.imshow(flip_lr_image)
    
    plt.subplot(4,3,i*3+3)
    plt.title('flip_up_down')
    plt.imshow(flip_ud_image)

random_flip

Centor Crop

Centor crop은 중앙을 기준으로 자른 이미지를 사용하는 augmentation 기법입니다.
central_fraction은 얼마나 확대를 할지 조절하는 매개변수입니다. 1.0인 경우 원본 이미지와 동일합니다.

plt.figure(figsize=(12,15))
central_fractions = [1.0, 0.75, 0.5, 0.25, 0.1]
col = len(central_fractions)
for i, frac in enumerate(central_fractions):
    cropped_tensor = tf.image.central_crop(image_tensor, frac)
    cropped_img = tf.keras.preprocessing.image.array_to_img(cropped_tensor)
    
    plt.subplot(1,col+1,i+1)
    plt.title(f'Center crop: {frac}')
    plt.imshow(cropped_img)

center crop

랜덤하게 centeral_crop을 적용하는 함수는 텐서플로우에서 기본적으로 제공되지 않습니다. 따라서 파이썬의 random 모듈 또는 텐서플로우의 랜덤 모듈을 사용하면 됩니다.

아래는 tf.random.uniform을 사용해서 central_fraction 매개변수에 전달할 값을 만들고 이를 사용해 cropped_tensor를 만들어내는 함수입니다.

def random_central_crop(image_tensor, range=(0, 1)):
    central_fraction = tf.random.uniform([1], minval=range[0], maxval=range[1], dtype=tf.float32)
    cropped_tensor = tensor = tf.image.central_crop(image_tensor, central_fraction)
    return cropped_tensor
    
plt.figure(figsize=(12,15))
col = 5
for i, frac in enumerate(central_fractions):
    cropped_tensor = random_central_crop(image_tensor)
    cropped_img = tf.keras.preprocessing.image.array_to_img(cropped_tensor)
    
    plt.subplot(1,col+1,i+1)
    plt.imshow(cropped_img)

텐서플로우의 tf.random 모듈에는 무작위성을 지닌 데이터를 얻을 수 있는 함수가 여러개 있으며 그중 2가지는 아래와 같습니다.

tf.random.uniform()tf.random.normal()의 차이는 랜덤 값을 uniform distribution으로 뽑는 것과 normal distribution으로 뽑는 차이입니다. normal distribution의 경우 mean, std를 통해 분포를 조절할 수 있습니다.

실습

tf.image.random_crop()

plt.figure(figsize=(12,15))
random_crop_tensor = tf.image.random_crop(image_tensor, [180,180,3])
random_crop_image = tf.keras.preprocessing.image.array_to_img(random_crop_tensor)

plt.imshow(random_crop_image)
plt.show()

tf.image.random_brightness()

# apply random_brightness on cat image
plt.figure(figsize=(12, 15))

random_bright_tensor = tf.image.random_brightness(image_tensor, max_delta=128)
random_bright_tensor = tf.clip_by_value(random_bright_tensor, 0, 255)
random_bright_image = tf.keras.preprocessing.image.array_to_img(random_bright_tensor)

plt.imshow(random_bright_image)
plt.show()

imgaug 라이브러리

imgaug 라이브러리 사용

augmentation만을 모아서 제공하는 전문 라이브러리인 imgaug를 활용해봅니다.

이미지에 augmentation을 적용할 때는 정답(ground truth 또는 gt)이 되는 데이터에도 augmentation이 동일하게 적용되어야 합니다. 아래 표에서 Image 컬럼은 각 원본 이미지들이고 Heatmaps, Seg. Maps(Segmentation Maps), Keypoints, Bounding Boxes, Polygons 컬럼은 해당 원본 데이터에 대해 각 이미지 태스크에 따른 정답 데이터입니다.

imgaug

imgaug에서는 배열을 이미지의 기본 형태로 사용합니다. 따라서 PIL Image 데이터형을 넘파이 배열로 변환하여 사용합니다.

import numpy as np
import imgaug.augmenters as iaa

image_arr = np.array(image)
image_arr.shape

augmentation 기법 사용

iaa.Affine()
imgaug.augmentersAffine()은 아핀 변환(Affine transform)을 이미지에 적용합니다. 2D 변환의 일종인 아핀 변환은 이미지의 스케일(scale)을 조절하거나 평행이동 또는 회전 등의 변환을 줄 수 있습니다.

images = [image_arr, image_arr, image_arr, image_arr]

rotate = iaa.Affine(rotate=(-25, 25))
images_aug = rotate(images=images)

plt.figure(figsize=(12,12))
plt.imshow(np.hstack(images_aug))
plt.show()

affine_transform

iaa.Crop()
텐서플로우 API가 제공하는 crop도 가능합니다.

images = [image_arr, image_arr, image_arr, image_arr]

crop = iaa.Crop(percent=(0,0.2))
images_aug = crop(images=images)

plt.figure(figsize=(12,12))
plt.imshow(np.hstack(images_aug))
plt.show()

crop

iaa.Sequential()
imgaug에서는 iaa.Sequential을 사용해서 여러 가지의 augmentation 기법을 순차적으로 적용할 수 있습니다.

images = [image_arr, image_arr, image_arr, image_arr]

rotate_crop = iaa.Sequential([
    iaa.Affine(rotate=(-25, 25)),
    iaa.Crop(percent=(0, 0.2))
])
images_aug = rotate_crop(images=images)

plt.figure(figsize=(12,12))
plt.imshow(np.hstack(images_aug))
plt.show()

Sequential

iaa.Sequential()의 augmentation 순서는 고정되어 있습니다. 이것을 random으로 기법들의 순서를 바꾸어 사용할 수 있도록 지원합니다.

images = [image_arr, image_arr, image_arr, image_arr]

rotate_crop = iaa.Sequential([
    iaa.Crop(percent=(0, 0.2)),
    iaa.Affine(rotate=(-25, 25)),
], random_order=True)
images_aug = rotate_crop(images=images)

plt.figure(figsize=(12,12))
plt.imshow(np.hstack(images_aug))
plt.show()

iaa.OneOf
iaa.OneOf()를 사용하면 여러 augmentation 기법들 중 하나를 선택하도록 할 수 있습니다.
아래에서는 gray scale로 변환하거나 saturation을 변화하는 augmentation 둘 중 하나가 적용되는 함수를 볼 수 있습니다.

images = [image_arr, image_arr, image_arr, image_arr]

seq = iaa.OneOf([
    iaa.Grayscale(slpha=(0.0, 1.0)),
    iaa.AddToSaturation((-50, 50))
])
images_aug = seq(images=images)

plt.figure(figsize=(12,12))
plt.imshow(np.hstack(images_aug))
plt.show()

iaa.Sometimes
imagu는 augmentation들이 일정 확률로 선택이 되게 하는 기능을 제공합니다. 이 기능을 사용하는 iaa.Sometimes()는 위의 iaa.OneOf()처럼 사용할 수 있는데 이를 활용해 iaa.AddToSaturation()을 0.6의 확률로, iaa.Grayscale()을 0.2의 확률로 적용하는 augmentation 함수를 구현해봅니다.

# Use iaa.SomeTimes with AddToSaturation & Grayscale
images = [image_arr, image_arr, image_arr, image_arr]

seq = iaa.Sequential([
     iaa.Sometimes(
         0.6,
         iaa.AddToSaturation((-50, 50))
     ),
     iaa.Sometimes(
         0.2,
         iaa.Grayscale(alpha=(0.0, 1.0))
     )
])
images_aug = seq(images=images)

plt.figure(figsize=(12,12))
plt.imshow(np.hstack(images_aug))
plt.show()

다양한 augmentation 기법을 활용하여 1024가지 이상의 가짓수가 조합될 수 있도록 구현해봅니다.

# Use various techniques and functions in imgaug library. Make at least 1,024 images and show 100 images.
seq = iaa.Sequential([
    iaa.OneOf([
         iaa.Grayscale(alpha=(0.0, 1.0)),
         iaa.Sometimes(
             0.5,
             iaa.AddToSaturation((-50, 50))
         )
    ]),
    iaa.Sequential([
        iaa.Crop(percent=(0, 0.2)),
        iaa.Affine(rotate=(-25, 25)),
    ], random_order=True)
])

plt.figure(figsize=(12, 40))
for i in range(20):
    images = [image_arr, image_arr, image_arr, image_arr, image_arr]
    images_aug = seq(images=images)
    plt.subplot(20,1,i+1)
    plt.imshow(np.hstack(images_aug))
    
plt.show()

그밖의 기법들

지금까지 살펴본 방식은 딥러닝이 아닌 수학적 알고리즘을 적용한 augmentation들입니다. 하지만 딥러닝을 활용한 data augmentation도 개발되고 있습니다.

대표적으로 GAN을 활용 할 수 있습니다. 쉬운 예로는 색상 변환 대신 스타일 트랜스퍼(style transfer) 모델을 적용해 볼 수 있습니다.

GAN aug

profile
임베디드와 AI를 공부하고 있습니다 :)

0개의 댓글