기계는 사람의 말을 어떻게 이해할까? 워드 임베딩(Word embedding)

솔트룩스

인간인 우리가 대화, 서류, 채팅 등을 통해 일상적으로 사용하는 언어를 '자연어 (Natural language)'라고 합니다.

그리고 이 자연어를 컴퓨터가 이해하도록 데이터화해서 기계가 처리하는 방법에 대해 연구하는 것을 '자연어 처리(NLP)'라고 하죠. 저희 솔트룩스가 가장 자신 있는 분야이기도 합니다 :-)

특히 오늘은 자연어 처리 분야 중, 가장 보편적으로 사용되고 있으면서 간편하고 쉽게 접근할 수 있는 '워드 임베딩 (Word embedding)'에 대해서 살펴볼까 합니다.

자연어의 벡터화

인간이 사용하는 자연어는 말 그대로 '문자' 인 기호로 이루어져 있습니다.

컴퓨터는 기호를 이해할 수 없죠. 반드시 수학적으로 표현 가능하도록 '데이터화'가 되어야 합니다.

그 이유를 자연어로 상상하기엔 어려우니까 잠시 다른 예제를 들어보겠습니다.

특징이 다양한 생물 데이터

위 그림은 다양한 생물들을 표현하고 있습니다.

이 생물들을 어떻게 하면 분류할 수 있을까요?

각 생물마다 매우 다양한 특징들이 있겠지만, 저는 '다리 개수'와 '몸 크기', 두 가지 특성으로 분류를 한 번 해보도록 하겠습니다.

특징을 바탕으로 분류된 생물 데이터

이렇게 생물 데이터를 다리 개수와 몸 크기를 특징(feature)으로 사용해서, x-y로 이루어진 2차원 좌표평면에 위치시킬 수 있을 겁니다. 즉, 생물 데이터들이 2차원 벡터로 이루어진 벡터 데이터로 변환된 것이죠.

보시다시피, 어류의 경우엔 왼쪽에 치우쳐져 있고, 강아지나 코끼리 같은 동물들은 오른쪽에 치우치게 됩니다.

데이터를 좌표평면 위에 위치시키게 되면, 특징에 맞춰 군집(clustering)을 형성하게 되고, 새로운 데이터가 입력으로 들어갈 때, 어떤 군집과 더 유사한지 그 유사점을 찾을 수 있게 되죠.

이러한 과정의 핵심은 '특징 추출(feature extraction)'에 있습니다.

과거에는 사람이 직접 데이터를 관찰하고, 특징을 결정한 후에 분류를 실시하였습니다.

생물 데이터와 같이 특징이 확실한 경우에는 어느 정도 분류를 수행하는 데 무리가 없었습니다.

하지만, 자연어 분야에서는 특징 추출 과정이 무척 어려워집니다.

특징 추출과 분류가 어려운 자연어 데이터

그냥 문자와 기호로 이루어진 자연어를 어떤 기준으로 나눌 수 있을까요?

가장 간단한 방법은, 모든 자연어 문자들을 독립적인 숫자로 치환하는 겁니다.

저희 솔트룩스의 사명(Mission)인 아래 문장을 통해 살펴보겠습니다.

'세상 모든 사람이 자유롭게 지식 소통하는 세상'이라는 문장을 띄어쓰기를 기준으로 하여 나누면 총 6개의 어절로 분리할 수 있습니다.

이렇게 분리된 6개의 단어들을 '사전 (Vocab)'에 속해 있다고 합니다.

분리된 어절은 6개의 배열 데이터로 변환하되, 하나의 값만 1로, 나머지는 0으로 표현합니다.

이런 표현 방법을 '원 핫 인코딩 (One-hot encoding)'이라고 하죠 :-)

그리고 위 표에 '데이터'라고 표기되어 있는 6개의 배열을 6차원 벡터로 이루어진 '원 핫 벡터 (One-hot vector)'라고 합니다.

