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


Archive»


 
 

Object Detection API에 애완동물 사진을 학습 시켜 보자


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


Object Detection API에 이번에는 애완동물 사진 데이타를 학습시켜 보도록 한다.

애완 동물 학습 데이타의 원본은  Oxford-IIIT Pets lives  http://www.robots.ox.ac.uk/~vgg/data/pets/ 에 있다. 약 37개의 클래스에, 클래스당 200개 정도의 이미지를 가지고 있다.



이번 글에서는 이 애완동물 데이타를 다운 받아서, Object Detection API에 학습 시키는 것까지 진행을 한다.

데이타를 다운로드 받은 후, Object Detection API에 학습 시키기 위해서, 데이타 포맷을 TFRecord 형태로 변환한 후, 학습을 하는 과정을 설명한다.


주의할점 : 이 튜토리얼은 총 37개의 클래스 약 7000장의 이미지를 학습시키는데, 17시간 이상이 소요되며, 구글 클라우 CloudML의 텐서플로우 클러스터에서 분산 러닝을 하도록 설명하고 있는데, 많은 비용이 들 수 있다. 전체 흐름과 과정을 이해하기 위해서는 17시간을 풀 트레이닝 시키지 말고 학습 횟수를 줄이거나 아니면 중간에서 학습을 멈춰서 비용이 많이 나오지 않도록 하는 것을 권장한다.

학습 데이타 다운로드 받기

%curl -O http://www.robots.ox.ac.uk/~vgg/data/pets/data/images.tar.gz

%curl -O http://www.robots.ox.ac.uk/~vgg/data/pets/data/annotations.tar.gz

※ 맥이기 때문에, curl -O 를 사용했는데, Linux의 경우에는 wget을 사용하면 된다.

파일을 다운로드 받았으면 압축을 풀어보자

  • images.tar.gz에는 애완동물의 학습용 이미지가 들어가 있다.

  • annotations.tar.gz 는 각 이미지에 대한 메타 데이타가 들어있다. 이미지 마다 나타난 동물의 종류, 사진상 동물의 위치 (박스)

TFRecord 파일 포맷으로  컨버팅 하기

압축을 푼 메타데이타와 이미지 파일을 이용해서 tfrecord 파일 형태로 컨버팅을 해야 한다. Tfrecord 내에는 이미지 바이너리, 이미지에 대한 정보 (이미지 크기, 인식할 물체의 위치, 라벨)등이 들어간다. 상세 데이타 포맷에 대해서는 다음글에서 설명하도록 한다.

이 데이타를 가지고 tfrecord 타입으로 컨버팅 하는 코드는 object_detection/create_pet_tf_record.py

에 이미 작성되어 있다. 아래 코드를 이용해서 실행해주면 자동으로 pet_train.record에 학습용 데이타를 pet_val.record에 테스트용 데이타를 생성해준다.


python object_detection/create_pet_tf_record.py \
   --label_map_path=object_detection/data/pet_label_map.pbtxt \
   --data_dir=`pwd` \
   --output_dir=`pwd`

학습 환경 준비하기

데이타가 준비되었으면 학습을 위한 환경을 준비해야 한다.

학습은 구글 클라우드 플랫폼의 CloudML을 사용한다. CloudML은 구글 클라우드 플랫폼의 Tensorflow managed 서비스로, Tensorflow 클러스터 설치나 운영 필요 없이 간단하게 명령어 만으로 여러대의 머신에서 학습을 가능하게 해준다.

CloudML을 사용하기 위해서는 몇가지 환경 설정을 해줘야 한다.

  • 먼저 학습용 데이타 (tfrecord)파일을 구글 클라우드 스토리지 (GCS)로 업로드 해야 한다.

  • Object Detection API에서 사물 인식에 사용된 모델의 체크 포인트를 업로드 해야 한다.

  • 클라우드에서 학습을 하기 때문에, 텐서플로우 코드를 패키징해서 업로드해야 한다.

학습 데이타 업로드 하기

데이타를 업로드하기전에, 구글 클라우드 콘솔에서 구글 클라우드 스토리지 버킷을 생성한다.

생성된 버킷명을 YOUR_GCS_BUCKET 환경 변수에 저장한다.

export YOUR_GCS_BUCKET=${YOUR_GCS_BUCKET}


다음 gsutil 유틸리티를 이용하여 YOUR_GCS_BUCKET 버킷으로 학습용 데이타와, 라벨맵 데이타를 업로드 한다.


gsutil cp pet_train.record gs://${YOUR_GCS_BUCKET}/data/pet_train.record
gsutil cp pet_val.record gs://${YOUR_GCS_BUCKET}/data/pet_val.record
gsutil cp object_detection/data/pet_label_map.pbtxt gs://${YOUR_GCS_BUCKET}/data/pet_label_map.pbtxt


학습된 모델 다운로드 받아서 업로드 하기

다음은 학습된 모델을 받아서, 그중에서 체크포인트를  GCS에 올린다.


curl -O http://storage.googleapis.com/download.tensorflow.org/models/object_detection/faster_rcnn_resnet101_coco_11_06_2017.tar.gz

tar -xvf faster_rcnn_resnet101_coco_11_06_2017.tar.gz
gsutil cp faster_rcnn_resnet101_coco_11_06_2017/model.ckpt.* gs://${YOUR_GCS_BUCKET}/data/


