The difference that I noticed is that the code in the second implementation uses tf.nn.rnn, which takes a list of inputs for each time step and generates a list of outputs for each time step.
(Inputs: a list of T values, each of which has a form tensor [batch_size, input_size].)
So, if you check the code in the second implementation on line 62, the input will be generated in n_steps * (batch_size, n_hidden)
In the 1st implementation, they iterate through n_time_steps and provide input data and receive the corresponding output and save it in the output list.
Code snippet from line 113 to 117
outputs = [] state = self._initial_state with tf.variable_scope("RNN"): for time_step in range(num_steps): if time_step > 0: tf.get_variable_scope().reuse_variables() (cell_output, state) = cell(inputs[:, time_step, :], state) outputs.append(cell_output)
Turning to your second question:
If you carefully noticed the input method in RNN in both implementations.
In the first implementation, the inputs already have the form batch_size x num_steps (here num_steps is the hidden size):
self._input_data = tf.placeholder(tf.int32, [batch_size, num_steps])
While in the second implementation, the original inputs are of the form (batch_size x n_steps x n_input). Therefore, to convert to a form, a weight matrix is ββrequired (n_steps x batch_size x hidden_size):
# Input shape: (batch_size, n_steps, n_input) _X = tf.transpose(_X, [1, 0, 2])
Hope this is helpful ...