Skip to main content

KCM

Kernel Contraction Matching (KCM)

Anomaly detection with no optimizer, no epoch axis, and no collapse. A drop-in scikit-learn estimator that ranks first by mean AUROC across the 47 ADBench datasets while training nothing.

ProblemInstallQuickstartResultsAPIPaper

DOI PyPI Python Tests License scikit-learn

Reference implementation for Mitigating Convergence Collapse in Fixed-Target Anomaly Detectors via Kernel-Anchored Locality Regularization, CIKM 2026.

Install

pip install kar-kcm                 # KCM only, no PyTorch
pip install "kar-kcm[kar]"          # adds KAR, which needs PyTorch

From source, before the first release lands on PyPI:

pip install git+https://github.com/jose-melo/kernel-contraction-matching

The problem: fixed-target detectors get worse as they train

A fixed-target detector trains a network to match a target that carries no information about how far a point lies from the data: a constant centre (Deep SVDD), the input itself (autoencoders), a frozen random network (RDP), a noise endpoint (flow-matching). The anomaly score is the residual that is left over.

As training converges that residual goes to zero everywhere the model can reach, anomalies included. The score field flattens, and detection decays while the training loss keeps falling.

Convergence collapse across fixed-target anomaly detectors

The score field is sharp early and flat late; the anomalies (stars) stop being separated from the normal cluster (dots). Nine detectors on ADBench cardio all reach an early peak and then decay toward convergence. Early stopping does not rescue this: the best epoch moves by two orders of magnitude across seeds, and the loss you would monitor decreases monotonically the whole time.

What KCM does

Replace the trained map with the kernel smoother a wide network approaches in its lazy regime. For a query z and training set X, KCM predicts the kernel-weighted average of the training points and scores the residual:

NW_h(z) = sum_i k_h(z, x_i) x_i / sum_i k_h(z, x_i)        Nadaraya-Watson reconstruction
score(z) = || z - NW_h(z) ||                                higher means more anomalous

Every training point's influence decays with distance, so as z leaves the data the prediction levels off and the residual grows. The bandwidth h is chosen by leave-one-out reconstruction error over a 21-point grid. There is no optimizer, no epoch axis, and nothing to early-stop.

Quickstart

from sklearn.datasets import make_blobs
from karkcm import make_kcm_pipeline

X_train, _ = make_blobs(n_samples=500, centers=1, random_state=0)
X_test, _ = make_blobs(n_samples=20, centers=[[8, 8]], random_state=0)

detector = make_kcm_pipeline().fit(X_train)

detector.predict(X_test)          # -1 outlier, +1 inlier
detector.anomaly_score(X_test)    # higher means more anomalous

make_kcm_pipeline() is StandardScaler plus KCM. KCM uses one isotropic bandwidth for every feature, so scaled input is what you want; the pipeline handles it and forwards KCM's own methods.

Results

Across the 47 ADBench datasets, against the 44 baselines ADBench ships:

mean AUROC mean rank neural training
KCM 0.8710 7.06 none
DTE-NP 0.8652 6.81 yes
LUNAR 0.8603 8.62 yes
KDE 0.8452 10.49 none

Nemenyi critical-difference diagram over the 47 datasets

KCM sits in the leading group of the critical-difference diagram, with no trained parameters.

Fit and inference time per detector

Fit is a bandwidth search and a matrix product: median 0.40 s per dataset on one CPU core, where the neural detectors sit one to two orders of magnitude higher.

Using the estimator

KCM follows the scikit-learn outlier-detector contract, so it clones, pickles, and drops into Pipeline and GridSearchCV.

from karkcm import KCM

KCM(bandwidth="loo", n_grid=21, trim_frac=0.0, max_reference=2000,
    contamination=0.1, chunk_size=4096, assume_scaled=False,
    novelty=True, random_state=None)
method returns
anomaly_score(X) ||z - NW(z)||, higher means more anomalous
score_samples(X) -anomaly_score(X), the scikit-learn orientation
decision_function(X) score_samples(X) - offset_, negative means outlier
predict(X) -1 outlier, +1 inlier
reconstruct(X) the Nadaraya-Watson reconstruction, per feature
kernel_mass(X) total kernel weight a query receives

reconstruct is the explanation channel: it returns what the model considers a normal version of each row, so the per-feature difference tells you why a point scored the way it did.

Two modes, following LocalOutlierFactor. novelty=True (the default) scores rows the model was not fitted on, which is the setting the paper uses. novelty=False exposes fit_predict for labelling the rows you fit on, using leave-one-out residuals so that no row is scored against itself.

