Unit 02.03: Compression artefacts a model will happily learn
JPEG compression removes information in a structured way, and a model will learn the structure.
Error that follows the 8x8 blocks
The same gradient saved at three quality levels, compared against the original.
The code measures the maximum and mean pixel error at each.
import io
import numpy as np
from PIL import Image
gradient = np.tile(np.linspace(0, 255, 64, dtype="uint8"), (64, 1))
original = Image.fromarray(gradient)
for quality in (95, 40, 10):
buffer = io.BytesIO()
original.save(buffer, format="JPEG", quality=quality)
reloaded = np.asarray(Image.open(io.BytesIO(buffer.getvalue())))
error = np.abs(reloaded.astype(int) - gradient.astype(int))
print(f"quality {quality:>2}: {len(buffer.getvalue()):>5} bytes, "
f"max pixel error {error.max():>3}, mean {error.mean():.2f}")
print("\nthe error is structured, not random -- it follows the 8x8 JPEG blocks")
# A model trained on quality-95 images and served quality-40 ones sees a
# different distribution. If your production images are compressed, your
# training images must be compressed the same way.
The error is not random noise - it follows JPEG's 8×8 block grid, so it is a pattern with a consistent shape. A model trained on high-quality images and served heavily compressed ones sees a systematically different distribution.
The reverse is worse: train on compressed images and the model may learn the artefacts as features, which works until someone upgrades the camera.
The mistake this prevents
The mistake is training on the highest-quality images you can obtain when production images arrive compressed. Match the training distribution to the serving one, including the compression.
Takeaway
Compression artefacts are structured and learnable. Train on images processed the way production images will be, at the same quality.
