분산 표현(Distributed Representation)

yuns_u·2021년 10월 26일
0

💛 문서 벡터화 : 등장 횟수 기반 표현, 분산 표현

문서 내 단어를 컴퓨터가 이해할 수 있도록 표현하는 것은 문서를 어떻게 벡터화할 것인가와 깊은 연관이 있다.
문서를 어떻게 벡터로 표현할 것인가에는 크게 두 가지 방법이 있다. 등장 횟수 기반 표현(Count-based Representation)분산 표현(Distributed Representation)이다.

등장 횟수 기반 표현은 문서 내 단어가 등장하는 횟수를 기반으로 문서를 벡터화하는 것이라면
분산 표현은 단어 자체를 벡터화하는 방법이다.

분산 표현에는 Word2Vec, fastText 등이 있으며 사용자가 벡터로 표현하고자 하는 타겟 단어(Target Word)가 해당 단어 주변 단어에 의해 결정된다.

💛 분산 표현(Distributed Representation)

분산 표현으로 문서를 벡터화하는 것은 분포 가설(Distribution Hypothesis)(linguistic items with similar distributions have similar meanings.)에 기반한다. 분포 가설의 핵심적인 주장은 "비슷한 위치에서 등장하는 단어들은 비슷한 의미를"가진다는 것이다.이는 비슷한 의미를 가진 단어는 주변 단어 분포도 비슷하다는 것을 뜻한다.

예를 들어
She is a beautiful woman.
She is an awesome woman.
에서 'beautiful'과 'awesome'은 해당 단어 주변에 분포한 단어가 유사하므로 두 단어의 뜻은 비슷할 것이라고 가정하는 것이 분포 가설인 것이다. 이러한 분포 가설에 기반하여 주변 단어 분포를 기준으로 단어의 벡터 표현이 결정되기 때문에 분산 표현이라고 불리게 되었다.

🍏 원-핫 인코딩(One-Hot Encoding)

원핫인코딩은 단어를 벡터화하고자 할 때 선택할 수 있는 가장 쉬운 방법이다.
표 형태의 데이터를 다룰 때 범주형 변수(카테고리)를 요소마다 0과 1의 형태로 나타내었던 것과 동일한 방법이다.
'I am a student' 를 원핫인코딩으로 나타내면 I:[1 0 0 0], am:[0 1 0 0], a:[0 0 1 0], student:[0 0 0 1]로 나타낼 수 있다.

원핫인코딩은 쉽게 이해할 수 있는 직관적인 방법이지만 단어 간 유사도를 구할 수 없다는 점에서 치명적인 단점을 가지고 있다고 할 수 있다. 단어 간 유사도는 코사인 유사도를 통해 구할 수 있다. 하지만 원핫인코딩을 사용한 두 벡터의 내적은 항상 0이므로 어떤 두 단어를 골라 코사인 유사도를 구하더라도 그 값은 0이 된다. 이렇게 두 단어 사이의 관계를 전혀 알 수 없다는 것이 원핫인코딩의 최대 단점이다.

원-핫 인코딩
장점: 직관적
단점: 단어 간 유사도 구할 수 없음.

코사인 유사도(Cosine Similarity) : 내적공간의 두 벡터간 각도의 코사인값을 이용하여 측정된 벡터간의 유사한 정도를 의미한다. 두 벡터의 방향이 완전히 동일한 경우에는 1의 값을 가지며, 90°의 각을 이루면 0, 180°로 반대의 방향을 가지면 -1의 값을 갖게 된다. 값이 1에 가까울 수록 유사도가 높다고 판단할 수 있다.

Cosine similarity=abab\large \text{Cosine similarity} = \frac{\vec{a} \cdot \vec{b} }{\vert \vec{a} \vert \vert \vec{b} \vert }

🍏 임베딩(Embedding)

원핫인코딩이 단어 간 유사도를 구할 수 없다는 문제점을 해결하고자 등장한 것이 임베딩(embedding)이다.
임베딩은 단어를 고정 길이의 벡터, 즉 차원이 일정한 벡터로 나타내기 때문에 이러한 이름이 붙었다.
임베딩을 거친 단어 벡터는 [0.04227, -0.0033, 0.1607, -0.0236, ...]처럼 원핫인코딩과는 다른 형태의 값을 가지게 된다. 위의 연속적인 수치들처럼 벡터 내의 각 요소가 연속적인 값을 가지게 되는 것이다.
임베딩은 자연어 처리 외에도 추천 시스템, GNN 등 다른 딥러닝 분야에서도 사용된다.
이러한 임베딩 방식 중 가장 널리 알려진 임베딩 방법인 Word2Vec에 대해 더 자세히 정리해보고자 한다.

