3장에서의 word2vec 문제점
- input layer의 one-hot 표현과 가중치 행렬 $W_{in}$의 곱 계산
- 어휘 수가 많아지면 one-hot vector의 size도 커짐(상당한 memory차지)
- hidden layer의 가중치 행렬 $W_{out} $의 곱
- Softmax layer 계산
위 2개의 계산이 병목되며 많은 계산시간이 소요하는 문제 발생
#해결방법
-> Embedding Layer
-> Negative Sampling(loss function)
Embedding Layer
가중치 parameter로부터 '단어 ID에 해당하는 vector'를 추출하는 layer
- 기존 one-hot encoder와 matmul계층의 행렬 곱 계산(행렬의 특정 행 추출) 대신 사용
Embedding layer 구현
import numpy as np
#행렬 생성
W = np.arange(21).reshape(7,3)
W
W[2]
W[5]
#가중치 W로부터 여러 행을 한번에 추출
idx = np.array([1,0,3,0])
W[idx]
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
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(A,idx,B) - B를 A의 idx번째 행에 더하기
# 파이썬의 for문 보다 numpy의 내장 메서드가 속도와 효율면에서 더 최적화
np.add.at(dW, self.idx,dout)
return None
Negative Sampling(loss function)
hidden layer의 가중치 행렬 $W_{out} $의 곱의 문제점을 해결하기 위해 Softmax 대신 negative sampling을 사용
- multi-class classification(다중 클래스 분류) 를 binary classification(이진 분류)로 근사하는 방법
- 어휘가 많아져도 계산량을 낮은 수준에서 일정하게 억제 가능
- 지금까지 긍정적 정답에 대해서만 학습
- 부정적 정답에 대해서 sigmoid layer의 출력을 0 에 가깝게 만드는 것
- 정답을 target으로 한 경우의 loss 구함
- 동시에 오답의 예를 몇 개 샘플링하여 loss 구함
- 각각의 데이터의 loss를 더한 값을 최종 loss로 한다.
다중 분류에서 이진 분류로
정답과 오답 각각에 대해 바르게 분류해야 한다.(정답/오답 모두 대상으로 문제 생각)
- hidden layer와 output의 weight 행렬의 내적으로 target에 해당하는 vetor만을 추출
- 추출된 vector와 hidden layer neuron의 inner product 계산
이전까진 모든 단어를 대상으로 계산 수행(출력층)
Negative sampling 후 target 단어 하나에 주목하여 해당 점수만을 계산
시그모이드 함수 & 교차 엔트로피 오차
# 흔히 사용되는 방식
이진 분류 - 시그모이드 적용(확률 변환) , loss - cross entropy error
다중 분류 - 소프트맥스 적용(확률 변환) , loss - cross entropy error
Negative sampling의 sampling(선별) 기법
말뭉치의 통계 데이터를 기초로 sampling
말뭉치에서 자주 등장하는 단어를 많이 추출/ 드물게 등장하는 단어를 적게 추출
각 단어의 출현 횟수를 구해 '확률분포'로 표현, 확률분포대로 단어 sampling
# 빈도가 잦은 단어를 처리하는 편이 좋은 결과로 이어진다.
import numpy as np
#0~9 숫자 중 하나 무작위 샘플링
np.random.choice(10)
np.random.choice(10)
# words에서 하나만 무작위로 샘플링
words = ['you','say','goodbye','I','hello','.']
np.random.choice(words)
# 5개만 무작위로 샘플링(중복 O)
np.random.choice(words, size=5)
# 5개만 무작위로 샘플링(중복 X)
np.random.choice(words, size=5, replace=False)
# 확률분포에 따른 샘플링
p = [0.5, 0.1, 0.05, 0.2, 0.05, 0.1]
np.random.choice(words, p=p)
$ p(w_i) $ - i 번째 단어의 확률
낮은 확률의 단어가 조금 더 쉽게 샘플링 되도록 각 요소에 0.75 제곱
Negative sampling 구현
class NegativeSamplingLoss:
def __init__(self, W, corpus, power=0.75, sample_size=5): #초기화 메서드
self.sample_size = sample_size
self.sampler = UnigramSampler(corpus, power, sample_size)
self.loss_layers = [SigmoidWithLoss() for _ in range(sample_size + 1)]
self.embed_dot_layers = [EmbeddingDot(W) for _ in range(sample_size + 1)]
self.params, self.grads = [], []
for layer in self.embed_dot_layers:
self.params += layer.params
self.grads += layer.grads
def forward(self, h, target):
batch_size = target.shape[0]
negative_sample = self.sampler.get_negative_sample(target)
# 긍정적 예 순전파
score = self.embed_dot_layers[0].forward(h, target)
correct_label = np.ones(batch_size, dtype=np.int32)
loss = self.loss_layers[0].forward(score, correct_label)
# 부정적 예 순전파
negative_label = np.zeros(batch_size, dtype=np.int32)
for i in range(self.sample_size):
negative_target = negative_sample[:, i]
score = self.embed_dot_layers[1 + i].forward(h, negative_target)
loss += self.loss_layers[1 + i].forward(score, negative_label)
return loss
def backward(self, dout=1):
dh = 0
for l0, l1 in zip(self.loss_layers, self.embed_dot_layers):
dscore = l0.backward(dout)
dh += l1.backward(dscore)
return dh
loss_layers, embed_dot_layers - 원하는 계층을 리스트로 보관, sample_size(오답) + 1(정답) 개의 계층 생성
- W - 출력 측 가중치
- corpus - 말뭉치(단어 ID 리스트)
- power - 확률분포에 제곱할 값
- sample - 오답 샘플링 횟수
word2vec으로 얻은 단어의 분산 표현
- 비슷한 단어를 가까이 모음
- 유추(비유) 문제 해결 가능
- word2vec의 단어의 분산 표현 사용시 유추 문제를 벡터의 덧셈, 뺄셈으로 풀이 가능
- ex) king - man + woman = queen
- 단어를 고정 길이 벡터로 변환해줌
- 자연어를 벡터로 변환하여 일반적인 머신러닝 기법을 적용 가능
분산 표현의 평가 방법
- 유사성, 유추 문제를 활용한 평가
- 단어의 유사성 평가 - 사람이 작성한 단어 유사도를 검증 세트를 사용해 평가
- 유추 문제 - 단어의 의미나 문법적인 문제를 어느정도 이해하고 있는지 측정
- 모델에 따라 정확도 다름
- 일반적으로 말뭉치(데이터)가 클수록 결과 좋음
- 단어 벡터 차원 수는 적당한 크기가 좋음(너무 크면 정확도 하락)
word2vec을 사용한 애플리케이션의 예
전이 학습(transfer learning) - 한 분야에서 배운 지식을 다른 분야에 적용하는 기법
### 본 게시물은 밑바닥부터 시작하는 딥러닝 2를 읽고 정리한 노트입니다. ###
'----------책---------- > 밑바닥부터 시작하는 딥러닝2' 카테고리의 다른 글
CHAPTER 6 게이트가 추가된 RNN (0) | 2020.02.27 |
---|---|
CHAPTER 5 순환 신경망(RNN) (0) | 2020.02.18 |
CHAPTER 3 word2vec (0) | 2020.02.03 |
CHAPTER2 - 자연어와 단어의 분산 표현 (0) | 2020.01.31 |
CHAPTER 1 - 신경망 복습 (0) | 2020.01.13 |
댓글