Deep Learning/from scratch II

[밑바닥부터 시작하는 딥러닝 2] - 3장 word2vec I

해파리냉채무침 2024. 2. 14. 23:48

통계 기반 기법 : 학습 데이터를 한꺼번에 처리(배치 학습)하고, 단어의 빈도를 기초로 단어를 표현한다.

추론 기반 기법:  학습 데이터의 일부를 사용하여 순차적으로 학습(미니 배치 학습)

추론 기반 기법과 신경망

맥락 정보를 입력받아 단어의 출현 확률 기반으로 맥락에서 나올 단어를 추측한다. 신경망에서는 단어를 원핫벡터로 변환한다. 

https://www.hanbit.co.kr/channel/category/category_view.html?cms_code=CMS1232324353

인덱스와 단어 ID와 같은 원소를 1로, 나머지는 모두 0으로 설정한다. 원핫벡터 변환 과정을 거치면 단어를 고정길이 벡터로 변환할 수 있다. 단어를 백터로 나타낼 수 있고, 신경망으로 처리할 수 있다. 

https://www.hanbit.co.kr/channel/category/category_view.html?cms_code=CMS1232324353

입력층 뉴런과의 가중합(weighted sum)은 은닉층 뉴런이다.

코드로 구현하면 다음과 같다. 

import numpy as np
c = np.array([[1,0,0,0,0,0,0]]) #입력 1*7
W= np.random.randn(7,3) #가중치 7*3
h= np.matmul(c,W) #1*3
print(h) #[[-1.52464989 -0.44265653  0.11759733]]

https://www.hanbit.co.kr/channel/category/category_view.html?cms_code=CMS1232324353

맨 앞 원소가 1이고 나머지가 0이므로 (1*7)(7*3) 행렬 곱에 의해 (1*3) 의 결과가 나오는데, 맨 앞 행벡터를 추출하는 것과 똑같은 결과다. 앞서 구현한 MatMul로도 코드를 구현할 수 있다.

import numpy as np # 해당 코드는 layer 파일에 존재
class MatMul:
    def __init__(self, W):
        self.params = [W]
        self.grads = [np.zeros_like(W)]
        self.x = None

    def forward(self, x):
        W, = self.params
        out = np.dot(x, W)
        self.x = x
        return out

    def backward(self, dout):
        W, = self.params
        dx = np.dot(dout, W.T)
        dW = np.dot(self.x.T, dout)
        self.grads[0][...] = dW
        return dx
import numpy as np
import sys
from layers import 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)

MatMul 계층에 가중치 W를 설정하고 forward() 메서드를 호출해 순전파를 수행한다.

단순한 word2vec

CBOW

you ___ goodbye and I say hello

CBOW(Continuous bag-of-words) 모델은 맥락에서 target을 추측하는 용도의 신경망이다. you와 goodbye의 맥락 단어를 이용해서 가운데의 단어를 추측한다. 

https://m.blog.naver.com/bigdata-pro/221870004360

 

입력층 단어가 두개인 이유는 맥락으로 고려할 단어가 you, goodbye 두개 이기 때문이다.

입력층-> 은닉층: 가중치가 Win에 의한 완전연결계층에 의해 이뤄진다. 은닉층 변환시 두개의 평균을 산출(1/2(h1+h2))하여 은닉층 뉴런으로 옮긴다.

은닉층 -> 출력층: 가중치가 Wout에 의한 완전연결계층에 의해 이뤄진다. 출력층 뉴런은 각 단어의 점수를 의미하며 점수에 softmax 함수를 적용해서 확률을 얻는다.

은닉층의 뉴런수 < 입력층의 뉴런수 -> 단어 예측에 필요한 정보를 간결하게 담을 수 있고, 밀집 벡터 표현을 할 수 있다. 

 

https://yerimoh.github.io/DL14/

가중치 Win의 각 행이 해당 단어의 분산표현을 의미한다. word2vec에서는 입력 측의 가중치(Win)만 이용하는 것이 가장 대중적인 선택이다. 

https://yerimoh.github.io/DL14/

2개의 MatMul 계층 출력을 더함 *0.5 =-> 은닉층 뉴런

은닉층 뉴런 * Wout을 가중치로 하는 Matmul 계층 =-> 출력 스코어 

코드로 구현하면 다음과 같다

import sys
import numpy as np
from 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)

# 계층 생성
in_layer0 = MatMul(W_in) #입력층 matmul 계층
in_layer1 = MatMul(W_in)
out_layer = MatMul(W_out) #출력층

h0 = in_layer0.forward(c0)
h1 = in_layer1.forward(c1)
h = 0.5 * (h0 + h1)
s = out_layer.forward(h)

print(s)
#[-0.28418723 -0.86067759 -0.57553732  2.44443733  1.48224567 -2.35013005 0.86157551]

입력층 측의 Matmul 계층이 가중치 W_in을 공유한다는 점 주의. 

 

CBOW 모델 학습

https://yerimoh.github.io/DL14/

 출력층에서 softmax 함수를 적용해서 확률을 도출한다.

노드 값의 크기를 흑백의 진하기로 나타낸다. CBOW 모델의 학습에서는 가중치를 조정하는 일을 하고, 그 결과 가중치 Win과 Wout 모두에 단어의 출현 패턴을 파악한 벡터가 학습된다. 

https://yerimoh.github.io/DL14/

softmax 함수를 이용해 점수를 확률로 변환-> 그 확률과 정답레이블로부터 cross entropy error를 구함 ->구한 loss로 학습 진행 

softmax 계층 + cross entropy error 계층 -> softmax with loss 계층 

Win :  입력측 완전연결계층의 가중치, 각 행이 각 단어의 분산 표현에 해당

Wout:  출력 측 완전연결계층의 가중치, 출력 가중치는 각 단어의 분산 표현이 열방향(수직 방향)으로 저장됨