🍎 Word2Vec

2013년에 고안된 Word2Vec은 단어를 벡터로 나타내는 방법으로 가장 널리 사용되는 임베딩 방법 중 하나이다.
Word2Vec은 특정 단어 양 옆에 있는 두 단어(window size =2)의 관계를 활용하기 때문에 분포 가설을 잘 반영하고 있다.
Word2Vec에는 CBoW와 Skip-gram이라는 두 가지 방법이 있다.

CBoW와 Skip-gram

  • CBoW(Continuous Bag-of-Words): 주변 단어에 대한 정보를 기반으로 중심 단어의 정보 예측
  • Skip-gram: 중심 단어의 정보를 기반으로 주변 단어의 정보를 예측하는 모델 인지

윤동주 시인의 <별 헤는 밤>의 일부분에 형태소 분석기로 토큰화한 것을 예로 들어 CBoW와 Skip-gram의 차이를 살펴보면 아래와 같다.

  • CBoW 를 사용하면 표시된 단어 정보를 바탕으로 아래의 [ ---- ] 에 들어갈 단어를 예측하는 과정으로 학습이 진행된다.

    “… 나 는 [ -- ] 하나 에 … “
    “… 는 별 [ ---- ] 에 아름다운 …”
    “… 별 하나 [ -- ] 아름다운 말 …”
    “… 하나 에 [ -------- ] 말 한마디 …”

  • Skip-gram을 사용하면 표시된 단어 정보를 바탕으로 다음의 [ ---- ] 에 들어갈 단어를 예측하는 과정으로 학습이 진행된다.

    “… [ -- ][ -- ] 별 [ ---- ][ -- ] …”
    “… [ -- ][ -- ] 하나 [ -- ][ -------- ] …”
    “… [ -- ][ ---- ] 에 [ -------- ][ -- ] …”
    “… [ ---- ][ -- ] 아름다운 [ -- ][ ------ ] …”

순전파 과정에서 CBoW가 Skip-gram보다 더 많은 정보를 바탕으로 특정 단어를 예측하기 때문에 더 성능이 좋을 것이라 판단할 수 있지만 역전파 관점에서 Skip-gram에서 더 많은 학습이 일어나기 대문에 Skip-gram의 성능이 CBoW보다 좀 더 좋게 나타나며 계산량이 Skip-gram이 더 많이 들어가는 리소스가 더 크다고 한다.

Word2Vec 모델 구조

성능이 좀 더 좋은 Skip-gram을 기준으로 Word2Vec의 구조에 대해 알아보도록 한다.

  • 입력층: 원핫인코딩된 단어 벡터
  • 은닉층: 임베딩 벡터의 차원수 만큼의 노드로 구성된 은닉층이 1개인 신경망
  • 출력층: 단어 개수 만큼의 노드로 이루어져 있으며 활성화 함수로 소프트맥스를 사용한다.

    위의 그림의 출처인 논문에서는 총 10,000개의 단어에 대해서 300차원의 임베딩 벡터를 구했기 때문에 신경망 구조가 위와 같아졌다.

Word2Vec 학습을 위한 학습 데이터 디자인

효율적인 학습을 위해서 학습 데이터를 잘 구성할 필요가 있다.
Word2Vec은 Window size가 2이므로 중심 단어 옆에 있는 2개의 단어에 대해 단어쌍을 구성한다.

"The tortoise jumped into the lake"라는 문장에 대해 단어쌍을 구성해본다면 윈도우 크기가 2인 경우 아래처럼 Skip-gram을 학습하기 위한 데이터쌍을 구축할 수 있다.

  • 중심단어: The // 주변문맥단어: tortoise, jumped
    -- 학습 샘플: (the, tortoise),(the, jumped)

  • 중심단어: tortoise // 주변문맥단어: the, jumped, into
    -- 학습 샘플:(tortoise, the), (tortoise, jumped), (tortoise, into)

  • 중심단어: jumped // 주변문맥단어: the, tortoise, into, the
    -- 학습 샘플: (jumped, the),(jumped, tortoise),(jumped, into),(jumped, the)

  • 중심단어: into // 주변문맥단어: tortoise, jumped, the, lake
    -- 학습 샘플: (into, tortoise),(into, jumped),(into, the),(into, lake)

