[NLP] implementation Word2Vec with Keras and numpy

Word2vec 구현

구현(이하 skip gram)

  • practical한 구현에는 여러 방법이 존재
    • 예컨대, embedding matrix 하나만 활용하여, 임베딩된 target과 임베딩된 context의 내적을 구하고 binary cross entropy 적용(full code with keras)
  • 구현시 유의점
    • W_out layer를 나온 s 값은 분기하므로, back propagation시 ds는 dl1, dl2를 합산해야 함
    • back propagation시, soft max와 cross entropy chaind을 chain rule을 통해 바로 구하면 더 간단하게 미분가능( y - t)

Negative Sampling

  • 내용참조
  • Skip gram 방식은 input: target word1, output: context words n
  • 계산량 CBOW보다 많음. (window size만큼 loss 계산)
  • softmax에서도 (1 x V) x (V x 1) 내적
    • 앞은 target 단어이므로 V개 concat
    • 뒤는 window 내의 context이므로 n번 내적
  • 이하 코드는 lazyprogrammer 참고하여 작성(full code)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    def get_negative_sampling_distribution(sentences, vocab_size):
    word_freq = np.ones(vocab_size) * 1e-5 # 0 방지 smoothing
    word_count = sum(len(sentence) for sentence in sentences)
    for sentence in sentences:
    for word in sentence:
    word_freq[word] += 1

    # smooth it: 너무 빈번한 단어만 나오지 않도록 조정
    p_neg = word_freq**0.75

    # normalize it
    p_neg = p_neg / p_neg.sum()

    assert(np.all(p_neg > 0))
    return p_neg
  • weight matrix 업데이트

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    def sgd(input_, targets, label, learning_rate, W, W2):
    # W[input_] shape: D <- word의 one hot encoding으로
    # lookup=dense vector
    # W2[:,targets] shape: D x N
    # activation shape: N
    print("input_:", input_, "targets:", targets)
    activation = W[input_].dot(W2[:, targets])
    prob = sigmoid(activation) # softmax 아니지?

    # return cost (binary cross entropy)
    cost = label * np.log(prob + 1e-10) + (1 - label) * \
    np.log(1 - prob + 1e-10)

    # gradients
    gW2 = np.outer(W[input_], prob - label) # D x N
    gW = np.sum((prob - label)*W2[:, targets], axis=1) # D

    # update weight
    W2[:, targets] -= learning_rate*gW2 # D x N
    W[input_] -= learning_rate*gW # D
    return cost.sum()

    c = sgd(input_=word, targets=targets, label=1, learning_rate=learning_rate, W=W, W2=W2)
    cost += c
    c = sgd(neg_word, target, 0, learning_rate, W, W2)
    cost += c

기타

  1. bias는 생략
    • input layer의 weight만 사용. bias는 성능 향상에 도움이 되지 않음
    • 참고
  2. keras embedding layer
    • output은 lookup table(weight matrix)
    • param input_length: 한 문장의 maximum길이. 짧으면 padding.
< !-- add by yurixu 替换Google的jquery并且添加判断逻辑 -->