Multi-source Domain Feature Adaptation Network for Andean Potato Disease Classification
This project implements a Multi-source Domain Feature Adaptation Network (MDFAN) for potato disease classification, specifically designed to address the domain shift between public datasets and real-world Andean field conditions.
- π Multi-source Domain Adaptation: Leverages multiple source domains (PlantVillage, commercial images) to improve generalization
- ποΈ Andean Field Augmentations: Specialized transforms simulating highland lighting conditions
- π― Open-Set Recognition: OOD detection for rejecting unknown disease classes
- β‘ Flexible Backbones: MobileNetV3 (lightweight) and ResNet50 (accuracy) via
timm - π οΈ Modern Tooling:
uvfor fast dependency management,rufffor linting
potato-achis/
βββ src/
β βββ models/
β β βββ model.py # Factory: BaselineModel, MDFAN
β β βββ backbones/ # MobileNet, ResNet (timm)
β β βββ mdfan/ # Domain adaptation components
β β βββ heads/ # Classification heads
β β βββ components/ # GRL, bottleneck
β βββ data/
β β βββ datasets/ # Dataset classes
β β βββ transforms/ # Augmentations (Andean)
β β βββ datamodule.py
β βββ losses/ # MMD, adversarial losses
β βββ utils/ # Metrics, OOD, visualization
β βββ train.py
β βββ eval.py
βββ configs/ # Hydra configs
βββ data/ # Data directory
βββ notebooks/
βββ tests/
βββ pyproject.toml # uv/hatch config
βββ uv.lock # Lockfile
Install uv:
# Linux/macOS
curl -LsSf https://astral.sh/uv/install.sh | sh
# Or with pip
pip install uv# Clone repository
git clone https://github.com/R0SEWT/potato-achis.git
cd potato-achis
# Create environment and install dependencies (uv handles everything)
uv sync
# With optional dependencies
uv sync --extra dev --extra viz --extra tracking --extra onnx
# Or install all extras
uv sync --all-extras# Run training
uv run python src/train.py --model baseline --backbone mobilenet_v3_small
# Run tests
uv run pytest
# Lint and format
uv run ruff check src/
uv run ruff format src/
# Type checking
uv run mypy src/
# Add a new dependency
uv add pandas
# Add a dev dependency
uv add --dev hypothesisBaseline (MobileNet without domain adaptation):
uv run python src/train.py \
--model baseline \
--backbone mobilenet_v3_small \
--data_dir ./data/raw/plantvillage \
--epochs 50 \
--batch_size 32MDFAN (Multi-source Domain Adaptation):
uv run python src/train.py \
--model mdfan \
--backbone resnet50 \
--source_dirs ./data/raw/plantvillage ./data/raw/local_commercial \
--target_dir ./data/raw/andean_field \
--epochs 50 \
--lambda_mmd 1.0 \
--lambda_adv 0.5 \
--lambda_align 0.0W&B tracking (requires optional tracking extra):
uv sync --extra tracking
uv run python src/train.py \
--model mdfan \
--backbone resnet50 \
--source_dirs ./data/raw/plantvillage ./data/raw/local_commercial \
--target_dir ./data/raw/andean_field \
--use_wandbSet WANDB_PROJECT / WANDB_ENTITY env vars as needed.
uv run python src/eval.py \
--checkpoint ./outputs/best_model.pt \
--test_dir ./data/raw/andean_field/test \
--ood_dir ./data/raw/andean_field/ood_classes \
--ood_method entropy \
--visualizeGrad-CAM (requires optional viz extra):
uv sync --extra viz
uv run python src/eval.py \
--checkpoint ./outputs/best_model.pt \
--test_dir ./data/raw/andean_field/test \
--gradcamuv run potato-predict \
--checkpoint ./outputs/exp/best_model.pt \
--input ./some_image.jpg
uv run potato-predict \
--checkpoint ./outputs/exp/best_model.pt \
--input ./some_folder_of_images \
--output ./outputs/predictions.jsonluv sync --extra onnx
uv run potato-export-onnx \
--checkpoint ./outputs/exp/best_model.pt \
--model baseline \
--backbone mobilenet_v3_small
# If your checkpoint was trained with a non-default class count, override it:
# --num_classes <N>| Class | Description |
|---|---|
early_blight |
Alternaria solani |
late_blight |
Phytophthora infestans |
healthy |
No visible disease |
bacterial_wilt |
Ralstonia solanacearum |
virus |
Various viral infections |
OOD Classes (Andean-specific):
frost_damage- High-altitude cold injurynutrient_deficiency- Mineral deficiencies
Input Image
β
βΌ
βββββββββββββββββββββββ
β Shared Backbone β (MobileNetV3 / ResNet50)
βββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββ
β Feature Extractor β (Bottleneck: 2048 β 256)
βββββββββββββββββββββββ
β
ββββββββββββββββββββββββββββββββ
βΌ βΌ
βββββββββββββββββββββββ βββββββββββββββββββββββ
β Domain Discriminatorβ β Source Classifiers β
β + GRL β β β
βββββββββββββββββββββββ βββββββββββββββββββββββ
β β
βΌ βΌ
Domain Loss Classification Loss
β β
βββββββββ¬βββββββββββββββββ
βΌ
Total Loss = L_cls + Ξ»_advΒ·L_domain + Ξ»_mmdΒ·L_mmd
# Environment info
uv python list # List available Python versions
uv venv --python 3.11 # Create venv with specific Python
# Dependencies
uv add torch --index pytorch # Add from specific index
uv remove pandas # Remove dependency
uv lock # Update lockfile
uv tree # Show dependency tree
# Running
uv run pytest -v # Run tests
uv run python -m src.train # Run as module
uv run jupyter lab # Start Jupyter (with notebooks extra)
# Build
uv build # Build wheel/sdist| Model | Source Acc | Target Acc | OOD AUROC |
|---|---|---|---|
| Baseline (MobileNet) | ~95% | ~70% | ~75% |
| Baseline (ResNet50) | ~97% | ~75% | ~78% |
| MDFAN (ResNet50) | ~95% | ~85% | ~85% |
- Baseline MobileNet/ResNet
- MDFAN with GRL + MMD
- OOD detection (MSP, entropy, energy)
- Andean field augmentations
- uv package management
- Classifier alignment (Stage 2)
- Grad-CAM visualization
- W&B integration
- ONNX export
Detailed roadmap: see docs/roadmap.md
@software{potato_achis_2025,
author = {R0SEWT, Nakato156},
title = {Potato-ACHIS: Multi-source Domain Adaptation for Andean Potato Disease Classification},
year = {2025},
url = {https://github.com/R0SEWT/potato-achis}
}Apache License 2.0 - see LICENSE