Skip-gram에서는 이러한 데이터쌍으로 구성된 학습데이터를 활용하게 되는데, 중심단어를 입력으로, 문맥단어(주변문맥단어)를 레이블로 하는 분류(classification)를 학습시키는 것이다.

Word2Vec의 결과

학습을 모두 마치면 10,000개의 단어에 대해 300차원의 임베딩 벡터가 생성된다. 만약 임베딩 벡터의 차원을 조절하고 싶다면 은닉층의 노드 수를 줄이거나 늘릴 수 있다. 아래의 그림은 신경망 내부의 은닉층에 이쓴 10000x300 크기의 가중치 행렬에 의해서 10000개 단어에 대한 300차원의 벡터가 생성되는 모습을 나타낸 이미지이다.

학습 과정에서 학습의 효율을 높이기 위한 더 다양한 기법들이 있다.
sub-sampling, negative-sampling 등의 키워드를 통해 word2vec을 좀 더 적은 계산으로 하는 방법에 대해 조사해볼 것이다.

결과적으로 skip-gram 모델을 통해 10000개의 단어에 대한 임베딩 벡터를 얻을 수있다. 이렇게 얻은 임베딩 벡터는 문장 간의 관련도 계산, 문서 분류와 같은 작업에 사용할 수 있다.

Word2Vec으로 임베딩한 벡터 시각화

Word2Vec으로 임베딩한 벡터는 단어 간의 의미적, 문법적 관계를 잘 나타낸다.

  1. man-woman 사이의 관게가 king-queen 사이의 관계와 매우 유사하게 나타난다.
    생성된 임베딩 벡터가 단어의 의미적(semantic)관계를 잘 표현하는 것을 확인할 수 있다.

  2. walking-walked사이의 관계와 swimming-swam 사이의 관계가 유사하게 나타난다. 생성된 임베딩 벡터가 단어의 문법적(혹은 구조적, syntactic)인 관계도 잘 표현하는 것을 확인할 수 있다.

  3. 고유명사에 대해서도 나라-수도와 같은 관계를 잘 표현하고 있는 것을 확인할 수 있다.

gensim 패키지로 Word2Vec 실습하기

gensim은 word2vec으로 사전학습된 임베딩 벡터를 쉽게 사용해볼 수 있는 패키지이다.

!pip install gensim --upgrade

4.0 이상 버전의 gensim이 필요하다.

  1. 구글 뉴스 말뭉치로 학습된 word2vec 벡터를 다운 받는다.
  2. 0~9 인덱스에 위치한 단어가 무엇인지 확인해본다.
  3. 임베딩 벡터의 차원과 값을 눈으로 확인해본다.
  4. 말뭉치에 등장하지 않는 단어의 임베딩 벡터를 확인해본다.
  5. 단어 간 유사도 파악하기

🍎 fastText

fastText는 word2vec 방식에 철자(character) 기반의 임베딩 방식을 더해준 새로운 임베딩 방식이다.

fastText의 등장 배경

1) OOV(Out of Vocabulary) 문제

데이터수집을 아무리 열심히 해도 세상 모든 단어가 들어가 있는 말뭉치를 구하는 것은 불가능하다.
이전에는 쓰이지 않았던 신조어가 등장하기도 한다.
word2vec의 경우 이처럼 말뭉치에 등장하지 않은 단어에 대해서는 임베딩 벡터를 만들지 못한다는 단점이 있다.
이처럼 기존 말뭉치에 등장하지 않는 단어가 등장하는 문제를 OOV(Out of Vocabulary)문제라고 한다.

Word2vec은 등장하지 않는 단어에 대해서는 학습하지 않기 때문에 예측 혹은 추론 단계에서 새로운 단어가 등장하면 에러를 발생시킨다. 또한 적게 등장하는 단어(rare words)에 대해서는 학습이 적게 일어나기 때문에 적절한 임베딩 벡터를 생성해내지 못한다는 단점도 있다. 이러한 word2vec의 문제를 해결하기 위해 fastText가 등장했다.

2) 철자 단위 임베딩(Character level Embedding)

fastText는 OOV 문제를 철자 단위 임베딩을 보조 정보로 사용하여 해결하였다.
철자 단위 임베딩이란 모델이 학습하지 못한 단어라고 하더라도 잘 쪼개고 보면 말뭉치에서 등장했던 단어를 통해 유추해 볼 수 있다는 아이디어에서 출발했다.

