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


Archive»


 

'경험'에 해당되는 글 3

  1. 2017.04.24 머신러닝 모델 개발 삽질기
  2. 2016.11.01 첫번째 게임을 만들어 보다
  3. 2008.07.25 IT를 하면서 필요한것... (3)
 

머신러닝 모델 개발 삽질기

빅데이타/머신러닝 | 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 코드를 모두 다시 고친일등.


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


첫번째 게임을 만들어 보다

IT 이야기 | 2016.11.01 09:24 | Posted by 조대협

첫번째 게임을 만들어보다.


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


요즘 게임 개발이 워낙 인기 있는 분야이고, 유니티로 게임을 개발하기가 워낙 쉽다고 해서, 언젠가 한번 게임을 개발해봐야하겠다는 막연한 생각만 가지고 있었는데, 게임 로그 수집 및 분석을 테스트할 기회가 되서, 아예 게임을 만들어보기로 하였다.


유니티 개발환경의 편리함


대략 10월10일 부터 시작해서, 개발이 끝난게 대략 10월 말 경이니까는 2~3주 정도 걸린것 같다.

유니티 개발이 처음이라서, 책부터 사보고 남는 시간 짬짬이 개발을 했는데, 아마 집중해서 했으면 일주정도면 되지 않았을까 한다.


유니티로 게임을 개발하면서, 먼저 느낀것은 개발 환경이 참 잘 짜야져 있다는 것이다. 객체를 정의한 후, 각 객체에 객체를 컨트롤하기 위한 코드를 짜서, 객체에 드래그앤 드롭을 하면 코드가 적용되고, 각 객체를 Prefab이라는 형태로 쉽게 라이브러리 하여 다시 불러 쓸 수 가 있다. 또한 충돌 처리나, 지형에 따른 이동 처리등이 아주 쉽게 가능하다. 대학교때 다이렉트X를 이용해서 게임을 개발할때를 생각하면 정말 많이 쉬어졌다.




게임을 만들기 위한 사운드나 그래픽 에셋, 그리고 각종 특수 효과도 유니티 에셋 스토어에서 어렵지 않게 구할 수 있었다.


유니티는 멀티 플랫폼을 지원하는데, 같은 코드로 빌드 환경을 바꿔서 윈도우/맥 환경에서 부터 안드로이드,IOS용 게임 까지 쉽게 빌드가 가능하다.(거의 신세계와 같은 느낌)


전체적인 느낌은 게임 뿐 아니라, 일반 프로그래밍 환경이 궁극적으로 가야하는 환경이 아닌가 싶다. 멀티 플랫폼 지원, 에셋 스토어, 그리고 객체에 코드를 넣는 부분은 객체지향형의 개념을 가장 잘 구현한 케이스가 아닌가 싶다. (나중에 개발 플랫폼을 만든다면, 이 개념을 차용하고 싶다.)

유니티 개발 생태계

유니티로 개발하면서 재미있었던 점 중의 하나가 개발자 생태계가 아주 발전되어 있다. 왠만한 질문은 구글링을 하면 유니티 커뮤니티에 답이 대부분 있고, 유니티 개발환경이 아무래도 화면 위주다 보니, 글로 쓴 문서 보다는 동영상이 따라하기 훨씬 편리했는데, 유니티 튜토리얼 관련 컨텐츠가 유투브에 아주 풍부하였다.

또한 유니티에서 제공하는 튜토리얼 문서 역시 쉽고 체계적이었다.

아마 이렇게 유니티가 유행하게 된 요인중 하나는 플랫폼이 쉬울뿐 아니라, 개발자 생태계를 잘 가꾼 유니티 회사에 있지 않나 싶다.


게임 개발의 어려움


막상 게임을 개발해보니, 프로그래밍 자체 보다는 캐릭터의 배치, 시나리오의 작성, 난이도 조절, UX 등이 더 큰 어려움으로 다가왔다. 아무래도 사용자의 재미를 위주로 하는 애플리케이션이다 보니 코딩 이외에도 신경을 써야할 부분이 매우 많았다.


결론은

그래서 결론은, 게임 개발은 아무나 하는 것이 아니라는 것… 지금도 게임 개발하고 계시는 게임 개발자 분들 존경합니다.

유니티의 개발환경은 에셋 스토어와, 객체 지향형 개념등 한 단계 앞서 있는 개념으로 배울게 많다는 것. 그리고 개발 플랫폼이 메이져가 되기 위해서는 생태계 형성이 중요하고, 동영상 컨텐츠가 중요하다는 것 등이었다.






IT를 하면서 필요한것...

IT 이야기/IT와 사람 | 2008.07.25 08:50 | Posted by 조대협
언제 한번 시간 나면 정리할려고 했던건데..
마소에서도 요청이 왔었고....
후배 개발자들을 위해서 필요한것들...

VIew & Vision
보는 시야가 틀려져야 한다..
구멍가게 시스템만 개발하다 보면 구멍 가게에 필요한 비젼과 시야만을 가지기 때문에 발전할 수 없다.
한국 개발자들도 세계에서 맹활약하는 사람들이 많다. 결코 한국 엔지니어가 세계 시장에서 뒤떨어지지 않는다..
특유의 성실함과 집요함은 아마 세계 최고가 아닐까?

Passion
열정... 열정없이 하는 일이 재미있고 제대로 될리가 없다..
열정이 가장 중요하지 않을까? 하려고 하는 의지만 있다면 결국은 하게 된다.
연금 술사라는 책에서 나와 있듯이.. "우주는 자신이 간절히 바라는 방향으로 움직이게 된다."

Exprience
경험 역시 매우 중요하다. 특히 IT에서는 기술이나 지식도 중요하지만 이를 실제로 필드에 적용하기 위해서는 여러가지 RISK를 피해가기 위한 경험과 노하우가 중요하다.

Effort
그리고 노력...!!
'못하는 것은 용서해도 안하는 것은 용서 못한다.." 열심히 노력하고 하고자 하는 의지가 없다면 모든 일은 '입으로만 떠드는 것일뿐..' 실행력은 노력에서 나온다.

나중에 시간나면 제대로 글로 한번 정리해봐야 겠다..