for textmining

빈도수 세기의 놀라운 마법 Word2Vec, Glove, Fasttext

|

안녕하세요. 이번 포스팅에서는 단어를 벡터화하는 임베딩(embedding) 방법론인 Word2Vec, Glove, Fasttext에 대해 알아보고자 합니다. 세 방법론은 대체 어떤 정보를 보존하면서 단어벡터를 만들기에 뛰어난 성능으로 유명세를 탄 것일까요? 저는 이번 포스팅에서 세 방법론이 크고 작은 차이점을 갖고 있지만 단어 동시 등장 정보(word’s of co-occurrence)를 보존한다는 점에서 빈도수 기반의 기존 방법론들과 본질적으로 다르지 않다는 점을 이야기해보려고 합니다. 자, 이제 시작해 볼까요.

Word2vec 개요

Word2Vec은 지난번 에서 언급한 것처럼 단어를 벡터로 바꾸는 방법론입니다. 크게 CBOW(Continuous Bag of Words)Skip-Gram 두 가지 방식이 있습니다. 전자는 주변에 있는 단어들을 가지고 중심에 있는 단어를 맞추는 방식이고, 후자는 중심에 있는 단어로 주변 단어를 예측하는 방법입니다. 예를 들어 보겠습니다.

나는 ____에 간다.

위 문장에 들어갈 수 있는 단어는 다양합니다. ‘학교’일 수도, ‘집’일 수도 있죠. ‘회사’일 수도 있습니다. 이렇듯 주변 단어를 가지고 중심에 있는 단어를 맞춤으로써 단어 벡터들을 만들어 내는 방법이 CBOW입니다. 반대로 아래처럼 ‘외나무다리’ 앞뒤로 어떤 단어가 올지 예측하는 방법은 Skip-Gram입니다.

__ 외나무다리 __

‘외나무다리’ 앞에는 어떤 단어가 올까요? 아마도 ‘-는’이겠지요. 그 앞에는 ‘원수’가 오겠고요. ‘외나무다리’ 뒤에는 어떤 단어가 등장할까요? ‘-에서’와 ‘만난다’일 가능성이 높겠네요. 우리가 학습시킬 말뭉치에서도 ‘외나무다리’ 뒤에 ‘-에서’, ‘만난다’는 표현이 나왔다고 칩시다. 그러면 Word2Vec은 ‘외나무다리’가 ‘-에서’, ‘만난다’와 어떤 연관이 있다고 보고 이를 감안해서 단어를 벡터로 만들게 됩니다.

여기서 고민해볼 문제가 하나 있습니다. ‘외나무다리’는 ‘원수’와 비슷한 표현(단어)이라고 볼 수 있을까요? 정답이 없는 문제입니다만 그렇지 않다고도, 그렇다고도 볼 수 있을 것 같습니다. ‘외나무다리’는 ‘원수’와는 그 의미가 정확히 같지는 않지만, 자주 같이 쓰이는 연어(collocation)이기 때문입니다.

Word2Vec의 목적함수와 코사인 유사도

Word2Vec은 Distributional Hypothesis에 근거한 방법론입니다. 비슷한 위치에 등장하는 단어들은 그 의미도 유사할 것이라는 전제가 깔려 있죠. 어쨌든 Word2Vec(Skip-Gram)은 아래 식을 최대화하는 걸 목표로 합니다.

[p(o c)=\frac { \exp({ u }{ o }^{ T }{ v }{ c }) }{ \sum { w=1 }^{ W }{ \exp({ u }{ w }^{ T }{ v }_{ c } } )}]

식 좌변의 의미를 곱씹어 볼까요? $o$는 주변단어(context word), $c$는 중심단어(center word)입니다. 다시 말해 $p(o|c)$는 중심단어($c$)가 주어졌을 때 주변단어($o$)가 등장할 조건부확률을 뜻합니다. 이 식을 최대화하는 것은 중심단어로 주변단어를 잘 맞춘다는 의미입니다. 즉 ‘외나무다리’가 등장했을 때 ‘원수’라는 표현이 나올 것이라는 사실을 예측하는 것이지요.

Word2Vec 저자들은 $p(o|c)$을 위 식 우변과 같이 정의했습니다. $u$와 $v$는 단어벡터들입니다. 예컨대 ‘외나무다리’라는 중심단어 벡터가 $v_c$, ‘원수’라는 주변단어 벡터가 $u_o$입니다. 사실 엄밀히 얘기하면 $u$와 $v$는 다른 벡터들입니다.

하지만 임베딩이 잘 되어 있다면 학습 결과로 도출된 $u$, $v$ 가운데 어떤 걸 써도 상관없다고 합니다. 이 때문에 이후 설명에서 큰 차이를 두지 않았습니다. Word2Vec의 학습 과정에 대해 좀 더 알고 싶은 분은 이곳을 참고하세요.

식 우변의 분모와 분자를 설명하기 전에 코사인 유사도를 설명하는 것이 좋겠습니다. 2차원 평면 위에 반지름이 1인 단위원이 있다고 칩시다. 코사인(cosine)의 정의에 의해 $cos(θ)$는 아래 그림의 녹색 선의 길이와 같습니다. $A$를 꼭지점으로 하는 직각삼각형의 빗변의 길이는 단위원 반지름인 1이기 때문이죠.

예컨대 $A$가 $B$에 정확히 포개어져 있을 때(θ=0도) $cos(θ)$는 1입니다. 녹색선의 길이가 단위원 반지름과 일치하기 때문입니다. $B$는 고정한 채 $A$가 y축 상단으로 옮겨간다(θ가 0도에서 90도로 증가)고 칩시다. 이때 $cos(θ)$는 점점 감소하여 0이 되게 됩니다. 아래 그림의 경우 빨간색 직선이 x축과 만나는 점이 바로 $cos(θ)$이 됩니다.

$cos(θ)$는 단위원 내 벡터들끼리의 내적(inner product)과 같습니다. 내적값이 커진다는 것은 두 벡터가 이루는 θ가 작아진다(유사도가 높아진다)는 의미로 받아들일 수 있습니다. 이는 고차원 벡터공간으로도 확대할 수 있습니다. Word2Vec 연구진은 이러한 코사인과 내적의 성질을 목적함수 구축에 적극 활용한 것 같습니다.

그렇다면 위 식 우변을 최대화한다는 말은 어떤 의미를 지니는 걸까요? 분자를 키우고, 분모를 줄이면 최대화 목표를 달성할 수 있겠죠. 우선 분자 부분을 봅시다.

[\exp({ u }{ o }^{ T }{ v }{ c })]

분자를 증가시킨다는 건 $\exp$의 지수를 크게 한다는 걸 뜻합니다. $\exp$의 지수는 두 벡터의 내적값이 됩니다. 이 값이 커진다는 건 앞서 언급했던 것처럼 벡터들 사이의 θ를 줄인다(즉 유사도를 높인다)는 말이 될 것 같습니다. 다시 말해 중심단어(c)와 주변단어(o)를 벡터공간에 뿌릴 때 인근에 위치시킨다(θ를 줄인다=유사도를 높인다)는 의미로 해석할 수 있다는 얘기입니다.

분모 줄이기는 어떻게 받아들여야 할까요? 분모는 아래와 같습니다.

