--- library_name: gliner pipeline_tag: token-classification base_model: Qwen/Qwen3-0.6B tags: - gliner - gliner-streaming - named-entity-recognition - zero-shot-ner - pii - privacy - multilingual language: - en metrics: - precision - recall - f1 license: apache-2.0 --- # GLiNER Streaming PII — Qwen3 0.6B An open-label PII detector built with the GLiNER streaming-span architecture and a Qwen3-0.6B causal backbone. It supports regular full-text inference, cached incremental streams, and full-session recomputation. This model was developed in collaboration between [Wordcab](https://wordcab.com/) and [Knowledgator](https://www.knowledgator.com/). For enterprise-ready, specialized PII/PHI/PCI models, contact us at info@knowledgator.com. ## Architecture Following the component schema in the [GLiNER architecture docs](https://github.com/urchade/GLiNER/blob/main/docs/add_custom_architecture.md), this checkpoint is composed of: [![GLiNER Streaming Span architecture](assets/gliner-streaming-architecture.svg)](assets/gliner-streaming-architecture.svg) ## Install and load ```bash pip install "gliner>=0.2.28" ``` ```python import torch from gliner import GLiNER device = "cuda" if torch.cuda.is_available() else "cpu" dtype = "bf16" if device == "cuda" else "fp32" model = GLiNER.from_pretrained( "knowledgator/gliner-stream-pii-v1.0", load_tokenizer=True, map_location=device, dtype=dtype, ).eval() labels = [ "person", "email address", "phone number", "street address", "credit card number", "passport number", ] ``` ## Three inference strategies | Strategy | API | What is computed | Best for | |---|---|---|---| | **1. Stateless full text** | No `session_id` | Complete input and label prompt | Documents, batches, independent requests | | **2. Cached incremental** | `session_id=[id]` | New chunk only; decoder KV, labels, words, and span history are reused | Live chat, ASR, logs, token streams | | **3. Full recompute** | `session_id=[id], recompute=True` | Accumulated session plus new chunk; cache and all spans are rebuilt | Final pass, changed labels, correction after drift | ### 1. Stateless full text ```python entities = model.predict_entities( "Jane Doe can be reached at jane.doe@example.com.", labels, threshold=0.5, ) ``` ### 2. Cached incremental session ```python session_id = "call-42" for chunk in [ "Customer Jane", " Doe asked us to call", " +1 (415) 555-0132.", ]: snapshot = model.inference( [chunk], labels, session_id=[session_id], threshold=0.5, )[0] print(snapshot) ``` ### 3. Full-session recompute ```python # The next chunk must be non-empty. This reruns all accumulated text # and also permits a changed label set. final_labels = labels + ["account number"] final_snapshot = model.inference( [" Account 12345678 was also mentioned."], final_labels, session_id=[session_id], recompute=True, threshold=0.5, )[0] model.clear_session(session_id) ``` Streaming details: - Each call returns the **complete current session snapshot**, not only new entities. - Chunks are concatenated verbatim; preserve boundary spaces and punctuation. - Offsets refer to the complete accumulated text. - Keep labels fixed unless using `recompute=True`; always clear finished sessions. ## Evaluation PIIMB ranking scores are label-agnostic, character-level masking metrics. They are micro-averaged within each task; group rows are unweighted averages across tasks. F2 is primary because it weights recall more heavily. Strict NER F1 also requires matching entity boundaries and type. | Scope / task | Precision | Recall | Masking F1 | Masking F2 | FPR | Strict NER F1 | |---|---:|---:|---:|---:|---:|---:| | **English average** | 87.36% | 91.55% | 89.18% | **90.53%** | 3.01% | — | | **Multilingual average** | 53.84% | 78.32% | 60.45% | **68.21%** | 5.85% | — | | `ai4privacy-en` | 94.69% | 95.16% | 94.92% | **95.06%** | 1.52% | 67.99% | | `ai4privacy-multi` | 87.34% | 92.96% | 90.07% | **91.78%** | 3.82% | 55.39% | | `gretel` | 86.95% | 95.58% | 91.06% | **93.72%** | 5.20% | 67.38% | | `mapa-eur-lex` | 20.34% | 63.67% | 30.83% | **44.65%** | 7.88% | 10.91% | | `nemotron-pii` | 72.75% | 88.07% | 79.68% | **84.51%** | 4.98% | 68.93% | | `privy` | 95.07% | 87.39% | 91.07% | **88.83%** | 0.33% | 81.68% | Configuration: PIIMB v0.3.0, dataset revision `4a13e9ffe6fd0d275efbde8afd4d8d8f1ffc2133`, `sentences` subset, threshold 0.5, bfloat16, evaluated 2026-07-24. The main weakness is multilingual legal and administrative text: `mapa-eur-lex` reaches only 44.65% masking F2. Validate on the target languages, domains, labels, and threshold before deployment. ## References - [Blog](https://medium.com/p/11aefa0e4ad8?postPublishedType=initial) - [GLiNER paper](https://arxiv.org/abs/2311.08526) - [Qwen3 Technical Report](https://arxiv.org/abs/2505.09388) - [PIIMB benchmark](https://huggingface.co/datasets/piimb/pii-masking-benchmark) - [GLiNER repository](https://github.com/urchade/GLiNER)