체크 포인트를 다운받아서 업로드 하는 이유는, 트랜스퍼 러닝 (Transfer Learning)을 하기 위함인데, 하나도 학습이 되지 않은 모델을 학습을 시키는데는 시간이 많이 들어간다. 트랜서퍼러닝은 이미 학습이 되어 있는 모델로 다른 데이타를 학습 시키는 방법인데, 사물을 인식하는 상태로 학습되어 있는 모델을 다른 물체 (여기서는 애완동물)를 학습하는데 사용하면 학습 시간을 많이 줄 일 수 있다. 이런 이유로, 사물 인식용으로 학습된 체크포인트를 로딩해서 이 체크포인트 부터 학습을 하기 위함이다.

설정 파일 변경하기

Object Detection API를 사용하기 위해서는 학습에 대한 설정 정보를 정의해야 한다.

이 설정 파일안에는 학습 데이타의 위치, 클래스의 수 및 각종 하이퍼 패러미터들이 정의되어 있다. 패러미터에 대한 자세한 설명은  https://github.com/tensorflow/models/blob/master/object_detection/g3doc/configuring_jobs.md를 참고하기 바란다. 이 예제에서는 설정 파일을 따로 만들지 않고 애완동물 사진 학습을 위해서 미리 정의되어 있는 템플릿 설정 파일을 이용하도록 한다.  설정 파일은 미리 정의된 모델에 따라 다른데, 여기서는 faster_rcnn_resnet101_pets 모델을 사용하기 때문에 object_detection/samples/configs/faster_rcnn_resnet101_pets.config 파일을 사용한다.


파일의 위치가 PATH_TO_BE_CONFIGURED 문자열로 정의되어 있는데, 이를 앞에서 만든 GCS 버킷명으로 변경해야 하기 때문에, 아래와 같이 sed 명령을 이용하여 해당 문자열을 변경하자


Linux : sed -i "s|PATH_TO_BE_CONFIGURED|"gs://${YOUR_GCS_BUCKET}"/data|g" object_detection/samples/configs/faster_rcnn_resnet101_pets.config


Max : sed -i ‘’ -e "s|PATH_TO_BE_CONFIGURED|"gs://${YOUR_GCS_BUCKET}"/data|g" object_detection/samples/configs/faster_rcnn_resnet101_pets.config


설정 파일 작성이 끝났으면 이를 GCS 버킷에 올린 후에, 학습시에 사용하도록 한다. 다음 명령어는 설정 파일을 GCS 버킷에 올리는 명령이다.

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


텐서플로우 코드 패키징 및 업로드

학습에 사용할 데이타와 체크포인트등을 업로드 했으면, 다음 텐서플로우 코드를 패키징 해야 한다. 이 글에서는 학습을 로컬 머신이 아니라 구글 클라우드의 텐서플로우 메니지드 서비스인 CloudML을 사용하는데, 이를 위해서는 텐서플로우코드와 코드에서 사용하는 파이썬 라이브러리들을 패키징해서 올려야 한다.


Object Detection API 모델 디렉토리에서 다음 명령어를 실행하면, model 디렉토리와 model/slim 디렉토리에 있는 텐서플로우 코드 및 관련 라이브러리를 같이 패키징하게된다.


# From tensorflow/models/
python setup.py sdist
(cd slim && python setup.py sdist)


명령을 실행하고 나면 패키징된 파일들은 dist/object_detection-0.1.tar.gzslim/dist/slim-0.1.tar.gz 에 저장되게 된다.

학습하기

구글 CloudML을 이용하여 학습하기. 그러면 학습을 시작해보자. 학습은 200,000 스탭에 총 17시간 정도가 소요되며, 비용이 3000$ 이상이 소요되니, 비용이 넉넉하지 않다면, 학습을 중간에 중단 시키기를 권장한다. 테스트 목적이라면 약 10~20분 정도면 충분하지 않을까 한다. 아니면 앞의 config 파일에서 trainning step을 작게 낮춰서 실행하기 바란다.


# From tensorflow/models/
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


학습을 시킬 텐서플로우 클러스터에 대한 정보는 object_detection/samples/cloud/cloud.yml 에 들어 있다. 내용을 보면,

trainingInput:

 runtimeVersion: "1.0"

 scaleTier: CUSTOM

 masterType: standard_gpu

 workerCount: 5

 workerType: standard_gpu

 parameterServerCount: 3

 parameterServerType: standard


scaleTier로 클러스터의 종류를 정의할 수 있는데, 서버 1대에서 부터 여러대의 클러스터까지 다양하게 적용이 가능하다. 여기서는 모델이 크기가 다소 크기 때문에, Custom으로 설정하였다.


역할

서버 타입

댓수

Master server

standard_gpu

1

Worker

standard_gpu

5

Parameter Server

standard

5


각 서버의 스펙은 상세 스펙은 나와있지 않고, 상대값으로 정의되어 있는데 대략 내용이 다음과 같다.



출처 https://cloud.google.com/ml-engine/docs/concepts/training-overview#machine_type_table




학습을 시작하고 나면 CloudML 콘솔에서 실행중인 Job을 볼 수 있고, Job을 클릭하면 자원의 사용 현황을 볼 수 있다. (CPU와 메모리 사용량)



학습을 시작한 후에, 학습된 모델을 Evaluate할 수 있는데, Object Detection API에서는 학습 말고 Evaluation 모델을 별도로 나눠서, 잡을 나눠서 수행하도록 하였다. 학습중에 생성되는 체크포인트 파일을 읽어서 Evaluation을 하는 형태이다.

다음을 Evaluation을 실행하는 명령어인데, 위의 학습 작업이 시작한 후에, 한시간 정도 후부터 실행해도 실행 상태를 볼 수 있다.


