1. Data Set

Kaggle의 개와 고양이 컬러 이미지를 아래 경로로 다운로드 받는다.

https://www.kaggle.com/tongpython/cat-and-dog

 

2. Data Argumentation

 

데이터 학습량을 늘려서 데이터가 변조되었을 때 모델이 이를 잘 캐치할 수 있도록 모델강화를 위해

데이터를 회전, 좌우반전, 이동, 역전등으로 이미지를 바꿀 것이다.

이때, 케라스에서 제공하는 이미지 제너레이터를 사용한다. 

 

tensorflow.keras.preprocessing.image에 ImageDataGenerator를 우선 로드하고

traning과 test set 폴더를 가지고 있는 cat-and-dog폴더까지 path를 지정해주자. 

 

데이터는 training set과 test set으로 나눠져 있으며 그 안에 고양이와 강아지 이미지가 각각 다른 파일에 존재한다. 

import os
from tensorflow.keras.preprocessing.image import ImageDataGenerator

rootPath = 'C:/Users/USER-PC/Documents/Kaggle_dataanalysis/cat-and-dog'

이제 ImageDataGenerator를 사용해서 이미지를 이리저리 굴려서 만들것이다. 

rescale, shear_range, zoom_range등의 옵션을 설정해줘서 해당 데이터 전처리를 하려고 한다. 

imageGenerator = ImageDataGenerator(rescale=1./255,
                                    rotation_range=20,
                                    width_shift_range=0.1,
                                    height_shift_range=0.1,
                                    brightness_range=[.2,.2],
                                    horizontal_flip=True,
                                    validation_split=.1)

rescale: 원래 이미지에 입력된 값만큼 이미지의 크기에 곱해서 조율함.

rotation_range: 지정된 각도 범위에서 임의로 원본 이미지를 회전.

width_shift_range: 지정된 수평방향 내에서 임의로 원본 이미지를 좌우로 이동.

height_shift_range: 지정된 수직방향 내에서 임의로 원본 이미지를 상하로 이동.

brightness_range: 이미지 밝기를 랜덤하게 주는 것.

horizontal_flip: 수평방향으로 뒤집기

validation_split: 주어진 데이터셋을 test와 training으로 나누는 비율.

 

*MNIST데이터를 사용할때는 손글씨이기 때문에 수평반전이 일어나면 안된다!

 

3. Data spliting

 

flow_from_directory함수를 사용해서 이미지 데이터들이 들어있는 directory 자체를 불러와서 training set과 validation set을 나눠준다. 

 

target_size option으로 읽어올 이미지의 크기를 정해주는데 우리는 64*64 사이즈로 읽어온다. 

subset은 위에서 validation_split으로 선정한 trainig과 validation의 비율만큰 이미지를 가지고 온다.

 

trainGen = imageGenerator.flow_from_directory(os.path.join(rootPath,'training_set'),
                                              target_size=(64,64),
                                              subset='training')

validationGen = imageGenerator.flow_from_directory(os.path.join(rootPath,'training_set'),
                                                  target_size=(64,64),
                                                  subset='validation')

 

4. Model setting

 

우리는 Sequential model을 사용해서 레이어를 선형으로 연결해서 구성할 것이다. 

Sequential은 첫번째레이어의 입력 형태에 대한 정보를 필요로 하지만 그 후에는 자동으로 형태를 추정하여 형태 정보를 갖고올 필요가 없다.

그리고 Add 메소드로 여러개의 레이어 추가가 가능하다.

 

우선 Sequential과 Layers를 불러온다. 

from tensorflow.keras.models import Sequential
from tensorflow.keras import layers

model = Sequential()

우리는 

Layers를 이용해 inputlayer에 우리가 읽어드려온 64*64 image 형태 정보를 준다.

Conv2D를 사용해 16개의 각각 3*3의 Convolution fiter를 적용해 줄 것이고, 

Maxpooling은 2*2사이즈로 수행 할 것이다.

Dropout할 비율을 0.3으로 정해주었다.

