0tokens

Apply for AI Grants India

Financial support for innovators building the future of AI in India.

Apply now

Chat · how to build image classifiers in python

How to Build Image Classifiers in Python: A Production Guide

  1. aigi

    Image classification turns pixels into a decision: crop disease or healthy crop, acceptable product or defect, document type A or B. For Indian teams, the hard part is rarely writing a few Keras layers. It is collecting representative images, preventing leakage, choosing the right error metric, and shipping a model that performs under changing light, devices, languages, and network conditions.

    This guide shows how to build image classifiers in Python using TensorFlow and Keras. The same workflow applies to PyTorch, but the examples use Keras because it provides a fast path from experiment to TensorFlow Lite deployment.

    Start with the decision, not the model

    Define the operational decision before selecting an architecture. A classifier may need to:

    • Assign exactly one class to every image (single-label multiclass).
    • Detect several attributes in one image (multilabel).
    • Decide between two outcomes (binary classification).
    • Reject uncertain or unfamiliar images instead of forcing a class.

    Write down the cost of each error. In a quality-control line, a false negative may allow a defective part through; in a screening workflow, a false negative may require human review rather than an automated diagnosis. This determines whether you optimise recall, precision, balanced accuracy, or a class-specific threshold.

    For broader computer-vision workflows, compare this classification pipeline with the approaches described in how to build computer vision models on GitHub. Classification is appropriate only when the entire image, rather than the location of an object, determines the label.

    Build a trustworthy dataset

    A small, clean dataset is more valuable than a large collection of duplicated or badly labelled images. Create a label specification that includes inclusion rules, exclusions, borderline examples, and the intended use of each class.

    Collect variation that the model will face in production:

    • Phones and cameras from different price bands.
    • Indoor, outdoor, low-light, and harsh-shadow conditions.
    • Different backgrounds, orientations, distances, and image quality.
    • Regional variation in crops, packaging, roads, uniforms, or equipment.
    • Images from the same users, locations, or devices that may create hidden correlations.

    Split data by source, not just by random image. If near-identical frames from one video appear in both training and validation sets, the reported score will be misleading. A useful starting point is 70% training, 15% validation, and 15% test data, with the test set locked until final evaluation.

    Keep an audit trail for label changes, dataset versions, and consent or licensing. This matters when images contain people, health information, customer documents, or farm locations.

    Set up the Python project

    Use a virtual environment and pin dependencies so experiments can be reproduced. A minimal TensorFlow setup is:

    python -m venv .venv
    source .venv/bin/activate       # Windows: .venv\\Scripts\\activate
    python -m pip install --upgrade pip
    pip install tensorflow scikit-learn matplotlib pandas pillow

    Use a project structure that separates data, training code, evaluation, and exported models:

    image-classifier/
    ├── data/
    ├── src/
    │   ├── train.py
    │   ├── evaluate.py
    │   └── export.py
    ├── models/
    └── requirements.txt

    Do not commit customer images, credentials, or large model files to Git. Store dataset manifests and checksums instead.

    Create a baseline with TensorFlow

    For a directory organised by class, image_dataset_from_directory handles labels and batching:

    import tensorflow as tf
    
    IMG_SIZE = (224, 224)
    BATCH_SIZE = 32
    SEED = 42
    
    train_ds = tf.keras.utils.image_dataset_from_directory(
        "data/train", image_size=IMG_SIZE, batch_size=BATCH_SIZE,
        seed=SEED, label_mode="int"
    )
    val_ds = tf.keras.utils.image_dataset_from_directory(
        "data/val", image_size=IMG_SIZE, batch_size=BATCH_SIZE,
        seed=SEED, label_mode="int"
    )
    
    normalise = tf.keras.layers.Rescaling(1./255)
    train_ds = train_ds.map(lambda x, y: (normalise(x), y)).prefetch(tf.data.AUTOTUNE)
    val_ds = val_ds.map(lambda x, y: (normalise(x), y)).prefetch(tf.data.AUTOTUNE)

    A small CNN is useful as a sanity check. It can reveal label problems and pipeline bugs before you spend compute on a larger model:

    model = tf.keras.Sequential([
        tf.keras.Input(shape=(*IMG_SIZE, 3)),
        tf.keras.layers.Conv2D(32, 3, activation="relu"),
        tf.keras.layers.MaxPooling2D(),
        tf.keras.layers.Conv2D(64, 3, activation="relu"),
        tf.keras.layers.MaxPooling2D(),
        tf.keras.layers.GlobalAveragePooling2D(),
        tf.keras.layers.Dense(128, activation="relu"),
        tf.keras.layers.Dense(len(train_ds.class_names), activation="softmax")
    ])
    
    model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])

    Train with checkpoints and early stopping rather than assuming a fixed epoch count:

    callbacks = [
        tf.keras.callbacks.ModelCheckpoint("models/best.keras", save_best_only=True,
                                           monitor="val_loss"),
        tf.keras.callbacks.EarlyStopping(patience=5, restore_best_weights=True)
    ]
    model.fit(train_ds, validation_data=val_ds, epochs=30, callbacks=callbacks)

    Prefer transfer learning for most products

    Training from scratch makes sense for educational datasets or very large, domain-specific collections. For most startup prototypes, use a pretrained backbone such as MobileNetV3, EfficientNet, or ResNet. MobileNet is a strong choice when inference must run on an Android phone, a low-cost device, or an edge gateway.

    base = tf.keras.applications.MobileNetV3Small(
        input_shape=(*IMG_SIZE, 3), include_top=False, weights="imagenet"
    )
    base.trainable = False
    
    inputs = tf.keras.Input(shape=(*IMG_SIZE, 3))
    x = tf.keras.layers.RandomFlip("horizontal")(inputs)
    x = tf.keras.layers.RandomRotation(0.08)(x)
    x = base(x, training=False)
    x = tf.keras.layers.GlobalAveragePooling2D()(x)
    x = tf.keras.layers.Dropout(0.2)(x)
    outputs = tf.keras.layers.Dense(len(train_ds.class_names), activation="softmax")(x)
    model = tf.keras.Model(inputs, outputs)
    model.compile(optimizer=tf.keras.optimizers.Adam(1e-3),
                  loss="sparse_categorical_crossentropy", metrics=["accuracy"])

    After the classifier head stabilises, unfreeze only the final backbone layers and fine-tune with a learning rate such as 1e-5. Keep batch-normalisation behaviour controlled by calling the backbone with training=False unless you have enough data and a deliberate reason to change it.

    Use augmentation carefully

    Augmentation should represent plausible production variation, not invent impossible examples. Horizontal flips may be unsafe when text, road signs, medical orientation, or left-right anatomy matters. Strong crops can remove the evidence needed for the label.

    Useful options include modest rotation, translation, contrast, brightness, and zoom. Apply augmentation only to training data. Keep validation and test images untouched so their scores reflect deployment conditions.

    Class imbalance needs more than augmentation. Inspect per-class counts and use class weights, targeted collection, or a balanced sampler. Never manufacture confidence with duplicate oversampling alone.

    Evaluate errors, not just accuracy

    Report a confusion matrix and per-class precision, recall, and F1. Use scikit-learn for a detailed report:

    from sklearn.metrics import classification_report
    import numpy as np
    
    true_labels, predicted_labels = [], []
    for images, labels in val_ds:
        probabilities = model.predict(images, verbose=0)
        true_labels.extend(labels.numpy())
        predicted_labels.extend(np.argmax(probabilities, axis=1))
    
    print(classification_report(true_labels, predicted_labels,
                                target_names=train_ds.class_names))

    Review false positives and false negatives manually. Look for shortcuts such as a watermark, background, camera type, or collection site. Test on a temporal holdout and, where relevant, separate Indian regions, languages, devices, or customer sites. For safety-sensitive use cases, add an abstain threshold that routes low-confidence predictions to a person.

    Track calibration as well as ranking quality. A prediction of 0.95 should be reliable if your product uses confidence to trigger an automated action. Temperature scaling or a validation-based threshold can improve this behaviour.

    Export and deploy responsibly

    Save the class order alongside the model. A correct neural network with a mismatched label map is still a production failure. Record image size, colour format, normalisation, preprocessing version, and model hash.

    For mobile or edge deployment, convert to TensorFlow Lite and measure accuracy after conversion. Float16 or integer quantisation can reduce size and latency, but representative calibration images are important for int8 quantisation. Benchmark on the actual target device rather than a development laptop.

    A production service should include input validation, maximum image size limits, structured logs, latency metrics, model-version tags, and a rollback path. Monitor confidence and class distribution for drift. If the camera, crop variety, packaging, or lighting changes, schedule relabelling and retraining instead of silently trusting old scores.

    Teams building several AI components may also need an orchestration layer; the design concerns overlap with building distributed systems with AI agents, especially around observability, retries, and versioned services. But keep the classifier itself deterministic and easy to test.

    A practical build sequence

    1. Define labels, error costs, and an abstain policy.
    2. Collect and split data by source; document consent and provenance.
    3. Build a tiny CNN baseline and verify the pipeline.
    4. Train a pretrained backbone with realistic augmentation.
    5. Inspect per-class errors and test on a locked, representative set.
    6. Fine-tune, calibrate thresholds, and compare against a human baseline.
    7. Export to the target runtime and benchmark latency, memory, and accuracy.
    8. Launch with monitoring, feedback capture, and a retraining schedule.

    For open-source workflows, study Indian student developers building open source AI for practical collaboration and publishing patterns. If your computer-vision prototype addresses a meaningful Indian problem, AI Grants India can help you move from a validated model to a fundable product.

    Last updated 23 September 2026

AIGI may be inaccurate. Replies seeded from the guide above.