Spaces:
Configuration error
Configuration error
File size: 6,296 Bytes
71be50a 09971a3 71be50a 09971a3 71be50a | 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 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | # Visual Defect Inspector
An industrial anomaly detection API built on [PatchCore](https://arxiv.org/abs/2106.08265), trained on the [MVTec AD](https://www.mvtec.com/company/research/datasets/mvtec-ad) dataset. Upload an image of a bottle and the API returns an anomaly prediction, confidence score, and a heatmap overlay highlighting suspicious regions.
**Live API:** [codehashira73-visual-defect-inspector.hf.space/docs](https://codehashira73-visual-defect-inspector.hf.space/docs)
---
## Demo
| Normal | Defective | Anomaly Heatmap |
|--------|-----------|-----------------|
|  |  |  |
> **Note:** This model is trained on MVTec AD bottle images β professionally lit, white background, standardized angles. Testing with images from this distribution will give reliable results. Random internet images may return false positives due to distribution shift (different backgrounds, lighting, angles).
---
## How It Works
PatchCore is a memory-based anomaly detection algorithm. Instead of learning what anomalies look like (which is impossible without labeled defect data), it learns what *normal* looks like and flags anything that deviates.
**Training (offline):**
1. Pass all normal training images through a pretrained CNN backbone (`resnet18`)
2. Extract intermediate feature maps from `layer2` and `layer3` β these capture both low-level textures and mid-level semantics
3. Flatten these into patch-level embeddings, one per spatial location
4. Apply coreset subsampling (ratio=0.1) to compress the embeddings into a representative memory bank β this keeps inference fast without sacrificing much accuracy
**Inference (at API call time):**
1. Pass the uploaded image through the same backbone
2. Extract patch embeddings from the same layers
3. For each patch, find its nearest neighbor in the memory bank and compute the distance
4. Large distance = that patch looks nothing like any normal patch = anomaly
5. Upsample per-patch distances back to image resolution β anomaly heatmap
6. Take the maximum patch distance as the image-level anomaly score
7. Compare score against a threshold computed during training β `NORMAL` or `ANOMALOUS`
### Why resnet18 over wide_resnet50_2?
Both backbones performed nearly identically β `wide_resnet50_2` achieved `pixel_AUROC=0.986` vs `resnet18` at `pixel_AUROC=0.978`. Since PatchCore's performance is driven primarily by the coreset memory bank and nearest-neighbor search rather than backbone capacity, the heavier backbone offers no meaningful advantage. `resnet18` was selected for its faster inference time and lower memory footprint at deployment, with negligible cost to detection performance.
---
## Results
Trained and evaluated on the **bottle** category of MVTec AD.
| Backbone | Image AUROC | Pixel AUROC | Image F1 | Model Size |
|----------|-------------|-------------|----------|------------|
| wide_resnet50_2 | 1.000 | 0.986 | 0.992 | ~1.5 GB |
| **resnet18 (deployed)** | **1.000** | **0.978** | **0.992** | **42 MB** |
Both runs logged with MLflow under the `visual-defect-inspector` experiment.
---
## API Usage
### `GET /health`
Health check endpoint.
```bash
curl https://codehashira73-visual-defect-inspector.hf.space/health
```
**Response:**
```json
{"status": "ok"}
```
---
### `POST /inspect`
Upload an image and get an anomaly prediction.
```bash
curl -X POST \
https://codehashira73-visual-defect-inspector.hf.space/inspect \
-F "file=@bottle.png"
```
**Response:**
```json
{
"prediction": "ANOMALOUS",
"anomaly_score": 0.9753,
"heatmap_base64": "/9j/4AAQSkZJRgAB..."
}
```
| Field | Type | Description |
|-------|------|-------------|
| `prediction` | string | `"NORMAL"` or `"ANOMALOUS"` |
| `anomaly_score` | float | Score between 0 and 1. Higher = more anomalous |
| `heatmap_base64` | string | Base64-encoded JPEG of the original image overlaid with the anomaly heatmap (blue = normal, red = anomalous) |
To render the heatmap in Python:
```python
import base64
from PIL import Image
import io
heatmap_bytes = base64.b64decode(response["heatmap_base64"])
image = Image.open(io.BytesIO(heatmap_bytes))
image.show()
```
---
## Project Structure
```
visual-defect-inspector/
βββ app/
β βββ __init__.py
β βββ main.py # FastAPI app β routes, CORS, validation
β βββ inference.py # Model loading (singleton) + predict logic
βββ saved_model/
β βββ weights/
β βββ torch/
β βββ model.pt # PatchCore model with memory bank (via Git LFS)
βββ Anomaly_detection.ipynb # Training, evaluation, MLflow logging
βββ Dockerfile
βββ requirements.txt
βββ .gitignore
```
---
## Tech Stack
| Component | Tool |
|-----------|------|
| Anomaly detection | [anomalib](https://github.com/openvinotoolkit/anomalib) |
| Backbone | ResNet18 (PyTorch) |
| Experiment tracking | MLflow |
| API framework | FastAPI + Uvicorn |
| Image processing | OpenCV, Pillow |
| Containerization | Docker |
| Deployment | Hugging Face Spaces |
| Model storage | Git LFS |
---
## Local Setup
**Prerequisites:** Python 3.10+, Git LFS installed
```bash
# Clone the repo
git clone https://github.com/JeremiahAdebayo/visual-defect-inspector.git
cd visual-defect-inspector
# Install dependencies
pip install -r requirements.txt
# Run the API
uvicorn app.main:app --reload
```
API will be available at `http://127.0.0.1:8000/docs`
**With Docker:**
```bash
docker build -t visual-defect-inspector .
docker run -p 7860:7860 visual-defect-inspector
```
---
## Limitations
- Trained on a single MVTec AD category (bottle). Does not generalize to other object types without retraining.
- Sensitive to distribution shift β images must closely resemble the MVTec training distribution (white background, controlled lighting, top-down angle) for reliable results.
- Anomaly threshold is fixed at training time. May need recalibration for production use cases with different defect types.
---
## Author
**Jeremiah Adebayo**
3rd Year Information Technology Student, University of Iloilo
[GitHub](https://github.com/JeremiahAdebayo) Β· [Hugging Face](https://huggingface.co/CodeHashira73) |