samuelsimko commited on
Commit
b994f0b
·
verified ·
1 Parent(s): b8ee2d2

Add full mode (paper's end-to-end configuration) and its per-seed thresholds; fix model card; remove __pycache__

Browse files
README.md CHANGED
@@ -21,9 +21,8 @@ pipeline_tag: text-classification
21
  language model and the replies the model produces, and it is trained on data generated from a written constitution of
22
  eleven harm categories.
23
 
24
- Paper: *EuroSafeAI Open Constitutional Classifiers* (arXiv: TODO) · Code: TODO · Data:
25
- [EuroSafeGuard-prompts](https://huggingface.co/datasets/EuroSafeAI/EuroSafeGuard-prompts),
26
- [EuroSafeGuard-replies](https://huggingface.co/datasets/EuroSafeAI/EuroSafeGuard-replies) (gated)
27
 
28
  ## Components
29
 
@@ -32,8 +31,9 @@ Paper: *EuroSafeAI Open Constitutional Classifiers* (arXiv: TODO) · Code: TODO
32
  | `probe/` | MLP probe (hidden size 256) on the activations of all 32 blocks of the protected model, reading the chat-formatted prompt; per-token logits are smoothed with an exponential moving average and the prompt score is their maximum | Llama-3.1-8B-Instruct |
33
  | `gate/seed{0..4}/` | Input classifier: LoRA adapter + one sigmoid head per harm category (11 heads); score = highest head | Qwen3.5-9B |
34
  | `exchange/` | Exchange classifier: reads `User: <prompt>\n\nAssistant: <reply>`; LoRA + 11 heads | Qwen3.5-9B |
35
- | `thresholds/seed{k}.json` | Score normalisation and thresholds for each input-classifier seed | |
36
- | `eurosafeguard.py` | Single-file loader | |
 
37
 
38
  The five `gate/seed*` folders are the five training runs (same data, different seeds) that the paper reports as a mean.
39
  They vary, especially against search attacks such as PAIR, so evaluate the seed you deploy.
@@ -42,7 +42,14 @@ They vary, especially against search attacks such as PAIR, so evaluate the seed
42
  Integrity, Physical Harm, Privacy, Self-Harm, Sexual Content. `taxonomy_11heads_short.json` lists what each category
43
  allows and disallows.
44
 
45
- ## How it decides (alert-unless-CBRN)
 
 
 
 
 
 
 
46
 
47
  1. **Input stage.** The input score is the mean of the probe and input-classifier scores, each z-scored on
48
  WildChat-clean. Its threshold (`alert_input_thr`) flags 5% of WildChat-clean prompts.
@@ -64,6 +71,28 @@ if decision == "refuse" or g.check_reply(prompt, reply, decision):
64
  reply = "Sorry, I can't help with that."
65
  ```
66
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  **Requirements:** `torch`, `transformers` with Qwen3.5 support, `peft`, `safetensors`, `huggingface_hub`. About 16 GB of
68
  GPU memory for Llama-3.1-8B (the probe) plus about 19 GB for each Qwen3.5-9B classifier (input and exchange). Use
69
  `load_exchange=False` to run the input stage only. The probe reads Llama-3.1-8B-Instruct activations. If you protect
@@ -71,13 +100,18 @@ Llama-3.1-8B-Instruct itself, you can reuse the activations of its forward pass.
71
 
72
  ## Results (from the paper; every guard calibrated to the same false-positive budget on real chat traffic)
73
 
74
- - **BELLS-O:** our input classifiers detect more harmful prompts than any supervisor on the leaderboard at a
75
- false-positive rate near 1%, and have the highest recall on its held-out jailbreak sets.
 
 
 
 
 
76
  - **PAIR** (iterative black-box attack), input stage at the 5% WildChat-clean budget: 21% of the behaviors that break
77
  the unprotected model get through, against 49% for the best other open guard.
78
- - **Chemical and biological goals** transferred to three target models: at most 1.1% get through in every setting.
79
- - **Alert mode** (this release's rule) vs refusing every flagged request: refusals of benign sensitive requests fall
80
- from 37% to 5–9%, while at most 3.6% of chemical and biological goals get through on five protected models.
81
  - **Latency:** the full guardrail adds 1.5% to generation time on the requests it escalates.
82
 
83
  Numbers are means over the five input-classifier seeds; see the paper for the full tables, judges and budgets.
@@ -100,15 +134,17 @@ Numbers are means over the five input-classifier seeds; see the paper for the fu
100
  Our adapters, heads, probe and code are released under Apache-2.0. The base models keep their own licenses:
101
  [Llama 3.1 Community License](https://huggingface.co/meta-llama/Llama-3.1-8B-Instruct) for the probe's protected model,
102
  and the [Qwen license](https://huggingface.co/Qwen/Qwen3.5-9B) for the classifier backbones. Some training data is
103
- licensed for non-commercial use only; see the dataset cards.
104
 
105
  ## Citation
106
 
107
  ```bibtex
108
- @article{eurosafeguard2026,
109
- title = {EuroSafeAI Open Constitutional Classifiers},
110
- author = {Waibl, Leonhard and Chen, Yen-Shan and Simko, Samuel and others},
111
- journal = {arXiv preprint arXiv:TODO},
 
 
112
  year = {2026}
113
  }
114
  ```
 
21
  language model and the replies the model produces, and it is trained on data generated from a written constitution of
22
  eleven harm categories.
23
 
24
+ Paper: *EuroSafeGuard: Open Constitutional Classifiers* (arXiv: coming soon) · Code: coming soon ·
25
+ Training prompts: coming soon (gated access) · Project page: [guard.safe.eu](https://guard.safe.eu)
 
26
 
27
  ## Components
28
 
 
31
  | `probe/` | MLP probe (hidden size 256) on the activations of all 32 blocks of the protected model, reading the chat-formatted prompt; per-token logits are smoothed with an exponential moving average and the prompt score is their maximum | Llama-3.1-8B-Instruct |
32
  | `gate/seed{0..4}/` | Input classifier: LoRA adapter + one sigmoid head per harm category (11 heads); score = highest head | Qwen3.5-9B |
33
  | `exchange/` | Exchange classifier: reads `User: <prompt>\n\nAssistant: <reply>`; LoRA + 11 heads | Qwen3.5-9B |
34
+ | `thresholds/seed{k}.json` | Alert mode: score normalisation and thresholds for each input-classifier seed | |
35
+ | `thresholds/full_seed{k}.json` | Full mode: normalisation (probe, gate, exchange), probe escalation cut, weights and threshold for each seed | |
36
+ | `eurosafeguard.py` | Single-file loader with both modes | |
37
 
38
  The five `gate/seed*` folders are the five training runs (same data, different seeds) that the paper reports as a mean.
39
  They vary, especially against search attacks such as PAIR, so evaluate the seed you deploy.
 
42
  Integrity, Physical Harm, Privacy, Self-Harm, Sexual Content. `taxonomy_11heads_short.json` lists what each category
43
  allows and disallows.
44
 
45
+ ## Two modes
46
+
47
+ | Mode | Load with | Paper configuration | Paper tables |
48
+ |---|---|---|---|
49
+ | `alert` (default) | `mode="alert"` | EuroSafeGuard (Input) at the 5% WildChat-clean budget, plus alert-unless-CBRN and the exchange check | Held-out attacks (Input columns), alert mode ("Alert, strict exchange") |
50
+ | `full` | `mode="full"` | EuroSafeGuard (Full): probe escalation, weighted sum of probe, input and exchange scores | End-to-end table |
51
+
52
+ ### Alert mode (input/alert, alert-unless-CBRN)
53
 
54
  1. **Input stage.** The input score is the mean of the probe and input-classifier scores, each z-scored on
55
  WildChat-clean. Its threshold (`alert_input_thr`) flags 5% of WildChat-clean prompts.
 
71
  reply = "Sorry, I can't help with that."
72
  ```
73
 
74
+ ### Full mode (the paper's end-to-end configuration)
75
+
76
+ 1. **Probe screen.** The probe scores every request. Only requests whose probe z-score exceeds `probe_escalation_z`
77
+ (1.1644, the 90th percentile on WildChat-clean) are escalated; the rest are never blocked.
78
+ 2. **Escalated requests** are scored by the input classifier and, once the protected model has replied, by the exchange
79
+ classifier. The exchange is blocked if `0.6·probe_z + 0.2·input_z + 0.2·exchange_z > full_thr`.
80
+ 3. All three scores are z-scored on WildChat-clean (the exchange on Llama-3-8B-Instruct replies: μ = 0.02560,
81
+ σ = 0.09032). `full_thr` is the smallest threshold that keeps every benign calibration set under its cap (WildChat-clean,
82
+ MMLU, GSM8K, Alpaca, Dolly, OASST 0.5%; XSTest-safe, OR-Bench-80k 2%; OR-Bench-hard 5%; benign rows of styled
83
+ jailbreak sets 40%): 3.382 / 3.571 / 3.132 / 3.097 / 3.318 for seeds 0–4. It was fitted once on the undefended
84
+ Llama-3-8B-Instruct's traffic.
85
+
86
+ ```python
87
+ g = EuroSafeGuard.from_pretrained("EuroSafeAI/EuroSafeGuard", seed=0, mode="full", devices=("cuda:0", "cuda:0", "cuda:1"))
88
+ reply = ... # your protected model
89
+ if g.check_full(prompt, reply): # probe on every request; gate + exchange only if escalated
90
+ reply = "Sorry, I can't help with that."
91
+ ```
92
+
93
+ `full_block(probe, gate, exchange, cfg)` applies the same rule to precomputed raw scores. On the paper's stored scores it
94
+ reproduces the end-to-end attack success of every seed exactly (mean 3.88%).
95
+
96
  **Requirements:** `torch`, `transformers` with Qwen3.5 support, `peft`, `safetensors`, `huggingface_hub`. About 16 GB of
97
  GPU memory for Llama-3.1-8B (the probe) plus about 19 GB for each Qwen3.5-9B classifier (input and exchange). Use
98
  `load_exchange=False` to run the input stage only. The probe reads Llama-3.1-8B-Instruct activations. If you protect
 
100
 
101
  ## Results (from the paper; every guard calibrated to the same false-positive budget on real chat traffic)
102
 
103
+ - **End to end** (Full mode, Llama-3-8B-Instruct, 1,974 Jailbreak Foundry attacks on held-out GuidedBench behaviors):
104
+ attack success falls from 7.95% to 3.88% (EuroSafe-CC++, our reimplementation of Constitutional Classifiers++, 4.57%),
105
+ adding at most 3.2 points of benign failure on any of six benign benchmarks. On gpt-oss-20b: 13.17% → 5.28%.
106
+ - **Compute:** only the 10% of requests the probe escalates reach the two classifiers, so the guardrail adds 15% of the
107
+ protected model's FLOPs.
108
+ - **Held-out jailbreaks**, input stage at the 5% WildChat-clean budget: 95.9% recall on the BELLS-O jailbreak set
109
+ (88.2% for HaloGuard, the strongest open guard); highest recall on three of four held-out jailbreak sets.
110
  - **PAIR** (iterative black-box attack), input stage at the 5% WildChat-clean budget: 21% of the behaviors that break
111
  the unprotected model get through, against 49% for the best other open guard.
112
+ - **Chemical and biological goals** transferred to three protected models: the full guardrail lets through at most 1.4% of goals on any model.
113
+ - **Alert mode** (`mode="alert"`) vs refusing every flagged request: refusals of benign sensitive requests fall
114
+ from 37% to 5–16% on six protected models, while at most 3.6% of chemical and biological goals get through.
115
  - **Latency:** the full guardrail adds 1.5% to generation time on the requests it escalates.
116
 
117
  Numbers are means over the five input-classifier seeds; see the paper for the full tables, judges and budgets.
 
134
  Our adapters, heads, probe and code are released under Apache-2.0. The base models keep their own licenses:
135
  [Llama 3.1 Community License](https://huggingface.co/meta-llama/Llama-3.1-8B-Instruct) for the probe's protected model,
136
  and the [Qwen license](https://huggingface.co/Qwen/Qwen3.5-9B) for the classifier backbones. Some training data is
137
+ licensed for non-commercial use only.
138
 
139
  ## Citation
140
 
141
  ```bibtex
142
+ @article{waibl2026eurosafeguard,
143
+ title = {EuroSafeGuard: Open Constitutional Classifiers},
144
+ author = {Waibl, Leonhard and Chen, Yen-Shan and Simko, Samuel and Michalak, Felix and
145
+ Diwan, Nirav and Singh, Arth and Thomas, Aditya and
146
+ Sch{\"o}lkopf, Bernhard and Jin, Zhijing},
147
+ journal = {arXiv preprint},
148
  year = {2026}
149
  }
150
  ```
__pycache__/eurosafeguard.cpython-312.pyc DELETED
Binary file (20.1 kB)
 
eurosafeguard.py CHANGED
@@ -7,6 +7,11 @@
7
  system_message = g.system_note(category) # prepend to the protected model's context
8
  blocked = g.check_reply(prompt, reply, decision) # True -> withhold the reply
9
 
 
 
 
 
 
10
  Components (see README.md):
11
  probe MLP probe on Llama-3.1-8B-Instruct activations (all 32 blocks) of the chat-formatted prompt; per-token
12
  logits are smoothed with an EMA and the prompt score is their maximum.
@@ -16,6 +21,10 @@ Rule (alert-unless-CBRN): input score = mean of the probe and gate z-scores (z-s
16
  alert_input_thr (flags 5% of WildChat-clean): refuse if the gate's top category is CBRN, otherwise answer under an
17
  alert system note and block the reply if the exchange score exceeds exch_thr_20pct. Below: answer normally and block the
18
  reply if the exchange score exceeds exch_thr_1pct.
 
 
 
 
19
 
20
  Memory: Llama-3.1-8B (~16 GB bf16) + Qwen3.5-9B for the gate (~19 GB) + Qwen3.5-9B for the exchange classifier (~19 GB).
21
  Pass devices=("cuda:0", "cuda:1", "cuda:2") to spread them, or load_exchange=False to skip the reply check.
@@ -32,6 +41,22 @@ import torch
32
  import torch.nn as nn
33
  import torch.nn.functional as F
34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  HEADS = ["CBRN", "Cyber", "Harm to Minors", "Harmful Manipulation", "Hate Speech", "Illegal Activities",
36
  "Information Integrity", "Physical Harm", "Privacy", "Self-Harm", "Sexual Content"]
37
 
@@ -110,11 +135,16 @@ class LoRAClassifier:
110
 
111
  # ----------------------------------------------------------------------------------------------------- guard
112
  class EuroSafeGuard:
113
- def __init__(self, root: str, seed: int = 0, devices=("cuda", "cuda", "cuda"), load_exchange: bool = True):
 
114
  from safetensors.torch import load_file
115
  from transformers import AutoModelForCausalLM, AutoTokenizer
116
 
 
 
 
117
  self.c = json.load(open(os.path.join(root, "thresholds", f"seed{seed}.json")))
 
118
  self.tax = json.load(open(os.path.join(root, "taxonomy_11heads_short.json")))
119
  pc = json.load(open(os.path.join(root, "probe", "probe_config.json")))
120
  self.layers, self.M, self.max_len = pc["layers"], pc["M"], pc["max_len"]
@@ -133,7 +163,8 @@ class EuroSafeGuard:
133
  return cls(repo_or_path, seed, **kw)
134
  from huggingface_hub import snapshot_download
135
  root = snapshot_download(repo_or_path, allow_patterns=["probe/*", f"gate/seed{seed}/*", "exchange/*",
136
- f"thresholds/seed{seed}.json", "*.json", "*.py"])
 
137
  return cls(root, seed, **kw)
138
 
139
  # -- input stage
@@ -196,6 +227,39 @@ class EuroSafeGuard:
196
  t = [f"User: {a}\n\nAssistant: {b}" for a, b in zip(prompts, replies)]
197
  return self.exchange.probs(t).max(1)
198
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  def check_reply(self, prompt, reply, decision="pass"):
200
  """True if the reply should be withheld. Stricter threshold for replies to alerted requests."""
201
  single = isinstance(prompt, str)
 
7
  system_message = g.system_note(category) # prepend to the protected model's context
8
  blocked = g.check_reply(prompt, reply, decision) # True -> withhold the reply
9
 
10
+ # Full mode: the configuration of the paper's end-to-end table (EuroSafeGuard (Full)).
11
+ g = EuroSafeGuard.from_pretrained("EuroSafeAI/EuroSafeGuard", seed=0, mode="full")
12
+ escalated = g.escalate(prompt) # probe-only check, before generation
13
+ blocked = g.check_full(prompt, reply) # True -> withhold the reply
14
+
15
  Components (see README.md):
16
  probe MLP probe on Llama-3.1-8B-Instruct activations (all 32 blocks) of the chat-formatted prompt; per-token
17
  logits are smoothed with an EMA and the prompt score is their maximum.
 
21
  alert_input_thr (flags 5% of WildChat-clean): refuse if the gate's top category is CBRN, otherwise answer under an
22
  alert system note and block the reply if the exchange score exceeds exch_thr_20pct. Below: answer normally and block the
23
  reply if the exchange score exceeds exch_thr_1pct.
24
+ Rule (full, thresholds/full_seed*.json; reproduces the paper's end-to-end numbers): z-score probe, gate and exchange
25
+ on WildChat-clean. Only requests whose probe z exceeds probe_escalation_z (the WildChat-clean 90th percentile) are
26
+ escalated; an escalated exchange is blocked if 0.6*probe_z + 0.2*gate_z + 0.2*exchange_z > full_thr. Non-escalated
27
+ requests are never blocked, so the gate and the exchange classifier run only on escalated traffic.
28
 
29
  Memory: Llama-3.1-8B (~16 GB bf16) + Qwen3.5-9B for the gate (~19 GB) + Qwen3.5-9B for the exchange classifier (~19 GB).
30
  Pass devices=("cuda:0", "cuda:1", "cuda:2") to spread them, or load_exchange=False to skip the reply check.
 
41
  import torch.nn as nn
42
  import torch.nn.functional as F
43
 
44
+ W_FULL = np.array([0.6, 0.2, 0.2]) # probe, gate, exchange
45
+
46
+
47
+ def full_block(probe, gate, exch, cfg) -> np.ndarray:
48
+ """Full-mode decision from raw scores (probe EMA-max logit, gate max-head prob, exchange max-head prob).
49
+ True -> block. Mirrors scripts/e2e_compose_ext.py: score = W.z if probe_z > probe_escalation_z else -inf;
50
+ blocked if score > full_thr. Pass NaN (or anything) for gate/exch of non-escalated items; they are not used."""
51
+ Z = np.c_[(np.asarray(probe, dtype=float) - cfg["probe_mu"]) / cfg["probe_sd"],
52
+ (np.asarray(gate, dtype=float) - cfg["gate_mu"]) / cfg["gate_sd"],
53
+ (np.asarray(exch, dtype=float) - cfg["exch_mu"]) / cfg["exch_sd"]]
54
+ esc = Z[:, 0] > cfg["probe_escalation_z"]
55
+ score = np.full(len(Z), -np.inf)
56
+ score[esc] = Z[esc] @ W_FULL
57
+ return score > cfg["full_thr"]
58
+
59
+
60
  HEADS = ["CBRN", "Cyber", "Harm to Minors", "Harmful Manipulation", "Hate Speech", "Illegal Activities",
61
  "Information Integrity", "Physical Harm", "Privacy", "Self-Harm", "Sexual Content"]
62
 
 
135
 
136
  # ----------------------------------------------------------------------------------------------------- guard
137
  class EuroSafeGuard:
138
+ def __init__(self, root: str, seed: int = 0, devices=("cuda", "cuda", "cuda"), load_exchange: bool = True,
139
+ mode: str = "alert"):
140
  from safetensors.torch import load_file
141
  from transformers import AutoModelForCausalLM, AutoTokenizer
142
 
143
+ if mode not in ("alert", "full"):
144
+ raise ValueError("mode must be 'alert' (input/alert rule) or 'full' (end-to-end rule)")
145
+ self.mode = mode
146
  self.c = json.load(open(os.path.join(root, "thresholds", f"seed{seed}.json")))
147
+ self.cf = json.load(open(os.path.join(root, "thresholds", f"full_seed{seed}.json"))) if mode == "full" else None
148
  self.tax = json.load(open(os.path.join(root, "taxonomy_11heads_short.json")))
149
  pc = json.load(open(os.path.join(root, "probe", "probe_config.json")))
150
  self.layers, self.M, self.max_len = pc["layers"], pc["M"], pc["max_len"]
 
163
  return cls(repo_or_path, seed, **kw)
164
  from huggingface_hub import snapshot_download
165
  root = snapshot_download(repo_or_path, allow_patterns=["probe/*", f"gate/seed{seed}/*", "exchange/*",
166
+ f"thresholds/seed{seed}.json",
167
+ f"thresholds/full_seed{seed}.json", "*.json", "*.py"])
168
  return cls(root, seed, **kw)
169
 
170
  # -- input stage
 
227
  t = [f"User: {a}\n\nAssistant: {b}" for a, b in zip(prompts, replies)]
228
  return self.exchange.probs(t).max(1)
229
 
230
+ # -- full mode (paper's end-to-end configuration)
231
+ def _need_full(self):
232
+ if self.cf is None:
233
+ raise RuntimeError("load with mode='full'")
234
+
235
+ def escalate(self, prompt):
236
+ """Probe-only escalation check (full mode): True if probe z > probe_escalation_z."""
237
+ self._need_full()
238
+ single = isinstance(prompt, str)
239
+ P = [prompt] if single else list(prompt)
240
+ e = (self.probe_scores(P) - self.cf["probe_mu"]) / self.cf["probe_sd"] > self.cf["probe_escalation_z"]
241
+ out = [bool(x) for x in e]
242
+ return out[0] if single else out
243
+
244
+ def full_scores(self, prompts: list[str], replies: list[str]) -> np.ndarray:
245
+ """-> raw [N, 3] (probe, gate, exchange); gate and exchange are NaN for non-escalated items."""
246
+ self._need_full()
247
+ p = self.probe_scores(list(prompts))
248
+ esc = np.flatnonzero((p - self.cf["probe_mu"]) / self.cf["probe_sd"] > self.cf["probe_escalation_z"])
249
+ R = np.full((len(p), 3), np.nan); R[:, 0] = p
250
+ if len(esc):
251
+ R[esc, 1] = self.gate.probs([prompts[i] for i in esc]).max(1)
252
+ R[esc, 2] = self.exchange_scores([prompts[i] for i in esc], [replies[i] for i in esc])
253
+ return R
254
+
255
+ def check_full(self, prompt, reply):
256
+ """Full mode: True if the exchange (prompt, reply) should be blocked."""
257
+ single = isinstance(prompt, str)
258
+ P, Rp = ([prompt], [reply]) if single else (list(prompt), list(reply))
259
+ R = self.full_scores(P, Rp)
260
+ out = [bool(x) for x in full_block(R[:, 0], R[:, 1], R[:, 2], self.cf)]
261
+ return out[0] if single else out
262
+
263
  def check_reply(self, prompt, reply, decision="pass"):
264
  """True if the reply should be withheld. Stricter threshold for replies to alerted requests."""
265
  single = isinstance(prompt, str)
thresholds/full_seed0.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "probe_mu": -6.815694701503735,
3
+ "probe_sd": 3.444286874679132,
4
+ "gate_mu": 0.03333534521305959,
5
+ "gate_sd": 0.10919123782498313,
6
+ "exch_mu": 0.02559613844389501,
7
+ "exch_sd": 0.090324355434096,
8
+ "probe_escalation_z": 1.164447941601081,
9
+ "probe_escalation_quantile": 0.9,
10
+ "weights": {
11
+ "probe": 0.6,
12
+ "gate": 0.2,
13
+ "exchange": 0.2
14
+ },
15
+ "full_thr": 3.3815571671026943,
16
+ "calibration": "EuroSafeGuard (Full), the configuration of the paper's end-to-end table. All z-scores use the mean and standard deviation on WildChat-clean (6,853 conversations); the exchange statistics use the exchange classifier's max-head probability on Llama-3-8B-Instruct replies to them. A request is escalated if its probe z exceeds probe_escalation_z (the WildChat-clean 90th percentile); an escalated exchange is blocked if 0.6*probe_z + 0.2*gate_z + 0.2*exchange_z > full_thr. full_thr is the smallest threshold that keeps every benign calibration set under its cap (fit half): WildChat-clean, MMLU, GSM8K, Alpaca, Dolly, OASST 0.5%; XSTest-safe, OR-Bench-80k 2%; OR-Bench-hard 5%; benign rows of styled jailbreak sets 40%. Reproduces scripts/e2e_compose_ext.py.",
17
+ "seed": 0
18
+ }
thresholds/full_seed1.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "probe_mu": -6.815694701503735,
3
+ "probe_sd": 3.444286874679132,
4
+ "gate_mu": 0.02970501206685616,
5
+ "gate_sd": 0.11025653741405626,
6
+ "exch_mu": 0.02559613844389501,
7
+ "exch_sd": 0.090324355434096,
8
+ "probe_escalation_z": 1.164447941601081,
9
+ "probe_escalation_quantile": 0.9,
10
+ "weights": {
11
+ "probe": 0.6,
12
+ "gate": 0.2,
13
+ "exchange": 0.2
14
+ },
15
+ "full_thr": 3.5707621643975536,
16
+ "calibration": "EuroSafeGuard (Full), the configuration of the paper's end-to-end table. All z-scores use the mean and standard deviation on WildChat-clean (6,853 conversations); the exchange statistics use the exchange classifier's max-head probability on Llama-3-8B-Instruct replies to them. A request is escalated if its probe z exceeds probe_escalation_z (the WildChat-clean 90th percentile); an escalated exchange is blocked if 0.6*probe_z + 0.2*gate_z + 0.2*exchange_z > full_thr. full_thr is the smallest threshold that keeps every benign calibration set under its cap (fit half): WildChat-clean, MMLU, GSM8K, Alpaca, Dolly, OASST 0.5%; XSTest-safe, OR-Bench-80k 2%; OR-Bench-hard 5%; benign rows of styled jailbreak sets 40%. Reproduces scripts/e2e_compose_ext.py.",
17
+ "seed": 1
18
+ }
thresholds/full_seed2.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "probe_mu": -6.815694701503735,
3
+ "probe_sd": 3.444286874679132,
4
+ "gate_mu": 0.03268957031742354,
5
+ "gate_sd": 0.12878089011617874,
6
+ "exch_mu": 0.02559613844389501,
7
+ "exch_sd": 0.090324355434096,
8
+ "probe_escalation_z": 1.164447941601081,
9
+ "probe_escalation_quantile": 0.9,
10
+ "weights": {
11
+ "probe": 0.6,
12
+ "gate": 0.2,
13
+ "exchange": 0.2
14
+ },
15
+ "full_thr": 3.131896552703142,
16
+ "calibration": "EuroSafeGuard (Full), the configuration of the paper's end-to-end table. All z-scores use the mean and standard deviation on WildChat-clean (6,853 conversations); the exchange statistics use the exchange classifier's max-head probability on Llama-3-8B-Instruct replies to them. A request is escalated if its probe z exceeds probe_escalation_z (the WildChat-clean 90th percentile); an escalated exchange is blocked if 0.6*probe_z + 0.2*gate_z + 0.2*exchange_z > full_thr. full_thr is the smallest threshold that keeps every benign calibration set under its cap (fit half): WildChat-clean, MMLU, GSM8K, Alpaca, Dolly, OASST 0.5%; XSTest-safe, OR-Bench-80k 2%; OR-Bench-hard 5%; benign rows of styled jailbreak sets 40%. Reproduces scripts/e2e_compose_ext.py.",
17
+ "seed": 2
18
+ }
thresholds/full_seed3.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "probe_mu": -6.815694701503735,
3
+ "probe_sd": 3.444286874679132,
4
+ "gate_mu": 0.03866907581677466,
5
+ "gate_sd": 0.13433606451867683,
6
+ "exch_mu": 0.02559613844389501,
7
+ "exch_sd": 0.090324355434096,
8
+ "probe_escalation_z": 1.164447941601081,
9
+ "probe_escalation_quantile": 0.9,
10
+ "weights": {
11
+ "probe": 0.6,
12
+ "gate": 0.2,
13
+ "exchange": 0.2
14
+ },
15
+ "full_thr": 3.097429574322379,
16
+ "calibration": "EuroSafeGuard (Full), the configuration of the paper's end-to-end table. All z-scores use the mean and standard deviation on WildChat-clean (6,853 conversations); the exchange statistics use the exchange classifier's max-head probability on Llama-3-8B-Instruct replies to them. A request is escalated if its probe z exceeds probe_escalation_z (the WildChat-clean 90th percentile); an escalated exchange is blocked if 0.6*probe_z + 0.2*gate_z + 0.2*exchange_z > full_thr. full_thr is the smallest threshold that keeps every benign calibration set under its cap (fit half): WildChat-clean, MMLU, GSM8K, Alpaca, Dolly, OASST 0.5%; XSTest-safe, OR-Bench-80k 2%; OR-Bench-hard 5%; benign rows of styled jailbreak sets 40%. Reproduces scripts/e2e_compose_ext.py.",
17
+ "seed": 3
18
+ }
thresholds/full_seed4.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "probe_mu": -6.815694701503735,
3
+ "probe_sd": 3.444286874679132,
4
+ "gate_mu": 0.020549819204687854,
5
+ "gate_sd": 0.1115630808512582,
6
+ "exch_mu": 0.02559613844389501,
7
+ "exch_sd": 0.090324355434096,
8
+ "probe_escalation_z": 1.164447941601081,
9
+ "probe_escalation_quantile": 0.9,
10
+ "weights": {
11
+ "probe": 0.6,
12
+ "gate": 0.2,
13
+ "exchange": 0.2
14
+ },
15
+ "full_thr": 3.318287213890092,
16
+ "calibration": "EuroSafeGuard (Full), the configuration of the paper's end-to-end table. All z-scores use the mean and standard deviation on WildChat-clean (6,853 conversations); the exchange statistics use the exchange classifier's max-head probability on Llama-3-8B-Instruct replies to them. A request is escalated if its probe z exceeds probe_escalation_z (the WildChat-clean 90th percentile); an escalated exchange is blocked if 0.6*probe_z + 0.2*gate_z + 0.2*exchange_z > full_thr. full_thr is the smallest threshold that keeps every benign calibration set under its cap (fit half): WildChat-clean, MMLU, GSM8K, Alpaca, Dolly, OASST 0.5%; XSTest-safe, OR-Bench-80k 2%; OR-Bench-hard 5%; benign rows of styled jailbreak sets 40%. Reproduces scripts/e2e_compose_ext.py.",
17
+ "seed": 4
18
+ }