labrat-aiko commited on
Commit
3074d19
·
verified ·
1 Parent(s): b62c537

docs: polish model card — link dataset, add limitations, raw ONNX snippet, label-index callout

Browse files
Files changed (1) hide show
  1. README.md +113 -32
README.md CHANGED
@@ -3,35 +3,43 @@ language: en
3
  license: apache-2.0
4
  library_name: transformers
5
  base_model: cross-encoder/nli-MiniLM2-L6-H768
 
 
6
  tags:
7
  - nli
8
  - zero-shot-classification
9
  - compliance
10
  - popia
11
  - south-africa
 
 
12
  - onnx
13
  - quantized
 
14
  pipeline_tag: zero-shot-classification
15
  ---
16
 
17
  # nli-popia-v1
18
 
19
- Cross-encoder NLI model fine-tuned for semantic validation of LLM outputs against
20
- **POPIA** (South Africa's Protection of Personal Information Act, 2013) compliance
21
- clauses. Used by the `POPIAJudge` in [semantix-ai](https://github.com/labrat-akhona/semantix-ai).
 
22
 
23
- - **Base model:** `cross-encoder/nli-MiniLM2-L6-H768` (~22M params)
24
- - **Fine-tuning:** 180 hand-authored premise/hypothesis/label triples (60 seeds + 120 paraphrases)
25
- - **Evaluation:** 150 pinned holdout pairs, 7 canonical POPIA clauses
26
- - **Deployment:** INT8 ONNX, ~15 ms CPU inference, 4 CPU-architecture variants
 
 
27
 
28
- ## Results
29
 
30
- Evaluated on the pinned `eval.jsonl` (150 pairs) against the stock base model as baseline:
31
 
32
  | Metric | Stock NLI | POPIA fine-tune | Delta |
33
  |-------------------------------------|-----------|-----------------|-------------|
34
- | Macro F1 | 0.517 | **0.813** | **+0.296** |
35
  | Accuracy | 0.707 | **0.833** | +0.127 |
36
  | POPIA consent | 0.612 | 0.902 | +0.290 |
37
  | POPIA minimality | 0.646 | 0.753 | +0.106 |
@@ -41,21 +49,9 @@ Evaluated on the pinned `eval.jsonl` (150 pairs) against the stock base model as
41
  | POPIA general processing | 0.400 | 0.893 | +0.493 |
42
  | POPIA data subject rights | 0.400 | 0.883 | +0.483 |
43
 
44
- **Release gate:** macro delta ≥ 0.10 AND no per-clause regression — **PASS**.
45
 
46
- ## Labels
47
-
48
- Label order matches the base model's `config.id2label`:
49
-
50
- | Index | Label |
51
- |-------|----------------|
52
- | 0 | contradiction |
53
- | 1 | entailment |
54
- | 2 | neutral |
55
-
56
- The `POPIAJudge` reads `probs[1]` (entailment) as the "compliance matches intent" score.
57
-
58
- ## Usage
59
 
60
  ```bash
61
  pip install 'semantix-ai[popia]'
@@ -72,8 +68,49 @@ verdict = judge.evaluate(
72
  threshold=POPIAJudge.recommended_threshold, # 0.75
73
  )
74
  print(verdict.passed, verdict.score)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  ```
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  ## Files
78
 
79
  | Path | Purpose |
@@ -84,23 +121,67 @@ print(verdict.passed, verdict.score)
84
  | `onnx/model_qint8_arm64.onnx` | INT8 quantized, ARM64 (Apple Silicon, Graviton) |
85
  | `tokenizer.json` | Rust `tokenizers` fast-tokenizer config |
86
  | `config.json` | Model config (shared across variants) |
87
- | `eval.jsonl` | Pinned 150-pair holdout set (bundled for reproducibility) |
88
 
89
- The judge auto-detects the best variant for the host CPU; consumers never pick manually.
90
 
91
  ## Training
92
 
93
  - 5 epochs, batch size 8, lr 2e-5, warmup 10%, weight decay 0.01
94
- - Cross-entropy loss, early stopping on `eval_loss` against a 10% dev split
95
  - CPU training on 180 rows: ~6 min
96
- - Reproducible via `scripts/train_popia.py` in the semantix-ai repo
97
 
98
  ## Intended use
99
 
100
- Compliance-sensitive audit of LLM outputs where a deterministic, auditable,
101
- non-API-dependent judge is required. Not a legal opinion — flags semantic
102
- mismatch between text and a clause intent.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
 
104
  ## License
105
 
106
- Apache 2.0.
 
 
 
 
3
  license: apache-2.0
4
  library_name: transformers
5
  base_model: cross-encoder/nli-MiniLM2-L6-H768
6
+ datasets:
7
+ - labrat-aiko/popia-compliance-nli
8
  tags:
9
  - nli
10
  - zero-shot-classification
11
  - compliance
12
  - popia
13
  - south-africa
14
+ - privacy
15
+ - legal
16
  - onnx
17
  - quantized
18
+ - cpu
19
  pipeline_tag: zero-shot-classification
20
  ---
21
 
22
  # nli-popia-v1
23
 
24
+ Cross-encoder NLI model fine-tuned for deterministic, local, auditable
25
+ validation of LLM outputs against **POPIA** (South Africa's Protection of
26
+ Personal Information Act, 2013) compliance clauses. Drop-in judge for the
27
+ `POPIAJudge` in [semantix-ai](https://github.com/labrat-akhona/semantix-ai).
28
 
29
+ - **Base:** `cross-encoder/nli-MiniLM2-L6-H768` (~22M params)
30
+ - **Training data:** 180 hand-authored triples → [`labrat-aiko/popia-compliance-nli`](https://huggingface.co/datasets/labrat-aiko/popia-compliance-nli)
31
+ - **Evaluation:** 150-pair pinned holdout, hash-verified by release gate
32
+ - **Deployment:** 4 INT8 ONNX CPU variants (AVX2 / AVX512 / AVX512-VNNI / ARM64), auto-selected
33
+ - **Inference:** ~70 ms mean on CPU, $0 API cost, no internet required
34
+ - **Release gate:** macro F1 delta ≥ 0.10 AND no per-clause regression — enforced in CI on every push to master
35
 
36
+ ## Results (150-pair pinned holdout)
37
 
38
+ Fine-tuned checkpoint versus the stock base model:
39
 
40
  | Metric | Stock NLI | POPIA fine-tune | Delta |
41
  |-------------------------------------|-----------|-----------------|-------------|
42
+ | **Macro F1** | 0.517 | **0.813** | **+0.296** |
43
  | Accuracy | 0.707 | **0.833** | +0.127 |
44
  | POPIA consent | 0.612 | 0.902 | +0.290 |
45
  | POPIA minimality | 0.646 | 0.753 | +0.106 |
 
49
  | POPIA general processing | 0.400 | 0.893 | +0.493 |
50
  | POPIA data subject rights | 0.400 | 0.883 | +0.483 |
51
 
52
+ Every clause improved. No regressions. Release gate: **PASS**.
53
 
54
+ ## Quick start
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
  ```bash
57
  pip install 'semantix-ai[popia]'
 
68
  threshold=POPIAJudge.recommended_threshold, # 0.75
69
  )
70
  print(verdict.passed, verdict.score)
71
+ # False 0.031
72
+ ```
73
+
74
+ Using the raw ONNX directly (no PyTorch, no semantix dependency):
75
+
76
+ ```python
77
+ import numpy as np, onnxruntime as ort
78
+ from tokenizers import Tokenizer
79
+ from huggingface_hub import hf_hub_download
80
+
81
+ model_path = hf_hub_download("labrat-aiko/nli-popia-v1", "onnx/model_quint8_avx2.onnx")
82
+ tok_path = hf_hub_download("labrat-aiko/nli-popia-v1", "tokenizer.json")
83
+ session = ort.InferenceSession(model_path)
84
+ tok = Tokenizer.from_file(tok_path)
85
+
86
+ encoded = tok.encode(
87
+ "Your data will be used to generate marketing offers without opt-in.",
88
+ "The responsible party is obtaining explicit opt-in consent.",
89
+ )
90
+ logits = session.run(None, {
91
+ "input_ids": np.array([encoded.ids], dtype=np.int64),
92
+ "attention_mask": np.array([encoded.attention_mask], dtype=np.int64),
93
+ })[0][0]
94
+ probs = np.exp(logits) / np.exp(logits).sum()
95
+ # Label order (id2label): {0: contradiction, 1: entailment, 2: neutral}
96
+ print("entailment:", probs[1])
97
  ```
98
 
99
+ ## Label order (read this before using the scores)
100
+
101
+ Label indices match the base model's `config.id2label`:
102
+
103
+ | Index | Label |
104
+ |-------|----------------|
105
+ | 0 | contradiction |
106
+ | 1 | **entailment** |
107
+ | 2 | neutral |
108
+
109
+ `POPIAJudge` (semantix-ai ≥ 0.2.0) reads `probs[1]` as the compliance score.
110
+ A Python-side bug in v0.1.5–v0.1.13 of semantix-ai was reading `probs[2]`
111
+ (neutral) — fixed in v0.2.0. The ONNX artefacts in this repo are unchanged;
112
+ only downstream Python code needed the label index correction.
113
+
114
  ## Files
115
 
116
  | Path | Purpose |
 
121
  | `onnx/model_qint8_arm64.onnx` | INT8 quantized, ARM64 (Apple Silicon, Graviton) |
122
  | `tokenizer.json` | Rust `tokenizers` fast-tokenizer config |
123
  | `config.json` | Model config (shared across variants) |
124
+ | `eval.jsonl` | Pinned 150-pair holdout (bundled for reproducibility) |
125
 
126
+ `POPIAJudge` auto-detects the best variant at load time; you never pick manually.
127
 
128
  ## Training
129
 
130
  - 5 epochs, batch size 8, lr 2e-5, warmup 10%, weight decay 0.01
131
+ - Cross-entropy loss, early stopping on `eval_loss` against 10% dev split
132
  - CPU training on 180 rows: ~6 min
133
+ - Reproducible via [`scripts/train_popia.py`](https://github.com/labrat-akhona/semantix-ai/blob/master/scripts/train_popia.py)
134
 
135
  ## Intended use
136
 
137
+ - Compliance-sensitive audit of LLM outputs where a deterministic,
138
+ auditable, non-API-dependent judge is required (e.g. CI validation,
139
+ audit trails, POPIA-aware `@validate_intent` decorators, MCP tools).
140
+ - Per-clause threshold-tunable gating: each of the 7 POPIA clauses has
141
+ a pre-tuned F1-optimal threshold shipped in
142
+ `semantix.presets.popia` — you can override per-deployment.
143
+ - Educational / research benchmark for local NLI approaches to
144
+ compliance judging versus LLM-as-judge pipelines.
145
+
146
+ ## Limitations
147
+
148
+ - **Does not replace a POPIA specialist, a DPIA, or the Information
149
+ Regulator.** Flags semantic mismatch between text and a clause intent;
150
+ not a legal opinion.
151
+ - **English-only.** No Afrikaans / isiZulu / Sesotho coverage yet.
152
+ - **Narrow domain.** 7 canonical clauses out of POPIA's full surface; some
153
+ adjacent areas (direct marketing under §69, automated decision-making
154
+ under §71) are not separately modelled.
155
+ - **Hand-authored eval set** (same author as train). External validation
156
+ is welcome and the eval set is Apache 2.0 so you can add your own cases.
157
+ - **Threshold-sensitive.** Per-clause F1-optimal thresholds are tuned on
158
+ *this* holdout. If your domain's distribution differs (dialect,
159
+ adversarial inputs, industry jargon), re-tune on your own held-out
160
+ set — the full recipe is in the semantix-ai repo.
161
+
162
+ ## Ecosystem
163
+
164
+ - **Training dataset**: [`labrat-aiko/popia-compliance-nli`](https://huggingface.co/datasets/labrat-aiko/popia-compliance-nli) (Apache 2.0)
165
+ - **Library**: [`semantix-ai`](https://pypi.org/project/semantix-ai/) (MIT), ships `POPIAJudge` + 7 presets
166
+ - **Source**: [labrat-akhona/semantix-ai](https://github.com/labrat-akhona/semantix-ai)
167
+ - **Writeup**: [I Fine-Tuned a Compliance Judge and Beat the Stock Model by +29.6pp F1](https://github.com/labrat-akhona/semantix-ai/blob/master/articles/devto-popia-finetune.md)
168
+
169
+ ## Citation
170
+
171
+ ```bibtex
172
+ @misc{nli-popia-v1-2026,
173
+ author = {Eland, Akhona},
174
+ title = {nli-popia-v1: A local NLI cross-encoder fine-tuned for POPIA compliance validation},
175
+ year = 2026,
176
+ publisher = {Hugging Face},
177
+ howpublished = {\url{https://huggingface.co/labrat-aiko/nli-popia-v1}},
178
+ note = {Apache 2.0}
179
+ }
180
+ ```
181
 
182
  ## License
183
 
184
+ Apache 2.0. Commercial and derivative use explicitly permitted. Forking
185
+ to build sibling compliance models (GDPR, HIPAA, EU AI Act, UK DPA) is
186
+ actively encouraged — same recipe, different clause corpus. A link back is
187
+ appreciated but not required.