기초적이지만 꽤 재미있는 word embedding 놀이

글쓴이 Inforience 날짜

클릭 >> Hello, world !! (from ShadowEgo)

들어가며…

최근의 기계학습 분야에서 가장 핵심적인 역할을 하고 있는 것들 중의 하나가 ‘embedding’이다. Wikipedia에 명시된 embedding의 정의 [0] 는 다음과 같다.

“In mathematics, an embedding is one instance of some mathematical structure contained within another instance, such as a group that is a subgroup. When some object X is said to be embedded in another object Y, the embedding is given by some injective and structure-preserving map f : X → Y. The precise meaning of “structure-preserving” depends on the kind of mathematical structure of which X and Y are instances.”

정의를 읽어보니, 뭔가 멋진 것 같은데, 머리가 슬슬 아파온다. 그래서 데이터 분석 분야에서는 embedding을 어떻게 설명하고 있는지 살펴보기로 한다.

“An embedding is a mapping of a discrete — categorical — variable to a vector of continuous numbers. In the context of neural networks, embeddings are low-dimensional, learned continuous vector representations of discrete variables” [1]

다른 설명을 봐도 머리가 아프니, (다른 설명은 쉬울 줄 알았는데 속았다…) 다음과 같이 간단하게 정리하자. Embedding은 우리가 표현하고자 하는 대상을 벡터공간의 좌표로 매핑하고 표현하는 과정이다. Embedding 대상은 대용량의 문서들에 포함된 단어들일 수 있고, 문서 자체일 수도 있고, 이미지가 될 수도 있고, 그래프가 될 수도 있다. 벡터공간의 좌표로 표현하게 되면 각 대상의 좌표 사이의 거리를 계산하거나, 대상들의 순서를 매기는 것과 같은 다양한 수학적 연산을 할 수 있게 된다. (단어들을 가지고 연산을 한다고? 신나는 일이다.) 차원이 아주 큰 대상을, 그것의 본래의 성질을 최대한 유지한 상태에서 활용이 용이한 형태로, 성질이 더 잘 나타나도록 압축시키기 위하여 쓸 수도 있다.

Embedding의 원리와 특성을 자세히 공부하는 것은 다음 기회에 포스팅하기로 하고 (잠시만 구글링을 해봐도 좋은 소개자료들이 넘쳐난다…), 이번 포스트는 embedding을 활용하면 어떤 것을 할 수 있을지 맛을 보기 위한 내용으로 구성해 보자.

Word2Vec

Embedding의 대상들 중에서 가장 주목을 많이 받고, 많이 활용되고 있는 것들 중의 하나는 단어(word)이다. 사실, 자연어 처리 분야에서는 단어나 문장을 수학적 공간좌표에 효율적으로 mapping, 표현하기 위하여 많은 노력을 기울여왔는데, word embedding이 그러한 노력에 한줄기 빛을 제공했다고 할 수 있다. (요즘은 여기저기서 계속 새로운 빛이 나오고 있긴 하다. 그래서 눈부셔…) Word embedding 방법들 중에서 가장 기초적이면서도 대표적인 것이 word2vec [2][3] 이라고 할 수 있는데, 이번 포스트는 나름대로 재미있어야 하므로, word2vec의 개념이나 원리는 잠시 뒤로 미뤄두고, word2vec을 실제 데이터에 적용해 본 결과만 즐겨보자. (과연 즐거울 것인가…)

Data

어떤 종류의 word 들을 embedding해서 가지고 놀면 재미있을까? 사람 이름, 지명, 음식명, 질병명, 영화 제목, 생활 용품 이름 등등, 많은 것들 중에서 고민해 볼 수 있다. 평소에 자주 먹는 음식의 종류에 따라 그 사람의 특성을 설명할 수도 있다는 말도 얼핏 들은 듯 한데, 정말 그럴 지도 궁금하고, 음식과 질병 사이의 관계도 궁금하니까 본 포스트에서는 음식명과 질병명을 활용해 보기로 한다.

