Graph Learning

Experiments conformal-shift

Do conformal guarantees hold when bots change tactics?

Links: CS224W L14 (advanced topics: conformal prediction, the L14 proof workshop on split conformal), L21 (trust), notebooks/project/retweet_thread.py §L14 (the same detector with 95% prediction sets). Atlas: uncertainty quantification; trustworthy ML on social data.

Question

Split conformal prediction promises that a prediction set contains the true label with probability at least 1 − α, for any model, as long as calibration and test data are exchangeable. A moderation team that publishes "95% coverage" makes that promise about next month's accounts, but next month's coordinated campaign may use different tactics. Does the guarantee survive, for whom does it break, and how cheaply can it be repaired?

Hypotheses (written before running)

  1. In distribution. On new worlds of the training type, both marginal and class-conditional (Mondrian) conformal cover at least 0.93 of accounts, and Mondrian covers at least 0.90 of bots.

  2. Marginal coverage hides the failure. Under every shift, marginal coverage stays at least 0.93, because humans are 97% of accounts.

  3. A tactic change breaks the bot guarantee. When rings switch from reciprocal to co-amplification, Mondrian bot coverage falls below 0.50.

  4. Cheap repair. Recalibrating Mondrian on 20 labelled bots (and 200 humans) of the new type restores bot coverage to at least 0.85.

Setup

Run: uv run marimo edit experiments/conformal-shift/conformal_shift.py and press the run button.

Results (summary; full table in results.md)

test type marginal: coverage marginal: bot coverage Mondrian: bot coverage recalibrated: bot coverage recalibrated: {human, bot} sets
same 0.953 0.978 0.967 0.967 0.000
co-amplify 0.939 0.233 0.144 0.967 0.554
naive 0.954 1.000 1.000 0.978 0.000
heavy camouflage 0.947 1.000 1.000 0.900 0.000
large rings 0.943 0.989 0.978 0.978 0.000
early (day 10) 0.955 0.156 0.133 1.000 0.751

Real-data extension: Twitch countries (added after the first run; hypotheses written before running it)

The synthetic shifts were designed. A real platform has shifts nobody designed: Twitch's six country graphs (gl.datasets.twitch) share one label (does the streamer broadcast mature content?) and the same account fields, but the communities, the share of mature streamers (0.25 in RU to 0.61 in DE) and the follow patterns differ. Detector: logistic regression on account fields that mean the same everywhere (log views, log account age, partner, log degree, clustering) and their neighbour means, trained on 40% of England (ENGB), calibrated on another 30%, tested on the last 30% ("same") and on DE, ES, FR, PTBR and RU. α = 0.05; "positive" = mature.

  1. In distribution. On held-out ENGB accounts, marginal and Mondrian coverage are both at least 0.93.
  2. A real shift breaks class-conditional coverage. In at least 2 of the 5 other countries, Mondrian coverage of one class falls below 0.90.

  3. Marginal coverage hides it. In those countries marginal coverage stays at least 0.90.

  4. Cheap repair. Recalibrating Mondrian on 200 labelled accounts of the target country gives both classes at least 0.90 coverage in every country.

Run: the second button in the notebook (under a minute; downloads 3 MB). Results go to twitch_results.json and a separate section of results.md.

Twitch results (summary; full table in results.md)

country mature share detector AUC marginal: coverage Mondrian: non-mature coverage recalibrated: worst class recalibrated: both-label sets
ENGB (same) 0.55 0.608 0.947 0.948 0.947 0.848
DE 0.60 0.658 0.941 0.870 0.944 0.819
ES 0.29 0.655 0.918 0.893 0.949 0.845
FR 0.37 0.620 0.863 0.793 0.951 0.863
PTBR 0.35 0.627 0.930 0.909 0.941 0.833
RU 0.25 0.545 0.925 0.914 0.947 0.879

Next steps

  1. Recalibrate from several small samples of different worlds (test the side-effect reading).
  2. Weighted conformal under covariate shift (Tibshirani et al. 2019) with density-ratio weights from unlabelled new-world accounts, which needs no new labels.

  3. Shift detection: a conformal martingale over the stream of new accounts' p-values (Vovk), to raise an alarm when exchangeability breaks.

