LFM2.5 Encoder 350M PII Detector (q8 ONNX) β€” Solus v1

The wider of the two entity extractors behind Solus's PII tools: LiquidAI's LFM2.5 bidirectional encoder with a BIOES token-classification head, exported to ONNX from the published safetensors and quantized to 8 bits.

It is a token classifier, not a generative model: it labels every subword and the spans are read back out of the tags, so it cannot invent a finding that is not in the input. It covers 40 kinds of personal detail across 16 languages β€” identity, contact, financial, credential, device, location, healthcare and special-category β€” where the GLiNER2 package covers seven in seven languages.

Boundaries of format-bound values (e-mail, IBAN, card, phone, URL) are repaired after the model by the regex tier in solus_engine::pii_hybrid, a port of the pii_hybrid_decode.py shipped with the upstream model. Without that tier a token classifier tags fragments β€” 905 and 555 inside a phone number β€” and a redaction built on fragments leaves the rest of the value in the document.

Specifications

Parameters 0.4B
Quantization 8-bit (MatMulNBits)
Install size 546.0 MB
Minimum RAM 2.0 GB
Minimum VRAM not required
Window 2,048 subwords, overlapped for longer text
Tagging scheme BIOES, 161 classes over 40 entity types
SHA-256 18b1ecc9c746ae4746b6a14de39902e538e4ec6ccfbe56ac27aad70aef12d41e (model_q8.onnx)

Installs as a directory. Every file below is required:

File Size
model_q8.onnx 401.3 KB
model_q8.onnx.data 541.1 MB
tokenizer.json 4.5 MB
labels.json 5.4 KB
onnx_export_metadata.json 1.4 KB

The graph

input_ids      [batch, sequence] int64
attention_mask [batch, sequence] int64
    ->  logits [batch, sequence, 161] float32

No cache inputs. This is a bidirectional encoder and the upstream modeling code forces use_cache=False, so a KV-cache interface would be meaningless β€” worth saying because another ONNX export of this model on the Hub ships exactly that, with 65536-wide logits: it exports the base model's language-model head rather than the tagger.

import json, numpy as np, onnxruntime as ort
from tokenizers import Tokenizer

labels = json.load(open("labels.json"))["labels"]
tok = Tokenizer.from_file("tokenizer.json")
sess = ort.InferenceSession("model_q8.onnx")

enc = tok.encode("Email laura@charite.de or call 905-555-0142 today.")
ids = np.array([enc.ids], dtype=np.int64)
logits = sess.run(["logits"], {"input_ids": ids, "attention_mask": np.ones_like(ids)})[0][0]
tags = [labels[c] for c in logits.argmax(-1)]   # BIOES, decode over enc.offsets

model_q8.onnx.data must sit beside the graph. onnx_export_metadata.json records the export settings and a smoke test taken from this graph.

Decoding: read the tags, then repair the boundaries

Entity types: contact.address, contact.email, contact.ip_address, contact.phone, contact.postal_code, credential.api_key, credential.connection_string, credential.jwt, credential.password, credential.private_key, developer.device_id, developer.login_credentials, device.imei, device.mac_address, financial.amount, financial.bank_account, financial.credit_card, financial.crypto_wallet, financial.iban, financial.swift_bic, healthcare.condition, healthcare.health_plan_id, healthcare.medical_record, healthcare.medication, identity.date_of_birth, identity.drivers_license, identity.national_id, identity.passport, identity.person_name, identity.ssn, identity.tax_id, legal.case_number, location.gps_coordinates, online.url, online.username, org.company_name, special.health_status, special.orientation, special.political, special.religion.

Reading BIOES over the tokenizer's offsets is not the whole decode. Like every byte-BPE token classifier, this model fragments the boundaries of format-bound values β€” it tags 905 and 555 inside a phone number, and https inside a URL. Anything that redacts from the raw tags therefore leaves the rest of the value in the document.

The upstream repo ships pii_hybrid_decode.py, a regex tier that fixes this: distinctive formats (e-mail, IBAN, card, IP, URL, SSN, MAC, crypto wallet, API key) are matched independently and own their boundaries, while false-positive- prone shapes (phone, date of birth, amount, postal code) only widen a fragment the model already found. Use it, or an equivalent β€” Solus reimplements it in Rust as solus_engine::pii_hybrid.

Conversion

LiquidAI/LFM2.5-Encoder-350M-PII-Detector (safetensors) converted to ONNX and quantized at the Faculty of Engineering, McMaster University. Modified from the original work, as the LFM Open License requires it be stated: the weights were exported from safetensors to an ONNX graph with torch.onnx.export (opset 17, use_cache off) and then quantized to 8-bit MatMulNBits (block size 128, asymmetric). The architecture, the head and the label set are unchanged.

Checked in stages: the fp32 export matches the PyTorch model to 3e-5 with identical spans on the export fixtures, and the 8-bit graph reproduces the same post-decode findings on all of them.

Provenance

  • Original model: LiquidAI/LFM2.5-Encoder-350M-PII-Detector
  • Licence: LFM Open License v1.0, included as LICENSE. Commercial use is not licensed for a legal entity above $10,000,000 annual revenue (qualified non-profits exempt).
  • Published for Solus, a desktop app for running AI models entirely on your own machine.
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support

Model tree for Fazmin/solus_v1_lfm2-encoder-350m-pii-q8