# Image classification: Why use both a transform and a processor to preprocess images?

**URL:** <https://discuss.huggingface.co/t/image-classification-why-use-both-a-transform-and-a-processor-to-preprocess-images/106267>\
**Category:** Beginners\
**Created:** [September 11, 2024, 7:39am UTC](https://discuss.huggingface.co/t/image-classification-why-use-both-a-transform-and-a-processor-to-preprocess-images/106267 "2024-09-11T07:39:56Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Steyn-vanLeeuwen](https://avatars.discourse-cdn.com/v4/letter/s/3da27b/32.png) [@Steyn-vanLeeuwen](https://discuss.huggingface.co/u/Steyn-vanLeeuwen)\
**Post date:** [September 11, 2024, 7:39am UTC](https://discuss.huggingface.co/t/image-classification-why-use-both-a-transform-and-a-processor-to-preprocess-images/106267/1 "2024-09-11T07:39:56Z")

</div>

This huggingface image-classification tutorial ( [notebooks/examples/image\_classification.ipynb at main · huggingface/notebooks · GitHub](https://github.com/huggingface/notebooks/blob/main/examples/image_classification.ipynb) ) uses torchvision transforms to preproces the images. In particular, there are val\_transforms that resize, crop and normalise the images in the test and validation datasets:  
val\_transforms = Compose(  
[  
Resize(size),  
CenterCrop(crop\_size),  
ToTensor(),  
normalize,  
]  
)  
My question is: why do we move this responsibility from the processor  
image\_processor = AutoImageProcessor.from\_pretrained(model\_checkpoint)  
to the val\_transforms? Or are we doing the preprocessing twice, as the image\_processor is also handed to the trainer as the tokenizer? Final question: do I still need to apply both the val\_transforms and the processor at inference?

---

<div class="post-metadata">

**Author:** ![mahmutc](https://sea2.discourse-cdn.com/hellohellohello/user_avatar/discuss.huggingface.co/mahmutc/32/52583_2.png) [@mahmutc](https://discuss.huggingface.co/u/mahmutc)\
**Post date:** [September 11, 2024, 11:02am UTC](https://discuss.huggingface.co/t/image-classification-why-use-both-a-transform-and-a-processor-to-preprocess-images/106267/2 "2024-09-11T11:02:53Z")

</div>

hi @Steyn-vanLeeuwen  
I’m quoting from the tutorial

> You might wonder why we pass along the `image_processor` as a tokenizer when we already preprocessed our data. This is only to make sure the image processor configuration file (stored as JSON) will also be uploaded to the repo on the hub.

I think you’re not doing two different preprocessing. You just take some numbers from image\_processor to pass to other two functions:

```auto
normalize = Normalize(mean=image_processor.image_mean, std=image_processor.image_std)
if "height" in image_processor.size:
    size = (image_processor.size["height"], image_processor.size["width"])
    crop_size = size
    max_size = None
elif "shortest_edge" in image_processor.size:
    size = image_processor.size["shortest_edge"]
    crop_size = (size, size)
    max_size = image_processor.size.get("longest_edge")

```

For inference you can apply just image\_processor as explained in the tutorial.

---

<div class="post-metadata">

**Author:** ![Steyn-vanLeeuwen](https://avatars.discourse-cdn.com/v4/letter/s/3da27b/32.png) [@Steyn-vanLeeuwen](https://discuss.huggingface.co/u/Steyn-vanLeeuwen)\
**Post date:** [September 11, 2024, 5:18pm UTC](https://discuss.huggingface.co/t/image-classification-why-use-both-a-transform-and-a-processor-to-preprocess-images/106267/3 "2024-09-11T17:18:11Z")

</div>

Hi @mahmutc ,

Thanks for your help!

However, after digging into the code a bit more, I don’t think the tutorial has got it quite right.

The val\_transforms performs resize from pytorchvision, which matches the smallest edge of the image to size and scales the other edge while maintaining the aspectratio. The image is then cropped by CenterCrop to get an image with dimensions (size, size).

The processor, on the other hand, preforms the resize transform from pillow, which just scales the image sides to the dimensions required by the model.

When applied to an image with width unequal to height, the difference between these two methods is that the first will crop a part of the image away, while the second method will compress the image more in one direction compared to the other direction.

I don’t know how big the difference in performance will be when using slightly different preprocessing during inference compared to training. But in my opinion it’s cleaner to always use the same preprocessing.

What do you think?

preprocessor:

> <https://github.com/huggingface/transformers/blob/v4.44.2/src/transformers/models/vit/image_processing_vit.py#L42>

pillow resize:

> **[Image Module](https://pillow.readthedocs.io/en/stable/reference/Image.html)**
>
> The Image module provides a class with the same name which is used to represent a PIL image. The module also provides a number of factory functions, including functions to load images from files, a...

---

<div class="post-metadata">

**Author:** ![mahmutc](https://sea2.discourse-cdn.com/hellohellohello/user_avatar/discuss.huggingface.co/mahmutc/32/52583_2.png) [@mahmutc](https://discuss.huggingface.co/u/mahmutc)\
**Post date:** [September 11, 2024, 8:55pm UTC](https://discuss.huggingface.co/t/image-classification-why-use-both-a-transform-and-a-processor-to-preprocess-images/106267/4 "2024-09-11T20:55:22Z")

</div>

hi fair point. I’m not sure if adding ratio to RandomResizedCrop makes the model more robust.

RandomResizedCrop(from train\_transforms) may not maintain the aspect ratio, similar to pillow’s resize.

[https://pytorch.org/vision/main/generated/torchvision.transforms.RandomResizedCrop.html#torchvision.transforms.RandomResizedCrop](https://pytorch.org/vision/main/generated/torchvision.transforms.RandomResizedCrop.html#torchvision.transforms.RandomResizedCrop)

Another point: processor is related to pretrained model. I wouldn’t be surprised if it performs better.

---

<div class="post-metadata">

**Author:** ![Steyn-vanLeeuwen](https://avatars.discourse-cdn.com/v4/letter/s/3da27b/32.png) [@Steyn-vanLeeuwen](https://discuss.huggingface.co/u/Steyn-vanLeeuwen)\
**Post date:** [September 12, 2024, 7:05am UTC](https://discuss.huggingface.co/t/image-classification-why-use-both-a-transform-and-a-processor-to-preprocess-images/106267/5 "2024-09-12T07:05:03Z")

</div>

Ahh, I was not aware that RandomResizedCrop also scales the image.

I might change the validation\_transforms to resemble the processor, but the train\_trainsforms seem fine like this.

Many thanks for helping me understand! 😃
