MaziyarPanahi commited on
Commit
428fc63
·
verified ·
1 Parent(s): 0a6a505

Add 8-bit OpenMed MLX Privacy Filter artifact

Browse files
Files changed (8) hide show
  1. .gitattributes +1 -0
  2. README.md +137 -0
  3. config.json +127 -0
  4. id2label.json +35 -0
  5. openmed-mlx.json +35 -0
  6. tokenizer.json +3 -0
  7. tokenizer_config.json +12 -0
  8. weights.safetensors +3 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ tokenizer.json filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: apache-2.0
3
+ base_model: openai/privacy-filter
4
+ pipeline_tag: token-classification
5
+ library_name: openmed
6
+ tags:
7
+ - openmed
8
+ - mlx
9
+ - apple-silicon
10
+ - token-classification
11
+ - pii
12
+ - privacy
13
+ - de-identification
14
+ - redaction
15
+ - quantized
16
+ - int8
17
+ - q8
18
+ - medical
19
+ - clinical
20
+ ---
21
+
22
+ # OpenAI Privacy Filter MLX 8-bit
23
+
24
+ This repository contains an 8-bit OpenMed MLX artifact for [`openai/privacy-filter`](https://huggingface.co/openai/privacy-filter), packaged for local PII detection on Apple Silicon with [OpenMed](https://github.com/maziyarpanahi/openmed).
25
+
26
+ OpenAI Privacy Filter is a bidirectional token-classification model for detecting personally identifiable information in text. This OpenMed MLX build keeps the original BIOES token-label head, uses the `o200k_base` tokenizer assets, and runs with OpenMed's Python and Swift MLX runtimes.
27
+
28
+ After the model is downloaded once, inference runs locally. No document text is sent to a server.
29
+
30
+ ## Model Details
31
+
32
+ - Source checkpoint: [`openai/privacy-filter`](https://huggingface.co/openai/privacy-filter)
33
+ - OpenMed MLX family: `openai-privacy-filter`
34
+ - Task: token classification for privacy span detection
35
+ - Weight format: `weights.safetensors`
36
+ - Quantization: 8-bit affine quantization, group size 64
37
+ - Runtime: OpenMed + MLX on Apple Silicon
38
+ - Tokenizer: `o200k_base` / tiktoken-style BPE
39
+ - Labels: `account_number`, `private_address`, `private_date`, `private_email`, `private_person`, `private_phone`, `private_url`, `secret`
40
+
41
+ The standard MLX layers are quantized, including embeddings, attention projections, MoE gates, and the token-classification head. Custom sparse-MoE expert tensors remain stored in their normal precision until OpenMed adds a dedicated expert-tensor quantization kernel.
42
+
43
+ ## Quick Start: Python
44
+
45
+ ```bash
46
+ pip install -U openmed "openmed[mlx]"
47
+ ```
48
+
49
+ ```python
50
+ from huggingface_hub import snapshot_download
51
+ from openmed.mlx.inference import create_mlx_pipeline
52
+
53
+ model_path = snapshot_download("OpenMed/privacy-filter-mlx-8bit")
54
+ pipe = create_mlx_pipeline(model_path)
55
+
56
+ text = "My name is Alice Smith and my email is alice.smith@example.com."
57
+ entities = pipe(text)
58
+
59
+ for entity in entities:
60
+ print(entity)
61
+ ```
62
+
63
+ Example output:
64
+
65
+ ```python
66
+ {
67
+ "entity_group": "private_person",
68
+ "word": "Alice Smith",
69
+ "start": 11,
70
+ "end": 22,
71
+ "score": 0.9999,
72
+ }
73
+ {
74
+ "entity_group": "private_email",
75
+ "word": "alice.smith@example.com",
76
+ "start": 39,
77
+ "end": 62,
78
+ "score": 0.9600,
79
+ }
80
+ ```
81
+
82
+ ## Quick Start: Swift and Apple Apps
83
+
84
+ Add OpenMedKit to your Xcode project:
85
+
86
+ 1. Open Xcode and choose File > Add Package Dependencies.
87
+ 2. Paste `https://github.com/maziyarpanahi/openmed`.
88
+ 3. Select the `OpenMedKit` package product.
89
+ 4. Download and cache the MLX model once, then run inference locally.
90
+
91
+ ```swift
92
+ import OpenMedKit
93
+
94
+ let modelURL = try await OpenMedModelStore.downloadMLXModel(
95
+ repoID: "OpenMed/privacy-filter-mlx-8bit"
96
+ )
97
+
98
+ let openmed = try OpenMed(backend: .mlx(modelDirectoryURL: modelURL))
99
+ let entities = try openmed.extractPII(
100
+ "My name is Alice Smith and my email is alice.smith@example.com."
101
+ )
102
+
103
+ for entity in entities {
104
+ print(entity.text, entity.label, entity.score)
105
+ }
106
+ ```
107
+
108
+ For iOS, run on Apple Silicon hardware. The iOS Simulator is not the recommended acceptance target for MLX inference.
109
+
110
+ ## Validation
111
+
112
+ The 8-bit artifact was validated against the unquantized OpenMed MLX artifact with fixed text samples. In a sanity check containing a person name, phone number, email, and address, both artifacts returned the same four span types with close scores:
113
+
114
+ | Span | bf16 score | q8 score |
115
+ |---|---:|---:|
116
+ | `private_person` | 1.0000 | 1.0000 |
117
+ | `private_phone` | 0.9891 | 0.9881 |
118
+ | `private_email` | 0.9662 | 0.9604 |
119
+ | `private_address` | 0.9107 | 0.9051 |
120
+
121
+ OpenMed also includes unit tests for:
122
+
123
+ - q8 artifact loading
124
+ - quantization metadata decoding
125
+ - finite logits from the q8 runtime
126
+ - bf16/q8 shape and argmax-label coherence
127
+ - BIOES/Viterbi span decoding
128
+
129
+ ## Intended Use
130
+
131
+ Use this model for local privacy filtering, PII detection, redaction workflows, and evaluation on Apple devices. For high-risk domains such as healthcare, legal, finance, education, and government, evaluate against your own data and policy requirements before production use.
132
+
133
+ ## Credits
134
+
135
+ - Base checkpoint: [`openai/privacy-filter`](https://huggingface.co/openai/privacy-filter)
136
+ - MLX conversion and runtime support: [OpenMed](https://github.com/maziyarpanahi/openmed)
137
+ - OpenMed website: [https://openmed.life](https://openmed.life)
config.json ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model_type": "openai_privacy_filter",
3
+ "inference_contract_version": 1,
4
+ "encoding": "o200k_base",
5
+ "num_hidden_layers": 8,
6
+ "num_experts": 128,
7
+ "experts_per_token": 4,
8
+ "vocab_size": 200064,
9
+ "num_labels": 33,
10
+ "hidden_size": 640,
11
+ "intermediate_size": 640,
12
+ "head_dim": 64,
13
+ "num_attention_heads": 14,
14
+ "num_key_value_heads": 2,
15
+ "sliding_window": 257,
16
+ "bidirectional_context": true,
17
+ "bidirectional_left_context": 128,
18
+ "bidirectional_right_context": 128,
19
+ "initial_context_length": 4096,
20
+ "max_position_embeddings": 131072,
21
+ "default_n_ctx": 128000,
22
+ "rope_theta": 150000,
23
+ "rope_scaling_factor": 32.0,
24
+ "rope_ntk_alpha": 1.0,
25
+ "rope_ntk_beta": 32.0,
26
+ "param_dtype": "bfloat16",
27
+ "_name_or_path": "openai/privacy-filter",
28
+ "_mlx_task": "token-classification",
29
+ "_mlx_family": "openai-privacy-filter",
30
+ "_mlx_model_type": "openai-privacy-filter",
31
+ "_mlx_runtime": {
32
+ "experimental": true,
33
+ "decode": "bioes-viterbi",
34
+ "tokenizer": "tiktoken"
35
+ },
36
+ "num_local_experts": 128,
37
+ "num_experts_per_tok": 4,
38
+ "rms_norm_eps": 1e-05,
39
+ "id2label": {
40
+ "0": "O",
41
+ "1": "B-account_number",
42
+ "2": "I-account_number",
43
+ "3": "E-account_number",
44
+ "4": "S-account_number",
45
+ "5": "B-private_address",
46
+ "6": "I-private_address",
47
+ "7": "E-private_address",
48
+ "8": "S-private_address",
49
+ "9": "B-private_date",
50
+ "10": "I-private_date",
51
+ "11": "E-private_date",
52
+ "12": "S-private_date",
53
+ "13": "B-private_email",
54
+ "14": "I-private_email",
55
+ "15": "E-private_email",
56
+ "16": "S-private_email",
57
+ "17": "B-private_person",
58
+ "18": "I-private_person",
59
+ "19": "E-private_person",
60
+ "20": "S-private_person",
61
+ "21": "B-private_phone",
62
+ "22": "I-private_phone",
63
+ "23": "E-private_phone",
64
+ "24": "S-private_phone",
65
+ "25": "B-private_url",
66
+ "26": "I-private_url",
67
+ "27": "E-private_url",
68
+ "28": "S-private_url",
69
+ "29": "B-secret",
70
+ "30": "I-secret",
71
+ "31": "E-secret",
72
+ "32": "S-secret"
73
+ },
74
+ "label2id": {
75
+ "B-account_number": 1,
76
+ "B-private_address": 5,
77
+ "B-private_date": 9,
78
+ "B-private_email": 13,
79
+ "B-private_person": 17,
80
+ "B-private_phone": 21,
81
+ "B-private_url": 25,
82
+ "B-secret": 29,
83
+ "E-account_number": 3,
84
+ "E-private_address": 7,
85
+ "E-private_date": 11,
86
+ "E-private_email": 15,
87
+ "E-private_person": 19,
88
+ "E-private_phone": 23,
89
+ "E-private_url": 27,
90
+ "E-secret": 31,
91
+ "I-account_number": 2,
92
+ "I-private_address": 6,
93
+ "I-private_date": 10,
94
+ "I-private_email": 14,
95
+ "I-private_person": 18,
96
+ "I-private_phone": 22,
97
+ "I-private_url": 26,
98
+ "I-secret": 30,
99
+ "O": 0,
100
+ "S-account_number": 4,
101
+ "S-private_address": 8,
102
+ "S-private_date": 12,
103
+ "S-private_email": 16,
104
+ "S-private_person": 20,
105
+ "S-private_phone": 24,
106
+ "S-private_url": 28,
107
+ "S-secret": 32
108
+ },
109
+ "_mlx_viterbi_biases": {
110
+ "transition_bias_background_stay": 0.0,
111
+ "transition_bias_background_to_start": 0.0,
112
+ "transition_bias_end_to_background": 0.0,
113
+ "transition_bias_end_to_start": 0.0,
114
+ "transition_bias_inside_to_continue": 0.0,
115
+ "transition_bias_inside_to_end": 0.0
116
+ },
117
+ "hidden_dropout_prob": 0.1,
118
+ "attention_probs_dropout_prob": 0.1,
119
+ "layer_norm_eps": 1e-12,
120
+ "swiglu_limit": 7.0,
121
+ "_mlx_quantization": {
122
+ "bits": 8,
123
+ "group_size": 64,
124
+ "mode": "affine"
125
+ },
126
+ "_mlx_weights_format": "safetensors"
127
+ }
id2label.json ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "0": "O",
3
+ "1": "B-account_number",
4
+ "2": "I-account_number",
5
+ "3": "E-account_number",
6
+ "4": "S-account_number",
7
+ "5": "B-private_address",
8
+ "6": "I-private_address",
9
+ "7": "E-private_address",
10
+ "8": "S-private_address",
11
+ "9": "B-private_date",
12
+ "10": "I-private_date",
13
+ "11": "E-private_date",
14
+ "12": "S-private_date",
15
+ "13": "B-private_email",
16
+ "14": "I-private_email",
17
+ "15": "E-private_email",
18
+ "16": "S-private_email",
19
+ "17": "B-private_person",
20
+ "18": "I-private_person",
21
+ "19": "E-private_person",
22
+ "20": "S-private_person",
23
+ "21": "B-private_phone",
24
+ "22": "I-private_phone",
25
+ "23": "E-private_phone",
26
+ "24": "S-private_phone",
27
+ "25": "B-private_url",
28
+ "26": "I-private_url",
29
+ "27": "E-private_url",
30
+ "28": "S-private_url",
31
+ "29": "B-secret",
32
+ "30": "I-secret",
33
+ "31": "E-secret",
34
+ "32": "S-secret"
35
+ }
openmed-mlx.json ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "format": "openmed-mlx",
3
+ "format_version": 2,
4
+ "task": "token-classification",
5
+ "family": "openai-privacy-filter",
6
+ "source_model_id": "openai/privacy-filter",
7
+ "config_path": "config.json",
8
+ "label_map_path": "id2label.json",
9
+ "preferred_weights": "weights.safetensors",
10
+ "fallback_weights": [
11
+ "weights.npz"
12
+ ],
13
+ "available_weights": [
14
+ "weights.safetensors"
15
+ ],
16
+ "weights_format": "safetensors",
17
+ "quantization": {
18
+ "bits": 8,
19
+ "group_size": 64,
20
+ "mode": "affine"
21
+ },
22
+ "max_sequence_length": 131072,
23
+ "tokenizer": {
24
+ "path": ".",
25
+ "files": [
26
+ "tokenizer.json",
27
+ "tokenizer_config.json"
28
+ ]
29
+ },
30
+ "runtime": {
31
+ "experimental": true,
32
+ "decode": "bioes-viterbi",
33
+ "tokenizer": "tiktoken"
34
+ }
35
+ }
tokenizer.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0614fe83cadab421296e664e1f48f4261fa8fef6e03e63bb75c20f38e37d07d3
3
+ size 27868174
tokenizer_config.json ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "backend": "tokenizers",
3
+ "eos_token": "<|endoftext|>",
4
+ "is_local": false,
5
+ "model_input_names": [
6
+ "input_ids",
7
+ "attention_mask"
8
+ ],
9
+ "model_max_length": 128000,
10
+ "pad_token": "<|endoftext|>",
11
+ "tokenizer_class": "TokenizersBackend"
12
+ }
weights.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fde03f50d02edefe911e511c012ccfb2302b0792014165d1add0ce9c7c798d65
3
+ size 2668486393