[\sum { w=1 }^{ W }{ \exp({ u }{ w }^{ T }{ v }_{ c })}]

따라서 분모는 중심단어(c)와 학습 말뭉치 내 모든 단어를 각각 내적한 것의 총합입니다. 분모를 줄이려면 주변에 등장하지 않은 단어와 중심단어와의 내적값은 작아져야 합니다. 즉 중심단어 주변에 등장하지 않은 단어에 해당하는 벡터와 중심단어 벡터 사이의 θ를 키운다(코사인 유사도를 줄인다)는 의미가 되겠습니다.

Word2Vec과 단어의 ‘동시 등장 정보’

여기까지 보면 Word2Vec은 빈도수 기반 방법론들과 별 관련이 없는 것도 같습니다. 그러면 Word2Vec이 어떻게 이와 관계를 지니게 되는 것일까요? 그 비밀은 학습 과정에 숨겨져 있습니다.

사용자가 주변단어 몇 개를 볼 지(window)를 정해주면 Word2Vec은 말뭉치를 window 크기로 슬라이딩하면서 스크린하며 중심단어별로 주변단어들을 보고 각 단어에 해당하는 벡터들의 요소값들을 조금씩 업데이트함으로써 단어를 벡터로 임베딩합니다.

다시 말해 Word2Vec은 window 내에 등장하지 않는 단어에 해당하는 벡터는 중심단어 벡터와 벡터공간상에서 멀어지게끔(내적값 줄이기), 등장하는 주변단어 벡터는 중심단어 벡터와 가까워지게끔(내적값 키우기) 한다는 것이죠.

그럼 이렇게 생각해보는건 어떨까요? window 내에 등장하지 않으면 결과값을 줄이고, 등장할 경우 결과값을 키우는 건? 이 정보를 명시적으로 보존하는 행렬이 있습니다. 주변 단어를 몇 개 볼지를 정하고 동시에 등장하는 단어의 빈도수를 세어 놓은 ‘단어-문맥행렬‘이 바로 그것입니다.

바꿔 말하면 Word2Vec은 기존 count 기반 방법론처럼 자주 같이 등장하는 단어들의 정보(co-occurrence)를 보존한다는 얘기입니다. Omer and Yoav(2014)도 Word2Vec은 본질적으로 기존 count 기반의 방법론과 다르지 않다는 점을 논증해 눈길을 끕니다.

그렇다면 GloVe, Fasttext는?

GloVe는 2014년 미국 스탠포드대학 연구팀에서 개발한 단어 임베딩 방법론입니다. GloVe 연구진이 명시적으로 밝혔듯 GloVe가 보존하려는 정보는 단어 동시 등장 여부입니다. GloVe로 임베딩된 단어 벡터끼리의 내적은 동시 등장확률의 로그값과 같습니다. (their dot product equals the logarithm of the words’ probability of co-occurrence) Word2Vec이 임베딩된 두 단어벡터의 내적이 코사인 유사도라면 GloVe는 동시 등장 확률인 셈이죠. GloVe의 학습 방식을 자세히 살펴보고 싶으신 분은 이곳을 참고하시면 좋을 것 같습니다.

한편 페이스북이 2016년 발표한 Fasttext는 원래 단어를 부분단어(subword)의 벡터들로 표현한다는 점을 제외하고는 Word2Vec과 거의 유사합니다. Fasttext 역시 Word2Vec처럼 단어들의 동시 등장 정보를 보존한다는 말입니다.

세 방법론의 한계

세 방법론이 ‘단어 동시 등장 정보’를 보존한다는 점을 논의했습니다. 그렇다면 이들 방법론에 한계점은 없는걸까요? 처음에 든 예시를 다시 들어보겠습니다.

나는 ___에 간다

위 예시에서 빈칸에는 ‘학교’, ‘집’, ‘회사’ 따위가 모두 들어갈 수 있습니다. ‘학교’, ‘집’, ‘회사’라는 단어가 위 예시 문장과 같은 경우에서만 쓰였다면 명백히 다른 단어임에도 불구하고 임베딩 벡터 공간에서 세 단어벡터의 유사도가 매우 높게 나타나게 됩니다.

물론 학습 말뭉치가 충분히 크다면 세 단어가 사용된 사례(문장)가 다양하기 때문에 ‘학교’, ‘집’, ‘회사’ 벡터 간 거리가 충분히 멀게(코사인 유사도가 작게) 임베딩이 될 겁니다. 하지만 의미상 아무런 관련이 없어 보이는 단어임에도 벡터공간에 매우 가깝게 임베딩되는 사례가 자주 발생하는 것 같습니다.

한번 예를 들어보겠습니다. 아래는 클리앙, 뽑뿌 등 6개 사이트에서 스크랩핑한 휴대폰 리뷰 29만7906개로 구성된 말뭉치를 Word2Vec으로 임베딩한 결과입니다. 이후 ‘소프트웨어’라는 단어와 코사인 유사도가 가장 높은 단어 5개를 뽑아봤습니다.

하드웨어, 0.75

OS, 0.68

os, 0.63

운영체제, 0.63

발적화, 0.62

‘OS’, ‘운영체제’, ‘발적화’ 같은 단어가 소프트웨어와 유사하다는 결과는 직관적으로 납득할 만하다고 생각합니다. 하지만 ‘하드웨어’가 ‘소프트웨어’랑 가장 비슷하다는 결과는 약간 받아들이기 힘듭니다. Word2Vec은 ‘하드웨어’ 주변단어와 ‘소프트웨어’ 주변단어들이 비슷한 분포를 보이기 때문에 이런 결과를 낸 것 같은데요. Word2Vec이 보존하려는 정보가 ‘동시등장 여부’이기 때문에 생기는 근본적인 한계가 아닐까 하는 생각이 듭니다.

Comment  Read more

idea of statistical semantics

|

이번 포스팅에서는 자연언어처리(Natural Language Processing)의 기본 가정 가운데 하나인 distributional hypothesis벡터공간모델(Vector Space Models)에 대해 알아보도록 하겠습니다. 그 핵심은 ‘빈도’를 ‘의미’로 진화시킬 수 있다는 아이디어인데요. 이와 아울러 NLP 분야에서 생각하는 유사도(similarity)와 NLP의 기본 절차에 대해서도 이야기해보겠습니다. 이와 관련해 괜찮은 아티클이 있어 공부 겸 소개 겸 정리를 해볼까 합니다.

NLP의 기본 가정

NLP 분야의 기본 가정들을 소개합니다.

VSMs : 문서 집합에 속하는 각각의 문서들을 벡터공간의 벡터로 표현(representation)할 수 있다. 벡터공간에 벡터로 표현된 문서들 사이의 거리가 가깝다면 의미가 유사하다(semantically similar).

distributional hypothesis : 비슷한 맥락에 등장하는 단어들은 유사한 의미를 지니는 경향이 있다. (words that occur in similar contexts tend to have similar meanings)

statistical semantics hypothesis : 언어 사용의 통계적 패턴은 사람들이 의미하는 바를 이해하는 데 쓰일 수 있다. (statistical patterns of human word usage can be used to figure out what people mean)

bag of words hypothesis : 어떤 문서에 출현한 단어들의 빈도는 문서와 쿼리의 관련성을 나타내는 경향이 있다. (the frequencies of words in a document tend to indicate the relevance of the document to a query) 어떤 문서가 쿼리 문서와 유사한 벡터라면 그 의미도 비슷하다.

