jeffasante commited on
Commit
2a6fcb8
·
verified ·
1 Parent(s): 43de9d9

Add privacy-filter README.md

Browse files
Files changed (1) hide show
  1. privacy/README.md +152 -0
privacy/README.md ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ library_name: cellm
3
+ license: apache-2.0
4
+ base_model: openai/privacy-filter
5
+ pipeline_tag: token-classification
6
+ tags:
7
+ - pii
8
+ - privacy
9
+ - token-classification
10
+ - rust
11
+ - quantized
12
+ - mixture-of-experts
13
+ - on-device
14
+ ---
15
+
16
+ # privacy-filter (cellm)
17
+
18
+ [`openai/privacy-filter`](https://huggingface.co/openai/privacy-filter) converted
19
+ to the cellm format and quantized for on-device inference. Runs in Rust on CPU
20
+ with no Python, no ONNX runtime, and no network access — the point of a PII
21
+ filter is that the text never leaves the machine.
22
+
23
+ Three quantization recipes are published. **`int4-g32` is the recommended
24
+ build**; the smaller two are included because the size/accuracy trade is a real
25
+ decision for mobile bundles and the numbers below are measured, not estimated.
26
+
27
+ ## Files
28
+
29
+ | File | Size | Recommended |
30
+ | --- | --- | --- |
31
+ | `privacy-filter-int4-g32-f16s.cellm` | 899 MB | **yes** |
32
+ | `privacy-filter-int3-g128.cellm` | 667 MB | size-constrained only |
33
+ | `privacy-filter-int2-g32.cellm` | 599 MB | not for compliance use |
34
+ | `tokenizer.json` | 27.9 MB | required by all three |
35
+
36
+ ## Model details
37
+
38
+ - **Base**: `openai/privacy-filter` (2.6 GB fp32 safetensors)
39
+ - **Architecture**: sparse MoE token classifier, 8 layers, 128 experts, top-4
40
+ - **Hidden size**: 640 · **Heads**: 14 query / 2 key-value · **Head dim**: 64
41
+ - **Vocab**: 200,064 · **Attention**: bidirectional, sliding window 128
42
+ - **RoPE**: YaRN, theta 150,000, factor 32
43
+ - **Labels**: 33 BIOES tags over 8 entity types
44
+
45
+ Experts are 84% of the file, so quantization targets them: each expert is stored
46
+ transposed (`[E, K, N]` → `[N, K]`) and group-quantized along `K` with affine
47
+ per-group scale and bias in f16. Embeddings are int8 with per-row f16 scales — a
48
+ fixed 122.5 MB floor, since 200,064 × 640 cannot be compressed further without
49
+ hurting rare-token recall. Everything else stays f16.
50
+
51
+ ### Entity types
52
+
53
+ `account_number`, `private_address`, `private_date`, `private_email`,
54
+ `private_person`, `private_phone`, `private_url`, `secret`
55
+
56
+ ## Usage
57
+
58
+ ```bash
59
+ ./target/release/pii privacy-filter-int4-g32-f16s.cellm \
60
+ --tokenizer tokenizer.json \
61
+ --text "Contact Bob Smith at bob.smith@example.com or (555) 123-4567."
62
+ ```
63
+
64
+ ```
65
+ === Contact Bob Smith at bob.smith@example.com or (555) 123-4567.
66
+ private_person [ 7: 17] " Bob Smith"
67
+ private_email [ 20: 42] " bob.smith@example.com"
68
+ private_phone [ 45: 60] " (555) 123-4567"
69
+ ```
70
+
71
+ `--redact` replaces each span with its label; `--dump-logits` prints per-token
72
+ scores. Spans are byte offsets into the input, so redaction is exact.
73
+
74
+ ## Benchmark
75
+
76
+ 140 texts / 12,740 chars / 366 gold spans. Ground truth is the **fp32 HF model's
77
+ own output** (transformers 5.6.2, torch 2.10.0) — this measures quantization
78
+ damage, not the base model's absolute accuracy. A span counts as correct only if
79
+ both its label and its exact boundaries match.
80
+
81
+ | Build | Size | Recall | Precision | F1 | Leak |
82
+ | --- | --- | --- | --- | --- | --- |
83
+ | **int4 g32** | **899 MB** | **0.978** | **0.975** | **0.977** | **2.2%** |
84
+ | int3 g128 | 667 MB | 0.954 | 0.923 | 0.938 | 4.6% |
85
+ | int2 g32 | 599 MB | 0.934 | 0.919 | 0.927 | 6.6% |
86
+
87
+ "Leak" is the fraction of fp32-detected PII that the quantized build misses.
88
+
89
+ ### Recall by entity type
90
+
91
+ | Entity type | Gold | int4 g32 | int3 g128 | int2 g32 |
92
+ | --- | --- | --- | --- | --- |
93
+ | `private_person` | 96 | 1.000 | 1.000 | 1.000 |
94
+ | `private_phone` | 22 | 1.000 | 1.000 | 1.000 |
95
+ | `private_email` | 87 | 1.000 | 1.000 | 0.954 |
96
+ | `private_url` | 13 | 1.000 | 0.923 | 0.769 |
97
+ | `secret` | 26 | 0.962 | 0.923 | 1.000 |
98
+ | `private_address` | 42 | 0.952 | 0.833 | 0.881 |
99
+ | `account_number` | 35 | 0.943 | 0.914 | 0.829 |
100
+ | `private_date` | 45 | 0.933 | 0.911 | 0.867 |
101
+
102
+ People, phones and emails survive aggressive quantization; **structured
103
+ identifiers and addresses do not**. int2 drops 23% of URLs and 17% of account
104
+ numbers, and its failure mode is worse than a clean miss — it *fragments* spans,
105
+ returning `.com` for a full email address. A truncated redaction looks like a
106
+ success to the calling code while still leaking the local part.
107
+
108
+ ### Resources
109
+
110
+ Apple M4, CPU backend, cold start on a 30-char input:
111
+
112
+ | Build | Load + infer | Peak RSS |
113
+ | --- | --- | --- |
114
+ | int4 g32 | 0.92 s | 479 MB |
115
+ | int3 g128 | 0.78 s | 440 MB |
116
+ | int2 g32 | 0.75 s | 432 MB |
117
+
118
+ Peak RSS is roughly half the file size: weights are mmapped and only 4 of 128
119
+ experts are touched per token, so the resident set never approaches the
120
+ on-disk footprint. **If your constraint is memory rather than bundle size, the
121
+ 899 MB build already fits in ~479 MB** and the smaller variants buy you little.
122
+
123
+ ## Known limitations
124
+
125
+ These are properties of the base model and are present in all three builds:
126
+
127
+ - **CVV codes and SWIFT/BIC codes are not detected.**
128
+ - Bank sort codes (`11-01-04`) are labelled `private_date`.
129
+ - IP addresses are labelled `private_url`.
130
+ - Organization names in a PII-dense context are over-flagged as
131
+ `private_address` — expect over-redaction of company names.
132
+ - Documentation placeholders are correctly ignored (`AKIAIOSFODNN7EXAMPLE`
133
+ scores `O` at p≈1.0) while real-looking keys are caught. Do not benchmark this
134
+ model with placeholder secrets; you will conclude it is broken.
135
+ - Boundary handling is left-inclusive of a preceding space. Trim before
136
+ comparing spans against another tagger.
137
+
138
+ ## Reproducing
139
+
140
+ ```bash
141
+ python tools/convert_privacy_filter_hf.py <hf_dir> out.cellm \
142
+ --quant int4 --group-size 32 --quant-embedding
143
+ ```
144
+
145
+ `--quant` accepts `int8`, `int4`, `int3`, `int2`; `--group-size` sets the
146
+ quantization group. Note that int3 packs 10 values per `u32` and wastes the top
147
+ 2 bits, so a 3-bit file is ~6.7% larger than the ideal bit count implies — which
148
+ is why `int3 g128` is 667 MB and not the 630 MB a naive calculation gives.
149
+
150
+ ## License
151
+
152
+ Apache-2.0, inherited from `openai/privacy-filter`.