본문 바로가기

멀티캠퍼스 프로젝트형 AI 서비스 개발 5회차/DL

4/20 수

728x90

수요일!

 

오늘은 이미지 증식(Image Augmentation)과 전이학습(Transfer Learning)에 대해 배운다.

 

AWS 서버 켜고 PuTTY로 가상환경 열자~

(AWS GPU 사용하려면, 쿠다 적용하고 코드 쓸 때 설정 추가해야 함)

 

Over-Fitting 줄이는 방법은 많은 양의 데이터를 사용, feature의 개수를 줄임, 규제(L1, L2) 사용, Dropout 사용!

conda activate machine_TF2_18
jupyter notebook --ip=0.0.0.0 --no-browser --port=8918

 

1. 4000개의 적은 데이터로 모델링

# 일부 이미지 분리(총 4000개)
import os, shutil

original_dataset_dir = './data/cat_dog/train'

## directory 생성 ##

base_dir = 'data/cat_dog_small'
os.mkdir(base_dir)

train_dir = os.path.join(base_dir,'train')
os.mkdir(train_dir)
validation_dir = os.path.join(base_dir,'validation')
os.mkdir(validation_dir)
test_dir = os.path.join(base_dir,'test')
os.mkdir(test_dir)

train_cats_dir = os.path.join(train_dir,'cats')
os.mkdir(train_cats_dir)
train_dogs_dir = os.path.join(train_dir,'dogs')
os.mkdir(train_dogs_dir)

validation_cats_dir = os.path.join(validation_dir,'cats')
os.mkdir(validation_cats_dir)
validation_dogs_dir = os.path.join(validation_dir,'dogs')
os.mkdir(validation_dogs_dir)

test_cats_dir = os.path.join(test_dir,'cats')
os.mkdir(test_cats_dir)
test_dogs_dir = os.path.join(test_dir,'dogs')
os.mkdir(test_dogs_dir)

## file 복사 ##

