참고자료: 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 연산을 직접 풀어보면서 하다보면 이해가 된다.