그렇다면, 음식과 질병에 대해 작성된 대용량의 문서 세트를 구해야 한다. 공식적으로 활용할 수 있는 자료들도 있겠지만, 이번 포스트는 기초적인 활용 방법을 느껴보는 것을 목적으로 하니까, 일단은 웹 상에서 어렵지 않게 구할 수 있는 문서 데이터들을 수집하여 활용해 보기로 한다. 음식에 대한 설명 문서들은 나무위키의 ‘식품관련정보’[4]와 ‘요리법/요리’[5], 그리고 ‘영양소’[6]에 업로드된 자료들을 활용하기로 한다. 질병과 관련된 문서는 (주관적으로 선택한) 주요 질병들에 대한 문서들을 직접 수집하여 활용한다. 이번 분석과정에서 선택한 23가지의 주요 질병명은 다음과 같은데, 평소의 식생활에 의해 영향을 많이 받을 것 같은 질병들을 골라 보았다. (의사가 아니므로 실제로는 식생활과 무관한 질병명이 포함되어 있을 수 있다…)

[고혈압, 당뇨, 고지혈증, 동맥경화, 심근경색, 협심증, 부정맥, 지방간, 감기, 인플루엔자, 폐렴, 비만, 간염, 대상포진, 장염, 위염, 췌장염, 신부전, 만성피로, 통풍, 신장결석, 빈혈, 변비]

이 데이터를 활용하여 embedding한 모델을 본 포스트에서는 앞으로 FD모델(Food-Disease 모델)이라고 부르기로 한다.

그림 0. FD모델의 Embedding 결과 확인

그림 0은 음식 관련 문서들에 포함된 단어들을 word2vec을 활용하여 벡터 공간에 mapping 한 뒤에, 각 벡터들을 t-SNE[7]를 써서 2차원으로 출력해 본 그림이다. 음식 관련된 문서들을 활용했기 때문에 대부분의 단어들이 음식명이기는 하지만, 음식명이 아닌 단어들도 꽤 보인다. (너무 당연한 이야기인가…) ‘불량식품’이나 ‘괴식’과 같은 단어들도 포함되어 있다는 점이 재미있다. 그림을 잘 들여다 보면, 청국장, 쌈장, 된장, 간장, 낫토 등이 가까운 곳에 위치하고 있고, 고기 종류들도 서로 가까운 곳에 모여 있는 듯 하다. (그렇다면, 각각 혼자 멀리 떨어져 있는 것처럼 보이는 ‘참깨’와 ‘채식주의’는 아웃사이더인가…?)

단어 간 관계

가장 먼저, 단어 사이의 거리를 계산해 보자.

표 1. 단어 간 거리

표 1은 FD모델을 적용하여 측정한 단어 간 거리값을 나타낸다. 삼겹살을 먹을 때에는 쌈장을 곁들일 때가 많은 것에 비해 파스타와 함께 먹는 경우는 많지 않으니 삼겹살과 쌈장 사이의 거리가 삼겹살과 파스타 사이의 거리보다 짧게 나왔다. (꿈보다 해몽일지도…. ) 고지혈증과 고혈압 사이의 거리가 고지혈증과 감기 사이의 거리보다 짧게 나왔는데, 고지혈증이 고혈압의 직접적인 원인이라는 점에서 꽤 타당한 결과인 듯 보인다. 또한 표 1에 제시된 결과대로라면 삼겹살을 많이 먹을 경우 비만에 걸릴 가능성이 통풍에 걸릴 가능성보다 높다고 해석할 수도 있겠다. (의학적인 근거는 없다.)

음식 단어와 가까운 단어들

아래의 그림 1, 그림2, 그림3은 각각 ‘김치’, ‘참치’, 그리고 ‘돼지’와 가까운 단어들 중에서 상위 10개를 추출한 결과를 보여준다.

그림 1. ‘김치’와 가까운 단어 리스트

‘김치’와 가까운 단어들을 보면 거의 모두 그럴 듯한 것들이 추출된 것 같다. 비빔밥과 간장은 조금 색다르게 느껴지는데, 비빔밥에 김치를 곁들여 먹거나, 아예 김치를 넣어서 비벼먹는 경우가 꽤 있다고 해석하자. (김치 비빔밥!!) 그리고, 김치와 간장의 관계도 고개를 갸웃거리게 했는데, 구글링을 좀 해보니 ‘간장김치’라는 메뉴도 있다. (억지로 끼워 맞추는 듯…)

그림 2. ‘참치’와 가까운 단어 리스트