Latent relation hypothesis : 비슷한 패턴으로 동시에 등장하는 단어쌍은 유사한 의미적 관계를 지니는 경향이 있다. (Pairs of words that co-occur in similar patterns tend to have similar semantic relations)

음, 뭔가 어렵죠? 사실 그 말이 그 말인 것 같고요. 위 내용을 종합해 저만의 언어로 풀어서 이야기하자면, 분석 대상 말뭉치 내 등장하는 단어들의 빈도를 세서 이를 벡터 형태로 바꿀 수 있고, 그 벡터들 간의 거리(유사도)를 잴 수 있으며, 이렇게 구한 거리는 언어학적인 의미를 내포한다는 이야기인 것 같습니다. 바꿔 말하면 컴퓨터는 그저 단어를 ‘숫자’로 바꿔서 ‘계산’할 뿐이지만 이 과정에서 자연언어의 ‘의미’도 ‘이해’할 수 있다는 가정인 셈이지요.

뒤에서 설명드릴 단어-문서행렬(Term-Document Matrix), 단어-문맥행렬(Word-Context Matrix), 페어-패턴행렬(Pair-Pattern Matrix) 등은 모두 위 가정을 전제로 한 분석 방법론입니다. Word2Vec, Glove, Fasttext 또한 마찬가지인 것 같습니다. 이들 방법론은 문맥 단어가 주어졌을 때 분석 대상 단어가 등장할 조건부 확률, 혹은 동시에 등장하는 빈도 따위를 보존하는 방식으로 단어를 벡터화하는 데 이 방법론의 대전제가 위의 가정에서 크게 벗어난 것 같지는 않다는 생각에서입니다. 어쨌든 단어의 의미를 숫자로, 언어학을 컴퓨터 사이언스로 문제와 해결방식을 각각 근본적으로 바꿨다는 점에서 괜찮은 아이디어인 것 같습니다물론 이 가정이 틀렸다는 게 엄밀하게 증명된다면 다른 얘기겠지만.

단어-문서행렬

수학에서 bagset과 유사한 개념입니다. 예컨대 bag {a, a, b, c, c, c}와 bag {c, a, c, b, a, c}는 같습니다. 즉 빈도는 고려하지만 등장 순서는 무시한다는 거죠. 이 때문에 단어-문서행렬을 bag of words 기반의 방법론이라고도 합니다. 단어들을 일종의 주머니(bag)에 넣어 둔다는 의미 정도로 해석할 수 있겠는데, 한번 주머니에 들어가면 순서가 뒤죽박죽 섞이기 때문에 이런 용어가 생긴 것 같습니다. 예를 들어 다음과 같은 단어들로 이뤄진 문장이 있다고 칩시다. 그럼 우리는 다음과 같은 단어-문서행렬을 만들 수 있습니다.

나,는,학교,에,가,ㄴ,다

학교,에,가,는,영희

나,는,영희,는,좋,다

- doc1 doc2 doc3
1 0 0
1 1 2
학교 1 1 0
1 1 0
1 1 0
1 0 0
1 0 1
영희 0 1 1
0 0 0
0 0 1

단어-문맥행렬

주변 단어를 몇 개 볼 지(window size)를 정하고 동시에 등장하는 단어의 빈도수를 세어서 행렬로 바꾸는 방법입니다. window 개념이 있기 때문에 단어-문서행렬과 달리 단어 등장 순서를 약간 고려하긴 합니다. 이 방법론은 distributional hypothesis와 밀접한 관련이 있습니다. 예시는 다음과 같습니다(window size = 1).

I enjoy flying

I like NLP

I like deep learning

- I like enjoy deep learing NLP flying
I 0 2 1 0 0 0 0
like 2 0 0 1 0 1 0
enjoy 1 0 0 0 0 0 0
deep 0 1 0 0 1 0 1
learning 0 0 0 1 0 0 0
NLP 0 1 0 0 0 0 0
flying 0 0 1 0 0 1 0

페어-패턴행렬

페어-패턴행렬의 행 벡터는 단어쌍(pairs of words)을 의미합니다. 예컨대 mason:stone, carpenter:word 따위가 되겠죠. 단어쌍에 대응되는 열 벡터는 해당 단어쌍과 함께 나타나는 패턴(patterns)을 뜻합니다. “X cuts Y”, “X works with Y” 등입니다. 이 행렬을 제대로 구축해놓으면 특정 패턴(예컨대 X solves Y)와 비슷한 패턴(Y is solved by Y)을 가려낼 수 있습니다.

유사도?

‘단어 뜻이 비슷하다’는 어떤 의미를 지니는 걸까요. 생각해보면 볼수록 알쏭달쏭한 개념입니다. 우선 제가 지금 설명드리고 있는 아티클을 기본으로 해서 제 생각을 정리해 말씀드려 보겠습니다. 단어들끼리는 어떤 관련을 맺고 있습니다. 엄밀히 얘기하면 이 세상에 완벽한 동의어는 없다고 말할 수 있을 정도로요. 심지어 반의어(antonyms)들조차 단어 사이의 관련성이 높습니다.

예를 들어 보죠. ‘춥다’와 ‘따뜻하다’는 반대되는 말이지 않습니까? 그렇다면 이 둘은 관계가 전혀 없을까요? ‘기온’을 언급한다는 점에 있어서는 비교적 강한 관계를 지닌다고 말할 수 있겠습니다. ‘흑’과 ‘백’, ‘크다’와 ‘작다’도 마찬가지로 ‘색상’, ‘크기’ 등과 관련해 관계를 맺고 있습니다.

지금 소개해드리고 있는 아티클은 단어 유사성과 관련해 다양한 개념들이 설명하고 있습니다. 우선 relational similarityattributional similarity가 있습니다.’개:멍멍’, ‘개:늑대’가 각각 전자와 후자의 대표 사례입니다. 전자는 단어 사이의 ‘관계’에, 후자는 ‘속성’에 방점을 둔 유사성 개념이라고 합니다. 유의어(synonyms), 부분어(meronyms), 반의어(antonyms) 등에서 알 수 있듯 모든 단어는 서로 밀접한 관계를 맺고 있습니다.

NLP 분야에서는 상위어(hypernym)를 공유하는 단어들이 의미적 유사성(semantic simliarity)을 지닌다고 정의한다고 합니다. 이 기준에 따르면 ‘자동차’와 ‘자전거’는 의미가 비슷한 단어입니다. ‘교통수단’이라는 상위어를 공유하기 때문입니다. 이 의미적 유사성이라는 개념은 앞서 언급한 attributional simliarity의 특수한 사례입니다. 또한 ‘벌’과 ‘꿀’처럼 동시에 빈번하게 같이 등장하는 단어들은 의미적으로 연관이 있을 가능성이 높다는 것이 이 분야의 대표적인 가정입니다.

Comment  Read more

RNN과 LSTM을 이해해보자!

|

이번 포스팅에서는 Recurrent Neural Networks(RNN)과 RNN의 일종인 Long Short-Term Memory models(LSTM)에 대해 알아보도록 하겠습니다. 우선 두 알고리즘의 개요를 간략히 언급한 뒤 foward, backward compute pass를 천천히 뜯어보도록 할게요.

