본문 바로가기
머신러닝 딥러닝

1004 CNN 구조 정리, Fine Tuning

by 대금부는개발자 2021. 10. 4.
SMALL

 

 

 

Flatten : Feature Extraction을 통해 나온 4차원 정보를 neural network에 집어넣기 위해 2차원 변환 → 이미지 하나가 3차원으로 표현되는데(이미지 개수까지 4차원) → 개수 빼고 이미지 하나의 3차원 데이터를 1차원 변환 → 이미지 자체에 대한 정보는 1차원이고 이미지가 여러 개 있기 때문에 총 2차원 변환

 

예측값과 실제 값을 비교 → loss 값을 줄여나가요!

loss 값이 만족스럽지 않아 반복 시 weight, loss, filter 등의 parameter 등을 update 해요~!

 

Training Data Ser에 많은 양의 Data가 있어야지 학습이 잘 돼요.

하지만 우리의 데이터가 적어 overfitting이 일어나요.

→ 약간의 기법(ImageDataGenerator)을 이용해 데이터를 늘려 가요 → Image Augmentation(이미지 증식)

하지만 이렇게 해도 정확도(accuracy)가 많이 증가하지는 않아요.

또한 한번 업데이트가 될 때마다

parameter가 다 업데이트가 돼요. → 시간이 너무 오래 걸려요.

 

Pretrained Network 이용 : VGG16, VGG119, MS ResNet, Google Inception, Efficient Net, Mobile Net...

 

 

반복 지점이 조금 달라요(입력 데이터가 Feature를 뽑아낸 Training Data set) → 여기서 Filter 학습은 이뤄지지 않아요.

 

정확도가 증가해요!! 아직 overfitting에 대한 처리는 하지 않았어요.

overfitting을 방지하려면 처음 training data set을 증식해야 해요.

 

Pretrained Network을 이용해서 Feature Extraction을 학습할 때 증식(Augmentation)을 이용하려면

어떻게 해야 하나요?

 

 

이렇게 반복하면 CNN과 비슷해져서 시간이 오래 걸려요.

여기서 Filter는 완성된 Filter이기 때문에 uqdate 할 필요가 없어요!

Pretrained Network을 사용할 때는 parameter(fiter)를 동결(계산을 안 함)

증식을 안 할 때보다는 시간이 오래 걸리지만 parameter를 동결하기 때문에 시간이 줄어요.

증식 → overfitting ↓ → accuracy ↑

 

 

여기서 정확도를 더 높이려면 어떻게 해야 하나요??

→ Fine Tuning

 

 

Fine Tuning(미세조정)

 

아까는 원래 Pretrained Network이 다른 이미지를 가지고 학습할 때 filter

우리 이미지와 완전히 들어맞지는 않아요!

parameter(fiter)를 완전히 동결시키지는 말고 update가 가능한 형태로 조금 풀어주자(1~3개 정도)

→ 상위 level layer(classifire의 가까운 쪽 layer)의 필터를 동결에서 해제

 

 

Fine Tuning을 하려면 한 가지 전제가 있는데 우리의 classifier가 완전히 동결시켜 있어야 해요.

(이전 작업을 먼저 한번 한 뒤 다시 Fine Tuning 작업)

 

Fine Tunung을 하는 절차

1. pretrained Network에 우리의 classifier(Net Work)을 추가

2. pretrained Network을 동결

3. 우리의 classifier를 학습

4. pretrained Network의 상위 layer 일부를 동결에서 해제

5. 우리의 classifier를 다시 학습

 

시간이 오래 걸려요....

 

코드로 한번 알아보아요!!

 

import numpy as np

import tensorflow as tf

from tensorflow.keras.preprocessing.image import ImageDataGenerator

from tensorflow.keras.applications import VGG16 # layer 16개

from tensorflow.keras.models import Sequential

from tensorflow.keras.layers import Flatten, Dense, Dropout

from tensorflow.keras.optimizers import Adam

import matplotlib.pyplot as plt

# 지금은 ImageDataGenerator을 이용하기 때문에 train_test_split나 Minmaxscaler가 필요 없어요!

 

# 학습용 data, validation data 폴더

