퐈니썬's LIfe - 잘 실패하자 RSS 태그 관리 글쓰기 방명록
2021-06-22 13:37:16
728x90
반응형

01. CIFAR-10 이미지 분류해 보기

01. ImageDataGenerator 사용해 보기

keras에서는 이미지데이터 학습을 쉽게하도록 하기위해 다양한 패키지를 제공한다. 그 중 하나가 ImageDataGenerator 클래스이다.

ImageDataGenerator 클래스를 통해 객체를 생성할 때 파라미터를 전달해주는 것을 통해 데이터의 전처리를 쉽게할 수 있고, 또 이 객체의 flow_from_directory 메소드를 활용하면 폴더 형태로된 데이터 구조를 바로 가져와서 사용할 수 있다.

이 과정은 매우 직관적이고 ImageDataGenerator를 사용하지 않는 방법에 비해 상당히 짧아진다.

ImageDataGenerator를 통해 parameter arugmentation을 하고, flow_from_directory
메소드를 사용해, 폴더를 특정 사이즈로 이미지를 불러올 수 있다. 

02. CIFAR-10 학습해 보기

학습과정은 기본적인 FLOW를 배경으로 하였다.

  • 이미지로드
  • train 과 validation 데이터 분리
  • 이미지 전처리 (정규화 포함, DATAGENERATOR, 원핫인코딩)
  • 학습모델형성
  • 학습진행
  • 학습평가 (시각화)

01. 이미지 로드

지난 시간에 subplot의 대한 사용법을 복습하고, rows: labels, columns 각 이미지로 하여,

10 x 10의 이미지를 추출해보았다. 데이터 탐색의 목적으로, 데이터 확인이 목적이다.

ex) 비행기는 비행기네,, 트럭은 트럭이네,, 등등 < 실무에 이러한 작업이 필수적>

CIFAR-10 이미지 플롯

02. train과 validation 데이터 분리

 이 과정은 추가적으로 진행하게 된 작업이다. 기본적으로 데이터가 주어지면 train set, validation set, test set으로 구분해야 한다.

 목적은 "Overfitting"!! 즉, 내가 만든 모델이 내가 제공한 train set데이터에 너무 과적합되도록 학습되어버려서 이를 조금이라도 벗어난 케이스에 대해서 예측률이 낮아지는 현상이 발생한다. 그렇기 때문에 이러한 현상을 막기 위해서 데이터를 목적에 맞도록 구분한다.

  • train set : 모델이 훈련하는 데이터셋
  • validation set : train set 학습 중간에 모델 평가에 사용되는 데이터셋 (모델 성능에 영향 줌)
  • test set : 오로지 모델의 성능 평가를 위해 사용되는 데이터셋 (모델 성능에 영향 안 줌)

 

이번 주차에서는 train set을 train을 위한 데이터셋과 validation을 위한 데이터셋으로 나누어 볼 것이다. 아주 간단하다. 왜냐하면, ImageDataGenerator과 flow_from_directory에서 쉽게 할 수 있다.

[train set, validation set] = [0.8, 0.2]로 나누어 볼 것이다.

train_datagen = ImageDataGenerator(rescale=1./255,
                                   rotation_range=15,
                                   shear_range=0.2,
                                   zoom_range=0.2,
                                   horizontal_flip=True,
                                   width_shift_range=0.1,
                                   height_shift_range=0.1,
                                   validation_split=0.2)

train_set = train_datagen.flow_from_directory('./CIFAR-10-images-master/train/',
                                              target_size=(32,32),
                                              batch_size=32,
                                              class_mode='categorical',
                                              subset='training')

val_set = train_datagen.flow_from_directory('./CIFAR-10-images-master/train/',
                                              target_size=(32,32),
                                              batch_size=32,
                                              class_mode='categorical',
                                          subset='validation')

#데이터 스플릿 확인 
size_data = [train_set.n, val_set.n]

plt.bar(range(len(size_data)), size_data)
ax = plt.subplot()
ax.set_xticks([0,1])
ax.set_xticklabels(['train set', 'validation set'])
plt.show()

 

핵심은, ImageDataGenerator로 argumentation에서 "validation_split"을 지정한 후에 (내가 원하는, 이는 이미지 전처리와 같음) 각 flow_from_directory시에 "subset"을 지정해주면 된다. 5만 장으로 구성되었던, train directory의 데이터를 학습에 4만 장, 1만 장으로 나누었다. Good!

 

데이터 분할 

03. 이미지 전처리

이미지 전처리에서는 ImageDataGenerator로 argumentation를 통해 데이터 학습을 위한 1) 데이터 가공 (정규화) 2) 데이터 뻥튀기를 통해 많은 데이터를 모델이 학습할 수 있도록 하는 역할이 있다. 생각할수록 굉장히 유용한 클래스이다.. overfitting 방지

