From 2d18805c287fb606baeb58101723ed0e3d233f65 Mon Sep 17 00:00:00 2001 From: Jihye Jeong Date: Wed, 4 Feb 2026 19:11:33 +0100 Subject: [PATCH 1/4] feat: add Hugging Face support to ClassifierContainer (#19) --- mapreader/classify/classifier.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/mapreader/classify/classifier.py b/mapreader/classify/classifier.py index 671d41bd..3aece18b 100644 --- a/mapreader/classify/classifier.py +++ b/mapreader/classify/classifier.py @@ -108,6 +108,7 @@ def __init__( is_inception: bool = False, load_path: str | None = None, force_device: bool = False, + huggingface=False, **kwargs, ): # set up device @@ -141,6 +142,7 @@ def __init__( ) self.labels_map = labels_map + self.huggingface = huggingface # set up model and move to device print("[INFO] Initializing model.") @@ -149,7 +151,25 @@ def __init__( self.input_size = input_size self.is_inception = is_inception elif isinstance(model, str): - self._initialize_model(model, **kwargs) + if self.huggingface: + try: + from transformers import AutoModelForImageClassification, AutoImageProcessor + except ImportError: + raise ImportError( + "Hugging Face models require the 'transformers' library: 'pip install transformers'." + ) + print(f"[INFO] Initializing Hugging Face model: {model}") + num_labels = len(self.labels.map) + self.model = AutoModelForImageClassification.from_pretrained( + model, + num_labels=num_labels, + ignore_mismatched_sizes=True + ).to(self.device) + self.hf_processor = AutoImageProcessor.from_pretrained(model) + self.input_size = getattr(self.hf_processor, "size", {"height": 224})["height"] + self.is_inception = False + else: + self._initialize_model(model, **kwargs) self.optimizer = None self.scheduler = None From 8cf2c25e16d313e2ee88e202ac7ba0f531d88b4b Mon Sep 17 00:00:00 2001 From: Jihye Jeong Date: Wed, 4 Feb 2026 19:32:25 +0100 Subject: [PATCH 2/4] feat: fix typo and support Hugging Face models (#192/hut101-#19) --- mapreader/classify/classifier.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mapreader/classify/classifier.py b/mapreader/classify/classifier.py index 3aece18b..fe4acbc4 100644 --- a/mapreader/classify/classifier.py +++ b/mapreader/classify/classifier.py @@ -159,7 +159,7 @@ def __init__( "Hugging Face models require the 'transformers' library: 'pip install transformers'." ) print(f"[INFO] Initializing Hugging Face model: {model}") - num_labels = len(self.labels.map) + num_labels = len(self.labels_map) self.model = AutoModelForImageClassification.from_pretrained( model, num_labels=num_labels, From a55798c0cd02800a44bee2f6e38e16c617827a70 Mon Sep 17 00:00:00 2001 From: Jihye Jeong Date: Mon, 16 Mar 2026 13:55:00 -0300 Subject: [PATCH 3/4] Apply reviewer feedback and fix --- mapreader/classify/classifier.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/mapreader/classify/classifier.py b/mapreader/classify/classifier.py index fe4acbc4..ce9f7dfb 100644 --- a/mapreader/classify/classifier.py +++ b/mapreader/classify/classifier.py @@ -108,7 +108,7 @@ def __init__( is_inception: bool = False, load_path: str | None = None, force_device: bool = False, - huggingface=False, + huggingface: bool = False, **kwargs, ): # set up device @@ -142,7 +142,6 @@ def __init__( ) self.labels_map = labels_map - self.huggingface = huggingface # set up model and move to device print("[INFO] Initializing model.") @@ -151,7 +150,7 @@ def __init__( self.input_size = input_size self.is_inception = is_inception elif isinstance(model, str): - if self.huggingface: + if huggingface: try: from transformers import AutoModelForImageClassification, AutoImageProcessor except ImportError: @@ -165,8 +164,14 @@ def __init__( num_labels=num_labels, ignore_mismatched_sizes=True ).to(self.device) - self.hf_processor = AutoImageProcessor.from_pretrained(model) - self.input_size = getattr(self.hf_processor, "size", {"height": 224})["height"] + hf_processor = AutoImageProcessor.from_pretrained(model) + size = getattr(hf_processor, "size", {}) + if "height" in size and "width" in size: + size = (size["height"], size["width"]) + elif "shortest_edge" in size: + size = (size["shortest_edge"], size["shortest_edge"]) + else: + size = input_size self.is_inception = False else: self._initialize_model(model, **kwargs) From 8367e8d08c726e0dbb1fdd894a6235c9ce33b611 Mon Sep 17 00:00:00 2001 From: Jihye Jeong Date: Mon, 16 Mar 2026 14:36:56 -0300 Subject: [PATCH 4/4] Updated docs and CHANGELOG --- CHANGELOG.md | 4 ++++ .../step-by-step-guide/4-classify/train.rst | 15 +++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a6eca48..67d9fc5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ The following table shows which versions of MapReader are compatible with which ## Pre-release _Add new changes here_ +### Added + +- Added Hugging Face model support to ClassifierContainer + ## [v1.8.1](https://github.com/Living-with-machines/MapReader/releases/tag/v1.8.1) (2025-08-11) ### Added diff --git a/docs/source/using-mapreader/step-by-step-guide/4-classify/train.rst b/docs/source/using-mapreader/step-by-step-guide/4-classify/train.rst index 40f8df03..f76ae0ee 100644 --- a/docs/source/using-mapreader/step-by-step-guide/4-classify/train.rst +++ b/docs/source/using-mapreader/step-by-step-guide/4-classify/train.rst @@ -344,25 +344,24 @@ There are a number of options for the ``model`` argument: If you use this option, your optimizer, scheduler and loss function will be loaded from last time. - **4. To load a** `hugging face model `__\ **, choose your model, follow the "Use in Transformers" or "Use in timm" instructions to load it and then pass this as the ``model`` argument.** + **4. To load a** `hugging face model `__\ **, pass the model's repository ID as a string and set ``huggingface=True``.** - e.g. `This model `__ is based on our `*gold standard* dataset `__. - It can be loaded using the `transformers `__ library: + MapReader will automatically download the model and its corresponding image processor from the Hugging Face Hub using the `transformers `__ library. + e.g. `This model `__ is based on our `*gold standard* dataset `__. + It can be loaded directly like this: + .. code-block:: python #EXAMPLE import torch - from transformers import AutoFeatureExtractor, AutoModelForImageClassification - from mapreader import ClassifierContainer - extractor = AutoFeatureExtractor.from_pretrained("davanstrien/autotrain-mapreader-5000-40830105612") - my_model = AutoModelForImageClassification.from_pretrained("davanstrien/autotrain-mapreader-5000-40830105612") + my_model = "davanstrien/autotrain-mapreader-5000-40830105612" device = 'cuda' if torch.cuda.is_available() else 'mps' if torch.backends.mps.is_available() else 'cpu' - my_classifier = ClassifierContainer(my_model, annotated_images.labels_map, dataloaders, device=device) + my_classifier = ClassifierContainer(my_model, annotated_images.labels_map, dataloaders, device=device, huggingface=True) .. note:: You will need to install the `transformers `__ library to do this (``pip install transformers``).