Files
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 12:49:20 +08:00

118 lines
4.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Open-Set Recognition with Agnostophobia Losses
## MNIST Tutorial
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](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 07 are *known*, classes 89 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.