이번 포스팅은 기본적으로 미국 스탠포드대학의 CS231n 강좌를 참고하되 forward, backward pass 관련 설명과 그림은 제가 직접 만들었음을 밝힙니다. GRU(Gated Recurrent Unit)가 궁금하신 분은 이곳을 참고하시면 좋을 것 같습니다. 자, 그럼 시작하겠습니다!

RNN의 기본 구조

RNN은 히든 노드가 방향을 가진 엣지로 연결돼 순환구조를 이루는(directed cycle) 인공신경망의 한 종류입니다. 음성, 문자 등 순차적으로 등장하는 데이터 처리에 적합한 모델로 알려져 있는데요. Convolutional Neural Networks(CNN)과 더불어 최근 들어 각광 받고 있는 알고리즘입니다.

위의 그림에서도 알 수 있듯 시퀀스 길이에 관계없이 인풋과 아웃풋을 받아들일 수 있는 네트워크 구조이기 때문에 필요에 따라 다양하고 유연하게 구조를 만들 수 있다는 점이 RNN의 가장 큰 장점입니다.

RNN의 기본 구조는 위 그림과 같습니다. 녹색 박스는 히든 state를 의미합니다. 빨간 박스는 인풋 $x$, 파란 박스는 아웃풋 $y$입니다. 현재 상태의 히든 state $h_t$는 직전 시점의 히든 state $h_{t-1}$를 받아 갱신됩니다.

현재 상태의 아웃풋 $y_t$는 $h_t$를 전달받아 갱신되는 구조입니다. 수식에서도 알 수 있듯 히든 state의 활성함수(activation function)비선형 함수하이퍼볼릭탄젠트(tanh)입니다.

그런데 활성함수로 왜 비선형 함수를 쓰는걸까요? 밑바닥부터 시작하는 딥러닝의 글귀를 하나 인용해 보겠습니다.

선형 함수인 $h(x) = cx$를 활성 함수로 사용한 3층 네트워크를 떠올려 보세요. 이를 식으로 나타내면 $y(x) = h(h(h(x)))$가 됩니다. 이 계산은 $y(x) = c * c * c * x$처럼 세번의 곱셈을 수행하지만 실은 $y(x) = ax$와 똑같은 식입니다. $a = c^3$이라고만 하면 끝이죠. 즉 히든레이어가 없는 네트워크로 표현할 수 있습니다. 그래서 층을 쌓는 혜택을 얻고 싶다면 활성함수로는 반드시 비선형함수를 사용해야 합니다.

RNN의 기본 구조

RNN의 기본 동작을 직관적으로 이해해 보기 위해 CS231n 강좌의 Karpathy갓파시가 든 예제를 가져와 봤습니다. 어떤 글자가 주어졌을 때 바로 다음 글자를 예측하는 character-level-model을 만든다고 칩시다. 예컨대 RNN 모델에 ‘hell’을 넣으면 ‘o’를 반환하게 해 결과적으로는 ‘hello’를 출력하게 만들고 싶은 겁니다.

우선 우리가 가진 학습데이터의 글자는 ‘h’, ‘e’, ‘l’, ‘o’ 네 개뿐입니다. 이를 one-hot-vector로 바꾸면 각각 $[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]$이 됩니다.

$x_1$은 $[1,0,0,0]$입니다. 이를 기반으로 $h_1$인 $[0.3, -0.1, 0.9]$를 만들었습니다($h_0$는 존재하지 않기 때문에 랜덤 값을 집어넣습니다). 이를 바탕으로 $y_1$인 $[1.0, 2.2, -3.0, 4.1]$로 생성했습니다. 마찬가지로 두번째, 세번째, 네번째 단계들도 모두 갱신하게 됩니다. 이 과정을 순전파(foward propagation)라고 부릅니다.

다른 인공신경망과 마찬가지로 RNN도 정답을 필요로 합니다. 모델에 정답을 알려줘야 모델이 parameter를 적절히 갱신해 나가겠죠. 이 경우엔 바로 다음 글자가 정답이 되겠네요. 예컨대 ‘h’의 다음 정답은 ‘e’, ‘e’ 다음은 ‘l’, ‘l’ 다음은 ‘l’, ‘l’ 다음은 ‘o’가 정답입니다.

위의 그림을 기준으로 설명을 드리면 첫번째 정답인 ‘e’는 두번째 요소만 1이고 나머지가 0인 one-hot-vector입니다. 그림을 보면 아웃풋에 진한 녹색으로 표시된 숫자들이 있는데 정답에 해당하는 인덱스를 의미합니다. 이 정보를 바탕으로 역전파(backpropagation)를 수행해 parameter값들을 갱신해 나갑니다.

그렇다면 RNN이 학습하는 parameter는 무엇일까요? 인풋 $x$를 히든레이어 $h$로 보내는 $W_{xh}$, 이전 히든레이어 $h$에서 다음 히든레이어 $h$로 보내는 $W_{hh}$, 히든레이어 $h$에서 아웃풋 $y$로 보내는 $W_{hy}$가 바로 parameter입니다. 그리고 모든 시점의 state에서 이 parameter는 동일하게 적용됩니다(shared weights).

RNN의 순전파

앞장에서 말씀드린 RNN의 기본 구조를 토대로 forward compute pass를 아래와 같이 그려봤습니다. 위에서 설명한 수식을 그래프로 옮겨놓은 것일 뿐입니다.

RNN의 역전파

자, 이제 backward pass를 볼까요? 아래 그림과 같습니다. 혹시 역전파가 생소하신 분은 이곳을 참고하시기 바랍니다.

위 움짤과 아래 그림은 같은 내용입니다. 우선 forward pass를 따라 최종 출력되는 결과는 $y_t$입니다. 최종 Loss에 대한 $y_t$의 그래디언트($dL/dy_t$)가 RNN의 역전파 연산에서 가장 먼저 등장합니다. 이를 편의상 $dy_t$라고 표기했고, 순전파 결과 $y_t$와 대비해 붉은색으로 표시했습니다. 앞으로 이 표기를 따를 예정입니다.

$dy_t$는 덧셈 그래프를 타고 양방향에 모두 그대로 분배가 됩니다. $dW_{hy}$는 흘러들어온 그래디언트 $dy_t$에 로컬 그래디언트 $h_t$를 곱해 구합니다. $dh_t$는 흘러들어온 그래디언트 $dy_t$에 $W_{hy}$를 곱한 값입니다. $dh_{raw}$는 흘러들어온 그래디언트인 $dh_t$에 로컬 그래디언트인 $1-tanh^2(h_{raw})$을 곱해 구합니다. 나머지도 동일한 방식으로 구합니다.

다만 아래 그림에 주의할 필요가 있습니다. RNN은 히든 노드가 순환 구조를 띄는 신경망입니다. 즉 $h_t$를 만들 때 $h_{t-1}$가 반영됩니다. 바꿔 말하면 아래 그림의 $dh_{t-1}$은 t-1 시점의 Loss에서 흘러들어온 그래디언트인 $W_{hy}*dy_{t-1}$뿐 아니라 ★에 해당하는 그래디언트 또한 더해져 동시에 반영된다는 뜻입니다.

LSTM의 기본 구조

