18.word2vec

word2vec

In [1]:
import tensorflow as tf
import matplotlib.pyplot as plt
import matplotlib
import numpy as np
In [2]:
# 단어 벡터를 분석해볼 임의의 문장들
sentences = ["나 우루루다",
             "나 강아지 좋다",
             "나 동물 좋다",
             "강아지 고양이 동물",
             "나 고양이 싫다"
             "강아지 여자친구 좋다", 
             "강아지 생선 우유 싫다",
             "고양이 생선 싫다 우유 좋다",
             "강아지 고양이 눈 좋다",
             "나 여자친구 좋다",
             "여자친구 나 좋다",
             "여자친구 나 영화 책 게임 좋다",
             "나 게임 만화 애니 좋다",
             "고양이 강아지 싫다",
             "강아지 고양이 좋다"]


  • 문장을 전부 합친 후 공백으로 단어들을 나누고 고유한 단어들로 리스트를 만듬
In [3]:
word_sequence = " ".join(sentences).split()
word_list = " ".join(sentences).split()
word_list = list(set(word_list))


  • 문자열로 분석하는 것 보다, 숫자로 분석하는 것이 훨씬 용이
  • 리스트에서 문자들의 인덱스를 뽑아서 사용하기 위해,
  • 이를 표현하기 위한 연관 배열과, 단어 리스트에서 단어를 참조 할 수 있는 인덱스 배열을 만듬
In [4]:
# word: index
word_dict = {w: i for i, w in enumerate(word_list)}


  • 윈도우 사이즈를 1 로 하는 skip-gram 모델을 만듬
  • 예) 나 게임 만화 애니 좋다
    -> ([나, 만화], 게임), ([게임, 애니], 만화), ([만화, 좋다], 애니)
    -> (게임, 나), (게임, 만화), (만화, 게임), (만화, 애니), (애니, 만화), (애니, 좋다)
In [5]:
skip_grams = []

for i in range(1, len(word_sequence) - 1):
    # (context, target) : ([target index - 1, target index + 1], target)
    # 스킵그램을 만든 후, 저장은 단어의 고유 번호(index)로 저장
    target = word_dict[word_sequence[i]]
    context = [word_dict[word_sequence[i - 1]], word_dict[word_sequence[i + 1]]]

    # (target, context[0]), (target, context[1])..
    for w in context:
        skip_grams.append([target, w])


# skip-gram 데이터에서 무작위로 데이터를 뽑아 입력값과 출력값의 배치 데이터를 생성하는 함수
def random_batch(data, size):
    random_inputs = []
    random_labels = []
    random_index = np.random.choice(range(len(data)), size, replace=False)

    for i in random_index:
        random_inputs.append(data[i][0])  # target
        random_labels.append([data[i][1]])  # context word

    return random_inputs, random_labels
In [6]:
training_epoch = 1000
learning_rate = 0.01
batch_size = 20

# 단어 벡터를 구성할 임베딩 차원의 크기
# 이 예제에서는 x, y 그래프로 표현하기 쉽게 2 개의 값만 출력
embedding_size = 2

# word2vec 모델을 학습시키기 위한 nce_loss 함수에서 사용하기 위한 샘플링 크기
# batch_size 보다 작아야
num_sampled = 15

# 총 단어 갯수
voc_size = len(word_list)
In [7]:
inputs = tf.placeholder(tf.int32, shape=[batch_size])

# tf.nn.nce_loss 를 사용하려면 출력값을 [batch_size, 1] 구성
labels = tf.placeholder(tf.int32, shape=[batch_size, 1])

# word2vec 모델의 결과 값인 임베딩 벡터를 저장할 변수
# 총 단어 갯수와 임베딩 갯수를 크기로 하는 두 개의 차원을 갖음
embeddings = tf.Variable(tf.random_uniform([voc_size, embedding_size], -1.0, 1.0))

# 임베딩 벡터의 차원에서 학습할 입력값에 대한 행들을 뽑음
# 예) embeddings     inputs    selected
#    [[1, 2, 3]  -> [2, 3] -> [[2, 3, 4]
#     [2, 3, 4]                [3, 4, 5]]
#     [3, 4, 5]
#     [4, 5, 6]]
selected_embed = tf.nn.embedding_lookup(embeddings, inputs)

# nce_loss 함수에서 사용할 변수들을 정의
nce_weights = tf.Variable(tf.random_uniform([voc_size, embedding_size], -1.0, 1.0))
nce_biases = tf.Variable(tf.zeros([voc_size]))

# nce_loss 함수를 직접 구현하려면 매우 복잡하지만,
# 함수를 텐서플로우가 제공하므로 그냥 tf.nn.nce_loss 함수를 사용
loss = tf.reduce_mean(
            tf.nn.nce_loss(nce_weights, nce_biases, labels, selected_embed, num_sampled, voc_size))

train_op = tf.train.AdamOptimizer(learning_rate).minimize(loss)
In [8]:
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)

loss_val_list = []
for step in range(1, training_epoch+1):
    batch_inputs, batch_labels = random_batch(skip_grams, batch_size)
    _, loss_val = sess.run([train_op, loss],
                           feed_dict={inputs: batch_inputs,
                                      labels: batch_labels})
    
    loss_val_list.append(loss_val)

    if step % 200 == 0:
        print("loss at step, step: {}: {}".format(step, loss_val))

    # matplot 으로 출력하여 시각적으로 확인해보기 위해
    # 임베딩 벡터의 결과 값을 계산하여 저장
    # with 구문 안에서는 sess.run 대신 간단히 eval() 함수를 사용
trained_embeddings = sess.run(embeddings, feed_dict={inputs: batch_inputs,
                                                     labels: batch_labels})
loss at step, step: 200: 3.1223583221435547
loss at step, step: 400: 3.23138165473938
loss at step, step: 600: 3.411635637283325
loss at step, step: 800: 2.716653347015381
loss at step, step: 1000: 2.981886625289917
In [9]:
plt.figure(figsize=(20, 7))
plt.title("cost")
plt.plot(loss_val_list, linewidth=0.7)
plt.show()
In [10]:
# matplotlib 한글 표시
import matplotlib.font_manager as fm

path_gothic = "/home/ururu/fonts/NanumGothic.ttf"
prop = fm.FontProperties(fname=path_gothic)
In [11]:
# 임베딩된 Word2Vec 결과 확인
# 결과는 해당 단어들이 얼마나 다른 단어와 인접해 있는지를 보여줌
plt.figure(figsize=(20, 7))
for i, label in enumerate(word_list):
    x, y = trained_embeddings[i]
    plt.scatter(x, y)
    plt.annotate(label, xy=(x, y), xytext=(5, 2),
                 textcoords='offset points', ha='right', va='bottom', fontproperties=prop)


plt.show()
In [12]:
from IPython.core.display import HTML, display

display(HTML("<style> .container{width:100% !important;}</style>"))

'Deep_Learning' 카테고리의 다른 글

19.word2vec  (0) 2018.12.20
17.seq2seq  (0) 2018.12.19
16.RNN_word_autoComplete  (0) 2018.12.18
15.RNN_mnist  (1) 2018.12.18
14.gan  (0) 2018.12.16

+ Recent posts