결과적으로 컴퓨터가 좋아하는 1과 0으로 자연어를 벡터화 하는데 성공했습니다! :-)

이제 새로운 문장이 들어올 때, 사전 속에 해당 단어가 존재한다면, 그 단어의 벡터로 치환해서 컴퓨터가 처리할 수 있겠죠?

그런데 문제는, 6차원의 벡터가 각 단어의 의미를 표현하고 있다고 보기는 어려울 겁니다.

Word2Vec

2013년, 구글의 미코로프는 word2vec이라고 하는 워드 임베딩 모델을 공개합니다.

(https://code.google.com/archive/p/word2vec/)

말 그대로, 단어(word)를 벡터로(to vector) 변환시켜주는 모델이죠.

어떤 원리로 동작하는지 아래 단어를 한번 볼까요?

두 단어가 무슨 뜻인지 알 수 있으신가요? :-)

위 단어는 아랍어로 쓰였는데, 저는 아랍어를 접해본 적이 없어서 전혀 뜻을 모르겠네요.

아마 컴퓨터가 자연어를 처음 보게 되면, 우리가 아랍어를 보듯이 그 의미를 유추해내기 어렵겠죠?

그럼 아래의 문장을 한번 살펴보겠습니다.

이제 알 수 없는 형태의 문자가 어떤 뜻인지 유추를 하실 수 있을 겁니다. :-)

왼쪽의 글자의 뜻은 강아지이고, 오른쪽 글자의 뜻은 고양이입니다.

만약, 강아지와 고양이라는 단어를 실제로는 모르더라도, 문장의 주변 단어를 보고 다양한 사실을 유추하실 수 있을 겁니다.

먼저 '짖었다'나 '울었다'와 같은 단어가 근처에 있는 것으로 보아, 어떤 동물이거나 생물을 뜻하는 단어라고 유추할 수 있겠죠?

마찬가지로, 멍멍!, 야옹! 과 같은 의성어 옆에 '짖었다'와 '울었다'가 있는 것으로 보아, '짖었다'와 '울었다'라는 대충 비슷한 의미를 내포하고 있다고 유추할 수 있을 것입니다.

Word2vec은 바로 이 아이디어를 이용합니다 :-)

기본적으로 word2vec은 간단한 신경망 구조로 이루어져 있는데요, 특정 단어를 입력으로 할 때, 그 단어의 원-핫 벡터를 입력으로 넣고, 주변 단어의 원-핫 벡터 값을 예측하는 방식으로 학습이 이루어집니다.

즉, 주변 단어의 원-핫 벡터 값과 신경망의 출력값이 차이가 난다면, 이 차이를 최소화하는 방향으로 신경망을 학습하는 것이죠.

이렇게 word2vec 학습을 거치고 나면, 각 단어마다 고유한 단어 벡터 (word vector)를 얻을 수가 있게 됩니다.

단어가 벡터로 표현이 되니까 비로소 좌표 평면 위에 위치시킬 수 있게 되겠죠?

프로그래밍 언어 중, Python과 gensim 라이브러리를 사용하시면, 매우 간단하게 word2vec을 학습해서 테스트해보실 수 있습니다 :-)

저는 100차원의 벡터 사이즈를 가지는 word2vec 모델을 학습해보도록 하겠습니다.

학습에는 대용량의 텍스트 데이터가 필요한데요! 여기서는 약간의 전처리를 가미한 한국어 위키피디아 데이터를 이용했습니다.

학습된 모델을 이용해 아래와 같이 입력하면, 특정 단어의 워드 벡터를 얻을 수 있습니다.

array([-0.17541541, -0.04150922, -0.6949256 , 0.2382443 , 0.63088024, -0.25842583, 0.59258497, 0.45911694,

0.24830624, -0.6868696 , 0.63933593, -0.39925617, 0.41687605, 0.10190477, 1.1934272 ,

....

0.49362758, 0.05030601, 0.38776514, -0.35022527, 0.25438496, -0.36755642, 0.519438 , 0.58914435, 0.5080435 ,

-0.19485532], dtype=float32)