RNN은 관련 정보와 그 정보를 사용하는 지점 사이 거리가 멀 경우 역전파시 그래디언트가 점차 줄어 학습능력이 크게 저하되는 것으로 알려져 있습니다. 이를 vanishing gradient problem이라고 합니다.

이 문제를 극복하기 위해서 고안된 것이 바로 LSTM입니다. LSTM은 RNN의 히든 state에 cell-state를 추가한 구조입니다. LSTM을 가장 쉽게 시각화한 포스트를 기본으로 해서 설명을 이어나가겠습니다.

cell state는 일종의 컨베이어 벨트 역할을 합니다. 덕분에 state가 꽤 오래 경과하더라도 그래디언트가 비교적 전파가 잘 되게 됩니다. LSTM 셀의 수식은 아래와 같습니다. ⊙는 요소별 곱셈을 뜻하는 Hadamard product 연산자입니다.

[\begin{align} { f }_{ t }&=\sigma ({ W }_{ xh_ f }{ x }_{ t }+{ W }_{ hh_ f }{ h }_{ t-1 }+{ b }_{ h_ f })\ { i }_{ t }&=\sigma ({ W }_{ xh_ i }{ x }_{ t }+{ W }_{ hh_ i }{ h }_{ t-1 }+{ b }_{ h_ i })\ { o }_{ t }&=\sigma ({ W }_{ xh_ o }{ x }_{ t }+{ W }_{ hh_ o }{ h }_{ t-1 }+{ b }_{ h_ o })\ { g }_{ t }&=\tanh { ({ W }_{ xh_ g }{ x }_{ t }+{ W }_{ hh_ g }{ h }_{ t-1 }+{ b }_{ h_ g }) } \ { c }_{ t }&={ f }_{ t }\odot { c }_{ t-1 }+{ i }_{ t }\odot { g }_{ t }\ { h }_{ t }&={ o }_{ t }\odot \tanh { ({ c }_{ t }) } \end{align}]

forget gate $f_t$는 ‘과거 정보를 잊기’를 위한 게이트입니다. $h_{t-1}$과 $x_t$를 받아 시그모이드를 취해준 값이 바로 forget gate가 내보내는 값이 됩니다. 시그모이드 함수의 출력 범위는 0에서 1 사이이기 때문에 그 값이 0이라면 이전 상태의 정보는 잊고, 1이라면 이전 상태의 정보를 온전히 기억하게 됩니다.

input gate $i_t⊙g_t$는 ‘현재 정보를 기억하기’ 위한 게이트입니다. $h_{t-1}$과 $x_t$를 받아 시그모이드를 취하고, 또 같은 입력으로 하이퍼볼릭탄젠트를 취해준 다음 Hadamard product 연산을 한 값이 바로 input gate가 내보내는 값이 됩니다. 개인적으로 $i_t$의 범위는 0~1, $g_t$의 범위는 -1~1이기 때문에 각각 강도와 방향을 나타낸다고 이해했습니다.

LSTM의 순전파

LSTM 순전파는 아래와 같습니다.

여기서 주목해야 할 점은 $H_t$입니다. 이 행렬을 행 기준으로 4등분해 $i, f, o, g$ 각각에 해당하는 활성함수를 적용하는 방식으로 $i, f, o, g$를 계산합니다. (물론 이렇게 계산하지 않고 다른 방식을 써도 관계는 없습니다) 이를 그림으로 나타내면 다음과 같습니다.

LSTM의 역전파

그럼 이제 LSTM의 역전파를 알아볼까요? 아래 움짤과 같습니다.

이제부터 나열한 그림은 위 움짤과 내용이 같습니다. 우선 $df_t, di_t, dg_t, do_t$를 구하기까지 backward pass는 RNN과 유사합니다.

$dH_t$를 구하는 과정이 LSTM backward pass 핵심이라고 할 수 있죠. $H_t$는 $i_t, f_t, o_t, g_t$로 구성된 행렬입니다. 바꿔 말하면 각각에 해당하는 그래디언트를 이를 합치면(merge) $dH_t$를 만들 수 있다는 뜻입니다. $i, f, o$의 활성함수는 시그모이드이고, $g$만 하이퍼볼릭탄젠트입니다. 각각의 활성함수에 대한 로컬 그래디언트를 구해 흘러들어온 그래디언트를 곱해주면 됩니다.

순전파 과정에서 $H_t$를 4등분해 $i_t, f_t, o_t, g_t$를 구했던 것처럼, backward pass에서는 $d_i, d_f, d_o, d_g$를 다시 합쳐 $dH_t$를 만듭니다. 이렇게 구한 $dH_t$는 다시 RNN과 같은 방식으로 역전파가 되는 구조입니다.

LSTM은 cell state와 히든 state가 재귀적으로 구해지는 네트워크입니다. 따라서 cell state의 그래디언트와 히든 state의 그래디언트는 직전 시점의 그래디언트 값에 영향을 받습니다. 이는 RNN과 마찬가지입니다. 이를 역전파시 반영해야 합니다.

파이썬 구현

CS231n 강좌에 파이썬 numpy 패키지만 활용해 구현해놓은 RNN 코드가 있습니다. 여기서 손실함수만 바꾸면 비교적 쉽게 LSTM 구조로 변경할 수가 있는데요. 제가 인터넷에 떠다니는 여러 자료를 보면서 글자나 단어 단위로 학습하기 위한 LSTM 손실 함수를 만들어봤습니다. 위 설명과 notation이 약간 다르긴 한데, 본질적으로는 완전히 같은 코드입니다.

파일럿 실험

이광수 장편소설 ‘무정’에 위 코드를 실험해봤습니다. ‘무정’은 32만 어절로 이뤄진 작품입니다. 1917년 작품이며 한자어와 대화체 문장이 많습니다. 텍스트는 이렇게 생겼습니다.

형식은, 아뿔싸! 내가 어찌하여 이러한 생각을 하는가, 내 마음이 이렇게 약하던가 하면서 두 주먹을 불끈 쥐고 전신에 힘을 주어 이러한 약한 생각을 떼어 버리려 하나, 가슴속에는 이상하게 불길이 확확 일어난다. 이때에, “미스터 리, 어디로가는가” 하는 소리에 깜짝 놀라 고개를 들었다. (중략) 형식은 얼마큼 마음에 수치한 생각이 나서 고개를 돌리며, “아직 그런말에 익숙지를 못해서……” 하고 말끝을 못 맺는다. 
“대관절 어디로 가는 길인가? 급하지 않거든 점심이나 하세그려.”
“점심은 먹었는걸.”
“그러면 맥주나 한잔 먹지.”
“내가 술을 먹는가.”
(중략)
“요― 오메데토오(아― 축하하네). 이이나즈케(약혼한사람)가 있나 보네 그려. 음나루호도(그러려니). 그러구도 내게는 아무 말도 없단 말이야. 에, 여보게”하고 손을 후려친다.

이 텍스트를 글자 단위로 one-hot-vector로 바꾼 뒤 LSTM에 넣어 학습시켜 보기로 했습니다. 하이퍼파라메터는 히든 차원수 100, learning rate 0.1을 줬습니다. 다음은 학습 결과입니다.

