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


Archive»


 
 

얼굴 인식 모델을 CNN 네트워크를 이용하여 학습을 시키고 있는데, 지금까지 최대 정확도가 60% 정도밖에 나오지 않는다.

오히려 dropout을 0.5 비율로 적용했더니, 정확도가 30% 정도로 떨어져 버렸다.


원인을 찾던중에 네트워크보다는 학습 데이타에 문제가 있을 것으로 추정된다.

학습 데이타의 양이 그리 많지 않은데 (4 클래스, 사람당 120장), 데이타가 깔끔하지 않다.

아래와 같은 데이타가 문제가 되는데

  • 회전각이 너무 큰경우
  • 선글라스를 쓴 경우
  • 화장이나 염색
  • 사진이 그레이 스케일 처리가 되어 있거나 특정 색상이 들어간경우 


그래서 데이타 클랜징 모듈에서 구글 클라우드 비젼 API를 이용하여 회전각이 20도 가 넘은 경우 제외하고, 라벨 인식을 이용하여 선글라스가 있을 경우도 데이타에서 제외했다. 다음은 학습후에 효과를 적는걸로

이렇게 튜닝 한 결과, 검증 정확도가 대략 80% 내외가 나온다.
이번에는 데이타를 더 모아서, 인당 200장 정도의 데이타로 학습을 시도해서 정확도를 높여볼 예정인데.

가만 보니, 얼굴 표정에 따라서도 오차가 꽤 있을 것으로 보인데, 심하게 찡그리는 얼굴들. 만약에 표정변화도를 비전 API에서 감정도로 받아들인후에, 이를 기반으로 범위를 정해서 필터 아웃 시키는 것을 만들어볼 필요가 있을듯.



데이타가 모자라서 웹에서 크라울링을 하고 나니, 중복되는 이미지가 많아져서 학습 데이타가 또 정확해지지 않는 현상이 생겼다.

그래서 크롭된 이미지에서 MD5 해쉬를 추출하여 저장하고, 이를 비교하는 방식으로 개선을 하였지만, 웹의 이미지의 특성상 같은 이미지라도 올리는 사람이 편집을해서 색이나 명도등을 바꾼 경우에는 같은 이미지이기는 하지만, 바이너리 데이타상으로는 다른 이미지이기 때문에 중복 체크 로직에 걸리지 않고 통과하는 현상을 보였다.





머신러닝 모델 개발 삽질기

빅데이타/머신러닝 | 2017.04.24 14:27 | Posted by 조대협

머신러닝 모델 개발 삽질 경험기


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


딥러닝을 공부하고 CNN 모델을 기반으로 무언가를 만들어보겠다는 생각에, 해외 유명 연예인 얼굴 사진을 가져다가 분류하는 얼굴 인식 모델을 만들어 보기로 하였다.

아직도 진행중이지만, 많은 시행 착오를 겪었는데 같은 시행 착오를 겪지 않고 경험을 공유하기 위해서 겪었던 시행 착오들을 정리해 본다.

학습 데이타 확보 및 분류

먼저 학습용 데이타를 수집 하는 것이 가장 문제 였다. 인터넷에서 사진을 모아서 학습 데이타로 사용해도 되겠지만, 아무래도 저작권 및 초상권 문제가 있고, 일일이 사진을 하나씩 받아서 수집하거나 또는 별도의 수집기를 만드는 것도 부담이 되었다.

그래서 찾은 것이 pubfig라는 셀럽 얼굴 데이타인데 http://www.cs.columbia.edu/CAVE/databases/pubfig/

상용 목적이 아니라 연구용 목적이면 사용이 가능하다. 이 데이타는 파일 URL, 셀럽 이름 형태로 라벨링이 되어 있기 때문에, 학습에 적합하리라고 생각하고, 이 파일을 기반으로 데이타를 수집하였다.


여기서 생긴 문제는, 이 데이타가 오래된 데이타라서 존재하지 않는 파일이 다수 있었고, 이 경우 파일을 저장하고 있는 사이트에서, 404 Not found와 같은 이미지를 리턴하였기 때문에, 이를 필터링해야 하였고, 같은 사진이 중복되서 오는 문제등이 있었기 때문에,상당량을 일일이 필터링을 해야 했다.