참고로 저는 100차원으로 벡터 사이즈를 결정했기 때문에, '대한민국'이라는 단어에 대한 100차원 벡터를 얻을 수 있었습니다.

만들어진 벡터들이 단어의 의미를 이쁘게 표현하고 있는지 확인해볼까요?

100차원의 벡터는 차원이 너무 커서 눈으로 확인하기 어려우니, t-sne 기법(https://ratsgo.github.io/machine learning/2017/04/28/tSNE/) 을 사용해 100차원을 2차원으로 축소해서 좌표 평면 위에 나열해보겠습니다 :-)

단어 사전에 들어가 있는 약 40만 개의 단어들을 좌표 평면 위의 점으로 표현해보았습니다!

어떤 단어들은 자기들끼리 조금씩 뭉쳐져 있는 게 보이네요 :-)

좀 더 확대해 볼까요?

학교와 관련된 단어들이 서로 근접한 좌표 평면에 위치하게 되는 것을 확인할 수 있습니다.

이처럼 word2vec을 수행하고 나면, 비슷한 의미를 가지는 단어들은 서로 비슷한 좌표에 위치하게 되죠 :-)

단어들을 좌표로 표현하게 되면, 단어들을 대상으로 벡터 연산이 가능해집니다.

위 그림과 같이 '왕', '남자', '여왕', '여자'가 좌표 평면 위에 위치하고 있다고 가정할 때, [여왕 - 왕] 벡터에 [남자] 벡터를 더하면 '여자' 가 위치한 좌표에 도달하게 됩니다.

이렇게 [여왕 - 왕 + 남자] 와 같은 수식을 이용해 워드 임베딩이 잘 이루어졌는지 검사하는 방법을 'analogy'라고 표현하죠 :-)

Analogy를 체험해보고 싶으시면, http://word2vec.kr/search/ 사이트에 접속하시면 바로 결과를 확인해보실 수 있습니다.

아래는 학습한 모델로 수행한 analogy 테스트 결과입니다!

[대한민국 - 서울 + 일본] = [도쿄]

[대한민국 - 서울 + 러시아] = [모스크바]

[왕 - 남자 + 왕비] = [여자]

[할아버지 - 남자 + 할머니] = [여자]

[남동생 - 남성 + 여동생] = [여성]

...

생각보다 성능이 좋게 잘 나오네요 :-)

기계가 이해하는 한국어의 의미

자! 이제 이 word2vec 모델을 이용해 재밌는 테스트를 해볼까 합니다 :-)

[대한민국 - 서울 + 일본]의 결과가 '도쿄'로 나오는 건 어떻게 보면 예측 가능한 단순한 사실이죠!

사람도 답변하기 애매하고 어려운 질문을 날려, 기계가 한국어의 의미를 어떻게 이해하고 있는지 실험해볼 예정입니다.

이와 같은 실험은 영어를 대상으로 graceavery라는 블로거가 먼저 소개를 했었는데요,

역시 재밌고, 한편으로는 철학적이기도 한 결과들이 많으니까, 함께 보시면 더욱 좋을 것 같습니다! :-)

먼저 사물들의 반대되는 성(姓) 을 알아볼까요?

[할아버지 - 할머니 + 농구] = [배구]

[할아버지 - 할머니 + 노트북] = [태블릿]

[할아버지 - 할머니 + 선풍기] = [청소기]

[할아버지 - 할머니 + 바다] = [숲]

[할아버지 - 할머니 + 연필] = [볼펜]

[할아버지 - 할머니 + 파도] = [안개]

[할아버지 - 할머니 + 물] = [기름]

[할아버지 - 할머니 + 버스] = [택시]

[할아버지 - 할머니 + 겨울] = [여름]

[할아버지 - 할머니 + 신] = [환상]

[할아버지 - 할머니 + 커피] = [와인]

[할아버지 - 할머니 + 밥] = [키스]