train_dir = '/content/drive/MyDrive/9월 30일/cat_dog_small/train'

valid_dir = '/content/drive/MyDrive/9월 30일/cat_dog_small/validation'

 

# 학습용 데이터에 대한 ImageDataGenerator를 만들어요!

train_datagen = ImageDataGenerator(rescale=1/255, # Normalization 처리

rotation_range=30,       # 회전 비율

width_shift_range=0.1,  # 10% 좌우 이동

height_shift_range=0.1, # 10% 위아래 이동

zoom_range=0.2,         #확대 축소

horizontal_flip=True,     # 좌우 뒤집기

fill_mode = 'nearest')

# validation 데이터는 증식을 사용하지 않아요

valid_datagen = ImageDataGenerator(rescale=1/255)

 

train_generator = train_datagen.flow_from_directory(

train_dir, #어디서부터 가져올 거니?

classes=['cats','dogs'],

target_size=(150,150), # 이미지 resize

# 여기서는 상관없지만 다른 pretrained Network을 사용할 때는 API를 읽어 적정 size로 사용하시는 게 좋아요!!

batch_size=20, # 한 번에 몇 개 가져올 거냐?

class_mode='binary')

 

valid_generator = valid_datagen.flow_from_directory(

valid_dir, #어디서부터 가져올 거니?

classes=['cats','dogs'],

target_size=(150,150), # 이미지 resize

# 여기서는 상관없지만 다른 pretrained Network을 사용할 때는 API를 읽어 적정 size로 사용하시는 게 좋아요!!

batch_size=20, # 한 번에 몇 개 가져올 거냐?

class_mode='binary')

 

# 데이터 준비 완료

 

# Pretrained Network

model_base = VGG16(weights='imagenet',

include_top=False, # classifier 날림

input_shape=(150,150,3))

 

# 모든 convolution layer 한방에 동결.

model_base.trainable = False # 파라미터를 변경시킬 수 있니? layer 동결!!

 

# print(model_base.summary()) # (None, 4, 4, 512)

 

model = Sequential()

 

model.add(model_base) # Pretrained Network를 붙여줘요.

 

# 특징을 가지는 image의 input shape의 (4, 4, 512)의 column의 개수를 2차원 변환

model.add(Flatten(input_shape=(4*4*512,)))

 

model.add(Dense(units=256,

activation='relu'))

 

model.add(Dropout(rate=0.5))

 

model.add(Dense(units=1,

activation='sigmoid')) # 마지막 분류작업

 

print(model.summary())

 

 

# Optimizer 설정

 

model.compile(optimizer=Adam(learning_rate=1e-5),

loss='binary_crossentropy',

metrics=['accuracy'])

 

# Learning

 

history = model.fit(train_generator,

steps_per_epoch=100,

epochs=30,

validation_data=valid_generator,

validation_steps=50,

verbose=1)

 

# loss: 0.2952 - accuracy: 0.8800 - val_loss: 0.2478 - val_accuracy: 0.9030

 

 

# 모든 layer 동결 해제

model_base.trainable = True

 

# print(model_base.summary())

 

# 이 중 상위 layer 몇 개만 동결 해제 summary에서 밑에 쪽 layer가 상위 레이어(classifier와 가깝게 있는 쪽)

# maxpooling은 filter가 없어서 의미가 없어요.

# filter가 있는 업데이트 할 convolution layer 즉 block5_conv1 ,block5_conv2, block5_conv3세게 layer만 풀어보아요!

# 상위 layer 3개만 동결에서 해제!

for layer in model_base.layers:

if layer.name in ['block5_conv1','block5_conv2','block5_conv3']:

layer.trainable = True

else:

layer.trainable = False

# 세게만 풀고 나머지는 다시 동결!

 

# 한번 더 학습!!

 

# Optimizer 설정

 

model.compile(optimizer=Adam(learning_rate=1e-5),

loss='binary_crossentropy',

metrics=['accuracy'])

 

# Learning

 

history = model.fit(train_generator,

steps_per_epoch=100,

epochs=30,

validation_data=valid_generator,

validation_steps=50,

verbose=1)

 

