GLiNER2-PII-CoreAI / README.md
mlboydaisuke's picture
GLiNER2-PII Core AI: macos JIT + ios AOT h18p + card
b9cfcad verified
|
Raw
History Blame Contribute Delete
4.9 kB
---
license: apache-2.0
base_model:
- fastino/gliner2-privacy-filter-PII-multi
- microsoft/mdeberta-v3-base
pipeline_tag: token-classification
tags:
- core-ai
- coreai
- apple
- on-device
- ner
- pii
- gliner
- deberta
library_name: coreai
---
# GLiNER2-PII β€” Core AI
The zoo's **first NER / schema-driven information-extraction** model, and its first **DeBERTa-v3**
(disentangled-attention) port. Zero-shot entity extraction: pass any label set at call time and the
model finds those entities in the text β€” the flagship use is **on-device PII redaction**.
[`fastino/gliner2-privacy-filter-PII-multi`](https://huggingface.co/fastino/gliner2-privacy-filter-PII-multi)
(Apache-2.0) on a multilingual [mDeBERTa-v3](https://huggingface.co/microsoft/mdeberta-v3-base) base
(278M), fused into **one static Core AI graph**; the tokenizer, schema linearization, and span
decode run in the Swift host.
> **Uncontested on iPhone.** An on-device GLiNER2 already exists (GLiNER2Swift) but it is
> macOS-CPU / MLX only. This runs the GPU on iPhone (and, AOT-compiled, the ANE) β€” the first GLiNER
> on Apple Silicon's accelerators.
## Use it
Three lines with [**CoreAIKit**](https://github.com/john-rocky/coreai-kit) β€” `InformationExtractor`
downloads this bundle once, then runs fully offline:
```swift
import CoreAIKitEmbeddings
let extractor = try await InformationExtractor(model: .gliner2PII)
// zero-shot: any labels you want, decided at call time
let entities = try await extractor.extract(
from: "Contact Dr. Sarah Johnson at sarah.j@acme.com or +1-415-555-0142.",
entities: ["person", "email", "phone number"])
// ["person": ["Sarah Johnson"], "email": ["sarah.j@acme.com"], "phone number": ["+1-415-555-0142"]]
// or redact in place
let clean = try await extractor.redact(
"SSN 123-45-6789, card 4111 1111 1111 1111.",
entities: ["social security number", "credit card number"])
// "SSN [SOCIAL SECURITY NUMBER], card [CREDIT CARD NUMBER]."
```
Runnable demo: **[Examples/InfoExtract β†—](https://github.com/john-rocky/coreai-kit/tree/main/Examples/InfoExtract)**
β€” a paste-text β†’ detect-and-redact PII app (iOS + macOS CLI).
## How it works
One fused static graph runs the whole model; the host handles the text↔schema plumbing that makes it
schema-agnostic.
- **Fused graph** β€” `forward(input_ids[1,256], attention_mask[1,256], text_word_idx[1,96],
schema_idx[1,17]) β†’ span_scores[1,16,96,8]`. Inside: mDeBERTa-v3 (disentangled attention, exported
at a fixed shape so the relative-position buckets gather cleanly) β†’ "first" sub-word pooling β†’
SpanMarker β†’ CountLSTM β†’ einsum β†’ sigmoid. `MMAX=16` labels, `T=96` words, span width `K=8`.
- **Schema-agnostic** β€” the label set is **not** baked in. The host linearizes the user's labels
into the graph's `input_ids` (`( [P] entities ( [E] l0 [E] l1 … ) ) [SEP_TEXT] …`) and supplies the
gather indices, so a single converted bundle answers any schema up to `MMAX`.
- **Host collator** β€” mDeBERTa SentencePiece/Unigram tokenization + GLiNER word-split + schema
linearization + first-sub-word / schema-marker gather positions. Byte-identical to GLiNER2's Python
`collate_fn_inference`.
- **Host decode** β€” per-label threshold + confidence-descending greedy NMS over character spans,
byte-identical to GLiNER2 `_format_spans`.
## Verification
Byte-gated against the reference GLiNER2 `ext.extract` at every tier β€” the Swift collator matches
Python `collate_fn_inference` (input ids + gather indices), the fp16 Core AI graph matches the fp32
reference (span-scores cos **0.999993**), and the decoded entities match exactly:
- **Python** β€” fp32 span-scores cos 1.0, decoded entities == `ext.extract`.
- **Swift on Mac GPU** β€” the demo PII suite decodes byte-identically; arbitrary runtime schemas
(credentials, org/money/date/location) also match `ext.extract` exactly.
- **iPhone 17 Pro** (A19 Pro, AOT h18p) β€” same suite, `GATE_RESULT: PASS`. Model load ~1.8 s;
extraction ~22–32 ms per text (warm).
## Files
- `macos/` β€” JIT `.aimodel` (fp16, ~582 MB) + `tokenizer/` + `extractor.json`.
- `ios/` β€” AOT-compiled h18p bundle (~823 MB; the device JIT is skipped) + `tokenizer/` +
`extractor.json`.
`extractor.json` carries the graph shapes and the GLiNER special-marker token ids (they live above
the Unigram vocab, so the host emits them directly). The tokenizer is the mDeBERTa SentencePiece model
declared as `XLMRobertaTokenizer` so swift-transformers routes it through its Unigram implementation.
- Base model: [fastino/gliner2-privacy-filter-PII-multi](https://huggingface.co/fastino/gliner2-privacy-filter-PII-multi) (Apache-2.0), on [microsoft/mdeberta-v3-base](https://huggingface.co/microsoft/mdeberta-v3-base) (MIT).
- Conversion + Swift-port reference: [CoreAI-Model-Zoo](https://github.com/john-rocky/CoreAI-Model-Zoo).