Building and Deploying an Image Classifier: Doors vs Windows

Krupa SawantKrupa Sawant
7 min read

In this post, I share how I built my first deep learning project—a simple door vs window image classifier—from collecting data to training a model and finally deploying it online with Gradio and Hugging Face Spaces.

It was my first time experiencing the full end‑to‑end cycle:

  • Collecting and downloading images

  • Training a model

  • Testing it

  • And deploying it as an interactive web app

Tools and Libraries Used

Before setting up the environment, here’s a quick look at the tools I used for this project:

  • Python 3.10 – I specifically chose Python 3.10 because some libraries (like fastai) did not yet support 3.11 or higher on Windows.

  • Jupyter Notebook – An interactive coding environment for writing and running code step by step.

  • Fastai – High‑level deep learning tools built on top of PyTorch that make it easy and fast to train and fine‑tune models (I used it here to work with a pre‑trained model).

  • ResNet34 – A popular convolutional neural network architecture, pre‑trained on ImageNet, that served as the backbone for my classifier.

  • DuckDuckGo Search API – Used to automatically download images for the dataset (doors and windows) directly from the web.

  • Gradio – A Python library for creating simple web interfaces to interact with models.

  • Hugging Face Spaces – A free hosting platform where I deployed my trained model with a Gradio interface.

Setting Up the Environment

Before starting with the code, here’s what I did to set up my system on Windows:

  1. Installed Python 3.10
    Downloaded Python from python.org and made sure it worked from the command line.

  2. Added Python and Pip to PATH
    Using Windows PowerShell, I added environment variables so that python and pip could be run anywhere.

  3. Installed Jupyter Notebook

     pip install notebook
     jupyter notebook
    

    This launched Jupyter in my browser, where I wrote and ran all my code step by step.

Notebook Steps

1. Install dependencies

!pip install -q fastai duckduckgo-search requests pillow
import os

2 .Download images

from duckduckgo_search import DDGS
import requests
from pathlib import Path
from PIL import Image
from io import BytesIO

# Configure
categories = ["door", "window"]
output_dir = Path("house")
output_dir.mkdir(exist_ok=True)

ddgs = DDGS()

def download_images(query, max_images=20):
    category_dir = output_dir / query
    category_dir.mkdir(exist_ok=True)
    count = 0
    for result in ddgs.images(query, max_results=max_images):
        url = result["image"]
        try:
            resp = requests.get(url, timeout=10)
            resp.raise_for_status()
            img = Image.open(BytesIO(resp.content)).convert("RGB")
            img.save(category_dir / f"{query}_{count}.jpg")
            count += 1
            print(f"Saved: {query}_{count}.jpg")
        except Exception as e:
            print(f"Failed {url} -> {e}")

for cat in categories:
    download_images(cat, max_images=30)
  • Creates a folder called house

  • Downloads ~30 images each for doors and windows using DuckDuckGo image search

Saves them into house/door and house/window folders

3.Remove broken images

from fastai.vision.all import verify_images, get_image_files
failed = verify_images(get_image_files(base_path))
failed.map(Path.unlink)  # Deletes them

This uses fastai.verify_images to remove corrupted images that can’t be opened.

4.Build and train the model

from fastai.vision.all import *
from pathlib import Path
import pathlib

pathlib.PosixPath = pathlib.WindowsPath

# Use relative path (no C:/... absolute path)
dls = ImageDataLoaders.from_folder(
    Path('house'),
    valid_pct=0.1,
    item_tfms=Resize(224),
    bs=8
)

learn = vision_learner(dls, resnet34, metrics=accuracy)
learn.fine_tune(5)

This is the core training step:

  1. Loads your dataset (with 10% used for validation)

  2. Uses resnet34 (a pre-trained convolutional neural network)

  3. Fine-tunes it for 5 epochs to classify images as door or window


5. Test the model on a new image

from fastai.vision.all import *

img = PILImage.create('house_test/test4.jpg')
pred_class, pred_idx, probs = learn.predict(img)
print(f"Prediction: {pred_class}, Confidence: {probs[pred_idx]:.2f}")

This loads a new image and prints the predicted class (door or window) with confidence.

6.Save the trained model (weights only)

# Save only the trained model weights
learn.save('stage-1')
print("Saved model weights as stage-1.pth")

Normally, learn.export() is the common way to save a Fastai model.
It creates a .pkl file that bundles:

  • The model architecture

  • The trained weights

  • The preprocessing steps

so you can directly load it anywhere with load_learner().

