Update README with full benchmark results and metadata
Browse files
README.md
CHANGED
|
@@ -1,144 +1,260 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
# Arcspan β Cybersecurity NER via Fine-tuned OpenAI Privacy Filter
|
| 2 |
|
| 3 |
-
**Arcspan**
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
|
| 5 |
---
|
| 6 |
|
| 7 |
-
##
|
| 8 |
|
| 9 |
-
|
| 10 |
|
| 11 |
-
|
| 12 |
|
| 13 |
---
|
| 14 |
|
| 15 |
-
##
|
| 16 |
|
| 17 |
| Property | Value |
|
| 18 |
|---|---|
|
| 19 |
-
|
|
| 20 |
-
| Total
|
|
|
|
| 21 |
| Experts | 128 total, 4 active per token |
|
| 22 |
-
| Context window | 128K tokens (effective window 257 tokens via banded attention) |
|
| 23 |
-
| d_model | 640 |
|
| 24 |
| Layers | 8 transformer blocks |
|
|
|
|
| 25 |
| Attention | Grouped-query (14 Q heads, 2 KV heads), RoPE |
|
|
|
|
| 26 |
| Decoding | Constrained Viterbi (BIOES transition enforcement) |
|
|
|
|
| 27 |
| License | Apache 2.0 |
|
| 28 |
|
| 29 |
---
|
| 30 |
|
| 31 |
-
## Label Space
|
|
|
|
|
|
|
| 32 |
|
| 33 |
-
| Label |
|
| 34 |
|---|---|
|
| 35 |
-
| `Malware` | Malware families, ransomware, trojans, backdoors, campaigns |
|
| 36 |
-
| `Indicator` | IOCs β IPs, domains, URLs, file hashes, file paths, registry keys |
|
| 37 |
| `System` | Operating systems, software, platforms, infrastructure components |
|
| 38 |
| `Organization` | Threat actors, APT groups, vendors, affected organizations |
|
| 39 |
| `Vulnerability` | CVEs, exploit names, vulnerability descriptions |
|
| 40 |
|
| 41 |
---
|
| 42 |
|
| 43 |
-
##
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
-
###
|
| 46 |
-
A sanity-check fine-tune on a small subset to validate the training pipeline end-to-end.
|
| 47 |
|
| 48 |
-
|
| 49 |
-
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
|
| 56 |
-
###
|
| 57 |
-
The R8 training run β a serious multi-source fine-tune on the full 5-class cybersecurity NER label space.
|
| 58 |
|
| 59 |
-
|
| 60 |
-
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
|
| 66 |
---
|
| 67 |
|
| 68 |
-
##
|
| 69 |
|
| 70 |
-
|
| 71 |
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
|
| 75 |
-
|
|
| 76 |
-
|
|
| 77 |
-
|
|
| 78 |
-
|
|
| 79 |
-
|
|
| 80 |
-
|
|
| 81 |
-
|
|
| 82 |
-
|
|
| 83 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 84 |
|
| 85 |
---
|
| 86 |
|
| 87 |
-
##
|
| 88 |
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
|
|
|
|
|
|
| 107 |
|
| 108 |
---
|
| 109 |
|
| 110 |
## Usage
|
| 111 |
|
| 112 |
```bash
|
| 113 |
-
# Install
|
| 114 |
pip install -e vendor/privacy-filter
|
| 115 |
|
| 116 |
-
# Run inference with
|
| 117 |
-
opf --checkpoint checkpoints/r8_5class/epoch_4 --device cpu
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 118 |
|
| 119 |
-
|
| 120 |
-
|
|
|
|
|
|
|
| 121 |
|
| 122 |
-
|
| 123 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 124 |
```
|
| 125 |
|
| 126 |
---
|
| 127 |
|
| 128 |
-
##
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 129 |
|
| 130 |
-
|
| 131 |
|
| 132 |
-
|
|
|
|
|
|
|
|
|
|
| 133 |
|
| 134 |
---
|
| 135 |
|
| 136 |
-
##
|
|
|
|
|
|
|
| 137 |
|
| 138 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 139 |
|
| 140 |
---
|
| 141 |
|
| 142 |
## License
|
| 143 |
|
| 144 |
-
|
|
|
|
| 1 |
+
---
|
| 2 |
+
language:
|
| 3 |
+
- en
|
| 4 |
+
license: apache-2.0
|
| 5 |
+
tags:
|
| 6 |
+
- named-entity-recognition
|
| 7 |
+
- cybersecurity
|
| 8 |
+
- token-classification
|
| 9 |
+
- ner
|
| 10 |
+
- threat-intelligence
|
| 11 |
+
- ioc-extraction
|
| 12 |
+
- moe
|
| 13 |
+
- span-detection
|
| 14 |
+
base_model: openai/privacy-filter
|
| 15 |
+
pipeline_tag: token-classification
|
| 16 |
+
---
|
| 17 |
+
|
| 18 |
# Arcspan β Cybersecurity NER via Fine-tuned OpenAI Privacy Filter
|
| 19 |
|
| 20 |
+
**Arcspan** fine-tunes [OpenAI's Privacy Filter](https://huggingface.co/openai/privacy-filter) β a 1.5B-parameter sparse MoE bidirectional token classifier β for **cybersecurity entity extraction** from threat intelligence reports.
|
| 21 |
+
|
| 22 |
+
The key insight: the Privacy Filter's label space is fully replaceable. By swapping the output head and fine-tuning on cybersecurity NER data, we get a model that extracts IOCs, malware names, CVEs, threat actors, and affected systems β at **50M active parameters** (11Γ fewer than the CyNER baseline at 560M dense params).
|
| 23 |
+
|
| 24 |
+
> **TL;DR:** Same task as CyNER, fraction of the compute, fully local/offline.
|
| 25 |
|
| 26 |
---
|
| 27 |
|
| 28 |
+
## Why this exists
|
| 29 |
|
| 30 |
+
SOC teams and threat intelligence platforms need fast, local IOC extraction. Existing tools like CyNER use large dense transformers β expensive to run, can't be deployed on-prem without significant hardware, and can't process sensitive reports that shouldn't leave the network.
|
| 31 |
|
| 32 |
+
The Privacy Filter's sparse MoE architecture activates only 50M of its 1.5B parameters per token, making it fast enough for real workloads while maintaining strong accuracy on the entity types that matter most.
|
| 33 |
|
| 34 |
---
|
| 35 |
|
| 36 |
+
## Model Architecture
|
| 37 |
|
| 38 |
| Property | Value |
|
| 39 |
|---|---|
|
| 40 |
+
| Base model | [openai/privacy-filter](https://huggingface.co/openai/privacy-filter) |
|
| 41 |
+
| Total parameters | 1.5B |
|
| 42 |
+
| Active parameters (per token) | ~50M (top-4 MoE routing) |
|
| 43 |
| Experts | 128 total, 4 active per token |
|
|
|
|
|
|
|
| 44 |
| Layers | 8 transformer blocks |
|
| 45 |
+
| Hidden size | 640 |
|
| 46 |
| Attention | Grouped-query (14 Q heads, 2 KV heads), RoPE |
|
| 47 |
+
| Context window | 128K tokens (effective: 257-token banded window) |
|
| 48 |
| Decoding | Constrained Viterbi (BIOES transition enforcement) |
|
| 49 |
+
| Precision | bfloat16 |
|
| 50 |
| License | Apache 2.0 |
|
| 51 |
|
| 52 |
---
|
| 53 |
|
| 54 |
+
## Label Space
|
| 55 |
+
|
| 56 |
+
5-class cybersecurity NER schema using BIOES tagging:
|
| 57 |
|
| 58 |
+
| Label | What it covers |
|
| 59 |
|---|---|
|
| 60 |
+
| `Malware` | Malware families, ransomware, trojans, backdoors, botnets, campaigns |
|
| 61 |
+
| `Indicator` | IOCs β IPs, domains, URLs, file hashes, file paths, registry keys, email addresses |
|
| 62 |
| `System` | Operating systems, software, platforms, infrastructure components |
|
| 63 |
| `Organization` | Threat actors, APT groups, vendors, affected organizations |
|
| 64 |
| `Vulnerability` | CVEs, exploit names, vulnerability descriptions |
|
| 65 |
|
| 66 |
---
|
| 67 |
|
| 68 |
+
## Benchmarks
|
| 69 |
+
|
| 70 |
+
### R8 Checkpoint β Exact-Match Micro F1 (paper-comparable)
|
| 71 |
+
|
| 72 |
+
Evaluated with strict exact span boundary matching (seqeval-style). These are the honest, paper-comparable numbers β not the relaxed containment scores.
|
| 73 |
+
|
| 74 |
+
| Benchmark | Micro F1 | Precision | Recall | Notes |
|
| 75 |
+
|---|---|---|---|---|
|
| 76 |
+
| **APTNER** (independent) | **0.498** | 0.668 | 0.397 | APT report style, independent held-out set |
|
| 77 |
+
| **CyNER** | **0.405** | 0.454 | 0.365 | Original CyNER test set |
|
| 78 |
+
|
| 79 |
+
#### Per-Class Breakdown β APTNER (Exact Match)
|
| 80 |
+
|
| 81 |
+
| Class | F1 | Precision | Recall |
|
| 82 |
+
|---|---|---|---|
|
| 83 |
+
| Malware | **0.707** | 0.793 | 0.637 |
|
| 84 |
+
| Indicator | **0.667** | 0.661 | 0.673 |
|
| 85 |
+
| Vulnerability | 0.500 | 0.429 | 0.600 |
|
| 86 |
+
| Organization | 0.326 | 0.500 | 0.242 |
|
| 87 |
+
| System | 0.160 | 0.615 | 0.092 |
|
| 88 |
|
| 89 |
+
#### Per-Class Breakdown β CyNER (Exact Match)
|
|
|
|
| 90 |
|
| 91 |
+
| Class | F1 | Precision | Recall |
|
| 92 |
+
|---|---|---|---|
|
| 93 |
+
| Malware | **0.577** | 0.585 | 0.570 |
|
| 94 |
+
| Indicator | 0.250 | 0.518 | 0.165 |
|
| 95 |
+
| System | 0.399 | 0.412 | 0.387 |
|
| 96 |
+
| Organization | 0.316 | 0.288 | 0.351 |
|
| 97 |
+
| Vulnerability | 0.375 | 0.500 | 0.300 |
|
| 98 |
|
| 99 |
+
#### Containment Span F1 (OPF native eval, relaxed boundary matching)
|
|
|
|
| 100 |
|
| 101 |
+
| Test Set | Span F1 | Precision | Recall |
|
| 102 |
+
|---|---|---|---|
|
| 103 |
+
| Enriched (primary) | 0.550 | 0.513 | 0.591 |
|
| 104 |
+
| APTNER | 0.550 | 0.687 | 0.459 |
|
| 105 |
+
| CyNER | 0.468 | 0.512 | 0.431 |
|
| 106 |
+
| SecureBERT2 | 0.451 | 0.513 | 0.403 |
|
| 107 |
+
|
| 108 |
+
> **Note on scoring:** Containment F1 is ~5 points higher than exact-match F1 due to relaxed boundary matching. Exact-match is the paper-comparable metric.
|
| 109 |
+
|
| 110 |
+
### What R8 tells us
|
| 111 |
+
|
| 112 |
+
- **Strong on Malware + Indicator** β F1 0.58β0.71, these are the most common IOC types
|
| 113 |
+
- **Weak on Organization + System recall** β the model detects entities but misses many in APT-report style prose; this is a training data representation gap, not an architecture limit
|
| 114 |
+
- **Boundary precision is solid** β APTNER detection F1 is 0.80, meaning the model *finds* entities; exact-match drops because boundary offsets aren't always perfect
|
| 115 |
+
- **No data leakage** β R8 was trained with strict deduplication; all held-out sets have zero exact or prefix-80 overlap with training data
|
| 116 |
|
| 117 |
---
|
| 118 |
|
| 119 |
+
## Checkpoints
|
| 120 |
|
| 121 |
+
### `checkpoints/r8_5class/epoch_4` β **Main checkpoint**
|
| 122 |
|
| 123 |
+
Full multi-source fine-tune. Best checkpoint from a 7-epoch training run (early stopped at patience=3).
|
| 124 |
+
|
| 125 |
+
| Parameter | Value |
|
| 126 |
+
|---|---|
|
| 127 |
+
| Training examples | 28,675 |
|
| 128 |
+
| Best epoch | 4 |
|
| 129 |
+
| Val loss | 0.1089 |
|
| 130 |
+
| Optimizer | AdamW, focal loss Ξ³=2 |
|
| 131 |
+
| Learning rate | 5e-5 (cosine), LLRD 0.9 |
|
| 132 |
+
| Batch size | 4 (grad accum 2) |
|
| 133 |
+
| O-downsampling | 0.7 |
|
| 134 |
+
|
| 135 |
+
### `checkpoints/cyner_v1_sanity`
|
| 136 |
+
|
| 137 |
+
Sanity-check fine-tune on 50 examples to validate the training pipeline end-to-end. Not intended for production use.
|
| 138 |
+
|
| 139 |
+
| Parameter | Value |
|
| 140 |
+
|---|---|
|
| 141 |
+
| Training examples | 50 |
|
| 142 |
+
| Best epoch | 1 |
|
| 143 |
+
| Best val loss | 0.687 |
|
| 144 |
+
| Val token accuracy | 90.1% |
|
| 145 |
|
| 146 |
---
|
| 147 |
|
| 148 |
+
## Training Data (R8)
|
| 149 |
|
| 150 |
+
28,675 examples aggregated from 20+ sources, deduplicated and leakage-cleaned:
|
| 151 |
+
|
| 152 |
+
| Source | Records |
|
| 153 |
+
|---|---:|
|
| 154 |
+
| CyNER v2 | 4,563 |
|
| 155 |
+
| CyberNER STIX | 3,723 |
|
| 156 |
+
| DNRTI | 2,834 |
|
| 157 |
+
| APTNER | 2,584 |
|
| 158 |
+
| APT reports (LLM-annotated) | 2,263 |
|
| 159 |
+
| NVD CVEs v2 | 1,995 |
|
| 160 |
+
| MITRE ATT&CK v2 | 1,485 |
|
| 161 |
+
| Synthetic IOC v2 | 1,292 |
|
| 162 |
+
| CyberNER | 1,204 |
|
| 163 |
+
| CyNER original | 717 |
|
| 164 |
+
| Defanged augmentation | 652 |
|
| 165 |
+
| ExploitDB | 500 |
|
| 166 |
+
| NVD CVE | 338 |
|
| 167 |
+
| + 9 more sources | ~345 |
|
| 168 |
+
|
| 169 |
+
**Leakage audit:** Zero exact-match and zero prefix-80 overlap between training data and any held-out benchmark (APTNER, CyNER, SecureBERT2, enriched test, validation).
|
| 170 |
|
| 171 |
---
|
| 172 |
|
| 173 |
## Usage
|
| 174 |
|
| 175 |
```bash
|
| 176 |
+
# Install the base framework
|
| 177 |
pip install -e vendor/privacy-filter
|
| 178 |
|
| 179 |
+
# Run inference with the R8 checkpoint
|
| 180 |
+
opf --checkpoint checkpoints/r8_5class/epoch_4 --device cpu \
|
| 181 |
+
"APT29 deployed Cobalt Strike beacon via CVE-2021-44228 against Microsoft Exchange servers."
|
| 182 |
+
|
| 183 |
+
# Evaluate on a JSONL test file
|
| 184 |
+
opf eval data/processed/cyner_test.jsonl \
|
| 185 |
+
--checkpoint checkpoints/r8_5class/epoch_4 \
|
| 186 |
+
--device cpu
|
| 187 |
+
|
| 188 |
+
# Fine-tune further with a custom dataset
|
| 189 |
+
opf train my_train.jsonl \
|
| 190 |
+
--val my_val.jsonl \
|
| 191 |
+
--output-dir ./my_checkpoint
|
| 192 |
+
```
|
| 193 |
|
| 194 |
+
**Input format** (JSONL):
|
| 195 |
+
```json
|
| 196 |
+
{"text": "Emotet was distributed via malicious Word documents exploiting CVE-2017-11882.", "spans": []}
|
| 197 |
+
```
|
| 198 |
|
| 199 |
+
**Output format:**
|
| 200 |
+
```json
|
| 201 |
+
{
|
| 202 |
+
"text": "Emotet was distributed via malicious Word documents exploiting CVE-2017-11882.",
|
| 203 |
+
"spans": [
|
| 204 |
+
{"start": 0, "end": 6, "label": "Malware", "text": "Emotet"},
|
| 205 |
+
{"start": 62, "end": 77, "label": "Vulnerability", "text": "CVE-2017-11882"}
|
| 206 |
+
]
|
| 207 |
+
}
|
| 208 |
```
|
| 209 |
|
| 210 |
---
|
| 211 |
|
| 212 |
+
## Repository Structure
|
| 213 |
+
|
| 214 |
+
```
|
| 215 |
+
arcspan/
|
| 216 |
+
βββ checkpoints/
|
| 217 |
+
β βββ r8_5class/epoch_4/ β Main checkpoint (model.safetensors + config.json)
|
| 218 |
+
β βββ cyner_v1_sanity/ β Sanity-check checkpoint
|
| 219 |
+
βββ data/
|
| 220 |
+
β βββ processed/ β Training/eval JSONL splits (all benchmarks)
|
| 221 |
+
β βββ label_spaces/ β Label space JSON configs
|
| 222 |
+
βββ scripts/ β Training, eval, and data processing scripts
|
| 223 |
+
βββ src/arcspan/ β Core Python package
|
| 224 |
+
βββ results/ β Benchmark results and audit reports
|
| 225 |
+
βββ research/
|
| 226 |
+
β βββ decisions/ β Architecture Decision Records (ADRs)
|
| 227 |
+
β βββ notes/progress/ β Research progress notes
|
| 228 |
+
β βββ paper/ β Paper draft and outline
|
| 229 |
+
βββ vendor/privacy-filter/ β OpenAI Privacy Filter (vendored)
|
| 230 |
+
```
|
| 231 |
+
|
| 232 |
+
---
|
| 233 |
|
| 234 |
+
## Roadmap
|
| 235 |
|
| 236 |
+
- **R9 training** β Stricter leakage-clean multi-source dataset (24,518 examples), targeting improved Organization + System recall
|
| 237 |
+
- **O-logit bias decoding** β Zero-cost inference trick to trade precision for recall on weak classes
|
| 238 |
+
- **Research paper** β "Sparse MoE vs. dense transformer for cybersecurity NER: an efficiency comparison"
|
| 239 |
+
- **Future verticals** β Energy/power systems, clinical NER (same architecture, different label space)
|
| 240 |
|
| 241 |
---
|
| 242 |
|
| 243 |
+
## Citation
|
| 244 |
+
|
| 245 |
+
If you use Arcspan in your work, please cite the base model:
|
| 246 |
|
| 247 |
+
```bibtex
|
| 248 |
+
@misc{openai2025privacyfilter,
|
| 249 |
+
title={Privacy Filter},
|
| 250 |
+
author={OpenAI},
|
| 251 |
+
year={2025},
|
| 252 |
+
url={https://huggingface.co/openai/privacy-filter}
|
| 253 |
+
}
|
| 254 |
+
```
|
| 255 |
|
| 256 |
---
|
| 257 |
|
| 258 |
## License
|
| 259 |
|
| 260 |
+
Apache 2.0 β same as the base [OpenAI Privacy Filter](https://github.com/openai/privacy-filter).
|