수요일!
오늘은 이미지 증식(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()

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이기 때문~

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 |