detector = KCM().fit(X_train)          # novelty=True: score new data
labels = KCM(novelty=False).fit_predict(X)   # label X itself

anomaly_auroc and anomaly_auprc are scorers with the sign already handled, for use with GridSearchCV.

KAR, for a trainable backbone

When a trained network is a requirement rather than a choice, KAR keeps one and constrains it to stay within a fixed radius rho of the KCM anchor, in KCM-residual units. That floor is what removes the collapse: rho = 0.5 is used unchanged on every dataset in the paper.

KAR under prolonged training

KAR needs PyTorch, which KCM does not: pip install "kar-kcm[kar]".

Reproducing the paper

pip install -e ".[paper]"
python scripts/download_datasets.py

python -m karkcm.experiments.kcm_benchmark      # Sec. 5, KCM over 47 datasets
python -m karkcm.experiments.collapse_gap       # Sec. 3, peak-to-final gap
python -m karkcm.experiments.backbone           # Sec. 6, backbone independence
python -m karkcm.experiments.aggregate          # per-section summary tables
python -m karkcm.experiments.kar_ablation --dataset 6_cardio --rho 0.5

results/ holds the per-run JSON and CSV records behind the paper's tables and figures, and results/figures/ the figures themselves. The experiment modules will not overwrite it: point KARKCM_RESULTS at a directory of your own, or pass --overwrite deliberately.

KCMAnchor in karkcm/kcm.py is the frozen object the paper's experiments call. KCM is the estimator-shaped front door onto the same arithmetic, and tests/test_estimator_parity.py locks the two together.

The 47 ADBench .npz files are fetched from ADBench and are not redistributed here.

Layout

karkcm/
  kcm.py            the kernel, the bandwidth search, the frozen anchor
  estimator.py      the scikit-learn estimator, pipeline and scorers
  kar.py            bounded correction and the KAR training loop
  nets.py           MLP, time-conditioned MLP, autoencoder
  baselines.py      the six fixed-target detectors of Sec. 3
  data.py           ADBench loading and the semi-supervised split
  experiments/      one runnable module per paper artifact
benchmarks/         KCM against scikit-learn's detectors
examples/           quickstart, pipeline and grid search, diagnostics
results/            the per-run records behind every table and figure
tests/

Citing

@inproceedings{demelocosta2026kar,
  author    = {De Melo Costa, José Lucas and Popineau, Fabrice and
               Rimmel, Arpad and Doan, Bich-Liên},
  title     = {Mitigating Convergence Collapse in Fixed-Target Anomaly Detectors
               via Kernel-Anchored Locality Regularization},
  booktitle = {Proceedings of the 35th ACM International Conference on Information
               and Knowledge Management (CIKM '26)},
  year      = {2026},
  doi       = {10.1145/3799682.3841143}
}

License

MIT, see LICENSE.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

kar_kcm-1.0.0.tar.gz (82.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

kar_kcm-1.0.0-py3-none-any.whl (38.6 kB view details)

Uploaded Python 3

File details

Details for the file kar_kcm-1.0.0.tar.gz.

File metadata

  • Download URL: kar_kcm-1.0.0.tar.gz
  • Upload date:
  • Size: 82.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for kar_kcm-1.0.0.tar.gz
Algorithm Hash digest
SHA256 ee1de1dbe784d4ad89a94cb14fa56bea1a2d0c6bc220959c094f4fa59d266ca4
MD5 24f88f32ceab16b6e88d6cd0c5ca3c29
BLAKE2b-256 c99a236ad84625b4eea6b721a2197027207545fc263f26fd8f3523abb9537acb

See more details on using hashes here.

Provenance

The following attestation bundles were made for kar_kcm-1.0.0.tar.gz:

Publisher: publish.yml on jose-melo/kernel-contraction-matching

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file kar_kcm-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: kar_kcm-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 38.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for kar_kcm-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6b74dc85e933a8753cd17708bb9a993c3e1932025318759b5d63ee601031a3d8
MD5 e43dfb5008519cc6266aff7ce7369a7c
BLAKE2b-256 8a95eaa7b2f8b3f9e0ce5c8981398827d271cb086865c7d07ab4e3a57eeb8a6e

See more details on using hashes here.

Provenance

The following attestation bundles were made for kar_kcm-1.0.0-py3-none-any.whl:

Publisher: publish.yml on jose-melo/kernel-contraction-matching

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page