이전 포스팅에선 통계기반기법에 대해 알아보았습니다. 하지만 통계기반기법에는 안타깝게도 단점이 있습니다. 통계기반기법의 단점을 보완하는 추론기반기법의 대표적인 모델인 CBOW와 Skip-gram에 대해 포스팅하겠습니다.
통계기반 기법과 추론기반기법(Word2vec)의 차이
통계기반 기법은 SVD를 해서 Sparse matrix를 처리해줘야 해서 계산량이 너무 많습니다. 따라서 추론기반기법이 유용합니다. 추론기반 기법은 신경망을 이용해야하기 때문에 미니 배치기법으로 학습합니다.
CBOW
추론기반기법인 Word2vec의 아이디어는 아래와 같습니다.
주변 맥락을 맞추는 신경망을 만들어서 학습하는 것입니다. 위와 같은 문장들을 반복해서 풀면서 단어의 출현패턴을 추론하는 신경망이 CBOW입니다.
각각의 단어들은 원핫인코딩으로 원핫벡터로 만들어 처리해줍니다.
총 어휘 수 만큼의 원소를 갖는 벡터를 준비하고, 원핫벡터를 만듭니다. 그리고 인풋데이터는 위 그림의 원핫표현과 같은 형태를 갖게됩니다.
CBOW가 대표적인 추론기반기법(word2vec) 모델입니다. 물론 skip-gram이라는 모델도 있습니다.
Skip-gram
CBOW모델은 (“you”, “???”, “goodbye”) 라는 데이터를 넣습니다. 위와 같은 원핫벡터 두 개를 더해서, 1/2를 해줘서 벡터를 만들어서 신경망에 통과시키게 됩니다.
Skip-gram은 위의 CBOW모델의 마지막에 Softmax 함수를 넣어주어서 각 어휘의 확률을 알아낼 수 있습니다.
위와 같은 word2vec 신경망에는 은닉층과 출력층 두가지 가중치가 있습니다. 단어의 분산표현(벡터)를 얻을 때 어떤 가중치로 얻을까요? 두 가중치를 단순히 합칠 수도 있지만, 보통 앞에(은닉층) 있는 가중치를 이용합니다.
학습데이터를 만들기 위해 수집한 코퍼스에서 맥락과 타깃을 만들어 줘야합니다. “you say goodbye and i say hello”라는 코퍼스로 예시로 들겠습니다.
맥락은 Window Size을 얼마로 해주느냐에 따라 달라지겠죠? 예제는 window size를 1로 해서 진행하겠습니다.
“you say goodbye and i say hello”라는 코퍼스를 위 그림같이 맥락과 타깃으로 정제해서 학습가능하게 만듭니다.
최종적으로는 원핫벡터로 바꿔주면 학습데이터가 만들어 집니다.
CBOW 모델구현
그러면 본격적으로 간단한 CBOW 모델을 만들어 봅시다.
class SimpleCBOW:
def __init__(self, vocab_size, hidden_size):
V, H = vocab_size, hidden_size
# 가중치 초기화
W_in = 0.01 * np.random.randn(V, H).astype('f')
W_out = 0.01 * np.random.randn(H, V).astype('f')
# 계층 생성
self.in_layer0 = MatMul(W_in)
self.in_layer1 = MatMul(W_in)
self.out_layer = MatMul(W_out)
self.loss_layer = SoftmaxWithLoss()
# 모든 가중치와 기울기를 리스트에 모은다.
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()도 해봅시다.
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
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
각 매개변수의 기울기를 self.grads에 모아놨기 때문에 기울기가 갱신됩니다.
CBOW기법을 확률적으로 설명하면 아래와 같습니다.
음의 로그 가능도
CBOW는 해당 단어에 대한 확률이므로, 그냥 손실함수를 구할때 그 단어에 해당하는 가능도만 다 더해주면 된다.
skip-gram과 CBOW의 차이
word2vec은 두가지 종류가 있는데 CBOW말고 skip-gram이 있다. 이것이 요즘에 더 잘쓰인다. CBOW의 반대라고 생각하면 된다. CBOW는 맥락에서 단어하나를 맞추는 것이고, skip-gram은 단어하나로 주변 맥락을 맞추는 것이다.
모델의 특성상 skip-gram이 단어분산표현의 정밀도가 높다. 하지만 맥락을 맞추는 거라서 학습시간이 오래걸린다. skip-gram은 맥락수만큼 구해야하기 때문,
skip-gram모델의 손실함수도 확률측면에서 구하면된다. CBOW에서 살짝 변형되어있다.
결론 : 통계기반과 추론기반 뭐가 좋을까?
어휘에 추가해야할 새단어가 생겼을 때, 추론기반기법은 기존에 학습해놓은 웨이트에서 추가로 학습하면 됩니다. 따라서 기존에 학습한 경험을 기반으로 학습가능합니다. 하지만 통계기반 기법은 계산을 처음부터 다시해야 합니다.
단어의 분산표현의 정밀도는 어떨까요? 연구 결과 우열을 가리기 힘들다고 합니다. 그래서 두가지 기법을 융합한 GloVe기법도 나왔습니다.
정밀도상의 우열은 가리기 힘들지만 컴퓨터자원문제와 전이학습의 용의성으로 인해 추론기반기법이 더 알맞는 방법이라 볼 수 있습니다.
통계기반 기법의 단점을 보완한 word2vec도 아직 학습하기에는 문제점이 있습니다. 이를 개선하는 방법은 다음 포스팅에서 계속하겠습니다.