However, when I tried to deploy on Hugging Face,
I kept hitting Windows path errors caused by the .pkl.
To avoid these issues, I skipped export entirely and instead used:

  • learn.save('stage-1'), which only stores the weights (stage-1.pth)

  • During deployment, I recreate the learner architecture in app.py and then load these weights instead.

After Training – Preparing for Deployment

Once training is done you will see a models/ folder created automatically by fastai.
Inside it, you now have:

models/
    stage-1.pth

This stage-1.pth file contains the trained weights of your model.
With this file ready, we can now move on to building a simple web app so we can interact with the model visually and prepare it for deployment.

Creating a Web App with Gradio

What is Gradio?
Gradio is a Python library that makes it easy to wrap any machine learning model in a web-based interface.It allows you to:

  • Upload an image (or other data)

  • Get predictions instantly

  • Use the same interface locally or on Hugging Face Spaces for public access


Installing Gradio

Before creating the app, make sure Gradio is installed.
If you already have fastai and torch installed from the training steps, simply run:

pip install gradio

Project Structure

We’ll organize our files so it works both locally and when deployed to Hugging Face:

bashCopyEditmy_app/
│
├── app.py            # Gradio app
├── requirements.txt  # Dependencies list
└── models/
    └── stage-1.pth   # The trained model weights
  • app.py: Loads the model weights and launches the Gradio interface.

  • requirements.txt: Will contain the list of libraries Hugging Face needs to install (fastai, gradio, torch, torchvision).

  • models: Folder where your stage-1.pth from training goes.

Understanding app.py (Gradio Interface)

The app.py script does four main things:

  1. Rebuilds a minimal DataLoaders and Learner
    Since we only saved weights (stage-1.pth), the code first creates a dummy DataLoaders object with the same class labels (['door', 'window']) and architecture (resnet34), then loads the saved weights:

     pythonCopyEditdls.vocab = ['door','window']
     learn = vision_learner(dls, resnet34, metrics=accuracy, loss_func=CrossEntropyLossFlat())
     learn.load('stage-1')
    
  2. Defines a predict function
    This function takes an uploaded image, resizes it, converts it to a tensor, runs it through the model, and returns the predicted label with confidence.

  3. Creates a Gradio interface

     pythonCopyEditgr.Interface(
         fn=predict,
         inputs=gr.Image(type="pil"),
         outputs=gr.Label(),
         title="Door vs Window Classifier"
     ).launch()
    
  4. Launches a local web app
    Running python app.py will start a local Gradio server with a browser link where you can test predictions interactively.

Deploying to Hugging Face Spaces

After confirming that the Gradio app runs locally, the next step is to make it available online so anyone can try it instantly.
For this, I used Hugging Face Spaces – a free service that hosts machine learning demos and automatically runs your Gradio app.


Prerequisites

Before deploying, make sure:

  • Git is installed on your local machine (or use GitHub Desktop).

  • You have a Hugging Face account.

  • (Optional but recommended) Set up SSH keys so you can push to Hugging Face without typing your password every time:

    • Go to your Hugging Face account → Settings → Access Tokens / SSH Keys

    • Add your public SSH key (generated using ssh-keygen).

Steps to Deploy

  1. Create a new Space

    • Go to Hugging Face Spaces

    • Click Create new Space, give it a name, choose Gradio as the SDK, and pick public/private.

  2. Clone the Space
    Copy the Git URL from the Space page and run:

     git clone https://huggingface.co/spaces/<username>/<space_name>
    

    or, if using SSH:

     git clone git@hf.co:spaces/<username>/<space_name>
    
  3. Copy your app files
    Into the cloned folder, copy:

     app.py
     requirements.txt
     models/stage-1.pth
    
  4. Commit and push

     git add .
     git commit -m "Initial commit"
     git push
    
  5. Au**tomatic build and launch**
    Hugging Face will install the requirements, build your Space, and launch the Gradio app.
    After a few minutes, your project will be live at a shareable URL.

Key Learnings

  • Collecting a small dataset from the web

  • Fine‑tuning a pre‑trained ResNet34 with fastai

  • Saving model weights (.pth) for portability

  • Building a Gradio interface

  • Deploying on Hugging Face Spaces

Conclusion

This project took me end‑to‑end: from images to a live AI app.
What started as a simple “door vs window” idea became a great lesson in training, debugging, saving, and deployment.

Try the live demo here:
Door vs Window Classifier

0
Subscribe to my newsletter

Read articles from Krupa Sawant directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Krupa Sawant
Krupa Sawant