├── -1. Tensorflow RNN Basic of Basic
├── README.MD
└── dynamic-rnn.png
├── 0. Basic
├── README.md
├── RNN-TF-dynamic-decode.py
└── dynamic-rnn-decode.png
├── 1. RNNWrapper
├── cell-cell.png
├── dynamic-rnn-decode2.png
├── math-basicRNN.png
├── readme.md
└── wrapper.png
├── 2. User Defined Helper
├── README.md
└── tacotron-decoder.png
├── 3. User Defined Decoder
├── BasicDecoder.png
├── BasicDecoder2.png
└── README.md
├── 4. Attention with Tensorflow
├── Attention.png
├── AttentionWrapper-API.png
├── Bahdanau-Luong-Attention.png
├── README.md
├── answer.png
├── attentioin-dynamic-rnn-decode.png
├── attention-layer-size.png
└── attention-shape.png
├── README.md
├── TF-RNN.png
├── a.bat
└── b.bat
/-1. Tensorflow RNN Basic of Basic/README.MD:
--------------------------------------------------------------------------------
1 | # Tensorflow RNN Basic of Basic
2 |
3 |
4 |
5 | * 위 그림은 tensorflow에서 기본적인 RNN모델을 만드는데 필요한 API들의 관계를 그린 것이다.
6 |
7 | * 아래의 Example은 (단어 3개 + SOS + EOS)로 전체 5개의 vocabulary를 가지고, embedding 처리 후, BasicRNNCell를 거치는 모델이다.
8 | * BasicRNNCell을 거친 후에 Fully-Connected Layer(OutputProjectionWrapper)를 한번 더 거치면 최종 output이 만들어진다.
9 | * 정리하면, 5개의 단어를 가지고, [minimal character-level RNN language model](http://karpathy.github.io/2015/05/21/rnn-effectiveness/)을 만들어 본다.
10 | * 위 그림에서 처럼, {cell, inputs, seq_length, inital_state} 이렇게 4개의 object를 만들어서 dynamic_rnn에 넘겨주면 된다.
11 | * 먼저 Example Code 전체를 보고, 부분 부분 살펴보자.
12 |
13 | ```python
14 | # -*- coding: utf-8 -*-
15 | import numpy as np
16 | import tensorflow as tf
17 | tf.reset_default_graph()
18 |
19 | def dynamic_rnn_test():
20 |
21 | vocab_size = 5
22 | SOS_token = 0
23 | EOS_token = 4
24 |
25 | x_data = np.array([[SOS_token, 3, 1, 2, 3, 2],[SOS_token, 3, 1, 2, 3, 1],[SOS_token, 1, 3, 2, 2, 1]], dtype=np.int32)
26 | y_data = np.array([[1,2,0,3,2,EOS_token],[3,2,3,3,1,EOS_token],[3,1,1,2,0,EOS_token]],dtype=np.int32)
27 | Y = tf.convert_to_tensor(y_data)
28 | print("data shape: ", x_data.shape)
29 | sess = tf.InteractiveSession()
30 |
31 | output_dim = vocab_size
32 | batch_size = len(x_data)
33 | hidden_dim =6
34 | num_layers = 2
35 | seq_length = x_data.shape[1]
36 | embedding_dim = 8
37 |
38 | init = np.arange(vocab_size*embedding_dim).reshape(vocab_size,-1)
39 |
40 | with tf.variable_scope('test') as scope:
41 | cell = tf.contrib.rnn.BasicRNNCell(num_units=hidden_dim)
42 | cell = tf.contrib.rnn.OutputProjectionWrapper(cell,output_dim)
43 |
44 | embedding = tf.get_variable("embedding", initializer=init.astype(np.float32),dtype = tf.float32)
45 | inputs = tf.nn.embedding_lookup(embedding, x_data) # batch_size x seq_length x embedding_dim
46 |
47 | initial_state = cell.zero_state(batch_size, tf.float32) #(batch_size x hidden_dim)
48 | outputs, last_state = tf.nn.dynamic_rnn(cell,inputs,sequence_length=[seq_length]*batch_size,initial_state=initial_state)
49 |
50 | weights = tf.ones(shape=[batch_size,seq_length])
51 | loss = tf.contrib.seq2seq.sequence_loss(logits=outputs, targets=Y, weights=weights)
52 |
53 | sess.run(tf.global_variables_initializer())
54 | print("initial_state: ", sess.run(initial_state))
55 | print("\n\noutputs: ",outputs)
56 | o = sess.run(outputs) #batch_size, seq_length, outputs
57 | o2 = sess.run(tf.argmax(outputs,axis=-1))
58 | print("\n",o,o2) #batch_size, seq_length, outputs
59 |
60 | print("\n\nlast_state: ",last_state)
61 | print(sess.run(last_state)) # batch_size, hidden_dim
62 |
63 | p = sess.run(tf.nn.softmax(outputs)).reshape(-1,output_dim)
64 | print("loss: {:20.6f}".format(sess.run(loss)))
65 | print("manual cal. loss: {:0.6f} ".format(np.average(-np.log(p[np.arange(y_data.size),y_data.flatten()]))) )
66 |
67 | if __name__ == '__main__':
68 | dynamic_rnn_test()
69 | print('Done')
70 | ```
71 |
72 | #[Code 설명]
73 | ```python
74 | vocab_size = 5
75 | SOS_token = 0
76 | EOS_token = 4
77 |
78 | x_data = np.array([[SOS_token, 3, 1, 2, 3, 2],[SOS_token, 3, 1, 2, 3, 1],[SOS_token, 1, 3, 2, 2, 1]], dtype=np.int32)
79 | y_data = np.array([[1,2,0,3,2,EOS_token],[3,2,3,3,1,EOS_token],[3,1,1,2,0,EOS_token]],dtype=np.int32)
80 | Y = tf.convert_to_tensor(y_data)
81 | ```
82 |
83 | * 0(SOS),1,2,3,EOS(4) --> 모두 5개의 단어에 대하여, batch_size=3인 sample data를 만들었다.
84 | * 이제 RNN모델의 core인 cell을 만들어 보자
85 |
86 |
87 | ```python
88 | cell = tf.contrib.rnn.BasicRNNCell(num_units=hidden_dim)
89 | cell = tf.contrib.rnn.OutputProjectionWrapper(cell,output_dim)
90 | ```
91 |
92 | * 여기서는 BasicRNNCell을 사용했고, BasicRNNCell은 hidden_dim만 지정해주면 된다. BasicRNNCell을 거쳐서 나온 결과의 dimension은 당연히 hidden_dim이 되는데, 최종 결과를 만들기 위해서는 vocab_size(=output_dim)의 dimension을 가질 수 있도록 Fully-Connected-Layer를 추가해 주면 된다.
93 | * Tensorflow RNN모델에서 Fully-Connected-Layer는 tf.contrib.rnn.OutputProjectionWrapper를 사용하면 된다.
94 | * BasicRNNCell 대신 BasicLSTMCell,GRUCell 등을 사용할 수도 있다.
95 |
96 | ---
97 | * inputs를 만드는 과정을 보자. embedding vector를 만든 후, embedding_lookup을 통해 단어들에 대한 embedding vector를 찾아준다.
98 |
99 | ```python
100 | embedding = tf.get_variable("embedding", initializer=init.astype(np.float32),dtype = tf.float32)
101 | inputs = tf.nn.embedding_lookup(embedding, x_data) # batch_size x seq_length x embedding_dim
102 | ```
103 | ---
104 | * 이제 initial_state를 만들어보자. 다음의 코드는 0으로된 initial_state를 만들어 준다.
105 | ```python
106 | initial_state = cell.zero_state(batch_size, tf.float32) #(batch_size x hidden_dim)
107 | ```
108 | * 필요에 따라, 0이 아닌 다른 값으로 initial_state를 만들 수도 있다.
109 |
110 | ---
111 | * 나머지 코드들은 test 목적으로 만든 것들로 쉽게 이해할 수 있다.
112 |
113 | ---
114 | * tf.nn.dynamic_rnn은 teacher forcing 방식. inference 목적으로로 사용하기 위해서는 모델을 많이 수정해야 함. ==> tf.contrib.seq2seq.dynamic_decode를 사용해야 한다.
115 |
116 |
--------------------------------------------------------------------------------
/-1. Tensorflow RNN Basic of Basic/dynamic-rnn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hccho2/Tensorflow-RNN-Tutorial/c27d72d3247b55a3d79b102a37558b5ba2242d1d/-1. Tensorflow RNN Basic of Basic/dynamic-rnn.png
--------------------------------------------------------------------------------
/0. Basic/README.md:
--------------------------------------------------------------------------------
1 | # Tensorflow에서 tf.contrib.seq2seq.dynamic_decode를 어떻게 사용해야 하는지 설명.
2 | 아래 그림은 tf.nn.dynamic_rnn과 tf.contrib.seq2seq.dynamic_decode의 입력 구조를 비교한 그림이다.
3 |
4 | 
5 | * Tensorflow에서는 seq2seq(encoder-decoder) 모델을 다룰 수 있는 dynamic_rnn, dynamic_decode를 제공하고 있다.
6 | * dynamic_rnn은 좀 더 단순한 구조로 되어 있는데, 여기서는 dynamic_decode를 설명한다.
7 | * cell은 BasicRNNCell,BasicLSTMCell,GRUCell이 올 수 있고, 이런 것들을 쌓은 MultiRNNCell도 올 수 있다.
8 | * initial_state는 hidden state의 초기값으로 zero_state, encoder의 마지막 hidden state, captioning model에서 image의 feature등이 올 수 있다.
9 | * TrainingHelper는 training 단계에서 사용하고, GreedyEmbeddingHelper는 inference 단계에서 사용하면 된다.
10 | * GreedyEmbeddingHelper는 inference에 사용하는 hleper로 전단계의 output의 argmax에 해당하는 결과를 다음 단계의 input으로 전달한다.
11 |
12 | ### [code 설명]
13 | * 전체 코드는 [RNN-TF-dynamic-decode.py](https://github.com/hccho2/RNN-Tutorial/blob/master/RNN-TF-dynamic-decode.py)에 있고, 이 페이지의 [아래](#full-code)에서도 확인할 수 있다.
14 | * 이제 코드의 시작부터 차근차근 설명해 보자.
15 | ```python
16 | vocab_size = 5
17 | SOS_token = 0
18 | EOS_token = 4
19 |
20 | x_data = np.array([[SOS_token, 2, 1, 2, 3, 2],[SOS_token, 3, 1, 2, 3, 1],[SOS_token, 1, 3, 2, 2, 1]], dtype=np.int32)
21 | y_data = np.array([[2, 1, 2, 3, 2,EOS_token],[3, 1, 2, 3, 1,EOS_token],[ 1, 3, 2, 2, 1,EOS_token]],dtype=np.int32)
22 | ```
23 | * 간단한 data로 설명하기 위해, 단어 개수 vocab_size = 5로 설정. 제시된 x_data, y_data를 보면 알 수 있듯이, x_data는 SOS_token으로 시작하고, y_data는 EOS_token으로 끝난다.
24 | * seq_length는 6이다. batch data들의 길이가 같지 않은 경우가 대부분인데, 이런 경우에는 Null을 도입하여 최대 길이(max_sequence)를 정하고, 뒷부분을 Null로 채워서 길이를 맞춘다. 여기서는 Null을 사용하지 않았다.
25 | * 실전 data에서는 data file을 읽어, 단어를 숫자로 mapping하고 Null로 padding하는 등의 preprocessing에 많은 시간이 소요될 수 있다.
26 | * Tensorflow의 data 입력 op인 placeholder를 사용해야하는데, 여기서는 간단함을 위해 사용하지 않는다.
27 |
28 |
29 | ```python
30 | output_dim = vocab_size
31 | batch_size = len(x_data)
32 | hidden_dim = 6
33 | num_layers = 2
34 | seq_length = x_data.shape[1]
35 | embedding_dim = 8
36 |
37 | state_tuple_mode = True
38 | init_state_flag = 0
39 | train_mode = True
40 | ```
41 | * output_dim은 RNN cell의 output에 연결되는 FC layer의 출력 dimension이다. 보통의 경우 단어 개수와 동일한 dimension이다. 그래서 output_dim = vocab_size
42 | * batch_size는 추가 설명 불필요^^
43 | * hidden_dim은 말 그대로 RNN cell의 hidden layer size.
44 | * num_layer는 Multi RNN모델에서 RNN layer를 몇 층으로 쌓을지 결정하는 값. 즉, num_layer만큼 LSTM cell을 쌓는다.
45 | * embedding_dim은 각 단어를 몇 차원 vector로 mapping할지 결정하는 변수.
46 | * 나머지 3개 변수(state_tuple_mode,init_state_flag,train_mode)는 코드 상의 옵션을 설정하는 변수로 중요한 것은 아님. 차차 설명.
47 |
48 | ```python
49 | cells = []
50 | for _ in range(num_layers):
51 | cell = tf.contrib.rnn.BasicLSTMCell(num_units=hidden_dim,state_is_tuple=state_tuple_mode)
52 | cells.append(cell)
53 | cell = tf.contrib.rnn.MultiRNNCell(cells)
54 | ```
55 | * RNN cell을 num_layer만큼 쌓아야하기 때문에 for loop를 통해서 BasicLSTMCell을 원하는 만큼 쌓았다.
56 | * BasicLSTMCell의 state_is_tuple항목은 c_state와 h_state(m_state라고 하기도 함)를 tuple형태로 관리할 지, 그냥 이어서 하나로 관리할 지 정하는 항목인데, model구조에 영향을 주는 것은 아니다.
57 | * Tensorflow에서는 tuple로 관리할 것을 권장하고 있다.
58 |
59 | ```python
60 | init = tf.contrib.layers.xavier_initializer()
61 | embedding = tf.get_variable("embedding",shape=[vocab_size,embedding_dim], initializer=init,dtype = tf.float32)
62 | inputs = tf.nn.embedding_lookup(embedding, x_data) # batch_size x seq_length x embedding_dim
63 | ```
64 |
65 | * 각 단어를 embedding vector로 변환할 수 있는 변수를 만든다. vocab_size x embedding_dim만큼의 변수가 필요하다.
66 | * embedding변수가 만들어지면, embedding_lookup을 통해, x_data를 embedding vector로 변환한다.
67 | * 참고로 embedding vector를 만들때 초기값을 아래와 같이 0,1,2,...로 지정하여 embedding vector로 변환이 어떻게 이루어지는지 확인해 볼 수도 있다.
68 | ```python
69 | init = np.arange(vocab_size*embedding_dim).reshape(vocab_size,-1).astype(np.float32) # 아래 embedding의 get_variable에서 shape을 지정하면 안된다.
70 | embedding = tf.get_variable("embedding", initializer=init,dtype = tf.float32)
71 |
72 | ```
73 |
74 | ---
75 | * 이제 RNN cell의 hidden state의 초기값을 지정하는 코드를 살펴보자.
76 | ```python
77 | if init_state_flag==0:
78 | initial_state = cell.zero_state(batch_size, tf.float32) #(batch_size x hidden_dim) x layer 개수
79 | else:
80 | h0 = tf.random_normal([batch_size,hidden_dim]) #실제에서는 적절한 값을 외부에서 받아와야 함.
81 | if state_tuple_mode:
82 | initial_state=(tf.contrib.rnn.LSTMStateTuple(tf.zeros_like(h0), h0),) + (tf.contrib.rnn.LSTMStateTuple(tf.zeros_like(h0), tf.zeros_like(h0)),)*(num_layers-1)
83 | else:
84 | initial_state = (tf.concat((tf.zeros_like(h0),h0), axis=1),) + (tf.concat((tf.zeros_like(h0),tf.zeros_like(h0)), axis=1),) * (num_layers-1)
85 | ```
86 | * hidden state의 초기값은 cell.zero_state(batch_size, tf.float32)와 같이 0으로 지정하는 경우도 있고,
87 | * encoder-decoder 모델에서의 decoder의 hidden state 초기값은 encoder의 마지막 hidden state값을 받아오기도 한다.
88 | * image에 대한 caption을 생성하는 모델에서는 image의 추상화된 feature를 초기값으로 사용할 수도 있다.
89 | * 또한 simple한 Attention 모델에서는 attention vector를 hidden state 초기값으로 전달하기도 한다.
90 | * 우리의 경우, init_state_flag==0인 경우는 0으로 초기화 했고,
91 | * init_state_flag가 0이 아니면, 밖에서 받아온 값으로 초기화해야 하는데, 예를 위해서 h0 = tf.random_normal([batch_size,hidden_dim])를 사용했다.
92 | * LSTM cell에서는 c_state와 h_state가 있기 때문에 각각의 값을 지정해야함.
93 | * 우리는 LSTM cell을 multi로 쌓았기 때문에, 제일 아래 층만 지정된 값을 주고, 나머지 층은 0으로 초기화.
94 | * 제일 아래층에서도 c_state는 0으로 초기화하고, h_state는 h0값으로 초기화 했다.
95 | ---
96 | * helper부분을 살펴보자.
97 | ```python
98 | if train_mode:
99 | helper = tf.contrib.seq2seq.TrainingHelper(inputs, np.array([seq_length]*batch_size))
100 | else:
101 | helper = tf.contrib.seq2seq.GreedyEmbeddingHelper(embedding, start_tokens=tf.tile([SOS_token], [batch_size]), end_token=EOS_token)
102 | ```
103 | * helper는 input data를 cell에 전달하는 역할을 하는데, training 모드에서는 TrainingHelper를 사용하고, inference 모드에서는 GreedyEmbeddingHelper가 사용된다.
104 | * TrainingHelper의 2번째 argument로 배치의 seq_length를 정해줘야 하는데, 우리는 (필요한 경우 Null을 붙혀) batch속에 있는 각각의 data 길이가 동일(지금의 예에서는 6)하게 만들어 놓았기 때문에, [seq_length]*batch_size로 하면 된다.
105 | * Null을 붙혀 data길이를 맞추었다면, 나중에 loss계산할 때, Null이 붙은 부분의 weight는 0으로 줘서 무시될 수 있도록 하면 된다.
106 | * GreedyEmbeddingHelper는 이전 단계의 output의 argmax에 해당하는 값을 다음 단계의 input으로 전달한다.
107 | * GreedyEmbeddingHelper는 batch개수 만큼의 SOS_token과 EOS_token이 parameter로 넘어간다. EOS_token이 생성될 때까지 RNN 모델이 돌아간다. EOS_token이 생성되지 않으면 무한 루프에 빠질 수 있다.
108 | * 무한 루프에 빠지는 것을 방지하기 위해 아래의 tf.contrib.seq2seq.dynamic_decode에서 maximum_iterations을 지정해 주는 것이 좋다.
109 | ---
110 | * 이제 모델의 마지막 부분인 BasicDecoder, dynamic_decode를 살펴보자.
111 | ```python
112 | output_layer = Dense(output_dim, name='output_projection')
113 | decoder = tf.contrib.seq2seq.BasicDecoder(cell=cell,helper=helper,initial_state=initial_state,output_layer=output_layer)
114 | outputs, last_state, last_sequence_lengths = tf.contrib.seq2seq.dynamic_decode(decoder=decoder,output_time_major=False,impute_finished=True,maximum_iterations=10)
115 |
116 | ```
117 | * output_layer는 RNN cell의 출력값을 받아 연결할 Full Connected Layer를 지정해 준다. output dimension만 정해주면 된다.
118 | * 지금까지의 만든 cell, helper, initial_state, output_layer를 BasicDecoder에 전달하여 decoder를 만들고, 이 decoder를 전달하여 최종적으로 dynamic_decode를 만든다.
119 | ---
120 | * 이후의 코드는 Neural Net 모형을 아는 사람은 어렵지 않게 이해할 수 있기 때문에 추가적인 설명은 생략한다.
121 | * 또한, tf.contrib.seq2seq.sequence_loss에서 계산해 주는 loss값과 cross entropy loss를 직접 계산한 값이 일치하는지도 확인하고 있다.
122 | * tf.contrib.seq2seq.sequence_loss의 targets은 one-hot으로 변환되지 않은 값이 전달된다.
123 | * 기타 여러가지 확인할 부분을 출력하는 코드가 추가되어 있다.
124 | ---
125 | [추가 설명]
126 | * loss를 계산하는 부분에 대한 설명:
127 | ```python
128 | weights = tf.ones(shape=[batch_size,seq_length])
129 | loss = tf.contrib.seq2seq.sequence_loss(logits=outputs.rnn_output, targets=Y, weights=weights)
130 | ```
131 | * 우리는 Null을 사용하지 않았기 때문에 모든 batch data의 sequence에 대해서 동일한 가중치 1을 부여했다.
132 | * Null을 사용했다면, Null이 들어가는 부분의 loss가 무시될 수 있도록 weights를 만들어 준다.
133 | ```python
134 | weights = tf.to_float(tf.not_equal(y_data, Null))
135 | ```
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 | ---
145 | ### Full CODE
146 |
147 | ```python
148 | # -*- coding: utf-8 -*-
149 |
150 | import numpy as np
151 | import tensorflow as tf
152 |
153 |
154 | from tensorflow.python.layers.core import Dense
155 | tf.reset_default_graph()
156 |
157 | vocab_size = 5
158 | SOS_token = 0
159 | EOS_token = 4
160 |
161 | x_data = np.array([[SOS_token, 2, 1, 2, 3, 2],[SOS_token, 3, 1, 2, 3, 1],[SOS_token, 1, 3, 2, 2, 1]], dtype=np.int32)
162 | y_data = np.array([[2, 1, 2, 3, 2,EOS_token],[3, 1, 2, 3, 1,EOS_token],[ 1, 3, 2, 2, 1,EOS_token]],dtype=np.int32)
163 | print("data shape: ", x_data.shape)
164 |
165 |
166 | output_dim = vocab_size
167 | batch_size = len(x_data)
168 | hidden_dim = 6
169 | num_layers = 2
170 | seq_length = x_data.shape[1]
171 | embedding_dim = 8
172 |
173 | state_tuple_mode = True
174 | init_state_flag = 0
175 | train_mode = True
176 |
177 |
178 |
179 | with tf.variable_scope('test',reuse=tf.AUTO_REUSE) as scope:
180 | # Make rnn
181 | cells = []
182 | for _ in range(num_layers):
183 | #cell = tf.contrib.rnn.BasicRNNCell(num_units=hidden_dim)
184 | cell = tf.contrib.rnn.BasicLSTMCell(num_units=hidden_dim,state_is_tuple=state_tuple_mode)
185 | cells.append(cell)
186 | cell = tf.contrib.rnn.MultiRNNCell(cells)
187 | #cell = tf.contrib.rnn.BasicRNNCell(num_units=hidden_dim)
188 |
189 |
190 | #init = np.arange(vocab_size*embedding_dim).reshape(vocab_size,-1).astype(np.float32) # 이경우는 아래의 embedding의 get_variable에서 shape을 지정하면 안된다.
191 | init = tf.contrib.layers.xavier_initializer()
192 | embedding = tf.get_variable("embedding",shape=[vocab_size,embedding_dim], initializer=init,dtype = tf.float32)
193 | inputs = tf.nn.embedding_lookup(embedding, x_data) # batch_size x seq_length x embedding_dim
194 |
195 |
196 |
197 | if init_state_flag==0:
198 | initial_state = cell.zero_state(batch_size, tf.float32) #(batch_size x hidden_dim) x layer 개수
199 | else:
200 | h0 = tf.random_normal([batch_size,hidden_dim]) #실제에서는 적절한 값을 외부에서 받아와야 함.
201 | if state_tuple_mode:
202 | initial_state=(tf.contrib.rnn.LSTMStateTuple(tf.zeros_like(h0), h0),) + (tf.contrib.rnn.LSTMStateTuple(tf.zeros_like(h0), tf.zeros_like(h0)),)*(num_layers-1)
203 | else:
204 | initial_state = (tf.concat((tf.zeros_like(h0),h0), axis=1),) + (tf.concat((tf.zeros_like(h0),tf.zeros_like(h0)), axis=1),) * (num_layers-1)
205 | if train_mode:
206 | helper = tf.contrib.seq2seq.TrainingHelper(inputs, np.array([seq_length]*batch_size))
207 | else:
208 | helper = tf.contrib.seq2seq.GreedyEmbeddingHelper(embedding, start_tokens=tf.tile([SOS_token], [batch_size]), end_token=EOS_token)
209 |
210 | output_layer = Dense(output_dim, name='output_projection')
211 | decoder = tf.contrib.seq2seq.BasicDecoder(cell=cell,helper=helper,initial_state=initial_state,output_layer=output_layer)
212 | # maximum_iterations를 설정하지 않으면, inference에서 EOS토큰을 만나지 못하면 무한 루프에 빠진다
213 | outputs, last_state, last_sequence_lengths = tf.contrib.seq2seq.dynamic_decode(decoder=decoder,output_time_major=False,impute_finished=True,maximum_iterations=10)
214 |
215 |
216 | Y = tf.convert_to_tensor(y_data)
217 | weights = tf.ones(shape=[batch_size,seq_length])
218 | loss = tf.contrib.seq2seq.sequence_loss(logits=outputs.rnn_output, targets=Y, weights=weights)
219 |
220 | optimizer = tf.train.AdamOptimizer(learning_rate=0.01)
221 | train = optimizer.minimize(loss)
222 |
223 |
224 | with tf.Session() as sess:
225 |
226 | sess.run(tf.global_variables_initializer())
227 | if train_mode:
228 | for step in range(100):
229 | _,l = sess.run([train,loss])
230 | if step %10 ==0:
231 | print("step: {}, loss: {}".format(step,l))
232 |
233 | p = sess.run(tf.nn.softmax(outputs.rnn_output)).reshape(-1,output_dim)
234 | print("loss: {:20.6f}".format(sess.run(loss)))
235 | print("manual cal. loss: {:0.6f} ".format(np.average(-np.log(p[np.arange(y_data.size),y_data.flatten()]))) )
236 |
237 | print("initial_state: ", sess.run(initial_state))
238 | print("\n\noutputs: ",outputs)
239 | o = sess.run(outputs.rnn_output) #batch_size, seq_length, outputs
240 | o2 = sess.run(tf.argmax(outputs.rnn_output,axis=-1))
241 | print("\n",o,o2) #batch_size, seq_length, outputs
242 |
243 | print("\n\nlast_state: ",last_state)
244 | print(sess.run(last_state)) # batch_size, hidden_dim
245 |
246 | print("\n\nlast_sequence_lengths: ",last_sequence_lengths)
247 | print(sess.run(last_sequence_lengths)) # [seq_length]*batch_size
248 |
249 | print("kernel(weight)",sess.run(output_layer.trainable_weights[0])) # kernel(weight)
250 | print("bias",sess.run(output_layer.trainable_weights[1])) # bias
251 |
252 | ```
253 |
--------------------------------------------------------------------------------
/0. Basic/RNN-TF-dynamic-decode.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | import numpy as np
4 | import tensorflow as tf
5 |
6 |
7 | from tensorflow.python.layers.core import Dense
8 | tf.reset_default_graph()
9 |
10 | vocab_size = 5
11 | SOS_token = 0
12 | EOS_token = 4
13 |
14 | x_data = np.array([[SOS_token, 2, 1, 2, 3, 2],[SOS_token, 3, 1, 2, 3, 1],[SOS_token, 1, 3, 2, 2, 1]], dtype=np.int32)
15 | y_data = np.array([[2, 1, 2, 3, 2,EOS_token],[3, 1, 2, 3, 1,EOS_token],[ 1, 3, 2, 2, 1,EOS_token]],dtype=np.int32)
16 | print("data shape: ", x_data.shape)
17 |
18 |
19 | output_dim = vocab_size
20 | batch_size = len(x_data)
21 | hidden_dim =6
22 | num_layers = 2
23 | seq_length = x_data.shape[1]
24 | embedding_dim = 8
25 | state_tuple_mode = True
26 | init_state_flag = 0
27 |
28 | #init = np.arange(vocab_size*embedding_dim).reshape(vocab_size,-1).astype(np.float32) # 이경우는 아래의 embedding의 get_variable에서 shape을 지정하면 안된다.
29 | init = tf.contrib.layers.xavier_initializer()
30 |
31 | train_mode = True
32 | with tf.variable_scope('test',reuse=tf.AUTO_REUSE) as scope:
33 | # Make rnn
34 | cells = []
35 | for _ in range(num_layers):
36 | #cell = tf.contrib.rnn.BasicRNNCell(num_units=hidden_dim)
37 | cell = tf.contrib.rnn.BasicLSTMCell(num_units=hidden_dim,state_is_tuple=state_tuple_mode)
38 | cells.append(cell)
39 | cell = tf.contrib.rnn.MultiRNNCell(cells)
40 | #cell = tf.contrib.rnn.BasicRNNCell(num_units=hidden_dim)
41 |
42 | embedding = tf.get_variable("embedding",shape=[vocab_size,embedding_dim], initializer=init,dtype = tf.float32)
43 | inputs = tf.nn.embedding_lookup(embedding, x_data) # batch_size x seq_length x embedding_dim
44 |
45 |
46 |
47 | if init_state_flag==0:
48 | initial_state = cell.zero_state(batch_size, tf.float32) #(batch_size x hidden_dim) x layer 개수
49 | else:
50 | if state_tuple_mode:
51 | h0 = tf.random_normal([batch_size,hidden_dim]) #h0 = tf.cast(np.random.randn(batch_size,hidden_dim),tf.float32)
52 | initial_state=(tf.contrib.rnn.LSTMStateTuple(tf.zeros_like(h0), h0),) + (tf.contrib.rnn.LSTMStateTuple(tf.zeros_like(h0), tf.zeros_like(h0)),)*(num_layers-1)
53 |
54 | else:
55 | h0 = tf.random_normal([batch_size,hidden_dim]) #h0 = tf.cast(np.random.randn(batch_size,hidden_dim),tf.float32)
56 | initial_state = (tf.concat((tf.zeros_like(h0),h0), axis=1),) + (tf.concat((tf.zeros_like(h0),tf.zeros_like(h0)), axis=1),) * (num_layers-1)
57 | if train_mode:
58 | helper = tf.contrib.seq2seq.TrainingHelper(inputs, np.array([seq_length]*batch_size))
59 | else:
60 | helper = tf.contrib.seq2seq.GreedyEmbeddingHelper(embedding, start_tokens=tf.tile([SOS_token], [batch_size]), end_token=EOS_token)
61 |
62 | output_layer = Dense(output_dim, name='output_projection')
63 | decoder = tf.contrib.seq2seq.BasicDecoder(cell=cell,helper=helper,initial_state=initial_state,output_layer=output_layer)
64 | # maximum_iterations를 설정하지 않으면, inference에서 EOS토큰을 만나지 못하면 무한 루프에 빠진다
65 | outputs, last_state, last_sequence_lengths = tf.contrib.seq2seq.dynamic_decode(decoder=decoder,output_time_major=False,impute_finished=True,maximum_iterations=10)
66 |
67 |
68 | Y = tf.convert_to_tensor(y_data)
69 | weights = tf.ones(shape=[batch_size,seq_length])
70 |
71 | loss = tf.contrib.seq2seq.sequence_loss(logits=outputs.rnn_output, targets=Y, weights=weights)
72 |
73 | optimizer = tf.train.AdamOptimizer(learning_rate=0.01)
74 | train = optimizer.minimize(loss)
75 |
76 |
77 | with tf.Session() as sess:
78 |
79 | sess.run(tf.global_variables_initializer())
80 | if train_mode:
81 | for step in range(100):
82 | _,l = sess.run([train,loss])
83 | if step %10 ==0:
84 | print("step: {}, loss: {}".format(step,l))
85 |
86 | p = sess.run(tf.nn.softmax(outputs.rnn_output)).reshape(-1,output_dim)
87 | print("loss: {:20.6f}".format(sess.run(loss)))
88 | print("manual cal. loss: {:0.6f} ".format(np.average(-np.log(p[np.arange(y_data.size),y_data.flatten()]))) )
89 |
90 | print("initial_state: ", sess.run(initial_state))
91 | print("\n\noutputs: ",outputs)
92 | o = sess.run(outputs.rnn_output) #batch_size, seq_length, outputs
93 | o2 = sess.run(tf.argmax(outputs.rnn_output,axis=-1))
94 | print("\n",o,o2) #batch_size, seq_length, outputs
95 |
96 | print("\n\nlast_state: ",last_state)
97 | print(sess.run(last_state)) # batch_size, hidden_dim
98 |
99 | print("\n\nlast_sequence_lengths: ",last_sequence_lengths)
100 | print(sess.run(last_sequence_lengths)) # [seq_length]*batch_size
101 |
102 | print("kernel(weight)",sess.run(output_layer.trainable_weights[0])) # kernel(weight)
103 | print("bias",sess.run(output_layer.trainable_weights[1])) # bias
--------------------------------------------------------------------------------
/0. Basic/dynamic-rnn-decode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hccho2/Tensorflow-RNN-Tutorial/c27d72d3247b55a3d79b102a37558b5ba2242d1d/0. Basic/dynamic-rnn-decode.png
--------------------------------------------------------------------------------
/1. RNNWrapper/cell-cell.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hccho2/Tensorflow-RNN-Tutorial/c27d72d3247b55a3d79b102a37558b5ba2242d1d/1. RNNWrapper/cell-cell.png
--------------------------------------------------------------------------------
/1. RNNWrapper/dynamic-rnn-decode2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hccho2/Tensorflow-RNN-Tutorial/c27d72d3247b55a3d79b102a37558b5ba2242d1d/1. RNNWrapper/dynamic-rnn-decode2.png
--------------------------------------------------------------------------------
/1. RNNWrapper/math-basicRNN.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hccho2/Tensorflow-RNN-Tutorial/c27d72d3247b55a3d79b102a37558b5ba2242d1d/1. RNNWrapper/math-basicRNN.png
--------------------------------------------------------------------------------
/1. RNNWrapper/readme.md:
--------------------------------------------------------------------------------
1 | # Tensorflow에서 BasicDecoder에 넘겨 줄 수 있는 사용자 정의 RNN Wrapper Class를 만들어 보자.
2 | ### [목차]
3 | * [쉬운 것부터 시작해보자](#쉬운-것부터-시작해보자)
4 | * [BasicRNNCell을 직접 만들어보자](#basicrnncell을-직접-만들어보자)
5 | * [User Defined RNNCell](#user-defined-rnncell)
6 | * [진정한 Wrapper 만들기](#진정한-wrapper-만들기)
7 |
8 | ### [쉬운 것부터 시작해보자]
9 |
10 | 아래 그림은 tf.contrib.seq2seq.BasicDecoder(class)와 tf.contrib.seq2seq.dynamic_decode(함수)의 입력 구조를 그려놓은 것이다.
11 | BasicDecoder, dynamic_decode를 잘 모르는 경우에는 이전 post인 [RNN-Tutorial](https://github.com/hccho2/RNN-Tutorial)를 참고하면 된다.
12 | 
13 | * Tensorflow의 dynamic_decode는 BasicDecoder를 입력받고, BasicDecoder는 cell, Helper 등을 입력받아 RNN모델이 구현된다.
14 | * 이 post에서는 user defined RNNCell 구현에 대해서 알아보고자 한다.
15 | * 먼저, cell의 대표적인 예로는 Tensorflow에 구현되어 있는 BasicRNNCell, GRUCell, BasicLSTMCell 등이 있다.
16 | * 이런 cell들은 (Tensorflow의) RNNCell을 상속받은 class들이다.
17 | * RNNCell을 상속받아 사용자 정의 RNN Wrapper class를 만들어 BasicDecoder로 넘겨줄 수 있다.
18 | * 이제, 초간단으로 만들어진 user defined RNN Wrapper의 sample code를 살펴보자.
19 |
20 | ```python
21 | from tensorflow.contrib.rnn import RNNCell
22 |
23 | class MyRnnWrapper(RNNCell):
24 | # property(output_size, state_size) 2개와 call을 정의하면 된다.
25 | def __init__(self,state_dim,name=None):
26 | super(MyRnnWrapper, self).__init__(name=name)
27 | self.sate_size = state_dim
28 |
29 | @property
30 | def output_size(self):
31 | return self.sate_size
32 |
33 | @property
34 | def state_size(self):
35 | return self.sate_size
36 |
37 | def call(self, inputs, state):
38 | # 이 call 함수를 통해 cell과 cell이 연결된다.
39 | cell_output = inputs
40 | next_state = state + 0.1
41 | return cell_output, next_state
42 | ```
43 | * 위 코드는, RNNCell을 상속받아 class MyRnnWrapper를 구현하고 있다.
44 | * MyRnnWrapper에서 반드시 구현하여야 하는 부분은 perperty output_size와 state_size 이다. 그리고 call(self, inputs, state)이라는 특수한 class method를 구현해야 한다.
45 | * output_size는 RNN Model에서 출력될 결과물의 dimension이고 state_size는 cell과 cell를 연결하는 hidden state의 크기이다.
46 | * call 함수(method)는 input과 직전 cell에서 넘겨 받은 hidden state값을 넘겨 받아, 필요한 계산을 수행한 후, 다음 단계로 넘겨 줄 next_state와 cell_output를 구하는 역할을 수행한다.
47 |
48 | 
49 | * 위 sample code은 넘겨받은 input을 그대로 output으로 내보내고, 넘겨 받은 state는 test 삼아, 0.1을 더해 next_state로 넘겨주는 의미 없는 example이다.
50 | * 지금까지 만든 MyRnnWrapper를 dynamic_decode로 넘겨 볼 수 있는 간단한 예를 만들어 돌려보자. 아래 코드가 이해되지 않는다면 위에서 언급한 [RNN-Tutorial](https://github.com/hccho2/RNN-Tutorial)를 참고하면 된다.
51 | * last state의 출력 값이 0.6인 이유는?
52 | ```python
53 | # coding: utf-8
54 | SOS_token = 0
55 | EOS_token = 4
56 | vocab_size = 5
57 | x_data = np.array([[SOS_token, 3, 3, 2, 3, 2],[SOS_token, 3, 1, 2, 3, 1],[SOS_token, 1, 3, 2, 2, 1]], dtype=np.int32)
58 |
59 | print("data shape: ", x_data.shape)
60 | sess = tf.InteractiveSession()
61 |
62 | output_dim = vocab_size
63 | batch_size = len(x_data)
64 | seq_length = x_data.shape[1]
65 | embedding_dim = 2
66 |
67 | init = np.arange(vocab_size*embedding_dim).reshape(vocab_size,-1)
68 |
69 | train_mode = True
70 | alignment_history_flag = False
71 | with tf.variable_scope('test') as scope:
72 | # Make rnn
73 | cell = MyRnnWrapper(embedding_dim,"xxx")
74 |
75 | embedding = tf.get_variable("embedding", initializer=init.astype(np.float32),dtype = tf.float32)
76 | inputs = tf.nn.embedding_lookup(embedding, x_data) # batch_size x seq_length x embedding_dim
77 |
78 | #######################################################
79 |
80 | initial_state = cell.zero_state(batch_size, tf.float32) #(batch_size x hidden_dim) x layer 개수
81 |
82 | helper = tf.contrib.seq2seq.TrainingHelper(inputs, np.array([seq_length]*batch_size,dtype=np.int32))
83 |
84 | decoder = tf.contrib.seq2seq.BasicDecoder(cell=cell,helper=helper,initial_state=initial_state,output_layer=None)
85 | outputs, last_state, last_sequence_lengths = tf.contrib.seq2seq.dynamic_decode(decoder=decoder,output_time_major=False,impute_finished=True,maximum_iterations=10)
86 |
87 |
88 | ######################################################
89 | sess.run(tf.global_variables_initializer())
90 | print("\ninputs: ",inputs)
91 | inputs_ = sess.run(inputs)
92 | print("\n",inputs_)
93 |
94 | print("\noutputs: ",outputs)
95 | outputs_ = sess.run(outputs.rnn_output)
96 | print("\n",outputs_)
97 |
98 | print("\nlast state: ",last_state)
99 | last_state_ = sess.run(last_state)
100 | print("\n",last_state_)
101 | """
102 | inputs: Tensor("test/embedding_lookup:0", shape=(3, 6, 2), dtype=float32)
103 |
104 | [[[0. 1.]
105 | [6. 7.]
106 | [6. 7.]
107 | [4. 5.]
108 | [6. 7.]
109 | [4. 5.]]
110 |
111 | [[0. 1.]
112 | [6. 7.]
113 | [2. 3.]
114 | [4. 5.]
115 | [6. 7.]
116 | [2. 3.]]
117 |
118 | [[0. 1.]
119 | [2. 3.]
120 | [6. 7.]
121 | [4. 5.]
122 | [4. 5.]
123 | [2. 3.]]]
124 |
125 | outputs: BasicDecoderOutput(rnn_output=, sample_id=)
126 |
127 | [[[0. 1.]
128 | [6. 7.]
129 | [6. 7.]
130 | [4. 5.]
131 | [6. 7.]
132 | [4. 5.]]
133 |
134 | [[0. 1.]
135 | [6. 7.]
136 | [2. 3.]
137 | [4. 5.]
138 | [6. 7.]
139 | [2. 3.]]
140 |
141 | [[0. 1.]
142 | [2. 3.]
143 | [6. 7.]
144 | [4. 5.]
145 | [4. 5.]
146 | [2. 3.]]]
147 |
148 | last state: Tensor("test/decoder/while/Exit_3:0", shape=(3, 2), dtype=float32)
149 |
150 | [[0.6 0.6]
151 | [0.6 0.6]
152 | [0.6 0.6]]
153 | """
154 | ```
155 |
156 | ### [BasicRNNCell을 직접 만들어보자]
157 | * 이제, 조금 더 의미 있는 user defined RNN Wrapper class를 만들어 보자. Tensorflow에 이미 구현되어 있는 tf.contrib.rnn.BasicRNNCell을 직접 구현해 보자.
158 | 
159 | * BasicRNNCell은 input과 이전 state를 concat하여 kernel을 곱한 후, bias를 더하고 tanh를 취하는 구조이다.
160 | * 이런 구조의 RNNCell을 만들기 위해서는 kernel과 bias를 정의해야 하고, call method에서 필요한 연산을 해 주면 된다.
161 | * kernel과 bias의 정의는 build(self, inputs_shape)라는 특수한 형태의 함수에서 해주면 된다.
162 | ```python
163 | class MyBasicRNNWrapper(RNNCell):
164 | # property(output_size, state_size) 2개와 call을 정의하면 된다.
165 | def __init__(self,state_dim,name=None):
166 | super(MyBasicRNNWrapper, self).__init__(name=name)
167 | self.sate_size = state_dim
168 |
169 | @property
170 | def output_size(self):
171 | return self.sate_size
172 |
173 | @property
174 | def state_size(self):
175 | return self.sate_size
176 |
177 | def build(self, inputs_shape):
178 | # 필요한 trainable variable이 있으면 여기서 생성하고, self.built = True로 설정하면 된다.
179 | input_depth = inputs_shape[1].value
180 | self._kernel = tf.get_variable('kernel', shape=[input_depth + self.sate_size, self.sate_size])
181 | self._bias = tf.get_variable('bias', shape=[self.sate_size], initializer=tf.zeros_initializer(dtype=tf.float32))
182 |
183 | self.built = True # 필요한 변수가 선언되었다는 것을 super에게 알려주는 역할.
184 |
185 | def call(self, inputs, state):
186 | # 이 call 함수를 통해 cell과 cell이 연결된다.
187 | gate_inputs = tf.matmul(tf.concat((inputs,state),axis=1),self._kernel)
188 | gate_inputs = tf.nn.bias_add(gate_inputs,self._bias)
189 | cell_output = tf.tanh(gate_inputs)
190 | next_state = cell_output
191 | return cell_output, next_state
192 |
193 | ```
194 | * 위와 같이 MyBasicRNNWrapper를 만들고 나면 MyRnnWrapper를 test했던 코드에서 Wrapper Class만 바꾸어서 test하면 된다.
195 | ```python
196 | hidden_dim = 4
197 | #cell = MyRnnWrapper(embedding_dim,"xxx")
198 | cell = MyBasicRNNWrapper(hidden_dim,"xxx")
199 | ```
200 |
201 | ### [User Defined RNNCell]
202 | * 입력 값인 input이 들어오면, FC layer를 한번 거친 후, state와 결합하여 연산하는 구조를 원한다면, call method를 수정해주면 된다.
203 | ```python
204 | def call(self, inputs, state):
205 | # 이 call 함수를 통해 cell과 cell이 연결된다.
206 | inputs = tf.layers.dense(inputs,units=self.input_depth,kernel_initializer = tf.contrib.layers.xavier_initializer(False), activation=tf.nn.relu)
207 | gate_inputs = tf.matmul(tf.concat((inputs,state),axis=1),self._kernel)
208 | gate_inputs = tf.nn.bias_add(gate_inputs,self._bias)
209 | cell_output = tf.tanh(gate_inputs)
210 | next_state = cell_output
211 | return cell_output, next_state
212 | ```
213 | * 출력값 cell_output을 FC layer를 한 번 거친 후, 내보내고 싶다면, 약간만 수정해 준다면 어렵지 않다.
214 | * 이런 식으로 원하는 구조로 얼마든지 변형이 가능하기 때문에, 원하는 모델을 만드는 것이 가능하다.
215 |
216 |
217 | ### [진정한 Wrapper 만들기]
218 | * RNN Wrapper는 말 그대로 RNN Cell을 감싸는 WRAP이다. Tensorflow에 구현되어 있는 BasicRNNCell, GRUCell, BasicLSTMCell등을 감싸서 새로운 구조를 만드는 틀이 될 수 있다.
219 | * 물론 내장되어 있는 RNN Cell뿐만 아니라, 우리가 여기서 다루고 있는 RNNWrapper를 다시 감싸는 RNNWrapper도 가능하다.
220 | * RNNCell을 감싸기 위해서는 init함수에서 원하는 RNNCell을 받으면 된다.
221 | 
222 | * 위 그림에서 볼 수 있듯이, 입력이 들어오면, 먼저 Wrapper가 받은 후, 내부의 RNNCell에 전달되는 구조이다.
223 | * tf.contrib.seq2seq.AttentionWrapper같은 경우에 입력이 들어오면, attention과 concat하여 새로운 input을 만드는데, 이렇게 catcat된 input을 내부의 RNNCell에 전달한다.
224 |
225 | ```python
226 | class MyBasicRNNWrapper2(RNNCell):
227 | # property(output_size, state_size) 2개와 call을 정의하면 된다.
228 | def __init__(self,cell,name=None):
229 | super(MyBasicRNNWrapper2, self).__init__(name=name)
230 | self.cell = cell
231 | @property
232 | def output_size(self):
233 | return self.cell.output_size
234 | @property
235 | def state_size(self):
236 | return self.cell.state_size
237 |
238 | def call(self, inputs, state):
239 | # 필요한 작업1: inputs, state를 이용하여 필요한 작업을 수행하여 self.cell에 넘겨줄 새로은 inputs, state를 만든다.
240 | cell_output, next_state = self.cell(inputs,state)
241 | # 필요한 작업2: self.cell이 return한 cell_outpus, next_state를 가공하여 return 값을 만든다.
242 | return cell_output, next_state
243 |
244 | hidden_dim = 4
245 | cell = MyBasicRNNWrapper2(tf.contrib.rnn.BasicRNNCell(hidden_dim),"xxx")
246 | ```
247 | * 위 코드의 call함수에서는 입력값인 (inputs, state)를 self.cell에 그래도 넘겼지만,
248 | * self.cell에 넘기기 전에 필요한 작업을 한 후 넘겨주고,
249 | * 그리고 self.cell에서 return 받는 결과에 필요한 후처리(post processing)를 수행한 후 return 하면 된다.
250 | * 예를 들어, Residual 같은 구조로 입력과 결과값을 더해서 output으로 내보내고 싶다거나, output과 state를 concat해서 새로운 output을 만들거나 등등
251 | ```python
252 | def call(self, inputs, state):
253 | cell_output, next_state = self.cell(inputs,state)
254 | cell_output = inputs + cell_output # residual rnn
255 | return cell_output, next_state
256 | ```
257 |
258 | * inputs를 FC layer에 넣은 후, cell에 넣어 줄 수도 있다. 이 때, 만들어지는 FC layer는 training이 된다.
259 | ```python
260 | def call(self, inputs, state):
261 | fc_outputs = tf.layers.dense(inputs,units=5,name='myFC') # FC layer
262 | cell_output, next_state = self.cell(fc_outputs,state)
263 | cell_output = inputs + cell_output # residual rnn
264 | return cell_output, next_state
265 | ```
266 |
267 | ### [p.s.]
268 | * 지금까지 tensorflow의 seq2seq 모델에서 BasicDecoder에 넘겨 줄 수 있는 user defined RNN Wrapper을 구현해 보았다.
269 | * RNN Wrapper를 구현하게 된 것은 Tacotron모델을 공부하는 과정에서 Bahdanau Attention을 변형하여 user defined Attention, user defined Helper 등을 공부했는데,
270 | * 이러한 것을 이해하기 위해서는 먼저 Wrapper Class를 잘 이해할 필요가 있기 때문에, user defined Wrapper Class 만들기를 정리해 보았다.
271 | * 추후,
272 | + user defined Helper class 만들기
273 | + user defined Attention 만들기 등을 정리해 볼 예정입니다.
274 |
--------------------------------------------------------------------------------
/1. RNNWrapper/wrapper.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hccho2/Tensorflow-RNN-Tutorial/c27d72d3247b55a3d79b102a37558b5ba2242d1d/1. RNNWrapper/wrapper.png
--------------------------------------------------------------------------------
/2. User Defined Helper/README.md:
--------------------------------------------------------------------------------
1 | # Tensorflow에서 BasicDecoder에 넘겨 줄 수 있는 사용자 정의 Helper Calss를 만들어 보자.
2 | User Defined Helper는 tensorflow.contrib.seq2seq.Helper를 상속받아 구현할 수 있다.
3 |
4 | ### [목차]
5 | * [왜 User Defined Helper가 필요한가](#왜-User-Defined-Helper가-필요한가)
6 | * [User Defined Helper 만들기](#User-Defined-Helper-만들기)
7 | * [TacotronTestHelper 만들기](#TacotronTestHelper-만들기)
8 |
9 | ### [왜 User Defined Helper가 필요한가]
10 | * 기본적으로 TrainingHelper, GreedyEmbeddingHelper, SampleEmbeddingHelper 등을 주로 사용한다.
11 | * 모델에 따라서는 이런 표준적인 Helper로 처리할 수 없는 경우가 있다.
12 | * 예를 들어, [Tacotron](https://arxiv.org/abs/1703.10135) 모델의 Decoder구조는 r(reduction factor, 아래 그림에서는 3)개의 output을 만들어 내고, 그 중 마지막 것을 다음 step의 input으로 넘겨주는 방식으로 설계되어 있다(inference 단계). 이런 모델을 구현하기 위해서는 User Defined Helper가 필요하다.
13 |
14 |
15 | * train 단계, inference 단계 각각에 맞는 Helper가 필요하다.
16 |
17 | ### [User Defined Helper 만들기]
18 | * TrainingHelper와 동일한 User Defined Helper를 하나 만들어보다.
19 | * tensorflow.contrib.seq2seq.Helper를 상속받아 구현해야 한다.
20 |
21 | ```python
22 | class MyRnnHelper(Helper):
23 | # property(batch_size,sample_ids_dtype,sample_ids_shape)이 정의되어야 하고, initialize,sample,next_inputs이 정의되어야 한다.
24 | def __init__(self,embedding,batch_size,output_dim,sequence_length):
25 | self._embedding = embedding
26 | self._batch_size = batch_size
27 | self._output_dim = output_dim
28 | self._sequence_length = sequence_length
29 |
30 | @property
31 | def batch_size(self):
32 | return self._batch_size
33 |
34 | @property
35 | def sample_ids_dtype(self):
36 | return tf.int32
37 |
38 | @property
39 | def sample_ids_shape(self):
40 | return tf.TensorShape([]) # sample_ids의 shape이 (batch_size,) 이므로, batch_size를 제외하면, "[]"이 된다.
41 |
42 | def next_inputs(self, time, outputs, state, sample_ids, name=None): # time+1을 위한 input을 만든다., outputs,state,sample_ids는 time step에서의 결과이다.
43 | # 넘어오는 sample_ids는 sample 함수에어 계산되어 넘어온 값이다. <----- 이런 계산은 BasicDecoder의 'step' 함수에서 이루어 진다.
44 | # next input을 계산하기 위해서 sample_ids를 이용하거나, outpus를 이용하거나 선택하면 된다.
45 |
46 | next_time = time + 1
47 | finished = (next_time >= self._sequence_length)
48 | next_inputs = tf.nn.embedding_lookup(self._embedding,sample_ids)
49 | return (finished, next_inputs, state) #finished==True이면 next_inputs,state는 의미가 없다.
50 |
51 | def initialize(self, name=None):
52 | # 시작하는 input을 정의한다.
53 | # return (finished, first_inputs). finished는 시작이니까, 무조건 False
54 | # first_inputs는 예를 위해서, SOS_token으로 만들어 보았다.
55 | return (tf.tile([False], [self._batch_size]), tf.nn.embedding_lookup(self._embedding,tf.tile([SOS_token], [self._batch_size])))
56 |
57 | def sample(self, time, outputs, state, name=None):
58 | return tf.argmax(outputs, axis=-1,output_type=tf.int32)
59 | ```
60 |
61 | * 필수 property 3개(batch_size, sample_ids_dtype, sample_ids_shape)를 구현해야하고,
62 | * member function 3개(initialize,sample,next_inputs)도 구현하면 된다.
63 | * 필수 property들과 member function을 구현하는데 필요한 추가적인 정보가 필요하다면 __init__ 에서 받아오도록 하면 된다.
64 | * def initialize(self, name=None): RNN 모형에서 첫 input data를 만들어 주는 역할을 한다.
65 | * def sample(self, time, outputs, state, name=None): time에서 만들어진 output, state을 조합해서 sample을 만든다. 예를 들어, TrainingHelper에서는 argmax를 취해서 sample을 만들고, SampleEmbeddingHelper에서는 단순 argmax 대신 distribution을 이용해서 random sampling으로 sample을 만든다.
66 | * def next_inputs(self, time, outputs, state,sample_ids, name=None): time step에서 만들어진 output, state와 sample함수에서 만들어진 sample_ids를 이용하여 time+1(다음 step)을 위한 입력 data를 만들어주면 된다.
67 | * next_inputs 함수 내에서 batch data마다 길이가 다르기 때문에, finished를 정확히 계산하려면 sequence_length를 __init__ 에서 받아와야 한다.
68 |
69 |
70 |
71 | ### [TacotronTestHelper 만들기]
72 | * Tacotron 모델에서 inference 단계에서 사용할 Helper를 만들어 보자.
73 |
74 | ```python
75 | class TacoTestHelper(Helper):
76 | def __init__(self, batch_size, output_dim, r):
77 | with tf.name_scope('TacoTestHelper'):
78 | self._batch_size = batch_size
79 | self._output_dim = output_dim
80 | self._end_token = tf.tile([0.0], [output_dim * r]) # [0.0,0.0,...]
81 |
82 | @property
83 | def batch_size(self):
84 | return self._batch_size
85 |
86 | @property
87 | def sample_ids_dtype(self):
88 | return tf.int32
89 |
90 | @property
91 | def sample_ids_shape(self):
92 | return tf.TensorShape([])
93 |
94 | def initialize(self, name=None):
95 | return (tf.tile([False], [self._batch_size]), tf.tile([[0.0]], [self._batch_size, self._output_dim]))
96 |
97 | def sample(self, time, outputs, state, name=None):
98 | # sample함수가 특별히 할 역할이 없기 때문에 그냥 garbage를 return한다.
99 | return tf.tile([0], [self._batch_size]) # Return all 0; we ignore them
100 |
101 | def next_inputs(self, time, outputs, state, sample_ids, name=None):
102 | '''Stop on EOS. Otherwise, pass the last output as the next input and pass through state.'''
103 | with tf.name_scope('TacoTestHelper'):
104 | finished = tf.reduce_all(tf.equal(outputs, self._end_token), axis=1)
105 | # Feed last output frame as next input. outputs is [N, output_dim * r]
106 | next_inputs = outputs[:, -self._output_dim:] #outputs: (batch_size, output_dim*r)에서 마지막 output_dim개만 return
107 | return (finished, next_inputs, state)
108 | ```
109 |
110 | * 함수 next_inputs에서 next_inputs를 계산하는 방식에만 주목하면 된다. output_dim*r 중에서 마지막 output_dim개만 return했다.
111 |
112 |
113 |
114 | ---
115 | ## Reference
116 | - https://github.com/keithito/tacotron
117 |
--------------------------------------------------------------------------------
/2. User Defined Helper/tacotron-decoder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hccho2/Tensorflow-RNN-Tutorial/c27d72d3247b55a3d79b102a37558b5ba2242d1d/2. User Defined Helper/tacotron-decoder.png
--------------------------------------------------------------------------------
/3. User Defined Decoder/BasicDecoder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hccho2/Tensorflow-RNN-Tutorial/c27d72d3247b55a3d79b102a37558b5ba2242d1d/3. User Defined Decoder/BasicDecoder.png
--------------------------------------------------------------------------------
/3. User Defined Decoder/BasicDecoder2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hccho2/Tensorflow-RNN-Tutorial/c27d72d3247b55a3d79b102a37558b5ba2242d1d/3. User Defined Decoder/BasicDecoder2.png
--------------------------------------------------------------------------------
/3. User Defined Decoder/README.md:
--------------------------------------------------------------------------------
1 | # 기본적으로 BasicDecoder를 사용하지만, User Defined Help나 RNNWrapper를 사용하기 위해서는 Cumtomization이 필요하다.
2 |
3 | ### [목차]
4 | * [User Defined Decoder는 언제 필요한가](#User-Defined-Decoder는-언제-필요한가)
5 | * [BasicDecoder Cumtomization](#BasicDecoder-Cumtomization)
6 |
7 | ---
8 |
9 |
10 | ### [User Defined Decoder는 언제 필요한가]
11 | * BasicDecoder의 __init__ 함수는 다음과 같은 proto type을 가진다.
12 |
13 |
14 | * 다음은 BasicDecoder의 member function인 step 함수이다.
15 | ```python
16 | def step(self, time, inputs, state, name=None):
17 | """Perform a decoding step.
18 | Args:
19 | time: scalar `int32` tensor.
20 | inputs: A (structure of) input tensors.
21 | state: A (structure of) state tensors and TensorArrays.
22 | name: Name scope for any created operations.
23 | Returns:
24 | `(outputs, next_state, next_inputs, finished)`.
25 | """
26 | with ops.name_scope(name, "BasicDecoderStep", (time, inputs, state)):
27 | cell_outputs, cell_state = self._cell(inputs, state)
28 | if self._output_layer is not None:
29 | cell_outputs = self._output_layer(cell_outputs)
30 | sample_ids = self._helper.sample(
31 | time=time, outputs=cell_outputs, state=cell_state)
32 | (finished, next_inputs, next_state) = self._helper.next_inputs(
33 | time=time,
34 | outputs=cell_outputs,
35 | state=cell_state,
36 | sample_ids=sample_ids)
37 | outputs = BasicDecoderOutput(cell_outputs, sample_ids)
38 | return (outputs, next_state, next_inputs, finished)
39 | ```
40 |
41 | * __init__에서 넘겨받은 cell, helper를 step함수에서 처리하고 있는 것을 볼 수 있다.
42 | * __init__에 넘겨지는 cell이나 helper를 표준적인 형식에서 벗어나게 customization했다면, BasicDecoder를 사용할 수 없다.
43 | * 좀 더 구체적으로 살펴보자.
44 | * Helper의 next_inputs함수의 proto type은 다음과 같다.
45 | ```python
46 | def next_inputs(self, time, outputs, state, sample_ids, name=None):
47 | ```
48 | * (time, outputs, state, sample_ids,name)으로 이루어진 argument에 다음과 같이 추가적인 argument가 더해진다고 해보자.
49 | ```python
50 | def next_inputs(self, time, outputs, state, new_arg, sample_ids, name=None):
51 | ```
52 | * 이런 경우에는, BasicDecoder를 customization해야 한다.
53 |
54 | * 또 다른 예로, cell의 __call__함수의 argument나 return의 형식이 변경되는 경우에도 BasicDecoder를 사용할 수 없다.
55 |
56 | ---
57 |
58 |
59 | ### [BasicDecoder Cumtomization]
60 | * Tensorflow의 BasicDecoder [구현](https://github.com/tensorflow/tensorflow/blob/r1.12/tensorflow/contrib/seq2seq/python/ops/basic_decoder.py)을 살펴보면 생각보다 간단함을 알 수 있다.
61 |
62 |
63 | * self.cell(...)이나 self._helper.next_input(...)이 customization 되어 있다면, 상황에 맞게 BasicDecoder의 step함수를 변경하기만 하면 된다.
64 | * 예를 들어, cell이 2개의 output을 return한다면(e.g. Tacotron2에서 rnn cell의 return (cell_outputs, stop_token)) 이런 변형된 output을 처리하려면 BasicDecoder의 step함수를 수정해야 한다.
65 | * 참고: 변형된 output을 하나로 묶어 return하고, Helper에서 처리할 수 있도록 Helper만 cumtomization해도 된다.
66 |
67 | ### [dynamic_decode]
68 | * tf.contrib.seq2seq.dynamic_decode는 class가 아니고 함수이다.
69 | * decoder(BasicDecoder)의 step 함수를 호출하여 loop 처리한다.
70 |
71 |
--------------------------------------------------------------------------------
/4. Attention with Tensorflow/Attention.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hccho2/Tensorflow-RNN-Tutorial/c27d72d3247b55a3d79b102a37558b5ba2242d1d/4. Attention with Tensorflow/Attention.png
--------------------------------------------------------------------------------
/4. Attention with Tensorflow/AttentionWrapper-API.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hccho2/Tensorflow-RNN-Tutorial/c27d72d3247b55a3d79b102a37558b5ba2242d1d/4. Attention with Tensorflow/AttentionWrapper-API.png
--------------------------------------------------------------------------------
/4. Attention with Tensorflow/Bahdanau-Luong-Attention.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hccho2/Tensorflow-RNN-Tutorial/c27d72d3247b55a3d79b102a37558b5ba2242d1d/4. Attention with Tensorflow/Bahdanau-Luong-Attention.png
--------------------------------------------------------------------------------
/4. Attention with Tensorflow/README.md:
--------------------------------------------------------------------------------
1 | # Tensorflow에서 Attention Model이 RNN API와 어떻게 연계되어 동작하는지 살펴보자.
2 |
3 | ## Attention Model
4 | * 대표적인 Attention Model은 `Bahdanau Attention`, `Luong Attention` 등이 있다.
5 | * 이런 Attention Model에 Monotonic한 성질을 더하여 Bahdanau Monotonic Attention, Luong Monotonic Attention이 만들어 질 수도 있다.
6 | * Tensorflow에서는 Attention Model이 `Attention Mechanism` 이라는 개념으로 다루어진다.
7 |
8 | 
9 |
10 | * 위 그림은 Tensorflow Attention API가 이전 tutorial에서 다룬 Tensorflow의 RNN API(BasicDecoder, dynamic_decode 등)와 어떻게 연결되는지 보여주고 있다.
11 | * 이전에 tutorial에서 다룬 BasicRNNCell, BasicLSTMCell, GRUCell 등은 class RNNCell을 상속받아 구현된 class들이다.
12 | * Attention Model을 적용하기 위해서는, 이런 cell들을 대신해서 AttentionWrapper라는 class가 필요한데, 이 AttentionWrapper 또한 RNNCell class를 상속하여 구현된 class이다.
13 |
14 | 
15 |
16 | * AttentionWrapper의 __init__함수의 주요 argument는 {cell, attention_mechanism, attention_layer_size, output_attention, initial_cell_state}이다.
17 | * 이 주요 argument를 하나씩 살펴보자.
18 |
19 | ### cell
20 | * cell에는 지금까지 다룬, BasicRNNCell, BasicLSTMCell, GRUCell 등을 넣어 주면된다.
21 |
22 |
23 | ### attention_mechanism
24 | * attention_mechanism은 `AttentionMechanism` object를 넣어 주어야 한다.
25 | * `AttentionMechanism`에는 `tf.contrib.seq2seq.BahdanauAttention`, `tf.contrib.seq2seq.LuongAttention`, `tf.contrib.seq2seq.BahdanauMonotonicAttention` 등이 있다.
26 |
27 | 
28 | * Attention은 score -> softmax -> alignment -> context -> attention 순으로 계산이 된다.
29 | * Bahdanau Attention과 Luong Attention은 score를 계산하는 방식이 다른 것 뿐이다.
30 | ```python
31 | attention_mechanism = tf.contrib.seq2seq.BahdanauAttention(num_units=11, memory=encoder_outputs,memory_sequence_length=input_lengths,normalize=False)
32 | ```
33 | * 여기서 `num_units`이 score의 dimension을 결정한다.
34 |
35 | 
36 | * Monotonic Attention은 score로부터 alignmnet를 계산할 때, softmax함수 대신 다른 방식 계산이 사용된다.
37 |
38 |
39 | ### attention_layer_size
40 | * `attention_layer_size`는 contex vector로 부터 attention을 구하는데 필요하다.
41 | * `attention_layer_size = None` 으로 설정되면 attention은 context vector로 주어진다.
42 | 
43 | * `attention_layer_size`가 None이 아니면 decoder hidden state와 context vector가 concat되어 Fully-Connected Layer를 한번 더 통과하여 attention vector를 만들어 낸다.
44 |
45 |
46 | ### output_attention
47 | * `output_attention = True` 이면 attention vector가 RNN의 output이 된다.
48 | * `output_attention = False` 이면 decoder의 hidden state가 RNN의 output이 된다.
49 | * 어떤 모델에서는 RNN의 output으로 attentin vector와 decoder hidden state를 concat하기도 하는데, 이런 경우에는 AttentionWrapper를 customization해야 한다.
50 |
51 |
52 | ## [Full Code]
53 | ```python
54 | # coding: utf-8
55 | import tensorflow as tf
56 | import numpy as np
57 |
58 | tf.reset_default_graph()
59 | def attention_test():
60 | vocab_size = 5
61 | SOS_token = 0
62 | EOS_token = 4
63 |
64 | x_data = np.array([[SOS_token, 3, 1, 2, 3, 2],[SOS_token, 3, 1, 2, 3, 1],[SOS_token, 1, 3, 2, 2, 1]], dtype=np.int32)
65 | y_data = np.array([[1,2,0,3,2,EOS_token],[3,2,3,3,1,EOS_token],[3,1,1,2,0,EOS_token]],dtype=np.int32)
66 | Y = tf.convert_to_tensor(y_data)
67 | print("data shape: ", x_data.shape)
68 | sess = tf.InteractiveSession()
69 |
70 | output_dim = vocab_size
71 | batch_size = len(x_data)
72 | hidden_dim =6
73 | seq_length = x_data.shape[1]
74 | embedding_dim = 8
75 |
76 | init = np.arange(vocab_size*embedding_dim).reshape(vocab_size,-1)
77 |
78 | alignment_history_flag = True # True이면 initial_state나 last state를 sess.run 하면 안됨. alignment_history가 function이기 때문에...
79 | with tf.variable_scope('test',reuse=tf.AUTO_REUSE) as scope:
80 | # Make rnn cell
81 | cell = tf.contrib.rnn.BasicRNNCell(num_units=hidden_dim)
82 |
83 |
84 | embedding = tf.get_variable("embedding", initializer=init.astype(np.float32),dtype = tf.float32)
85 | inputs = tf.nn.embedding_lookup(embedding, x_data) # batch_size x seq_length x embedding_dim
86 |
87 | #encoder_outputs은 Encoder의 output이다. 보통 Memory라 불린다. 여기서는 toy model이기 때문에 ranodm값을 생성하여 넣어 준다.
88 | encoder_outputs = tf.convert_to_tensor(np.random.normal(0,1,[batch_size,20,30]).astype(np.float32)) # 20: encoder sequence length, 30: encoder hidden dim
89 |
90 | # encoder_outpus의 길이는 20이지만, 다음과 같이 조절할 수 있다.
91 | input_lengths = [5,10,20] # encoder에 padding 같은 것이 있을 경우, attention을 주지 않기 위해
92 |
93 | # attention mechanism # num_units = Na = 11
94 | attention_mechanism = tf.contrib.seq2seq.BahdanauAttention(num_units=11, memory=encoder_outputs,memory_sequence_length=input_lengths,normalize=False)
95 |
96 |
97 | attention_initial_state = cell.zero_state(batch_size, tf.float32)
98 | cell = tf.contrib.seq2seq.AttentionWrapper(cell, attention_mechanism, attention_layer_size=13,initial_cell_state=attention_initial_state,
99 | alignment_history=alignment_history_flag,output_attention=True)
100 | cell = tf.contrib.rnn.OutputProjectionWrapper(cell,output_dim)
101 |
102 | # 여기서 zero_state를 부르면, 위의 attentionwrapper에서 넘겨준 attention_initial_state를 가져온다. 즉, AttentionWrapperState.cell_state에는 넣어준 값이 들어있다.
103 | initial_state = cell.zero_state(batch_size, tf.float32) # AttentionWrapperState
104 |
105 | helper = tf.contrib.seq2seq.TrainingHelper(inputs, np.array([seq_length]*batch_size))
106 |
107 | decoder = tf.contrib.seq2seq.BasicDecoder(cell=cell,helper=helper,initial_state=initial_state)
108 |
109 | outputs, last_state, last_sequence_lengths = tf.contrib.seq2seq.dynamic_decode(decoder=decoder,output_time_major=False,impute_finished=True)
110 |
111 | weights = tf.ones(shape=[batch_size,seq_length])
112 | loss = tf.contrib.seq2seq.sequence_loss(logits=outputs.rnn_output, targets=Y, weights=weights)
113 |
114 | opt = tf.train.AdamOptimizer(0.01).minimize(loss)
115 |
116 | sess.run(tf.global_variables_initializer())
117 | for i in range(100):
118 | loss_,_ =sess.run([loss,opt])
119 | print("{} loss: = {}".format(i,loss_))
120 |
121 | if alignment_history_flag ==False:
122 | print("initial_state: ", sess.run(initial_state))
123 | print("\n\noutputs: ",outputs)
124 | o = sess.run(outputs.rnn_output) #batch_size, seq_length, outputs
125 | o2 = sess.run(tf.argmax(outputs.rnn_output,axis=-1))
126 | print("\n",o,o2) #batch_size, seq_length, outputs
127 |
128 | print("\n\nlast_state: ",last_state)
129 | if alignment_history_flag == False:
130 | print(sess.run(last_state)) # batch_size, hidden_dim
131 | else:
132 | print("alignment_history: ", last_state.alignment_history.stack())
133 | alignment_history_ = sess.run(last_state.alignment_history.stack())
134 | print(alignment_history_)
135 | print("alignment_history sum: ",np.sum(alignment_history_,axis=-1))
136 |
137 | print("cell_state: ", sess.run(last_state.cell_state))
138 | print("attention: ", sess.run(last_state.attention))
139 | print("time: ", sess.run(last_state.time))
140 |
141 | alignments_ = sess.run(last_state.alignments)
142 | print("alignments: ", alignments_)
143 | print('alignments sum: ', np.sum(alignments_,axis=1)) # alignments의 합이 1인지 확인
144 | print("attention_state: ", sess.run(last_state.attention_state))
145 |
146 | print("\n\nlast_sequence_lengths: ",last_sequence_lengths)
147 | print(sess.run(last_sequence_lengths)) # [seq_length]*batch_size
148 |
149 | p = sess.run(tf.nn.softmax(outputs.rnn_output)).reshape(-1,output_dim)
150 | print("loss: {:20.6f}".format(sess.run(loss)))
151 | print("manual cal. loss: {:0.6f} ".format(np.average(-np.log(p[np.arange(y_data.size),y_data.flatten()]))) )
152 |
153 | if __name__ == '__main__':
154 | attention_test()
155 | ```
156 |
157 | ### Summary
158 | * input dimension = 8, hidden dimention = 6, (attention mechanism) num_units=11, (AttentionWrapper) attention_layer_size=13
159 | * encoder output shape = (N,20,30)
160 | 
161 | * e_i를 계산할 때, 행렬곱을 2가지 방법으로 할 수 있다. [코드](https://gist.github.com/hccho2/81265eea686465fc0fd7aba5cbb73051)
162 | ### Quiz
163 | * T_e = ?
164 | * a: (N,20), h: (N,20,30) 일 때, context c를 구하는 과정을 tensorflow 연산으로 구현하라.
165 |
166 | [정답](https://github.com/hccho2/Tensorflow-RNN-Tutorial/blob/master/4.%20Attention%20with%20Tensorflow/answer.png)
167 |
--------------------------------------------------------------------------------
/4. Attention with Tensorflow/answer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hccho2/Tensorflow-RNN-Tutorial/c27d72d3247b55a3d79b102a37558b5ba2242d1d/4. Attention with Tensorflow/answer.png
--------------------------------------------------------------------------------
/4. Attention with Tensorflow/attentioin-dynamic-rnn-decode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hccho2/Tensorflow-RNN-Tutorial/c27d72d3247b55a3d79b102a37558b5ba2242d1d/4. Attention with Tensorflow/attentioin-dynamic-rnn-decode.png
--------------------------------------------------------------------------------
/4. Attention with Tensorflow/attention-layer-size.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hccho2/Tensorflow-RNN-Tutorial/c27d72d3247b55a3d79b102a37558b5ba2242d1d/4. Attention with Tensorflow/attention-layer-size.png
--------------------------------------------------------------------------------
/4. Attention with Tensorflow/attention-shape.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hccho2/Tensorflow-RNN-Tutorial/c27d72d3247b55a3d79b102a37558b5ba2242d1d/4. Attention with Tensorflow/attention-shape.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Tensorflow RNN-tutorial
2 |
3 |
4 |
5 |
6 | #### -1. [Tensorflow RNN Basic of Basic](https://github.com/hccho2/Tensorflow-RNN-Tutorial/tree/master/-1.%20Tensorflow%20RNN%20Basic%20of%20Basic)
7 | 여기서는 Tensorflow에서 RNN 모델에 대한 공부를 시작할 때 배우게 되는 dynamic_rnn에 대해서 알아본다.
8 | - dynamic_rnn은 Seq2Seq(Encoder-Decoder)모델을 배우기 전에 먼저 알아야 할 기본적인 RNN 모델 API이다.
9 |
10 |
11 | #### 0. [Basic RNN Model](https://github.com/hccho2/RNN-Tutorial/tree/master/0.%20Basic)
12 | Tensorflow의 다음과 같은 API를 사용하여 기본적인 RNN 모델의 작동 원리를 알 수 있다.
13 | - dynamic_decode를 사용하여 Tensorflow RNN모델 사용법에 관해 알아본다.
14 | - BasicRNNCell, BasicLSTMCell, GRUCell
15 | - TrainingHelper, GreedyEmbeddingHelper
16 | - BasicDecoder
17 | - dynamic_decode
18 |
19 | #### 1. [User Defined RNNWrapper](https://github.com/hccho2/RNN-Tutorial/tree/master/1.%20RNNWrapper)
20 | 사용자 정의 RNN Wrapper를 만드는 방법에 대하여 알아본다.
21 | - RNNCell을 상속받아 사용자 정의 RNN Wrapper class를 정의한다.
22 | - 여기서 만드는 RNN Wrapper는 BasicRNNCell을 대체할 수 있다.
23 |
24 |
25 |
26 |
27 |
28 | #### 2. [User Defined Helper](https://github.com/hccho2/Tensorflow-RNN-Tutorial/tree/master/2.%20User%20Defined%20Helper)
29 | 주로 사용하는 TrainingHelper, GreedyEmbeddingHelper, SampleEmbeddingHelper를 대신할 수 있는 사용자 정의 Helper를 만들어 보자.
30 | - Tacotron과 같은 모델에서는 RNN decoder를 구현하려면 사용자 정의 Helper가 반드시 필요하다.
31 |
32 |
33 | #### 3. [User Defined Decoder](https://github.com/hccho2/Tensorflow-RNN-Tutorial/tree/master/3.%20User%20Defined%20Decoder)
34 | BasicDecoder를 대체할 수 있는 사용자 정의 Decoder를 만들어 보자.
35 |
36 |
37 |
38 | #### 4. [Attention with Tensorflow](https://github.com/hccho2/Tensorflow-RNN-Tutorial/tree/master/4.%20Attention%20with%20Tensorflow)
39 | - Bahdanau Attention, Luong Attention이 Tensorflow내에서 어떻게 작동하는지에 대하여 알아 보자.
40 |
41 |
--------------------------------------------------------------------------------
/TF-RNN.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hccho2/Tensorflow-RNN-Tutorial/c27d72d3247b55a3d79b102a37558b5ba2242d1d/TF-RNN.png
--------------------------------------------------------------------------------
/a.bat:
--------------------------------------------------------------------------------
1 | git add --all
2 | git commit -am.
3 | git push origin +master
--------------------------------------------------------------------------------
/b.bat:
--------------------------------------------------------------------------------
1 | git fetch --all
2 | git reset --hard origin/master
--------------------------------------------------------------------------------