그리고, 사진상에, 여러 얼굴이 있는 이미지가 많았기 때문에, VISION API로 얼굴을 인식해서 얼굴 사진만 잘라낼 요량이었기 때문에, 독사진만을 일일이 보고 골라내야 했다. 나중에 생각해보니 VISION API로 얼굴이 한명만 인식이 되는 사진만 필터링을 했으면 됐을텐데. 불필요한 작업이 많았다.

라벨을 문자열로 쓴 문제

학습 데이타에 대한 라벨을 생성할때, 괜히 가독성을 높힌다고 라벨을 문자열로 해서 각 사람의 이름을 사용하였다.

CNN에서 마지막은 Softmax는 matrix이기 때문에, 라벨 문자열을 나중에 list.indexOf를 이용하여 배열로 변경할 예정이었는데, 파이썬에서는 쉽게 될지 몰라고, 텐서플로우 코드에서는 이 과정이 쉽지 않았다.

그래서..

결국은 라벨 데이타를 문자열이 아니라, 0~44의 int 값으로 재 생성한후에,


   batch_label_on_hot=tf.one_hot(tf.to_int64(batch_label),

       FLAGS.num_classes, on_value=1.0, off_value=0.0)


tf.one_hot 함수를 이용하여, 1*45 행렬로 바뀌어서 사용하였다.

학습용 및 검증용 데이타를 초기에 분류하지 않았던 문제

학습데이타를 준비할때, 학습 데이타를 학습용과 검증용으로 따로 분류를 해놨어야 하는데, 이 작업을 안해서, 결국 모델을 만들다가 다시 학습 데이타를 7:3 비율로 학습 데이타와 검증용 데이타로 분류하는 작업을 진행하였다.

학습 데이타의 분포가 골고르지 못했던 문제

사진을 모으는 과정에서 필터링 되서 버려지는 데이타가 많았고, 원본 데이타 역시 사람별로 사진 수가 고르지 못했기 때문에, 결과적으로 모여진 학습 데이타의 분포가 사람별로 고르지 못했다.

학습데이타가 많은 셀럽은 200~250장, 적은 사람은 50장으로 편차가 컸다.


이로 인해서 첫번째 모델의 학습이 끝난 후에, 모델을 검증해보니, 학습 데이타를 많이 준 사람으로 대부분 분류를 해냈다. 47개의 클래스 약 6000장의 사진으로 5시간 학습 시킨 결과, 예측을 검증하는 과정에서 90%이상을 모두 브래드피트로 인식해내는 문제가 생겼다. (내 맥북이 브레드피트를 좋아하는가??)


그래서 결과적으로 학습데이타와 검증 데이타를 클래스별로 분포를 같게 하기 위해서, 클래스당 약 50 장의 샘플 사진으로 맞춰서 예측 결과가 편중되는 현상을 해결하려고 하였다.

학습 순서가 클래스별로 된 문제

클래스별 학습 데이타의 양을 균일하게 맞췄음에도 불구하고, 모델의 학습 결과가 특정 클래스들로 편향되는 현상이 발생하였다.

이는 학습을 시킬때, 골고루 학습을 시켜야 하는데, 학습 데이타를 순서대로 학습을 시켰기 때문에 발생한 문제이다. 즉 풀어서 말하자면, “브래드 피트"를 20번 학습 시키고, “안젤리나 졸리"를 20분 학습 시키고, “브루스 윌리스”를 20번 학습 시켜서 모델이 첫 학습데이타 쪽으로 편향되는 현상이 발생한것인데, 이를 해결하려면 학습 데이타를 랜덤으로 만들어서 학습시켜야 한다.

예를 들어 “브래드 피트”,”안젤리나 졸리",”브루스 윌리스",”안젤리나 졸리",”브루스 윌리스", ”안젤리나 졸리",“브래드 피트” …. 이런식으로 말이다.

즉 코드 상에서 배치 데이타를 읽어올때 셔플 처리를 하면되는데 이를 위해서 데이타를 읽는 부분을 다음과 같이 변경 하였다.


def get_input_queue(csv_file_name,num_epochs = None):

   train_images = []

   train_labels = []

   for line in open(csv_file_name,'r'):

       cols = re.split(',|\n',line)

       train_images.append(cols[0])

       # 3rd column is label and needs to be converted to int type

       train_labels.append(int(cols[2]) )

                           

   input_queue = tf.train.slice_input_producer([train_images,train_labels],

                                              num_epochs = num_epochs,shuffle = True)

   

   return input_queue


