File size: 3,527 Bytes
1b26403
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
---
license: mit
tags:
  - solar-energy
  - image-classification
  - photovoltaic
  - dust-detection
  - efficientnet
  - svm
  - explainable-ai
datasets:
  - safwanshamsir99/solar-photovoltaics-panell-for-dust-dectection
library_name: scikit-learn
pipeline_tag: image-classification
metrics:
  - accuracy
  - roc_auc
model-index:
  - name: solar-panel-dust-xai
    results:
      - task:
          type: image-classification
          name: Solar panel clean vs dirty
        metrics:
          - type: accuracy
            value: 0.9029
            name: Test Accuracy (merged held-out)
          - type: roc_auc
            value: 0.9596
            name: AUC-ROC
          - type: accuracy
            value: 0.9824
            name: External accuracy (2,562 imgs)
          - type: accuracy
            value: 0.9974
            name: External accuracy (383 imgs)
---

# Solar Panel Dust Detection with Explainable AI

Hybrid **EfficientNet-B2 (frozen) + RBF-SVM** model for classifying a single RGB
image of a photovoltaic (PV) panel as **clean** or **dirty**, with a focus on
cross-dataset generalisation and explainability (Grad-CAM, Score-CAM, Integrated
Gradients, SHAP, LIME).

## Model

- **Feature extractor**: EfficientNet-B2, ImageNet weights, frozen, global-average
  pooled → 1,408-d vector.
- **Head**: RBF-kernel SVM (`C=10`, `gamma=auto`), `class_weight="balanced"`.
- **Architecture is exactly the deployed production model** (version `v007`).

| Metric | Value |
|--------|-------|
| Test accuracy (merged held-out, 381 imgs) | **90.29%** |
| AUC-ROC | **0.9596** |
| 5-fold CV accuracy | **86.38%** |
| External: Dusty/Clean (2,562 imgs) | **98.24%** (98.0% dirty recall) |
| External: Faulty-panel clean/dirty (383 imgs) | **99.74%** (100% dirty recall) |

## Files

- `svm_classifier.pkl` — trained RBF-SVM head (joblib).
- `scaler.pkl` — fitted `StandardScaler` applied to pooled features.
- `pipeline_meta.json` — full training metadata and per-metric scores.
- `class_names.json` — label order (`["clean", "dirty"]`).
- `demo.py` — self-contained inference script.

## Usage

```bash
pip install tensorflow scikit-learn joblib numpy pillow

python demo.py panel.jpg            # print label, confidence, dustiness
python demo.py clean.jpg dirty.jpg  # batch
```

> The first run downloads the EfficientNet-B2 ImageNet weights (~80 MB) from
> TensorFlow via `keras`.

## How it was trained

A single-source model overfits one acquisition pipeline and collapses on new data
(observed: ~6% dirty recall on external sets). The fix was to **merge three public
PV-dust sources** into one 3,787-image corpus and retrain:

| Split | Clean | Dirty | Total |
|-------|------:|------:|------:|
| Train | 1,750 | 1,279 | 3,029 |
| Val   |   218 |   159 |   377 |
| Test  |   220 |   161 |   381 |
| **All** | 2,188 | 1,599 | **3,787** |

The frozen representation + margin-based SVM then transfers far better across
acquisition sources (see external-validation metrics above).

## Intended use & limitations

- For single-panel RGB inspection; labels are binary (clean/dirty), not severity.
- Confidence for every prediction is produced; a configurable confidence
  threshold can route low-confidence samples to human review.
- The backbone is loaded fresh from ImageNet weights at inference (not stored in
  this repo), matching the deployed frozen-backbone protocol.

## Related

Full experimental details, the IEEE-format paper, and the five-method XAI module
live in the companion project repo.