# loss: 0.0427 - accuracy: 0.9835 - val_loss: 0.2003 - val_accuracy: 0.9300

 

 

 

# accuracy와 loss 비교

 

train_acc = history.history['accuracy']

valid_acc = history.history['val_accuracy']

 

train_loss = history.history['loss']

valid_loss = history.history['val_loss']

 

fig = plt.figure()

fig_1 = fig.add_subplot(1,2,1)

fig_2 = fig.add_subplot(1,2,2)

 

fig_1.plot(train_acc, color='b', label='training_accuracy')

fig_1.plot(valid_acc, color='r', label='validation_accuracy')

fig_1.legend()

 

fig_2.plot(train_loss, color='b', label='training_loss')

fig_2.plot(valid_loss, color='r', label='validation_loss')

fig_2.legend()

 

plt.tight_layout()

plt.show()

 

 

 

 

 

 

# 여담으로 위에서는 안 했지만 학습을 진행 시킬 때마다 아래와 같이

early stopping이나 callback은 필수적으로 들어가는 게 좋아요!

 

from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint

 

# Early Stopping

es = EarlyStopping(monitor='val_loss',   #val_loss가 더이상 감소되지 않을 경우 EarlyStopping을 적용합니다.

                   mode='auto'# val_acc 즉 정확도일 경우, 값이 클수록 좋기때문에 "max"를 입력하고, val_loss일 경우

                                              작을수록 좋기 때문에 "min"을 입력합니다. # auto는 모델이 알아서 판단합니다.

                   verbose=1

                   patience=5)

# patience=5 epoch이 증가하면 val_loss가 감소해야 하는데 overfitting 발생 시 오히려 증가할 때 5번 참겠다.



# Checkpoint

# Checkpoint는 validation accuracy가 증가할 때마다 모델을 지속적으로 특정 폴더에 특정 파일 이름으로 저장시켜주는 역할

 

model_filename = './{epoch:06d}-{val_accuracy:0.6f}-{accuracy:0.6f}.hdf5' 

#epoch의 수-val_accuracy의 값-accuracy값을 이용해서 파일이름을 만드는것입니다. 뒤에 0.6f같은것은 소수점 6자리까지 실수로 만든다는 의미입니다. 

epoch이 돌때 마다 자동적으로 accuracy의 값이 달라지기 때문에 파일명이 자동적으로 변경되는 방식입니다.

 

 

 

checkpointer = ModelCheckpoint(

    filepath=model_filename, 

    verbose=1

    period=1,  # period : 한 epoch 마다

    save_best_only=True,

   #True인 경우, 모델의 weights만 저장됩니다. False인 경우, 모델 레이어 및 weights 모두 저장됩니다.

    mode='max', # val_acc 인 경우 max, val_loss 인 경우 min 혹은 자동으로 auto

    monitor='val_accuracy')

 # monitor : 기준이 되는 값,어떤 값을 지켜보면서 epoch를 더 돌릴지 그만할 지 결정

#validation set의 loss가 가장 작을 때 저장하고 싶으면 'val_loss'를 입력하고

#만약 train set의 loss가 가장 작을 때 모델을 저장하고 싶으면 'loss'를 입력합니다.

 

 

history = model.fit(train_generator,

                    steps_per_epoch=100,

                    epochs=30,

                    validation_data=valid_generator,

                    validation_steps=50,

                    callbacks=[es, checkpointer], 

                    # 사용방법은 history에 callback 인자를 줘요! 

                    verbose=1)

 

 

Epoch 8/30 100/100 [==============================] - 29s 291ms/step - loss: 0.0188 - accuracy: 0.9925 - val_loss: 0.2432 - val_accuracy: 0.9380 Epoch 00008: val_accuracy did not improve from 0.94100 Epoch 00008: early stopping

LIST

'머신러닝 딥러닝' 카테고리의 다른 글

0117 Random Forest  (0) 2022.01.17
0114 Decision Tree  (0) 2022.01.14
1001 Data Augmentation  (0) 2021.10.01
0930 Image generator  (0) 2021.09.30
0930 cat&dog CNN CSV파일  (0) 2021.09.30

댓글