혜온의 이것저것

[Chapter 4 word2vec 속도 개선] 1 word2vec 개선 #1 본문

Deep Learning/밑바닥부터 시작하는 딥러닝2

[Chapter 4 word2vec 속도 개선] 1 word2vec 개선 #1

혜온 :) 2022. 7. 11. 17:00

4.1.1 Embedding 계층

앞장의 word2vec 구현에서는 단어를 원핫 표현으로 바꿨다. 그것을 MatMul 계층에 입력하고, MatMul 계층에서 가중치 행렬을 곱했다.

여기서 어휘 수가 100만개인 경우를 상상해보자. 이때 은닉층 뉴런이 100개라면, MatMul 계층의 행렬 곱은 그림처럼 된다.

그림에서 결과적으로 수행하는 일은 단지 행렬의 특정 행을 추출하는 것뿐이다.

따라서 원핫 표현으로의 변환과 MatMul 계층의 행렬 곱 계싼은 사실 필요가 없다.

 

그러면 가중치 매개변수로부터 단어ID에 해당하는 행을 추출하는 계층을 만들어보자. 

그 계층을 Embedding 계층이라 부르겠다.

 

4.1.2 Embedding 계층 구현

행렬에서 특정 행을 추출하는 것은 쉽다.

가중치 W가 2차원 넘파이 배열일 때, 이 가중치로부터 특정 행을 추출하려면 그저 W[2]나 W[5]처럼 원하는 행을 명시하면 된다.

또한 가중치 W로부터 여러 행을 한꺼번에 추출하는 일도 간단하게 할 수 있다.

 

Embedding 계층의 forward() 매서드를 구현해보자.

class Embedding:
    def __init__(self,W):
        self.params=[W]
        self.grads=[np.zeros_like(W)]
        self.idx=None
        
    def forward(self,idx):
        W,=self.params
        self.idx=idx
        out=W[idx]
        return out

이 책의 구현 규칙에 따라 인스턴스 변수 params와 grads를 사용한다. 

또한 인스턴스 변수 idx에는 추출하는 행의 인덱스를 배열로 저장한다.

 

역전파에 대해 생각해보자.

Embedding 계층의 순전파는 가중치 W의 특정행을 추출할 뿐이었다. 단순히 가중치의 특정 행 뉴련만을 다음 층으로 흘려보낸 것이다.

따라서 역전파에서는 앞 층(출력 측 층)으로부터 전해진 기울기를 다음 층(입력 측 층)으로 그대로 흘려주면 된다. 다만, 앞 층으로부터 전해진 기울기를 가중치 기울기 dW의 특정 행에 설정한다.

기초로 backward()를 구현해보면 다음과 같이 작성할 수 있다.

def backward(self,dout):
    dW,=self.grads
    dW[...]=0
    dW[self.idx]=dout
    return None

가중치 기울기 dW를 꺼낸 다음, dW[...]=0 문장에서 dW의 원소를 0으로 덮어쓴다.

그리고 앞 층에서 전해진 기울기 dout을 idx번째 행에 할당한다.

 

사실 backward() 구현에는 문제가 하나 있다.

그 문제는 idx의 원소가 중복될 때 발생한다.

그림으로 예를 보면 다음과 같다.

dW의 0번째 행에 2개의 값이 할당된다. 먼저 쓰여진 값을 덮어쓴다는 뜻이다.

이 중복 문제를 해결하려면 할당이 아닌 더하기를 해야한다. 즉, dh의 각 행의 값을 dW의 해당 행에 더해준다.

def backward(self,dout):
    dW,=self.grads
    dW[...]=0
    
    for i, word_id in enumerate(self.idx):
        dW[word_id]+=dout[i]
        # 혹은
        # np.add.at(dW, self.idx, dout)
        
        return None

for문을 사용해 해당 인덱스에 기울기를 더했다. 이것으로 idx가 중복 인덱스가 있더라도 올바르게 처리된다.

 

word2vec의 구현은 입력 측 MatMul 계층을 Embedding 계층으로 전환할 수 있다. 그 효과로 메모리 사용량을 줄이고 쓸데없는 계산도 생략할 수 있게 되었다.

 

Comments