📝 상세 정리#
- 기존의 CBOW모델은 말뭉치에 포함된 어휘 수가 많아지면 계산량도 커진다는 단점이 있었다.
- 이를 Embedding 계층과 네거티브샘플링이라는 새로운 손힐함수를 이용하여 개선할 것이다.
4.1 word2vec 개선 1#
- 기존의 CBOW모델에서 어휘가 100만개가 된다고 가정해보자.
- 그렇다면 입력층은 $W_{in} = 1000000 * 100, W_{out} = 100 * 1000000$의 행렬이 된다.
- 심지어 원핫 벡터라 상당히 sparse한데..
- 이를 Embedding 계층 도입으로 해결해보자.
- $W_{in}$은 Embedding으로, $W_{out}$은 네거티브 샘플링으로 해결할 것이다.
- 그렇다면 입력층은 $W_{in} = 1000000 * 100, W_{out} = 100 * 1000000$의 행렬이 된다.
- 4.1.1 Embedding 계층
- 다시한번 어휘 수가 100만개인 상황을 상상해보자.
- 단어의 원핫벡터는 100만차원..
- 그런데, 이 연산이 무엇을 의미하는걸까?
- 이는 그저 행렬의 특정 행을 추출하는 것뿐이다!
- 다시말해, 원핫표현으로의 변환가 행렬 곱연산은 사실 큰 필요가 없다.
- 가중치 매개변수로부터 단어 ID에 해당하는 행을 추출하기만 하면 된다.
- 해당 계층을 만들어보자.
- 이를 Embedding 계층이라고 하고, 단어 임베딩이라는 용어에서 유래했다.
- Embedding 계층에 단어의 분산 표현을 저장할 것이다.
- 다시한번 어휘 수가 100만개인 상황을 상상해보자.
- 4.1.2 Embedding 계층 구현
- 행렬에서 특정 행을 추출하는것은 꽤나 쉽다.
- $W$가 2차원 numpy 배열이라면, W[2]처럼 원하는 행을 명시하면 끝
- 입력층 단어가 일때도 쉽게 된다.
- 따라서 구현에서도 W[idx]로 인덱싱만 진행하면 된다.
- $W$가 2차원 numpy 배열이라면, W[2]처럼 원하는 행을 명시하면 끝
- 역전파에서도 똑같이 전해진 기울기를 idx번째 행에 전달하면 된다.
- 그런데 여기서 문제가 발생한다.
- idx의 원소가 중복된다면? 예를 들어 입력층에서 넣은 단어인덱스 배열이 [0, 2, 0, 4]라면?
- 이 문제를 해결하기 위해 구현 시 dW의 층을 0으로 초기화하고 각 인덱스에 대해 더해주자.
- 행렬에서 특정 행을 추출하는것은 꽤나 쉽다.
4.2 word2vec 개선 2#
- 여기서는 은닉층 이후의 처리, 즉 행렬곱과 Softmax계층의 계산 파트의 병목을 해소할 것
- 네거티브 샘플링을 이용할 것이다.
- 4.2.1 은닉층 이후 계산의 문제점
- 언제나 그랬듯 어휘가 100만개, 은닉층 뉴런이 100개라고 생각해보자.
- $W_{out} = 100 * 1000000$ 의 행렬 연산을 해서 100만 길이의 출력층을 만들고
- 이에 softmax 함수를 적용해서 확률을 얻어내야 한다.
- 언제나 그랬듯 어휘가 100만개, 은닉층 뉴런이 100개라고 생각해보자.
- 4.2.2 다중 분류에서 이진 분류로
- 이 기법의 핵심 아이디어는 다중 분류(multi-class classification)을 이중 분류(binary classification)으로 근사하는데 있다.
- 100만개의 단어 중 옳은 단어 하나를 고르는 문제를, 맥락이 주어졌을 때 타깃 단어는 say 입니까? 라는 이진 분류, 즉 결정 문제로 바꿀 수 있다.
- 그렇다면 출력층에는 뉴런을 하나만 준비하면 된다!
- 따라서 연산은 $W_{out}[idx] = 100 * 1$ 로 바뀌게 되고, 길이 1의 출력층만 sigmoid를 적용하면 되게 되었다.
- 이 기법의 핵심 아이디어는 다중 분류(multi-class classification)을 이중 분류(binary classification)으로 근사하는데 있다.
- 4.2.3 시그모이드 함수와 교차 엔트로피 오차
- 이진 분류 문제를 신경망으로 풀 때에는
- 점수에 시그모이드 함수를 적용해 확률로 변환하고
- 손실을 구할 때에는 손실 함수로 교차 엔트로피 오차를 사용한다.
- 시그모이드 함수는 앞에서 배운것과 같이 다음과 같고,
- $y = \frac{1}{1+e^{-x}}$
- 교차 엔트로피 오차는 다음과 같다.
- $L = -(t\log y + (1-t)\log (1-y))$
- $y$는 시그모이드 함수의 출력, $t$는 정답 레이블
- $t = 1$일 때 Yes, $t = 0$일때 No
- 따라서 $t = 1$일때 $-\log y$가, $t = 0$일 때 $-\log (1-y)$가 출력된다
- 이때 역전파 계산 결과, Chain Rule로 계산을 완료하면 전달되는 오차(기울기)가 $y-t$가 된다.
- $t = 0$일때는 $y$가 크면 크게 학습하고, $y$가 작으면 작게 학습한다는 의미도 된다!
- 이진 분류 문제를 신경망으로 풀 때에는
- 4.2.4 다중 분류에서 이진 분류로
- ![[Pasted image 20260127170240.png]]
- 위의 모든 최적화를 거친 그림은 위와 같다.
- 여기서 출력층의 Embedding 계층과 내적 연산을 합쳐서 Embedding dot 계층으로 표현하면 조금 더 간단하게도 그릴 수 있다.
- Embedding dot 계층은 $h, idx$를 입력받아서 점수를 반환한다.
- 내적은 $\text{Score} = \sum\limits_{i=1}^d{h_i \cdot w_i} = h \cdot w_{target}$ 이라고 생각할 수 있고,
- 곱의 결과로 나온 벡터가 실제 정답과 얼마나 유사한지에 대한 값이라고 생각할 수 있다.
- 4.2.5 네거티브 샘플링
- 위는 정답의 예만 신경썼고, 오답의 예를 신경쓰지 않았다.
- 이를 어떻게 학습시키면 좋을까?
- 모든 오답에 대해서 이진 분류를 학습시키면 어떨까?
- 그렇다면 다시 어휘의 수에 연산량이 비례하게 된다….
- 따라서 근사적인 해법으로, 부정적인 예를 조금만 선택하자!
- 이를 네거티브 샘플링이라고 한다.
- 위는 정답의 예만 신경썼고, 오답의 예를 신경쓰지 않았다.
- 4.2.6 네거티브 샘플링의 샘플링 기법
- 샘플링을 단순히 무작위로 할 것인가?
- 더 좋은 방법이 있다.
- 말뭉치의 통계 데이터를 기초로 샘플링하자!
- 자주 등장하는 단어를 많이 추출하고, 드물게 등장하는 단어를 적게 추출하자.
- 단어의 출현 횟수를 확률분포로 나타내고, 그 확률분포대로 단어를 샘플링하면 된다.
- 그런데, word2vec의 네거티브 샘플링에서는 각 확률분포에 0.75승을 하라고 권장한다.
- 이는 출현확률이 낮은 단어를 버리지 않게하기 위함으로, 낮은 출현율의 단어의 확률을 조금 끌어올릴 수 있다.
- 샘플링을 단순히 무작위로 할 것인가?
- 4.2.7 네거티브 샘플링 구현
- 앞과 크게 다르지 않다.
4.3 개선판 word2vec 학습#
- PTB 데이터셋으로 학습해보자.
- 4.3.1 CBOW 모델 구현
- 4.3.2 CBOW 모델 학습 코드
- 4.3.3 CBOW 모델 평가
4.4 word2vec 남은 주제#
- 4.4.1 word2vec을 사용한 애플리케이션의 예
- 전이 학습
- 한 분야에서 배운 지식을 다른 분야에 적용하는 기법
- 자연어 문제를 풀 때, 처음부터 학습하는 것이 아니라 위키백과나 구글 뉴스등의 큰 말뭉치로 학습을 끝낸 후, 우리가 원하는 작업에 돌입하자.
- 문장을 고정크기 벡터로 변환할 때에는 단어 벡터들의 합을 이용하자.
- 전이 학습
- 4.4.2 단어 벡터 평가 방법
- 우리가 얻어낸 분산 표현이 좋은지는 어떻게 평가할 수 있을까?
- 단어의 유사성
- 사람이 작성한 단어 유사도를 검증 세트로 사용해 평가하는 것
- 유추 문제를 이용한 평가
- “king : queen = man : ?”
- 과 같은 문제를 출제해서 정답률로 측정
4.5 정리#
- CBOW모델은 말뭉치의 어휘 수 증가에 비례해 계산량이 증가하는 문제가 있었다.
- 이를 Embedding계층 구현, 네거티브 샘플링 두가지 방법을 도입해서 해결하였다.
- 핵심은 어휘 모두를 처리하는 것이 아니라 일부 단어만을 대상으로 하는 것이다.
❔질문 사항#
- yes / no 결정문제로 만들면 no가 나오면 yes가 나올때까지 돌리는건가? 근데 그러면 똑같이 시간복잡도가 $O(N)$인거 아닌가?
- 아하, 위는 학습에서나 나오는 이야기고, 결국 나중에 디코딩할때는 = 단어를 찾을 때는 어떤 벡터의 결과값으로 가장 가까운 단어를 찾아가는건가? 그건 어떻게 이루어지지? 벡터공간에서 가장 가까운 점 찾기가 쉽나?
- -> 근사 최근접 이웃 (Approximate Nearest Neighbor, ANN) 알고리즘을 이용한다.
- [[260127_TIL_Approximate Nearest Nighbor 알고리즘]]
🔗 참고 자료#
- 해당 사이트에서 단어들 끼리의 벡터 연산을 직접 수행해볼 수 있다.
시그모이드 함수의 미분
- $\frac{\partial y}{\partial x} = y(1 - y)$
교차 엔트로피 오차 미분
- $$ \begin{aligned} \frac{\partial L}{\partial y} &= - \left( \frac{t}{y} - \frac{1 - t}{1 - y} \right) \\ &= - \left( \frac{t(1 - y) - y(1 - t)}{y(1 - y)} \right) \\ &= - \left( \frac{t - ty - y + ty}{y(1 - y)} \right) \\ &= \frac{y - t}{y(1 - y)} \end{aligned} $$
최종 역전파
- $$ \begin{aligned} \frac{\partial L}{\partial x} &= \frac{\partial L}{\partial y} \cdot \frac{\partial y}{\partial x} \\ &= \frac{y - t}{y(1 - y)} \cdot y(1 - y) \\ &= y - t \end{aligned} $$
