Text Classification
GLiNER2
Safetensors
English
decision-model
calibration
selective-prediction
conformal-prediction
abstention
risk-aware
security
cybersecurity
security-operations
soc
pentest
red-team
blue-team
Eval Results (legacy)
Instructions to use TyrusRC/haruspex with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- GLiNER2
How to use TyrusRC/haruspex with GLiNER2:
from gliner2 import AutoExtractor extractor = AutoExtractor.from_pretrained("TyrusRC/haruspex") # Extract entities text = "Apple CEO Tim Cook announced iPhone 15 in Cupertino yesterday." result = extractor.extract_entities(text, ["company", "person", "product", "location"]) print(result) - Notebooks
- Google Colab
- Kaggle
Update network adapter
Browse files- network/README.md +124 -0
- network/calibrator.json +7 -2
- network/eval.json +27 -5
- network/final/adapter_config.json +11 -11
- network/final/adapter_model.safetensors +1 -1
- network/ood.json +1 -0
- network/ood_train.npy +3 -0
network/README.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: apache-2.0
|
| 3 |
+
library_name: gliner2
|
| 4 |
+
pipeline_tag: text-classification
|
| 5 |
+
language:
|
| 6 |
+
- en
|
| 7 |
+
tags:
|
| 8 |
+
- decision-model
|
| 9 |
+
- calibration
|
| 10 |
+
- selective-prediction
|
| 11 |
+
- conformal-prediction
|
| 12 |
+
- abstention
|
| 13 |
+
- risk-aware
|
| 14 |
+
- security
|
| 15 |
+
- cybersecurity
|
| 16 |
+
- security-operations
|
| 17 |
+
- soc
|
| 18 |
+
- pentest
|
| 19 |
+
- red-team
|
| 20 |
+
- blue-team
|
| 21 |
+
- gliner2
|
| 22 |
+
base_model: fastino/GLiNER2.5-Decide
|
| 23 |
+
metrics:
|
| 24 |
+
- accuracy
|
| 25 |
+
model-index:
|
| 26 |
+
- name: haruspex
|
| 27 |
+
results:
|
| 28 |
+
- task:
|
| 29 |
+
type: text-classification
|
| 30 |
+
name: Security decision (boolean / choice / score)
|
| 31 |
+
dataset:
|
| 32 |
+
type: custom
|
| 33 |
+
name: network pack test split (71 rows)
|
| 34 |
+
metrics:
|
| 35 |
+
- type: accuracy
|
| 36 |
+
value: 0.9437
|
| 37 |
+
name: accuracy
|
| 38 |
+
- type: ece
|
| 39 |
+
value: 0.0224
|
| 40 |
+
name: ece
|
| 41 |
+
- type: brier
|
| 42 |
+
value: 0.0191
|
| 43 |
+
name: brier
|
| 44 |
+
---
|
| 45 |
+
|
| 46 |
+
# TyrusRC/haruspex (network)
|
| 47 |
+
|
| 48 |
+
**Haruspex** is a small, local **decision layer** for security operations. It reads a
|
| 49 |
+
situation and returns a *calibrated* typed verdict — **boolean** (yes/no + probability),
|
| 50 |
+
**choice** (pick one option), **score** (rate on a rubric) — and **abstains** when it is
|
| 51 |
+
not confident enough for your risk budget.
|
| 52 |
+
|
| 53 |
+
Haruspex **reuses** the published decision encoder
|
| 54 |
+
[`fastino/GLiNER2.5-Decide`](https://huggingface.co/fastino/GLiNER2.5-Decide) (Apache-2.0, non-autoregressive, CPU/GPU) and
|
| 55 |
+
specializes it on security decisions. It does not train a decision model from scratch.
|
| 56 |
+
|
| 57 |
+
- Base: `fastino/GLiNER2.5-Decide`.
|
| 58 |
+
- Added: a typed decision contract, security specialization data, a certified
|
| 59 |
+
**selective-calibration** layer (accept/abstain against a risk budget), conformal
|
| 60 |
+
**prediction sets**, and a **novelty gate** that abstains on unfamiliar input.
|
| 61 |
+
- Serves the TypeSafe `POST /v1/systemone` and native `/v1/evaluate` contracts.
|
| 62 |
+
|
| 63 |
+
## Intended use (security, both sides)
|
| 64 |
+
|
| 65 |
+
- **Offensive (pentest / red-team):** is this template/probe relevant to the target?
|
| 66 |
+
is this scanner hit a real finding? finding severity; verdict discipline
|
| 67 |
+
(vulnerable / not-vulnerable / inconclusive); attack-path next step.
|
| 68 |
+
- **Defensive (SOC / blue-team):** alert and incident triage (true / benign / false
|
| 69 |
+
positive), alert severity/priority, detection-rule applicability, incident routing, CVE
|
| 70 |
+
applicability, ATT&CK tactic of Windows/Sysmon events. Raw Defender, Sentinel, Elastic
|
| 71 |
+
ECS and Windows event JSON is normalised before the model reads it.
|
| 72 |
+
|
| 73 |
+
It is a classifier for bounded decisions — not a chatbot, not an exploit generator.
|
| 74 |
+
|
| 75 |
+
## Use
|
| 76 |
+
|
| 77 |
+
```python
|
| 78 |
+
from haruspex import Haruspex
|
| 79 |
+
m = Haruspex.load("TyrusRC/haruspex", subfolder="network", device="cuda") # or "mps" / "cpu"
|
| 80 |
+
print(m.decide({"type":"boolean","state":"Target: WordPress 6.2, PHP 8.1",
|
| 81 |
+
"question":"Is a WordPress xmlrpc.php template relevant?",
|
| 82 |
+
"criteria":{"true":"WordPress target","false":"not WordPress"}}))
|
| 83 |
+
```
|
| 84 |
+
|
| 85 |
+
Or serve the decision API (keyless, self-hosted):
|
| 86 |
+
|
| 87 |
+
```sh
|
| 88 |
+
pip install "haruspex[serve] @ git+https://github.com/TyrusRC/haruspex"
|
| 89 |
+
haruspex-serve --adapters network=TyrusRC/haruspex#network --port 3000 # POST /v1/systemone · /v1/evaluate
|
| 90 |
+
```
|
| 91 |
+
|
| 92 |
+
## Calibration
|
| 93 |
+
|
| 94 |
+
Fitted calibrator: accept threshold `0.0`, target risk `0.2` at delta `0.1`, coverage on the calibration split `1.0` (n=44), temperature `1.0`.
|
| 95 |
+
|
| 96 |
+
Each verdict carries the full probability distribution over its options (temperature-
|
| 97 |
+
scaled). A Learn-then-Test selective layer accepts a verdict only when its confidence
|
| 98 |
+
clears a threshold certified on a held-out calibration split, so that with probability
|
| 99 |
+
1 - delta the error among accepted verdicts stays within the target risk; otherwise it
|
| 100 |
+
abstains with `"route": "escalate"`. A conformal prediction set lists the options the
|
| 101 |
+
true answer is among, and a novelty gate abstains on inputs unlike the training data.
|
| 102 |
+
Fit with `python -m haruspex.calibrate` and `python -m haruspex.ood`; evaluate with
|
| 103 |
+
`python -m haruspex.eval`.
|
| 104 |
+
|
| 105 |
+
## Evaluation
|
| 106 |
+
|
| 107 |
+
Held-out test sets, never used for training, model selection or calibration:
|
| 108 |
+
|
| 109 |
+
- **network pack test split (71 rows)**: accuracy 0.9437, ECE 0.0224, Brier 0.0191; with the calibrator it answers 1.0 of rows at accuracy 0.971 and abstains on the rest.
|
| 110 |
+
|
| 111 |
+
Comparisons against general LLMs are in the repo's `docs/benchmark.md`.
|
| 112 |
+
|
| 113 |
+
## Limitations
|
| 114 |
+
|
| 115 |
+
- A specialist for the decision types above; novel free-form judgments belong to a
|
| 116 |
+
general LLM.
|
| 117 |
+
- Calibrated on this domain's held-out split; recalibrate before relying on the
|
| 118 |
+
guarantee on your own data.
|
| 119 |
+
- Prediction-set coverage is marginal over the calibration mix, not per input.
|
| 120 |
+
- A calibrator fitted on a mix of domains holds its risk target on average over that
|
| 121 |
+
mix, not on each domain: check each test set's accepted accuracy under Evaluation,
|
| 122 |
+
and route a domain with its own adapter to that adapter.
|
| 123 |
+
|
| 124 |
+
Apache-2.0. Repo + recipe: https://github.com/TyrusRC/haruspex
|
network/calibrator.json
CHANGED
|
@@ -1,7 +1,12 @@
|
|
| 1 |
{
|
| 2 |
-
"threshold":
|
| 3 |
"target_risk": 0.2,
|
| 4 |
"achieved_risk": 0.0,
|
| 5 |
"coverage": 1.0,
|
| 6 |
-
"n": 44
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
}
|
|
|
|
| 1 |
{
|
| 2 |
+
"threshold": 0.0,
|
| 3 |
"target_risk": 0.2,
|
| 4 |
"achieved_risk": 0.0,
|
| 5 |
"coverage": 1.0,
|
| 6 |
+
"n": 44,
|
| 7 |
+
"delta": 0.1,
|
| 8 |
+
"temperature": 1.0,
|
| 9 |
+
"temperature_scope": "all",
|
| 10 |
+
"set_q": 0.0,
|
| 11 |
+
"set_alpha": 0.1
|
| 12 |
}
|
network/eval.json
CHANGED
|
@@ -1,7 +1,29 @@
|
|
| 1 |
{
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
}
|
|
|
|
| 1 |
{
|
| 2 |
+
"n": 71,
|
| 3 |
+
"accuracy": 0.9437,
|
| 4 |
+
"accuracy_ci95": [
|
| 5 |
+
0.8639,
|
| 6 |
+
0.9779
|
| 7 |
+
],
|
| 8 |
+
"brier": 0.0191,
|
| 9 |
+
"ece": 0.0224,
|
| 10 |
+
"ece_adaptive": 0.0224,
|
| 11 |
+
"p50_ms": 43.2,
|
| 12 |
+
"by_source": {
|
| 13 |
+
"model": {
|
| 14 |
+
"n": 69,
|
| 15 |
+
"accuracy": 0.971
|
| 16 |
+
},
|
| 17 |
+
"model_declined": {
|
| 18 |
+
"n": 2,
|
| 19 |
+
"accuracy": 0.0
|
| 20 |
+
}
|
| 21 |
+
},
|
| 22 |
+
"selective": {
|
| 23 |
+
"coverage": 1.0,
|
| 24 |
+
"accepted_accuracy": 0.971,
|
| 25 |
+
"accepted_risk": 0.029
|
| 26 |
+
},
|
| 27 |
+
"test_n": 71,
|
| 28 |
+
"dataset": "network pack test split"
|
| 29 |
}
|
network/final/adapter_config.json
CHANGED
|
@@ -35,22 +35,22 @@
|
|
| 35 |
"rank_pattern": {},
|
| 36 |
"revision": null,
|
| 37 |
"target_modules": [
|
|
|
|
|
|
|
| 38 |
"project_end.0",
|
| 39 |
-
"
|
| 40 |
-
"
|
| 41 |
"project_start.3",
|
|
|
|
|
|
|
| 42 |
"classifier.0",
|
| 43 |
-
"query_proj",
|
| 44 |
"project_start.0",
|
| 45 |
-
"classifier.2",
|
| 46 |
-
"project_end.3",
|
| 47 |
-
"value_proj",
|
| 48 |
-
"projector.2",
|
| 49 |
-
"count_pred.2",
|
| 50 |
-
"count_pred.0",
|
| 51 |
"out_project.3",
|
| 52 |
-
"
|
| 53 |
-
"
|
|
|
|
|
|
|
|
|
|
| 54 |
],
|
| 55 |
"target_parameters": null,
|
| 56 |
"task_type": null,
|
|
|
|
| 35 |
"rank_pattern": {},
|
| 36 |
"revision": null,
|
| 37 |
"target_modules": [
|
| 38 |
+
"dense",
|
| 39 |
+
"count_pred.0",
|
| 40 |
"project_end.0",
|
| 41 |
+
"projector.2",
|
| 42 |
+
"classifier.2",
|
| 43 |
"project_start.3",
|
| 44 |
+
"count_pred.2",
|
| 45 |
+
"project_end.3",
|
| 46 |
"classifier.0",
|
|
|
|
| 47 |
"project_start.0",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
"out_project.3",
|
| 49 |
+
"out_project.0",
|
| 50 |
+
"value_proj",
|
| 51 |
+
"key_proj",
|
| 52 |
+
"query_proj",
|
| 53 |
+
"projector.0"
|
| 54 |
],
|
| 55 |
"target_parameters": null,
|
| 56 |
"task_type": null,
|
network/final/adapter_model.safetensors
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
size 31766440
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:16492ad29e1aa1b73c5cf86b439509c9c8297de41f791a0d71281a53c137f7dd
|
| 3 |
size 31766440
|
network/ood.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"alpha": 0.01, "dim": 2048, "cal_scores": [0.552101, 0.59451, 0.595525, 0.604385, 0.611636, 0.623373, 0.652501, 0.653637, 0.658146, 0.659068, 0.663924, 0.66851, 0.683587, 0.68777, 0.688723, 0.696749, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]}
|
network/ood_train.npy
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f856616e0c5713e73b552902f8009aea7addc0b3e34bf6f7b09593120ed284e8
|
| 3 |
+
size 1147008
|