# From tensorflow/models/
gcloud ml-engine jobs submit training `whoami`_object_detection_eval_`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.eval \
   --region asia-east1 \
   --scale-tier BASIC_GPU \
   -- \
   --checkpoint_dir=gs://${YOUR_GCS_BUCKET}/train \
   --eval_dir=gs://${YOUR_GCS_BUCKET}/eval \
  --pipeline_config_path=gs://${YOUR_GCS_BUCKET}/data/faster_rcnn_resnet101_pets.config


학습 진행 상황 확인하기

학습이 진행중에도, Evaluation을 시작했으면, Tensorboard를 이용하여 학습 진행 상황을 모니터링 할 수 있다. 학습 진행 데이타가 gs://${YOUR_GCS_BUCKET} 에 저장되기 때문에, 이 버킷에 있는 데이타를 Tensorboard로 모니터링 하면 된다.

실행 방법은 먼저 GCS 에 접속이 가능하도록 auth 정보를 설정하고, Tensorboard에 로그 파일 경로를

GCS 버킷으로 지정하면 된다.

gcloud auth application-default login
tensorboard --logdir=gs://${YOUR_GCS_BUCKET}


아래는 실제 실행 결과이다.



Evaluataion이 끝났으면, 테스트된 이미지도 IMAGES 탭에서 확인이 가능하다.



학습된 모델을 Export 하기

학습이 완료되었으면, 이 모델을 예측 (Prediction)에 사용하기 위해서 Export 할 수 있다. 이렇게 Export 된 이미지는 나중에 다시 로딩하여 예측(Prediction)코드에서 로딩을 하여 사용이 가능하다.

${YOUR_GCS_BUCKET}에 가면 체크 포인트 파일들이 저장되어 있는데, 이 체크 포인트를 이용하여 모델을 Export 한다.



GCS 버킷에서 Export 하고자 하는 Check Point 번호를 선택한 후에 Export 하면 된다, 여기서는 200006 Check Point를 Export 해보겠다.


${CHECKPOINT_NUMBER} 환경 변수를

export CHECKPOINT_NUMBER=200006

으로 설정한 다음에 다음 명령어를 실행한다.


# From tensorflow/models
gsutil cp gs://${YOUR_GCS_BUCKET}/train/model.ckpt-${CHECKPOINT_NUMBER}.* .
python object_detection/export_inference_graph.py \

   --input_type image_tensor \

   --pipeline_config_path object_detection/samples/configs/faster_rcnn_resnet101_pets.config \

   --trained_checkpoint_prefix model.ckpt-${CHECKPOINT_NUMBER} \

   --output_directory output_inference_graph.pb


명령을 실행하고 나면 output_inference_graph.pb 디렉토리에 모델이 Export 된것을 확인할 수 있다.

다음 글에서는 직접 자신의 사진 데이타만을 가지고 학습과 예측을 하는 방법에 대해서 알아보겠다.


참고 자료



저작자 표시 비영리
신고
크리에이티브 커먼즈 라이선스
Creative Commons License


Tensorflow Object Detection API


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


Tensorflow Object Detection API는, Tensorflow 를 이용하여 이미지를 인식할 수 있도록 개발된 모델로, 라이브러리 형태로 제공되며, 각기 다른 정확도와 속도를 가지고 있는 5개의 모델을 제공한다. 머신러닝이나 텐서플로우에 대한 개념이 거의 없더라도 라이브러리 형태로 손쉽게 사용할 수 있으며, 직접 사용자 데이타를 업로드해서 학습을 하여, 내 시나리오에 맞는 Object Detection System을 손쉽게 만들 수 있다.


Object Detection API를 설치하기 위해서는 텐서플로우 1.x 와 파이썬 2.7x 버전이 사전 설치되어 있어야 한다. 이 글에서는 파이썬 2.7.13과 텐서플로우 2.7.13 버전을 기준으로 하고, 맥에 설치하는 것을 기준으로 한다. 리눅스나 다른 플랫폼 설치는 원본 설치 문서 https://github.com/tensorflow/models/blob/master/object_detection/g3doc/installation.md 를 참고하기 바란다.


설치 및 테스팅

Protocol Buffer 설치

Object Detection API는 내부적으로 Protocol Buffer를 사용한다. MAC에서 Protocol Buffer를 설치 하는 방법은 https://github.com/google/protobuf/tree/master/pythonhttp://bcho.tistory.com/1182 를 참고하기 바란다.

설치가 되었는지를 확인하려면, 프롬프트 상에서 protoc 명령을 실행해보면 된다.

파이썬 라이브러리 설치

프로토콜 버퍼 설치가 끝났으면, 필요한 파이썬 라이브러리를 설치한다.

% pip install pillow

% pip install lxml

% pip install jupyter

% pip install matplotlib

Object Detection API 다운로드 및 설치

Object Detection API 설치는 간단하게, 라이브러리를 다운 받으면 된다. 설치할 디렉토리로 들어가서 git clone 명령어를 통해서, 라이브러리를 다운로드 받자

% git clone https://github.com/tensorflow/models

Protocol Buffer 컴파일

다음 프로토콜 버퍼를 사용하기 위해서 protoc로 proto 파일을 컴파일 한데, Object Detection API를 설치한 디렉토리에서 models 디렉토리로 들어간 후에, 다음 명령어를 수행한다.


protoc object_detection/protos/*.proto --python_out=.

PATH 조정하기

설치가 끝났으면 Object Detection API를 PATH와 파이썬 라이브러리 경로인 PYTHONPATH에 추가한다. 맥에서는 사용자 홈디렉토리의 .bash_profile 에 추가 하면되낟.

PYTHONPATH 환경 변수에 {Object Detection API 설치 디렉토리}/models/slim 디렉토리와 Object Detection API 설치 디렉토리}/models/models 디렉토리를 추가한다.

같은 디렉토리를 PATH에도 추가해준다.


export PYTHONPATH=$PYTHONPATH:/Users/terrycho/dev/workspace/objectdetection/models:/Users/terrycho/dev/workspace/objectdetection/models/slim

export PATH=$PATH:/Users/terrycho/dev/workspace/objectdetection/models:/Users/terrycho/dev/workspace/objectdetection/models/slim

테스팅

설치가 제대로 되었는지를 확인하기 위해서 {Object Detection API 설치 디렉토리}/models/ 디렉토리에서 다음 명령을 실행해보자


% python object_detection/builders/model_builder_test.py


문제 없이 실행이 되었으면 제대로 설치가 된것이다.


사용하기

설치가 끝났으면 실제로 사용해 보자, Object Detection API를 인스톨한 디렉토리 아래 models/object_detection/object_detection_tutorial.ipynb 에 테스트용 노트북 파일이 있다. 이 파일을 주피터 노트북 (http://jupyter.org/)을 이용하여 실행해보자.
(원본 코드 https://github.com/tensorflow/models/blob/master/object_detection/object_detection_tutorial.ipynb)


실행을 하면 결과로 아래와 같이 물체를 인식한 결과를 보여준다.




이 중에서 중요한 부분은 Model Preparation이라는 부분으로,

여기서 하는 일은 크게 아래 3가지와 같다.

  • Export 된 모델 다운로드

  • 다운로드된 모델 로딩

  • 라벨맵 로딩


Export 된 모델 다운로드

Object Detection API는 여러가지 종류의 미리 훈련된 모델을 가지고 있다.

모델 종류는 https://github.com/tensorflow/models/blob/master/object_detection/g3doc/detection_model_zoo.md 를 보면 되는데,  다음과 같은 모델들을 지원하고 있다.  COCO mAP가 높을 수 록 정확도가 높은 모델인데, 대신 예측에 걸리는 속도가 더 느리다.


Model name

Speed

COCO mAP

Outputs

ssd_mobilenet_v1_coco

fast

21

Boxes

ssd_inception_v2_coco

fast

24

Boxes

rfcn_resnet101_coco

medium

30

Boxes

faster_rcnn_resnet101_coco

medium

32

Boxes

faster_rcnn_inception_resnet_v2_atrous_coco

slow

37

Boxes


모델은 *.gz 형태로 다운로드가 되는데, 이 파일안에는 다음과 같은 내용들이 들어있다.

  • Check point (model.ckpt.data-00000-of-00001, model.ckpt.index, model.ckpt.meta)
    텐서플로우 학습 체크 포인트로, 나중에, 다른 데이타를 학습 시킬때 Transfer Learning을 이용할때, 텐서플로우 그래프에 이 체크포인트를 로딩하여, 그 체크포인트 당시의 상태로 학습 시켜놓을 수 있다. 이 예제에서는 사용하지 않지만, 다른 데이타를 이용하여 학습할때 사용한다.

  • 학습된 모델 그래프 (frozen_inference_graph.pb)
    학습이 완료된 그래프에 대한 내용을 Export 해놓은 파일이다. 이 예제에서는 이 모델 파일을 다시 로딩하여 Prediction을 수행한다.

  • Graph proto (pgrah.pbtxt)


기타 파일들

이외에도 기타 다른 파일들이 있는데, 다른 파일들은 이미 Object Detection API 안에 이미 다운로드 되어 있다.

  • 라벨맵
    라벨맵은 {Object Detection API 설치 디렉토리}/models/object_detection/data  디렉토리 안에 몇몇 샘플 모델에 대한 라벨맵이 저장되어 있다. 라벨맵은 모델에서 사용한 분류 클래스에 대한 정보로 name,id,display_name 식으로 정의되며, name은 텍스트 라벨, id는 라벨을 숫자로 표현한 값 (반드시 1부터 시작해야 한다.), display_name은 Prediction 결과를 원본 이미지에서 인식한 물체들을 박스처리해서 출력하는데 이때 박스에 어떤 물체인지 출력해주는 문자열에 들어가는 텍스트 이다.
    여기서 사용한 라벨맵은 mscoco_label_map.pbtxt 파일이 사용되었다.

  • 학습 CONFIG 파일
    모델 학습과 예측에 사용되는 각종 설정 정보를 저장한 파일로 위에서 미리 정의된 모델별로 각각 다른 설정 파일을 가지고 있으며 설정 파일의 위치는  {Object Detection API 설치 디렉토리}/models/object_detection/samples/configs 에 {모델명}.config 에 저장되어 있다.


다운로드된 모델과 라벨맵 로딩

위에서 많은 파일이 다운되고 언급되었지만 예측 (Prediction)에는 학습된 그래프 모델을 저장한 frozen_inference_graph.pb 파일과, 분류 라벨이 저장된 mscoco_label_map.pbtxt 두 개만 사용된다.


다음 코드 부분에서 모델을 다운 로드 받고, 모델 파일과 라벨 파일의 경로를 지정하였다.


# What model to download.

MODEL_NAME = 'ssd_mobilenet_v1_coco_11_06_2017'

MODEL_FILE = MODEL_NAME + '.tar.gz'

DOWNLOAD_BASE = 'http://download.tensorflow.org/models/object_detection/'


# Path to frozen detection graph. This is the actual model that is used for the object detection.

PATH_TO_CKPT = MODEL_NAME + '/frozen_inference_graph.pb'


# List of the strings that is used to add correct label for each box.

PATH_TO_LABELS = os.path.join('data', 'mscoco_label_map.pbtxt')


NUM_CLASSES = 90


그리고 마지막 부분에 분류 클래스의 수를 설정한다. 여기서는 90개의 클래스로 정의하였다.

만약에 모델을 바꾸고자 한다면 PATH_TO_CKPT를 다른 모델 파일로 경로만 변경해주면 된다.


다음으로  frozen_inference_graph.pb  로 부터 모델을 읽어서 그래프를 재생성하였다.


detection_graph = tf.Graph()

with detection_graph.as_default():

 od_graph_def = tf.GraphDef()

 with tf.gfile.GFile(PATH_TO_CKPT, 'rb') as fid:

   serialized_graph = fid.read()

   od_graph_def.ParseFromString(serialized_graph)

   tf.import_graph_def(od_graph_def, name='')


나머지 부분은 이미지를 읽어서, 로딩된 모델을 이용하여 물체를 Detection 하는 코드이다.


여기까지 간단하게 Tensorflow Object Detection API를 설치 및 사용하는 방법에 대해서 알아보았다.

다음 글에서는 다른 데이타로 모델을 학습해서 예측하는 부분에 대해서 알아보도록 하겠다.


참고 자료





저작자 표시 비영리
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

CloudML을 이용하여 예측하기

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


지난글 (http://bcho.tistory.com/1189) 에서 학습된 모델을 *.pb 파일 포맷으로 Export 하였다. 그러면 이 Export 된 모델을 이용하여 예측 (prediction)을 하는 방법에 대해서 알아보겠다. 앞글에서도 언급했듯이, 예측은 Google CloudML을 이용한다.

전체 코드를 https://github.com/bwcho75/facerecognition/blob/master/CloudML%20Version/face_recog_model/%2528wwoo%2529%2BML%2BEngine%2Bprediction.ipynb 를 참고하기 바란다.

Export된 모델을 CloudML에 배포하기

학습된 모델을 CloudML에 배포하기 위해서는 export된 *.pb 파일과 variables 폴더를 구글 클라우드 스토리지 ( GCS / Google Cloud Storage) 에 업로드해야 한다.

아니면 학습때 모델 Export를 GCS로 시킬 수 도 있다.


아래는 terrycho-face-recog-export 라는 GCS 버킷아래 /export 디렉토리에, export 된 *.pb 파일과 variables 폴더가 저장된 모습이다.


다음 구글 클라우드 콘솔에서 ML Engine을 선택하여, Models 메뉴를 고른다. 이 메뉴는 모델을 배포하고 Prediction을 해주는 기능이다.



Models 화면으로 들어오면 Create Model 버튼이 나온다. 이 버튼을 이용해서 모델을 생성한다.





모델 생성시에 아래와 같이 단순하게 모델이름을 넣어주면된다.




모델 이름을 넣어준후에, 해당 모델에 실제 Export된 모델 파일을 배포해줘야 하는데, CloudML은 버전 기능을 제공한다. 그래서 아래 그림과 같이 Create Version 버튼을 눌러서 새로운 버전을 생성한다.





Create Version 메뉴에서는 Name에 버전명을 쓰고, Source에는 Export된 *.pb 파일과 variables 폴더가 저장된 GCS 경로를 선택한다.



아래는 terrycho-face-recog-export 버킷을 선택한 후, 그 버킷안에 export 폴더를 선택하는 화면이다.



선택을 해서 배포를 하면 아래와 같이 v7 버전이름을 모델이 배포가 된다.


배포된 모델로 예측 (Prediction)하기

그러면 배포된 모델을 사용해서 예측을 해보자. 아래가 전체코드이다.


from googleapiclient import discovery

from oauth2client.client import GoogleCredentials

import numpy

import base64

import logging


from IPython.display import display, Image


cropped_image = "croppedjolie.jpg"

display(Image(cropped_image))


PROJECT = 'terrycho-ml'

MODEL_NAME = 'face_recog'

MODEL_VERSION ='v7'



def call_ml_service(img_str):

   parent = 'projects/{}/models/{}/versions/{}'.format(PROJECT, MODEL_NAME,MODEL_VERSION)

   pred = None


   request_dict = {

       "instances": [

           {

               "image": {

                   "b64": img_str

               }

           }

       ]

   }


   try:

       credentials = GoogleCredentials.get_application_default()

       cloudml_svc = discovery.build('ml', 'v1', credentials=credentials)

       request = cloudml_svc.projects().predict(name=parent, body=request_dict)

       response = request.execute()

       print(response)

       #pred = response['predictions'][0]['scores']

       #pred = numpy.asarray(pred)


   except Exception, e:

       logging.exception("Something went wrong!")


   return pred



# base64 encode the same image

with open(cropped_image, 'rb') as image_file:

   encoded_string = base64.b64encode(image_file.read())


# See what ML Engine thinks

online_prediction = call_ml_service(encoded_string)


print online_prediction


코드를 살펴보면

       credentials = GoogleCredentials.get_application_default()

       cloudml_svc = discovery.build('ml', 'v1', credentials=credentials)


에서 discovery.build를 이용해서 구글 클라우드 API 중, ‘ML’ 이라는 API의 버전 ‘v1’을 불러왔다. CloudML 1.0 이다. 다음 credentials는 get_application_default()로 디폴트 credential을 사용하였다.

다음으로, CloudML에 request 를 보내야 하는데, 코드 윗쪽으로 이동해서 보면


def call_ml_service(img_str):

   parent = 'projects/{}/models/{}/versions/{}'.format(PROJECT, MODEL_NAME,MODEL_VERSION)

   pred = None


   request_dict = {

       "instances": [

           {

               "image": {

                   "b64": img_str

               }

           }

       ]

   }


를 보면 request body에 보낼 JSON을 request_dict로 정의하였다. 이때, 이미지를 “b64”라는 키로 img_str을 넘겼는데, 이 부분은 이미지 파일을 읽어서 base64 스트링으로 인코딩 한 값이다.

request = cloudml_svc.projects().predict(name=parent, body=request_dict)


다음 request 를 만드는데, 앞에서 선언한 cloudml_svc객체를 이용하여 prediction request 객체를 생성한다. 이때 parent 에는 모델의 경로가 들어가고 body에는 앞서 정의한 이미지가 들어있는 JSON 문자열이 된다.


   parent = 'projects/{}/models/{}/versions/{}'.format(PROJECT, MODEL_NAME,MODEL_VERSION)


Parent에는 모델의 경로를 나타내는데, projects/{프로젝트명}/models/{모델명}/versions/{버전명} 형태로 표현되며, 여기서는 projects/terrycho-ml/models/face_recog/versions/v7 의 경로를 사용하였다.


이렇게 request 객체가 만들어지면 이를 request.execute()로 이를 호출하고 결과를 받는다.

       response = request.execute()

       print(response)


결과를 받아서 출력해보면 다음과 같은 결과가 나온다.




2번째 라벨이 0.99% 확률로 유사한 결과가 나온것을 볼 수 있다. 라벨 순서 대로 첫번째가 제시카 알바, 두번째가 안젤리나 졸리, 세번째가 니콜 키드만, 네번째가 설현, 다섯번째가 빅토리아 베컴이다.


이제 까지 여러회에 걸쳐서 텐서플로우를 이용하여 CNN 모델을 구현하고, 이 모델을 기반으로 얼굴 인식을 학습 시키고 예측 시키는 모델 개발까지 모두 끝 맞췄다.


실제 운영 환경에서 사용하기에는 모델이 단순하지만, 여기에 CNN 네트워크만 고도화하면 충분히 사용할만한 모델을 개발할 수 있을 것이라고 본다. CNN 네트워크에 대한 이론 보다는 실제 구현하면서 데이타 전처리 및 학습과, 학습된 모델의 저장 및 이를 이용한 예측 까지 전체 흐름을 설명하기 위해서 노력하였다.


다음은 이 얼굴 인식 모델을 실제 운영환경에서 사용할만한 수준의 품질이 되는 모델을 사용하는 방법을 설명하고자 한다.

직접 CNN 모델을 만들어도 되지만, 얼마전에, 발표된 Tensorflow Object Detection API (https://github.com/tensorflow/models/tree/master/object_detection)는 높은 정확도를 제공하는 이미지 인식 모델을 라이브러리 형태로 제공하고 있다. 다음 글에서는 이 Object Detection API를 이용하여 연예인 얼굴을 학습 시키고 인식하는 모델을 개발하고 학습 및 예측 하는 방법에 대해서 알아보도록 하겠다.



저작자 표시 비영리
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

TFRecord


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


텐서플로우를 접하게 다 보면 필히 만나는 부분이 텐서플로우 학습 데이타 포맷인 TFRecord라는 파일 포맷이다. 마침 얼굴 인식 모델을 이번에는 텐서플로우에서 미리 개발되어 제공되는 물체 인식 API인 Tensorflow Object Detection API를 사용해서 얼굴을 학습시켜보려고 하니 데이타 포맷을 TFRecord 포맷으로 변경해야 한다. 그래서, TFRecord 파일을 만들어보고, 테스트를 위해서 데이타 내용도 직접 읽는 코드를 작성해보았다. (전체 코드는 https://github.com/bwcho75/objectdetection/tree/master/tfrecord 에 다.)

TFRecord 파일 포맷이란

TFRecord 파일은 텐서플로우의 학습 데이타 등을 저장하기 위한 바이너리 데이타 포맷으로, 구글의 Protocol Buffer 포맷으로 데이타를 파일에 Serialize 하여 저장한다.

CSV 파일에서와 같이 숫자나 텍스트 데이타를 읽을때는 크게 지장이 없지만, 이미지를 데이타를 읽을 경우 이미지는 JPEG나 PNG 형태의 파일로 저장되어 있고 이에 대한 메타 데이타와 라벨은 별도의 파일에 저장되어 있기 때문에, 학습 데이타를 읽을때 메타데이타나 라벨용 파일 하나만 읽는 것이 아니라 이미지 파일도 별도로 읽어야 하기 때문에, 코드가 복잡해진다.


또한 이미지를 JPG나 PNG 포맷으로 읽어서 매번 디코딩을 하게 되면, 그 성능이 저하되서 학습단계에서 데이타를 읽는 부분에서 많은 성능 저하가 발생한다.


이와 같이 성능과 개발의 편의성을 이유로 TFRecord 파일 포맷을 이용하는 것이 좋다.


그러면 간단한 예제를 통해서 TFRecord 파일을 쓰고 읽는 방법에 대해서 알아보도록 하자

본 예제는 http://warmspringwinds.github.io/tensorflow/tf-slim/2016/12/21/tfrecords-guide/ 글과 https://github.com/tensorflow/models/blob/master/object_detection/g3doc/using_your_own_dataset.md 글을 참고하였다.


TFRecord 파일 생성

TFRecord 파일 생성은 tf.train.Example에 Feature를 딕셔너리 형태로 정의한 후에, tf.train.Example 객체를 TFRecord 파일 포맷 Writer인 tf.python_io.TFRecordWriter를 통해서 파일로 저장하면 된다.


다음 코드를 보자, 이 코드는 Tensorflow Object Detection API를 자신의 데이타로 학습시키기 위해서 데이타를 TFRecord 형태로 변환하여 저장하는 코드의 내용이다.

이미지를 저장할때 사물의 위치를 사각형 좌표로 지정하고 저장한다.


def create_cat_tf_example(encoded_image_data):


 height = 1032

 width = 1200

 filename = 'example_cat.jpg'

 image_format = 'jpg'


 xmins = [322.0 / 1200.0]

 xmaxs = [1062.0 / 1200.0]

 ymins = [174.0 / 1032.0]

 ymaxs = [761.0 / 1032.0]

 classes_text = ['Cat']

 classes = [1]


 tf_example = tf.train.Example(features=tf.train.Features(feature={

     'image/height': dataset_util.int64_feature(height),

     'image/width': dataset_util.int64_feature(width),

     'image/filename': dataset_util.bytes_feature(filename),

     'image/source_id': dataset_util.bytes_feature(filename),

     'image/encoded': dataset_util.bytes_feature(encoded_image_data),

     'image/format': dataset_util.bytes_feature(image_format),

     'image/object/bbox/xmin': dataset_util.float_list_feature(xmins),

     'image/object/bbox/xmax': dataset_util.float_list_feature(xmaxs),

     'image/object/bbox/ymin': dataset_util.float_list_feature(ymins),

     'image/object/bbox/ymax': dataset_util.float_list_feature(ymaxs),

     'image/object/class/text': dataset_util.bytes_list_feature(classes_text),

     'image/object/class/label': dataset_util.int64_list_feature(classes),

 }))

 return tf_example


저장되는 내용은 이미지의 높이와 너비 (height,weight), 파일명 (filename), 인코딩 포맷 (format), 이미지 바이너리 (encoded), 이미지내에서 물체의 위치를 가르키는 사각형 위치 (xmin,ymin,xmax,ymax) 와 라벨 값등이 저장된다.


코드를 유심이 살표보면 생각보다 이해하기어렵지 않다.

tf.train.Example 객체를 만들고 이때 인자로 features에 TFRecord에 저장될 갚들의 목록을 딕셔너리 형태로 저장한다.

이때 저장되는 데이타의 이름과 값을 지정해야 하는데


'image/height': dataset_util.int64_feature(height),


를 보면 'image/height' 이 데이타의 이름이 되고, dataset_util.int64_feature(height), 가 height 값을 텐서플로우용 리스트형으로 변형하여 이를 학습용 피쳐 타입으로 변환하여 저장한다.

이 예제는 Object Detection API의 일부이기 때문에, dataset_util이라는 모듈을 사용했지만, 실제로 이 함수의 내부를 보면  tf.train.Feature(int64_list=tf.train.Int64List(value=values)) 로 구현이 되어 있다.


다음 이렇게 생성된 tf.train.Example 객체를 tf.python_io.TFRecordWriter 를 이용해서 다음과 같이 파일에 써주면 된다.

   writer = tf.python_io.TFRecordWriter(tfrecord_filename)

   writer.write(tf_example.SerializeToString())


다음은 코드 전체이다.


import tensorflow as tf

from PIL import Image

from object_detection.utils import dataset_util


def create_cat_tf_example(encoded_image_data):


 height = 1032

 width = 1200

 filename = 'example_cat.jpg'

 image_format = 'jpg'


 xmins = [322.0 / 1200.0]

 xmaxs = [1062.0 / 1200.0]

 ymins = [174.0 / 1032.0]

 ymaxs = [761.0 / 1032.0]

 classes_text = ['Cat']

 classes = [1]


 tf_example = tf.train.Example(features=tf.train.Features(feature={

     'image/height': dataset_util.int64_feature(height),

     'image/width': dataset_util.int64_feature(width),

     'image/filename': dataset_util.bytes_feature(filename),

     'image/source_id': dataset_util.bytes_feature(filename),

     'image/encoded': dataset_util.bytes_feature(encoded_image_data),

     'image/format': dataset_util.bytes_feature(image_format),

     'image/object/bbox/xmin': dataset_util.float_list_feature(xmins),

     'image/object/bbox/xmax': dataset_util.float_list_feature(xmaxs),

     'image/object/bbox/ymin': dataset_util.float_list_feature(ymins),

     'image/object/bbox/ymax': dataset_util.float_list_feature(ymaxs),

     'image/object/class/text': dataset_util.bytes_list_feature(classes_text),

     'image/object/class/label': dataset_util.int64_list_feature(classes),

 }))

 return tf_example


def read_imagebytes(imagefile):

   file = open(imagefile,'rb')

   bytes = file.read()


   return bytes

   

def main():

   print ('Converting example_cat.jpg to example_cat.tfrecord')

   tfrecord_filename = 'example_cat.tfrecord'

   bytes = read_imagebytes('example_cat.jpg')

   tf_example = create_cat_tf_example(bytes)


   writer = tf.python_io.TFRecordWriter(tfrecord_filename)

   writer.write(tf_example.SerializeToString())


main()


참고로 이 예제는 앞에서도 언급하였듯이 Object Detection API에 대한 의존성을 가지고 있기 때문에 일반적인 텐서플로우 개발환경에서는 실행이 되지 않는다. Tensorflow Object Detection API 를 인스톨해야 dataset_util 를 사용할 수 있기 때문에 Object Detection API 설치가 필요하다.

만약에 Object Detection API 설치 없이 TFRecord Writer를 짜보고 싶은 경우에는 http://warmspringwinds.github.io/tensorflow/tf-slim/2016/12/21/tfrecords-guide/ 문서에 예제가 간단하게 잘 정리되어 있으니 참고하기 바란다.

TFRecord에서 데이타 읽기

데이타를 읽는 방법도 크게 다르지 않다. 쓰는 순서의 반대라고 보면 되는데, TFReader를 통해서 Serialized 된 데이타를 읽고, 이를 Feature 목록을 넣어서 파싱한 후에, 파싱된 데이타셋에서 각 피쳐를 하나하나 읽으면 된다.


코드를 보자


def readRecord(filename_queue):

   reader = tf.TFRecordReader()

   _,serialized_example = reader.read(filename_queue)

   

   #'''

   keys_to_features = {

       'image/height': tf.FixedLenFeature((), tf.int64, 1),

       'image/width': tf.FixedLenFeature((), tf.int64, 1),

       'image/filename': tf.FixedLenFeature((), tf.string, default_value=''),

       #'image/key/sha256': tf.FixedLenFeature((), tf.string, default_value=''),

       'image/source_id': tf.FixedLenFeature((), tf.string, default_value=''),

       'image/encoded': tf.FixedLenFeature((), tf.string, default_value=''),

: (중략)

   }

   

   features = tf.parse_single_example(serialized_example,features= keys_to_features)

   

   height = tf.cast(features['image/height'],tf.int64)

   width = tf.cast(features['image/width'],tf.int64)

   filename = tf.cast(features['image/filename'],tf.string)

   source_id = tf.cast(features['image/source_id'],tf.string)

   encoded = tf.cast(features['image/encoded'],tf.string)

: (중략)

   return height,width,filename,source_id,encoded,image_format


TFRecoderReader를 이용하여 파일을 읽는데, 파일을 직접읽지 않고 filename_queue를 이용해서 읽는다. 코드 전체를 보면, 이 큐는

filename_queue = tf.train.string_input_producer([tfrecord_filename])

로, 파일 이름 목록을 가지고 리턴하는 string_input_producer를 사용하였다.

파일을 읽으면 데이타는 직렬화 된 상태로 리턴이 되어 serialized_example 에 저장된다.

이를 각 개별 피쳐로 디코딩 하기 위해서 피쳐 목록을 keys_to_features 딕셔너리에 저장한다.

이때, 각 피쳐의 이름과, 타입을 정의한다.

다음은 ‘image/height’ 피쳐를 정의하여 int 64 타입으로 읽어드리는 부분이다.


       'image/height': tf.FixedLenFeature((), tf.int64, 1),


피쳐 목록과, 데이타 타입은 TFRecord 파일을 쓸때 사용한 이름과 데이타 타입을 그대로 사용하면 된다.

피쳐 목록이 정의되었으면


   features = tf.parse_single_example(serialized_example,features= keys_to_features)


를 통해서 피쳐를 파싱해낸다. 파싱된 피쳐는 features에 딕셔너리 형태로 저장된다.

다음 리턴 받은 텐서를 각 변수에 저장한다. 이때 타입 캐스팅을 해서 저장한다. (이미 타입을 맞춰서 데이타를 꺼냈기 때문에, 별도의 캐스팅은 필요없지만 확실히 하기 위해서 캐스팅을 한다.)

다음은 ‘image/height’ 를 피쳐를 배열에서 뽑아서, int64 타입으로 변환하여 height 에 저장하는 부분이다.


   height = tf.cast(features['image/height'],tf.int64)


리턴값은 텐서가 되는데, 이 값을 출력하는 코드를 보자

당연히 텐서이기 때문에 Session 을 시작해야 하는데, 먼저 파일에서 데이타를 읽기 위해서 filename queue를 정의한다.

    filename_queue = tf.train.string_input_producer([tfrecord_filename])

다음 filename_queue를 인자로 넘겨서 height,source_id 등의 값을 *.tfrecord 파일에서 읽어서 텐서로 리턴 받는다.


    height,width,filename,source_id,encoded,image_format = readRecord(filename_queue)


다음 세션을 시작하고, readRecord 에서 리턴된 값을 받아온다.         vheight,vwidth,vfilename,vsource_id,vencoded,vimage_format = sess.run([height,width,filename,source_id,encoded,image_format])


전체 코드는 https://github.com/bwcho75/objectdetection/tree/master/tfrecord/reader.py 를 참고하기 바란다.


마지막으로 받은 값을 화면에 출력한다.



간단하게 tfRecord 파일 포맷으로 학습용 데이타를 쓰는 방법을 알아보았다. 텐서플로우 코드가 간단해 지고 성능에 도움이 되는 만큼 데이타 전처리 단계에서 가급적이면 학습 데이타를 tfrecord 타입으로 바꿔서 학습하는 것을 권장한다. (특히 이미지 데이타!!)


참고 자료


저작자 표시 비영리
신고
크리에이티브 커먼즈 라이선스
Creative Commons License
 

티스토리 툴바