들어가기전에
다시 처음으로 돌아가서 우리는 문서를 분석할때 가장 먼저 하는 일은 토큰화해서 쪼개는 일이였다. 쪼개고 나면 우리는 단어 사전을 가지게 된다. 우리는 그 단어 사전에 있는 단어들을 컴퓨터가 특정 연산을 할 수 있도록 뭔가 수치화해야한다.
one-hot-encoding이라는 방법이 있었는데 one-hot-encoding은 단어사전에서 특정 단어의 인덱스를 통해서 벡터로 표현만 해줄 뿐이지 각 단어들간의 관계( 유사도 등)는 전혀 담을 수가 없다.
( 총 5개 단어들을 가지는 단어사전에서 3번째 단어를 [ 0 0 1 0 0 ] 로 인코딩 하는 방식 )
위와 같은 단순한 인코딩으로는 단어의 의미를 녹여내는 것에 문제가 있고 sparse 하기 때문에 메모리의 낭비가 심하므로 embedding이 필요했다. 앞선 포스팅에서 embedding의 방법이 대표적으로 3가지가 있었다고 했는데
- 어떤 단어가 자주 등장했는가 - TF-IDF
- 단어가 어떤 순서로 사용되었는가 - ELMo, GPT
- 어떤 단어가 같이 쓰였는가 - Word2Vec
이렇게 3가지가 있었다. 오늘 정리하려고 하는 것은 Word2Vec 이다.
즉 Word2Vec이란 "어떤 단어가 같이 쓰였는가" 라는 철학을 가지고 단어들을 embedding 하는 방식일 것이다.
Word2Vec (Skip-gram) 은 어떻게 임베딩을 만들어낼까?
뭔가 기본 아이디어를 잃어버리지 않으면서 나아가야 이 어려운 nlp 를 공부해 나갈 수 있을 것 같다. 다시 한번 Word2Vec이란 우리가 토큰화한 단어들을 주변에 같이 쓰인 단어들과의 관련성을 높이는 방식으로 벡터화하는 임베딩이다. 즉 Word2Vec 을 사용하면 우리가 가진 단어들이 어떤 차원에 벡터로 뿌려질텐데 애초에 벡터화할때 주변에 같이 쓰인 단어들과의 관련성을 높이는 방식으로 벡터화를 했으므로 관련성이 높은 단어들은 공간상에 비슷한 위치에 존재할 것이다.
자, 그럼 Word2Vec은 어떤 방식으로 주변단어들과의 관련성을 녹여낸 벡터를 만들어낼까?
우선 skip-gram의 아이디어부터 알아보자.
skip gram 은 주어진 문장에 대해서 target word(위 그림에서는 "passes")를 중심으로 window(위 그림에서는 window는 1이다) 크기를 가지고 context words를 찾아가면서 학습데이터를 스스로 만드는 비지도학습의 방식이다. 그러니까 위의 그림처럼 window가 1이라면 한번 target word가 sliding할때마다 2개의 학습데이터들 만들어가는 꼴이다. skip-gram의 input은 target word, prediction output은 context words인 것을 고려하면 그 학습데이터의 label은 context words라고 할 수 있겠다.
이 그림이 skip-gram 모델의 아키텍쳐이다. input으로 target word 의 one-hot-vector를 받고 output으로 context words를 예측한다.
여기서 의문이 생겨야 한다.
context words를 예측해서 뭐? 중요한거는 단어 사전에 있는 단어들의 embedding을 만들어야하는거 아니야?
맞다. 잊으면 안되는게 우리의 목적은 주변에 같이 쓰인 단어들과의 관련성을 녹여낸 word representation embedding을 찾아내는게 목적이다.
다시 이 목적을 상기시키고 위의 그림을 다시 보면 어디서 그 임베딩을 뽑아낼 수 있을까?
! 바로 hidden layer 양 옆에 있는 weight matrix 를 embedding으로 사용하는 것이다 !
즉, Word2Vec은 모델의 비지도 학습이 끝난 후 hidden layer의 파라미터(weight) 행렬을 각 단어들의 임베딩으로 사용한다 주변 단어를 잘 맞추도록 훈련을 시키고 나니 그 훈련에 쓰인 weight matrix를 임베딩으로 뽑아내면서 우리의 본래 목적을 성취한것이다.
그렇다면 이제 어떻게 학습시키는지 조금 더 자세하게 알아보자
Word2Vec의 학습과정
skip gram 모델의 구조에 따르면 hidden layer 양옆에 두개의 weight matrix가 존재하는데 앞으로 설명할때 앞의 weight matrix를 U, 뒤의 weight matrix를 V라고 하겠다. 참고로 U의 행의 크기는 토큰들의 개수(v)이고 열의 크기는 임베딩의 차원수(d)로서 이는 사용자가 직접 정하는 하이퍼파라미터라고 할 수 있다. V의 형태는 U를 transpose한 것과 같다. 형태만 같을 뿐이지 U와 V 두개의 행렬은 분명히 다른 성분을 갖는 weight matrix이고 update하는 방식도 다르다.
그렇다면 두개 중에 어떤 weight matrix를 최종 임베딩으로 사용할지 궁금할 수 있는데
U만 사용하거나 U+V(transpose) 를 사용하거나 U와 V(transpose)를 concatenate해서 2d차원의 임베딩을 사용하기도 한다.
이것이 skip-gram의 forward propagation의 전체 맥락이다
input layer부터 살펴보자
input layer는 V size의 one-hot-encoded-vector가 들어온다. 앞서 설명했든 corpus에서 토큰화된 단어사전들의 인덱스를 one-hot-encoding 방식으로 표현한 vector이다.
이 input layer는 첫번째 weight matrix U를 거치는데
행렬의 연산을 보면 결국은 one-hot-encoded-vector의 인덱스를 U로부터 참조할 뿐이다(look-up) 즉 input vector의 index를 U를 lookup해서 얻은 vector가 hidden layer가 되고 이를 projection한다고 한다.
그러고 나면 hidden layer의 vector는 두번째 weight matrix V를 만나게 된다.
V는 (d*v)의 사이즈를 가지는 행렬인데 hidden layer와 V의 행렬곱으로 결국 이 모델이 예측하는 vector가 나오게 된다. 그 vector의 size는 당연히 (단어사전의토큰의개수*1) 일 것이고 softmax를 돌려서 확률의 의미를 부여하면 위의 그림처럼 y(pred)를 얻을 수 있다.
그러면 우리는 특정 target word일때 단어사전의 모든 토큰들에 대해서 context word일 확률값들을 다 구하게 된것이다. 이제 무엇을 해야하는가 모델이 예측한 이 확률벡터를 실제 정답 레이블과 비교해서 그 오차를 줄이는 방향으로 back propagation을 하면 된다.
그 레이블은 어디있더라??
우리는 처음에 window를 1로 정했기 때문에 훈련데이터를 2개 얻었다. 자세히 말하자면 target word("passes") 1개에 대해서 context word("the,who")를 2개 가지고 있는 것이다. 그렇다면 레이블은 결국 context word 의 one-hot-encoded vector 2개이다. 즉 위에서 구한 모델이 예측한 확률벡터와 현재 iteration의 context word의 one-hot-encoded vector 를 비교하면 된다.
window가 1이였으므로 label이 2개이므로 위와 같이 각 레이블에 대해서 확률벡터와 차이를 구한다. 이렇게 구한 벡터는 window에 따른 context word의 개수만큼 나올 것이다. 이 벡터들을 다 더해서 back propagation을 수행하게 된다.
'자연어처리' 카테고리의 다른 글
자연어처리 스터디기록(3)-딥러닝 정리 (0) | 2020.02.08 |
---|---|
자연어처리 스터디(4)- neural language model (0) | 2020.02.05 |
자연어처리 스터디 기록(2)-임베딩의 의미 (0) | 2020.01.27 |
자연어처리 스터디 기록(1)-임베딩 (0) | 2020.01.23 |