TensorFlow
machine learning
tensor shapes
debugging
neural networks

Tensorflow Assign requires shapes of both tensors to match. lhs shape 20 rhs shape 48

Master System Design with Codemia

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

Introduction

The TensorFlow error Assign requires shapes of both tensors to match. lhs shape=20 rhs shape=48 happens when you update a variable with a value that has different dimensionality. This often appears during checkpoint restore, custom training loops, or manual weight assignment. The message is precise: the destination variable has 20 elements (or a dimension size of 20), but the incoming tensor has 48.

Even experienced teams hit this when model architecture changes between runs. A layer width changed from 20 to 48, but old checkpoints are still loaded. Another frequent cause is data preprocessing producing unexpected feature counts, which propagates into incompatible variable shapes.

Core Sections

1. Identify the exact variable pair that mismatches

Start by tracing which assignment failed. In eager mode, inspect variable and source tensor shapes before assignment.

python
1import tensorflow as tf
2
3w = tf.Variable(tf.zeros([20]), name="w")
4new_value = tf.ones([48])
5
6print("lhs:", w.shape)
7print("rhs:", new_value.shape)
8# w.assign(new_value)  # raises shape mismatch

In model code, print layer weights:

python
for var in model.trainable_variables:
    print(var.name, var.shape)

This quickly reveals whether the mismatch is in embeddings, dense layers, or optimizer slot variables.

2. Make checkpoint restores explicit and partial when needed

If architecture evolved, strict restore will fail. Use controlled restore semantics:

python
ckpt = tf.train.Checkpoint(model=model)
status = ckpt.restore("/path/to/ckpt")
status.expect_partial()  # if intentionally loading subset

Then verify critical layers actually loaded. Blindly ignoring mismatches can start training from random weights without you noticing.

For Keras models, load_weights(..., by_name=True, skip_mismatch=True) can help during migration, but always log skipped variables.

3. Stabilize input feature dimensionality

Sometimes the variable shape is “wrong” because your input pipeline changed feature count. Add assertions near preprocessing:

python
1FEATURE_DIM = 20
2
3@tf.function
4def preprocess(x):
5    x = tf.cast(x, tf.float32)
6    tf.debugging.assert_equal(tf.shape(x)[-1], FEATURE_DIM,
7                              message="Feature width drift detected")
8    return x

This catches drift before it reaches model assignment paths.

4. Regenerate variables when shape changes are intentional

If you intentionally changed a layer width, regenerate new checkpoints and discard incompatible weights for that layer.

python
1inputs = tf.keras.Input(shape=(64,))
2x = tf.keras.layers.Dense(48, activation="relu", name="proj")(inputs)
3out = tf.keras.layers.Dense(1)(x)
4model = tf.keras.Model(inputs, out)

Trying to force old [20] weights into a [48] layer is mathematically invalid; migration needs an explicit mapping strategy, not direct assignment.

Common Pitfalls

  • Changing model layer sizes but restoring checkpoints created from old architecture.
  • Suppressing restore warnings without auditing which variables were skipped.
  • Letting feature engineering change column counts between training and serving.
  • Assuming mismatch is random while optimizer slot variables are actually the failing tensors.
  • Reusing stale checkpoints across experiments with different hyperparameters and layer widths.

Summary

lhs shape=20 rhs shape=48 is a deterministic contract violation between a variable and assigned value. Resolve it by locating the exact variable pair, validating checkpoint compatibility, and enforcing fixed feature dimensions. When architecture changes are intentional, migrate weights selectively or retrain affected layers with fresh checkpoints. Treat shape expectations as part of your model interface, and these assignment errors become easy to diagnose instead of disruptive runtime surprises.

A practical way to keep this issue from returning is to turn the fix into a lightweight runbook. Capture the exact environment assumptions (tool versions, runtime flags, cluster or platform settings, and required dependencies), then store a short verification command sequence that any teammate can run from a clean setup. This makes troubleshooting deterministic instead of person-dependent and reduces rework during on-call incidents.

It also helps to add one automated guardrail in CI or pre-deploy checks that validates the critical assumption described above. That guardrail might be a linter rule, a smoke test, a schema check, a policy validation step, or a minimal integration test. When the same class of failure is caught before release, teams spend less time on emergency debugging and more time on controlled improvements.


Course illustration
Course illustration

All Rights Reserved.