블로그 이미지
평범하게 살고 싶은 월급쟁이 기술적인 토론 환영합니다.같이 이야기 하고 싶으시면 부담 말고 연락주세요:이메일-bwcho75골뱅이지메일 닷컴. 조대협


Archive»


 
 

Object Detection API를 이용하여 커스텀 데이타 학습하기

얼굴인식 모델 만들기


조대협 (http://bcho.tistory.com)


이번글에서는 Tensorflow Object Detection API를 이용하여 직접 이미지를 인식할 수 있는 방법에 대해서 알아보자. 이미 가지고 있는 데이타를 가지고 다양한 상품에 대한 인식이나, 사람 얼굴에 대한 인식 모델을 머신러닝에 대한 전문적인 지식 없이도 손쉽게 만들 수 있다.


Object Detection API 설치

Object Detection API 설치는 http://bcho.tistory.com/1193http://bcho.tistory.com/1192 에서 이미 다뤘기 때문에 별도로 언급하지 않는다.

학습용 데이타 데이타 생성 및 준비

Object Detection API를 학습 시키기 위해서는 http://bcho.tistory.com/1193 예제와 같이 TFRecord 형태로 학습용 파일과 테스트용 파일이 필요하다. TFRecord 파일 포맷에 대한 설명은 http://bcho.tistory.com/1190 를 참고하면 된다.


이미지 파일을 TFRecord로 컨버팅하는 전체 소스 코드는 https://github.com/bwcho75/objectdetection/blob/master/custom/create_face_data.py 를 참고하기 바란다.

구글 클라우드 VISION API를 이용하여,얼굴이 있는지 여부를 파악하고, 얼굴 각도가 너무 많이 틀어진 경우에는 필터링 해낸후에,  얼굴의 위치 좌표를 추출하여 TFRecord 파일에 쓰는 흐름이다.

VISION API를 사용하기 때문에 반드시 서비스 어카운트 (Service Account/JSON 파일)를 구글 클라우드 콘솔에서 만들어서 설치하고 실행하기 바란다.


사용 방법은

python create_face_data.py {이미지 소스 디렉토리} {이미지 아웃풋 디렉토리} {TFRECORD 파일명}


형태로 사용하면 된다.

예) python ./custom/create_face_data.py /Users/terrycho/trainingdata_source /Users/terrycho/trainingdata_out


{이미지 소스 디렉토리} 구조는 다음과 같다.

{이미지 소스 디렉토리}/{라벨1}

{이미지 소스 디렉토리}/{라벨2}

{이미지 소스 디렉토리}/{라벨3}

:

예를 들어

/Users/terrycho/trainingdata_source/Alba

/Users/terrycho/trainingdata_source/Jessica

/Users/terrycho/trainingdata_source/Victoria

:

이런식이 된다.



명령을 실행하면, {이미지 아웃풋 디렉토리} 아래

  • 학습 파일은 face_training.record

  • 테스트 파일은 face_evaluation.record

  • 라벨맵은 face_label_map.pbtxt

로 생성된다. 이 세가지 파일이 Object Detection API를 이용한 학습에 필요하고 부가적으로 생성되는  csv 파일이 있는데

  • all_files.csv : 소스 디렉토리에 있는 모든 이미지 파일 목록

  • filtered_files.csv : 각 이미지명과, 라벨, 얼굴 위치 좌표 (사각형), 이미지 전체 폭과 높이

  • converted_result_files.csv : filtered_files에 있는 이미지중, 얼굴의 각도등이 이상한 이미지를 제외하고 학습과 테스트용 데이타 파일에 들어간 이미지 목록으로, 이미지 파일명, 라벨 (텍스트), 라벨 (숫자), 얼굴 좌표 (사각형) 을 저장한다.


여기서 사용한 코드는 간단한 테스트용 코드로, 싱글 쓰레드에 싱글 프로세스 모델로 대규모의 이미지를 처리하기에는 적절하지 않기 때문에, 운영환경으로 올리려면, Apache Beam등 분산 프레임웍을 이용하여 병렬 처리를 하는 것을 권장한다. http://bcho.tistory.com/1177 를 참고하기 바란다.


여기서는 학습하고자 하는 이미지의 바운드리(사각형 경계)를 추출하는 것을 VISION API를 이용해서 자동으로 했지만, 일반적인 경우는 이미지에서 각 경계를 수동으로 추출해서 학습데이타로 생성해야 한다




이런 용도로 사용되는 툴은 https://medium.com/towards-data-science/how-to-train-your-own-object-detector-with-tensorflows-object-detector-api-bec72ecfe1d9 문서에 따르면 FastAnnotationTool이나 ImageMagick 과 같은 툴을 추천하고 있다.



