갑자기, 머신러닝, 케라스, 얼굴인식
얼굴인식. 쉽다. 누구나 할 수 있다.
그래서 나도 한 번 적어본다.
우선 나를 포함한 주변 3인의 얼굴을 각각 500장 정도 찍는다.
그리고 얼굴만 Detect 한다.
그 얼굴을 같은 Size로 잘 가공 한다.
일단 사진을 다 읽어온다.
딥러닝에 필요한 Dim 으로 맞춘다. 동시에 정규화(Scaling) 한다.
대략 (?, ?, ?, ?) 요런 Dim 구조를 갖는다.
모델을 구성한다. Input과 Output이 있다.
모델을 Compile 한다.
데이터를 늘리는 수작(?)을 부린다. 클래스에 위배되지 않을 만큼만.
모델을 통한 학습을 시작한다.
GPU 를 사고싶은 생각이 들 것이다.
참고로 나는 GTX1080 을 사용한다.
이렇게 나열해 보니. 별것 없다.
기술 스택을 나열해 보자면.
Python, Tensorflow, keras, 기타 등등.
다른 글에서 Numpy, Pandas 관련 이야기는 대략 한 것 같은데.
사실 여기서 중요한건. 설치를 하고 막 코드를 공부하고 그런 것 보다는!
모델링에 좀 더 힘을 쏟았다.
VGG_FACE Pre-trained 를 함께 사용했다.
모델링에서는 CNN 기반의 베이스 모델을 통한 학습을 진행했다.
기호에 맞게, 여러 모델을 만들어 Ensemble 형태의 Architects 를 가져가도 좋다.
그럼 쥬피터에서 시작을 해보면!
from keras.models import Model, Sequential
from keras.layers import Input, Convolution2D, ZeroPadding2D, MaxPooling2D, Flatten, Dense, Dropout, Activation
from PIL import Image
import numpy as np
from keras.preprocessing.image import load_img, save_img, img_to_array
from keras.applications.imagenet_utils import preprocess_input
from keras.preprocessing import image
import matplotlib.pyplot as plt
import cv2
from keras import backend as K
if('tensorflow' == K.backend()):
import tensorflow as tf
from keras.backend.tensorflow_backend import set_session
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
sess = tf.Session(config=config)
model = Sequential()
model.add(ZeroPadding2D((1,1),input_shape=(224, 224, 3)))
model.add(Convolution2D(64, (3, 3), activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D((2,2), strides=(2,2)))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(128, (3, 3), activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(128, (3, 3), activation='relu'))
model.add(MaxPooling2D((2,2), strides=(2,2)))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(256, (3, 3), activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(256, (3, 3), activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(256, (3, 3), activation='relu'))
model.add(MaxPooling2D((2,2), strides=(2,2)))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(512, (3, 3), activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(512, (3, 3), activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(512, (3, 3), activation='relu'))
model.add(MaxPooling2D((2,2), strides=(2,2)))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(512, (3, 3), activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(512, (3, 3), activation='relu'))
model.add(ZeroPadding2D((1,1)))
model.add(Convolution2D(512, (3, 3), activation='relu'))
model.add(MaxPooling2D((2,2), strides=(2,2)))
model.add(Convolution2D(4096, (7, 7), activation='relu'))
model.add(Dropout(0.5))
model.add(Convolution2D(4096, (1, 1), activation='relu'))
model.add(Dropout(0.5))
model.add(Convolution2D(2622, (1, 1)))
model.add(Flatten())
model.add(Activation('softmax'))
from keras.models import model_from_json
model.load_weights('./data/vgg_face_w.h5')
아! 참고로 저 .h5 파일은 인터넷에 널려있다.
last_layer = model.layers[-3].output
x = Flatten(name='flatten')(last_layer)
x = Dense(3, activation='softmax', name='fc8')(x)
out = Activation('softmax')(x)
custom_vgg_model = Model(model.layers[0].input, out)
여기서! 나는 내 개인적인 데이터를 사용할 것이므로, 3개의 Output이 존재한다.
그래서! 마지막 Output 파라미터를 변경한다.
from keras.preprocessing.image import ImageDataGenerator
train_path = '/home/david/python_cuda/data/train'
test_path = '/home/david/python_cuda/data/test'
data_aug_gen = ImageDataGenerator(
rescale=1/255.,
width_shift_range=0.25,
height_shift_range=0.25,
shear_range=0,
zoom_range=0.15,
horizontal_flip=True,
vertical_flip=False
)
'''
├── test
│ ├── david
│ ├── jhok
│ ├── jinsu
│ ├── mrlee
│ └── ...
└── train
├── david
├── jhok
├── jinsu
├── mrlee
└── ...
대략 이런 Directory 구조를 가져야 이번 Logic 을 실행 할 수 있다.
'''
train_generator = data_aug_gen.flow_from_directory(
train_path,
target_size=(224, 224),
shuffle=True,
batch_size=16,
class_mode='categorical'
)
test_generator = data_aug_gen.flow_from_directory(
test_path,
target_size=(224, 224),
shuffle=False,
batch_size=16,
class_mode='categorical'
)
데이터의 수를 증가시키는 수작을 부린다.
사실, 전이학습의 이점이 적은 데이터로도 좋은 학습 효과를 가질 수 있다는 것이지만,
너무 적다. 이건 아니다. (각 Class 별로 학습 데이터 약 330개 정도를 가지고 진행 하였다.)
_ = custom_vgg_model.fit_generator(
train_generator,
steps_per_epoch=50,
epochs=200,
validation_data=test_generator,
validation_steps=20
)
열심히 돌린다. 구경만 하면 된다.
# 데이터 레이블 확인
yhat = list(train_generator.class_indices)
# 이미지 가공 ( input, Output Dim T)
def preprocess_image(image_path):
img = load_img(image_path, target_size=(224, 224))
img = img_to_array(img)
img = np.expand_dims(img, axis=0)
img = preprocess_input(img)
return img
path = '/home/david/python_cuda/data/ljg2.jpg' # Mr. Lee의 사진이다.
%time
res = custom_vgg_model.predict(preprocess_image(path))[0,:]
print(res, yhat[np.argmax(res, axis=0)])
결과는!
CPU times: user 7 µs, sys: 1e+03 ns, total: 8 µs Wall time: 16.7 µs [0.21194156 0.21194156 0.57611686] [0.21194156 0.21194156 0.57611686] MrLee
MrLee 가 나왔다. 이게 사진을 보여주면 더 좋을텐데... 아는 분들 사진으로 하는 거라서...
자칫... 신뢰성을 못 줄 수 있어서 좀 아쉽지만.
이건 직접 해봐야 느낄 수 있다.
열심히 삽시다.