목차
👀, 🤷♀️ , 📜
이 아이콘들을 누르시면 코드, 개념 부가 설명을 보실 수 있습니다:)
자연어처리의 의미
Natural Language Processing (NLP)
자연어: 한국어와 영어 등 우리가 평소에 쓰는 말
자연어 처리: 컴퓨터가 우리 말을 알아듣게(이해하게)만드는 것 으로 ‘단어의 의미’를 이해시키는 게 중요
단어의 의미를 잘 파악하는 법
- 1) 시소러스를 활용한 기법
- 2) 통계 기반 기법
- 3) 추론 기반 기법(word2vec)
지난 포스트에서 1) 과 2)를 봤으니 이번엔 3)을 보겠다!
추론기반 기법 word2vec
신경망(word2vec)을 이용하여 추론을 하는 기법
⛔ 통계 기반 기법의 문제점
- 주변 단어의 빈도를 기초로 단어 표현 ➡ 대규모 말뭉치를 다룰 때 문제가 발생.
- 말뭉치 전체의 통계(동시발생 행렬과 PPMI 등)를 이용해 단 1회의 처리 (SVD 등)만에 단어의 분산 표현을 얻음( 추론기반에선 배치학습이라는 전체가 아닌 국소적 단위를 이용함)
- 이런 거대 행렬에 SVD를 적용하는 일은 현실적이지 않다.
⭕ 추론 기반 기법
추론 기반 기법: 주변 단어 (맥락)가 주어졌을 때 “?”에 무슨 단어가 들어가는지를 추측하는 작업
신경망을 이용하는 경우는 미니배치로 학습하는 것이 일반적 -> 신경망이 한번에 소량(미니배치)의 학습 샘플씩 반복해서 학습하며 가중치를 갱신.
➡ 말뭉치의 어휘 수가 많아 SVD 등 계산량이 큰 작업을 처리하기 어려운 경우에도 신경망을 학습 가능
➕ 추론기반, 통계기반 공통점
분포 가설에 기초: 단어의 의미는 주변 단어에 의해 형성된다에 기반 ➡ 단어의 동시발생 가능성
준비: 원핫 one-hot 표현
= 원핫 벡터
신경망에서의 단어 처리
신경망은 “you”와 “say” 등의 단어를 있는 그대로 처리할 수 없으니 단어를 ‘고정 길이의 벡터’로 변환 필요
➡ 단어를 one-hot 표현으로 변환.
원핫 표현: 벡터 원소 중 하나만 1이고 나머지는 모두 0인 벡터
[ex] “You say goodbye and I say hello.”
[만드는 법]
1) 총 어휘 수만큼의 원소를 갖는 벡터를 준비
2) 인덱스가 단어 ID와 같은 원소를 1로, 나머지는 모두 0으로
3) 이처럼 단어를 고정 길이 벡터로 변환하면 우리 신경망의 입력
층은 밑처럼 뉴런의 수를 ‘고정’가능
[장점]
- 단어를 벡터로 나타내기 가능
- 신경망을 구성하는 ‘계층’들은 벡터 처리 가능.
- 단어를 신경망으로 처리 가능
[신경망 처리]
원핫 표현으로 된 단어 하나를 완전연결계층을 통해 변환
- 완전연결계층: 각각의 노드가 이웃 층의 모든 노드와 화살표로 연결
- 이 화살표에는 가중치(매개변수)가 존재: 입력층 뉴런과의 가중합 weighted sum 이 은닉층 뉴런
- 편향을 생략(뒤에 설명)
가중치를 명확하게 보여주기 위해 이를 단순화 해서 그리면,
👀 코드 보기
import numpy as np
c = np.array([[1, 0, 0, 0, 0, 0, 0]]) # 입력/원핫표현
W = np.random.randn(7, 3) # 가중치
h = np.matmul(c, W) # 중간 노드
print(h)
# [[-0.70012195 0.25204755 -0.79774592]]
WARNING_ 이 코드에서 입력 데이터(c )의 차원 수(ndim)는 2입니다. 이는 미니배치 처리를 고려한 것으로, 최초의 차원(0번째 차원)에 각 데이터를 저장.
위의 그림의 행렬의 곱을 MatMul 계층으로 구현한다.
계산된 가중치에 해당 입력층에 맞는 인덱스에 해당하는 가중치를 뽑아낸다.
다시 설명하면 앞의 코드에서 c와 W의 행렬 곱 부분에 주목해보자.
➡️ c는 원핫 표현이므로 단어 ID에 대응하는 원소만 1이고 그 외에는 0인 벡터이다.
➡️ 따라서 앞 코드의 c와 W의 행렬 곱은 결국 위의 그림처럼 가중치의 행벡터 하나를 ‘뽑아낸’ 것과 같다.
🚫 문제점
그런데 위의 가중치 추출에서 가중치로부터 행벡터를 뽑아낼 뿐인데 행렬 곱을 계산하는 건 비효율적이다.
word2vec 개선 ① 절에서 개선할 예정이다.
또한, 앞의 코드로 수행한 작업은 (1장에서 구현한) MatMul 계층으로도 수행할 수 있다.
👀 코드, 코드 설명 보기
import sys
sys.path.append('..')
import numpy as np from common.layers import MatMul ## MatMul 소환
c = np.array([[1, 0, 0, 0, 0, 0, 0]])
W = np.random.randn(7, 3) # 가중치는 랜덤으로 설정해줘야 한다!! -> 학습하면저 알아서 고쳐진다
layer = MatMul(W)
h = layer.forward(c)
print(h)
# [[-0.70012195 0.25204755 -0.79774592]]
- common 디렉터리에 있는 MatMul 계층을 임포트해 사용.
- MatMul 계층에 가중치 W를 설정하고
- forward ( ) 메서드를 호출해 순전파를 수행합니다.
CBOW 모델
앞의 원핫벡터를 이용한 가중치 신경망을 구현해봤으니 단순한 word2vec 구현을 위한 준비는 끝났다.
이제 word2vec을 구현해보자.
word2vec의 대표적인 모델로는 크게 2가지인 CBOW 모델과 skip-gram모델이 있다.
그럼 그 중 하나인 CBOW 모델부터 구현해보자.
즉, 앞에서 설명한 밑의 그림을 구현해보자는 것이다.
CBOW 모델 사용
- ‘모델’을 신경망으로 구축이 목표
- word2vec에서 제안하는 CBOW continuous bag-of-words 신경망 사용
(CBOW 모델과 skip-gram 모델은 word2vec에서 사용되는 신경망)
[이 모델의 추론 처리]
CBOW 모델은 맥락으로부터 타깃 target을 추측하는 용도
- ‘타깃’: 중앙 단어
- ‘맥락’: 그 주변 단어들
[처리 overview]
입력을 원핫 표현으로 변환하여 시작한다
CBOW 모델의 입력: 맥락(그 주변 단어들)
원핫표현으로 변환함으로써, CBOW 모델이 처리할 수 있도록 준비
- 입력층이 2개 있고, 은닉층을 거쳐 출력층에 도달.
- 두 입력층에서 은닉층으로의 변환은 똑같은 완전연결계층(가중치는 W_in )이 처리
- 은닉층에서 출력층 뉴런으로의 변환은 다른 완전연결계층(가중치는 W out )이 처리
🤷♀️ 이 그림에서 입력층이 2개인 이유
맥락으로 고려할 단어를 2개로 정했기 때문.(you, goodbye)
즉, 맥락에 포함시킬 단어가 N개라면 입력층도 N개.
[은닉층]
은닉층의 뉴런은 입력층의 완전연결계층에 의해 변환된 값이 되는데,
입력층이 여러 개이면 전체를 ‘평균’하면 됨.
[출력층]
출력층의 뉴런은 총 7개인데, 이 뉴런 하나하나가 각각의 단어에 대응.
즉 결과로 나올 수 있는 값의 개수를 말함
- 출력층 뉴런은 각 단어의 ‘점수’를 뜻함
- 점수: 확률로 해석되기 전의 값
- 점수에 소프트맥스 함수를 적용해서 ‘확률’획득 가능
- 값이 높을수록 대응 단어의 출현 확률도 높아짐
입력층에서 은닉층으로의 변환은 완전연결계층(가중치는 \(W_{in}\) )에 의해서 이뤄짐
이때 완전연결계층의 가중치 \(W_{in}\) 은 7×3 행렬이며, 이 가중치가 바로 단어의 분산 표현의 정체.
- 가중치 \(W_{in}\) 의 각 행 = 해당 단어의 분산 표현
- 학습을 진행할수록 맥락에서 출현하는 단어를 잘 추측하는 방향으로 이 분산 표현들이 갱신
- 찾고자 하는 값인 “say”가 제일 까맣죠?
[핵심] 은닉층의 뉴런 수 < 입력층의 뉴런 수
은닉층: 단어 예측에 필요한 정보를 ‘간결하게’ 담음
➡ 결과적으로 밀집벡터 표현을 얻기 가능.
인코딩: 은닉층의 정보는 인간은 이해할 수 없는 코드로 쓰임.
디코딩: 은닉 층의 정보로부터 원하는 결과를 얻는 작업
➡ 인코딩 된 정보를 이해 가능한 표현으로 복원하는 작업
더 알아보기: 대충 이런 느낌이구나 라는 것만 가져가자
지금까지 우리는 CBOW 모델을 ‘뉴런 관점’에서 그림
‘계층 관점’에서 그림(밑)
주의) 편향을 사용하지 않는 완전연결계층의 처리는 MatMul 계층의 순전파와 같음
계층은 내부에서 행렬 곱을 계산.
👀 CBOW 모델의 추론 처리 구현 코드 보기
추론 처리란 ‘점수’를 구하는 처리임
import sys
sys.path.append('..')
import numpy as np from common.layers import MatMul
# 샘플 맥락 데이터
c0 = np.array([[1, 0, 0, 0, 0, 0, 0]])
c1 = np.array([[0, 0, 1, 0, 0, 0, 0]])
# 가중치 초기화
W_in = np.random.randn(7, 3)
W_out = np.random.randn(3, 7)
# 계층 생성
# 처리하는 MatMul 계층을 맥락 수만큼 (여기에서는 2개) 생성
# 출력층 측의 MatMul 계층은 1개만 생성합니다
in_layer0 = MatMul(W _in)
in_layer1 = MatMul(W _in)
out_layer = MatMul(W _out)
# 순전파
# 입력층 측의 MatMul 계층들(in_layer0과 in_layer1 )의 forward ( )메서드를 호출해 중간 데이터를 계산하고,
# 출력층 측의 MatMul 계층(out_layer)을 통과시켜 각 단어의 점수 구함
h0 = in_layer0.forward(c0)
h1 = in_layer1.forward(c1)
h = 0.5 * (h0 + h1)
s = out_layer.forward(h)
print(s)
# [[ 0.30916255 0.45060817 -0.77308656 0.22054131 0.15037278
# -0.93659277 -0.59612048]]
-> CBOW 모델은 활성화 함수를 사용 하지 않는 간단한 신경망
[결과]
확률은 맥락(전후 단어) 이 주어졌었을 때 그 중앙에 어떤 단어가 출현하는지를 나타냄
위의 예에서 맥락은 “you”와 “goodbye”이고,
정답 레이블(신경망이 예측해야 할단어)은 “say”.
이때 ‘가중치가 적절히 설정된’ 신경망이라면 ‘확률’을 나타내는 뉴런들 중 정답에 해당하는 뉴런의 값이 클 것이라 기대
(노드의 값이 클수록 진하게 나타냄)
- CBOW 모델의 학습에서는 올바른 예측을 할 수 있도록 가중치를 조정하는 일을 함
- 그 결과로 가중치 W_{in} 에(정확하게는 \(W_{in}\) 과 \(W_{out}\) 모두에) 단어의 출현 패턴을 파악한 벡터가 학습
➕ 말뭉치가 다르면 학습 후 얻게 되는 단어의 분산 표현도 달라짐
예컨대 말뭉치로 ‘스포츠’ 기사만을 사용하는 경우와 ‘음악’ 관련 기사만을 사용하는 경우는 얻게 되는 단어의 분산 표현이 크게 다름.
[학습 과정]
1) 소프트맥스 함수를 이용해 점수를 확률로 변환
2) 그 확률과 정답 레이블로부터 교차 엔트로피 오차를 구함
3) 값을 손실로 사용해 학습을 진행.
여기선, Softmax 계층과 Cross Entropy Error 계층을 사용,
But, 우리는 이 두 계층을 Softmax with Loss라는 하나의 계층으로 구현.
➡ Softmax 계층과 Cross Entropy Error 계층을 Softmax with Loss 계층으로 합침
[word2vec의 가중치와 분산 표현]
word2vec에서 사용되는 신경망에는 두 가지 가중치 존재
- 입력 측 완전연결계층의 가중치(\(W_{in}\) )
- 입력 측 가중치 \(W_{in}\) 의 각 행: 각 단어의 분산 표
- 출력 측 완전연결계층의 가중치(\(W_{out}\) )
- 출력 측 가중치 \(W_{out}\) = 단어 의미가 인코딩된 벡터가 저장
- 다만, 출력측가중치는 분산표현이 열 방향(수직방향)으로 저장
최종적으로 이용하는 단어의 분산 표현으로 선택할 가중치는?
선택지는 세 가지
1) 입력 측의 가중치만 이용한다.
2) 출력 측의 가중치만 이용한다.
3) 양쪽 가중치를 모두 이용한다.
A와 B 안은 어느 한쪽 가중치만 이용한다는 것.
마지막 C 안에서는 두 가중치를 어떻게 조합하느냐에 따라 다시 몇 가지 방법을 생각 가능
➡ 그 중 하나는 두 가중치를 단순히 합치는 것.
word2vec (특히 skip-gram 모델)
1) 안인 ‘입력 측의 가중치만 이용한다’가 가장 대중적인 선택.
학습 데이터 준비
word2vec 학습에 쓰일 학습 데이터를 준비.
말뭉치로부터 맥락과 타깃을 만드는 함수를 구현
[맥락과 타깃]
- 맥락: 신경망의 입력
- 타깃: 정답 레이블은 맥락에 둘러 싸인 중앙의 단어
목표: 신경망에 ‘맥락’을 입력했을때 ‘타깃’이 출현할 확률을 높이는 것(그렇게 되도록 학습시킬 겁니다).
[EX] 말뭉치에서 맥락과 타깃을 만드는 예
- 각 샘플 데이터에서 맥락의 수는 여러 개(이 예에서는 2개)가 될 수 있으나, 타깃은 오직 하나 뿐.
- 그래서 맥락을 영어로 쓸 때는 끝에 ‘s’를 붙여 복수형임을 명시하는 게 좋음
1️⃣ 말뭉치 텍스트를 단어 ID로 변환
preprocess( ) 함수를 사용: 말뭉치 전처리 함수
👀 코드 보기
import sys
sys.path.append('..')
from common.util import preprocess
text = 'You say goodbye and I say hello.'
corpus, word_to_id, id_to_word = preprocess(text)
print(corpus)
# [0 1 2 3 4 1 5 6]
print(id_to_word)
# {0:'you', 1:'say', 2:'goodbye', 3:'and', 4:'i', 5: 'hello', 6: '.'}
2️⃣ 단어 ID의 배열인 corpus로부터 맥락과 타깃을 만들어 냄.
맥락은 2차원 배열
- 맥락의 N번째 차원: 각 N 번째 맥락 데이터가 저장
- contexts[0]에는 0번째 맥락이 저장
- contexts[1]에는 1번째 맥락이 저장
- 타깃의 N번째 차원: 각 N 번째 타깃 데이터가 저장
- target[0]에는 0번째 타깃이 저장
- target[1]에는 1번째 타깃이 저장
(윈도우 크기는 1)
👀 코드 보기
create_contexts_target (corpus, window_size)
# 인수를 두 개 받음.
# 하나는 단어 ID의 배열(corpus), 다른 하나는 맥락의 윈도우 크기(window_size)
def create_contexts_target(corpus, window_size=1):
target = corpus[window _size:-window_size]
contexts = []
for idx in range(window_size, len(corpus)-window_size):
cs = []
for t in range(-window_size, window_size + 1):
if t == 0:
continue
cs.append(corpus[idx + t])
contexts.append(cs)
# 맥락과 타깃을 각각 넘파이 다차원 배열로 돌려줌
return np.array(contexts), np.array(target)
# 실제로 사용
contexts, target = create_contexts_target(corpus, window_size=1)
print(contexts)
# [[0 2]
# [1 3]
# [2 4]
# [3 1]
# [4 5]
# [1 6]]
print(target)
# [1 2 3 4 1 5]
이 그림과 같은 결과가 나왔다
3️⃣ 이를 원핫 표현으로 변환
다차원 배열의 형상에 주목: 이 그림에서는 단어 ID를 이용했을 때의 맥락의 형상은 (6, 2)
이를 원핫 표현으로 변환하면 (6, 2, 7 )
(데이터 개수, 맥락개수, 전체 문장길이)
convert_one_hot ( )
함수를 사용: common/utill.py에 구현
CBOW 모델 구현
전체 신경망 SimpleCBOW
라는 이름으로 구현
👀 코드 보기
import sys
sys.path.append('..')
import numpy as np
from common.layers import MatMul, SoftmaxWithLoss
# 이 초기화 메서드는 인수로
# 어휘 수(vocab _size )와
은닉층의 뉴런 수(hidden _size )받음
class SimpleCBOW:
def __init__(self, vocab_size, hidden_size):
V, H = vocab_size, hidden_size
# 가중치 초기화 두 가중치는 각각 작은 무작위 값으로 초기화
# 이때 넘파이 배열의 데이터 타입을 astype ('f ') 즉, 32비트 부동소수점 수로 초기화
W_in = 0.01 * np.random.randn(V, H).astype('f')
W_out = 0.01 * np.random.randn(H, V).astype('f')
# 계층 생성
# 입력 측의 MatMul 계층을 2개,
## 입력 측의 맥락 처리계층은 맥락에서 사용하는 단어의 수(윈도우 크기)만큼 만들어야 함
## 입력 측 MatMul 계층들은 모두 같은 가중치를 이용하도록 초기화
# 출력 측의 MatMul 계층을 하나,
# Softmax with Loss 계층을 하나 생성
self.in_layer0 = MatMul(W_in)
self.in_layer1 = MatMul(W_in)
self.out_layer = MatMul(W_out)
self.loss_layer = SoftmaxWithLoss()
# 모든 가중치와 기울기를 리스트에 모은다
# 이 신경망에서 사용되는 매개변수와 기울기를 인스턴스 변수 params와 grads 리스트에 각각 모아둠
layers = [self.in_layer0, self.in_layer1, self.out_layer]
self.params, self.grads = [], []
for layer in layers:
self.params += layer.params
self.grads += layer.grads
# 인스턴스 변수에 단어의 분산 표현을 저장한다 .
self.word_vecs = W_in
# 신경망의 순전파인 forward ( ) 메서드를 구현
# 인수로 맥락 (contexts)과 타깃(target)을 받아 손실(loss)을 반환
def forward(self, contexts, target):
h0 = self.in_layer0.forward(contexts[:, 0])
h1 = self.in_layer1.forward(contexts[:, 1])
h = (h0 + h1) * 0.5
score = self.out_layer.forward(h)
loss = self.loss_layer.forward(score, target)
return loss
➕ 인수 contexts는 3차원 넘파이 배열이라고 가정.
위 예에서라면,
배열의 형상은 (6, 2, 7 )
- 0번째 차원의 원소 수: 미니배치의 수
- 1번째 차원의 원소 수: 맥락의 윈도우 크기
- 2번째 차원: 원핫 벡터의 길이
target의 형상은 2차원, (6, 7)
# 마지막으로 역전파인 backward ( )를 구현
def backward(self, dout=1):
ds = self.loss_layer.backward(dout)
da = self.out_layer.backward(ds)
da *= 0.5
self.in_layer1.backward(da)
self.in_layer0.backward(da)
return None
이미 각 매개변수의 기울기를 인스턴스 변수 grads에 모아둠
따라서 forward ( ) 메서드를 호출한 다음 backward ( ) 메서드를 실행하는 것만으로 grads 리스트의 기울기가 갱신
[학습 코드 구현]
1) 학습 데이터를 준비해 신경망에 입력
2) 기울기를 구하고
3) 가중치 매개변수를 순서대로 갱신해 감
👀 코드 보기
import sys
sys.path.append('..')
from common.trainer import Trainer
from common.optimizer import Adam
from simple _cbow import SimpleCBOW
from common.util import preprocess, create_contexts_target, convert_one_hot
window_size = 1
hidden_size = 5
batch_size = 3
max_epoch = 1000
text = 'You say goodbye and I say hello.'
corpus, word_to_id, id_to_word = preprocess(text)
vocab_size = len(word_to_id)
contexts, target = create_contexts_target(corpus, window_size)
target = convert_one_hot(target, vocab_size)
contexts = convert _one _hot(contexts, vocab _size)
model = SimpleCBOW(vocab_size, hidden_size)
optimizer = Adam()
# 신경망을 학습 학습 데이터로부터 미니배치를 선택한 다음,
# 신경망에 입력해 기울기를 구하고,
# 그 기울기를 Optimizer 에 넘겨 매개변수를 갱신하는 일련의 작업을 수행
trainer = Trainer(model, optimizer)
trainer.fit(contexts, target, max_epoch, batch_size)
trainer.plot()
[결과] ➡ 학습을 거듭할수록 손실이 줄어듦
[학습이 끝난 후의 가중치 매개변수] 앞의 코드 바로 뒤에 다음 코드를 추가합니다.
👀 코드 보기
word_vecs = model.word_vecs
for word_id, word in id_to_word.items():
print(word, word_vecs[word _id])
[결과] 단어를 밀집벡터로 나타냄
CBOW 모델과 확률
CBOW 모델을 ‘확률’ 관점에서 다시 살펴보겠다.
‘확률’의 표기법
- \(P(A)\): A라는 현상이 일어날 확률
- 동시 확률 \(P(A,B)\): ‘A와 B가 동시에 일어날 확률’
-
사후 확률 $$P(A B)$$ : ‘사건이 일어난 후 의 확률 ’ ,‘B 가 주어졌을 때 A가 일어날 확률’
CBOW 모델을 확률 표기법으로 기술:
맥락을 주면 타깃 단어가 출현할 확률을 출력
[EX] 맥락 \(w_{t-1}\) 과 \(w_{t+1}\) 이 주어질 때, 타깃이 \(w_t\) 가 될 확률?
\(P(w_t | w_{t−1} ,w_{t+1})\)
- ‘\(w_{t-1}\) 과 \(w_{t+1}\) 이 일어난 후 \(w_t\)가 일어날 확률’
- ‘\(w_{t-1}\) 과 \(w_{t+1}\) 이 주어졌을 때 \(w_t\)가 일어날 확률’
CBOW 모델의 손실 함수도 간결하게 표현: 교차 엔트로피 오차
- \(y_k\):‘k번째에 해당하는 사건이 일어날 확률’
- \(t_k\) : 정답 레이블(원핫 벡터로 표현)
- 여기서 문제의 정답: ‘\(w_t\) 가 발생’
- \(w_t\) 해당 원소만 1, 나머지는 0
- 즉, \(w_t\) 이외의 일이 일어날 경우에 대해서는 해당 원핫 레이블의 요소는 0
[적용]
음의 로그 가능도(negative log likelihood)
-> CBOW 모델의 손실 함수는 단순히 확률에 log를 취한 다음 마이너스를 붙이면 됨
[말뭉치 전체로 확장] CBOW 모델의 학습이 수행하는 일:
- 이 손실 함수의 값을 가능한 한 작게 만드는 것.
- 이때의 가중치 매개변수:우리가 얻고자 하는 단어의 분산 표현.
skip-gram 모델
word2vec은 2개의 모델 제안_ CBOW 모델, skip-gram 모델
- skip-gram은 CBOW에서 다루는 맥락과 타깃을 역전시킨 모델
CBOW 모델: 맥락이 여러 개 존재, 이로부터 타깃 추측.
skip-gram 모델: 타깃으로부터 주변의 여러 단어 (맥락)를 추측
[skip-gram 모델의 구성]
- skip-gram 모델의 입력층: 하나
- 출력층(답이 될 수 있는 것): 맥락의 수만큼 존재
1) 각 출력층에서는 (Softmax with Loss 계층 등을 이용해) 개별적으로 손실을 구함
2) 이 개별 손실들을 모두 더한 값이 최종 손실.
skip-gram 모델을 확률로
1️⃣ 먼저 확률 식을 보자
2️⃣ 여기서 맥락의 단어들 사이에 관련성이 없다고 가정 후 분해 (‘조건부 독립’이라고 가정). 3️⃣ 손실함수 유도 skip-gram 모델의 손실 함수는 맥락별 손실을 구한 다음 모두 더함.
[말뭉치 전체로 확장]
- 단어 분산 표현의 정밀도 면에서 skip-gram 모델의 결과가 더 좋은 경우가 많아 앞의 모델보다 이걸 쓰는 것을 추천(특히 말뭉치가 커질수록 저빈도 단어나 유추 문제의 성능 면에서 skip-gram 모델이 더 뛰어남)
- 속도는 CBOW가 더 빠름
통계 기반 vs 추론 기반
학습하는 틀
- 통계 기반 기법: 말뭉치의 전체 통계로부터 1회 학습하여 단어의 분산 표현을 얻음
- 추론 기반 기법: 말뭉치를 일부분씩 여러 번 보며 학습(미니배치 학습).
단어의 분산 표현을 갱신해야 하는 상황(새 어휘 추가)
- 통계 기반 기법: 계산을 처음부터 다시 단어의 분산 표현을 조금만 수정하고 싶어도, 동시발생 행렬을 다시 만들고 SVD를 수행하는 일련의 작업을 다시 해야 함.
- 추론 기반 기법: 기존에 학습한 경험을 해치지 않으면서 단어의 분산 표현을 효율적으로 갱신 가능.
단어의 분산 표현의 성격이나 정밀도
- 통계 기반 기법: 분산표현이 주로 단어의 유사성이 인코딩됨.
- 추론 기반 기법: 분산표현이 복잡한 단어 사이의 패턴까지도 파악되어 인코딩.
단어의 유사성을 정량 평가해본 결과,
의외로 추론 기반과 통계 기반 기법의 우열을 가릴 수 없음
- 두 방법은 (특정 조건 하에서) ‘서로 연결되어 있다’