이렇게 학습용 파일을 생성하였으면 다음 과정은 앞의  http://bcho.tistory.com/1193 에서 언급한 절차와 크게 다르지 않다.

체크포인트 업로드

학습 데이타가 준비 되었으면 학습을 위한 준비를 하는데, 트랜스퍼 러닝 (Transfer learning)을 위해서 기존의 학습된 체크포인트 데이타를 다운 받아서 이를 기반으로 학습을 한다.

Tensorflow Object Detection API는 경량이고 단순한 모델에서 부터 정확도가 비교적 높은 복잡한 모델까지 지원하고 있지만, 복잡도가 높다고 해서 정확도가 꼭 높지는 않을 수 있다. 복잡한 모델일 수 록 학습 데이타가 충분해야 하기 때문에, 학습하고자 하는 데이타의 양과 클래스의 종류에 따라서 적절한 모델을 선택하기를 권장한다.


여기서는 faster_rcnn_inception_resnet_v2 모델을 이용했기 때문에 아래와 같이 해당 모델의 체크포인트 데이타를 다운로드 받는다.


curl -O http://download.tensorflow.org/models/object_detection/faster_rcnn_inception_resnet_v2_atrous_coco_11_06_2017.tar.gz


파일의 압축을 푼 다음 체크 포인트 파일을 학습 데이타용 Google Cloud Storage (GCS) 버킷으로 업로드 한다.

gsutil cp faster_rcnn_inception_resnet_v2_atrous_coco_11_06_2017/model.ckpt.* gs://${YOUR_GCS_BUCKET}/data/





설정 파일 편집 및 업로드

다음 학습에 사용할 모델의 설정을 해야 하는데,  object_detection/samples/configs/ 디렉토리에 각 모델별 설정 파일이 들어 있으며, 여기서는 faster_rcnn_inception_resnet_v2_atrous_pets.config 파일을 사용한다.


이 파일에서 수정해야 하는 부분은 다음과 같다.

클래스의 수

