NeuroWhAI의 잡블로그

[TensorFlow] LSTM으로 단어 글자 예측하기 본문

개발 및 공부/라이브러리&프레임워크

[TensorFlow] LSTM으로 단어 글자 예측하기

NeuroWhAI 2018. 1. 31. 20:19


※ 이 글은 '골빈해커의 3분 딥러닝 텐서플로맛'이라는 책을 보고 실습한걸 기록한 글입니다.


아주 간단한 예시입니다.
4글자로 된 단어가 있을때 앞의 3글자만 보고 마지막 글자를 예측하는 신경망을 설계합니다.
예) 'wor' -> 'd'

코드:
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#-*- coding: utf-8 -*-
 
import sys
import tensorflow as tf
import numpy as np
 
char_arr = [chr(ch) for ch in range(97123)]
 
num_dic = {n: i for i, n in enumerate(char_arr)}
dic_len = len(num_dic)
 
seq_data = ['word''wood''deep''dive''cold''cool''load',
    'love''kiss''kind']
 
def make_batch(seq_data):
    input_batch = []
    target_batch = []
 
    for seq in seq_data:
        input = [num_dic[n] for n in seq[:-1]]
        target = num_dic[seq[-1]]
        input_batch.append(np.eye(dic_len)[input])
        target_batch.append(target)
 
    return input_batch, target_batch
 
learning_rate = 0.01
n_hidden = 128
total_epoch = 30
 
n_step = 3
n_input = n_class = dic_len
 
= tf.placeholder(tf.float32, [None, n_step, n_input])
= tf.placeholder(tf.int32, [None])
 
= tf.Variable(tf.random_normal([n_hidden, n_class]))
= tf.Variable(tf.random_normal([n_class]))
 
cell1 = tf.nn.rnn_cell.BasicLSTMCell(n_hidden)
cell1 = tf.nn.rnn_cell.DropoutWrapper(cell1, output_keep_prob=0.5)
cell2 = tf.nn.rnn_cell.BasicLSTMCell(n_hidden)
 
multi_cell = tf.nn.rnn_cell.MultiRNNCell([cell1, cell2])
 
outputs, states = tf.nn.dynamic_rnn(multi_cell, X, dtype=tf.float32)
 
outputs = tf.transpose(outputs, [102])
outputs = outputs[-1]
model = tf.matmul(outputs, W) + b
 
cost = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(
    logits=model, labels=Y
))
 
optimizer = tf.train.AdamOptimizer(learning_rate).minimize(cost)
 
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
 
    input_batch, target_batch = make_batch(seq_data)
 
    for epoch in range(total_epoch):
        _, loss = sess.run([optimizer, cost],
            feed_dict={X: input_batch, Y: target_batch})
 
        print('Epoch:''%04d' % (epoch + 1),
            'cost =''{:.6f}'.format(loss))
        sys.stdout.flush()
 
    print('완료!')
 
    prediction = tf.cast(tf.argmax(model, 1), tf.int32)
    prediction_check = tf.equal(prediction, Y)
    accuracy = tf.reduce_mean(tf.cast(prediction_check, tf.float32))
 
    input_batch, target_batch = make_batch(seq_data)
 
    predict, accuracy_val = sess.run([prediction, accuracy],
        feed_dict={X: input_batch, Y: target_batch})
 
    predict_words = []
    for idx, val in enumerate(seq_data):
        last_char = char_arr[predict[idx]]
        predict_words.append(val[:3+ last_char)
 
    print('\n=== 예측 결과 ===')
    print('입력값:', [w[:3+ ' ' for w in seq_data])
    print('예측값:', predict_words)
    print('정확도:', accuracy_val)
 
    
cs

결과:
Epoch: 0001 cost = 3.404235
Epoch: 0002 cost = 2.449252
Epoch: 0003 cost = 1.443516
Epoch: 0004 cost = 1.174067
Epoch: 0005 cost = 0.492063
Epoch: 0006 cost = 0.842435
Epoch: 0007 cost = 0.483240
Epoch: 0008 cost = 0.355300
Epoch: 0009 cost = 0.377058
Epoch: 0010 cost = 0.289324
Epoch: 0011 cost = 0.212049
Epoch: 0012 cost = 0.394625
Epoch: 0013 cost = 0.151902
Epoch: 0014 cost = 0.069047
Epoch: 0015 cost = 0.032184
Epoch: 0016 cost = 0.131735
Epoch: 0017 cost = 0.119544
Epoch: 0018 cost = 0.113929
Epoch: 0019 cost = 0.084501
Epoch: 0020 cost = 0.153773
Epoch: 0021 cost = 0.102427
Epoch: 0022 cost = 0.087498
Epoch: 0023 cost = 0.029386
Epoch: 0024 cost = 0.019681
Epoch: 0025 cost = 0.032489
Epoch: 0026 cost = 0.019890
Epoch: 0027 cost = 0.012101
Epoch: 0028 cost = 0.073793
Epoch: 0029 cost = 0.072436
Epoch: 0030 cost = 0.006594
완료!

=== 예측 결과 ===
입력값: ['wor ', 'woo ', 'dee ', 'div ', 'col ', 'coo ', 'loa ', 'lov ', 'kis ', 'kin ']
예측값: ['word', 'wood', 'deep', 'dive', 'cold', 'cool', 'load', 'love', 'kiss', 'kind']
정확도: 1.0

이번엔 무려 11초만에 결과가 나왔습니다.
어흑 감격...

LSTM -> Dropout -> LSTM
구조이며 입력 X에는 예를들어 'word'라면 'w', 'o', 'r'들을 각각 인덱스로 바꾼 값이 차례로 들어갑니다.
출력 Y는 목표 글자에 해당하는 인덱스가 됩니다.

BasicLSTMCell으로 LSTM 셀을 두개 만들고
DropoutWrapper로 드롭아웃을 적용한다음
MultiRNNCell로 (LSTM->Dropout) 셀과 (LSTM) 셀을 이어붙힙니다.
그리고 이전처럼 dynamic_rnn로 구동가능하게 만듭니다.
(dynamic_rnn이 정확히 뭘하는건지 더 공부해야겠습니다.)

이전예제처럼 일련의 과정을 통해 신경망 출력의 마지막 step 출력만 남기고 다 버립니다.
그런다음 FC로 원 핫 인코딩된 최종 출력을 냅니다.

이번엔 비용함수에 sparse_softmax_cross_entropy_with_logits를 사용했는데
softmax_cross_entropy_with_logits와 다르게 labels가 원 핫 인코딩된 형식이 아니라 그냥 목푯값 자체 입니다.
그래서 Y placeholder의 Shape이 [None]형태 인겁니다.

그다음은 별거 없습니다.
LSTM은 수식도 복잡해서 아직 이해를 못했는데 열심히 봐야겠습니다 ㅠㅠ





Comments