""" Configuration for ML training and inference pipeline. """ import os from pathlib import Path from typing import Dict, List # NOTE: the old CROPINTEL_SOYBEAN_HEALTHY_DIRS / Mendeley-Healthy injection was # removed. Mixing Healthy from a different source than the disease images made # the model detect the image source instead of the disease (fake 100% accuracy). # Soybean now trains on a single-acquisition dataset (see CROPS["soybean"]). # Base paths BASE_DIR = Path(__file__).parent DATA_DIR = BASE_DIR / "data" MODELS_DIR = BASE_DIR / "models" TRAINING_DIR = BASE_DIR / "training" # Create directories if they don't exist DATA_DIR.mkdir(exist_ok=True) MODELS_DIR.mkdir(exist_ok=True) TRAINING_DIR.mkdir(exist_ok=True) # Crop configurations # Each crop uses four classes: three high-volume diseases + Healthy (see loader + supplemental/). # Optional extra images: place folders under ml/data//supplemental/ that match class names, or run # python -m ml.scripts.download_datasets --supplemental --crop [--dataset user/slug] # If supplemental_dataset_name is set below, --supplemental uses it as the default slug. CROPS = { "corn": { "dataset_name": "smaranjitghose/corn-or-maize-leaf-disease-dataset", "diseases": [ "Common Rust", "Gray Leaf Spot", "Blight", "Healthy", ], "supplemental_dataset_name": None, "image_size": (224, 224), }, "soybean": { # Single-acquisition dataset (healthy + diseases from one camera program). # The previous mix (sivm205 diseases + Mendeley Healthy) taught the model # to detect the image SOURCE, not the disease — fake 100% test accuracy. "dataset_name": "vaishaligbhujade/soybean-leaf-dataset-for-disease-classification", "diseases": [ "Rust", "Frogeye Leaf Spot", "Bacterial Pustule", "Target Leaf Spot", "Yellow Mosaic", "Sudden Death Syndrome", "Healthy", ], "supplemental_dataset_name": None, "image_size": (224, 224), }, "wheat": { "dataset_name": "kushagra3204/wheat-plant-diseases", # Expanded 2026-06-10 from 4 → 8 classes (all ≥576 imgs in the dataset). # The three rusts + mildew + healthy, plus Septoria, Loose Smut, and # Fusarium Head Blight (high-impact field diseases). "diseases": [ "Stripe (Yellow) Rust", "Leaf Rust", "Stem Rust", "Powdery Mildew", "Septoria", "Loose Smut", "Fusarium Head Blight", "Healthy", ], "supplemental_dataset_name": None, "image_size": (224, 224), }, "rice": { "dataset_name": "anshulm257/rice-disease-dataset", # supplemental/: Paddy Doctor field images (imbikramsaha/paddy-doctor) — # added after the v1 model scored 0.6% on external field photos (it # predicted "Healthy" for nearly everything outside the lab-style # training distribution). "diseases": [ "Rice Blast", "Bacterial Leaf Blight", "Brown Spot", "Healthy", ], # Brown Spot and Rice Blast lesions are visually inseparable on white- # background field leaves (Dhan-Shomadhan), so a 4-class model confidently # mislabels Brown Spot as Blast (29.6% recall). Collapse them into one # honest "fungal leaf lesion" class — both folders still load, but train # under one label. See [[rice-data-lever-exhausted]]. "label_aliases": { "Rice Blast": "Blast or Brown Spot", "Brown Spot": "Blast or Brown Spot", }, "supplemental_dataset_name": "imbikramsaha/paddy-doctor", "image_size": (224, 224), }, "tomato": { # Multi-source (lab + field) — single-style datasets taught rice/soybean # shortcuts, so tomato starts with the diverse mix. "dataset_name": "cookiefinder/tomato-disease-multiple-sources", # Trimmed 2026-06-13 from 11 -> 8 classes. Spider Mites, Target Spot and # Powdery Mildew were dropped: none have PlantDoc field supplemental data # and none have external holdout support (Spider Mites 2 imgs at 0% # recall; the other two have zero external test images), so the 11-class # model couldn't be honestly validated on them and they dragged field # accuracy down. Spider Mites is also a pest, not a pathogen. The kept 8 # are real, testable tomato diseases (incl. both blights). See # [[project_tomato_trim]]. "diseases": [ "Bacterial Spot", "Early Blight", "Late Blight", "Leaf Mold", "Septoria Leaf Spot", "Yellow Leaf Curl Virus", "Mosaic Virus", "Healthy", ], "supplemental_dataset_name": None, "image_size": (224, 224), }, } # Training hyperparameters TRAINING_CONFIG = { "batch_size": 32, "epochs": 60, "learning_rate": 0.001, "validation_split": 0.2, "test_split": 0.1, "image_size": (224, 224), "num_channels": 3, "augmentation": True, } # Model architecture (using EfficientNetB0 for good accuracy/speed balance) MODEL_CONFIG = { "base_model": "EfficientNetB0", "include_top": False, "weights": "imagenet", "input_shape": (224, 224, 3), "dropout_rate": 0.5, "dense_units": 512, } # TensorFlow Lite conversion settings TFLITE_CONFIG = { "optimize": True, "quantization": "float16", # Options: None, "float16", "int8" "representative_dataset_size": 100, } # Confidence threshold for production inference CONFIDENCE_THRESHOLD = 0.7 # Model versioning MODEL_VERSION_FORMAT = "v{version}_{timestamp}"