Data Analysis & ML/Deep Learning

[Deep Learning][딥러닝] CNN Image Augmentation(이미지 증식)

YSY^ 2021. 1. 24. 15:37

적은 datasets에 CNN 학습하는 경우

  • Data의 수가 많지 않을 때 CNN을 통한 모형 학습이 어려울 수 있음
    • 딥러닝은 많은 수의 데이터를 통해 feature engineering 과정 없이 feature를 찾을 수 있는데 있음
    • 하지만 모델이 작고 regularization이 잘 되어 있다면 수백 개의 샘플로도 훈련 가능
  • Data가 많지 않아 CNN 학습에 어려움이 있을 때 사용 가능한 방법
    • Data augmentation 활용
      • 이미지의 색깔, 각도 등을 약간씩 변형하여 data의 수를 늘림
    • Pre-trained network의 활용
      • ImageNet 등에서 학습된 기존의 모형과 weight를 불러온 후 목적에 맞게 약간 수정하여 모형 생성

Data for cats vs. dogs

  • 2013년 Kaggle의 computer vision competition data 활용 https://www.kaggle.com/c/dogs-vs-cats/data
  • 개와 고양이를 구분하기 위한 문제로 각 12,500개의 이미지를 포함
  • Medium-resolution color JPEGs
  • 25000장의 사진 중 4000장의 cats/dogs 사진(2000 cats, 2000 dogs) 만을 사용하여 학습하여 좋은 모형을 만들어 낼 수 있을까?
    • 학습: 2000, 검증: 1000, 테스트: 1000
# 이미지 다운로드
import gdown
url = 'https://drive.google.com/uc?id=1nBE3N2cXQGwD8JaD0JZ2LmFD-n3D5hVU'
fname = 'cats_and_dogs_small.zip'
gdown.download(url, fname, quiet=False)
#패키지 다운로드 및 데이터 압축 풀기
!mkdir data
!pip install zipfile

## 압축 풀기
!unzip -q ./cats_and_dogs_small.zip -d data/cats_and_dogs_small
  • Input: 150 X150 픽셀의 RGB layer
  • Output: cat or dog (binary classification)
  • Hidden layers: Conv2D(with relu activation) + MaxPooling2D
import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers as layers
import numpy as np
np.random.seed(1)
tf.random.set_seed(1)

learning_rate = 0.001
dropout_rate = 0.5
N_EPOCHS = 50
N_BATCH=20

# 모델 정의
def create_model():
    model = keras.Sequential()
    # Feature Extraction(특성 추출-이미지의 특징을 추출하는 layer들.)
    #Conv2D - kernel_size: 3, padding='SAME', stride=1(기본값)
    #MaxPool2D - pool_size: 2(기본), padding='SAME'
    model.add(layers.Conv2D(64, kernel_size=3, padding="SAME", activation='relu', 
                            input_shape=(150,150,3)))
    model.add(layers.MaxPool2D(padding='SAME'))

    model.add(layers.Conv2D(64, kernel_size=3, padding="SAME", activation='relu'))
    model.add(layers.MaxPool2D(padding='SAME'))

    model.add(layers.Conv2D(128, kernel_size=3, padding="SAME", activation='relu'))
    model.add(layers.MaxPool2D(padding='SAME'))

    model.add(layers.Conv2D(128, kernel_size=3, padding="SAME", activation='relu'))
    model.add(layers.MaxPool2D(padding='SAME'))

    # classification layer (분류 - Dense)
    model.add(layers.Flatten())
    model.add(layers.Dropout(dropout_rate))
    model.add(layers.Dense(512, activation='relu'))
    # model.add(layers.Dropout(dropout_rate))
    #출력
    model.add(layers.Dense(1, activation='sigmoid')) #이진분류-unit수:1, 활성함수:sigmoid

    return model

 

Data preprocessing(데이터전처리)

  • CNN 입력을 위한 이미지 전처리 단계

    • 사진 파일 읽기
    • JPEG content를 RGB 픽셀 값으로 디코딩
    • floating point tensor 형태로 변환
    • 0-255 사이의 값을 가지는 픽셀 값을 [0,1] 사이 값으로 변환
  • keras.preprocessing.image.ImageDataGenerator를 사용하여 자동으로 입력 가능한 형태로 변환할 수 있음

