[카카오 개발자 콘퍼런스] 발표: 모종훈·오형석 / 글: 이가람
01. 지식그래프 : 카카오미니와 검색 적용 소개 (발표: 남기훈 / 글: 김동현)
02. 눈으로 듣는 음악 추천 시스템 (발표: 최규민 / 글: 김태훈)
03. 이미지로 이미지 검색하기 (발표: 이주영 / 글: 이가람)
04. 딥러닝을 활용한 뉴스 메타 태깅 (발표: 김기도 / 글: 김규형)
05. 딥러닝을 이용한 실시간 인코딩 효율 최적화 (발표: 여욱형 / 글: 정소영)
06. 카카오 봇 플랫폼 소개 (발표: 황지수 / 글: 이형남)
07. 카카오가 가지고 있는 음성처리 기술 (발표: 노재근 / 글: 이형남)
08. 딥러닝을 이용한 얼굴 인식 (발표: 신종주 / 글: 김동현)
09. TOROS N2 (발표: 김성진 / 글: 김태훈)
10. 텐서플로로 OCR 개발해보기: 문제점과 문제점과 문제점 (발표: 모종훈·오형석 / 글: 이가람)
11. S2Graph와 GraphQL (발표: 윤도영 / 글: 김규형)
12. AI시대에 맞는 서비스 개발(발표: 이석영 / 글: 정소영)
외국어로 쓰여진 메뉴판의 글자를 번역해주는 기능이 있다면 편리하지 않을까? 광학 문자 인식기(optical character recognition, OCR)는 사람이 쓰거나 기계로 인쇄한 글자 이미지를 텍스트로 변환하여 인식하는 기술을 말한다. OCR 연구는 번역기와는 달리 데이터의 제약이 적은 장점을 가지고 있다. 렌더링(rendering)하고 싶은 텍스트(text), 폰트(font), 변환(transformation)만 정해주면 데이터를 얼마든지 합성하여 생성해 낼 수 있기 때문이다.
모델을 개발할 때 어떤 모델과 하이퍼 파라미터(hyper parameter)를 사용할지 결정하는 것보다 개발하고 있는 모델을 학습시키는 프로그램이 잘 동작하는가 파악하는 것이 더 중요한 과제이다. 즉, 테스트를 하는 것이 가장 중요하다. 모델을 개발하면서 가장 고통스러운 순간은 다음 세 가지 경우가 있다.
3위 - 모델 빌드(build)는 성공하는데 데이터만 넣으면 동작하지 않는 경우: 이는 조금만 디버깅(debugging)하다 보면 쉽게 처리된다.
2위 - 모델을 학습시키는데 데이터의 반 정도까지 돌다가 갑자기 동작하지 않는 경우: MNIST(Modified National Institute of Standards and Technology database) 데이터로 학습하는 과정에서 배치(batch) 사이즈가 30이면 동작하고 64면 돌다가 멈추는 현상이 있다. 학습 데이터의 수가 6만 개이기 때문에 배치 사이즈가 30인 경우는 개수가 나누어 떨어지지만 64인 경우 나누어 떨어지지 않게 된다. 결국 남는 데이터에 대해 작은 크기의 배치가 들어오게 되고 배치 사이즈가 64로 가정된 그래프에 대해 문제가 발생한다.
1위 – 데이터도 모델도 이상이 없는데 결과가 모호하게 나오는 경우: 주어진 데이터에 대해 업샘플링(upsampling)할 때 리셰이프(reshape)를 잘못하게 되면 차원(dimension)이 동일하더라도 모델의 성능이 좋지 않고 예상한 결과가 나오지 않게 된다.
이러한 문제들을 미리 해결하기 위해서 테스트가 반드시 필요하다. 모델을 만드는 텐서플로(tensorflow) 코드도 하나의 프로그램이다. 소프트웨어 개발 및 테스트를 위한 모든 방법을 적용할 수는 없지만 모델을 개발하는 과정에서 테스트와 디버깅에 조금만 신경 쓰면 훨씬 더 빠르게 문제를 파악할 수 있다.
텐서플로는 훌륭한 머신러닝(machine learning) 라이브러리(library)이지만 모델을 개발하는 과정에서 디버깅이 힘든 원인을 제공하기도 한다. 텐서플로는 그래프를 정의하고 정의한 그래프에 데이터를 흘려 보내는 구조를 가지고 있다. 특정 노드(node)에 대해 프린트(print)를 해보면 해당 노드의 디스크립션(description)만 파악할 수 있을 뿐 어떤 값(value)이 실제로 지나가는지 알 수 없다는 한계를 가지고 있다. tf.Print를 통해 그래프 안에 노드를 만들어서 입력 값으로 들어갈 것을 지정하면 해당 노드에서 데이터가 지나가면서 갖는 값을 출력 값으로 얻을 수 있다.
코드가 복잡해지면 함수화를 통해서 역할을 나누고 각 함수들에 대한 테스트 케이스를 만들어 확인한다. 모델을 만들 때 여러 함수를 통해 모듈(module)을 만들고 각각의 함수들이 가져야 할 입력 값과 출력 값을 확인하면 자신의 역할에 따라 정확하게 동작하고 있는지 파악할 수 있다. 하지만 이렇게 만들어진 모델 내부의 모듈들은 초깃값이 임의로 설정(random initialization)되기 때문에 반드시 똑같은 결과를 얻을 것이라 보장할 수는 없지만 차원(dimension) 체크 정도는 쉽게 가능하다는 이점이 있다.
즉, tf.Print는 모델이 동작하다가 멈출 때 의심이 가는 부분에 대해 디버깅을 하기 위해 사용하고, tf.test.TestCase는 모듈을 하나씩 만들어가면서 단계적으로 사용하면 나중에 발생할 수도 있는 문제를 미리 해결할 수 있다.
알고리즘이 동작하지 않으면 작은 크기의 데이터부터 시작해본다. OCR 개발의 경우 데이터 셋을 난이도에 따라 세 단계로 나누었다. 첫 번째 단계로는 가장 간단한 데이터로 적은 양의 단어, 하나의 폰트, 흰색 배경, 변환이 적용되지 않은 글자 이미지를 사용한다. 이 데이터를 사용해서 잘 동작하면 두 번째 단계로 영어 단어, 여러 개의 폰트, 단일 배경, 변환이 적용된 글자 이미지를 사용하고 마지막 세 번째 단계로 한글 및 영어 단어, 배경 추가, 변환이 적용된 데이터를 사용한다. 이런 방식의 사이클(cycle)을 통해 가장 단순한 데이터부터 실제로 원하는 단계의 복잡한 데이터까지 순차적으로 실험하면서 모델의 파라미터(parameter) 및 구조를 변경하며 진행하면 효율적인 작업이 될 수 있다.
모델을 개발할 때 필요한 과정을 정리하면 다음과 같다.
1. 기본 모델을 만들 때
- 모델의 각 모듈들을 간단히 테스트할 수 있는 테스트 케이스를 만들자.
- 데이터 셋을 작게 유지해서 실험해보자.
- 런타임(runtime) 도중 오류가 나는 경우 tf.Print로 출력해보자.
2. 기본 모델이 동작하기 시작한다면
- 여러 모델 구조와 데이터 셋으로 실험하면서 최적의 데이터를 찾자.
- 물론 새로 만드는 모듈들은 테스트 케이스를 만들자.
OCR 모델은 1. 합성곱 신경망(convolutional neural network, CNN), 2. 순환 신경망(recurrent neural network, RNN), 3. CTC(connectionist temporal classification) 알고리즘, 이렇게 3가지 요소로 구성되어 있다.
1. CNN
- CNN은 이미지의 특징 중에서 글자 예측에 유용한 정보를 자동으로 추출할 수 있다는 장점이 있다(feature extraction). 사람의 두뇌 중에서 일차 시각 피질(primary visual cortex)에 해당하는 부위는 외부로부터의 시각적인 정보에 반응하는데 자극의 각도에 따라 민감하게 반응하는 세포(cell)의 종류가 다르다. 인공신경망(artificial neural network)에 이러한 방식을 유사하게 구현한 것이 CNN이다. 커널(kernel)에 따라 이미지 내 특정 속성의 자극에 강하게 반응하며 형태 정보를 반영하고 추출된 특징에 따라 모델이 파라미터를 학습하게 된다.
2. RNN
- RNN은 CNN의 제한된 수용장(receptive field)의 범위를 확장시켜서 이미지로부터 더 좋은 특징(feature)들을 추출할 수 있게 한다. CNN의 경우 전체 이미지 중 특정 부분만 반영하기 때문에 전체 이미지에 대한 정보를 담을 수 없다는 한계가 있다. 예를 들어, 알파벳 m의 경우 부분적인 정보만 가지고는 이 문자를 i로 판단할지 m으로 판단할지 구분할 때 어려움이 발생하게 된다. 하지만 RNN을 사용하면 주변의 다른 글자 정보들을 종합적으로 이용해서 해당 글자의 예측을 높이는 방향으로 모델 튜닝(tuning)이 가능하다.
3. CTC 알고리즘
- 글자를 인식할 때 한 글자에 해당하는 이미지가 어디서부터 어디까지인지 간격의 규칙을 파악하는 것은 어렵다. 설명 변수와 예측 변수 사이의 관계 정렬이 되어있지 않을 때 CTC 알고리즘을 사용한다. CTC 알고리즘은 글자 이미지에 대해 임의로 분할된 각 영역마다 그 영역을 반영하는 특징에 대해 확률적으로 글자를 하나씩 예측한다. 이 알고리즘은 목적함수인 p(Y|X)를 쉽게 계산할 수 있도록 도와준다. 글자 이미지가 없는 영역은 빈 칸(blank)으로 처리하고 각 단계 별로 예측된 중복 글자들을 합쳐 디코딩(decoding)하여 최종 텍스트를 얻는다. 하지만 최종적으로 디코딩 되는 결과가 유일하지 않을 수도 있으며 가능한 모든 조합에 대해 다이나믹 프로그래밍(dynamic programming)을 사용하기 때문에 처리하는 데 많은 시간이 소요되는 단점이 있다.
모델 구조를 개발하는 과정에서 최대 목표는 모델의 성능과 속도를 향상시키는 것이다. 하지만 이를 상용화하여 서비스를 제공하는 경우 사용자들이 얼마나 편리하게 사용할 수 있는가에 대해서 고려할 때 둘 중 어느 것에 더 중점을 둘 것인가에 대한 기준을 설정해야 한다. 성능과 속도를 향상시키고자 할 때 트레이드 오프(trade off)가 있을 수 밖에 없는데, 많은 양의 정보를 제한된 장비로 처리하는 서비스 상황에서는 빠른 속도가 성능보다 중요할 수도 있다.
모델 내부 구조 중 다음 상태(state)를 위해 RNN은 필연적으로 그 전 상태의 정보가 필요하기 때문에 병렬 계산이 불가능하여 속도에 영향을 미친다. 또한 CTC는 각 영역별 단계마다 독립적으로 글자를 예측하기 때문에 이전 단계에서 예측된 정보를 사용하지 않는 단점을 가지고 있다(conditional independence assumption). 또한 글자를 예측하기 위해서는 최소한으로 필요한 글자 수 이상의 단계 수가 필요하기 때문에 이미지 사이즈를 줄이는 것에 대한 제약이 따른다. 즉, 특징 맵(feature map)의 사이즈가 클 수 밖에 없다.
이러한 단점을 보완하여 모델의 속도를 높이기 위해 RNN(LSTM, long short-term memory models)과 CTC 알고리즘을 사용하지 않는 방향으로 여러 실험이 진행되었다. CTC의 약점을 극복하기 위해 인코더-디코더에 어텐션 기법(encoder-decoder with attention)을 적용하거나 RNN(LSTM)을 없애기 위해 팽창된 컨볼루션(dilated convolution)과 셀프 어텐션(self-attention)이 사용되었다. 다양한 시도의 결과에서 속도는 조금 향상되었지만 정확도가 희생되어 기존 모델의 성능을 능가하진 못한 한계를 보였다. 하지만 이렇게 여러 모델을 활용해 실험을 진행할 때의 시행착오에도 불구하고 OCR 모델은 개선의 여지가 충분히 있을 것으로 생각된다.
※ 카카오 OCR 기술에 대한 자세한 내용은 카카오 AI 리포트 2018년 12월호(겨울호)를 통해서 만나 보실 수 있습니다.
본문에 삽입된 슬라이드 자료는 'if kakao 2018' 개발자 콘퍼런스 발표자료에서 인용하였습니다.
(출처: https://if.kakao.com)
콘퍼런스 발표 | 모종훈 simiro.m@kakaocorp.com, 오형석 hulk.oh@kakaocorp.com
글 | 이가람 garam24@snu.ac.kr
서울대학교에서 수학과 통계학을 전공하고 최근 머신러닝, 딥러닝, 블록체인에 관심을 갖고 공부하며 그 접점을 찾으려 하고 있습니다. 궁금한 게 많은 문과적인 이과생이고 세상을 조금이라도 더 나은 곳으로 만드는 데 기여하길 바라며 노력하고 있습니다.