TensorFlow
image processing
deep learning
per_image_standardization
batch processing

How to perform tf.image.per_image_standardization on a batch of images in tensorflow

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.image.per_image_standardization normalizes one image at a time by subtracting that image's mean and dividing by an adjusted standard deviation. The catch is that the function is defined for a single image tensor, so a batch needs one extra step to apply the transform image by image.

What the Function Actually Does

Per-image standardization is different from dataset-wide normalization. Instead of using one global mean and standard deviation for the whole training set, TensorFlow computes statistics independently for each image.

That can help when brightness and contrast vary a lot across samples. After the transform, every image is centered near zero and scaled to a comparable range, which often makes optimization more stable.

The function expects an image shaped like [height, width, channels]. If your input is batched, the shape is usually [batch, height, width, channels], so you need to apply the operation across the first dimension.

Apply It to a Batch With tf.map_fn

The most direct solution is tf.map_fn. It runs a function on each image in the batch while preserving the batch dimension.

python
1import tensorflow as tf
2
3batch = tf.random.uniform(
4    shape=(4, 224, 224, 3),
5    minval=0,
6    maxval=255,
7    dtype=tf.float32,
8)
9
10standardized = tf.map_fn(
11    tf.image.per_image_standardization,
12    batch,
13    fn_output_signature=tf.float32,
14)
15
16print(batch.shape)
17print(standardized.shape)

This is the standard pattern when your batch already exists as a tensor in memory. Each image is standardized independently, which is exactly what the API intends.

If you want to confirm the effect numerically, inspect one image before and after:

python
1image_before = batch[0]
2image_after = standardized[0]
3
4print("mean before:", tf.reduce_mean(image_before).numpy())
5print("std before:", tf.math.reduce_std(image_before).numpy())
6print("mean after:", tf.reduce_mean(image_after).numpy())
7print("std after:", tf.math.reduce_std(image_after).numpy())

The post-standardization mean should be near zero, and the standard deviation should be near one, subject to TensorFlow's small safety adjustment for low-variance images.

Prefer Dataset.map in an Input Pipeline

If your data already flows through tf.data, apply the preprocessing inside the pipeline rather than after batching in Python code. This keeps the work in the graph and composes well with shuffle, cache, and prefetch.

python
1import tensorflow as tf
2
3def preprocess(image, label):
4    image = tf.cast(image, tf.float32)
5    image = tf.image.per_image_standardization(image)
6    return image, label
7
8dataset = tf.data.Dataset.from_tensor_slices((
9    tf.random.uniform((8, 64, 64, 3), 0, 255, dtype=tf.float32),
10    tf.range(8),
11))
12
13dataset = dataset.map(preprocess, num_parallel_calls=tf.data.AUTOTUNE)
14dataset = dataset.batch(4).prefetch(tf.data.AUTOTUNE)
15
16for images, labels in dataset.take(1):
17    print(images.shape, labels.numpy())

In this version, each unbatched image is standardized before it reaches the batch step. That is often cleaner than mapping over an already batched tensor.

Dtype and Value Range Matter

Always cast integer images to tf.float32 before preprocessing. Most model code expects floats, and standardization is fundamentally a floating-point operation.

If your images come from uint8 tensors in the 0 to 255 range, per_image_standardization can still handle them after casting. If they are already scaled to 0.0 through 1.0, the function remains valid; it simply computes statistics from that scale instead.

python
1image = tf.constant(
2    [[[0, 128, 255], [255, 128, 0]]],
3    dtype=tf.uint8,
4)
5
6image = tf.cast(image, tf.float32)
7image = tf.image.per_image_standardization(image)
8print(image.dtype)

When Not to Use It

Per-image standardization is not always the best normalization strategy. If your model depends on preserving absolute intensity relationships across images, independent normalization can remove signal you care about.

For transfer learning, many pretrained models expect a very specific preprocessing function, such as scaling to [-1, 1] or subtracting ImageNet channel means. In those cases, follow the model's documented preprocessing rather than swapping in per-image standardization.

Common Pitfalls

The most common error is passing a four-dimensional batch directly into tf.image.per_image_standardization. That raises a shape error because the function expects a single image.

Another issue is forgetting to cast integer tensors to tf.float32. Even if TensorFlow accepts the input, downstream behavior becomes harder to reason about and may not match your model pipeline.

Developers also sometimes standardize after batching and then wonder why performance suffers. If you already use tf.data, preprocessing per item in Dataset.map is usually the better path.

Finally, do not mix per-image standardization with a pretrained model's required preprocessing unless you know the change is acceptable. Normalization choices are part of the model contract.

Summary

  • 'tf.image.per_image_standardization operates on one image, not a full batch.'
  • Use tf.map_fn to standardize an in-memory batch image by image.
  • In tf.data, apply the transform before batching with Dataset.map.
  • Cast images to tf.float32 before standardization.
  • Follow the preprocessing expected by pretrained models instead of substituting this blindly.

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
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