Keras의 ImageDataGenerator 클래스

  • 학습을 위해 이미지에 임의의 변형을 적용
  • 변형된 이미지를 배치 단위로 생성하여 모형 학습시 사용하기 위한 generator를 생성
  • 데이터 전체가 순환되어 배치 생성을 끝없이 함
  • flow_from_directory(directory) 메소드
    • 이미지가 특정 폴더 안에 분류 되어 있을 경우 subdirectory의 이름으로부터 target class를 자동으로 만들어냄
# train, validation, test 이미지가 들어있는 폴더 경로를 지정
train_dir = './data/cats_and_dogs_small/train'
validation_dir = './data/cats_and_dogs_small/validation'
test_dir = './data/cats_and_dogs_small/test'
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import matplotlib.pyplot as plt

# ImageDataGenerator 생성 - 각 pixel 을 0 ~ 1 사이로 범위 조정(scaling)
train_datagen = ImageDataGenerator(rescale=1/255) #각 픽셀에 1/255를 곱한다.
test_datagen =  ImageDataGenerator(rescale=1/255) #각 픽셀에 1/255를 곱한다.
# 이미지와 연결 -> generator를 생성
# Train Set
train_generator = train_datagen.flow_from_directory(
                                    train_dir, #이미지가 분류 되있는 디렉토리.
                                    target_size=(150,150), #이미지들을 150 X 150으로 resizing
                                    class_mode='binary', # output 클래스 형태
                                    batch_size=N_BATCH   #미니배치 사이즈
                                )
# Validation Set
validation_generator = test_datagen.flow_from_directory(
                                    validation_dir, #이미지가 분류 되있는 디렉토리.
                                    target_size=(150,150), #이미지들을 150 X 150으로 resizing
                                    class_mode='binary', # output 클래스 형태
                                    batch_size=N_BATCH   #미니배치 사이즈
                                )
# Test Set
test_generator = test_datagen.flow_from_directory(
                                    test_dir, #이미지가 분류 되있는 디렉토리.
                                    target_size=(150,150), #이미지들을 150 X 150으로 resizing
                                    class_mode='binary', # output 클래스 형태
                                    batch_size=N_BATCH   #미니배치 사이즈
                                )
# label의 클래스들을 확인
train_generator.class_indices # {'cats': 0, 'dogs': 1}

# step 수 (에폭당 몇번 weight 업데이트 할것인지)
len(train_generator), len(validation_generator), len(test_generator) # (100, 50, 50)

# 배치개수 만큼 이미지 조회
batch = train_generator.next() #2

len(batch), type(batch) #(2, tuple)

type(batch[0]), batch[0].shape # (numpy.ndarray, (20, 150, 150, 3))
# 이미지 확인
plt.figure(figsize=(10,10))
for i in range(4):
    plt.subplot(2,2,i+1)
    plt.imshow(batch[0][i])
plt.show()   

 

 

Batch Generator를 이용한 Model Training(학습)

  • 모델 훈련(학습)

    • 모델.fit() 메소드

    • 주요 매개변수

      • fit() 에 훈련데이터 셋으로 첫번째 매개변수에 Batch generator(train_generator) 제공

        • Batch generator가 input 데이터와 output 라벨(label)을 제공한다.
      • steps_per_epoch

        • 한 epoch(전체 데이터셋학습)당 몇 step(파라미터 업데이트) 횟수 지정
        • len(train_generator) 를 지정.
      • validation_data

        • 검증 데이터셋 지정
        • Batch generator 지정
        • (x_val, y_val)과 같이 tuple 형태의 validation data를 지정할 수도 있음
      • validation_steps

        • 몇 step마다 검증 할 것인지 지정.
        • len(validation_generator) 를 지정
          • validation data 개수를 batch_size로 나눈 값으로 지정
# 모델 생성, 컴파일
model = create_model()
model.compile(optimizer=keras.optimizers.Adam(learning_rate),
              loss='binary_crossentropy',  #개, 고양이 분류이니 이진분류
              metrics=['accuracy'])