fnames = ['cat.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir,fname)
    dst = os.path.join(train_cats_dir, fname)
    shutil.copyfile(src,dst)

fnames = ['cat.{}.jpg'.format(i) for i in range(1000,1500)]
for fname in fnames:
    src = os.path.join(original_dataset_dir,fname)
    dst = os.path.join(validation_cats_dir, fname)
    shutil.copyfile(src,dst)
    
fnames = ['cat.{}.jpg'.format(i) for i in range(1500,2000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir,fname)
    dst = os.path.join(test_cats_dir, fname)
    shutil.copyfile(src,dst)
    

fnames = ['dog.{}.jpg'.format(i) for i in range(1000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir,fname)
    dst = os.path.join(train_dogs_dir, fname)
    shutil.copyfile(src,dst)

fnames = ['dog.{}.jpg'.format(i) for i in range(1000,1500)]
for fname in fnames:
    src = os.path.join(original_dataset_dir,fname)
    dst = os.path.join(validation_dogs_dir, fname)
    shutil.copyfile(src,dst)
    
fnames = ['dog.{}.jpg'.format(i) for i in range(1500,2000)]
for fname in fnames:
    src = os.path.join(original_dataset_dir,fname)
    dst = os.path.join(test_dogs_dir, fname)
    shutil.copyfile(src,dst)

 

# keras가 제공하는 ImageDataGenerator
import os
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import matplotlib.pyplot as plt

train_dir = './data/cat_dog_small/train'
valid_dir = './data/cat_dog_small/validation'

# ImageDataGenerator 생성
train_datagen = ImageDataGenerator(rescale=1/255)
validation_datagen = ImageDataGenerator(rescale=1/255)

train_generator = train_datagen.flow_from_directory(
    train_dir,               # target directory
    classes=['cats','dogs'], # [0, 1]
    target_size=(150,150),   # image resize
    batch_size=20,
    class_mode='binary'
)

validation_generator = validation_datagen.flow_from_directory(
    valid_dir,               # target directory
    classes=['cats','dogs'], # [0, 1]
    target_size=(150,150),   # image resize
    batch_size=20,
    class_mode='binary'
)

 

import numpy as np
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout
from tensorflow.keras.optimizers import Adam # or RMSprop
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler

model = Sequential()

model.add(Conv2D(filters=32,
                 kernel_size=(3,3),
                 activation='relu',
                 input_shape=(150,150,3))) # color!

model.add(MaxPooling2D(pool_size=(2,2)))

model.add(Conv2D(filters=64,
                 kernel_size=(3,3),
                 activation='relu'))

model.add(Conv2D(filters=128,
                 kernel_size=(3,3),
                 activation='relu'))

model.add(MaxPooling2D(pool_size=(2,2)))

model.add(Conv2D(filters=128,
                 kernel_size=(3,3),
                 activation='relu'))

model.add(MaxPooling2D(pool_size=(2,2)))

model.add(Flatten())

model.add(Dense(units=256, activation='relu'))

model.add(Dense(units=1, activation='sigmoid'))

print(model.summary())

model.compile(optimizer=Adam(learning_rate=1e-4),
             loss='binary_crossentropy',
             metrics=['accuracy'])

history = model.fit(train_generator, # 이미지 2000개 / 20개씩 batch = 100번
                   steps_per_epoch=100,
                   epochs=30,
                   validation_data=validation_generator, # 이미지 1000개 / 20개씩 batch = 50번
                   validation_steps=50)

model.save('./data/cats_dogs_small_cnn_model.h5') # val_accuracy: 0.7090

 

# history 객체로 그래프 그려보기
import matplotlib.pyplot as plt

train_acc = history.history['accuracy']
valid_acc = history.history['val_accuracy']

train_loss = history.history['loss']
valid_loss = history.history['val_loss']

figure = plt.figure(figsize=(15,5))
ax1 = figure.add_subplot(1,2,1)
ax2 = figure.add_subplot(1,2,2)

ax1.plot(train_acc, color='r', label='train accuracy')
ax1.plot(valid_acc, color='b', label='valid accuracy')
ax1.legend()
ax1.grid()

ax2.plot(train_loss, color='r', label='train loss')
ax2.plot(valid_loss, color='b', label='valid loss')
ax2.legend()
ax2.grid()

plt.tight_layout()
plt.show()

정확도와 loss가 굉장이 안 좋다

 

2. Image Augmentation(이미지 증식)

데이터셋 자체의 양이 적다면 이를 rotation, scaling 등을 적용하여(image에 noise를 주어) 개수를 늘림

# Image Augmentation(이미지 증식)
from tensorflow.keras.preprocessing import image
from tensorflow.keras.preprocessing.image import ImageDataGenerator

# train datagen = ImageDataGenerator(rescale=1/255)
datagen = ImageDataGenerator(rotation_range=20,
                             width_shift_range=0.1,
                             height_shift_range=0.1,
                             zoom_range=0.1,
                             horizontal_flip=True,
                             vertical_flip=True,
                             fill_mode='nearest') # 보정
                             
img = image.load_img('./data/cat_dog_small/train/cats/cat.3.jpg',
                    target_size=(150,150))

x = image.img_to_array(img)
print(type(x), x.shape)

x = x.reshape((1,) + x.shape)
print(x.shape)

figure = plt.figure()
ax = []

for i in range(20):
    ax.append(figure.add_subplot(4,5,i+1))
    
idx = 0
for batch in datagen.flow(x, batch_size=1):
    ax[idx].imshow(image.array_to_img(batch[0]))
    idx += 1
    if idx == 20:
        break

plt.tight_layout()
plt.show()

# 증식을 이용해서 4000개의 이미지를 학습
import os
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import matplotlib.pyplot as plt

train_dir = './data/cat_dog_small/train'
valid_dir = './data/cat_dog_small/validation'

# ImageDataGenerator 생성
train_datagen = ImageDataGenerator(rescale=1/255,
                                   rotation_range=30, # ImageDataGenerator + Image Augmentation
                                   width_shift_range=0.1,
                                   height_shift_range=0.1,
                                   zoom_range=0.2,
                                   horizontal_flip=True,
                                   fill_mode='nearest')

validation_datagen = ImageDataGenerator(rescale=1/255)

train_generator = train_datagen.flow_from_directory(
    train_dir,               # target directory
    classes=['cats','dogs'], # [0, 1]
    target_size=(150,150),   # image resize
    batch_size=20,
    class_mode='binary'
)

validation_generator = validation_datagen.flow_from_directory(
    valid_dir,               # target directory
    classes=['cats','dogs'], # [0, 1]
    target_size=(150,150),   # image resize
    batch_size=20,
    class_mode='binary'
)

import numpy as np
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout
from tensorflow.keras.optimizers import Adam # or RMSprop
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler

model = Sequential()

model.add(Conv2D(filters=32,
                 kernel_size=(3,3),
                 activation='relu',
                 input_shape=(150,150,3))) # color!

model.add(MaxPooling2D(pool_size=(2,2)))

model.add(Conv2D(filters=64,
                 kernel_size=(3,3),
                 activation='relu'))

model.add(Conv2D(filters=128,
                 kernel_size=(3,3),
                 activation='relu'))

model.add(MaxPooling2D(pool_size=(2,2)))

model.add(Conv2D(filters=128,
                 kernel_size=(3,3),
                 activation='relu'))

model.add(MaxPooling2D(pool_size=(2,2)))

model.add(Flatten())

model.add(Dense(units=256, activation='relu'))

model.add(Dense(units=1, activation='sigmoid'))

print(model.summary())

model.compile(optimizer=Adam(learning_rate=1e-4),
             loss='binary_crossentropy',
             metrics=['accuracy'])

history = model.fit(train_generator, # 이미지 2000개 / 20개씩 batch = 100번
                   steps_per_epoch=100,
                   epochs=30,
                   validation_data=validation_generator, # 이미지 1000개 / 20개씩 batch = 50번
                   validation_steps=50)

model.save('./data/cats_dogs_small_cnn_model_augmentation.h5') # val_accuracy: 0.7560

# history 객체로 그래프 그려보기
import matplotlib.pyplot as plt

train_acc = history.history['accuracy']
valid_acc = history.history['val_accuracy']

train_loss = history.history['loss']
valid_loss = history.history['val_loss']

figure = plt.figure(figsize=(15,5))
ax1 = figure.add_subplot(1,2,1)
ax2 = figure.add_subplot(1,2,2)

ax1.plot(train_acc, color='r', label='train accuracy')
ax1.plot(valid_acc, color='b', label='valid accuracy')
ax1.legend()
ax1.grid()

ax2.plot(train_loss, color='r', label='train loss')
ax2.plot(valid_loss, color='b', label='valid loss')
ax2.legend()
ax2.grid()

plt.tight_layout()
plt.show()

 

전이학습 : 

우리는 지금까지 filter → Conv, Weights와 bias → FC layer 값들을 처음부터 학습시켜 시간이 너무 오래 걸림

 

이에 학습해야 하는 데이터를 Pretrained Network(사전 훈련된 네트워크)에 전달해서 학습 시간을 줄이고 더 좋은 filter를 이용하는 방법을 Transfer Learning(전이학습)이라 함

 

입력 데이터의 resize를 어떻게 넣으냐에 따라 Activation Map의 사이즈가 달라지므로, 이미지의 특성이 유실되지 않도록 잘 넣어야 함

 

include_top=True로 imagenet에 사용된 FC layer까지 사용해주면 당연히 label 개수가 맞지 않는다!

왜냐, 1000개를 분류하는데에 최적화된 DNN layer이기 때문~

imagenet의 FC Layer까지 모두 사용한 경우와 아닌 경우

 

 

3. 우리는 CNN의 전이학습 모델 중 VGG16(Conv layer가 16개)을 써본다!

# Transfer Learning
from tensorflow.keras.applications import VGG16

model_base = VGG16(weights='imagenet',     # imagenet 경진대회에서 사용한 W를 사용하겠다
                  include_top=False,       # imagenet을 학습시킬 때 사용했던 FC layer은 사용하지 않겠다
                  input_shape=(150,150,3)) # include_top=False이면 입력 데이터의 사이즈를 넣어줘야 함
#                    include_top=True,
#                    input_shape=(224,224,3))

print(model_base.summary())

# 개와 고양이 데이터를 VGG16에 통과시켜서 Activation Map을 만들자. ndarray 형태로 저장해야 함
import os
import numpy as np
from tensorflow.keras.preprocessing.image import ImageDataGenerator

base_dir = './data/cat_dog_small'
train_dir = os.path.join(base_dir, 'train') # ./data/cat_dog_small/train
valid_dir = os.path.join(base_dir, 'validation')
test_dir = os.path.join(base_dir, 'test')

datagen = ImageDataGenerator(rescale=1/255)

def extraction_feature(directory, sample_count):
    features = np.zeros(shape=(sample_count, 4, 4, 512)) # 4차원
    labels = np.zeros(shape=(sample_count,)) # 1차원
    
    generator = datagen.flow_from_directory(
        directory,
        classes=['cats', 'dogs'], # 각 디렉토리의 이미지 레이블 : 고양이 0, 개 1
        target_size=(150,150),
        batch_size=20,
        class_mode='binary'
    )
    
    i = 0
    
    for x_data_batch, t_data_batch in generator: # batch size(이미지 20개)에 대한 픽셀 데이터
        feature_batch = model_base.predict(x_data_batch) # 20개 이미지 특성 추출
        features[i*20:(i+1)*20] = feature_batch
        labels[i*20:(i+1)*20] = t_data_batch
        
        i = i + 1
        
        if i*20 >= sample_count:
            break
    
    return features, labels
    
train_features, train_labels = extraction_feature(train_dir, 2000)
valid_features, valid_labels = extraction_feature(valid_dir, 1000)
test_features, test_labels = extraction_feature(test_dir, 1000)

# 이 Activation Map을 이용해서 DNN 학습을 하자

train_x_data = np.reshape(train_features, (2000, 4*4*512)) # 2차원으로
train_t_data = train_labels
                          
valid_x_data = np.reshape(valid_features, (1000, 4*4*512))
valid_t_data = valid_labels

test_x_data = np.reshape(test_features, (1000, 4*4*512))
test_t_data = test_labels

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Flatten, Dense, Dropout
from tensorflow.keras.optimizers import Adam

model = Sequential()
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'))

model.compile(optimizer=Adam(learning_rate=1e-4),
             loss='binary_crossentropy',
             metrics=['accuracy'])

history = model.fit(train_x_data, train_t_data,
                   epochs=30,
                   batch_size=20,
                   validation_data=(valid_x_data, valid_t_data)) # val_accuracy: 0.9050

 

1. 4/11 월 2. 4/12 화 3. 4/13 수 4. 4/14 목 5. 4/15 금
Deep Learning
Perceptron,
Nueral Network
Deep Learning
Initialization,
ReLU,
Drop-out,
Early-Stopping
Deep Learning
Image,
CNN,
Convolution Layer,
Channel,
Filter,
Stride,
Padding,
Feature Map,
Activation Map
Deep Learning
CNN,
Feature Extraction,
Pooling
Deep Learning
CNN
6. 4/18 월 7. 4/19 화 8. 4/20 수 9. 4/21 목 10. 4/22 금
Deep Learning
Generator
Deep Learning
AWS,
Generator
Deep Learning
Image Augmentation,
Transfer Learning
Deep Learning
Transfer Learning,
Fine Tuning
Deep Learning

11. 4/25 월 4/26 화 ~ 5/19 목
Deep Learning

AI 프로젝트

* 복습과 필사!

728x90

'멀티캠퍼스 프로젝트형 AI 서비스 개발 5회차 > DL' 카테고리의 다른 글

4/22 금  (0) 2022.04.23
4/21 목  (0) 2022.04.22
4/19 화  (0) 2022.04.19
4/18 월  (0) 2022.04.18
4/15 금  (0) 2022.04.15