[할아버지 - 할머니 + 사탕] = [과자]

[할아버지 - 할머니 + 소고기] = [닭고기]

[할아버지 - 할머니 + 치킨] = [피자]

[할아버지 - 할머니 + 손] = [주먹]

[할아버지 - 할머니 + 초록색] = [노란색]

[할아버지 - 할머니 + 기업] = [투자]

[할아버지 - 할머니 + 사랑] = [행복]

[할아버지 - 할머니 + 컴퓨터] = [개발자]

[할아버지 - 할머니 + 시간] = [매일]

[할아버지 - 할머니 + 공부] = [수업]

[할아버지 - 할머니 + 인생] = [추억]

[할아버지 - 할머니 + 기쁨] = [장난]

[할아버지 - 할머니 + 분노] = [절망]

[할아버지 - 할머니 + 점심] = [배달]

[할아버지 - 할머니 + 회의] = [선점]

[할아버지 - 할머니 + 그림] = [jpg]

우리가 추상적으로 생각하는 반대되는 의미를 가지는 단어들을 기계도 알고 있나 봅니다 :-)

다음으로 재료와 구성요소에 대해서 살펴볼까요?

[건물 - 콘크리트 + 사람] = [냄새]

[건물 - 콘크리트 + 컴퓨터] = [인터페이스]

[건물 - 콘크리트 + 사랑] = [언제나]

[건물 - 콘크리트 + 바다] = [모래]

[건물 - 콘크리트 + 물] = [녹]

[건물 - 콘크리트 + 시간] = [속도]

[건물 - 콘크리트 + 공부] = [적응]

[건물 - 콘크리트 + 인생] = [미소]

[건물 - 콘크리트 + 손] = [감]

[건물 - 콘크리트 + 지식] = [구현]

[건물 - 콘크리트 + 우정] = [목소리]

[건물 - 콘크리트 + 세계] = [사이클]

[건물 - 콘크리트 + 분노] = [상처]

[건물 - 콘크리트 + 힙합] = [리듬]

[건물 - 콘크리트 + 배고픔] = [방전]

[건물 - 콘크리트 + 태양] = [빛]

[건물 - 콘크리트 + 쾌락] = [공명]

[건물 - 콘크리트 + 데이터] = [프로토콜]

[건물 - 콘크리트 + 구름] = [얼음]

[건물 - 콘크리트 + 초록색] = [황색]

[건물 - 콘크리트 + 자유] = [도파민]

이외에도 재밌는 관계들을 추론해보았습니다 :-)

[여름 - 더위 + 겨울] = [마름]

[여름 - 더위 + 인간] = [욕구]

[여름 - 더위 + 바다] = [플랑크톤]

[여름 - 더위 + 재미] = [자질]

[선풍기 - 바람 + 눈] = [눈물]

[사람 - 지능 + 컴퓨터] = [소프트웨어]

[인생 - 사람 + 컴퓨터] = [관리자]

[그림 - 연필 + 영화] = [스타]

[오케스트라 - 바이올린 + 인간] = [육체]

[손 - 박수 + 발] = [달리기]

[삼겹살 - 소주 + 맥주] = [햄]

마치며

오늘은 word2vec을 이용해 기계가 생각하는 한국어의 의미에 대해 살펴보았는데요!

한 번 word2vec 모델을 만들어두면 정말 시간 가는 줄 모르고 이것저것 가지고 놀아보게 됩니다 :-)

언어를 단순히 사전처럼 저장하는 것이 아니라, 그 단어가 가지고 있는 의미를 수학적으로 표현할 수 있다는 사실은 무척 매력적으로 느껴지죠.

Word2vec은 학습 방법도, 사용 방법도 전혀 어렵지 않고, 매우 간편하게 사용할 수 있으니, 이 포스팅을 보시는 분들도 다양한 실험을 해보시고 공유해주시면 재밌을 것 같습니다 :-)

기업문화 엿볼 때, 더팀스

로그인

/