그림 2에 표시된 ‘참치’와 가까운 단어들의 경우에는 조금 애매하게 느껴지는 단어들이 여럿 포함된 듯 하다. 예를 들어, 참치와 비빔면의 관계성이 애매하게 느껴진다. (단, 모 회사에서 참치 비빔면을 출시한 바 있다고 한다.) ‘젓’과의 관계도 의문이었는데, 참치 내장으로도 젓갈을 담근다고 한다. (역시 꿈보다 해몽 같지만…) 아무리 그래도 참치 김밥이나 참치 샌드위치를 생각할 때, 참치와 마요네즈와의 관계가 상대적으로 낮게 나온 것은 불만스럽다. (개인적인 성향…)

그림 3. ‘돼지’와 가까운 단어 리스트

그림 3에 표시된 ‘돼지’와 가까운 단어들은 모두 이상할 것이 없는 것들로 구성되어 있는 듯 하다. 물론, ‘제육’이나 ‘족발’이 리스트에 없는 것이 서운하게 느껴질 사람도 있을 수 있다.

질병 단어와 가까운 단어들

아래의 그림 4, 그림5, 그림6은 각각 ‘고혈압’, ‘감기’, 그리고 ‘콜레스테롤’과 가까운 단어들 중에서 상위 10개를 추출한 결과를 보여준다.

그림 4. ‘고혈압’과 가까운 단어 리스트

그림 4를 보면, ‘고혈압’과 가까운 단어들이 꽤 타당하게 선택된 것을 알 수 있다. 고혈압은 당뇨와 같은 다른 합병증을 일으키는 원인이 되기도 하지만 적극적인 치료를 받으면 잘 관리할 수 있는 질환이라고 한다.

그림 5. ‘감기’와 가까운 단어 리스트

그림 5에서는 감기와 가까운 단어들을 확인할 수 있다. 그림 4에 나타난 리스트와는 달리, ‘바이러스, ‘면역’, ‘인플루엔자’ 등이 리스트에 포함된 것으로 보아 꽤 타당한 선택 결과라고 생각된다.

그림 6. ‘콜레스테롤’과 가까운 단어 리스트

콜레스테롤은 혈액을 통해 운반되는 성분으로서, 심혈관 질환이나 혈압 수치와 관련되며, 음식을 통해 흡수되기 때문에 혈중 콜레스테롤 농도는 평소의 식습관과 밀접한 관계가 있다고 한다. 그림 6에서 선택된 단어 리스트를 보면, 콜레스테롤에 대한 문서에서 불포화 지방산이나 트랜스 지방에 대한 언급이 빠지지 않는다는 점이 잘 반영된 듯 하다.

가장 거리가 먼 단어 선택

표 2. 거리가 먼 단어 선택 결과

표 2의 각 행은 주어진 4가지 단어들 중에서 가장 거리가 먼 단어를 FD모델을 기반으로 선택해 본 결과를 나타낸다. 종류가 다르거나, 관련성이 낮은 단어들이 적절하게 선택되었음을 확인할 수 있다. 이러한 개념을 잘 활용할 경우, 사람들이 평소에 즐겨 먹는 음식들에 대한 정보를 모을 수 있다면 그 정보를 바탕으로 사람들의 성향을 충분히 그룹핑할 수도 있겠다는 생각을 해보게 된다.

음식과 질병 관계

그림 7. 음식과 가까운 질병

그림 7은 특정 음식과 가까운 질병명을 추출한 결과들을 보여준다. ‘볶음밥’이나 ‘피시&칩스’와 가장 가까운 질병은 (아무래도 기름기가 많을 수 있으니) 당뇨병이나 심근경색이 선택되는 것이 타당해 보인다. 그런데 ‘달걀밥’이나 ‘연어’와 가까운 질병명들을 보니 뭔가 의심스러운 생각이 든다. 달걀밥이 이렇게 많은 질병과 골고루 관련되어 있다는 말인가. 그리고 연어가 만성피로나 심근경색을 유발한다고? 연어의 효능과 관련된 자료를 찾아보면, 오히려 심혈관 질환이나 혈액 순환 장애에 도움이 되고 피로회복에도 좋은 영향을 끼친다는 내용이 많다. 그렇다면, 단순히 거리가 가깝다는 사실만으로는 해당 음식이 질병에 좋다는 의미인지 나쁘다는 의미인지 파악하기 어렵다는 판단을 할 수 있다.