Results

Generated by conformal_shift.py from config.yaml (α = 0.05, train world 0, calibration worlds [1, 2, 3], test worlds [10, 11, 12]). Means over test worlds. Thresholds: marginal 0.470; Mondrian human 0.472, bot 0.326.

test type method coverage bot coverage human coverage bots flagged {bot} alone {human, bot} sets
same marginal 0.953 0.978 0.952 0.978 0.000
same Mondrian 0.953 0.967 0.952 0.967 0.000
same Mondrian, recalibrated 0.913 0.967 0.911 0.967 0.000
co-amplify marginal 0.939 0.233 0.957 0.233 0.000
co-amplify Mondrian 0.937 0.144 0.957 0.144 0.000
co-amplify Mondrian, recalibrated 0.839 0.967 0.836 0.489 0.554
naive marginal 0.954 1.000 0.953 1.000 0.000
naive Mondrian 0.954 1.000 0.953 1.000 0.000
naive Mondrian, recalibrated 0.880 0.978 0.878 0.978 0.000
heavy camouflage marginal 0.947 1.000 0.946 1.000 0.000
heavy camouflage Mondrian 0.947 1.000 0.946 1.000 0.000
heavy camouflage Mondrian, recalibrated 0.922 0.900 0.923 0.900 0.000
large rings marginal 0.943 0.989 0.941 0.989 0.000
large rings Mondrian 0.943 0.978 0.941 0.978 0.000
large rings Mondrian, recalibrated 0.908 0.978 0.904 0.978 0.000
early (day 10) marginal 0.955 0.156 0.975 0.156 0.000
early (day 10) Mondrian 0.954 0.133 0.975 0.133 0.000
early (day 10) Mondrian, recalibrated 0.974 1.000 0.974 0.200 0.751

Verdicts: H1 supported, H2 supported, H3 supported, H4 supported.

Real-data extension: Twitch countries

Generated by conformal_shift.py (Twitch extension) from config.yaml: train and calibrate on ENGB, test on held-out ENGB ("same") and DE, ES, FR, PTBR, RU; α = 0.05; seeds [0, 1, 2]; recalibration on 200 labelled accounts of the target country. Means over seeds.

country method mature share detector AUC coverage mature coverage non-mature coverage both-label sets
same marginal 0.55 0.608 0.947 0.949 0.945 0.848
same Mondrian 0.55 0.608 0.947 0.947 0.948 0.848
same Mondrian, recalibrated 0.55 0.608 0.947 0.947 0.948 0.848
DE marginal 0.60 0.658 0.941 0.991 0.865 0.747
DE Mondrian 0.60 0.658 0.943 0.990 0.870 0.753
DE Mondrian, recalibrated 0.60 0.658 0.956 0.964 0.944 0.819
ES marginal 0.29 0.655 0.918 0.987 0.890 0.817
ES Mondrian 0.29 0.655 0.920 0.986 0.893 0.821
ES Mondrian, recalibrated 0.29 0.655 0.953 0.962 0.949 0.845
FR marginal 0.37 0.620 0.863 0.995 0.786 0.723
FR Mondrian 0.37 0.620 0.867 0.995 0.793 0.731
FR Mondrian, recalibrated 0.37 0.620 0.954 0.960 0.951 0.863
PTBR marginal 0.35 0.627 0.930 0.978 0.905 0.818
PTBR Mondrian 0.35 0.627 0.932 0.977 0.909 0.822
PTBR Mondrian, recalibrated 0.35 0.627 0.947 0.957 0.941 0.833
RU marginal 0.25 0.545 0.925 0.973 0.909 0.869
RU Mondrian 0.25 0.545 0.928 0.972 0.914 0.872
RU Mondrian, recalibrated 0.25 0.545 0.949 0.947 0.949 0.879

Verdicts: H8 supported, H9 supported, H10 refuted, H11 supported.

In the repository: experiments/conformal-shift/ · README.md config.yaml conformal_shift.py results.json results.md twitch_results.json