# 학습
histroy= model.fit(train_generator, #학습 데이터셋으로 Data(Batch) Generator 지정
                    epochs=N_EPOCHS,
                    steps_per_epoch=len(train_generator),
                    validation_data=validation_generator, #검증 데이터셋-Data Generator를 지정
                    validation_steps = len(validation_generator)
                    ) #verbose = 0을 지정하면 학습내용을 보지 않을 수 있습니다.

model.evaluate(test_generator) #data generator 
#  loss: 1.4930 - accuracy: 0.7220

 

Data augmentation (데이터 증식)

  • 학습 이미지의 수가 적어서 overfitting이 발생할 가능성을 줄이기 위해 기존 훈련 데이터로부터 그럴듯한 이미지를 랜덤하게 생성하여 데이터의 수를 늘리는 data augmentation 적용

    • rotation_range: random rotation 각도 범위(0-180)
    • width_shift_range,height_shift_range`: 수평 혹은 수직 이동 범위(비율)
    • shear_range: 기울어지는 변환(shearing transformation)의 각도 범위(반시계방향)
    • zoom_range: 확대 비율([lower, upper] = [1-zoom_range, 1+zoom_range])
    • horizontal_flip: 수평으로 뒤집음(mirror image)
    • fill_mode: 변환된 이미지에서 생기는 빈 부분을 채우는 방법
  • 이미지 변환을 통해서 이미지를 늘리는 작업(Image augmentation)

  • train_set에만 적용, validation, test set에는 적용하지 않는다. (rescaling만 한다.)

train_gen = ImageDataGenerator(
    rescale = 1/255,
    rotation_range= 40,
    width_shift_range=0.2, #[-0.2, 0, +0.2]  ex)[-1, -0.5, 0, 0.5, 1]
    height_shift_range=0.2,
    shear_range=0.2, #찌그리는 형태
    zoom_range=0.2,
    horizontal_flip=True
)

test_gen = ImageDataGenerator(rescale=1/255) #validation/test set 용(rescale만 진행)
train_generator = train_gen.flow_from_directory(train_dir,
                                                target_size=(150,150),
                                                class_mode='binary',
                                                batch_size=N_BATCH)

validation_generator = test_gen.flow_from_directory(validation_dir,
                                                target_size=(150,150),
                                                class_mode='binary',
                                                batch_size=N_BATCH)

test_generator = test_gen.flow_from_directory(test_dir,
                                                target_size=(150,150),
                                                class_mode='binary',
                                                batch_size=N_BATCH)
model.evaluate(train_generator) # loss: 0.6930 - accuracy: 0.5000
# 확인
import os
from tensorflow.keras.preprocessing.image import load_img, img_to_array

image_path = os.path.join(train_dir, 'dogs', 'dog.0.jpg')
print(image_path)

img = load_img(image_path)
img

 

x = img_to_array(img)
x = x[np.newaxis, ...]
x.shape #(1, 375, 499, 3)
train_gen2 = ImageDataGenerator(
    # rescale = 1/255,
    rotation_range= 40,
    width_shift_range=0.2, #[-0.2, 0, +0.2]  ex)[-1, -0.5, 0, 0.5, 1]
    height_shift_range=0.2,
    shear_range=0.2, #찌그리는 형태
    zoom_range=0.2,
    horizontal_flip=True
)
gen = train_gen2.flow(x, batch_size=1) #Data Generator생성
plt.figure(figsize=(10,10))
for i in range(5):
    plt.subplot(5, 1, i+1)
    batch = gen.next()
    img = batch[0].astype('uint8')
    plt.imshow(img)
plt.show()

,하나의 이미지가 여러개의 이미지로 증식되었다

# 모델 생성 및 컴파일
model = create_model()
model.compile(optimizer=keras.optimizers.Adam(learning_rate),
              loss='binary_crossentropy',
              metrics=['accuracy'])

model.summary()

 

#학습
history=model.fit(train_generator,
                epochs=N_EPOCHS,
                steps_per_epoch=len(train_generator),
                validation_data = validation_generator,
                validation_steps=len(validation_generator))
model.evaluate(test_generator) #loss: 0.5078 - accuracy: 0.7590

loss가 대폭줄었고 정확도도 소폭 올라간 것을 볼 수 있다.

728x90
반응형