model.add(layers.ImputLayer(input_shape=(64,64,3)))
model.add(layers.Conv2D(16,(3,3),(1,1),'same',activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Dropout(rate=0.3))

model.add(layers.Conv2D(32, (3, 3), (1, 1), 'same', activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Dropout(rate=0.3))

model.add(layers.Conv2D(64, (3, 3), (1, 1), 'same', activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Dropout(rate=0.3))

 

컨볼루션이나 맥스풀링을 하면서 주요특징이 추출되고 이런 작업은 이차원에서 진행이 되지만 

fullyconnected layer로 넘겨주기 위해서는 2차원 자료를 1차원자료로 변환하는 작업이 필요한데, 이 때 사용하는 것이 flatten()이다. 

Dense로 512개의 유닛을 가진 fully connected layer를 모델에 추가하고 , 256개의 fully connected layer를 또 하나 추가한다. 2개의 출력 유닛을 가진 sigmoid 층을 연결한다. 

model.add(layers.Flatten())
model.add(layers.Dense(512, activation='relu'))
model.add(layers.Dense(256, activation='relu'))
model.add(layers.Dense(2, activation='sigmoid'))

model.summary()

이미지 데이터 1차원으로 압축

5. Trainig Process

 

model의 compile함수를 사용해서 실제 학습을 시킬 것이다.

optimizeradam을 사용할 것이다.

 

머신러닝 딥러닝에서 흔히 사용하는 optimizer는 SGD, Momentum, NAG, Adagrad, RMSprop, Adam 등 여러가지가 있는데 우리는 Adam을 사용 할 것이다. 

---------------------------------------------------------------------------

Adam?

Adam은 Momentum과 RMSprop를 합친 경사하강법이다.

---------------------------------------------------------------------------

우리는 개와 고양이의 문제인 이분법이기 때문에 loss함수를 binary_crossentropy로 설정해주었다. 

 

Metric은 학습 평가 기준을 말한다. 

우리가 흔하게 아는 'accuracy'로 설정한 경우, 클래스분류 문제에서 categorical_accuracy()함수를 사용해서 정확도를 계산한다. 또한, 사용자 정의 매트릭을 만들어서 사용할 수도 있다. 

사용자 정의 매트릭스를 사용하기 위해서는 아래의 링크를 참고하면 좋을 것이다.

https://tykimos.github.io/2017/09/24/Custom_Metric/

 

클래스별로 학습과정 살펴보기

fit() 함수 로그에는 기본적으로 손실값과 정확도가 표시됩니다. 이진분류 모델에서는 정확도값 하나만 보더라도 학습이 제대로 되고 있는 지 알 수 있지만, 다중클래스분류 문제에서는 클래스별로 학습이 제대로 되고 있는 지 확인하기 위해서는 정확도값 하나로는 부족함이 많습니다. 이진분류 문제에서 클래스간 불균형이 있을 경우에도 정확도값 하나로는 판단할 수가 없습니다. 본 장에서는 학습 중에 클래스별로 정밀도(precision)와 재현율(recall)을 살펴볼

tykimos.github.io

다시 정리해보면 optimizer는 adam, loss는 binary_crossentropy, metrics는 'acc'를 코드에 반영할 것이다. 

model.compile(
    optimizer='adam',
    loss='binary_crossentropy', 
    metrics=['acc'],
)

케라스에서 모델을 학습시킬때는 fit()함수를 사용하는데, 제너레이터로 생성된 배치학습을 시킬 경우, fit_generator()를 사용한다. 

우선 training시킬 데이터를 넣어주고, epoch을 이용해 전체 훈련 데이터셋의 학습 반복 횟수를 지정한다.

steps_per_epoch을 이용해 한 epoch에 사용한 스텝수를 지정한다. 

validation_data에 만들어진 검증데이터셋 제너레이터를 넣어주고,

validation_steps를 이용해 epoch종료 때마다 검증 스텝수를 지정한다. 

epochs = 32
history = model.fit_generator(
    trainGen, 
    epochs=epochs,
    steps_per_epoch=trainGen.samples / epochs, 
    validation_data=validationGen,
    validation_steps=trainGen.samples / epochs,
)

 

6. Visualization and estimation the result

 

Keras에는 모델 학습 시 fit()함수를 많이 사용한다고 언급했습니다. 이 때, 리턴갑으로 학습 이력 정보를 리턴할 수 있다. 

각 epoch마다 loss(훈련 손실값), acc(훈련 정확도), val_loss(검증 손실값), val_acc(검증 정확도)들이 저장되어 있다. 

 

각 loss, acc, val_loss, val_acc를 불러와서 epoch별로 loss와 val_loss의 경향, acc와 val_acc의 경향을 알아보고자한다.

import matplotlib.pyplot as plt

def show_graph(history_dict):
    accuracy = history_dict['acc']
    val_accuracy = history_dict['val_acc']
    loss = history_dict['loss']
    val_loss = history_dict['val_loss']

    epochs = range(1, len(loss) + 1)
    
    plt.figure(figsize=(16, 1))
    
    plt.subplot(121)
    plt.subplots_adjust(top=2)
    plt.plot(epochs, accuracy, 'ro', label='Training accuracy')
    plt.plot(epochs, val_accuracy, 'r', label='Validation accuracy')
    plt.title('Trainging and validation accuracy and loss')
    plt.xlabel('Epochs')
    plt.ylabel('Accuracy and Loss')

    plt.legend(loc='upper center', bbox_to_anchor=(0.5, -0.1),
              fancybox=True, shadow=True, ncol=5)
#     plt.legend(bbox_to_anchor=(1, -0.1))

    plt.subplot(122)
    plt.plot(epochs, loss, 'bo', label='Training loss')
    plt.plot(epochs, val_loss, 'b', label='Validation loss')
    plt.title('Training and validation loss')
    plt.xlabel('Epochs')
    plt.ylabel('Loss')
    plt.legend(loc='upper center', bbox_to_anchor=(0.5, -0.1),
          fancybox=True, shadow=True, ncol=5)
#     plt.legend(bbox_to_anchor=(1, 0))

    plt.show()
show_graph(history.history)

 

 

test set도 generator를 이용해서 gestGenerator를 만든다. 이전에 trainig data를 1/255로 rescale해주었기 때문에, 

test set도 똑같이 rescale해준다. 하지만 다른 이미지 조정은 해주지 않는다. 

testGenerator = ImageDataGenerator(
    rescale=1./255
)

testGen = imageGenerator.flow_from_directory(
    os.path.join(rootPath, 'test_set'),
    target_size=(64, 64),
)

model.evaluate_generator(testGen)

7. Prediction

 

이제 모델로 예측을 해보려고 한다. 

class는 '고양이'와 '개' binary이다. 

from tensorflow.keras.preprocessing.image import array_to_img
import numpy as np

cls_index = ['고양이', '개']

imgs = testGen.next()
arr = imgs[0][0]
img = array_to_img(arr).resize((128, 128))
plt.imshow(img)
result = model.predict_classes(arr.reshape(1, 64, 64, 3))
print('예측: {}'.format(cls_index[result[0]]))
print('정답: {}'.format(cls_index[np.argmax(imgs[1][0])]))

 

요약

1. trainig 과 validation, test data로 분류

2. 새로운 이미지가 들어와도 학습할 수 있도록 image argumentation 수행 (이미지 좌우반전, 회전, 이동, 밝기조절 등 tensorflow.keras.imagegenerator 이용해서)

3. sequential과 layer를 이용해, input layer를 주고 convolutional layer 사이즈 입력, maxpooling 사이즈 입력, drop out 비율 입력

4. fullyconnected layer로 연결하기 전에 2차원으로 나온 특성을 1차원으로 압축

5. 가장 많이 사용되는 adam을 이용해 최적화 진행

6. 테스트

 

옵티마이저에 대한 적절하고 쉬운 설명: 

https://needjarvis.tistory.com/685

'데이터분석 > 딥러닝' 카테고리의 다른 글

GAN 모델이란?  (2) 2021.04.06
MNIST를 이용해 간단한 CNN만들기  (2) 2020.02.12
배치학습 vs 온라인학습  (0) 2020.02.12

+ Recent posts