TensorFlow
tf.unpack
Variable
dynamic dimension
machine learning

Using tf.unpack when first dimension of Variable is None

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

tf.unpack was the old name for what is now tf.unstack, and the core limitation has not changed: if you unstack along an axis, TensorFlow must know how many output tensors to create. When the first dimension is None, that count is not known statically, so a plain unstack along that axis becomes ambiguous. The fix is either to provide num explicitly or to redesign the computation so it does not require creating a Python list of unknown length.

Why None Causes Trouble Here

In TensorFlow shape notation, None usually means “this dimension is dynamic and will be known only at runtime.” That is perfectly fine for many operations. It is especially common for the batch dimension.

But unstack is different from an operation such as matrix multiplication. It does not just transform one tensor into another tensor. It creates multiple separate tensors. To do that, TensorFlow needs to know how many outputs to build.

So if you try to unstack along a dimension whose size is unknown, TensorFlow cannot determine the output list length at graph-construction time.

The Modern API Is tf.unstack

Older code may still mention tf.unpack, but the current name is tf.unstack.

python
1import tensorflow as tf
2
3x = tf.constant([[1, 2], [3, 4], [5, 6]])
4parts = tf.unstack(x, axis=0)
5
6for part in parts:
7    print(part)

This works because the size of axis 0 is known to be 3.

If the Size Is Known, Pass num

If the shape metadata is incomplete but you still know how many slices should exist, pass num explicitly.

python
1import tensorflow as tf
2
3x = tf.keras.Input(shape=(4,))
4parts = tf.unstack(x, num=3, axis=0)

The important point is that num tells TensorFlow how many outputs to create even if the static shape metadata on that axis is missing.

That only works when the axis length is actually fixed by the problem. If the batch size is truly variable, hardcoding num is the wrong fix.

Dynamic Batch Size Usually Means You Should Not Unstack Axis 0

A common source of confusion is trying to unstack the batch dimension. In many models the first dimension is None because the batch size should vary. Unstacking that axis would require TensorFlow to produce a Python list whose length depends on runtime input size.

That is usually a design smell. Instead of splitting the batch into separate tensors, keep the batch dimension intact and use tensor-aware operations such as:

  • 'tf.map_fn'
  • vectorized tensor ops
  • 'tf.TensorArray in lower-level control-flow code'

For example, if the goal is to process each batch element independently, tf.map_fn is often the better fit.

python
1import tensorflow as tf
2
3x = tf.keras.Input(shape=(4,))
4
5processed = tf.map_fn(lambda row: row * 2.0, x)
6model = tf.keras.Model(inputs=x, outputs=processed)

This keeps the batch dimension dynamic without forcing a static output list length.

If You Need a Static Time Axis, Unstack That Axis Instead

In sequence models, sometimes the first dimension is the batch and the second dimension is a fixed number of time steps. In that case, unstacking the time axis may make sense if that axis length is known.

python
1import tensorflow as tf
2
3sequence = tf.keras.Input(shape=(5, 8))
4steps = tf.unstack(sequence, num=5, axis=1)
5print(len(steps))

This works because the axis being unstacked has a known size of 5, even though the batch dimension remains dynamic.

The Practical Rule

Ask two questions before using tf.unstack.

  1. Which axis am I unstacking.
  2. Is that axis length statically known.

If the answer to the second question is no, then plain unstacking is usually the wrong tool unless you can honestly provide num.

Common Pitfalls

  • Treating tf.unpack as though it can always split a dynamic batch dimension into an arbitrary Python-length list.
  • Forgetting that tf.unpack is legacy naming and that tf.unstack is the modern API.
  • Supplying a fake num for an axis whose runtime size is genuinely variable.
  • Unstacking axis 0 out of habit when the real goal should have been a vectorized operation or tf.map_fn.
  • Confusing “dynamic tensor shapes are allowed” with “every op can ignore unknown output counts.”

Summary

  • 'tf.unpack is the old name for tf.unstack.'
  • Unstacking requires TensorFlow to know how many output tensors to create.
  • If the target axis size is unknown, you usually need to provide num or choose a different operation.
  • Dynamic batch dimensions are a common reason unstacking axis 0 fails.
  • When the length is truly dynamic, tf.map_fn or vectorized tensor operations are usually a better design.

Course illustration
Course illustration

All Rights Reserved.