Iter 0 : 랫萬게좁뉘쁠름끈玄른작밭裸觀갈나맡文플조바늠헝伍下잊볕홀툽뤘혈調記운피悲렙司狼독벗칼둡걷착날完잣老엇낫業4改‘촉수릎낯깽잊쯤죽道넌友련친씌았융타雲채發造거크휘탁亨律與命텐암먼헝평琵헤落유리벤産이馨텐

Iter 4900: 를왔다내 루방덩이종 은얼에는 집어흔영채는아무 우선을 에서가며 건들하아버전는 애양을자에 운 모양이 랐다. 은 한다선과 ‘마는 .식세식가들어 ,

형식다

“내었다.있이문

Iter750000 : 으로 유안하였다. 더할까하는 세상이 솔이요, 알고 게식도 들어울는 듯하였다. 태에그려 깔깔고 웃는듯이 흔반다. 우선형은사람을 어려보낸다.

“그려가?”

한다. 영채는손을 기쁘

Iter1000000 : 에 돌내면서,

“여러 넣어오습데다. 그 말대 아무도좀 집림과 시오 백매, 저는 열녀더러, 기런 소년이가아니라.”

“어리지요.”

노파도 놀라며,

“저희마다가말없습니까.”

“아니 (대화체)

꽤 오랜 시간 학습시켰음에도 여전히 뜻 모를 글자들을 내뱉고 있는 점이 아쉽습니다. 다만 ‘영채’, ‘선형’ 등 무정 인물명들을 언급하거나, 따옴표를 써서 대화체 문장을 구성하거나, ‘-요’ ‘-까’ ‘-다’ 같은 종결어미를 사용해 문장을 끝맺고 있는 등 잘 하고 있는 점도 눈에 띕니다. 긴 글 읽어주셔서 감사합니다.

Comment  Read more

Word2Vec으로 문장 분류하기

|

이번 포스팅에선 요즘 인기를 끌고 있는 단어 임베딩 방법론 가운데 하나인 Word2Vec을 활용해서 문장을 분류하는 방법에 대해 이야기해보려고 합니다. 우선은 뽐뿌, 클리앙, 세티즌 등 휴대폰 리뷰사이트에 있는 스마트폰 리뷰들을 분석해 보려고 하는데요. 어떤 일을 하려고 하는지 한번 예를 들어보죠.

리뷰1: 발열은 LTE폰의 숙명 ㅠㅠ

리뷰2: HD촬영기능 하나만으로도 충분히 만족하시리라 봅니다~~

리뷰1을 작성한 사용자는 배터리를 휴대폰의 중요한 기능이라고 생각하는 모양입니다. 리뷰2의 경우엔 카메라겠지요. 이렇게 리뷰가 하나 주어졌을 때 해당 리뷰를 작성한 사용자가 휴대폰의 어떤 기능을 중시하는지를 알아맞혀 보고 싶은 겁니다. 다시 말해 휴대폰 리뷰 문장을 ‘배터리’, ‘카메라’, ‘디자인’, ‘사운드’ 따위의 기능(범주)으로 분류(classification)하는 문제가 관심이 되겠습니다. 물론 사람이 리뷰를 하나하나 읽어보면서 확인해도 되지만 21세기를 살아가는 우리는 컴퓨터의 힘을 빌려보죠.

Word2Vec으로 단어 임베딩하기

2013년 구글에서 개발한 Word2Vec이라는 방법론이 있습니다. 이름 그대로 단어(Word)를 벡터(Vector)로 바꿔주는 방법입니다. 이를 임베딩(Embedding)이라고 합니다. Word2Vec을 정확하게 이해하려면 역시 논문을 읽는 것을 추천하고요, Word2Vec 학습 방식에 관심이 있으신 분은 이곳을, GloVe, Fasttext 같은 다른 방법론과의 비교에 관심 있으시면 이곳에 한번 들러보셔요.

주지하다시피 Word2Vec의 효과는 놀랍습니다. 단어를 벡터화할 때 단어의 문맥적 의미를 보존하기 때문이죠. 위의 그림처럼 MAN과 WOMAN 사이의 거리는 KING과 QUEEN 거리와 유사합니다. 벡터로 바뀐 단어들은 ‘유클리디안 거리’니, ‘코사인 유사도’니 하는 방식들로 그 거리를 잴 수 있고 그 거리가 가까울(작을) 경우 의미가 비슷한 단어라고 해석할 수 있게 됩니다.

말로만 장황하게 얘기하는 것보다는 예를 드는 것이 좋겠네요. 우선 루리웹, 뽐뿌, 세티즌, 클리앙, 플레이웨어즈 5개 사이트에서 총 29만7906개의 리뷰를 수집했습니다. 이후 포스태깅(형태소분석) 작업을 실시했습니다. 대표적인 한국어 포스태거로 KoNLPy가 있는데요, 저는 이것 말고 김현중 서울대 박사과정이 개발한 cohesion tokenizer를 사용했습니다. cohesion tokenizer는 KoNLPy처럼 품사 정보까지 반환하지는 않지만 토크나이징을 분석 대상 코퍼스의 출현 빈도를 학습한 결과를 토대로 토큰을 나눠주기 때문에 분석 품질이 비교적 좋습니다. Word2Vec에 품사정보까지 넣을 필요는 없기도 하고요. 어쨌든 cohesion tokenizer로 토크나이징한 결과물은 다음과 같습니다.

발열,은,LTE,폰,의,숙명,ㅠㅠ

HD,촬영,기능,하나,만,으로,도,충분히,만족,하시리,라,봅,니다

이렇게 토크나이징한 결과물을 파이썬 gensim 패키지를 활용해 Word2Vec 방법론을 적용합니다. Word2Vec을 적용하는 데 단 두 줄이면 됩니다.

# Word2Vec embedding
from gensim.models import Word2Vec
embedding_model = Word2Vec(tokenized_contents, size=100, window = 2, min_count=50, workers=4, iter=100, sg=1)

위 코드 의미는 다음과 같습니다. 포스태깅된 컨텐츠를 100차원의 벡터로 바꿔라. 주변 단어(window)는 앞뒤로 두개까지 보되, 코퍼스 내 출현 빈도가 50번 미만인 단어는 분석에서 제외해라. CPU는 쿼드코어를 쓰고 100번 반복 학습해라. 분석방법론은 CBOW와 Skip-Gram 중 후자를 선택해라.

그럼 임베딩이 잘 됐는지 확인해볼까요? gensim 패키지가 제공하는 기능 중에 ‘most_similar’라는 함수가 있습니다. 두 벡터 사이의 코사인 유사도를 구해줍니다. 그 값이 클 수록 비슷한 단어라는 뜻인데, 아래 코드는 ‘디자인’이라는 단어와 가장 비슷한(코사인 유사도가 큰) 100개 단어를 출력하라는 지시입니다.

# check embedding result
print(embedding_model.most_similar(positive=["디자인"], topn=100))

Word2Vec 모델이 내뱉는 결과는 아래와 같습니다.

색감, 그립감, 외형, 색깔, UI, 색깔, 각진, 뒷면, 외관…

“오 생각보다 괜찮다.” 결과물을 처음 보고 느낀 점입니다. 같은 방식으로 ‘사운드’도 해봤습니다.

오디오, 음장, 음질, 퀄리티, 헤드, MP3, 스피커…

역시 굿입니다.