이를 통해 두 가지를 한 번에 하는 마법 같은 경험을 하였다

 

#개수작을 좋아하는 나는 사용할 수 있는 모든 argumentation을 최대한 활용하였다. 
train_datagen = ImageDataGenerator(rescale=1./255,
                                   rotation_range=15,
                                   shear_range=0.2,
                                   zoom_range=0.2,
                                   horizontal_flip=True,
                                   width_shift_range=0.1,
                                   height_shift_range=0.1,
                                   validation_split=0.2)

rescale:정규화 위해
rotation_range = 0~15도 까지 회전하기
shear_range = 시계반대방향으로 밀림,0.2이라면, 0.2 라이안내외로 
							시계반대방향으로 변형
zoom_range = “1-수치”부터 “1+수치”사이 범위로 확대/축소,0.2이라면, 
							0.8배에서 1.2배 크기 변화를 시킴
horizontal_flip = 수평방향으로 뒤집기
width_shift_range, height_shift_range = 0.1 배율의 픽셀 만큼 이동

 

진짜 돌아가는 건지, 그러니깐 ImageDataGenerator가 구동되는지 궁금했다.

 

CIFAR10의 비행기 그림

 

airplane의 하나를 해당 조건으로 25장의 이미지로 만들어 저장하여 불러보았다.

뭐,,, 확실히 이미지의 변화가 생긴 거 같긴 하다.  ok!

 

 

ImageDataGenerator를 통해 argumentation  수행 결과

 

import numpy as np
import os
import matplotlib.pyplot as plt

from keras.preprocessing.image import ImageDataGenerator, 
array_to_img, img_to_array, load_img


train_datagen = ImageDataGenerator(rescale=1./255,
                                   rotation_range=15,
                                   shear_range=0.2,
                                   zoom_range=0.2,
                                   horizontal_flip=True,
                                   width_shift_range=0.1,
                                   height_shift_range=0.1,
                                   validation_split=0.2)


img = load_img('./CIFAR-10-images-master/train/airplane/0001.jpg')
plt.figure()
a = plt.imread(img)
plt.imshow(a)
plt.show()
x = img_to_array(img)
x = x.reshape((1,) + x.shape)

i = 0
for batch in train_datagen.flow(x, batch_size=20, 
save_to_dir='./CIFAR-10-images-master/tmp_files', save_prefix='tmp', 
save_format='jpg'):
    i += 1
    if i > 24:
        break
image_dir = './CIFAR-10-images-master/tmp_files'
plt.figure(figsize=(5,5))
images = os.listdir('./CIFAR-10-images-master/tmp_files')
for i in range(5):
    for j in range(5):
        plt.subplot(5,5,i*5 +j + 1)
        fn = image_dir+ '/' + images[i]
        image = plt.imread(fn)
        plt.grid(False)
        plt.tight_layout()
        plt.imshow(image)
plt.show()

 

04. 이미지 모델 생성 & 학습 진행 & 학습평가 (시각화)

여러 가지 모델에 대하여 생성하고, 학습하고 평가까지 한 번에 해보았다. 코드 스플릿이 필요하긴 할 듯,, 다음에..

기본적은 CNN이며 둘 차이는 layer 수와 optimizer를 두었다.

이전과 다른 것은 ImageDataGenerator로 데이터를 전처리 및 부풀렸기 때문에, model에 대하여 fit() 메서드를 사용하는 것이아니라, fit_generator() 메소드를 사용한다는 것! 중요!

 

#모델 1
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 30, 30, 32)        896       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 15, 15, 32)        0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 13, 13, 32)        9248      
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 6, 6, 32)          0         
_________________________________________________________________
flatten (Flatten)            (None, 1152)              0         
_________________________________________________________________
dense (Dense)                (None, 64)                73792     
_________________________________________________________________
dense_1 (Dense)              (None, 10)                650       
=================================================================
Total params: 84,586
Trainable params: 84,586
Non-trainable params: 0
_________________________________________________________________

#compile
optimzier = "adam"
loss function = "categorical_crossentropy"
metrics(평가) = "acc"
#fit
epoch = "30"
batch_size = "32"

 

모델#1에 대한 학습 결과

음,, validation accuracy가 70% 언저리.. 변경! 옵티마이저. Layers와 epoch를 변경!

 

#모델 2
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 30, 30, 32)        896       
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 28, 28, 32)        9248      
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 14, 14, 32)        0         
_________________________________________________________________
dropout (Dropout)            (None, 14, 14, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 12, 12, 64)        18496     
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 10, 10, 64)        36928     
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 5, 5, 64)          0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 5, 5, 64)          0         
_________________________________________________________________
flatten (Flatten)            (None, 1600)              0         
_________________________________________________________________
dense (Dense)                (None, 128)               204928    
_________________________________________________________________
dense_1 (Dense)              (None, 10)                1290      
=================================================================
Total params: 271,786
Trainable params: 271,786
Non-trainable params: 0
_________________________________________________________________

