593b94c120
pytest / Unit Tests (push) Has been cancelled
pytest / Integration (integration_tests_a) (push) Has been cancelled
pytest / Integration (integration_tests_b) (push) Has been cancelled
pytest / Integration (integration_tests_c) (push) Has been cancelled
pytest / Integration (integration_tests_d) (push) Has been cancelled
pytest / Integration (integration_tests_e) (push) Has been cancelled
pytest / Integration (integration_tests_f) (push) Has been cancelled
pytest / Integration (integration_tests_g) (push) Has been cancelled
pytest / Integration (integration_tests_h) (push) Has been cancelled
pytest / Integration (integration_tests_i) (push) Has been cancelled
pytest / Integration (integration_tests_j) (push) Has been cancelled
pytest / Distributed (distributed_a) (push) Has been cancelled
pytest / Distributed (distributed_b) (push) Has been cancelled
pytest / Distributed (distributed_c) (push) Has been cancelled
pytest / Distributed (distributed_d) (push) Has been cancelled
pytest / Distributed (distributed_e) (push) Has been cancelled
pytest / Distributed (distributed_f) (push) Has been cancelled
pytest / Minimal Install (push) Has been cancelled
pytest / Event File (push) Has been cancelled
pytest (slow) / py-slow (push) Has been cancelled
Publish JSON Schema / publish-schema (push) Has been cancelled
118 lines
4.4 KiB
Markdown
118 lines
4.4 KiB
Markdown
# Open-Set Recognition with Agnostophobia Losses
|
||
|
||
## MNIST Tutorial
|
||
|
||
[](https://colab.research.google.com/github/ludwig-ai/ludwig/blob/main/examples/open_set_recognition/open_set_mnist.ipynb)
|
||
|
||
The notebook `open_set_mnist.ipynb` walks through the full open-set recognition workflow on a
|
||
real image dataset:
|
||
|
||
- **Dataset**: MNIST digits — classes 0–7 are *known*, classes 8–9 act as *unknown/background*
|
||
- **Models**: three Ludwig image classifiers using `stacked_cnn` encoder and `category` output
|
||
- CE Baseline (`softmax_cross_entropy`) — trained on known classes only
|
||
- Entropic Open-Set (`entropic_open_set`) — entropy maximisation on background samples
|
||
- Objectosphere (`objectosphere`) — norm push on known + norm suppression on background
|
||
- **Evaluation**: confidence histograms and ROC curves for unknown detection
|
||
|
||
The notebook is Colab-compatible — it installs Ludwig and torchvision, downloads MNIST, saves
|
||
images to disk, builds `train.csv`/`test.csv`, trains all three models, and plots results.
|
||
|
||
YAML configs for standalone use:
|
||
|
||
- `config_baseline_mnist.yaml`
|
||
- `config_entropic_mnist.yaml`
|
||
- `config_objectosphere_mnist.yaml`
|
||
|
||
______________________________________________________________________
|
||
|
||
## Quick Validation Script
|
||
|
||
This example reproduces the key findings from:
|
||
|
||
> Dhamija, A. R., Günther, M., & Boult, T. (2018).
|
||
> **Reducing Network Agnostophobia.**
|
||
> *NeurIPS 2018.* https://arxiv.org/abs/1811.04110
|
||
|
||
Standard classifiers are trained to output high-confidence predictions for every input — even inputs
|
||
from classes never seen during training. This is called *network agnostophobia*: the network is
|
||
incapable of expressing "I don't know."
|
||
|
||
The paper proposes two loss functions that address this:
|
||
|
||
| Loss | Description |
|
||
| --------------------- | -------------------------------------------------------------------------- |
|
||
| **Entropic Open-Set** | CE on known samples + entropy maximisation on background samples |
|
||
| **Objectosphere** | CE + logit-norm push for known + entropy + norm suppression for background |
|
||
|
||
Both are available in Ludwig's category and binary output features.
|
||
|
||
### Quick start
|
||
|
||
```bash
|
||
pip install ludwig
|
||
python train_open_set.py
|
||
```
|
||
|
||
The script generates a synthetic two-class-family dataset (four known Gaussian clusters + two unknown
|
||
clusters), trains three classifiers, and prints a comparison table showing mean max probability on
|
||
unknowns — lower is better for open-set recognition.
|
||
|
||
Expected output (approximate):
|
||
|
||
```
|
||
Model | Max-prob (known) | Max-prob (unknown) | Norm known | Norm unknown
|
||
-----------------------|-----------------|-------------------|------------|-------------
|
||
CE Baseline | 0.998 | 0.741 | 8.828 | 5.375
|
||
Entropic Open-Set | 0.974 | 0.273 | 6.254 | 0.637
|
||
Objectosphere | 0.874 | 0.363 | 13.843 | 2.361
|
||
```
|
||
|
||
### Ludwig configuration
|
||
|
||
#### Entropic Open-Set Loss
|
||
|
||
```yaml
|
||
output_features:
|
||
- name: label
|
||
type: category
|
||
loss:
|
||
type: entropic_open_set
|
||
background_class: 4 # integer index of the background/unknown class
|
||
```
|
||
|
||
#### Objectosphere Loss
|
||
|
||
```yaml
|
||
output_features:
|
||
- name: label
|
||
type: category
|
||
loss:
|
||
type: objectosphere
|
||
background_class: 4
|
||
xi: 10.0 # minimum logit norm for known-class samples
|
||
zeta: 0.1 # weight for unknown-class magnitude suppression
|
||
```
|
||
|
||
`background_class` is the **integer index** of the background/unknown class in Ludwig's
|
||
vocabulary for that feature. You can discover it by inspecting the saved model's
|
||
`training_set_metadata.json` file after a training run — look for the `str2idx` field of the
|
||
relevant output feature.
|
||
|
||
### Inference-time unknown detection
|
||
|
||
For **Objectosphere** models, unknown inputs can be detected using a simple threshold on the logit
|
||
L2 norm:
|
||
|
||
```python
|
||
predictions = model.predict(dataset=df)
|
||
|
||
# Retrieve raw logits via the API (requires model.collect_activations)
|
||
import torch
|
||
|
||
norms = logit_tensor.norm(dim=-1)
|
||
is_unknown = norms < threshold # choose threshold from validation set
|
||
```
|
||
|
||
For both loss types, you can also use the **maximum softmax probability** as a simpler threshold:
|
||
samples with max-prob below some value (e.g. 0.5) are flagged as unknown.
|