| | --- |
| | title: Animal Image Classification Using InceptionV3 |
| | emoji: π |
| | colorFrom: blue |
| | colorTo: red |
| | sdk: gradio |
| | sdk_version: 6.5.1 |
| | app_file: app.py |
| | pinned: false |
| | license: mit |
| | short_description: InceptionV3-based animal image classifier with data cleaning |
| | models: |
| | - AIOmarRehan/Animal-Image-Classification-Using-CNN |
| | datasets: |
| | - AIOmarRehan/AnimalsDataset |
| | --- |
| | |
| | [If you would like a detailed explanation of this project, please refer to the Medium article below.](https://medium.com/@ai.omar.rehan/building-a-clean-reliable-and-accurate-animal-classifier-using-inceptionv3-175f30fbe6f3) |
| |
|
| | --- |
| | # Animal Image Classification Using InceptionV3 |
| |
|
| | *A complete end-to-end pipeline for building a clean, reliable deep-learning classifier.* |
| |
|
| | This project implements a **full deep-learning workflow** for classifying animal images using **TensorFlow + InceptionV3**, with a major focus on **dataset validation and cleaning**. Before training the model, I built a comprehensive system to detect corrupted images, duplicates, brightness/contrast issues, mislabeled samples, and resolution outliers. |
| |
|
| | This repository contains the full pipelineβfrom dataset extraction to evaluation and model saving. |
| |
|
| | --- |
| |
|
| | ## Features |
| |
|
| | ### Full Dataset Validation |
| |
|
| | The project includes automated checks for: |
| |
|
| | * Corrupted or unreadable images |
| | * Hash-based duplicate detection |
| | * Duplicate filenames |
| | * Misplaced or incorrectly labeled images |
| | * File naming inconsistencies |
| | * Extremely dark/bright images |
| | * Very low-contrast (blank) images |
| | * Outlier resolutions |
| |
|
| | ### Preprocessing & Augmentation |
| |
|
| | * Resize to 256Γ256 |
| | * Normalization |
| | * Light augmentation (probabilistic) |
| | * Efficient `tf.data` pipeline with caching, shuffling, prefetching |
| |
|
| | ### Transfer Learning with InceptionV3 |
| |
|
| | * Pretrained ImageNet weights |
| | * Frozen base model |
| | * Custom classification head (GAP β Dense β Dropout β Softmax) |
| | * EarlyStopping + ModelCheckpoint + ReduceLROnPlateau callbacks |
| |
|
| | ### Clean & Reproducible Training |
| |
|
| | * 80% training |
| | * 10% validation |
| | * 10% test |
| | * High stability due to dataset cleaning |
| |
|
| | --- |
| |
|
| | ## 1. Dataset Extraction |
| |
|
| | The dataset is stored as a ZIP file (Google Drive). After mounting the drive, it is extracted and indexed into a Pandas DataFrame: |
| |
|
| | ```python |
| | drive.mount('/content/drive') |
| | |
| | zip_path = '/content/drive/MyDrive/Animals.zip' |
| | extract_to = '/content/my_data' |
| | |
| | with zipfile.ZipFile(zip_path, 'r') as zip_ref: |
| | zip_ref.extractall(extract_to) |
| | ``` |
| |
|
| | Each image entry records: |
| |
|
| | * Class |
| | * Filename |
| | * Full path |
| |
|
| | --- |
| |
|
| | ## 2. Dataset Exploration |
| |
|
| | Before any training, I analyzed: |
| |
|
| | * Class distribution |
| | * Image dimensions |
| | * Grayscale vs RGB |
| | * Unique sizes |
| | * Folder structures |
| |
|
| | Example class-count visualization: |
| |
|
| | ```python |
| | plt.figure(figsize=(32, 16)) |
| | class_count.plot(kind='bar') |
| | ``` |
| |
|
| | This revealed imbalance and inconsistent image sizes early. |
| |
|
| | --- |
| |
|
| | ## 3. Visual Sanity Checks |
| |
|
| | Random images were displayed with their brightness, contrast, and shape to manually confirm dataset quality. |
| |
|
| | This step prevents hidden issuesβespecially in community-created or scraped datasets. |
| |
|
| | --- |
| |
|
| | ## 4. Data Quality Detection |
| |
|
| | The system checks for: |
| |
|
| | ### Duplicate Images (Using MD5 Hashing) |
| |
|
| | ```python |
| | def get_hash(path): |
| | with open(path, 'rb') as f: |
| | return hashlib.md5(f.read()).hexdigest() |
| | |
| | df['file_hash'] = df['full_path'].apply(get_hash) |
| | duplicate_hashes = df[df.duplicated('file_hash', keep=False)] |
| | ``` |
| |
|
| | ### Corrupted Files |
| |
|
| | ```python |
| | try: |
| | with Image.open(file_path) as img: |
| | img.verify() |
| | except: |
| | corrupted_files.append(file_path) |
| | ``` |
| |
|
| | ### Brightness/Contrast Outliers |
| |
|
| | Using PILβs `ImageStat` to detect very dark/bright samples. |
| |
|
| | ### Label Consistency Check |
| |
|
| | ```python |
| | folder = os.path.basename(os.path.dirname(row["full_path"])) |
| | ``` |
| |
|
| | This catches mislabeled entries where folder name β actual class. |
| |
|
| | --- |
| |
|
| | ## 5. Preprocessing Pipeline |
| |
|
| | Custom preprocessing: |
| |
|
| | * Resize β Normalize |
| | * Optional augmentation |
| | * Efficient `tf.data` batching |
| |
|
| | ```python |
| | def preprocess_image(path, target_size=(256, 256), augment=True): |
| | img = tf.image.decode_image(...) |
| | img = tf.image.resize(img, target_size) |
| | img = img / 255.0 |
| | ``` |
| |
|
| | Split structure: |
| |
|
| | | Split | Percent | |
| | | ---------- | ------- | |
| | | Train | 80% | |
| | | Validation | 10% | |
| | | Test | 10% | |
| |
|
| | --- |
| |
|
| | ## 6. Model β Transfer Learning with InceptionV3 |
| |
|
| | The model is built using **InceptionV3 pretrained on ImageNet** as a feature extractor. |
| |
|
| | ```python |
| | inception = InceptionV3( |
| | input_shape=input_shape, |
| | weights="imagenet", |
| | include_top=False |
| | ) |
| | ``` |
| |
|
| | At first, **all backbone layers are frozen** to preserve pretrained representations: |
| |
|
| | ```python |
| | for layer in inception.layers: |
| | layer.trainable = False |
| | ``` |
| |
|
| | A custom classification head is added: |
| |
|
| | * GlobalAveragePooling2D |
| | * Dense(512, ReLU) |
| | * Dropout(0.5) |
| | * Dense(N, Softmax) β where *N = number of classes* |
| |
|
| | This setup allows the model to learn dataset-specific patterns while avoiding overfitting during early training. |
| |
|
| | --- |
| |
|
| | ## 7. Initial Training (Frozen Backbone "Feature Extraction") |
| |
|
| | The model is compiled using: |
| |
|
| | * **Loss**: `sparse_categorical_crossentropy` |
| | * **Optimizer**: Adam |
| | * **Metric**: Accuracy |
| |
|
| | Training is performed with callbacks to improve stability: |
| |
|
| | * **EarlyStopping** (restore best weights) |
| | * **ModelCheckpoint** (save best model) |
| | * **ReduceLROnPlateau** |
| |
|
| | ```python |
| | history = model.fit( |
| | train_ds, |
| | validation_data=val_ds, |
| | epochs=5, |
| | callbacks=callbacks |
| | ) |
| | ``` |
| |
|
| | This stage allows the new classification head to converge while keeping the pretrained backbone intact. |
| |
|
| | --- |
| |
|
| | ## 8. Fine-Tuning the InceptionV3 Backbone |
| |
|
| | After the initial convergence, **fine-tuning is applied** to improve performance. |
| |
|
| | The **last 30 layers** of InceptionV3 are unfrozen: |
| |
|
| | The model is then recompiled and trained again: |
| |
|
| | ```python |
| | history = model.fit( |
| | train_ds, |
| | validation_data=val_ds, |
| | epochs=10, |
| | callbacks=callbacks |
| | ) |
| | ``` |
| |
|
| | Fine-tuning allows higher-level convolutional filters to adapt to the animal dataset, resulting in better class separation and generalization. |
| |
|
| | --- |
| |
|
| | ## 9. Model Evaluation |
| |
|
| | The final model is evaluated on a **held-out test set**. |
| |
|
| | ### Accuracy & Loss Curves |
| |
|
| | Training and validation curves are plotted to monitor: |
| |
|
| | * Convergence behavior |
| | * Overfitting |
| | * Generalization stability |
| |
|
| | These plots confirm that fine-tuning improves validation performance without introducing instability. |
| |
|
| |  |
| |
|
| | --- |
| |
|
| | ### Confusion Matrix |
| |
|
| | A confusion matrix is computed to visualize class-level performance: |
| |
|
| | * Highlights misclassification patterns |
| | * Reveals class confusion (e.g., visually similar animals) |
| |
|
| | Both annotated and heatmap-style confusion matrices are generated. |
| |
|
| |  |
| |
|
| | --- |
| |
|
| | ### Classification Metrics |
| |
|
| | The following metrics are computed on the test set: |
| |
|
| | * **Accuracy** |
| | * **Precision (macro)** |
| | * **Recall (macro)** |
| | * **F1-score (macro)** |
| |
|
| | A detailed **per-class classification report** is also produced: |
| |
|
| | * Precision |
| | * Recall |
| | * F1-score |
| | * Support |
| |
|
| | This provides a deeper understanding beyond accuracy alone. |
| |
|
| | ``` |
| | 10/10 ββββββββββββββββββββ 1s 106ms/step - accuracy: 0.9826 - loss: 0.3082 - Test Accuracy: 0.9900 |
| | 10/10 ββββββββββββββββββββ 1s 93ms/step |
| | |
| | Classification Report: |
| | precision recall f1-score support |
| | |
| | cats 0.99 0.97 0.98 100 |
| | dogs 0.97 0.99 0.98 100 |
| | snakes 1.00 1.00 1.00 100 |
| | |
| | accuracy 0.99 300 |
| | macro avg 0.99 0.99 0.99 300 |
| | weighted avg 0.99 0.99 0.99 300 |
| | ``` |
| |
|
| | --- |
| |
|
| | ### ROC Curves (Multi-Class) |
| |
|
| | To further evaluate model discrimination: |
| |
|
| | * One-vs-Rest ROC curves are generated per class |
| | * A **macro-average ROC curve** is computed |
| | * AUC is reported for overall performance |
| |
|
| | These curves demonstrate strong separability across all classes. |
| |
|
| |  |
| |
|
| | --- |
| |
|
| | ## 10. Final Model |
| |
|
| | The best-performing model (after fine-tuning) is saved and later used for deployment: |
| |
|
| | ```python |
| | model.save("Inception_V3_Animals_Classification.h5") |
| | ``` |
| |
|
| | This trained model is deployed using **FastAPI + Docker** for inference and **Gradio on Hugging Face Spaces** for public interaction. |
| |
|
| | --- |
| |
|
| | ## Updated Key Takeaways |
| |
|
| | > **Clean data enables strong fine-tuning.** |
| |
|
| | By combining: |
| |
|
| | * Rigorous dataset validation |
| | * Transfer learning |
| | * Selective fine-tuning |
| | * Comprehensive evaluation |
| |
|
| | the model achieves **high accuracy, stable convergence, and reliable real-world performance**. |
| |
|
| | Fine-tuning only a subset of pretrained layers strikes the optimal balance between **generalization and specialization**. |
| |
|
| | --- |