맞벌이라는 단어를 모른다고해도 아래의 단어들을 알면 대략적인 의미를 유추해볼 수 있다.
맞절, 맞선, 맞대다, 맞들다, 맞장구치다, 맞잡다 ... 를 알면 접두사 '맞-'의 의미를 유추할 수 있다.
벌다, 벌어, 벌고 ...를 알면 어근 '벌'의 의미를 유추할 수 있다.
깊이, 넓이, 구이 ...를 알면 접미사 '-이'의 의미를 유추할 수 있다.
이 세 가지를 잘 조합하면 맞벌이의 의미를 유추할 수 있는 것이다.

❗️ fastText가 철자 단위 임베딩을 적용하는 방법은 Character n-gram이다.
이에 대해 추가적으로 더 조사해볼 필요가 있다.

fastText는 3~6개로 묶은 character의 정보(3~6 gram)단위를 사용한다.
3~6개 단위로 묶기 이전에 모델이 접두사와 접미사를 인식할 수 있도록 해당 단어 앞뒤로 '<','>'를 붙여준다.
그리고나서 해당 단어를 3~6개 character-level로 잘라서 임베딩을 적용한다.

위의 eating이라는 단어를 철자 단위 임베딩하는 과정은 3-gram 철자단위로 임베딩된 것이다.
이 과정을 거치면 3-gram에 대해서는 아래와 같은 6개의 철자 단위가 나오게 된다.

이와 같은 방식을 3개부터 6개까지 진행한 뒤 임베딩 벡터를 생성하고 원래 eating의 임베딩 벡터와 함께 사용하면 아래와 같이 나타낼 수 있다.

wordLength(n)Character n-grams
eating3<ea, eat, ati, tin, ing, ng>
eating4<eat, eati, atin, ting, ing>
eating5<eati, eatin, ating, ting>
eating6<eatin, eating, ating>

이렇게 총 18개(3+4+5+6)의 character-level n-gram을 얻을 수 있다.
fastText에서는 이러한 과정으로 얻어진 n-gram들의 임베딩 벡터를 모두 구하게 된다.
문서에 따라 상이하지만 상당한 수를 다루는 데에도 불구하고 알고리즘이 매우 효율적으로 구성되어 있어 word2vec과 비교했을 때 시간 상 큰 차이가 나지 않는다.

위처럼 eating이라는 단어가 말뭉치 내에 있다면 skip-gram으로부터 학습한 임베딩 백터에 위에서 얻은 18개 character-level n-gram들의 벡터를 더해준다.
반대로 eating이라는 단어가 말뭉치에 없다면 18개 character-level n-gram들의 벡터만으로 구성한다.

3) 철자 단위 임베딩 시각화

fastText의 철자 단위 임베딩이 어떤 관계를 맺고 있는지 이미지를 통해 확인해볼 수 있다.
아래의 그림은 X , Y축에 있는 단어 내 character n-gram에 대하여 서로의 연관관계를 나타낸 그래프이다.
빨간색을 나타낼수록 두 단어가 유사한 관계를 가지고 있음을 나타낸다.

위 그림에 따르면 ity>와 ness>가 매우 유사한 관계를 보인다고 할 수 있다.
이 둘은 모두 명사형으로 바꿔주는 접미사의 역할을 한다.
fastText를 사용하면 이처럼 단어의 문법적 구조를 잘 나타낸다는 특징을 가지고 있다.


위의 그림에서는 link와 nnect, onnect, connec 등이 상당히 유사한 관계에 있다는 것을 확인할 수 있다.
3~6개까지의 연속된 character를 다루고 있기 때문에 connect라는 단어 자체가 포함되어 있지는 않지만 connect와 link가 가지고 있는 연결하다라는 의미를 n-gram 임베딩 벡터도 유사하게 가지고 있다는 것을 확인할 수 있다.

예를 들어, connectivitiy와 linkage라는 단어의 유사도를 구한다고 한다면 Word2Vec은 두 단어 중 하나라도 말뭉치 내에 없다면 에러를 발생시키지만 fastText는 높은 정확도로 두 단어의 임베딩 벡터를 구하고 유사도를 구할 수 있다는 장점이 있다.

4) gensim 패키지로 fastText 실습하기

임베딩 벡터를 사용하여 문장 분류 수행하기

profile
💛 공부 블로그 💛

0개의 댓글