클래스 수를 정의한다. 이 예제에서는 총 5개의 클래스로 분류를 하기 때문에 아래와 같이 5로 변경하였다.

 8 model {

 9   faster_rcnn {

10     num_classes: 5

11     image_resizer {

학습 데이타 파일 명 및 라벨명

학습에 사용할 학습데이타 파일 (tfrecord)와 라벨 파일명을 지정한다.

126 train_input_reader: {

127   tf_record_input_reader {

128     input_path: "gs://terrycho-facedetection/data/face_training.record"

129   }

130   label_map_path: "gs://terrycho-facedetection/data/face_label_map.pbtxt"

131 }


테스트 데이타 파일명 및 라벨 파일명

학습후 테스트에 사용할 테스트 파일 (tfrecord)과 라벨 파일명을 지정한다

140 eval_input_reader: {

141   tf_record_input_reader {

142     input_path: "gs://terrycho-facedetection/data/face_evaluation.record"

143   }

144   label_map_path: "gs://terrycho-facedetection/data/face_label_map.pbtxt"

145   shuffle: false

146   num_readers: 1


만약에 학습 횟수(스탭)을 조정하고 싶으면 num_steps 값을 조정한다. 디폴트 설정은 20만회인데, 여기서는 5만회로 수정하였다.

117   # never decay). Remove the below line to train indefinitely.
118   # num_steps: 200000
119   num_steps: 50000
120   data_augmentation_options {
121     random_horizontal_flip {
122     }


설정 파일 수정이 끝났으면 gsutil cp 명령을 이용하여 해당 파일을 GCS 버킷에 다음과 같이 업로드 한다.

gsutil cp object_detection/samples/configs/faster_rcnn_inception_resnet_v2_atrous_pets.config gs://${YOUR_GCS_BUCKET}/data/faster_rcnn_inception_resnet_v2_atrous_pets.config

코드 패키징

models/ 디렉토리에서 다음 명령을 수행하여, 모델 코드를 패키징한다.

python setup.py sdist

(cd slim && python setup.py sdist)



학습


gcloud ml-engine jobs submit training `whoami`_object_detection_`date +%s` \

   --job-dir=gs://${YOUR_GCS_BUCKET}/train \

   --packages dist/object_detection-0.1.tar.gz,slim/dist/slim-0.1.tar.gz \

   --module-name object_detection.train \

   --region asia-east1 \

   --config object_detection/samples/cloud/cloud.yml \

   -- \

   --train_dir=gs://${YOUR_GCS_BUCKET}/train \

   --pipeline_config_path=gs://${YOUR_GCS_BUCKET}/data/faster_rcnn_resnet101_pets.config

모니터링

학습이 진행되면 텐서보드를 이용하여 학습 진행 상황을 모니터링할 수 있고, 또한 테스트 트레이닝을 수행하여, 모델에 대한 테스트를 동시 진행할 수 있다. http://bcho.tistory.com/1193 와 방법이 동일하니 참고하기 바란다.


학습을 시작하면 텐서보드를 통해서, Loss 값이 수렴하는 것을 확인할 수 있다.



결과

학습이 끝나면 텐서보드에서 테스트된 결과를 볼 수 있다. 이 예제의 경우 모델을 가장 복잡한 모델을 사용했는데 반하여, 총 5개의 클래스에 대해서 클래스당 약 40개정도의 학습 데이타를 사용했는데, 상대적으로 정확도가 낮았다. 실 서비스에서는 더 많은 데이타를 사용하기를 권장한다.



활용

학습된 모델을 활용하는 방법은 학습된 모델을 export 한후에, (Export 하는 방법은  http://bcho.tistory.com/1193 참고) export 된 모델을 로딩하여, 코드에서 불러서 사용하면 된다.

http://bcho.tistory.com/1192 참고



저작자 표시 비영리
신고

 

얼굴 인식 모델을 만들어보자

#3 - 학습된 모델로 예측하기


조대협 (http://bcho.tistory.com)


앞글에 걸쳐서 얼굴 인식을 위한 데이타를 수집 및 정재하고, 이를 기반으로 얼굴 인식 모델을 학습 시켰다.

 

 

이번글에서는 학습이 된 데이타를 가지고, 사진을 넣어서 실제로 인식하는 코드를 만들어보자

전체 소스 코드는 https://github.com/bwcho75/facerecognition/blob/master/2.%2BFace%2BRecognition%2BPrediction%2BTest.ipynb 와 같다.

모델 로딩 하기

 

모델 학습에 사용한 CNN 모델을 똑같이 정의한다. conv1(),conv2(),conv3(),conv4(),fc1(),fc2(), build_model() 등 학습에 사용된 CNN 네트워크를 똑같이 정의하면 된다.

 

다음으로 이 모델에 학습된 값들을 채워 넣어야 한다.

# build graph

images = tf.placeholder(tf.float32,[None,FLAGS.image_size,FLAGS.image_size,FLAGS.image_color])

keep_prob = tf.placeholder(tf.float32) # dropout ratio

 

예측에 사용할 image 를 넘길 인자를  images라는 플레이스홀더로 정의하고, dropout 비율을 정하는 keep_prob도 플레이스 홀더로 정의한다.

 

prediction = tf.nn.softmax(build_model(images,keep_prob))

 

그래프를 만드는데, build_model에 의해서 나온 예측 결과에 softmax 함수를 적용한다. 학습시에는 softmax 함수의 비용이 크기 때문에 적용하지 않았지만, 예측에서는 결과를 쉽게 알아보기 위해서  softmax 함수를 적용한다. Softmax 함수는 카테고리 별로 확률을 보여줄때 전체 값을 1.0으로 해서 보여주는것인데, 만약에 Jolie,Sulyun,Victora 3개의 카테코리가 있을때 각각의 확률이 70%,20%,10%이면 Softmax를 적용한 결과는 [0.7,0.2,0.1] 식으로 출력해준다.

 

sess = tf.InteractiveSession()

sess.run(tf.global_variables_initializer())

 

다음 텐서플로우 세션을 초기화 하고,

 

saver = tf.train.Saver()

saver.restore(sess, 'face_recog')

 

마지막으로 Saver의 restore 함수를 이용하여 ‘face_recog’라는 이름으로 저장된 학습 결과를 리스토어 한다. (앞의 예제에서, 학습이 완료된 모델을 ‘face_recog’라는 이름으로 저장하였다.)

 

예측하기

로딩 된 모델을 가지고 예측을 하는 방법은 다음과 같다. 이미지 파일을 읽은 후에, 구글 클라우드 VISION API를 이용하여, 얼굴의 위치를 추출한후, 얼굴 이미지만 크롭핑을 한후에, 크롭된 이미지를 텐서플로우 데이타형으로 바꾼후에, 앞서 로딩한 모델에 입력하여 예측된 결과를 받게 된다.

 

얼굴 영역 추출하기

먼저 vision API로 얼굴 영역을 추출하는 부분이다. 앞의 이미지 전처리에 사용된 부분과 다르지 않다.

 

import google.auth

import io

import os

from oauth2client.client import GoogleCredentials

from google.cloud import vision

from PIL import Image

from PIL import ImageDraw

 

FLAGS.image_size = 96

 

# set service account file into OS environment value

os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "/Users/terrycho/keys/terrycho-ml.json"

 

위와 같이 구글 클라우드 Vision API를 사용하기 위해서 억세스 토큰을 Service Account 파일로 다운 받아서 위와 같이 GOOGLE_APPLICATION_CREDENTIALS 환경 변수에 세팅 하였다.

 

visionClient = vision.Client()

print ('[INFO] processing %s'%(imagefile))

 

#detect face

image = visionClient.image(filename=imagefile)

faces = image.detect_faces()

face = faces[0]

 

다음 vision API 클라이언트를 생성한 후에, detect_faces() 를 이용하여 얼굴 정보를 추출해낸다.

 

print 'number of faces ',len(faces)

 

#get face location in the photo

left = face.fd_bounds.vertices[0].x_coordinate

top = face.fd_bounds.vertices[0].y_coordinate

right = face.fd_bounds.vertices[2].x_coordinate

bottom = face.fd_bounds.vertices[2].y_coordinate

rect = [left,top,right,bottom]

 

추출된 얼굴 정보에서 첫번째 얼굴의 위치 (상하좌우) 좌표를 리턴 받는다.

얼굴 영역을 크롭하기

앞에서 입력 받은 상하좌우 좌표를 이용하여, 이미지 파일을 열고,  크롭한다.

 

fd = io.open(imagefile,'rb')

image = Image.open(fd)

 

import matplotlib.pyplot as plt

# display original image

print "Original image"

plt.imshow(image)

plt.show()

 

 

# draw green box for face in the original image

print "Detect face boundary box "

draw = ImageDraw.Draw(image)

draw.rectangle(rect,fill=None,outline="green")

 

plt.imshow(image)

plt.show()

 

crop = image.crop(rect)

im = crop.resize((FLAGS.image_size,FLAGS.image_size),Image.ANTIALIAS)

plt.show()

im.save('cropped'+imagefile)

 

크롭된 이미지를 텐서플로우에서 읽는다.

 

print "Cropped image"

tfimage = tf.image.decode_jpeg(tf.read_file('cropped'+imagefile),channels=3)

tfimage_value = tfimage.eval()

 

크롭된 파일을 decode_jpeg() 메서드로 읽은 후에, 값을 tfimage.eval()로 읽어드린다.

 

tfimages = []

tfimages.append(tfimage_value)

 

앞에서 정의된 모델이 한개의 이미지를 인식하는게 아니라 여러개의 이미지 파일을 동시에 읽도록 되어 있기 때문에, tfimages라는 리스트를 만든 후, 인식할 이미지를 붙여서 전달한다.

 

plt.imshow(tfimage_value)

plt.show()

fd.close()

 

p_val = sess.run(prediction,feed_dict={images:tfimages,keep_prob:1.0})

name_labels = ['Jessica Alba','Angelina Jolie','Nicole Kidman','Sulhyun','Victoria Beckam']

i = 0

for p in p_val[0]:

   print('%s %f'% (name_labels[i],float(p)) )

   i = i + 1

 

tfimages 에 이미지를 넣어서 모델에 넣고 prediction 값을 리턴 받는다. dropout은 사용하지 않기 때문에, keep_prob을 1.0으로 한다.

나온 결과를 가지고 Jessica, Jolie,Nicole Kidman, Sulhyun, Victoria Beckam 일 확률을 각각 출력한다.


전체 코드는 https://github.com/bwcho75/facerecognition/blob/master/2.%2BFace%2BRecognition%2BPrediction%2BTest.ipynb


다음은 설현 사진을 가지고 예측을 한 결과 이다.


 

이 코드는 학습된 모델을 기반으로 얼굴을 인식이 가능하기는 하지만 실제 운영 환경에 적용하기에는 부족하다. 파이썬 모델 코드를 그대로 옮겼기 때문에, 성능도 상대적으로 떨어지고, 실제 운영에서는 모델을 업그레이드 배포 할 수 있고, 여러 서버를 이용하여 스케일링도 지원해야 한다.

그래서 텐서플로우에서는 Tensorflow Serving 이라는 예측 서비스 엔진을 제공하고 구글 클라우에서는 Tensorflow Serving의 매니지드 서비스인, CloudML 서비스를 제공한다.

 

앞의 두 글이 로컬 환경에서 학습과 예측을 진행했는데, 다음 글에서는 상용 서비스에 올릴 수 있는 수준으로 학습과 예측을 할 수 있는 방법에 대해서 알아보도록 하겠다.

 

저작자 표시 비영리
신고

연예인 얼굴 인식 서비스를 만들어보자 #2


CSV 목록에 있는 이미지 데이타를 읽어보자


조대협 (http://bcho.tistory.com)


앞의 글(http://bcho.tistory.com/1166) 에서는 얼굴 인식 데이타를 확보하고, 전처리를 통해서 96x96 사이즈로 만드는 것을 살펴보았다.

그러면, 이 전처리가 끝난 데이타를 텐서플로우에서 학습용으로 쓰기 위해서 데이타를 읽어 들이는 것을 살펴보겠다.


파일에서 학습데이타를 읽는 방법과 큐에 대한 설명은 아래 두 글을 참고하기 바란다.

http://bcho.tistory.com/1165

http://bcho.tistory.com/1163

파일 포맷

파일 포맷은 다음과 같다

/Users/terrycho/traning_datav2/training/007BIL_Aaron_Eckhart_001.jpg,Aaron Eckhart

/Users/terrycho/traning_datav2/training/08486023.jpg,Aaron Eckhart

/Users/terrycho/traning_datav2/training/09.jpg,Aaron Eckhart

/Users/terrycho/traning_datav2/training/0_61_091107_411.jpg,Aaron Eckhart


‘,’로 구분되는 CSV 형태의 파일 포맷이며, 앞에는 이미지의 경로, 뒤에는 해당 이미지의 라벨이 명시되어 있다.


예제 코드

예제코드를 살펴보자

예제 코드의 형태는 http://bcho.tistory.com/1165 에 소개된 CSV 파일을 읽는 코드와 크게 드리지 않다.


import tensorflow as tf

import numpy as np

import matplotlib.pyplot as plt


csv_file =  tf.train.string_input_producer(['/Users/terrycho/dev/ws_gae_demo/terry-face-recog/training_file.txt']

                                               ,name='filename_queue')

textReader = tf.TextLineReader()

_,line = textReader.read(csv_file)

imagefile,label = tf.decode_csv(line,record_defaults=[ [""],[""] ])

image = tf.image.decode_jpeg(tf.read_file(imagefile),channels=3)



with tf.Session() as sess:

   

   coord = tf.train.Coordinator()

   threads = tf.train.start_queue_runners(sess=sess, coord=coord)

   

   for i in range(100):

       image_value,label_value,imagefile_value = sess.run([image,label,imagefile])

       plt.imshow(image_value)

       plt.show()

       print label_value,":",imagefile_value

   

   coord.request_stop()

   coord.join(threads)


특별한 부분만 살펴보자면

imagefile,label = tf.decode_csv(line,record_defaults=[ [""],[""] ])

image = tf.image.decode_jpeg(tf.read_file(imagefile),channels=3)

부분인데, TextReader로 읽어드린 문자열을 파싱해서 이미지 파일명 (imagefile)과 라벨(label)로 추출하고

이 imagefile을가지고, tf.image.decode_jpeg 메서드를 이용하여 jpeg  파일을 읽어서 텐서형으로 바꾼다. 이때, channel=3 으로 설정하였는데, 이유는 이 이미지는 칼라 이미지로 RGB 3개의 값을 가지기 때문에 3차원으로 정의하였다.


다음 텐서 플로우 세션을 시작한 다음에

image_value,label_value,imagefile_value = sess.run([image,label,imagefile])

Image,label,imagefile 값을 읽은 후에, 확인을 위해서 matplotlib를 이용하여, 이미지와, 라벨, 그리고 파일 경로를 출력하여, 값이 정확하게 읽히는지 순서에 맞게 읽히고 누락은 없는지 확인할수 있다.

(확인을 위해서 데이타를 읽을때 shuffle을 하지 않고 순차적으로 읽었다.)


실행 결과

그 실행 결과를 보면 다음과 같다.



다른 코드


만약에 읽어드린 이미지들을 한꺼번에 보고 싶을 경우에는 아래와 같은 코드를 사용한다. 아래 코드는 200개의 이미지를 읽어서 가로로 10개씩 출력하는 코드이다. 아래 코드 부분을 바꿔치면 된다.

   fig = plt.figure(figsize=(20,120))

   for i in range(200):

       image_value,label_value,imagefile_value = sess.run([image,label,imagefile])

    

       subplot = fig.add_subplot(50,10,i+1)

       subplot.set_xlabel(label_value)

       plt.imshow(image_value)

       print label_value ,imagefile_value

   plt.show(


출력 결과는 다음과 같다.


다음번에는 텐서로 읽어드린 이미지 데이타를 활용하여 얼굴 인식 모델을 CNN으로 만들어보고 학습 시켜 보겠다.




저작자 표시 비영리
신고