get_input_queue 함수에, csv_file_name을 인자로 주면, 이 파일을 한줄 단위로 읽어서, 첫번째는 파일명, 세번째는 라벨로 읽은 후에, 각각 train_images와  train_lables에 각각 string과 int 형으로 저장한다

그 다음이 배열을 가지고 tf.train.slice_input_producer를 사용하면 배열에서 데이타를 읽어 드리는 input queue 를 생성하는데, 이때 인자로 shuffle = True로 주면 데이타를 리턴 할때 순차적으로 리턴하지 않고 셔플된 형태로 랜덤하게 리턴한다.


def read_data(input_queue):

   image_file = input_queue[0]

   label = input_queue[1]

   

   image =  tf.image.decode_jpeg(tf.read_file(image_file),channels=FLAGS.image_color)

   

   return image,label,image_file


다음으로, 이 큐를 이용하여 이미지 파일명과, 라벨을 읽어서 이미지 파일 데이타(텐서)와 라벨로 읽는 코드를 read_data라는 함수로 구현하였다. 입력값은 input_queue인데, input queue에서 데이타를 읽으면 첫번째는 이미지 파일명, 두번째는 라벨이 되는데, 첫번째 파일명을 tf.image.decode_jpeg함수를 이용하여 텐서로 읽은후, 읽은 이미지 데이타와 라벨을 리턴하였다.


def read_data_batch(csv_file_name,batch_size=FLAGS.batch_size):

   input_queue = get_input_queue(csv_file_name)

   image,label,file_name= read_data(input_queue)

   image = tf.reshape(image,[FLAGS.image_size,FLAGS.image_size,FLAGS.image_color])

   

   batch_image,batch_label,batch_file = tf.train.batch([image,label,file_name],batch_size=batch_size)

                                                      #,enqueue_many=True)

   batch_file = tf.reshape(batch_file,[batch_size,1])


   batch_label_on_hot=tf.one_hot(tf.to_int64(batch_label),

       FLAGS.num_classes, on_value=1.0, off_value=0.0)

   return batch_image,batch_label_on_hot,batch_file


마지막으로, 배치로 데이타를 읽는 함수 부분에서 앞에 정의한 get_input_queue와 read_data 함수를 이용하여 데이타를 shuffle 된 상태로 읽은 후에, tf.train.batch를 이용하여 일정한 개수 (배치) 형태로 리턴하도록 하였다.


그 결과 예측 결과가 한쪽으로 편향되는 현상을 없앨 수 는 있었다.

샘플 데이타의 부족

데이타 편향 현상은 잡았지만, 클래스의 수(45)에 대비하여, 샘플데이타의 수(클래스당 50개)로 부족하여, 학습을 계속 진행해도 cross entropy 함수는 4~7 사이에서 왔다갔다 하면서 더 이상 0으로 수렴하지 않았고 정확도되 0~35% 사이를 왔다갔다 하면서 수렴을 하지 않았다.


그래서, 학습 이미지의 색이나, 방향등을 변경하는 방법으로 데이타를 뻥튀기 하려고 하는데, 이 부분은 아직 작업중.

그외에 자잘한 삽질

모 그외에도 엄청 여러가지 삽질을 하고 있다. 그래도 모델 하나 제대로 만들어봐야 겠다는 생각에 끝까지 우격다짐으로 진행하고 있지만, 학습을 돌다가 스크린 세이버나, 절전 모드로 들어가서 학습이 중단된 사례. 모델을 개발하다가 중간에 텐서 플로우 버전이 올라가서 코드를 수정한 일. 맥에서 개발하다가 윈도우 머신에 GPU로 바꿨더니, 파이썬 2.7이 아니라 파이썬 3.5만 지원을 해서, 2.7 코드를 모두 다시 고친일등.


머신러닝이 과학이나 수학보다 노가다라는데, 몸소 느끼는 중.


연예인 얼굴 인식 서비스를 만들어보자 #1 - 학습데이타 준비하기


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


CNN 에 대한 이론 공부와 텐서 플로우에 대한 기본 이해를 끝내서 실제로 모델을 만들어보기로 하였다.

CNN을 이용한 이미지 인식중 대중적인 주제로 얼굴 인식 (Face recognition)을 주제로 잡아서, 이 모델을 만들기로 하고 아직 실력이 미흡하여 호주팀에서 일하고 있는 동료인 Win woo 라는 동료에게 모델과 튜토리얼 개발을 부탁하였다.