그림 8. 음식-질병 관계를 구분하여 실험한 결과 (1)
그림 9. 음식-질병 관계를 구분하여 실험한 결과 (2)

그림 8과 그림 9는 5가지 질병 – 고지혈증(Hyperlipidemia), 당뇨(Diabets), 비만(Obesity), 지방간(Liver), 고혈압(High blood pressure) – 들에 좋은 음식을 설명한 문장들과 나쁜 음식을 설명한 문장들을 구분하여 수집한 뒤에, 해당 문장들에 포함된 단어들과 음식명 사이의 거리의 평균값을 구한 결과를 보여준다. 간에 좋은 음식과 나쁜 음식을 설명한 문장들의 예는 아래의 표 3에서 확인할 수 있다. 그림 8에서 삼겹살과 hyperlipidemia_bad 와의 거리값은 고지혈증에 나쁜 음식들에 대하여 설명한 문장들에 포함된 단어들과 삼겹살 사이의 거리의 평균값을 의미한다.

표 3. 간에 좋은 음식에 대한 설명 문장들과 간에 좋은 음식에 대한 설명 문장들의 예

그림 8과 그림 9에 나타난 결과들을 종합해 보면, (몇 가지 예외를 제외하고) 삼겹살, 튀김, 술, 나트륨, 햄버거는 5가지 선택된 질병들에 좋지 않은 것으로 설명한 문장들에 포함된 단어들과 거리가 가깝다고 판단할 수 있으며, 녹차, 현미, 오이는 해당 질병들에 좋은 음식들을 설명한 문장들에 포함된 단어들과 거리가 가깝다고 판단할 수 있다.

마치며…

이번 포스트에서는, embedding이 어떻게 응용될 수 있을지에 대해 맛을 볼 목적으로, word2vec을 적용하여 단어들 사이의 거리를 측정해 보고, 그 결과들이 상식에 얼마나 부합할 지에 대하여 알아보았다. 생각해 보면, 단어들 사이의 의미상 거리를 제대로 측정할 수만 있다면, 그것만으로도 꽤 많은 응용 서비스를 파생시킬 수 있다. 인포리언스는 이미 오래 전에, 지능적인 영어 학습 서비스를 개발하는 과정에서 word embedding을 활용한 바 있는데, 학생들의 어휘 학습 수준에 맞는 새로운 학습 단어를 추천하거나, 학생이 학습한 문장과 유사한 수준의 다른 문장을 추천하는 과정에서 문장의 구조적 특성과 문장을 구성하는 단어들 사이의 유사성을 복합적으로 고려하도록 구현했다. [8]

실험 과정에서 더욱 정제된 문서의 집합들을 활용하고 섬세한 데이터 가공 절차와 학습 과정을 적용할 수 있다면 더 좋은 결과를 얻을 수 있을 것이지만, 이번 포스트에서 활용한 데이터에는 사실 노이즈가 꽤 포함되어 있었다. 예를 들어, 특정 음식에 대한 설명 문서에 해당 음식과 전혀 무관한 설명들이 포함되어 있는 경우도 있었다. (이것이 수집 대상 데이터 자체의 문제인지, 아니면 데이터를 수집하기 위해 작성한 코드의 오류에 의해 생긴 것인지는 좀 더 확인을 해봐야 하지만)

Word2vec은 이미 유명 라이브러리에 포함되어 있으므로, 실제 코드에 적용해 보는 것은 어렵지 않다. 따라서, 이번 포스트에 소개한 실험과정에서는 word2vec을 적용하는 과정보다 데이터를 모아 활용 가능한 형태로 정리하는 과정에 더 많은 시간과 노력이 필요했다.

본 포스트에서 가장 주의할 것은, 실험에 활용한 데이터에 따라 이러한 실험의 결과가 달라진다는 점이다. 다시 말해서, 다른 문서 데이터 세트를 대상으로 실험을 진행했다면, 매우 다른 결과를 얻게 될 수 있다. 그리고 질병과 관련하여 이 포스트에서 언급한 내용들은 실제 의학적 전문 지식과 크게 다를 수도 있다는 점에 유의해야 한다.

References