Assignment Overview
In this assignment, you will build a complete Medical Image Classification System for detecting plant diseases from leaf images. This comprehensive project requires you to apply ALL concepts from Module 5: CNN architecture design, data augmentation, transfer learning with pretrained models, model evaluation with metrics and visualizations, and creating production-ready inference pipelines.
TensorFlow 2.x and Keras for model building.
Additional allowed libraries: NumPy, Matplotlib, Seaborn, scikit-learn (for metrics only).
No PyTorch or other deep learning frameworks.
CNN Architecture (5.1)
Convolutional layers, pooling, batch normalization, dropout, and model design
Transfer Learning (5.2)
Pretrained models, feature extraction, fine-tuning strategies
Evaluation & Deployment (5.2)
Confusion matrix, classification report, inference pipeline
The Scenario
AgriTech Solutions - Plant Disease Detection
You have been hired as a Machine Learning Engineer at AgriTech Solutions, a startup developing AI-powered tools for farmers. The CEO has given you this challenge:
"Farmers are losing millions of dollars every year due to plant diseases that go undetected until it's too late. We need an AI system that can analyze photos of plant leaves and instantly tell farmers if their crops are healthy or diseased—and if diseased, what specific disease it is. Can you build this for us using deep learning?"
Your Task
Create a Jupyter Notebook called plant_disease_classifier.ipynb that implements a complete
image classification system. You will build TWO models: a custom CNN from scratch and a transfer learning model
using EfficientNetB0. Your system must achieve at least 85% validation accuracy and include
comprehensive evaluation with visualizations.
Model 1: Custom CNN
Design your own CNN architecture from scratch with at least 3 convolutional blocks, batch normalization, and dropout. Target: 70%+ accuracy.
Model 2: Transfer Learning
Use EfficientNetB0 pretrained on ImageNet with fine-tuning. Implement both feature extraction and fine-tuning phases. Target: 85%+ accuracy.
The Dataset
You will use a subset of the PlantVillage Dataset containing leaf images from 6 classes. Download and organize the data as shown below.
tfds.load('plant_village')
Dataset Structure
Organize your dataset into the following folder structure:
plant_disease_data/
├── train/
│ ├── Tomato_healthy/ # ~1000 images
│ ├── Tomato_Early_blight/ # ~1000 images
│ ├── Tomato_Late_blight/ # ~1000 images
│ ├── Potato_healthy/ # ~150 images
│ ├── Potato_Early_blight/ # ~1000 images
│ └── Potato_Late_blight/ # ~1000 images
├── validation/
│ ├── Tomato_healthy/ # ~200 images
│ ├── Tomato_Early_blight/ # ~200 images
│ ├── Tomato_Late_blight/ # ~200 images
│ ├── Potato_healthy/ # ~50 images
│ ├── Potato_Early_blight/ # ~200 images
│ └── Potato_Late_blight/ # ~200 images
└── test/
├── Tomato_healthy/ # ~100 images
├── Tomato_Early_blight/ # ~100 images
├── Tomato_Late_blight/ # ~100 images
├── Potato_healthy/ # ~25 images
├── Potato_Early_blight/ # ~100 images
└── Potato_Late_blight/ # ~100 images
Dataset Details
- Total Classes: 6 (2 healthy + 4 diseased)
- Image Size: Varies (resize to 224×224)
- Format: JPEG/PNG color images
- Split: ~70% train, ~15% validation, ~15% test
- Class Imbalance: Note that Potato_healthy has fewer samples
Class Labels
| Index | Class Name | Type |
|---|---|---|
| 0 | Potato_Early_blight | Diseased |
| 1 | Potato_Late_blight | Diseased |
| 2 | Potato_healthy | Healthy |
| 3 | Tomato_Early_blight | Diseased |
| 4 | Tomato_Late_blight | Diseased |
| 5 | Tomato_healthy | Healthy |
Requirements
Your plant_disease_classifier.ipynb must implement ALL of the following tasks.
Each task is mandatory and will be evaluated individually.
Data Loading & Exploration
Create functions to load and explore the dataset:
- Use
keras.utils.image_dataset_from_directory()to load train, validation, and test sets - Set
image_size=(224, 224)andbatch_size=32 - Display sample images from each class (at least 2 per class)
- Print class distribution and identify any imbalance
- Apply performance optimization with
cache(),shuffle(), andprefetch()
def load_datasets(data_dir, image_size=(224, 224), batch_size=32):
"""Load train, validation, and test datasets from directory."""
# Must return: train_ds, val_ds, test_ds, class_names
pass
def visualize_samples(dataset, class_names, samples_per_class=2):
"""Display sample images from each class."""
pass
Data Augmentation Pipeline
Create a data augmentation layer using Keras preprocessing layers:
- Must include:
RandomFlip,RandomRotation,RandomZoom - Add at least one more augmentation (contrast, brightness, or translation)
- Visualize augmentation effects on a sample image (show original + 5 augmented versions)
data_augmentation = keras.Sequential([
layers.RandomFlip("horizontal"),
layers.RandomRotation(0.2),
layers.RandomZoom(0.2),
# Add more augmentation layers
], name='data_augmentation')
Model 1: Custom CNN Architecture
Design and build a CNN from scratch:
- Minimum 3 convolutional blocks (Conv2D → BatchNorm → ReLU → MaxPool)
- Progressive filter increase (e.g., 32 → 64 → 128)
- Use
GlobalAveragePooling2Dinstead of Flatten - Include Dropout layers (at least 2) for regularization
- Include the data augmentation layer at the start
- Print model summary showing total and trainable parameters
def create_custom_cnn(input_shape, num_classes, data_augmentation):
"""Build a custom CNN with best practices."""
# Must include: Rescaling, augmentation, 3+ conv blocks,
# BatchNorm, GlobalAveragePooling2D, Dropout
pass
Training Custom CNN with Callbacks
Train the custom CNN with proper configuration:
- Compile with Adam optimizer, appropriate loss, and accuracy metric
- Implement
ModelCheckpointto save best model - Implement
EarlyStoppingwith patience=5 - Implement
ReduceLROnPlateauto reduce learning rate on plateau - Train for maximum 30 epochs
- Handle class imbalance using
class_weightparameter
def compute_class_weights(train_ds, class_names):
"""Compute class weights to handle imbalance."""
pass
callbacks = [
keras.callbacks.ModelCheckpoint(...),
keras.callbacks.EarlyStopping(...),
keras.callbacks.ReduceLROnPlateau(...)
]
Model 2: Transfer Learning with EfficientNetB0
Implement transfer learning with two phases:
- Load EfficientNetB0 with
include_top=Falseandweights='imagenet' - Phase 1 (Feature Extraction): Freeze base model, train only classification head for 10 epochs
- Phase 2 (Fine-tuning): Unfreeze last 20 layers, train with 10x lower learning rate
- Use the EfficientNet preprocessing function
- Target accuracy: 85%+ on validation set
def create_transfer_model(input_shape, num_classes):
"""Create EfficientNetB0 transfer learning model."""
base_model = keras.applications.EfficientNetB0(
input_shape=input_shape,
include_top=False,
weights='imagenet'
)
# Freeze base_model
# Add classification head
pass
def fine_tune_model(model, base_model, train_ds, val_ds, unfreeze_layers=20):
"""Phase 2: Unfreeze top layers and fine-tune."""
pass
Training History Visualization
Create comprehensive training visualizations:
- Plot accuracy curves (train vs validation) for both models
- Plot loss curves (train vs validation) for both models
- Create a comparison chart of both models' final performance
- Use proper labels, legends, and titles
def plot_training_history(history, title="Training History"):
"""Plot accuracy and loss curves."""
# Create 1x2 subplot with accuracy and loss
pass
def compare_models(history_custom, history_transfer):
"""Compare performance of both models."""
pass
Model Evaluation on Test Set
Comprehensive evaluation on the held-out test set:
- Evaluate both models on test set using
model.evaluate() - Generate predictions for all test images
- Create confusion matrix visualization using seaborn heatmap
- Generate classification report with precision, recall, F1-score per class
- Identify which disease classes are most commonly confused
def evaluate_model(model, test_ds, class_names):
"""Full evaluation with confusion matrix and classification report."""
# Get predictions
# Create confusion matrix
# Print classification report
pass
Visualize Misclassifications
Analyze model failures:
- Find and display at least 9 misclassified images
- Show true label, predicted label, and confidence for each
- Identify if there are patterns in misclassifications
- Write a brief analysis (in markdown cell) explaining why certain classes might be confused
def visualize_misclassifications(model, test_ds, class_names, n=9):
"""Display misclassified images with labels and confidence."""
pass
Production Inference Pipeline
Create a deployment-ready prediction function:
- Accept a single image path as input
- Handle image loading, resizing, and preprocessing
- Return top-3 predictions with class names and confidence scores
- Include error handling for invalid image paths
- Demonstrate with 3 sample images (show image + predictions)
def create_prediction_pipeline(model, class_names, image_size=(224, 224)):
"""Create production-ready prediction function."""
def predict(image_path):
# Load and preprocess image
# Get predictions
# Return top 3 results as list of dicts
pass
return predict
# Usage demonstration
predict = create_prediction_pipeline(best_model, class_names)
results = predict('test_leaf.jpg')
print(results) # [{'class': 'Tomato_healthy', 'confidence': 0.95}, ...]
Save Best Model
Export your best performing model:
- Save the best model in Keras format (
.keras) - Print the final test accuracy and model file size
- Write a summary comparing both models in a markdown cell
# Save the best model
best_model.save('plant_disease_model.keras')
print(f"Model saved. File size: {os.path.getsize('plant_disease_model.keras') / 1e6:.2f} MB")
Submission
Create a public GitHub repository with the exact name shown below:
Required Repository Name
plant-disease-classifier
Required Files
plant-disease-classifier/
├── plant_disease_classifier.ipynb # Your main Jupyter Notebook
├── plant_disease_model.keras # Your best saved model
├── requirements.txt # Python dependencies
├── images/
│ ├── confusion_matrix.png # Confusion matrix visualization
│ ├── training_history.png # Training curves
│ ├── sample_predictions.png # Sample prediction results
│ └── augmentation_demo.png # Data augmentation visualization
├── README.md # Required documentation
└── .gitignore # Ignore data folder, checkpoints
README.md Must Include:
- Your full name and submission date
- Project overview and problem statement
- Dataset description and preprocessing steps
- Model architectures (custom CNN and transfer learning)
- Results summary with accuracy comparison table
- Key findings and what you learned
- Instructions to run your notebook
Do Include
- Both models implemented and trained
- All 10 tasks completed in notebook
- Clear markdown explanations between code cells
- All required visualizations saved as images
- Saved model file (.keras format)
- requirements.txt with all dependencies
- README.md with all required sections
Do Not Include
- Dataset images (use .gitignore)
- Model checkpoints during training
- __pycache__ or .ipynb_checkpoints folders
- Virtual environment folders
- Code that doesn't run without errors
- Notebooks with unexecuted cells
Enter your GitHub username - we'll verify your repository automatically
Grading Rubric
Your assignment will be graded on the following criteria (250 points total):
| Criteria | Points | Description |
|---|---|---|
| Data Loading & Augmentation | 30 | Correct dataset loading, visualization, and augmentation pipeline with performance optimization |
| Custom CNN Architecture | 40 | Well-designed architecture with BatchNorm, Dropout, GlobalAveragePooling, achieving 70%+ accuracy |
| Transfer Learning Model | 50 | Correct implementation of feature extraction + fine-tuning phases, achieving 85%+ accuracy |
| Training & Callbacks | 30 | Proper use of callbacks, class weights for imbalance, and training configuration |
| Evaluation & Metrics | 35 | Confusion matrix, classification report, misclassification analysis with insights |
| Visualizations | 25 | Training curves, sample predictions, confusion matrix heatmaps - all properly labeled |
| Inference Pipeline | 20 | Production-ready prediction function with error handling and demonstration |
| Code Quality & Documentation | 20 | Clean code, docstrings, markdown explanations, proper README |
| Total | 250 |
Bonus Points (+25)
Achieve 90%+ test accuracy with either model, or implement Grad-CAM visualization
Passing Score
175+ points (70%) with both models trained and 85%+ transfer learning accuracy
Auto-Fail
Notebook doesn't run, plagiarism detected, or missing required files
Ready to Submit?
Make sure you have completed all requirements and reviewed the grading rubric above.
Submit Your AssignmentWhat You Will Practice
CNN Architecture Design (5.1)
Building convolutional blocks, choosing filter sizes, applying BatchNormalization and Dropout for regularization
Transfer Learning (5.2)
Loading pretrained models, feature extraction vs fine-tuning, learning rate scheduling for fine-tuning
Data Augmentation
Using Keras preprocessing layers, RandomFlip, RandomRotation, RandomZoom, and understanding when augmentation helps
Model Evaluation
Confusion matrix interpretation, precision/recall/F1 metrics, identifying misclassification patterns
Pro Tips
Model Architecture
- Start simple - add complexity only if needed
- Use GlobalAveragePooling2D over Flatten
- Place Dropout AFTER Dense layers, not Conv layers
- BatchNorm goes before or after activation (be consistent)
Transfer Learning
- Always freeze base model first, train head
- Use 10-100x lower learning rate for fine-tuning
- Unfreeze only top layers (last 20-30)
- Use the model's own preprocessing function
Training Tips
- Use callbacks - don't manually stop training
- Monitor validation loss, not training loss
- If overfitting: add more augmentation/dropout
- If underfitting: increase model capacity
Common Mistakes
- Forgetting to set training=False for inference
- Not normalizing images (use Rescaling or preprocess_input)
- Evaluating on training data instead of test data
- High learning rate destroying pretrained weights