이제 부터 연재하는 연예인 얼굴 인식 서비스는 Win woo 가 만든 코드를 기반으로 하여 설명한다. (코드 원본 주소 : https://github.com/wwoo/tf_face )

얼굴 데이타를 내려 받자

먼저 얼굴 인식 모델을 만들려면, 학습을 시킬 충분한 데이타가 있어야 한다. 사람 얼굴을 일일이 구할 수 도 없고, 구글이나 네이버에서 일일이 저장할 수 도 없기 때문에, 공개된 데이타셋을 활용하였는데, PubFig (Public Figures Face Database - http://www.cs.columbia.edu/CAVE/databases/pubfig/) 를 사용하였다.



이 데이타셋에는 약 200명에 대한 58,000여장의 이미지를 저장하고 있는데, 이 중의 일부만을 사용하였다.

Download 페이지로 가면, txt 파일 형태 (http://www.cs.columbia.edu/CAVE/databases/pubfig/download/dev_urls.txt) 로 아래와 같이


Abhishek Bachan 1 http://1.bp.blogspot.com/_Y7rzCyUABeI/SNIltEyEnjI/AAAAAAAABOg/E1keU_52aFc/s400/ash_abhishek_365x470.jpg 183,60,297,174 f533da9fbd1c770428c8961f3fa48950
Abhishek Bachan 2 http://1.bp.blogspot.com/_v9nTKD7D57Q/SQ3HUQHsp_I/AAAAAAAAQuo/DfPcHPX2t_o/s400/normal_14thbombaytimes013.jpg 49,71,143,165 e36a8b24f0761ec75bdc0489d8fd570b
Abhishek Bachan 3 http://2.bp.blogspot.com/_v9nTKD7D57Q/SL5KwcwQlRI/AAAAAAAANxM/mJPzEHPI1rU/s400/ERTYH.jpg 32,68,142,178 583608783525c2ac419b41e538a6925d


사람이름, 이미지 번호, 다운로드 URL, 사진 크기, MD5 체크섬을 이 필드로 저장되어 있다.

이 파일을 이용하여 다운로드 URL에서 사진을 다운받아서, 사람이름으로된 폴더에 저장한다.

물론 수동으로 할 수 없으니 HTTP Client를 이용하여, URL에서 사진을 다운로드 하게 하고, 이를 사람이름 폴더 별로 저장하도록 해야 한다.


HTTP Client를 이용하여 파일을 다운로드 받는 코드는 일반적인 코드이기 때문에 별도로 설명하지 않는다.

본인의 경우에는 Win이 만든 https://github.com/wwoo/tf_face/blob/master/tf/face_extract/pubfig_get.py 코드를 이용하여 데이타를 다운로드 받았다.

사용법은  https://github.com/wwoo/tf_face 에 나와 있는데,


$> python tf/face_extract/pubfig_get.py tf/face_extract/eval_urls.txt ./data

를 실행하면 ./data 디렉토리에 이미지를 다운로드 받아서 사람 이름별 폴더에 저장해준다.

evals_urls.txt에는 위에서 언급한 dev_urls.txt 형태의 데이타가 들어간다.


사람 종류가 너무 많으면 데이타를 정재하는 작업이 어렵고, (왜 어려운지는 뒤에 나옴) 학습 시간이 많이 걸리기 때문에, 약 47명의 데이타를 다운로드 받아서 작업하였다.

쓰레기 데이타 골라내기

데이타를 다운받고 나니, 아뿔사!! PubFig 데이타셋이 오래되어서 없는 이미지도 있고 학습에 적절하지 않은 이미지도 있다.


주로 학습에 적절하지 않은 데이타는 한 사진에 두사람 이상의 얼굴이 있거나, 이미지가 사라져서 위의 우측 그림처럼, 이미지가 없는 형태로 나오는 경우인데, 이러한 데이타는 어쩔 수 없이 눈으로 한장한장 다 걸러내야만 하였다.

아마 이 작업이 가장 오랜 시간이 걸린 작업이 아닐까도 한다. 더불어서 머신러닝이 정교한 수학이나 알고리즘이 아니라 노가다라고 불리는 이유를 알았다.

얼굴 추출하기

다음 학습에 가능한 데이타를 잘 골라내었으면, 학습을 위해서 사진에서 얼굴만을 추출해내야 한다. 포토샵으로 일일이 할 수 없기 때문에 얼굴 영역을 인식하는 API를 사용하기로한다. OPEN CV와 같은 오픈소스 라이브러리를 사용할 수 도 있지만 구글의 VISION API의 경우 얼굴 영역을 아주 잘 잘라내어주고, 코드 수십줄만 가지고도 얼굴 영역을 알아낼 수 있기 때문에 구글 VISION API를 사용하였다.

https://cloud.google.com/vision/




VISION API ENABLE 하기

VISION API를 사용하기 위해서는 해당 구글 클라우드 프로젝트에서 VISION API를 사용하도록 ENABLE 해줘야 한다.

VISION API를 ENABLE하기 위해서는 아래 화면과 같이 구글 클라우드 콘솔 > API Manager 들어간후




+ENABLE API를 클릭하여 아래 그림과 같이 Vision API를 클릭하여 ENABLE 시켜준다.




SERVICE ACCOUNT 키 만들기

다음으로 이 VISION API를 호출하기 위해서는 API 토큰이 필요한데, SERVICE ACCOUNT 라는 JSON 파일을 다운 받아서 사용한다.

구글 클라우드 콘솔에서 API Manager로 들어간후 Credentials 메뉴에서 Create creadential 메뉴를 선택한후, Service account key 메뉴를 선택한다



다음 Create Service Account key를 만들도록 하고, accountname과 id와 같은 정보를 넣는다. 이때 중요한것이 이 키가 가지고 있는 사용자 권한을 설정해야 하는데, 편의상 모든 권한을 가지고 있는  Project Owner 권한으로 키를 생성한다.


(주의. 실제 운영환경에서 전체 권한을 가지는 키는 보안상의 위험하기 때문에 특정 서비스에 대한 접근 권한만을 가지도록 지정하여 Service account를 생성하기를 권장한다.)




Service account key가 생성이 되면, json 파일 형태로 다운로드가 된다.

여기서는 terrycho-ml-80abc460730c.json 이름으로 저장하였다.


예제 코드

그럼 예제를 보자 코드의 전문은 https://github.com/bwcho75/facerecognition/blob/master/com/terry/face/extract/crop_face.py 에 있다.


이 코드는 이미지 파일이 있는 디렉토리를 지정하고, 아웃풋 디렉토리를 지정해주면 이미지 파일을 읽어서 얼굴이 있는지 없는지를 체크하고 얼굴이 있으면, 얼굴 부분만 잘라낸 후에, 얼굴 사진을 96x96 사이즈로 리사즈 한후에,

70%의 파일들은 학습용으로 사용하기 위해서 {아웃풋 디렉토리/training/} 디렉토리에 저장하고

나머지 30%의 파일들은 검증용으로 사용하기 위해서 {아웃풋 디렉토리/validate/} 디렉토리에 저장한다.


그리고 학습용 파일 목록은 다음과 같이 training_file.txt에 파일 위치,사람명(라벨) 형태로 저장하고

/Users/terrycho/traning_datav2/training/wsmith.jpg,Will Smith

/Users/terrycho/traning_datav2/training/wsmith061408.jpg,Will Smith

/Users/terrycho/traning_datav2/training/wsmith1.jpg,Will Smith


검증용 파일들은 validate_file.txt에 마찬가지로  파일위치와, 사람명(라벨)을 저장한다.

사용 방법은 다음과 같다.

python com/terry/face/extract/crop_face.py “원본 파일이있는 디렉토리" “아웃풋 디렉토리"

(원본 파일 디렉토리안에는 {사람이름명} 디렉토리 아래에 사진들이 쭈욱 있는 구조라야 한다.)


자 그러면, 코드의 주요 부분을 살펴보자


VISION API 초기화 하기

  def __init__(self):

       # initialize library

       #credentials = GoogleCredentials.get_application_default()

       scopes = ['https://www.googleapis.com/auth/cloud-platform']

       credentials = ServiceAccountCredentials.from_json_keyfile_name(

                       './terrycho-ml-80abc460730c.json', scopes=scopes)

       self.service = discovery.build('vision', 'v1', credentials=credentials)


초기화 부분은 Google Vision API를 사용하기 위해서 OAuth 인증을 하는 부분이다.

scope를 googleapi로 정해주고, 인증 방식을 Service Account를 사용한다. credentials 부분에 service account key 파일인 terrycho-ml-80abc460730c.json를 지정한다.


얼굴 영역 찾아내기

다음은 이미지에서 얼굴을 인식하고, 얼굴 영역(사각형) 좌표를 리턴하는 함수를 보자


   def detect_face(self,image_file):

       try:

           with io.open(image_file,'rb') as fd:

               image = fd.read()

               batch_request = [{

                       'image':{

                           'content':base64.b64encode(image).decode('utf-8')

                           },

                       'features':[{

                           'type':'FACE_DETECTION',

                           'maxResults':MAX_RESULTS,

                           }]

                       }]

               fd.close()

       

           request = self.service.images().annotate(body={

                           'requests':batch_request, })

           response = request.execute()

           if 'faceAnnotations' not in response['responses'][0]:

                print('[Error] %s: Cannot find face ' % image_file)

                return None

               

           face = response['responses'][0]['faceAnnotations']

           box = face[0]['fdBoundingPoly']['vertices']

           left = box[0]['x']

           top = box[1]['y']

               

           right = box[2]['x']

           bottom = box[2]['y']

               

           rect = [left,top,right,bottom]

               

           print("[Info] %s: Find face from in position %s" % (image_file,rect))

           return rect

       except Exception as e:

           print('[Error] %s: cannot process file : %s' %(image_file,str(e)) )

 

VISION API를 이용하여, 얼굴 영역을 추출하는데, 위의 코드에서 처럼 image_file을 읽은후에, batch_request라는 문자열을 만든다. JSON 형태의 문자열이 되는데, 이때 image라는 항목에 이미지 데이타를 base64 인코딩 방식으로 인코딩해서 전송한다. 그리고 VISION API는 얼굴인식뿐 아니라 사물 인식, 라벨인식등 여러가지 기능이 있기 때문에 그중에서 타입을 ‘FACE_DETECTION’으로 정의하여 얼굴 영역만 인식하도록 한다.


request를 만들었으면, VISION API로 요청을 보내면 응답이 오는데, 이중에서 response 엘리먼트의 첫번째 인자 ( [‘responses’][0] )은 첫번째 얼굴은 뜻하는데, 여기서 [‘faceAnnotation’]을 하면 얼굴에 대한 정보만을 얻을 수 있다. 이중에서  [‘fdBoundingPoly’] 값이 얼굴 영역을 나타내는 사각형이다. 이 갑ㄱㅅ을 읽어서 left,top,right,bottom 값에 세팅한 후 리턴한다.


얼굴 잘라내고 리사이즈 하기

앞의 detect_face에서 찾아낸 얼굴 영역을 가지고 그 부분만 전체 사진에서 잘라내고, 잘라낸 얼굴을 학습에 적합하도록 같은 크기 (96x96)으로 리사이즈 한다.

이런 이미지 처리를 위해서 PIL (Python Imaging Library - http://www.pythonware.com/products/pil/)를 사용하였다.

   def crop_face(self,image_file,rect,outputfile):

       try:

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

           image = Image.open(fd)  

           crop = image.crop(rect)

           im = crop.resize(IMAGE_SIZE,Image.ANTIALIAS)

           im.save(outputfile,"JPEG")

           fd.close()

           print('[Info] %s: Crop face %s and write it to file : %s' %(image_file,rect,outputfile) )

       except Exception as e:

           print('[Error] %s: Crop image writing error : %s' %(image_file,str(e)) )

image_file을 인자로 받아서 , rect 에 정의된 사각형 영역 만큼 crop를 해서 잘라내고, resize 함수를 이용하여 크기를 96x96으로 조정한후 (참고 IMAGE_SIZE = 96,96 로 정의되어 있다.) outputfile 경로에 저장하게 된다.        


실행을 해서 정재된 데이타는 다음과 같다.


생각해볼만한점들

이 코드는 간단한 토이 프로그램이기 때문에 간단하게 작성했지만 실제 운영환경에 적용하기 위해서는 몇가지 고려해야 할 사항이 있다.

먼저, 이 코드는 싱글 쓰레드로 돌기 때문에 속도가 상대적으로 느리다 그래서 멀티 쓰레드로 코드를 수정할 필요가 있으며, 만약에 수백만장의 사진을 정재하기 위해서는 한대의 서버로 되지 않기 때문에, 원본 데이타를 여러 서버로 나눠서 처리할 수 있는 분산 처리 구조가 고려되어야 한다.

또한, VISION API로 사진을 전송할때는 BASE64 인코딩된 구조로 서버에 이미지를 직접 전송하기 때문에, 자칫 이미지 사이즈들이 크면 네트워크 대역폭을 많이 잡아먹을 수 있기 때문에 가능하다면 식별이 가능한 크기에서 리사이즈를 한 후에, 서버로 전송하는 것이 좋다. 실제로 필요한 얼굴 크기는 96x96 픽셀이기 때문에 필요없이 1000만화소 고화질의 사진들을 전송해서 네트워크 비용을 낭비하지 않기를 바란다.


다음은 이렇게 정재한 파일들을 텐서플로우에서 읽어서 학습 데이타로 활용하는 방법에 대해서 알아보겠다.


grpc 설치하기

프로그래밍 | 2015.04.02 02:11 | Posted by 조대협

Google RPC 설치하기

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


지난 GRPC 소개에 이어서 오늘은 JAVA에서 GRPC를 사용하기 위한 설치 방법을 설명한다.


  • https://github.com/grpc/grpc-common/tree/master/java
  • https://github.com/grpc/grpc-common
  • https://github.com/grpc/grpc-common/blob/master/java/javatutorial.md
  • https://github.com/grpc/grpc-java


글들을 참고하였으며, 컴파일 환경 설정등을 위해서 생각보다 시간이 많이 소요된다. (삽질,Visual Studio 설치 포함 한 2~3시간 걸린듯)


grpc hello world / java





grpc-java 설치하기

https://github.com/grpc/grpc-java#how-to-build 를 참고


준비 : java 8, maven 3.2.x,gradle 2.3 필요


1. 코드 받기

 C:\dev\libs> git clone https://github.com/grpc/grpc-java


2. 관련 라이브러리 설치


1) Netty 4.1 설치

grpc-java는 Netty 4.1에 기반함. 아래절차에 따라서 설치한다.

cd C:\dev\libs\grpc-java>

$ git submodule update --init

$ cd lib/netty

$ mvn install -pl codec-http2 -am -DskipTests=true


2) Protocolbuf 3.0.0-alhpa-2 설치 (windows)

안타깝게도 알파버전이라 윈도우즈용 인스톨 바이너리가 없다. 소스 받아서 직접 컴파일해야 한다.

윈도우 환경에서는 C/C++ 컴파일러가 필요하니까는 간단하게 Visual Studio 무료 버전을 깔자 https://www.visualstudio.com/en-us/products/free-developer-offers-vs.aspx

(무료 버전 제공)

다음은 c:\dev\lib\protobuf에 설치 하는 순서이다.


C:\dev\libs>git clone https://github.com/google/protobuf.git


다음으로, C:\dev\libs\protobuf\vsprojects 에 들어가면 visual studio 프로젝트 파일이 있음

VC로 Release 빌드하면 됨. (이때 반드시, Release 모드로 빌드할것, Debug 모드로 빌드하면 나중에 grpc-java 빌드할때 링크에러남). Test 코드 빌드하다가 에러가 나는데 무시하자. 테스트 코드가 안들어가 있다.


빌드 후, C:\dev\libs\protobuf\vsprojects 아래에 readme.txt를 보고 따라할것


C:\dev\libs\protobuf\vsprojects\Release 에 빌드 결과가 생김

안에 protoc.exe가 생김



3. grpc-java 설치


위에서 만든 protoc.exe를 path가 있는 디렉토리에 복사하거나.

본인의 경우에는 위의 디렉토리 자체를 다 PATH에 걸어버렸다. (연관 라이브러리들이 있어서리)

다음으로 grpc-java를 설치하자


앞에서 받은 grpc-java 디렉토리로 가서

$ gradlew install -Pprotobuf.include=C:\dev\libs\protobuf\src  -Pprotobuf.libs=C:\dev\libs\protobuf\vsprojects\Release


여기까지 했으면 grpc 설치가 완료되었다. 실제로 동작하는지 확인하려면, 예제 코드를 돌려보면 되는데, 실행 방법은 다음과 같다. 


서버 실행

gradlew :grpc-examples:helloWorldServer -Pprotobuf.include=C:\dev\libs\protobuf\src  -Pprotobuf.libs=C:\dev\libs\protobuf\vsprojects\Release



클라이언트 실행

gradlew :grpc-examples:helloWorldClient -Pprotobuf.include=C:\dev\libs\protobuf\src  -Pprotobuf.libs=C:\dev\libs\protobuf\vsprojects\Release


실행시 위와 같이 protocol buf lib 위치와 소스 위치를 지정해야 하는데, 매번 지정하기 귀찮다면 다음과 같이 환경 변수로 넣어놓아도 된다.

Since specifying those properties every build is bothersome, you can instead create %HOMEDRIVE%%HOMEPATH%.gradle\gradle.properties with contents like:

protobuf.include=C:\\path\\to\\protobuf-3.0.0-alpha-2\\src

protobuf.libs=C:\\path\\to\\protobuf-3.0.0-alpha-2\\vsprojects\\Release


소프트웨어를 잘하고 싶으시면 개발자를 그만 뽑으세요.




<사진 : 태극기 휘날리며(영화)中>


간만의 포스팅입니다. 요즘 일도 너무 바쁘고 여유가 안생겨서, 그동안 포스팅을 거의 못했네요. 평소에 생각하던 내용인데, 요즘 들어 소프트웨어니, 서비스니 하면서 여기저기서 사람 뽑는 글들이 많아서 올려봅니다.


"소프트웨어를 잘하고 싶은데, 개발자를 뽑지 말라니??" 의아하게 생각하실지도 모르지만, 낚시 타이틀이 아니라 진정으로 드리고 싶은 이야기 입니다.

제가 해외 개발자들이나 엔지니어들과 일해봤을때, 한국 개발자가 실력적으로 그렇게 밀린다고 생각하지는 않습니다. 문제는 관리입니다.!!

아무리 똑똑한 개발자를 뽑아 놓는다 하더라도, 개발자들이 만들어야 할 소프트웨어의 구조를 잡을 아키텍트가 없고, 프로젝트를 위한 계획과 엔지니어에 대한 배치를 제대로 하지 못하면 개발은 제대로 이루어지지 않습니다.

좋은 아키텍트가 있고, 좋은 프로젝트 메니져와, 프로덕트 오너가 있는것은 두번째 조건이라고 생각합니다. 일단 있어야 합니다.

아키텍트가 기술적으로 실력이 떨어지더라도 아키텍트는 기술적 설계만이 본업이 아닙니다. 비지니스와 개발간을 연결하고 개발자간을 연결해서 전체 시스템에 대한 기술적인 그림을 보고 조율을 합니다.

프로젝트관리자 역시, 프로젝트 일정에 따라서 끊임없이 위험요소를 관리하고 우선순위를 조정해야 하며, 개발자원을 적절하게 투입해야 합니다.


즉 정리해서 말하면, 개발자보다는 제대로된 리더쉽을 갖추는 것이 중요합니다. 외부에서 좋은 리더쉽을 데리고올 수도있지만, 그런 리더쉽이 역할이 있는 팀 구조를 만드는 것이 선행되야하고 그 다음으로 그런 리더쉽을 가지고 있는 사람을 데려다가 배치해야 합니다.


국내 기업들이 소프트웨어를 강화하기 위해서 개발자 모시기에 여념이 없고, 내부적으로 개발자를 키우기 위한 프로그램도 진행하고, 뽑을때 미국 처럼 코딩 시험도 보는데.. 그건 그거고...

전쟁 나가는데 사병만 1000명 뽑으면 모합니까?? 통솔한 분대장도 필요하고 장군도 필요하고... 소총분대 분대장, 박격포 부대 분대장.. 기갑부대 분대장등 각 역할에 따라서 적절한 리더들을 잘 뽑는게 중요하지 않을까 싶습니다.


이제 개발자 그만 뽑으시고, 제대로된 program manager, product manager, architect,scrum master 등등 리더쉽 인력에 눈을 돌려봐야할 시기가 아닌가 싶습니다. 특히나 요즘 처럼 리모트 개발이 용이해지고 인건비 문제로 인해서 중국이나 인도 인력을 많이 사용하고 신기술은 미국에 있는 개발자들과 협업을 하는 지금 이러한 사람들을 잘 아울러서 관리하여 제대로된 소프트웨어를 만들어 낼 수 있는 조율자(Coordinator-코디네이터)의 역할이 앞으로 점점 더 중요해질 것 같습니다.


요즘 개발자 채용 트렌드를 보면 총든 병사들만 가지고 전쟁을 하려고 하는게 아닌가 싶습니다.... (인해전술도 아니고.. )