A production-ready deep learning system for hierarchical plant disease detection using MobileNetV3 with transfer learning.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β INPUT IMAGE β
βββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββ
β STAGE 1: Plant Classifier β
β (Pre-trained Model) β
β - Apple β
β - Tomato β
β - Potato β
β - Corn β
β - Pepper β
βββββββββββββββ¬ββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββ
β Route to Specific Disease β
β Classifier β
βββββββββββββββ¬ββββββββββββββββ
β
βββββββββββββ΄ββββββββββββ¬ββββββββββββ¬ββββββββββββ¬ββββββββββββ
βΌ βΌ βΌ βΌ βΌ
βββββββββββ βββββββββββ βββββββββββ βββββββββββ βββββββββββ
β Apple β β Tomato β β Potato β β Corn β β Pepper β
β Disease β β Disease β β Disease β β Disease β β Disease β
βClassifierβ βClassifierβ βClassifierβ βClassifierβ βClassifierβ
β(4 class)β β(10 class)β β(3 class)β β(4 class)β β(2 class)β
ββββββ¬βββββ ββββββ¬βββββ ββββββ¬βββββ ββββββ¬βββββ ββββββ¬βββββ
β β β β β
ββββββββββββββββββββββββ΄βββββββββββββ΄βββββββββββββ΄βββββββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β FINAL PREDICTION β
β Plant + Disease β
β + Confidence Scores β
βββββββββββββββββββββββββββ
- Black_rot
- Cedar_apple_rust
- Apple_scab
- healthy
- Bacterial_spot
- Early_blight
- Late_blight
- Leaf_Mold
- Septoria_leaf_spot
- Spider_mites Two-spotted_spider_mite
- Target_Spot
- Tomato_Yellow_Leaf_Curl_Virus
- Tomato_mosaic_virus
- healthy
- Early_blight
- Late_blight
- healthy
- Cercospora_leaf_spot Gray_leaf_spot
- Common_rust
- Northern_Leaf_Blight
- healthy
- Bacterial_spot
- healthy
- Pretrained on: ImageNet
- Input size: 224x224x3
- Parameters: ~5.4M (per model)
- Optimization: Mixed precision training (FP16)
Input (224x224x3)
β
MobileNetV3Large (frozen initially)
β
GlobalAveragePooling2D
β
Dropout(0.3)
β
Dense(256, relu)
β
Dropout(0.3)
β
Dense(num_classes, softmax)
-
Phase 1: Train classifier head (base frozen)
- Epochs: 15
- Learning rate: 0.001.
-
Phase 2: Fine-tune top 30 layers
- Epochs: 15
- Learning rate: 0.0001
| Plant | Classes | Val Accuracy | Parameters |
|---|---|---|---|
| Apple | 4 | ~98% | 5.4M |
| Tomato | 10 | ~95% | 5.4M |
| Potato | 3 | ~99% | 5.4M |
| Corn | 4 | ~97% | 5.4M |
| Pepper | 2 | ~99% | 5.4M |
- Python: Recommended version 3.11 or 3.12. (Note: Python 3.14+ may have compatibility issues with current deep learning libraries).
- Virtual Environment: It is highly recommended to use a virtual environment for dependency isolation.
-
Clone the repository:
git clone <repository_url> cd zali-backend
-
Create and Activate Virtual Environment:
Windows (PowerShell):
python -m venv venv .\venv\Scripts\Activate.ps1Windows (Git Bash / MINGW64):
python -m venv venv source venv/Scripts/activatemacOS / Linux:
python -m venv venv source venv/bin/activateNote for Python 3.14 users on Windows: There is a known bug where venv creation fails with "Unable to copy venvlauncher.exe". If you encounter this, use the venv Python binary directly without activation (see step 2 in Running the Application below).
-
Install Dependencies:
pip install -r app/requirements.txt
-
Navigate to the app directory:
cd app -
Start the FastAPI server (with venv activated):
python -m uvicorn main:app --host 0.0.0.0 --port 8000 --reload
Alternatively, if venv activation fails (Python 3.14 bug), run directly with the venv Python binary:
PowerShell:
..\venv\Scripts\python.exe -m uvicorn main:app --host 0.0.0.0 --port 8000 --reload
Git Bash:
../venv/Scripts/python.exe -m uvicorn main:app --host 0.0.0.0 --port 8000 --reload
The API will now be available at http://localhost:8000. You can access the automatic documentation at http://localhost:8000/docs.
- Framework: FastAPI
- Deep Learning Library: PyTorch (using
.pthmodels) - Computer Vision: PIL (Pillow), Torchvision
- Server: Uvicorn
from inference import HierarchicalPlantDiseaseDetector
detector = HierarchicalPlantDiseaseDetector(
plant_classifier_path='plant_classifier.h5',
disease_models_path='disease_models/'
)
result = detector.predict('path/to/image.jpg')
print(f"Plant: {result['plant']}")
print(f"Disease: {result['disease']}")
print(f"Confidence: {result['disease_confidence']:.2%}")results = detector.predict_batch(['img1.jpg', 'img2.jpg', 'img3.jpg'])
for result in results:
print(f"{result['image_path']}: {result['full_diagnosis']}")# Single image
python inference.py --image test.jpg
# Batch processing
python inference.py --batch ./test_images/ --output results.csv.
βββ hierarchical_plant_disease_detection.ipynb # Main training notebook
βββ inference.py # Standalone inference script
βββ README.md # This file
βββ disease_models/ # Trained models directory
β βββ Apple_disease_classifier.h5
β βββ Apple_class_indices.json
β βββ Tomato_disease_classifier.h5
β βββ Tomato_class_indices.json
β βββ Potato_disease_classifier.h5
β βββ Potato_class_indices.json
β βββ Corn_disease_classifier.h5
β βββ Corn_class_indices.json
β βββ Pepper_disease_classifier.h5
β βββ Pepper_class_indices.json
β βββ system_metadata.json
β βββ model_performance_summary.csv
βββ reorganized_dataset/ # Training data
βββ Apple/
β βββ train/
β βββ val/
βββ Tomato/
βββ Potato/
βββ Corn/
βββ Pepper/
class Config:
IMG_SIZE = (224, 224)
BATCH_SIZE = 32
EPOCHS = 30
LEARNING_RATE = 0.001
VALIDATION_SPLIT = 0.2- Random rotation: Β±15Β°
- Width/height shift: Β±10%
- Zoom: Β±20%
- Horizontal flip: True
- Shear: 0.1
- Brightness: [0.8, 1.2]
- Memory Efficient: Only loads relevant disease model
- Scalable: Easy to add new plants or diseases
- Fast Inference: Lazy loading of models
- Leverages ImageNet pretrained weights
- Fast convergence
- High accuracy with limited data
- 2x faster training on modern GPUs
- Reduced memory footprint
- Maintained accuracy
- Comprehensive error handling
- Batch processing support
- CSV export functionality
- Command-line interface
PlantVillage/
βββ Apple___Black_rot/
βββ Apple___Cedar_apple_rust/
βββ Tomato___Bacterial_spot/
βββ ...
-
EarlyStopping: Prevents overfitting
- Monitor: val_accuracy
- Patience: 5 epochs
-
ReduceLROnPlateau: Adaptive learning rate
- Monitor: val_loss
- Factor: 0.5
- Patience: 3 epochs
-
ModelCheckpoint: Saves best model
- Monitor: val_accuracy
- Save best only
# Flask example
from flask import Flask, request, jsonify
from inference import HierarchicalPlantDiseaseDetector
app = Flask(__name__)
detector = HierarchicalPlantDiseaseDetector(
plant_classifier_path='models/plant_classifier.h5',
disease_models_path='models/disease_models/'
)
@app.route('/predict', methods=['POST'])
def predict():
file = request.files['image']
file.save('temp.jpg')
result = detector.predict('temp.jpg')
return jsonify(result)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)import tensorflow as tf
# Convert to TFLite
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_model = converter.convert()
with open('model.tflite', 'wb') as f:
f.write(tflite_model)import tf2onnx
# Convert to ONNX
spec = (tf.TensorSpec((None, 224, 224, 3), tf.float32, name="input"),)
model_proto, _ = tf2onnx.convert.from_keras(model, input_signature=spec)
with open("model.onnx", "wb") as f:
f.write(model_proto.SerializeToString())FROM tensorflow/tensorflow:latest-gpu
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY inference.py .
COPY disease_models/ disease_models/
COPY plant_classifier.h5 .
EXPOSE 5000
CMD ["python", "api.py"]import unittest
from inference import HierarchicalPlantDiseaseDetector
class TestDetector(unittest.TestCase):
def setUp(self):
self.detector = HierarchicalPlantDiseaseDetector(
plant_classifier_path='plant_classifier.h5',
disease_models_path='disease_models/'
)
def test_single_prediction(self):
result = self.detector.predict('test_image.jpg')
self.assertIn('plant', result)
self.assertIn('disease', result)
self.assertIsInstance(result['disease_confidence'], float)import time
# Measure inference time
images = ['img1.jpg', 'img2.jpg', 'img3.jpg']
start = time.time()
results = detector.predict_batch(images)
elapsed = time.time() - start
print(f"Average inference time: {elapsed/len(images):.3f}s per image"){
"plant": "Tomato",
"plant_confidence": 0.9876,
"disease": "Early_blight",
"disease_confidence": 0.9543,
"full_diagnosis": "Tomato___Early_blight",
"top_predictions": [
{"disease": "Early_blight", "confidence": 0.9543},
{"disease": "Late_blight", "confidence": 0.0321},
{"disease": "healthy", "confidence": 0.0087}
],
"image_path": "path/to/image.jpg"
}Image,Plant,Plant_Confidence,Disease,Disease_Confidence,Full_Diagnosis
img1.jpg,Apple,0.99,Black_rot,0.96,Apple___Black_rot
img2.jpg,Tomato,0.98,Early_blight,0.94,Tomato___Early_blight
img3.jpg,Potato,0.99,healthy,0.97,Potato___healthy-
Why Hierarchical?
- Reduces complexity (5 binary classifiers vs 1 multi-class)
- Better accuracy per plant
- More interpretable predictions
-
Transfer Learning Benefits
- Faster training
- Better generalization
- Requires less data
-
MobileNetV3 Advantages
- Lightweight (5.4M params)
- Fast inference
- Mobile-friendly
Issue: Out of memory during training
# Solution: Reduce batch size
config.BATCH_SIZE = 16 # Instead of 32Issue: Model not loading
# Solution: Use absolute paths
import os
model_path = os.path.abspath('disease_models/Apple_disease_classifier.h5')Issue: Low accuracy on new images
# Solution: Check image preprocessing
# Ensure images are RGB and normalized
img = img.convert('RGB')
img_array = img_array / 255.0from tensorflow.keras.callbacks import TensorBoard
tensorboard = TensorBoard(
log_dir='./logs',
histogram_freq=1,
write_graph=True
)
model.fit(train_gen, callbacks=[tensorboard, ...])tensorboard --logdir=./logsWe welcome contributions! Please follow these guidelines:
- Fork the repository
- Create a feature branch
- Add tests for new features
- Submit a pull request
This project is licensed under the MIT License - see LICENSE file for details.
- PlantVillage dataset creators
- TensorFlow/Keras team
- MobileNetV3 authors
For questions or issues, please open a GitHub issue or contact:
- Email: your.email@example.com
- GitHub: @yourusername
Built with β€οΈ for sustainable agriculture