fix(diagnosis): ship the CNN weights the Space was missing
Browse filesEvery /api/v1/diagnosis/predict on the live Space answered 503 "Diagnosis
model is not available": model_wrapper.load() raised FileNotFoundError
because the TorchScript export and its metadata were never committed.
The cause was one unanchored .gitignore pattern. `trained_artifacts_fast/`
has no leading slash, so git matched it at every depth -- it was meant for
the scratch copy training drops at the repo root, but it also swallowed
ml/post_symptom_diagnosis/saved_models/trained_artifacts_fast/. Every other
module ships its saved_models/; this one shipped a lone README, and the gap
read as intentional -- the top-level README documented the 503 under Known
Issues as "the CNN artifacts are not in this repo".
Anchor the pattern to /trained_artifacts_fast/ and commit the two files
inference actually reads. The .pt goes through LFS, which the Space requires
for binaries. The .pth checkpoint stays ignored: it is the training-side
fallback, no inference path opens it, and it would add 14 MB to the image
for nothing.
Verified by loading the wrapper from the shipped pair alone -- 88 classes,
img_size 192 -- and running a forward pass to a normalised top-3.
|
@@ -59,7 +59,18 @@ backend/.env.*
|
|
| 59 |
backend/artifacts/*/advisor/
|
| 60 |
backend/artifacts/edge/fallback_events.jsonl
|
| 61 |
backend/artifacts/**/sync_state.json
|
| 62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
|
| 64 |
# Local user files
|
| 65 |
*.crdownload
|
|
|
|
| 59 |
backend/artifacts/*/advisor/
|
| 60 |
backend/artifacts/edge/fallback_events.jsonl
|
| 61 |
backend/artifacts/**/sync_state.json
|
| 62 |
+
|
| 63 |
+
# The scratch copy of the diagnosis CNN that training drops at the repo root.
|
| 64 |
+
# The leading slash is load-bearing: written bare, this pattern matched at every
|
| 65 |
+
# depth and silently swallowed the *real* artifacts under
|
| 66 |
+
# ml/post_symptom_diagnosis/saved_models/trained_artifacts_fast/ too. They never
|
| 67 |
+
# reached the Space, so model_wrapper.load() raised FileNotFoundError and every
|
| 68 |
+
# /api/v1/diagnosis/predict answered 503 "Diagnosis model is not available".
|
| 69 |
+
/trained_artifacts_fast/
|
| 70 |
+
|
| 71 |
+
# The .pth checkpoint is the training-side fallback; inference only ever reads
|
| 72 |
+
# the TorchScript export and the metadata JSON, so keep 14 MB out of the image.
|
| 73 |
+
ml/post_symptom_diagnosis/saved_models/trained_artifacts_fast/*.pth
|
| 74 |
|
| 75 |
# Local user files
|
| 76 |
*.crdownload
|
|
@@ -439,7 +439,7 @@ Full walkthrough: [README_HUGGINGFACE.md](README_HUGGINGFACE.md).
|
|
| 439 |
|
| 440 |
## Known Issues & Limitations
|
| 441 |
|
| 442 |
-
- **Disease diagnosis
|
| 443 |
|
| 444 |
- **Dependency versions are load-bearing.** `scikit-learn==1.8.0` and `numpy>=2.0,<3` are pinned exactly because the committed models embed the library versions that serialized them. Installing a different scikit-learn breaks unpickling with `No module named '_loss'`, and every advisor request fails. Don't relax these pins without retraining.
|
| 445 |
|
|
|
|
| 439 |
|
| 440 |
## Known Issues & Limitations
|
| 441 |
|
| 442 |
+
- **Disease diagnosis weights are LFS-tracked, so a plain clone won't run it.** The CNN artifacts now ship with the repo at `ml/post_symptom_diagnosis/saved_models/trained_artifacts_fast/`, but a clone made without Git LFS leaves the 14 MB TorchScript export as a 133-byte pointer file, and `/api/v1/diagnosis/predict` answers `503 Diagnosis model is not available`. Run `git lfs pull` after cloning.
|
| 443 |
|
| 444 |
- **Dependency versions are load-bearing.** `scikit-learn==1.8.0` and `numpy>=2.0,<3` are pinned exactly because the committed models embed the library versions that serialized them. Installing a different scikit-learn breaks unpickling with `No module named '_loss'`, and every advisor request fails. Don't relax these pins without retraining.
|
| 445 |
|
|
@@ -7,14 +7,25 @@ This directory stores the trained model artifacts for the **Post-Symptom Diagnos
|
|
| 7 |
```
|
| 8 |
saved_models/
|
| 9 |
└── trained_artifacts_fast/
|
| 10 |
-
├──
|
| 11 |
-
|
| 12 |
-
└── plant_disease_model_fast_torchscript.pt # TorchScript export (primary inference)
|
| 13 |
```
|
| 14 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
## How to populate
|
| 16 |
|
| 17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
|
| 19 |
## Usage
|
| 20 |
|
|
|
|
| 7 |
```
|
| 8 |
saved_models/
|
| 9 |
└── trained_artifacts_fast/
|
| 10 |
+
├── class_metadata_fast.json # Class names, crop mapping, img_size — committed
|
| 11 |
+
└── plant_disease_model_fast_torchscript.pt # TorchScript export, primary inference — committed via LFS
|
|
|
|
| 12 |
```
|
| 13 |
|
| 14 |
+
Both files are committed, so the deployed Space can serve diagnoses. Only these
|
| 15 |
+
two are: `best_plant_disease_model_fast.pth` is the training-side checkpoint and
|
| 16 |
+
no inference path reads it, so `.gitignore` keeps its 14 MB out of the image.
|
| 17 |
+
|
| 18 |
## How to populate
|
| 19 |
|
| 20 |
+
Nothing to do for a normal clone — but clone *with* Git LFS, or run `git lfs
|
| 21 |
+
pull` afterwards. Without it the `.pt` stays a 133-byte pointer, `torch.jit.load`
|
| 22 |
+
fails, and `/api/v1/diagnosis/predict` answers `503 Diagnosis model is not
|
| 23 |
+
available`.
|
| 24 |
+
|
| 25 |
+
After retraining, copy the fresh `trained_artifacts_fast/` contents over these
|
| 26 |
+
files. Keep the `.gitignore` rule anchored as `/trained_artifacts_fast/` — written
|
| 27 |
+
bare it matches at every depth and silently re-excludes this directory, which is
|
| 28 |
+
exactly how the artifacts went missing from the Space before.
|
| 29 |
|
| 30 |
## Usage
|
| 31 |
|
|
@@ -0,0 +1,184 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"class_names": [
|
| 3 |
+
"Apple__black_rot",
|
| 4 |
+
"Apple__healthy",
|
| 5 |
+
"Apple__rust",
|
| 6 |
+
"Apple__scab",
|
| 7 |
+
"Cassava__bacterial_blight",
|
| 8 |
+
"Cassava__brown_streak_disease",
|
| 9 |
+
"Cassava__green_mottle",
|
| 10 |
+
"Cassava__healthy",
|
| 11 |
+
"Cassava__mosaic_disease",
|
| 12 |
+
"Cherry__healthy",
|
| 13 |
+
"Cherry__powdery_mildew",
|
| 14 |
+
"Chili__healthy",
|
| 15 |
+
"Chili__leaf curl",
|
| 16 |
+
"Chili__leaf spot",
|
| 17 |
+
"Chili__whitefly",
|
| 18 |
+
"Chili__yellowish",
|
| 19 |
+
"Coffee__cercospora_leaf_spot",
|
| 20 |
+
"Coffee__healthy",
|
| 21 |
+
"Coffee__red_spider_mite",
|
| 22 |
+
"Coffee__rust",
|
| 23 |
+
"Corn__common_rust",
|
| 24 |
+
"Corn__gray_leaf_spot",
|
| 25 |
+
"Corn__healthy",
|
| 26 |
+
"Corn__northern_leaf_blight",
|
| 27 |
+
"Cucumber__diseased",
|
| 28 |
+
"Cucumber__healthy",
|
| 29 |
+
"Gauva__diseased",
|
| 30 |
+
"Gauva__healthy",
|
| 31 |
+
"Grape__black_measles",
|
| 32 |
+
"Grape__black_rot",
|
| 33 |
+
"Grape__healthy",
|
| 34 |
+
"Grape__leaf_blight_(isariopsis_leaf_spot)",
|
| 35 |
+
"Jamun__diseased",
|
| 36 |
+
"Jamun__healthy",
|
| 37 |
+
"Lemon__diseased",
|
| 38 |
+
"Lemon__healthy",
|
| 39 |
+
"Mango__diseased",
|
| 40 |
+
"Mango__healthy",
|
| 41 |
+
"Peach__bacterial_spot",
|
| 42 |
+
"Peach__healthy",
|
| 43 |
+
"Pepper_bell__bacterial_spot",
|
| 44 |
+
"Pepper_bell__healthy",
|
| 45 |
+
"Pomegranate__diseased",
|
| 46 |
+
"Pomegranate__healthy",
|
| 47 |
+
"Potato__early_blight",
|
| 48 |
+
"Potato__healthy",
|
| 49 |
+
"Potato__late_blight",
|
| 50 |
+
"Rice__brown_spot",
|
| 51 |
+
"Rice__healthy",
|
| 52 |
+
"Rice__hispa",
|
| 53 |
+
"Rice__leaf_blast",
|
| 54 |
+
"Rice__neck_blast",
|
| 55 |
+
"Soybean__bacterial_blight",
|
| 56 |
+
"Soybean__caterpillar",
|
| 57 |
+
"Soybean__diabrotica_speciosa",
|
| 58 |
+
"Soybean__downy_mildew",
|
| 59 |
+
"Soybean__healthy",
|
| 60 |
+
"Soybean__mosaic_virus",
|
| 61 |
+
"Soybean__powdery_mildew",
|
| 62 |
+
"Soybean__rust",
|
| 63 |
+
"Soybean__southern_blight",
|
| 64 |
+
"Strawberry___leaf_scorch",
|
| 65 |
+
"Strawberry__healthy",
|
| 66 |
+
"Sugarcane__bacterial_blight",
|
| 67 |
+
"Sugarcane__healthy",
|
| 68 |
+
"Sugarcane__red_rot",
|
| 69 |
+
"Sugarcane__red_stripe",
|
| 70 |
+
"Sugarcane__rust",
|
| 71 |
+
"Tea__algal_leaf",
|
| 72 |
+
"Tea__anthracnose",
|
| 73 |
+
"Tea__bird_eye_spot",
|
| 74 |
+
"Tea__brown_blight",
|
| 75 |
+
"Tea__healthy",
|
| 76 |
+
"Tea__red_leaf_spot",
|
| 77 |
+
"Tomato__bacterial_spot",
|
| 78 |
+
"Tomato__early_blight",
|
| 79 |
+
"Tomato__healthy",
|
| 80 |
+
"Tomato__late_blight",
|
| 81 |
+
"Tomato__leaf_mold",
|
| 82 |
+
"Tomato__mosaic_virus",
|
| 83 |
+
"Tomato__septoria_leaf_spot",
|
| 84 |
+
"Tomato__spider_mites_(two_spotted_spider_mite)",
|
| 85 |
+
"Tomato__target_spot",
|
| 86 |
+
"Tomato__yellow_leaf_curl_virus",
|
| 87 |
+
"Wheat__brown_rust",
|
| 88 |
+
"Wheat__healthy",
|
| 89 |
+
"Wheat__septoria",
|
| 90 |
+
"Wheat__yellow_rust"
|
| 91 |
+
],
|
| 92 |
+
"class_to_crop": {
|
| 93 |
+
"Apple__black_rot": "Apple",
|
| 94 |
+
"Apple__healthy": "Apple",
|
| 95 |
+
"Apple__rust": "Apple",
|
| 96 |
+
"Apple__scab": "Apple",
|
| 97 |
+
"Cassava__bacterial_blight": "Cassava",
|
| 98 |
+
"Cassava__brown_streak_disease": "Cassava",
|
| 99 |
+
"Cassava__green_mottle": "Cassava",
|
| 100 |
+
"Cassava__healthy": "Cassava",
|
| 101 |
+
"Cassava__mosaic_disease": "Cassava",
|
| 102 |
+
"Cherry__healthy": "Cherry",
|
| 103 |
+
"Cherry__powdery_mildew": "Cherry",
|
| 104 |
+
"Chili__healthy": "Chili",
|
| 105 |
+
"Chili__leaf curl": "Chili",
|
| 106 |
+
"Chili__leaf spot": "Chili",
|
| 107 |
+
"Chili__whitefly": "Chili",
|
| 108 |
+
"Chili__yellowish": "Chili",
|
| 109 |
+
"Coffee__cercospora_leaf_spot": "Coffee",
|
| 110 |
+
"Coffee__healthy": "Coffee",
|
| 111 |
+
"Coffee__red_spider_mite": "Coffee",
|
| 112 |
+
"Coffee__rust": "Coffee",
|
| 113 |
+
"Corn__common_rust": "Corn",
|
| 114 |
+
"Corn__gray_leaf_spot": "Corn",
|
| 115 |
+
"Corn__healthy": "Corn",
|
| 116 |
+
"Corn__northern_leaf_blight": "Corn",
|
| 117 |
+
"Cucumber__diseased": "Cucumber",
|
| 118 |
+
"Cucumber__healthy": "Cucumber",
|
| 119 |
+
"Gauva__diseased": "Gauva",
|
| 120 |
+
"Gauva__healthy": "Gauva",
|
| 121 |
+
"Grape__black_measles": "Grape",
|
| 122 |
+
"Grape__black_rot": "Grape",
|
| 123 |
+
"Grape__healthy": "Grape",
|
| 124 |
+
"Grape__leaf_blight_(isariopsis_leaf_spot)": "Grape",
|
| 125 |
+
"Jamun__diseased": "Jamun",
|
| 126 |
+
"Jamun__healthy": "Jamun",
|
| 127 |
+
"Lemon__diseased": "Lemon",
|
| 128 |
+
"Lemon__healthy": "Lemon",
|
| 129 |
+
"Mango__diseased": "Mango",
|
| 130 |
+
"Mango__healthy": "Mango",
|
| 131 |
+
"Peach__bacterial_spot": "Peach",
|
| 132 |
+
"Peach__healthy": "Peach",
|
| 133 |
+
"Pepper_bell__bacterial_spot": "Pepper_bell",
|
| 134 |
+
"Pepper_bell__healthy": "Pepper_bell",
|
| 135 |
+
"Pomegranate__diseased": "Pomegranate",
|
| 136 |
+
"Pomegranate__healthy": "Pomegranate",
|
| 137 |
+
"Potato__early_blight": "Potato",
|
| 138 |
+
"Potato__healthy": "Potato",
|
| 139 |
+
"Potato__late_blight": "Potato",
|
| 140 |
+
"Rice__brown_spot": "Rice",
|
| 141 |
+
"Rice__healthy": "Rice",
|
| 142 |
+
"Rice__hispa": "Rice",
|
| 143 |
+
"Rice__leaf_blast": "Rice",
|
| 144 |
+
"Rice__neck_blast": "Rice",
|
| 145 |
+
"Soybean__bacterial_blight": "Soybean",
|
| 146 |
+
"Soybean__caterpillar": "Soybean",
|
| 147 |
+
"Soybean__diabrotica_speciosa": "Soybean",
|
| 148 |
+
"Soybean__downy_mildew": "Soybean",
|
| 149 |
+
"Soybean__healthy": "Soybean",
|
| 150 |
+
"Soybean__mosaic_virus": "Soybean",
|
| 151 |
+
"Soybean__powdery_mildew": "Soybean",
|
| 152 |
+
"Soybean__rust": "Soybean",
|
| 153 |
+
"Soybean__southern_blight": "Soybean",
|
| 154 |
+
"Strawberry___leaf_scorch": "Strawberry",
|
| 155 |
+
"Strawberry__healthy": "Strawberry",
|
| 156 |
+
"Sugarcane__bacterial_blight": "Sugarcane",
|
| 157 |
+
"Sugarcane__healthy": "Sugarcane",
|
| 158 |
+
"Sugarcane__red_rot": "Sugarcane",
|
| 159 |
+
"Sugarcane__red_stripe": "Sugarcane",
|
| 160 |
+
"Sugarcane__rust": "Sugarcane",
|
| 161 |
+
"Tea__algal_leaf": "Tea",
|
| 162 |
+
"Tea__anthracnose": "Tea",
|
| 163 |
+
"Tea__bird_eye_spot": "Tea",
|
| 164 |
+
"Tea__brown_blight": "Tea",
|
| 165 |
+
"Tea__healthy": "Tea",
|
| 166 |
+
"Tea__red_leaf_spot": "Tea",
|
| 167 |
+
"Tomato__bacterial_spot": "Tomato",
|
| 168 |
+
"Tomato__early_blight": "Tomato",
|
| 169 |
+
"Tomato__healthy": "Tomato",
|
| 170 |
+
"Tomato__late_blight": "Tomato",
|
| 171 |
+
"Tomato__leaf_mold": "Tomato",
|
| 172 |
+
"Tomato__mosaic_virus": "Tomato",
|
| 173 |
+
"Tomato__septoria_leaf_spot": "Tomato",
|
| 174 |
+
"Tomato__spider_mites_(two_spotted_spider_mite)": "Tomato",
|
| 175 |
+
"Tomato__target_spot": "Tomato",
|
| 176 |
+
"Tomato__yellow_leaf_curl_virus": "Tomato",
|
| 177 |
+
"Wheat__brown_rust": "Wheat",
|
| 178 |
+
"Wheat__healthy": "Wheat",
|
| 179 |
+
"Wheat__septoria": "Wheat",
|
| 180 |
+
"Wheat__yellow_rust": "Wheat"
|
| 181 |
+
},
|
| 182 |
+
"num_classes": 88,
|
| 183 |
+
"img_size": 192
|
| 184 |
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:878a6a60624e180f0fa295fed20a2a8532faa6e7f6cc37719465f6850cd13f66
|
| 3 |
+
size 14678584
|