본문 바로가기
machine learning

Char based Text to CNN 한글 적용하기

by 유주원 2018. 4. 10.

Text의 각 Character들을 (한글로 치면 하나의 음절) 하나의 특징데이터로 삼고 CNN을 이용해서 분류작업을 해보기로 했다.


기본 Text to CNN에 대한 간략한 설명.


 http://www.wildml.com/2015/11/understanding-convolutional-neural-networks-for-nlp/


대략적으로 설명하자면 각각의 text내의 word 들을 vector로 변환한 후 해당 vector 값들을 나열해서 2차원 이미지 배열 처럼 만든다.

예를들어 I like coffee 라는 text가 있다면 I, like, coffee 이 단어들을 각각 3차원 벡터로 변환을 하고 ([1,0,0], [0,1,0], [0,0,1]) 변환된 벡터를 나열하면 3 * 3의 행렬이 생성된다. 이 형렬 값은 결국엔 가로 3 x 세로 3의 이미지 데이터와 같은 입력 양식을 가지게 되고 해당 값을 입력으로 CNN을 돌려서 분류 작업을 하는 것이다.


참고로 위의 설명은 char 기반이 아니라 text의 word 기반으로 특징데이터를 잡는다.


아래는 char 기반 cnn의 각 언어별 코드


tensorflow : https://github.com/scharmchi/char-level-cnn-tf


keras : https://github.com/blues-lin/Char-level-CNN-for-Text-Classification-in-Keras


pytorch : https://github.com/srviest/char-cnn-pytorch


나는 pytorch를 이용해서 작업해 보기로 한다.


일단 위의 코드를 다운받아서 돌려보기로 했다. 

돌리는 건 정말 간단하다. 아래와 같이 실행시키면 train이 되고 모델이 만들어 진다.


$> python train.py


아래와 같은 모델 layer에 대한 description이 쫙 나타나고, batch로 training 시작





일단 여기서 궁금한 거 하나!!

왜 1d convolution을 돌렸을까??? 어짜피 2차원이니깐 2d로 돌려도 되지 않을까??


여기에 대한 내 생각은 x축, y축 고려없이 한 축으로만 돌리려고 한거 아닐까?? 

이미지의 경우 주변 픽셀이 영향을 미치지만 문장의 경우 앞뒤 관계만 고려하면 되니깐 구지 2d로 돌리지 않아도 되는게 아닐까 생각한다.


이미지의 경우 가로, 세로, (RGB) 이렇게 3차원이라 2d convolution을 여러개 실행 하는 것이고, 지금 현재 위의 char based cnn 은 특징 데이터, 길이 이렇게 2차원 데이터라 1차원 배열이 길이 만큼 늘어선 형태라고 생각하면 된다. 그래서 1d conv를 진행하는 것이다. 

(위에는 뻘소리....)


흠흠.. 어쨌든 결과적으로 아래와 같은 precision과 recall 값이 나타났다. epoch 12까지 돌린 수치의 결과이며 아마 더 돌리면 prec나 recall이 더 좋아질 것 같긴 하다.



pytorch로 되어 있는 코드의 경우 영어를 기준으로 작성되었기 때문에 한글을 입력으로 받을 경우 encoding 문제에 대한 처리가 필요하다.

encode('utf-8'), decode('utf-8') 에 대한 적절한 조합을 함으로써 이를 해결할 수가 있다.


그 다음으로 문제되는 상황이 있는데, 바로 ont-hot encoding issue 이다.

영어같은 경우엔 대소문자 각각이 26자이고 normalize를 적용하면 되기 때문에 26개의 차원만 가지면 ont-hot encoding을 충분히 적용할 수 있다.

하지만 한글 같은 경우엔 자소의 조합으로 생성되는 단어가 많기 때문에, 하나하나 각각을 one-hot encoding으로 처리하기에는 벡터 차원의 수가 너무 많다.

두 가지 방법을 고려해봤는데, 첫번째는 입력 단어에 대해 자소를 분리한 후, 자소 단위로 특징 데이터를 만드는 것이 첫번째 방법이다.

ex ) 나는 학교에 간다 -> ㄴㅏㄴㅡㄴㅎㅏㄱㄱㅛㅇㅔㄱㅏㄴㄷㅏ


one-hot은 자음과 모음만 구성하면 된다.


두 번째로 생각한 방법은 pretrained model을 이용하는 것이다. 하지만 과연 음절까지 vector로 pretrain을 제공하는 모델이 있을까??

바로 fasttext가 각광받는 이유 중의 하나가 여기에 있다고 봐도 될 것 같다.


아래 url로 들어가면 각 나라별 pretrained된 vector 값들을 확인할 수가 있다.


https://github.com/facebookresearch/fastText/blob/master/pretrained-vectors.md


아래와 같이 작성하면 fasttext의 pretrained model을 불러 올 수가 있다.



이제 이렇게 변환된 vector 값을 이용해서 char base CNN을 적용해 보자.

참고로 위의 예제 이외에도 ㄱ이나 ㄴ도 당연하게 fasttext pretrained 모델에서 벡터값이 형성이 된다.


돌리다 보니 생기게 된 에러 문구...


Assertion 't >=0 && t < n_classes` failed.


classification 할때 먼가가 안맞아서 생기는 것 같은데 도통 모르겠다...


google group에서 찾은 링크 하나가 나에게 희망이 되길...


https://groups.google.com/forum/#!topic/torch7/ktvhX4QI6pc


요약하자면 label을 0부터 주지말고 1부터 줘.. 이 말인데.. 정말 이것 때문일까..

(와 !@##$@!@#$#@ 이거 때문인거 맞네...)