TensorFlow
tf.nn.dynamic_rnn
input tensor structure
`RNN`
deep learning

How is the input tensor for TensorFlow's tf.nn.dynamic_rnn operator structured?

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

tf.nn.dynamic_rnn expects sequence data with an explicit time dimension, a batch dimension, and one or more feature dimensions. The exact order depends on whether you use the default batch-major layout or set time_major=True, and that distinction is the main thing to get right before debugging shapes.

The Default Shape: Batch Major

By default, dynamic_rnn expects input shaped like:

python
[batch_size, max_time, features]

That means:

  • 'batch_size is how many sequences are processed together'
  • 'max_time is the number of time steps in the padded batch'
  • 'features is the feature width at each time step'

Example:

python
1import tensorflow as tf
2
3x = tf.random.normal((32, 20, 8))
4cell = tf.compat.v1.nn.rnn_cell.BasicRNNCell(num_units=16)
5outputs, state = tf.compat.v1.nn.dynamic_rnn(cell, x, dtype=tf.float32)
6
7print(outputs.shape)
8print(state.shape)

Here, 32 sequences are processed, each sequence has 20 time steps, and each time step has 8 features.

The Alternative Shape: Time Major

If you set time_major=True, the expected layout becomes:

python
[max_time, batch_size, features]

Example:

python
1import tensorflow as tf
2
3x = tf.random.normal((20, 32, 8))
4cell = tf.compat.v1.nn.rnn_cell.BasicRNNCell(num_units=16)
5outputs, state = tf.compat.v1.nn.dynamic_rnn(
6    cell,
7    x,
8    dtype=tf.float32,
9    time_major=True,
10)
11
12print(outputs.shape)
13print(state.shape)

This layout can reduce some internal transposes in certain workflows, but it is only correct if the input tensor is actually organized that way.

What the Feature Dimension Means

The last dimension represents the input at one time step. For text, it might be an embedding vector. For sensor data, it might be a vector of measurements. For one-hot categorical input, it might be the one-hot width.

So a shape of (32, 20, 300) usually means:

  • 32 sequences per batch
  • 20 tokens or time steps per sequence
  • 300 features per token

That interpretation is more important than memorizing the raw numbers.

Variable-Length Sequences Use Padding Plus sequence_length

A batch often contains sequences of different true lengths. The common pattern is:

  • pad shorter sequences to max_time
  • pass the real lengths through sequence_length
python
1import tensorflow as tf
2
3x = tf.random.normal((3, 5, 4))
4lengths = tf.constant([5, 3, 4])
5cell = tf.compat.v1.nn.rnn_cell.BasicRNNCell(num_units=6)
6
7outputs, state = tf.compat.v1.nn.dynamic_rnn(
8    cell,
9    x,
10    sequence_length=lengths,
11    dtype=tf.float32,
12)

That tells TensorFlow which time steps are real and which padded steps should be ignored for state propagation.

Nested Input Structures Are Also Possible

dynamic_rnn can accept more complex input structures where each time step contains multiple tensors. In that case the structure of the input mirrors the structure expected by the RNN cell.

Still, the same principle holds: each component must carry batch and time dimensions in the correct order.

For most practical uses, though, the question is about a single 3D tensor, and the answer is batch-major by default unless you explicitly switch to time-major.

Common Pitfalls

The most common mistake is confusing batch-major and time-major layouts.

Another mistake is forgetting that the input is a sequence of feature vectors, not a flat 2D batch matrix.

A third issue is padding sequences but forgetting to supply sequence_length, which can make the RNN treat padded zeros as real time steps.

Finally, tf.nn.dynamic_rnn belongs to the TensorFlow 1.x style API family, so if you are working in modern tf.keras, use current recurrent layers unless you specifically need this lower-level interface.

Summary

  • The default dynamic_rnn input shape is [batch_size, max_time, features].
  • With time_major=True, the shape becomes [max_time, batch_size, features].
  • The last dimension represents the feature vector at each time step.
  • Variable-length sequences are usually padded and paired with sequence_length.
  • Most confusion comes from mixing up dimension order, not from the RNN cell itself.
  • If you are using modern TensorFlow, prefer current Keras RNN layers unless you specifically need dynamic_rnn.

Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Basis Lab
No course covers this one yet

Basis Lab writes one for you from a sentence about what you want to be able to do, then teaches it and checks you understood. Your first course is free.

Build my course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design