본문 바로가기

카테고리 없음

word2vec

참고자료: https://towardsdatascience.com/word2vec-from-scratch-with-numpy-8786ddd49e72

import re


def tokenize(text):
    # obtains tokens with a least 1 alphabet
    pattern = re.compile(r'[A-Za-z]+[\w^\']*|[\w^\']*[A-Za-z]+[\w^\']*')
    return pattern.findall(text.lower())
    
def mapping ( text ) :
    word_to_id = {}
    id_to_word = {}
    
    for i, word in enumerate(set(text)) :
        word_to_id[word] = i
        id_to_word[i] = word
        
    return word_to_id, id_to_word
    
def generate_training_data(tokens, word_to_id, window_size) :
    
    N = len(tokens)
    X, Y = [], []
    
    for i in range(N) : #select target word
        tokens_in_windows = list(range(max(0, i-window_size), i)) + list( range(i+1,min(N, i+window_size+1)))
        
        for j in tokens_in_windows : # adjacent words
            X.append(word_to_id[tokens[i]])
            Y.append(word_to_id[tokens[j]])
            
    X = np.array(X)
    X = np.expand_dims(X, axis = 0)
    Y = np.array(Y)
    Y = np.expand_dims(Y, axis = 0)
    
    return X, Y
        
import numpy as np
sample_text = "I love you"

document = tokenize(sample_text) 
word_to_id, id_to_word = mapping(document)
X, Y = generate_training_data(document, word_to_id, 2)

word_to_id
'''{'you': 0, 'i': 1, 'love': 2}'''

vocab_size = len(id_to_word)
m = Y.shape[1]

Y_one_hot[Y.flatten(), np.arange(m)] = 1
'''array([[0., 1., 0.],
       [0., 0., 1.],
       [1., 0., 0.],
       [0., 0., 1.],
       [1., 0., 0.],
       [0., 1., 0.]])'''
       
Y_one_hot

 

X = Input word indices. shape = (1,m)

Y: One-hot encoding of output word indices. X 주변 window size 내에 있는 단어들의 값들을 one-hot encoding한 것.

 

vocab_size = vocabulary size of your corpus

emb_size = embedding size. How many dimensions to represent each vocabulary

 

 

word2vec의 목적

 

- sparse representation -> dense representation

- word2vec은 0과 1의 조합으로 전체 단어 중 해당 단어만을 1로 대표하는 벡터(sparse)를 단어 간의 {발생확률(?) 값으로} 연관관계로 빽빽하게 채워낸 벡터로 변환시킨다.

 

설명

 

문장이 'I love you'라고 할 때, word_to_id = {'I':0, 'love':1, 'you':2}로 문장을 수치화할 수 있다.

 

X = ['I', 'love', 'you'] -> [0, 1, 2] ->(one-hot-encoding) [ [1,0,0], [0,1,0], [0,0,1] ]

 

Y는 X(target word) 주변 window size 내에 있는 단어들의 값들

Y = ['love', 'you', 'I', 'you', 'I', 'love'] -> [1,2,0,2,1,2] -> [ [0,1,0], [0,0,1], [1,0,0], [0,0,1], [0,1,0], [0,0,1] ]

이 과정에서 각각의 Y의 target word와  매칭해주기 위해서, X를 Y값에 맞춰서 적어준다.

X = ['I', 'I', 'love', 'love', 'you', 'you'] -> [0,0,1,1,2,2] -> [ [1,0,0], [1,0,0], [0,1,0], [0,1,0], [0,0,1], [0,0,1] ]

이렇게 sparse representation를 구현했다.

(X, Y) = [ ( [1,0,0], [0,1,0] ), ( [1,0,0], [0,0,1] ), ... ( [0,0,1], [0,1,0] ), ( [0,0,1], [0,0,1] ) ]

* X와 Y값을 묶어서 표현해보았다.

 

이제 주어진 X값을 사용해 embedding layer와 weight layer를 matrix multiplication하고, softmax값 처리를 해주었을 때, Y값이 나올 수 있도록 학습시켜준다. 그 과정에서 학습되어 나온 weight layer가 바로 우리가 원하는 word2vec값이다. 이게 가능한 이유는 Y값이 one-hot encoding되었기 때문인데, 이 부분은 간단한 data의 matrix 연산을 직접 풀어보면서 하다보면 이해가 된다.