단어벡터로 가중치 행렬 만들기

우리가 하고 싶은 작업은 이것입니다.

문맥적 정보가 보존된 상태의 단어 벡터 사이의 거리(유사도)를 구하고 이를 가중치 삼아 각 문장별로 스코어를 구한다. 이렇게 구한 스코어를 바탕으로 각 리뷰 문장을 특정 기능에 할당(분류)한다.

뭔가 어렵죠? 앞으로 차근차근 설명해보겠습니다.

Word2Vec의 아웃풋은 아래와 같은 단어벡터 행렬입니다. 첫번째 열의 각 요소는 위의 코드 가운데 ‘min_count’ 조건을 만족하는 코퍼스 내 모든 단어가 됩니다. 아래 행렬의 열의 개수는 ‘‘임베딩 차원수(size) + 1(단어가 속한 열)’이 됩니다. 다시 말해 행벡터가 각 단어에 대응하는 단어벡터라는 뜻이지요. 하지만 행렬 각 요소의 숫자들은 사람이 이해하기 어렵습니다. 그도 그럴 것이 100차원 벡터공간의 좌표값들이기 때문입니다사람은 4차원도 못그리는데 말이죠.

- V1 V2 V3
배터리 0.1256 0.2211 0.5473
발열 0.2385 0.7562 0.8754
0.2845 0.1293 0.9483

이를 사람이 이해하기 편하게 거리행렬(distance matrix)로 바꿔볼까요? 거리를 재는 방식은 다양하지만 일단은 가장 친숙한 유클리디안 방법을 써보겠습니다. 직각삼각형의 너비와 높이를 알면 피타고라스 정리에 의해 빗변의 길이를 구할 수 있죠? 정확히 그 식을 사용해 100차원 공간 안에 있는 벡터들 사이의 길이를 재는 겁니다. 이렇게 구한 거리행렬은 아래와 같습니다.

- 배터리 발열
배터리 0 1 10
발열 1 0 8
10 8 0

설명의 편의를 위해 제가 임의의 숫자를 적었습니다만, 위의 거리행렬이 의미하는 바는 이렇습니다. ‘배터리’와 ‘배터리’ 사이의 거리는 얼마일까요? 정확하게 일치하기 때문에 0입니다. 마찬가지로 ‘발열’과 ‘발열’, ‘은’과 ‘은’ 거리도 0입니다. 이런 방식으로 거리행렬의 모든 대각성분은 0이 됩니다.

한편 예시에서는 ‘배터리’와 ‘발열’ 사이의 거리가 1, ‘배터리’와 ‘은’은 10으로 나왔습니다. 그렇다면 ‘은’보다는 ‘발열’이 ‘배터리’와 유사한 단어라고 볼 수 있겠네요. 이것이 이제 우리가 만들 가중치 행렬이 지향하는 핵심 원리입니다. 즉, 특정 쿼리 단어(예를 들어 ‘배터리’)와 거리가 가까운(=의미가 유사한) 단어는 높은 가중치, 그렇지 않은 단어는 낮은 가중치를 가지도록 가중치행렬을 만들어보자는 것입니다. 이를 수식으로 나타내면 다음과 같습니다.

[{ W }{ ij }=exp\left( -\frac { d{ ({ x }{ i },{ x }_{ j }) }^{ 2 } }{ 2\sigma^{2} } \right)]

왜 이렇게 복잡한 수식을 쓰냐고요? 통계학을 전공하신 분이라면 한눈에 알아보셨겠지만, $exp$ 앞의 계수를 제외하면 이는 정규분포(normal distribution) 식과 같습니다. 정규분포는 연속 확률 분포의 일종으로 수많은 자연, 사회현상을 설명하는 데 탁월한 분석도구로 정평이 나 있습니다. 위 식 지수의 분자에 $d$는 거리행렬의 ‘거리’를 의미합니다. 즉 0에서 ∞ 범위를 지니는 들쭉날쭉한 벡터간 거리들을 아주 예쁜 모양의 정규분포로, 그것도 특정 범위로 스케일링까지 해서 반환한다는 얘기입니다.

거리행렬에 위 수식을 적용한 행렬에서 우리가 원하는 특정 쿼리 단어(예를 들어 ‘배터리’와 ‘사운드’)만 남기고 나머지를 제거한 행렬이 바로 가중치 행렬이 됩니다. 아래와 최종 결과입니다. 다시 한번 가중치행렬의 의미를 곱씹어 보면, 쿼리단어인 ‘배터리’와 의미가 유사한 ‘발열’이라는 단어는 높은 가중치(0.9)를, ‘배터리’와 별 상관이 없는 조사 ‘은’은 낮은 가중치(0.1)를 갖습니다. 마찬가지로 ‘사운드’ 기준으로 보면 이와 관련이 높은 ‘음질’이라는 단어는 높은 가중치(0.84)를, 그렇지 않은 나머지 단어들은 낮은 가중치를 갖게 됩니다.

- 배터리 발열 음질
배터리 1 0.9 0.1 0.1
사운드 0.1 0.1 0.01 0.84

가중치 행렬로 문장별 스코어 구하기

이제 처음 우리가 풀려고 했던 문제를 다시 떠올려봅시다. 휴대폰 리뷰 문장을 ‘배터리’, ‘카메라’, ‘디자인’, ‘사운드’ 따위의 기능(범주)으로 분류(classification)하려고 합니다.

발열,은,LTE,폰,의,숙명,ㅠㅠ

자, 7개 단어로 이뤄진 위 문장의 스코어를 매겨볼까요? 처음 등장한 단어 ‘발열’의 가중치는 0.9입니다. ‘은’은 0.1이네요. 이렇게 문장에 등장한 7개 단어에 해당하는 가중치를 가중치행렬에서 Lookup 방식으로 가져올 수 있습니다. 7개 단어 가중치를 모두 더한 값이 바로 이 문장이 ‘배터리’ 기능을 얼마나 중시하는지를 알려주는 지표가 되는 겁니다. 즉, ‘배터리’ 스코어는 ‘배터리’라는 쿼리 단어와 나머지 단어 사이의 가중치들의 선형결합(linear combination)입니다.

그런데 여기서 문제가 하나 있습니다. 문장에 등장한 단어 하나하나마다 가중치행렬에서 Lookup 형식으로 가중치들을 가져오는 건 계산상 너무 비효율적입니다. 위 문장만 해도 단어가 7개 있으므로 무려 7번이나 Lookup을 해야 한다는 얘기입니다. 이를 좀 빠르고 편하게 하는 방법이 없을까요?

이럴 때 단어문서행렬(Term-Document Matrix)가 강력한 힘을 발휘합니다. TDM의 행은 ‘단어’, 열은 ‘문서’가 됩니다. 즉 위 문장을 아래와 같은 행렬로 변환하는 작업입니다.

- Doc1 Doc2
발열 1 0
1 0

위 행렬을 해석하면 이렇습니다. ‘발열,은,LTE,폰,의,숙명,ㅠㅠ’이라는 Doc1은 ‘발열’이라는 단어가 문장에 있기 때문에 ‘발열’ 행, ‘Doc1’ 열의 값은 1이 됩니다. 마찬가지로 ‘은’ 행, ‘Doc1’ 열도 1입니다. 만약 행에 해당하는 단어가 쓰이지 않은 리뷰(doc)의 요소 값은 0, 쓰였다면 1이 됩니다. 저의 경우 단어 등장여부를 binary로 TDM을 구축했습니다. 즉, ‘발열’이라는 단어가 한번 쓰였든 두번 쓰였든 그 값을 1로 했다는 뜻입니다. 물론 빈도수 그대로 TDM을 구축해도 될 겁니다.