#compile
optimzier = keras.optimizers.RMSprop(lr=0.0001, decay=0.0000001)
loss function = "categorical_crossentropy"
metrics(평가) = "acc"
#fit
epoch = "40"
batch_size = "32"

모델#2에 대한 학습결과

Accuracy가 높아지지 않았지만, validation의 accuracy가 train의 accuracy보다 높다...(?)

왜지?? 이는, train set에서 과적합이 발생하지 않고, validation set에서 잘 맞추었다는 이야기로, 정확도는 낮지만 bias와 variance가 낮은 모델이라고 볼 수 있다.

 

여기서 과적합에 대한 내용을 잠시 담자면, 조금 찾아보니깐, → "validation set의 accuracy가 train set보다 낮다면, Regularization을 계산 반복해야 한다."

이 말을 이해하고자 다음 그림을 인용해보았다.

 

정규화에 대한 자료 (인용)

 

작성자는 이렇게 말한다. "overfitting 그래프(3번째)를 보면, 데이터 분포에 비해서 loss함수가 복잡해지고, smooth 하지 않다. 즉, 새로운 데이터를 넣으면 제대로 예측하지 못할 가능성이 높다."

 

2번째의 그래프의 경우 데이터 분포와 조화가 잘되어 smooth 하다, 이러한 곡선이 적절한 모델일 가능성이 높다고 한다. 이는 변동성을 낮추어야 한다고 하는데,, 잘 이해는 되지 않는다 다만 앞서 말한 것처럼 변동성을 낮추기 위해서 "Regularization" 이 필요하다고 한다.

 

그럼 해보자!

옵티 아미저는 model1과 함께 가고, epoch 늘리고 layers는 model2를 따라가는데,

Regularization을 layer마다 추가해보자! 어떻게? 케라스에서 친절히 제공한다.

  • kernel_regularizer=regularizers.l2(weight_decay) Good!
  • from keras import regularizers부터 하고 보자.
  • from keras.layers import BatchNormalization
  • layers에 padding 옵션 추가 - 레이어의 인풋과 아웃풋에 크기에 대한 것으로 "same"은 아웃풋이 원래 인풋과 동일한 길이를 갖도록 인풋을 패딩
#model3
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 32, 32, 32)        896       
_________________________________________________________________
batch_normalization (BatchNo (None, 32, 32, 32)        128       
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 32, 32, 32)        9248      
_________________________________________________________________
batch_normalization_1 (Batch (None, 32, 32, 32)        128       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 16, 16, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 16, 16, 64)        18496     
_________________________________________________________________
batch_normalization_2 (Batch (None, 16, 16, 64)        256       
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 16, 16, 64)        36928     
_________________________________________________________________
batch_normalization_3 (Batch (None, 16, 16, 64)        256       
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 8, 8, 64)          0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 8, 8, 128)         73856     
_________________________________________________________________
batch_normalization_4 (Batch (None, 8, 8, 128)         512       
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 8, 8, 128)         147584    
_________________________________________________________________
batch_normalization_5 (Batch (None, 8, 8, 128)         512       
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 4, 4, 128)         0         
_________________________________________________________________
flatten (Flatten)            (None, 2048)              0         
_________________________________________________________________
dense (Dense)                (None, 128)               262272    
_________________________________________________________________
dense_1 (Dense)              (None, 10)                1290      
=================================================================
Total params: 552,362
Trainable params: 551,466
Non-trainable params: 896
_________________________________________________________________


#compile
optimzier = "adam"
loss function = "categorical_crossentropy"
metrics(평가) = "acc"
#fit
epoch = "40"
batch_size = "32"

 

모델#3 에 대한 학습 결과

  • 모델에 대한 evaluate() 메서드를 통해 val_set의 평가 점수를 추출하고, CNN error 스코어로 정의하여 추출해보았다. "CNN Error : 20%"!!
  • 즉, Validation accuracy가 대략 80%에 도달하였다.
  • 이전에 목적한 거와 같이 Train set accuracy가 더 높다. 즉, overfitting이 발생했다는 것이고,,
  • 비록 정확도는 높았지만, bias나 variance를 가 더 생겨서 validation 학습 때는 train set의 정확도에 비해 떨어진다고 볼 수 있다. 일정 부분 과적합이 발생했다고 보인다..
  • 생각한 대로 모델이 나오진 않았지만 5% 정도 validation 정확도를 높인 것에 대해 정규화 과정의 역할을 확인할 수 있었다.
  • 다만, val loss 함수의 그래프가 많은 피크를 보인 것 또한,, 뭔가 정규화가 잘된 거 같지도 않고,,
  • 다음에는, bias와 variance를 고려하여 모델을 잘 찾아서 적용해보자..
728x90
반응형