Keras
TensorFlow
Image Resizing
PIL
Deep Learning

Inconsistency between image resizing with Keras PIL and 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

Yes, image resizing can differ between Keras using PIL and TensorFlow using tf.image.resize, even when the target size looks identical. The differences usually come from interpolation algorithms, antialiasing behavior, pixel coordinate conventions, aspect-ratio handling, and dtype conversion.

This matters more than many teams expect. If training used one resizing pipeline and inference uses another, the model may see systematically different pixel values and lose accuracy in subtle, hard-to-debug ways.

Why the Outputs Differ

The most common causes are:

  • different interpolation defaults
  • different antialiasing behavior when shrinking
  • different channel and dtype handling
  • different preprocessing order, such as resize before crop versus crop before resize

Even if both sides say “bilinear,” the implementation details can still differ enough to produce non-identical arrays.

A Minimal Comparison

PIL example:

python
1from PIL import Image
2import numpy as np
3
4image = Image.open("input.jpg").convert("RGB")
5resized_pil = image.resize((224, 224), Image.BILINEAR)
6pil_array = np.asarray(resized_pil, dtype=np.float32) / 255.0
7
8print(pil_array.shape, pil_array.min(), pil_array.max())

TensorFlow example:

python
1import tensorflow as tf
2
3raw = tf.io.read_file("input.jpg")
4image = tf.image.decode_jpeg(raw, channels=3)
5image = tf.image.convert_image_dtype(image, tf.float32)
6resized_tf = tf.image.resize(image, [224, 224], method="bilinear")
7
8print(resized_tf.shape, tf.reduce_min(resized_tf).numpy(), tf.reduce_max(resized_tf).numpy())

Both produce a 224 x 224 x 3 float tensor, but the values may not be exactly the same.

Common Sources of Mismatch

One common mismatch is dtype order. PIL often gives you uint8 data first, while TensorFlow pipelines often convert to float32 during or before resize. That can slightly alter results depending on the processing order.

Another mismatch is antialiasing. TensorFlow exposes an antialias option:

python
1resized_tf = tf.image.resize(
2    image,
3    [224, 224],
4    method="bilinear",
5    antialias=True
6)

PIL may use different filtering behavior when downscaling, so enabling or disabling antialiasing can change how closely TensorFlow matches the PIL-based output.

A third mismatch is hidden preprocessing. For example:

  • one path may center-crop before resize
  • another may resize directly
  • one may normalize to [-1, 1]
  • another may normalize to [0, 1]

Those differences often get blamed on resizing even when the root cause is the overall preprocessing pipeline.

Keras Utilities May Still Use PIL Semantics

Older Keras image utilities and some preprocessing helpers historically relied on PIL under the hood. Newer TensorFlow pipelines often use tf.image directly. So “Keras versus TensorFlow” may actually mean “PIL semantics versus TensorFlow image-op semantics.”

That is why the real fix is usually not to guess which library is “correct,” but to pick one pipeline and use it consistently in training, validation, and inference.

How to Make Training and Inference Consistent

The safest strategy is:

  1. choose one resizing implementation
  2. use it everywhere
  3. test exact pixel outputs on a sample image

If you are training in TensorFlow, the simplest answer is often to move all image preprocessing into a TensorFlow input pipeline:

python
1def preprocess(path):
2    raw = tf.io.read_file(path)
3    image = tf.image.decode_jpeg(raw, channels=3)
4    image = tf.image.convert_image_dtype(image, tf.float32)
5    image = tf.image.resize(image, [224, 224], method="bilinear", antialias=True)
6    return image

Then use the same function, or an exported equivalent, in validation and serving.

If your production stack must use PIL, then it may be better to train with PIL-style preprocessing too, or at least benchmark the difference explicitly.

How to Debug the Difference

If outputs do not match, compare them step by step:

  • raw decoded image shape
  • channel order
  • dtype before resize
  • interpolation mode
  • antialias setting
  • normalization range after resize

You can also inspect the actual numeric difference:

python
diff = pil_array - resized_tf.numpy()
print(np.max(np.abs(diff)))
print(np.mean(np.abs(diff)))

That tells you whether the mismatch is tiny numerical noise or a genuinely different preprocessing behavior.

Common Pitfalls

One common mistake is assuming “bilinear” means identical output across libraries. It does not guarantee bit-for-bit equivalence.

Another mistake is training with one pipeline and serving with another because the resize calls look superficially similar. Models can be very sensitive to that mismatch.

It is also easy to focus only on resize and ignore normalization, crop order, or channel handling, which often contribute just as much to the inconsistency.

Finally, do not validate the pipeline only by image shape. Two arrays can have the same shape and still be meaningfully different as model inputs.

Summary

  • PIL-based Keras resizing and TensorFlow resizing can produce different pixel values.
  • Differences usually come from interpolation details, antialiasing, dtype conversion, and pipeline order.
  • The safest solution is to standardize on one preprocessing pipeline across training and inference.
  • Compare actual arrays, not just output shapes, when debugging.
  • In production ML systems, consistency matters more than picking one library out of habit.

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

All Rights Reserved.