자, 이제 거의 다 왔습니다!

TDM과 가중치행렬을 내적(inner product)해주면 문장별로 스코어를 한방에 구할 수 있습니다. 내적 개념이 생소하거나 헷갈리시는 분이라면 선형대수학(Linear Algebra)을 처음부터 파실 필요는 없고, 고등학교 수학 책을 다시 한번 보시면 됩니다. 직관적으로 이해할 수 있도록 아래 예시를 준비했는데요. 우선 말뭉치에 등장하는 전체 단어 수가 7개이고, 우리가 조사하고 싶은 기능은 $f_1$, $f_2$, $f_3$ 이렇게 세 가지가 있다고 가정해보겠습니다. 두번째와 여섯번째 단어로 구성된 리뷰의 각 기능별 스코어는 다음과 같습니다.

보시다시피 기능별 스코어는 TDM에서 1에 해당하는 위치의 가중치행렬 열벡터를 참조(Lookup)해 이를 기능별로 따로 합산하는 방식으로 계산하게 됩니다. 이를 전체 리뷰로 확장하게 되면 전체 내적의 결과는 (쿼리 단어의 수 x 문서의 수) 행렬 형태가 됩니다. 즉, Doc1의 ‘배터리’ 스코어가 이 스코어행렬의 1행 1열에 해당하는 요소가 되는 것이죠. 만약 쿼리 단어를 ‘배터리’뿐 아니라 ‘사운드’, ‘카메라’ 등까지 지정했다면 같은 방식으로 Doc1의 ‘사운드’ 스코어는 2행 1열, Doc1의 ‘카메라’ 스코어는 3행 1열이 됩니다. 마찬가지로 Doc2의 ‘배터리’, ‘사운드’, ‘카메라’ 스코어는 1행 2열, 2행 2열, 3행 2열이 됩니다.

파일럿 실험 결과

휴대폰 리뷰 29만7906개를 위와 같은 방식으로 스코어를 매겼습니다. 제가 임의로 선정한 쿼리 단어는 ‘디자인’, ‘화면’, ‘음질’, ‘스펙’, ‘촬영’, ‘운영체제’, ‘배터리’ 총 7개입니다. 위의 챕터에도 설명했듯 각 리뷰별로 쿼리단어 수(제 경우엔 7개)에 해당하는 스코어들이 나옵니다. 여기서 가장 높은 값을 지닌 스코어에 해당하는 쿼리단어를 해당 리뷰가 중시하는 기능으로 분류했습니다. 결과(각 기능별 스코어 상위 5개)는 아래와 같습니다.

배터리

케이스 끼웠고요. 발열은 액정위에서 일어나는겁니다.
ls 전자꺼 사용 중인데 충전 잘 되네요... 하지만 무선충전에 단점 발열 ㅠㅠ
근데 진짜 꼽을게..............발열뿐
아이패드2는 정말... 발열이라는 것을 몰랐는데...
베가레이서3은진짜 발열,베터리만좋으면 짱인데

촬영

갤럭시S 2 사진 촬영/ 동영상 촬영
촬영은 기존에 사용중인 SKT 갤투로 찰칵~
전 카메라 화질과 720p 촬영이 중요한데 어떨런지
3d 촬영이요
헉 그렇게 무겁나요;;;;3D로 영상촬영도 된다던데;;; 잘 나오려나;;

디자인

제가 코 파다 피나면 저 색깔 나오는데.. 아침에 똥 누다가도 가끔 나와요.. 그래서 웬지 친근한 색감
액정색깔차이만 눈에 들어오네요
이거 궁금해서 `색상` `색깔`로 한번씩 검색하니 많이 나오더라구요
미치도록 선명한 대화면 액정과 완전 편리한 UI 아몰레드에 푹 빠져봅시다!!
삼성 핸드폰은 기능은 다 좋은거같은데 ........... 색깔 드럽게 못뽑는다는 ....

화면

갤3 화면 액정이 나갔는지.. 이상한 화면이 뜨는데요...
액정 화면은 몇 인치 인가요?
갤럭시 s3 흰색 화면 잔상
사진만 봐서는 갤스2 화면이 더 좋아보이네요. 갤스는 푸르딩딩한게 촌티나는 색상같아요
아무래도 화면밝기 낮추면 조금이라도 더 버텨주겠죠?ㅋㅋ

운영체제

결국은 운영체제에 따라 갈릴듯.
운영체제가 다르니 비교하기 그렇죠
운영체제가... 달라서..
운영체제가 쉣이었음
단일 운영체제 바다는 왜 그 모양인가요...

사운드

아레나에서도 이렇게 평했군요. 정말 음질 표현을 너무 잘했네욬ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
음질은안드에서상급이죠 ㅎㅎ
음질은 좋았으니.. 잭꽃아야되지만:
음질은... 제가 막귀라서. 핸드폰 음질 다 똑같은거 아닌가요?
스피커는 저도 공감 ㅋㅋㅋㅋ 음질은 먹는건가여 수준

스펙

스펙으로만 따져도 옴냐2보다 아이폰이 훨씬 성능이 좋을텐데요... ^^;;
갤투가 하드웨어 스펙이 좋죠 그래서 갤투 이제 os도 같고
그렇군요... 하긴 하드웨어 스펙도 더 낫구 ㅠㅠ
갤럭시는 나올때마다 스펙종결수준이니까요..ㅎㅎ
삼성 스펙만 쩔지... 벤치는 믿을게 못될듯하오

마치며

이상으로 Word2Vec을 활용한 문장 분류 방법을 알아보았습니다. 이 프레임워크를 단순하게 요약하면 다음과 같습니다. 우선 TDM을 구축하고, Word2Vec 기반으로 가중치매트릭스를 생성합니다.

위와 같이 구축한 가중치매트릭스와 TDM을 내적해 스코어를 산출합니다.

이미 눈치 채셨겠지만 어떤 문서가 특정 쿼리 단어와 얼마나 연관성이 있는지 스코어를 낼 수 있습니다. 바꿔 말하면 쿼리 단어를 어떻게 선정하느냐에 따라 다양한 문장분류기를 만들어낼 수 있다는 얘기입니다. 질문이나 지적해주실 내용 있으시면 메일이나 댓글 등으로 해주시면 됩니다. 여기까지 읽어주셔서 감사합니다.

Comment  Read more

이제 블로그 시작

|

이틀 간 기나긴 삽질 끝에 깃헙을 파고 드디어 블로그를 시작하게 됐다. jekyll을 이용한 블로그는 네이버나 티스토리 블로그에 비해 자유도가 높지만 진입장벽 또한 높아서 처음 세팅하는 데 무척 애를 먹었다. 공부한 내용들과 의문점들을 차곡차곡 적어나갈 계획이다. 일단은 자연언어처리, 머신러닝, 언어학 따위의 글들을 적을 것 같다. 초심을 잃지 말아야지..

Comment  Read more