# Day_25_01_DogsAndCats.py
import tensorflow as tf
import numpy as np
import os
import time
import pickle
import matplotlib.pyplot as plt
from tensorflow.keras import optimizers
from tensorflow.keras.preprocessing.image import ImageDataGenerator as IDG
# 베이스 라인 만들 것임
# 이미지 증식 후 분석
# slim 에서 본거 같이 사전학습된 것으로 우리꺼 예측해볼 것 (전이 학습)
def get_model_name(version):
filename = 'dogcat_small_{}.h5'.format(version) # h5 keras에서 사용하는 확장자
return os.path.join('dogs_and_cats_model', filename)
def get_history_name(version):
filename = 'dogcat_small_{}.history'.format(version) # h5 keras에서 사용하는 확장자
return os.path.join('dogs_and_cats_model', filename)
def show_history(history, version):
plt.subplot(1, 2, 1) # 2개로 나눠서 쓸거임
plt.plot(history['loss'], 'r', label='train')
plt.plot(history['val_loss'], 'g', label='valid')
plt.title('loss {}'.format(version))
plt.legend()
plt.subplot(1, 2, 2) # acc
plt.plot(history['acc'], 'r', label='train')
plt.plot(history['val_acc'], 'g', label='valid')
plt.title('acc {}'.format(version))
plt.legend()
plt.show()
def save_history(history, version):
with open(get_history_name(version), 'wb') as f: # 쓰기 모드로 파일 염
pickle.dump(history.history, f) # history 에 접근
def load_history(version):
with open(get_history_name(version), 'rb') as f: # 쓰기 모드로 파일 염
history = pickle.load(f) # history 에 접근
show_history(history, version)
def load_model(version):
model = tf.keras.models.load_model(get_model_name(version))
# model.summary()
test_gen = IDG(rescale=1/255)
test_flow = test_gen.flow_from_directory(
'dogs_and_cats/small/test',
batch_size=1000, # 검사 데이터 전체
target_size=(150, 150), # resize 기능을 제공해줌
class_mode='binary' # sigmoid 어울리는 모드로 변환
)
# print('acc :', model.evaluate_generator(test_flow, steps=1, verbose=0))
x_test, y_test = test_flow.next()
print('acc :', model.evaluate(x_test, y_test, verbose=0))
def model_1_baseline():
# 이미지 만들어내는 함수
# 이미지를 만들어냄 방법만 알고 있고 소스를 다시 연결해줘야함
data_gen = IDG(rescale=1/255)
batch_size = 32
# 3가지 방법 -> (x,y), pandas, 폴더에 있는것
# 우리 폴더 안에 있는 25000개의 데이터를 무제한으로 가져옴 -> 조심해야함
train_flow = data_gen.flow_from_directory(
'dogs_and_cats/small/train',
batch_size=batch_size,
target_size=(150, 150), # resize 기능을 제공해줌
class_mode='binary' # sigmoid 어울리는 모드로 변환
)
# class_mode "categorical", "binary", "sparse"
valid_flow = data_gen.flow_from_directory(
'dogs_and_cats/small/train',
batch_size=batch_size,
target_size=(150, 150), # resize 기능을 제공해줌
class_mode='binary' # sigmoid 어울리는 모드로 변환
)
# 여기까지 x, y 만든셈임
model = tf.keras.Sequential()
model.add(tf.keras.layers.Input(shape=[150, 150, 3])) # 224 써도 되지만 하드웨어 문제 -> 150만 쓰자
model.add(tf.keras.layers.Conv2D(32, [3, 3], activation='relu'))
model.add(tf.keras.layers.MaxPool2D([2, 2]))
model.add(tf.keras.layers.Conv2D(64, [3, 3], activation='relu'))
model.add(tf.keras.layers.MaxPool2D([2, 2]))
model.add(tf.keras.layers.Conv2D(128, [3, 3], activation='relu'))
model.add(tf.keras.layers.MaxPool2D([2, 2]))
model.add(tf.keras.layers.Conv2D(128, [3, 3], activation='relu'))
model.add(tf.keras.layers.MaxPool2D([2, 2]))
# 3차원에서 2차원
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(512, activation='relu'))
model.add(tf.keras.layers.Dense(1, activation='sigmoid'))
model.compile(optimizer=tf.keras.optimizers.RMSprop(0.0001),
loss=tf.keras.losses.binary_crossentropy,
metrics=['acc'])
history = model.fit_generator(
train_flow,
epochs=10,
steps_per_epoch=2000 // batch_size, # 정확하게 나눠 떨어지지 않으면 자투리는 사용하지 않겠다
validation_data=valid_flow,
# validation_steps=batch_size,
verbose=2,
)
model.save(get_model_name(version=1))
save_history(history, version=1)
def model_2_augmentation():
# 이미지 만들어내는 함수
# 이미지를 만들어냄 방법만 알고 있고 소스를 다시 연결해줘야함
# featurewise_center=False,
# samplewise_center=False,
# featurewise_std_normalization=False,
# samplewise_std_normalization=False,
# zca_whitening=False, # 공부해보기 이미지 preprocessing 할 때 씀
# zca_epsilon=1e-6,
# rotation_range=0,
# width_shift_range=0.,
# height_shift_range=0.,
# brightness_range=None,
# shear_range=0.,
# zoom_range=0.,
# channel_shift_range=0.,
# fill_mode='nearest',
# cval=0.,
# horizontal_flip=False,
# vertical_flip=False,
# rescale=None,
# preprocessing_function=None,
# data_format=None,
# validation_split=0.0,
# dtype=None):
train_gen = IDG( # 이미지 다양하게 증식
rescale=1/255,
horizontal_flip=True, # 수직뒤집기, 수평뒤집기중 수집 뒤집기 사용할 것임
width_shift_range=0.1, # 10% 로 이동가능하다.
height_shift_range=0.1,
shear_range=0.1, # 이미지 변형
zoom_range=0.1,
rotation_range=20,
)
valid_gen = IDG(
rescale=1/255
)
# 이미지 증식의 이유 -> 다양한 데이터로 학습하기 위해 -> 검색은 데이터 증식할 필요 없다.
# 그렇기 때문에 2개로 generation 나눔
batch_size = 32
# 3가지 방법 -> (x,y), pandas, 폴더에 있는것
# 우리 폴더 안에 있는 25000개의 데이터를 무제한으로 가져옴 -> 조심해야함
train_flow = train_gen.flow_from_directory(
'dogs_and_cats/small/train',
batch_size=batch_size,
target_size=(150, 150), # resize 기능을 제공해줌
class_mode='binary' # sigmoid 어울리는 모드로 변환
)
# class_mode "categorical", "binary", "sparse"
valid_flow = valid_gen.flow_from_directory(
'dogs_and_cats/small/train',
batch_size=batch_size,
target_size=(150, 150), # resize 기능을 제공해줌
class_mode='binary' # sigmoid 어울리는 모드로 변환
)
# 여기까지 x, y 만든셈임
model = tf.keras.Sequential()
model.add(tf.keras.layers.Input(shape=[150, 150, 3])) # 224 써도 되지만 하드웨어 문제 -> 150만 쓰자
model.add(tf.keras.layers.Conv2D(32, [3, 3], activation='relu'))
model.add(tf.keras.layers.MaxPool2D([2, 2]))
model.add(tf.keras.layers.Conv2D(64, [3, 3], activation='relu'))
model.add(tf.keras.layers.MaxPool2D([2, 2]))
model.add(tf.keras.layers.Conv2D(128, [3, 3], activation='relu'))
model.add(tf.keras.layers.MaxPool2D([2, 2]))
model.add(tf.keras.layers.Conv2D(128, [3, 3], activation='relu'))
model.add(tf.keras.layers.MaxPool2D([2, 2]))
# 3차원에서 2차원
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(512, activation='relu'))
model.add(tf.keras.layers.Dense(1, activation='sigmoid'))
model.compile(optimizer=tf.keras.optimizers.RMSprop(0.0001),
loss=tf.keras.losses.binary_crossentropy,
metrics=['acc'])
history = model.fit_generator(
train_flow,
epochs=10,
steps_per_epoch=2000 // batch_size, # 정확하게 나눠 떨어지지 않으면 자투리는 사용하지 않겠다
validation_data=valid_flow,
# validation_steps=batch_size,
verbose=2,
)
# model.fit()
model.save(get_model_name(version=2))
save_history(history, version=2)
# 이미 학습해서 만들어놓음
def model_3_pretrained():
def extract_features(conv_base, data_gen, directory, sample_count, batch_size):
x = np.zeros([sample_count, 4, 4, 512])
y = np.zeros([sample_count])
flow = data_gen.flow_from_directory(
directory,
target_size=(150, 150),
batch_size=batch_size,
class_mode='binary'
)
# feature 생성
for ii, (xx, yy) in enumerate(flow):
n1 = ii * batch_size
n2 = n1 + batch_size
# 32로 나눴을 때 자투리가 있음 마지막 자투리를 x, y에 추가하는 코드를 구현해보자
if n2 > sample_count:
remained = sample_count - n1
x[n1:n2] = conv_base.predict(xx[:remained])
y[n1:n2] = yy
break
# feature 생성 핵심 코드
x[n1:n2] = conv_base.predict(xx) # feature 예측과 추출은 동일한 것이기 때문에
y[n1:n2] = yy
# x를 2차원으로 변환을 함
return x.reshape(-1, 4 * 4 * 512), y
# 마지막 dense layer 1000으로 고정되어 있으서 내가 수정해줘야함
conv_base = tf.keras.applications.VGG16(
include_top=False, # dense layer 가져오지 않는다.
input_shape=[150, 150, 3]
)
# conv 5블록 가져옴 -> 어디에 사용?? Feature 추출할 때 사용
conv_base.summary() # Total params: 14,714,688
batch_size = 32
data_gen = IDG(rescale=1/255)
# feature을 생성하는데 이미지 증식하지 않겠다. ->피처는 이미지 원본을 증식한 후에 피처를 만드는 것임
x_train, y_train = extract_features(conv_base, data_gen, 'dogs_and_cats/small/train', 2000, batch_size)
x_valid, y_valid = extract_features(conv_base, data_gen, 'dogs_and_cats/small/validation', 1000, batch_size)
x_test, y_test = extract_features(conv_base, data_gen, 'dogs_and_cats/small/test', 1000, batch_size)
model = tf.keras.Sequential()
model.add(tf.keras.layers.Input(shape=[4 * 4 * 512])) # x_train 이 2차원이기 때문에 이렇게 사용
# ------------------------------ #
# 이미 피처를 만들었기 때문에 해줄 필요 없음
# model.add(tf.keras.layers.Conv2D(32, [3, 3], activation='relu'))
# model.add(tf.keras.layers.MaxPool2D([2, 2]))
# model.add(tf.keras.layers.Conv2D(64, [3, 3], activation='relu'))
# model.add(tf.keras.layers.MaxPool2D([2, 2]))
# model.add(tf.keras.layers.Conv2D(128, [3, 3], activation='relu'))
# model.add(tf.keras.layers.MaxPool2D([2, 2]))
# model.add(tf.keras.layers.Conv2D(128, [3, 3], activation='relu'))
# model.add(tf.keras.layers.MaxPool2D([2, 2]))
# ------------------------------ #
model.add(tf.keras.layers.Dense(512, activation='relu'))
model.add(tf.keras.layers.Dense(1, activation='sigmoid'))
model.compile(optimizer=tf.keras.optimizers.RMSprop(0.0001),
loss=tf.keras.losses.binary_crossentropy,
metrics=['acc'])
history = model.fit(
x_train, y_train,
epochs=1, batch_size=batch_size,
verbose=2, validation_data=(x_valid, y_valid)
)
# 모델을 저장하긴 하지만 다른 모델가 호환이 안되기 때문에 의미는 없음( 입력 모양이 다름 )
model.save(get_model_name(version=3))
save_history(history, version=3)
print('acc :', model.evaluate(x_test, y_test)) # load 모델을 이용해서 출력이 안됨
def model_4_pretrained_augmentation():
train_gen = IDG(
rescale=1 / 255,
horizontal_flip=True, # 수직뒤집기, 수평뒤집기중 수집 뒤집기 사용할 것임
width_shift_range=0.1, # 10% 로 이동가능하다.
height_shift_range=0.1,
shear_range=0.1, # 이미지 변형
zoom_range=0.1,
rotation_range=20,
)
valid_gen = IDG(
rescale=1 / 255
)
# 이미지 증식의 이유 -> 다양한 데이터로 학습하기 위해 -> 검색은 데이터 증식할 필요 없다.
# 그렇기 때문에 2개로 generation 나눔
batch_size = 32
# 3가지 방법 -> (x,y), pandas, 폴더에 있는것
# 우리 폴더 안에 있는 25000개의 데이터를 무제한으로 가져옴 -> 조심해야함
train_flow = train_gen.flow_from_directory(
'dogs_and_cats/small/train',
batch_size=batch_size,
target_size=(150, 150), # resize 기능을 제공해줌
class_mode='binary' # sigmoid 어울리는 모드로 변환
)
# class_mode "categorical", "binary", "sparse"
valid_flow = valid_gen.flow_from_directory(
'dogs_and_cats/small/train',
batch_size=batch_size,
target_size=(150, 150), # resize 기능을 제공해줌
class_mode='binary' # sigmoid 어울리는 모드로 변환
)
# 여기까지 x, y 만든셈임
# 마지막 dense layer 1000으로 고정되어 있으서 내가 수정해줘야함
conv_base = tf.keras.applications.VGG16(
include_top=False, # dense layer 가져오지 않는다.
)
# --------------------------------------- #
# 학습하지 않게 얼려버림 (웨이트가 바뀌지 않음 왜?? 이미 이 코드 만든사람이 잘 만들었으니깐)
conv_base.trainable = False # 업데이트 하지 않을 것임
# 이런식으로 업데이트를 일정 layer만 할 수 있음
for layer in conv_base.layers:
print(layer.name)
# layer.trainable = True
# block5 들어가 있는건 업데이트 하지 않겠다.
if 'block5' in layer.name:
layer.trainable = False
model = tf.keras.Sequential()
model.add(tf.keras.layers.Input(shape=[150, 150, 3])) # 224 써도 되지만 하드웨어 문제 -> 150만 쓰자
# ------------------------------------------------------------------- 시작 #
# layer처럼 직접 넣을 수도 있음
model.add(conv_base)
# 3차원에서 2차원
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(512, activation='relu'))
model.add(tf.keras.layers.Dense(1, activation='sigmoid'))
model.compile(optimizer=tf.keras.optimizers.RMSprop(0.0001),
loss=tf.keras.losses.binary_crossentropy,
metrics=['acc'])
history = model.fit_generator(
train_flow,
epochs=10,
steps_per_epoch=2000 // batch_size, # 정확하게 나눠 떨어지지 않으면 자투리는 사용하지 않겠다
validation_data=valid_flow,
# validation_steps=batch_size,
# verbose=2,
)
# model.fit()
model.save(get_model_name(version=4))
save_history(history, version=4)
# model_1_baseline()
# model_2_augmentation()
model_3_pretrained()
# model_4_pretrained_augmentation()
# load_history(version=3)
# load_model(version=4)
# load_history(version=4)
# Instructions for updating:
# load_model(version=1)
# load_model(version=4)
# Please use Model.fit, which supports generators.
# fit generation 대신 fit 을 써달라.