Upload int8-weight-only release artifact
Browse files- .gitattributes +4 -0
- README.md +408 -0
- config.json +202 -0
- figures/evaluation-test-1-1.png +3 -0
- figures/evaluation-train-1-1.png +3 -0
- label-taxonomy.yaml +242 -0
- model_quantized.onnx +3 -0
- model_quantized.onnx_data +3 -0
- tokenizer.json +3 -0
- tokenizer_config.json +13 -0
- viterbi_calibration.json +14 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,7 @@ 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 |
+
figures/evaluation-test-1-1.png filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
figures/evaluation-train-1-1.png filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
model_quantized.onnx_data filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
tokenizer.json filter=lfs diff=lfs merge=lfs -text
|
README.md
ADDED
|
@@ -0,0 +1,408 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
language:
|
| 3 |
+
- ko
|
| 4 |
+
- en
|
| 5 |
+
license: apache-2.0
|
| 6 |
+
library_name: onnxruntime
|
| 7 |
+
pipeline_tag: token-classification
|
| 8 |
+
inference: false
|
| 9 |
+
base_model: openai/privacy-filter
|
| 10 |
+
tags:
|
| 11 |
+
- onnx
|
| 12 |
+
- onnxruntime
|
| 13 |
+
- int8
|
| 14 |
+
- weight-only
|
| 15 |
+
- token-classification
|
| 16 |
+
- ner
|
| 17 |
+
- pii
|
| 18 |
+
- privacy
|
| 19 |
+
- pii-masking
|
| 20 |
+
- korean
|
| 21 |
+
- finance
|
| 22 |
+
- bioes
|
| 23 |
+
- viterbi
|
| 24 |
+
- mixture-of-experts
|
| 25 |
+
datasets:
|
| 26 |
+
- BCCard/pii-masking-openpii-finance
|
| 27 |
+
metrics:
|
| 28 |
+
- f1
|
| 29 |
+
- precision
|
| 30 |
+
- recall
|
| 31 |
+
---
|
| 32 |
+
|
| 33 |
+
# 1. Overview
|
| 34 |
+
This repository provides the INT8 weight-only ONNX Runtime serving artifact for a Korean/English PII detection model for the finance domain. The model was built by full fine-tuning [`openai/privacy-filter`](https://huggingface.co/openai/privacy-filter) - a 1.4B-parameter MoE with 50M active parameters - on synthetic finance-domain PII data. It tags 18 PII entity types using 73
|
| 35 |
+
BIOES token classes at token level.
|
| 36 |
+
|
| 37 |
+
The model is designed as the NER layer of a multi-layer PII-masking gateway in front of LLM services. It should be deployed with a deterministic regex backstop for fully structured identifiers and must not be treated as a standalone anonymization, compliance or privacy guarantee. High-sensitivity deployments require in-domain evaluation and ongoing monitoring.
|
| 38 |
+
|
| 39 |
+
This repository does not contain PyTorch weights. `AutoModelForTokenClassification.from_pretrained()`
|
| 40 |
+
and the standard Transformers token-classification pipeline therefore do not load this artifact. Use ONNX Runtime as shown in [Usage](#13-usage).
|
| 41 |
+
|
| 42 |
+
The serving chain is:
|
| 43 |
+
|
| 44 |
+
```text
|
| 45 |
+
text
|
| 46 |
+
-> tokenizer
|
| 47 |
+
-> INT8 weight-only ONNX graph
|
| 48 |
+
-> FP32 logits
|
| 49 |
+
-> constrained BIOES Viterbi
|
| 50 |
+
-> character-offset spans
|
| 51 |
+
-> whitespace boundary refinement
|
| 52 |
+
```
|
| 53 |
+
|
| 54 |
+
## 1.1. TL;DR
|
| 55 |
+
* **Base model**: [`openai/privacy-filter`](https://huggingface.co/openai/privacy-filter) โ 1.4B-parameter MoE (128 experts, 50M active), 8 layers, hidden 640, bidirectional banded attention (ยฑ128), o200k tokenizer
|
| 56 |
+
* **Domain / Language**: Finance (BC Card โ cards, accounts, national IDs, customer service text) / Korean + English
|
| 57 |
+
* **Task**: Token classification (BIOES) โ character-offset PII spans โ masking
|
| 58 |
+
* **Labels (18)**: `PERSON, RRN, FRN, CARD_NUMBER, ACCOUNT_NUMBER, SECRET, USER_ID, EMAIL, PHONE, PASSPORT, DRIVER_LICENSE, GENERIC_ID, ADDRESS, ZIPCODE, DATE, CARD_EXPIRY, CVC, IPIN`
|
| 59 |
+
* **Method**: Full fine-tuning (all parameters incl. experts & router) with a re-initialized 73-class head (rows copied from the base head by taxonomy mapping)
|
| 60 |
+
* **Decoding**: **constrained BIOES Viterbi** (not per-token argmax) + whitespace span refinement โ the bundled `viterbi_calibration.json` exposes precisionโrecall operating-point biases without retraining
|
| 61 |
+
* **Format**: INT8 weight-only ONNX (`MatMulNBits`, `QMoE`, `GatherBlockQuantized`) with FP32 activations and logits; graph + external tensor data + tokenizer + label taxonomy + Viterbi calibration sidecar
|
| 62 |
+
* **Sequence length**: trained on sequences โค768 tokens โ chunk longer inputs
|
| 63 |
+
* **Intended use**
|
| 64 |
+
- In-house **PII masking gateway** (detect โ mask before text reaches an LLM)
|
| 65 |
+
- Korean-centric finance text with mixed English (IDs, e-mails, card numbers)
|
| 66 |
+
|
| 67 |
+
## 1.2. Label Taxonomy (N=18)
|
| 68 |
+
The 18 labels re-map the upstream ai4privacy source labels to the granularity a Korean financial masking policy needs - merging fragments into single spans (`GIVENNAME`/`SURNAME` โ `PERSON`, `CITY`/`STREET`/`BUILDINGNUM` โ `ADDRESS`) and adding Korea-specific classes absent upstream (`RRN`, `FRN`, `IPIN`, `CARD_EXPIRY`, `CVC`, `SECRET`). `data source` records the row-source buckets in which each label occurs: `ko` means `openpii-1.5m-ko`, `en` means `openpii-1.5m-en`, and `domain` means locally synthesized rows.
|
| 69 |
+
|
| 70 |
+
| label | description | data source |
|
| 71 |
+
|-------|-------------|-------------|
|
| 72 |
+
| `PERSON` | full name (surname + given, single span) | ko, en, domain |
|
| 73 |
+
| `RRN` | resident registration number (Korea) | ko, domain |
|
| 74 |
+
| `FRN` | foreign registration number | domain |
|
| 75 |
+
| `CARD_NUMBER` | credit/debit card PAN | ko, en, domain |
|
| 76 |
+
| `ACCOUNT_NUMBER` | bank account number | ko, domain |
|
| 77 |
+
| `SECRET` | auth secret (password / API key / token) | ko, domain |
|
| 78 |
+
| `USER_ID` | online member ID | ko, en, domain |
|
| 79 |
+
| `EMAIL` | email address | ko, en, domain |
|
| 80 |
+
| `PHONE` | phone number (mobile / landline) | ko, en, domain |
|
| 81 |
+
| `PASSPORT` | passport number | ko, en, domain |
|
| 82 |
+
| `DRIVER_LICENSE` | driver's license number | ko, en, domain |
|
| 83 |
+
| `GENERIC_ID` | generic identifier (no KO counterpart) | ko, en, domain |
|
| 84 |
+
| `ADDRESS` | address (city / street / building, single span) | ko, en, domain |
|
| 85 |
+
| `ZIPCODE` | postal code | ko, en, domain |
|
| 86 |
+
| `DATE` | date / time | ko, en, domain |
|
| 87 |
+
| `CARD_EXPIRY` | card expiry date | domain |
|
| 88 |
+
| `CVC` | card verification code | domain |
|
| 89 |
+
| `IPIN` | I-PIN number | domain |
|
| 90 |
+
|
| 91 |
+
Each entity type has `B-`, `I-`, `E-` and `S-` boundary classes, plus the background class `O`. This yields 73 output classes. The bundled `label-taxonomy.yaml` and `config.json` must remain in the same label order.
|
| 92 |
+
|
| 93 |
+
## 1.3. Usage
|
| 94 |
+
Install the CPU runtime and client dependencies:
|
| 95 |
+
|
| 96 |
+
```bash
|
| 97 |
+
pip install "onnxruntime>=1.28,<1.29" "huggingface-hub>=1.5" "transformers>=5.6" numpy
|
| 98 |
+
```
|
| 99 |
+
|
| 100 |
+
The following example downloads the repository and runs the INT8 ONNX graph. To reproduce the validated output, use the functions in [Viterbi Reference Implementation](#43-viterbi-reference-implementation)
|
| 101 |
+
to apply constrained BIOES decoding and recover refined character-offset spans. Independent token argmax is not equivalent to the validated decoding chain.
|
| 102 |
+
|
| 103 |
+
```python
|
| 104 |
+
import json
|
| 105 |
+
from pathlib import Path
|
| 106 |
+
|
| 107 |
+
import numpy as np
|
| 108 |
+
import onnxruntime as ort
|
| 109 |
+
|
| 110 |
+
from huggingface_hub import snapshot_download
|
| 111 |
+
from transformers import AutoTokenizer
|
| 112 |
+
|
| 113 |
+
model_id = "BCCard/MoAI-Privacy-Filter-INT8"
|
| 114 |
+
model_dir = Path(snapshot_download(repo_id=model_id))
|
| 115 |
+
tokenizer = AutoTokenizer.from_pretrained(model_dir)
|
| 116 |
+
config = json.loads((model_dir / "config.json").read_text(encoding="utf-8"))
|
| 117 |
+
labels = tuple(
|
| 118 |
+
config["id2label"][str(index)]
|
| 119 |
+
for index in range(len(config["id2label"]))
|
| 120 |
+
)
|
| 121 |
+
calibration = json.loads(
|
| 122 |
+
(model_dir / "viterbi_calibration.json").read_text(encoding="utf-8")
|
| 123 |
+
)
|
| 124 |
+
biases = calibration["operating_points"]["default"]["biases"]
|
| 125 |
+
|
| 126 |
+
session = ort.InferenceSession(
|
| 127 |
+
str(model_dir / "model_quantized.onnx"),
|
| 128 |
+
providers=["CPUExecutionProvider"],
|
| 129 |
+
)
|
| 130 |
+
text = "๊ณ ๊ฐ ๋ชจ์์ด๋(000000-0000000)๊ป์ 010-0000-0000๋ก ์ฐ๋ฝ ์์ฒญํ์
จ์ต๋๋ค."
|
| 131 |
+
encoding = tokenizer(
|
| 132 |
+
text,
|
| 133 |
+
return_offsets_mapping=True,
|
| 134 |
+
add_special_tokens=False,
|
| 135 |
+
return_tensors="np",
|
| 136 |
+
)
|
| 137 |
+
offsets = encoding.pop("offset_mapping")[0].tolist()
|
| 138 |
+
feeds = {
|
| 139 |
+
model_input.name: np.asarray(encoding[model_input.name], dtype=np.int64)
|
| 140 |
+
for model_input in session.get_inputs()
|
| 141 |
+
}
|
| 142 |
+
logits = session.run(["logits"], feeds)[0]
|
| 143 |
+
length = int(feeds["attention_mask"][0].sum())
|
| 144 |
+
|
| 145 |
+
# Copy constrained_viterbi() and decode_spans() from Section 4.3.
|
| 146 |
+
path = constrained_viterbi(logits[0, :length], labels, biases)
|
| 147 |
+
tags = [labels[class_id] for class_id in path]
|
| 148 |
+
spans = decode_spans(tags, offsets[:length], text)
|
| 149 |
+
|
| 150 |
+
print(logits.shape)
|
| 151 |
+
print(spans)
|
| 152 |
+
```
|
| 153 |
+
|
| 154 |
+
Output from the INT8 graph:
|
| 155 |
+
|
| 156 |
+
```text
|
| 157 |
+
(1, 30, 73)
|
| 158 |
+
[
|
| 159 |
+
{'start': 3, 'end': 6, 'label': 'PERSON'},
|
| 160 |
+
{'start': 8, 'end': 22, 'label': 'RRN'},
|
| 161 |
+
{'start': 26, 'end': 39, 'label': 'PHONE'}
|
| 162 |
+
]
|
| 163 |
+
```
|
| 164 |
+
|
| 165 |
+
The offsets use Python's half-open character interval `[start, end)`. Masking is downstream policy logic. For example, the spans above can produce:
|
| 166 |
+
|
| 167 |
+
```text
|
| 168 |
+
๊ณ ๊ฐ [PERSON]๋([RRN])๊ป์ [PHONE]๋ก ์ฐ๋ฝ ์์ฒญํ์
จ์ต๋๋ค.
|
| 169 |
+
```
|
| 170 |
+
|
| 171 |
+
For batches, enable right padding and pass only `input_ids` and `attention_mask` to the graph. `offset_mapping` stays outside ONNX and is used only to map decoded token tags back to the original text. Inputs are INT64 and the graph always returns FP32 logits.
|
| 172 |
+
|
| 173 |
+
|
| 174 |
+
## 1.4. Training Data
|
| 175 |
+
| Dataset | Role | Size |
|
| 176 |
+
|---------|------|------|
|
| 177 |
+
| (Public) [BCCard/pii-masking-openpii-finance](https://huggingface.co/datasets/BCCard/pii-masking-openpii-finance) (v2) | Training / validation | ~58.5k train rows ยท ~14.5k validation rows |
|
| 178 |
+
| (Private) BCCard/pii-masking-openpii-finance-test (v2) | Golden Set (release gate; never used for training/tuning) | 2,000 rows (ko 1,460 / en 540) |
|
| 179 |
+
|
| 180 |
+
* Sources: curated Korean subset of `ai4privacy/pii-masking-openpii-1.5m` (label taxonomy remapped, name spans merged & naturalized) + finance-domain synthetic templates + **~30% English replay** (forgetting guard)
|
| 181 |
+
* Hard-example design baked into v2: surface-similar non-PII decoys (FP suppression), label-confusion pairs in one sentence (RRNโFRN, DRIVER_LICENSEโGENERIC_ID), weak-context true PII (FN suppression), long-span address boundary variants
|
| 182 |
+
* All values are synthetic; validity-pattern collisions with real identifiers are removed at generation time (e.g. card numbers are forced to fail Luhn)
|
| 183 |
+
|
| 184 |
+
|
| 185 |
+
## 1.5. Training Procedure
|
| 186 |
+
| Item | Value |
|
| 187 |
+
|------|-------|
|
| 188 |
+
| Method | Full fine-tuning (1.4B params โ experts and router included) |
|
| 189 |
+
| Head | 33-class base head โ 73-class head, initialized by copying base rows via taxonomy mapping |
|
| 190 |
+
| Loss | Token-level cross-entropy |
|
| 191 |
+
| Batch | effective 16 (per-device ร world ร accum), fixed across hardware layouts |
|
| 192 |
+
| LR / scheduler | 1e-4 / linear decay, warmup 3% |
|
| 193 |
+
| Optimizer | AdamW (fused), weight decay 0.0, max_grad_norm 1.0 |
|
| 194 |
+
| Epochs | 5 โ best checkpoint by validation span micro-F1, **decoded with the same constrained Viterbi as deployment** |
|
| 195 |
+
| Precision | FP32 master weights + BF16 autocast; MoE router/experts explicitly kept FP32 during compute |
|
| 196 |
+
| Hardware | 1ร NVIDIA H100 (~5h) |
|
| 197 |
+
|
| 198 |
+
<div align="center">
|
| 199 |
+
<img src="figures/evaluation-train-1-1.png" alt="Training loss, learning-rate and gradient-norm curves for the v1 and v2 models" >
|
| 200 |
+
</div>
|
| 201 |
+
|
| 202 |
+
<div align="center">
|
| 203 |
+
<img src="figures/evaluation-test-1-1.png" alt="Training-time validation metric curves for the v1 and v2 models" >
|
| 204 |
+
</div>
|
| 205 |
+
|
| 206 |
+
<br>
|
| 207 |
+
|
| 208 |
+
# 2. Evaluation
|
| 209 |
+
## 2.1. INT8 Validation Results
|
| 210 |
+
The INT8 artifact was evaluated on all 14,543 v2 validation rows with the same tokenizer, actual character offsets, constrained Viterbi decoder and whitespace refinement used in the serving example.
|
| 211 |
+
|
| 212 |
+
| Metric | INT8 ONNX |
|
| 213 |
+
|---|---:|
|
| 214 |
+
| strict micro F1 | 0.9599 |
|
| 215 |
+
| macro F1 | 0.9607 |
|
| 216 |
+
| ko strict micro F1 | 0.9560 |
|
| 217 |
+
| ko macro F1 | 0.9571 |
|
| 218 |
+
| en strict micro F1 | 0.9689 |
|
| 219 |
+
| en macro F1 | 0.9641 |
|
| 220 |
+
| masking coverage - diagnostic | 0.9980 |
|
| 221 |
+
| ko masking coverage - diagnostic | 0.9987 |
|
| 222 |
+
| en masking coverage - diagnostic | 0.9967 |
|
| 223 |
+
|
| 224 |
+
Masking coverage is the proportion of gold PII characters covered by the union of predicted spans, regardless of predicted label. It is a diagnostic value and was not used as the INT8 pass or fail gate.
|
| 225 |
+
|
| 226 |
+
## 2.2. INT8 Parity Against FP32 ONNX
|
| 227 |
+
| Metric | FP32 ONNX | INT8 ONNX | Delta |
|
| 228 |
+
|---|---:|---:|---:|
|
| 229 |
+
| strict micro F1 | 0.959801 | 0.959886 | +0.000085 |
|
| 230 |
+
| macro F1 | 0.960264 | 0.960662 | +0.000398 |
|
| 231 |
+
| masking coverage - diagnostic | 0.997960 | 0.997980 | +0.000020 |
|
| 232 |
+
| ko strict micro F1 | 0.955986 | 0.956047 | +0.000061 |
|
| 233 |
+
| en strict micro F1 | 0.968768 | 0.968910 | +0.000142 |
|
| 234 |
+
|
| 235 |
+
INT8 predictions reached strict micro F1 0.998568 against FP32 predictions and matched exactly on 14,429 of 14,543 rows. Overall PERSON recall changed by -0.000276 and ADDRESS recall changed by +0.000116. All thresholds fixed before the full run passed. Small positive quality deltas do not show that INT8 is intrinsically more accurate. Quantization moved a small number of boundary decisions in both directions.
|
| 236 |
+
|
| 237 |
+
## 2.3. Limitations and Deployment Guidance
|
| 238 |
+
* The graph uses Microsoft contrib operators. ONNX Runtime 1.28.0 with `CPUExecutionProvider` was validated. Confirm operator placement and fallback behavior before selecting another provider.
|
| 239 |
+
* The M4 validation run was a functional observation, not a serving benchmark. Measure warmup, latency percentiles, throughput, RSS and peak memory on target hardware.
|
| 240 |
+
* Independent token argmax can create invalid BIOES paths and does not reproduce the reported metrics. Use constrained Viterbi decoding.
|
| 241 |
+
* Weak-context Korean person names remain the main known miss channel. Names without honorifics, particles or nearby role cues require particular monitoring.
|
| 242 |
+
* Alphanumeric identifiers can swap among `USER_ID`, `SECRET`, `GENERIC_ID` and `ACCOUNT_NUMBER`. The value may still be masked even when the semantic label is wrong.
|
| 243 |
+
* Training and evaluation use synthetic data. Robustness to real customer text, slang, OCR noise and previously unseen credential formats has not been established.
|
| 244 |
+
* The label policy is fixed to the 18 types above. Changing taxonomy or boundary policy requires fine-tuning.
|
| 245 |
+
* Inputs beyond 768 tokens were not part of this release validation. Chunk longer inputs with overlap and reconcile spans at chunk boundaries.
|
| 246 |
+
* Use deterministic pattern rules as a backstop for structured identifiers and retain review paths for high-sensitivity workflows.
|
| 247 |
+
|
| 248 |
+
<br>
|
| 249 |
+
|
| 250 |
+
# 3. Future Work
|
| 251 |
+
* Benchmark the INT8 artifact on the actual serving hardware and execution provider.
|
| 252 |
+
* Improve weak-context PERSON coverage and collect privacy-safe shadow-mode failure patterns for a future data revision.
|
| 253 |
+
|
| 254 |
+
<br>
|
| 255 |
+
|
| 256 |
+
# 4. Meta Info
|
| 257 |
+
## 4.1. Citation
|
| 258 |
+
```bibtex
|
| 259 |
+
@misc{bccard2026moaiprivacyfilter,
|
| 260 |
+
title = {MoAI Privacy Filter INT8: A Korean Finance-Domain PII Detection Model},
|
| 261 |
+
author = {BC Card AX Team},
|
| 262 |
+
year = {2026},
|
| 263 |
+
howpublished = {https://huggingface.co/BCCard/MoAI-Privacy-Filter-INT8},
|
| 264 |
+
note = {INT8 weight-only ONNX artifact of a full fine-tune of openai/privacy-filter}
|
| 265 |
+
}
|
| 266 |
+
```
|
| 267 |
+
|
| 268 |
+
## 4.2. See Also
|
| 269 |
+
* Base model - [`openai/privacy-filter`](https://huggingface.co/openai/privacy-filter)
|
| 270 |
+
* Parent BF16 model - [`BCCard/MoAI-Privacy-Filter`](https://huggingface.co/BCCard/MoAI-Privacy-Filter)
|
| 271 |
+
* Training dataset - [`BCCard/pii-masking-openpii-finance`](https://huggingface.co/datasets/BCCard/pii-masking-openpii-finance)
|
| 272 |
+
* Source data attribution - `ai4privacy/pii-masking-openpii-1.5m` under CC-BY-4.0
|
| 273 |
+
|
| 274 |
+
## 4.3. Viterbi Reference Implementation
|
| 275 |
+
These functions apply the BIOES transition constraints and calibration biases used for validation, then recover character-offset spans with whitespace boundary refinement. Keep `config.json`, `label-taxonomy.yaml` and `viterbi_calibration.json` in their bundled label order and configuration.
|
| 276 |
+
|
| 277 |
+
<details>
|
| 278 |
+
<summary>Show the constrained Viterbi and span-decoding reference code</summary>
|
| 279 |
+
|
| 280 |
+
```python
|
| 281 |
+
import numpy as np
|
| 282 |
+
|
| 283 |
+
|
| 284 |
+
def transition_bias(
|
| 285 |
+
from_prefix: str,
|
| 286 |
+
to_prefix: str,
|
| 287 |
+
biases: dict[str, float],
|
| 288 |
+
) -> float:
|
| 289 |
+
if from_prefix == "O" and to_prefix == "O":
|
| 290 |
+
return biases["transition_bias_background_stay"]
|
| 291 |
+
if from_prefix == "O" and to_prefix in {"B", "S"}:
|
| 292 |
+
return biases["transition_bias_background_to_start"]
|
| 293 |
+
if from_prefix in {"E", "S"} and to_prefix == "O":
|
| 294 |
+
return biases["transition_bias_end_to_background"]
|
| 295 |
+
if from_prefix in {"E", "S"} and to_prefix in {"B", "S"}:
|
| 296 |
+
return biases["transition_bias_end_to_start"]
|
| 297 |
+
if from_prefix in {"B", "I"} and to_prefix == "I":
|
| 298 |
+
return biases["transition_bias_inside_to_continue"]
|
| 299 |
+
if from_prefix in {"B", "I"} and to_prefix == "E":
|
| 300 |
+
return biases["transition_bias_inside_to_end"]
|
| 301 |
+
raise ValueError(f"Unsupported transition family: {from_prefix} -> {to_prefix}")
|
| 302 |
+
|
| 303 |
+
|
| 304 |
+
def constrained_viterbi(
|
| 305 |
+
logits: np.ndarray,
|
| 306 |
+
labels: tuple[str, ...],
|
| 307 |
+
biases: dict[str, float],
|
| 308 |
+
) -> list[int]:
|
| 309 |
+
scores = np.asarray(logits, dtype=np.float32)
|
| 310 |
+
num_classes = len(labels)
|
| 311 |
+
parsed = [
|
| 312 |
+
("O", None) if tag == "O" else tuple(tag.split("-", 1))
|
| 313 |
+
for tag in labels
|
| 314 |
+
]
|
| 315 |
+
start_scores = np.full(num_classes, -np.inf, dtype=np.float32)
|
| 316 |
+
end_scores = np.full(num_classes, -np.inf, dtype=np.float32)
|
| 317 |
+
transition_scores = np.full(
|
| 318 |
+
(num_classes, num_classes),
|
| 319 |
+
-np.inf,
|
| 320 |
+
dtype=np.float32,
|
| 321 |
+
)
|
| 322 |
+
|
| 323 |
+
for class_id, (tag_prefix, _) in enumerate(parsed):
|
| 324 |
+
if tag_prefix in {"O", "B", "S"}:
|
| 325 |
+
start_scores[class_id] = 0.0
|
| 326 |
+
if tag_prefix in {"O", "E", "S"}:
|
| 327 |
+
end_scores[class_id] = 0.0
|
| 328 |
+
|
| 329 |
+
for from_id, (from_prefix, from_label) in enumerate(parsed):
|
| 330 |
+
for to_id, (to_prefix, to_label) in enumerate(parsed):
|
| 331 |
+
allowed = (
|
| 332 |
+
from_prefix in {"O", "E", "S"}
|
| 333 |
+
and to_prefix in {"O", "B", "S"}
|
| 334 |
+
) or (
|
| 335 |
+
from_prefix in {"B", "I"}
|
| 336 |
+
and to_prefix in {"I", "E"}
|
| 337 |
+
and from_label == to_label
|
| 338 |
+
)
|
| 339 |
+
if allowed:
|
| 340 |
+
transition_scores[from_id, to_id] = transition_bias(
|
| 341 |
+
from_prefix,
|
| 342 |
+
to_prefix,
|
| 343 |
+
biases,
|
| 344 |
+
)
|
| 345 |
+
|
| 346 |
+
delta = start_scores + scores[0]
|
| 347 |
+
backpointers = np.zeros((scores.shape[0], num_classes), dtype=np.int64)
|
| 348 |
+
for token_id in range(1, scores.shape[0]):
|
| 349 |
+
candidates = delta[:, None] + transition_scores
|
| 350 |
+
backpointers[token_id] = np.argmax(candidates, axis=0)
|
| 351 |
+
delta = np.max(candidates, axis=0) + scores[token_id]
|
| 352 |
+
|
| 353 |
+
last_class = int(np.argmax(delta + end_scores))
|
| 354 |
+
path = [last_class]
|
| 355 |
+
for token_id in range(scores.shape[0] - 1, 0, -1):
|
| 356 |
+
path.append(int(backpointers[token_id, path[-1]]))
|
| 357 |
+
return list(reversed(path))
|
| 358 |
+
|
| 359 |
+
|
| 360 |
+
def decode_spans(
|
| 361 |
+
tags: list[str],
|
| 362 |
+
offsets: list[list[int]],
|
| 363 |
+
text: str,
|
| 364 |
+
) -> list[dict[str, int | str]]:
|
| 365 |
+
spans = []
|
| 366 |
+
current = None
|
| 367 |
+
|
| 368 |
+
def flush() -> None:
|
| 369 |
+
nonlocal current
|
| 370 |
+
if current is None:
|
| 371 |
+
return
|
| 372 |
+
start = current["start"]
|
| 373 |
+
end = current["end"]
|
| 374 |
+
while start < end and text[start].isspace():
|
| 375 |
+
start += 1
|
| 376 |
+
while end > start and text[end - 1].isspace():
|
| 377 |
+
end -= 1
|
| 378 |
+
if start < end:
|
| 379 |
+
spans.append(
|
| 380 |
+
{
|
| 381 |
+
"start": start,
|
| 382 |
+
"end": end,
|
| 383 |
+
"label": current["label"],
|
| 384 |
+
}
|
| 385 |
+
)
|
| 386 |
+
current = None
|
| 387 |
+
|
| 388 |
+
for tag, (start, end) in zip(tags, offsets, strict=True):
|
| 389 |
+
if tag == "O":
|
| 390 |
+
flush()
|
| 391 |
+
continue
|
| 392 |
+
tag_prefix, label = tag.split("-", 1)
|
| 393 |
+
if tag_prefix in {"B", "S"} or current is None or current["label"] != label:
|
| 394 |
+
flush()
|
| 395 |
+
current = {
|
| 396 |
+
"start": start,
|
| 397 |
+
"end": end,
|
| 398 |
+
"label": label,
|
| 399 |
+
}
|
| 400 |
+
else:
|
| 401 |
+
current["end"] = end
|
| 402 |
+
if tag_prefix in {"E", "S"}:
|
| 403 |
+
flush()
|
| 404 |
+
flush()
|
| 405 |
+
return spans
|
| 406 |
+
```
|
| 407 |
+
|
| 408 |
+
</details>
|
config.json
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"OpenAIPrivacyFilterForTokenClassification"
|
| 4 |
+
],
|
| 5 |
+
"attention_bias": true,
|
| 6 |
+
"attention_dropout": 0.0,
|
| 7 |
+
"bos_token_id": null,
|
| 8 |
+
"classifier_dropout": 0.0,
|
| 9 |
+
"default_n_ctx": 128000,
|
| 10 |
+
"eos_token_id": 199999,
|
| 11 |
+
"head_dim": 64,
|
| 12 |
+
"hidden_act": "silu",
|
| 13 |
+
"hidden_size": 640,
|
| 14 |
+
"id2label": {
|
| 15 |
+
"0": "O",
|
| 16 |
+
"1": "B-PERSON",
|
| 17 |
+
"2": "I-PERSON",
|
| 18 |
+
"3": "E-PERSON",
|
| 19 |
+
"4": "S-PERSON",
|
| 20 |
+
"5": "B-RRN",
|
| 21 |
+
"6": "I-RRN",
|
| 22 |
+
"7": "E-RRN",
|
| 23 |
+
"8": "S-RRN",
|
| 24 |
+
"9": "B-FRN",
|
| 25 |
+
"10": "I-FRN",
|
| 26 |
+
"11": "E-FRN",
|
| 27 |
+
"12": "S-FRN",
|
| 28 |
+
"13": "B-CARD_NUMBER",
|
| 29 |
+
"14": "I-CARD_NUMBER",
|
| 30 |
+
"15": "E-CARD_NUMBER",
|
| 31 |
+
"16": "S-CARD_NUMBER",
|
| 32 |
+
"17": "B-ACCOUNT_NUMBER",
|
| 33 |
+
"18": "I-ACCOUNT_NUMBER",
|
| 34 |
+
"19": "E-ACCOUNT_NUMBER",
|
| 35 |
+
"20": "S-ACCOUNT_NUMBER",
|
| 36 |
+
"21": "B-SECRET",
|
| 37 |
+
"22": "I-SECRET",
|
| 38 |
+
"23": "E-SECRET",
|
| 39 |
+
"24": "S-SECRET",
|
| 40 |
+
"25": "B-USER_ID",
|
| 41 |
+
"26": "I-USER_ID",
|
| 42 |
+
"27": "E-USER_ID",
|
| 43 |
+
"28": "S-USER_ID",
|
| 44 |
+
"29": "B-EMAIL",
|
| 45 |
+
"30": "I-EMAIL",
|
| 46 |
+
"31": "E-EMAIL",
|
| 47 |
+
"32": "S-EMAIL",
|
| 48 |
+
"33": "B-PHONE",
|
| 49 |
+
"34": "I-PHONE",
|
| 50 |
+
"35": "E-PHONE",
|
| 51 |
+
"36": "S-PHONE",
|
| 52 |
+
"37": "B-PASSPORT",
|
| 53 |
+
"38": "I-PASSPORT",
|
| 54 |
+
"39": "E-PASSPORT",
|
| 55 |
+
"40": "S-PASSPORT",
|
| 56 |
+
"41": "B-DRIVER_LICENSE",
|
| 57 |
+
"42": "I-DRIVER_LICENSE",
|
| 58 |
+
"43": "E-DRIVER_LICENSE",
|
| 59 |
+
"44": "S-DRIVER_LICENSE",
|
| 60 |
+
"45": "B-GENERIC_ID",
|
| 61 |
+
"46": "I-GENERIC_ID",
|
| 62 |
+
"47": "E-GENERIC_ID",
|
| 63 |
+
"48": "S-GENERIC_ID",
|
| 64 |
+
"49": "B-ADDRESS",
|
| 65 |
+
"50": "I-ADDRESS",
|
| 66 |
+
"51": "E-ADDRESS",
|
| 67 |
+
"52": "S-ADDRESS",
|
| 68 |
+
"53": "B-ZIPCODE",
|
| 69 |
+
"54": "I-ZIPCODE",
|
| 70 |
+
"55": "E-ZIPCODE",
|
| 71 |
+
"56": "S-ZIPCODE",
|
| 72 |
+
"57": "B-DATE",
|
| 73 |
+
"58": "I-DATE",
|
| 74 |
+
"59": "E-DATE",
|
| 75 |
+
"60": "S-DATE",
|
| 76 |
+
"61": "B-CARD_EXPIRY",
|
| 77 |
+
"62": "I-CARD_EXPIRY",
|
| 78 |
+
"63": "E-CARD_EXPIRY",
|
| 79 |
+
"64": "S-CARD_EXPIRY",
|
| 80 |
+
"65": "B-CVC",
|
| 81 |
+
"66": "I-CVC",
|
| 82 |
+
"67": "E-CVC",
|
| 83 |
+
"68": "S-CVC",
|
| 84 |
+
"69": "B-IPIN",
|
| 85 |
+
"70": "I-IPIN",
|
| 86 |
+
"71": "E-IPIN",
|
| 87 |
+
"72": "S-IPIN"
|
| 88 |
+
},
|
| 89 |
+
"initial_context_length": 4096,
|
| 90 |
+
"initializer_range": 0.02,
|
| 91 |
+
"intermediate_size": 640,
|
| 92 |
+
"label2id": {
|
| 93 |
+
"B-ACCOUNT_NUMBER": 17,
|
| 94 |
+
"B-ADDRESS": 49,
|
| 95 |
+
"B-CARD_EXPIRY": 61,
|
| 96 |
+
"B-CARD_NUMBER": 13,
|
| 97 |
+
"B-CVC": 65,
|
| 98 |
+
"B-DATE": 57,
|
| 99 |
+
"B-DRIVER_LICENSE": 41,
|
| 100 |
+
"B-EMAIL": 29,
|
| 101 |
+
"B-FRN": 9,
|
| 102 |
+
"B-GENERIC_ID": 45,
|
| 103 |
+
"B-IPIN": 69,
|
| 104 |
+
"B-PASSPORT": 37,
|
| 105 |
+
"B-PERSON": 1,
|
| 106 |
+
"B-PHONE": 33,
|
| 107 |
+
"B-RRN": 5,
|
| 108 |
+
"B-SECRET": 21,
|
| 109 |
+
"B-USER_ID": 25,
|
| 110 |
+
"B-ZIPCODE": 53,
|
| 111 |
+
"E-ACCOUNT_NUMBER": 19,
|
| 112 |
+
"E-ADDRESS": 51,
|
| 113 |
+
"E-CARD_EXPIRY": 63,
|
| 114 |
+
"E-CARD_NUMBER": 15,
|
| 115 |
+
"E-CVC": 67,
|
| 116 |
+
"E-DATE": 59,
|
| 117 |
+
"E-DRIVER_LICENSE": 43,
|
| 118 |
+
"E-EMAIL": 31,
|
| 119 |
+
"E-FRN": 11,
|
| 120 |
+
"E-GENERIC_ID": 47,
|
| 121 |
+
"E-IPIN": 71,
|
| 122 |
+
"E-PASSPORT": 39,
|
| 123 |
+
"E-PERSON": 3,
|
| 124 |
+
"E-PHONE": 35,
|
| 125 |
+
"E-RRN": 7,
|
| 126 |
+
"E-SECRET": 23,
|
| 127 |
+
"E-USER_ID": 27,
|
| 128 |
+
"E-ZIPCODE": 55,
|
| 129 |
+
"I-ACCOUNT_NUMBER": 18,
|
| 130 |
+
"I-ADDRESS": 50,
|
| 131 |
+
"I-CARD_EXPIRY": 62,
|
| 132 |
+
"I-CARD_NUMBER": 14,
|
| 133 |
+
"I-CVC": 66,
|
| 134 |
+
"I-DATE": 58,
|
| 135 |
+
"I-DRIVER_LICENSE": 42,
|
| 136 |
+
"I-EMAIL": 30,
|
| 137 |
+
"I-FRN": 10,
|
| 138 |
+
"I-GENERIC_ID": 46,
|
| 139 |
+
"I-IPIN": 70,
|
| 140 |
+
"I-PASSPORT": 38,
|
| 141 |
+
"I-PERSON": 2,
|
| 142 |
+
"I-PHONE": 34,
|
| 143 |
+
"I-RRN": 6,
|
| 144 |
+
"I-SECRET": 22,
|
| 145 |
+
"I-USER_ID": 26,
|
| 146 |
+
"I-ZIPCODE": 54,
|
| 147 |
+
"O": 0,
|
| 148 |
+
"S-ACCOUNT_NUMBER": 20,
|
| 149 |
+
"S-ADDRESS": 52,
|
| 150 |
+
"S-CARD_EXPIRY": 64,
|
| 151 |
+
"S-CARD_NUMBER": 16,
|
| 152 |
+
"S-CVC": 68,
|
| 153 |
+
"S-DATE": 60,
|
| 154 |
+
"S-DRIVER_LICENSE": 44,
|
| 155 |
+
"S-EMAIL": 32,
|
| 156 |
+
"S-FRN": 12,
|
| 157 |
+
"S-GENERIC_ID": 48,
|
| 158 |
+
"S-IPIN": 72,
|
| 159 |
+
"S-PASSPORT": 40,
|
| 160 |
+
"S-PERSON": 4,
|
| 161 |
+
"S-PHONE": 36,
|
| 162 |
+
"S-RRN": 8,
|
| 163 |
+
"S-SECRET": 24,
|
| 164 |
+
"S-USER_ID": 28,
|
| 165 |
+
"S-ZIPCODE": 56
|
| 166 |
+
},
|
| 167 |
+
"max_position_embeddings": 131072,
|
| 168 |
+
"model_type": "openai_privacy_filter",
|
| 169 |
+
"num_attention_heads": 14,
|
| 170 |
+
"num_experts_per_tok": 4,
|
| 171 |
+
"num_hidden_layers": 8,
|
| 172 |
+
"num_key_value_heads": 2,
|
| 173 |
+
"num_local_experts": 128,
|
| 174 |
+
"onnx_config": {
|
| 175 |
+
"activation_dtype": "float32",
|
| 176 |
+
"block_size": 32,
|
| 177 |
+
"external_data": "model_quantized.onnx_data",
|
| 178 |
+
"model_file": "model_quantized.onnx",
|
| 179 |
+
"operator_profile": "MatMulNBits + QMoE + GatherBlockQuantized",
|
| 180 |
+
"output_dtype": "float32",
|
| 181 |
+
"weight_bits": 8,
|
| 182 |
+
"weight_only": true
|
| 183 |
+
},
|
| 184 |
+
"output_router_logits": false,
|
| 185 |
+
"pad_token_id": 199999,
|
| 186 |
+
"rms_norm_eps": 1e-05,
|
| 187 |
+
"rope_parameters": {
|
| 188 |
+
"beta_fast": 32.0,
|
| 189 |
+
"beta_slow": 1.0,
|
| 190 |
+
"factor": 32.0,
|
| 191 |
+
"original_max_position_embeddings": 4096,
|
| 192 |
+
"rope_theta": 150000.0,
|
| 193 |
+
"rope_type": "yarn",
|
| 194 |
+
"truncate": false
|
| 195 |
+
},
|
| 196 |
+
"router_aux_loss_coef": 0.001,
|
| 197 |
+
"sliding_window": 128,
|
| 198 |
+
"tie_word_embeddings": false,
|
| 199 |
+
"transformers_version": "5.13.1",
|
| 200 |
+
"use_cache": false,
|
| 201 |
+
"vocab_size": 200064
|
| 202 |
+
}
|
figures/evaluation-test-1-1.png
ADDED
|
Git LFS Details
|
figures/evaluation-train-1-1.png
ADDED
|
Git LFS Details
|
label-taxonomy.yaml
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# =============================================================================
|
| 2 |
+
# Label Mapping - ai4privacy 1.5m ๋ผ๋ฒจ -> ๋ด๋ถ ํ์ต ๋ผ๋ฒจ ๋งคํ ํ
์ด๋ธ
|
| 3 |
+
#
|
| 4 |
+
# * ์ญํ : ๋ชจ๋ธ ํ์ต ๋ผ๋ฒจ = ๋ก๊น
์คํค๋ง ํค = ์ ์ฑ
ํ
์ด๋ธ ํค์ ๋จ์ผ ์์ค
|
| 5 |
+
# (docs/handoff/2026-07-03-pii-masking-architecture-qna.md [13])
|
| 6 |
+
# * ์ญ์ฐ ๊ทผ๊ฑฐ: playbooks/privacy_filter/privacy-filter-policy.md (ํ 1 ์ ํ ํจํด / ํ 2 ๋ง์คํน ๊ธฐ์ค)
|
| 7 |
+
# * ์ค์ธก ๊ทผ๊ฑฐ: docs/handoff/2026-07-03-ai4privacy-1p5m-ko-audit.md (v0 ์ด์ + ko ์๋ธ์
๊ฐ์ฌ)
|
| 8 |
+
# * v0 -> v1 ๋ณ๊ฒฝ: ์ฃผ์ ์ฒ๋ฆฌ ํ์ (๋จ์ผ+์๋ธ๋ง์คํน) / FRN ์ ์ค / USER_IDยทACCOUNT_NUMBER
|
| 9 |
+
# ๋๋กญ ์ฒ ํ / ์ฌ๊ถยท์ด์ ๋ฉดํ ๋ถ๋ฆฌ ์ ์ง / regex ์ ๋ด ํญ๋ชฉ ๋ถ๋ฆฌ
|
| 10 |
+
# * 2026-07-21: AGEยทGENDER ๋๋กญ ํ์ (ํ1ยทํ2 ๋ฌด๊ทผ๊ฑฐ - ์ ์ฑ
์ญ์ฐ ์์น ๊ด์ฒ , N=17 -> 15)
|
| 11 |
+
# * 2026-07-21: ํ2 ๋ฌธ๋งฅ ํญ๋ชฉ 3์ข
๋ชจ๋ธ ์น๊ฒฉ (CARD_EXPIRYยทCVCยทIPIN - ๋ฌธ๋งฅ ๊ฒ์ถ์ ๋ชจ๋ธ ๋ ์ธ
|
| 12 |
+
# ๋ณธ๋ น, ํค์๋ regex๋ ์ด์ค ๋ ์ธ ๋ณํ. N=15 -> 18, 61 -> 73ํด๋์ค)
|
| 13 |
+
# =============================================================================
|
| 14 |
+
|
| 15 |
+
version: v1
|
| 16 |
+
date: 2026-07-21
|
| 17 |
+
basis:
|
| 18 |
+
policy: playbooks/privacy_filter/privacy-filter-policy.md
|
| 19 |
+
audit: docs/handoff/2026-07-03-ai4privacy-1p5m-ko-audit.md
|
| 20 |
+
|
| 21 |
+
# -----------------------------------------------------------------------------
|
| 22 |
+
# 1. ๋ชจ๋ธ ํ์ต ๋ผ๋ฒจ (N=18 -> BIOES 4N+1 = 73ํด๋์ค)
|
| 23 |
+
# * data_source: ๋ผ๋ฒจ ํ๋ณธ์ ์ถ์ฒ ๋ฆฌ์คํธ - ko(1.5m-ko ์ ์ ๋ณธ) / en(1.5m-en ๋ฆฌํ๋ ์ด) /
|
| 24 |
+
# domain(๋๋ฉ์ธ ๋ถํธ์คํธ๋ฉ ๋๊ธฐ - ํค๋๋ ์ ์ฌ ๋ผ๋ฒจ ํ ๋ณต์ฌ๋ก init)
|
| 25 |
+
# * RRN์ 1.5m ์ ๋๋ถ์ ko ํ์ (en TAXNUM์ GENERIC_ID fallback) - domain์ ์ฆ๊ฐ ๋ฐฉ์ B
|
| 26 |
+
# * en ๋ถํฌ ์ค์ธก (2026-07-13, 163,740ํ/1,247,393์คํฌ): ์์ 19์ข
์ง์ค - PASSWORD 0,
|
| 27 |
+
# ACCOUNTNUM 1, USERNAME 20 -> "ํฌ์ ๋ผ๋ฒจ์ en ๋ด๋น" ๊ฐ์ค ๊ธฐ๊ฐ, [domain] ์ฌ๋ฐฐ์
|
| 28 |
+
# -----------------------------------------------------------------------------
|
| 29 |
+
model_labels:
|
| 30 |
+
- name: PERSON
|
| 31 |
+
description: ์ฑ๋ช
(์ฑ+์ด๋ฆ ๋ณํฉ ๋จ์ผ ์คํฌ)
|
| 32 |
+
policy_ref: "ํ2 ์ฑ๋ช
(๊น*์ฉ - ์ฒซยท๋ ๊ธ์ ์ ์ธ) / ํ2 ์ฑ๋ช
(์๋ฌธ) (์ 4์๋ฆฌ ๋
ธ์ถ) - ์นํ ์ ์คํฌ๋ฆฝํธ(ํ๊ธ/์๋ฌธ)๋ก ๊ท์น ๋ถ๊ธฐ, full-span ๊ฒฝ๊ณ ํ์"
|
| 33 |
+
data_source: [ko, en]
|
| 34 |
+
head_init_base: private_person
|
| 35 |
+
- name: RRN
|
| 36 |
+
description: ์ฃผ๋ฏผ๋ฑ๋ก๋ฒํธ
|
| 37 |
+
policy_ref: "ํ1 ์ฃผ๋ฏผ๋ฒํธ / ํ2 ์ฃผ๋ฏผ๋ฑ๋ก๋ฒํธ (๋ค 7์๋ฆฌ ๋ง์คํน)"
|
| 38 |
+
data_source: [ko, domain] # domain = ์ฆ๊ฐ ๋ฐฉ์ B ์ ๊ท ์์ฑ๋ถ (์ ๋ต๋ฌธ ยง3.3.1)
|
| 39 |
+
head_init_base: account_number
|
| 40 |
+
- name: FRN
|
| 41 |
+
description: ์ธ๊ตญ์ธ๋ฑ๋ก๋ฒํธ (์ ์ค - 1.5m ์์ค 0๊ฑด)
|
| 42 |
+
policy_ref: "ํ1 ์ธ๊ตญ์ธ๋ฑ๋ก๋ฒํธ ([5-8] ์์) / ํ2 ์ฃผ๋ฏผ๋ฑ๋ก๋ฒํธ(์ธ๊ตญ์ธ๋ฑ๋ก๋ฒํธ ํฌํจ) (๋ค 7์๋ฆฌ)"
|
| 43 |
+
data_source: [domain]
|
| 44 |
+
head_init_from: RRN
|
| 45 |
+
- name: CARD_NUMBER
|
| 46 |
+
description: ์ ์ฉ/์ฒดํฌ์นด๋ ๋ฒํธ
|
| 47 |
+
policy_ref: "ํ1 ์นด๋๋ฒํธ / ํ2 ์นด๋๋ฒํธ (7~12๋ฒ์งธ ์๋ฆฌ, PCI-DSS)"
|
| 48 |
+
data_source: [ko, en, domain] # domain = ์ฆ๊ฐ ๋ฐฉ์ B ์ ๊ท ์์ฑ๋ถ (์ ๋ต๋ฌธ ยง3.3.1)
|
| 49 |
+
head_init_base: account_number
|
| 50 |
+
- name: ACCOUNT_NUMBER
|
| 51 |
+
description: ๊ณ์ข๋ฒํธ (v0 ๋๋กญ ์ฒ ํ - ํ2 ๋ง์คํน ๊ธฐ์ค ์กด์ฌ)
|
| 52 |
+
policy_ref: "ํ1 ๊ณ์ข๋ฒํธ (์ ํ๋ฒํธ ํก์ ์ํ - recognizer ์ฐ์ ์์ ํ์) / ํ2 ๊ณ์ข๋ฒํธ (๋ค 5์๋ฆฌ)"
|
| 53 |
+
data_source: [domain] # ko 5ยทen 1๊ฑด ์ค์ธก - ํฉ์ฑ ์ฆ๊ฐ ํ์ (์ํ๋ณ ํฌ๋งท ๊ท์น ์์ฑ ์ฉ์ด)
|
| 54 |
+
head_init_base: account_number
|
| 55 |
+
- name: SECRET
|
| 56 |
+
description: ์ธ์ฆ ์ํฌ๋ฆฟ (๋น๋ฐ๋ฒํธยทAPI ํคยทํ ํฐ ํตํฉ - ์นด๋/ํ์/ISP ๊ตฌ๋ถ์ ๋ฌธ๋งฅ ๋ถ๊ฐ + ์ก์
๋์ผ)
|
| 57 |
+
policy_ref: "ํ2 ์นด๋๋น๋ฐ๋ฒํธยท์จ๋ผ์ธ ํ์ ํจ์ค์๋ยทISP๋น๋ฐ๋ฒํธ (์ฒ๋ฆฌ ๊ธ์ง -> ๊ฒ์ดํธ์จ์ด์์๋ LLM ๋
ธ์ถ ๊ธ์ง = ์ ์ฒด ๋ง์คํน์ผ๋ก ํด์)"
|
| 58 |
+
data_source: [domain] # 1.5m ์ ๋ฌด (ko 4ยทen 0 ์ค์ธก) - ๋๋ฉ์ธ/ํฉ์ฑ ์ฆ๊ฐ ์ ๋ด
|
| 59 |
+
head_init_base: secret # base 8์ข
์ค secret ํ ์ ํ ๋ณต์ฌ (์ธ์ ์๋ ์ง๊ณ ์์)
|
| 60 |
+
- name: USER_ID
|
| 61 |
+
description: ์จ๋ผ์ธ ํ์ ID (v0 ๋๋กญ ์ฒ ํ - ํ2 ๋ง์คํน ๊ธฐ์ค ์กด์ฌ)
|
| 62 |
+
policy_ref: "ํ2 ์จ๋ผ์ธ ํ์ ID (์ 2์๋ฆฌ ์ ์ธ)"
|
| 63 |
+
data_source: [domain] # ko 4ยทen 20๊ฑด ์ค์ธก - ์ฆ๊ฐ ํ์
|
| 64 |
+
head_init_base: account_number
|
| 65 |
+
- name: EMAIL
|
| 66 |
+
description: ์ด๋ฉ์ผ ์ฃผ์
|
| 67 |
+
policy_ref: "ํ1 ์ด๋ฉ์ผ / ํ2 ์ด๋ฉ์ผ์ฃผ์ (ID ์ 2์๋ฆฌ ์ ์ธ ๋ง์คํน)"
|
| 68 |
+
data_source: [ko, en]
|
| 69 |
+
head_init_base: private_email
|
| 70 |
+
- name: PHONE
|
| 71 |
+
description: ์ ํ๋ฒํธ (ํด๋ํฐ/์ผ๋ฐ์ ํ ํตํฉ - ์นํ ๋จ๊ณ์์ ํ๋ฆฌํฝ์ค๋ก ์ฌ๋ถ๋ฅ)
|
| 72 |
+
policy_ref: "ํ1 ํด๋ํฐ๋ฒํธยท์ ํ๋ฒํธ / ํ2 ๊ธฐ๋ณธ ๋ค 6์๋ฆฌ ๊ณตํต - ๋ด๋ถ๋ง ์ฑ๋ ํ์ ํด๋ํฐ
|
| 73 |
+
๋ค 4์๋ฆฌ ์ํ (์นํ ์ ๊ฐ ํ๋ฆฌํฝ์ค๋ก ํด๋ํฐ ํ๋ณ + ์ฑ๋ ์ถ ๋ถ๊ธฐ)"
|
| 74 |
+
data_source: [ko, en]
|
| 75 |
+
head_init_base: private_phone
|
| 76 |
+
- name: PASSPORT
|
| 77 |
+
description: ์ฌ๊ถ๋ฒํธ (๋ถ๋ฆฌ ์ ์ง - ๋ง์คํน ๊ธฐ์ค ์์ด + ko 3,211๊ฑด)
|
| 78 |
+
policy_ref: "ํ1 ์ฌ๊ถ๋ฒํธ / ํ2 ์ฌ๊ถ๋ฒํธ (๋ค 4์๋ฆฌ)"
|
| 79 |
+
data_source: [ko, en]
|
| 80 |
+
head_init_base: account_number
|
| 81 |
+
- name: DRIVER_LICENSE
|
| 82 |
+
description: ์ด์ ๋ฉดํ๋ฒํธ (๋ถ๋ฆฌ ์ ์ง - ๋ง์คํน ๊ธฐ์ค ์์ด + ko 4,092๊ฑด)
|
| 83 |
+
policy_ref: "ํ1 ์ด์ ๋ฉดํ๋ฒํธ / ํ2 ์ด์ ๋ฉดํ๋ฒํธ (์ค๊ฐ 6์๋ฆฌ)"
|
| 84 |
+
data_source: [ko, en]
|
| 85 |
+
head_init_base: account_number
|
| 86 |
+
- name: GENERIC_ID
|
| 87 |
+
description: ๋ฒ์ฉ ์๋ณ์ (ํ๊ตญ ๋์๋ฌผ ์๋ ID๋ฅ - recall-first๋ก O ๋์ ์ ์ง)
|
| 88 |
+
policy_ref: "audit ยง5 (SOCIALNUM 10์๋ฆฌยทIDCARDNUM ์์ซ์)"
|
| 89 |
+
data_source: [ko, en]
|
| 90 |
+
head_init_base: account_number
|
| 91 |
+
- name: ADDRESS
|
| 92 |
+
description: ์ฃผ์ (์ยท๋๋ก๋ช
ยท๊ฑด๋ฌผ๋ฒํธ ํตํฉ ์คํฌ - ์นํ ๋จ๊ณ์์ ์ซ์ ์๋ธ๋ง์คํน)
|
| 93 |
+
policy_ref: "ํ2 ์ฃผ์ (์ง๋ฒ: ์/๋ฉด/๋ ๋ฏธ๋ง ์ซ์ / ๋๋ก๋ช
: ๊ฑด๋ฌผ๋ฒํธยท์์ธ์ฃผ์ ์ซ์ ๋ง์คํน -> ์คํฌ ๋ด ๊ท์น ์นํ)"
|
| 94 |
+
data_source: [ko, en]
|
| 95 |
+
head_init_base: private_address
|
| 96 |
+
- name: ZIPCODE
|
| 97 |
+
description: ์ฐํธ๋ฒํธ (๋ถ๋ฆฌ ์ ์ง - keep ํ ๊ธ ์ธ๋ถ์ฑ ์ ์ )
|
| 98 |
+
policy_ref: "handoff [10] ZIPCODE keep ์ค์ฆ"
|
| 99 |
+
data_source: [ko, en]
|
| 100 |
+
head_init_base: private_address
|
| 101 |
+
- name: DATE
|
| 102 |
+
description: ๋ ์งยท์๊ฐ (์๋
์์ผ ๋ฏธ๋ถ๋ฆฌ - ko ๋ฐ์ดํฐ DOB 0๊ฑด + ๊ณผ์ ๋ง์คํน ์ค์ ์ธ์ ์กฐํญ)
|
| 103 |
+
policy_ref: "ํ2 ์๋
์์ผ (๋
ธ์ถ ๊ธ์ง - DATE ์ ์ฒด ๋ง์คํน์ผ๋ก ์ด๊ณผ ์ค์)"
|
| 104 |
+
data_source: [ko, en]
|
| 105 |
+
head_init_base: private_date
|
| 106 |
+
- name: CARD_EXPIRY
|
| 107 |
+
description: ์นด๋์ ํจ๊ธฐํ (ํ2 ๋ฌธ๋งฅ ํญ๋ชฉ ์น๊ฒฉ 2026-07-21 - ํค์๋ regex ์ด์ค ๋ ์ธ ๋ณํ)
|
| 108 |
+
policy_ref: "ํ2 ์นด๋์ ํจ๊ธฐํ (**/** ์ ์ฒด ๋ง์คํน)"
|
| 109 |
+
data_source: [domain] # 1.5m ์์ฒ 0๊ฑด - ์ฆ๊ฐ ์ ๋ด (PAN ๋๋ฐ ๋ฌธ๋งฅ ์์ฑ)
|
| 110 |
+
head_init_base: private_date
|
| 111 |
+
- name: CVC
|
| 112 |
+
description: ์นด๋๊ฒ์ฆ์ฝ๋ (CVC/CVV/CAV ํตํฉ - ํ2 ๋ฌธ๋งฅ ํญ๋ชฉ ์น๊ฒฉ 2026-07-21)
|
| 113 |
+
policy_ref: "ํ2 ์นด๋๊ฒ์ฆ์ฝ๋ (์ ์ฅยท์ถ๋ ฅ ๊ธ์ง -> ๊ฒ์ดํธ์จ์ด ์ ์ฒด ๋ง์คํน ํด์)"
|
| 114 |
+
data_source: [domain] # 1.5m ์์ฒ 0๊ฑด - ์ฆ๊ฐ ์ ๋ด (๋จ๋
์์ฑ ๊ธ์ง - PAN ๋๋ฐ ํ์)
|
| 115 |
+
head_init_base: account_number
|
| 116 |
+
- name: IPIN
|
| 117 |
+
description: I-PIN ๋ฒํธ (ํ2 ๋ฌธ๋งฅ ํญ๋ชฉ ์น๊ฒฉ 2026-07-21 - ๊ฐ ๊ท๊ฒฉ pending)
|
| 118 |
+
policy_ref: "ํ2 I-PIN (๋ค 5์๋ฆฌ - ํ์ดํ ๋ฌด๊ด ์ซ์ ๊ธฐ์ค)"
|
| 119 |
+
data_source: [domain] # 1.5m ์์ฒ 0๊ฑด - ๊ท๊ฒฉ ํ์ ์ ํ์ผ๋ฟ ์๋๋ง
|
| 120 |
+
head_init_base: account_number
|
| 121 |
+
|
| 122 |
+
# -----------------------------------------------------------------------------
|
| 123 |
+
# 2. ์์ค ๋ผ๋ฒจ ๋งคํ (ai4privacy 1.5m -> ๋ด๋ถ ๋ผ๋ฒจ)
|
| 124 |
+
# * "O" = ํ์ต์์ ๋น์ํฐํฐ ์ฒ๋ฆฌ (๋๋กญ ๋ฆฌ์คํธ - ์ ์ฑ
ํ ์ปจํ ํ ํ์ )
|
| 125 |
+
# * ์กฐ๊ฑด๋ถ ๋งคํ์ locale + value_pattern ์์ ์ฅ์น ๋๋ฐ
|
| 126 |
+
# -----------------------------------------------------------------------------
|
| 127 |
+
source_mapping: # <source_mapping>
|
| 128 |
+
GIVENNAME: PERSON
|
| 129 |
+
SURNAME: PERSON
|
| 130 |
+
TITLE: O # ๊ตฐ/์/gun/yang ์ง์ญ ์กด์นญ 88% - ์ ๋ ๋๋กญ
|
| 131 |
+
TAXNUM:
|
| 132 |
+
label: RRN # <conditional_mapping>
|
| 133 |
+
condition:
|
| 134 |
+
locale: ko
|
| 135 |
+
value_pattern: '^\d{6}-[1-4]\d{6}$' # ์ค์ธก 3,975/3,975 ์ ํฉ - ์์ ์ฅ์น
|
| 136 |
+
fallback: GENERIC_ID # ๋น์ ํฉ ๊ฐ / ํ ๋ก์ผ์ผ(en ๋ฆฌํ๋ ์ด)์ ์ธ๋ฌด ID -> ๋ฒ์ฉ ID
|
| 137 |
+
SOCIALNUM: GENERIC_ID
|
| 138 |
+
IDCARDNUM: GENERIC_ID
|
| 139 |
+
DRIVERLICENSENUM: DRIVER_LICENSE
|
| 140 |
+
PASSPORTNUM: PASSPORT
|
| 141 |
+
TELEPHONENUM: PHONE
|
| 142 |
+
EMAIL: EMAIL
|
| 143 |
+
CREDITCARDNUMBER: CARD_NUMBER
|
| 144 |
+
ACCOUNTNUM: ACCOUNT_NUMBER
|
| 145 |
+
CITY: ADDRESS
|
| 146 |
+
STREET: ADDRESS
|
| 147 |
+
BUILDINGNUM: ADDRESS
|
| 148 |
+
ZIPCODE: ZIPCODE
|
| 149 |
+
DATE: DATE
|
| 150 |
+
TIME: DATE
|
| 151 |
+
AGE: O # 2026-07-21 ๋๋กญ ํ์ - ํ1ยทํ2 ๋ฌด๊ทผ๊ฑฐ (quasi-identifier ์กด์น์ ํ๊ธฐ)
|
| 152 |
+
GENDER: O # ใ
|
| 153 |
+
SEX: O # ใ (GENDER ์ค๋ณต ์์ค)
|
| 154 |
+
USERNAME: USER_ID
|
| 155 |
+
PASSWORD: SECRET # ko 4ยทen 0๊ฑด - ์๋ ๋ฏธ๋ฏธ, ๋ณธ ํ๋ณธ์ ๋๋ฉ์ธ/ํฉ์ฑ ์ฆ๊ฐ
|
| 156 |
+
# ๋กฑํ
์ผ (ko <= 40๊ฑด, ํ์ต ๋ผ๋ฒจ ๋ถ์ ๊ฒฉ) - ์ ์ฑ
ํ ์ปจํ ๋๊ธฐ ๋๋กญ ๋ฆฌ์คํธ
|
| 157 |
+
ORGANISATION: O
|
| 158 |
+
URL: O
|
| 159 |
+
AMOUNT: O
|
| 160 |
+
COUNTRY: O
|
| 161 |
+
CURRENCY: O
|
| 162 |
+
BANKNAME: O
|
| 163 |
+
TIMEZONE: O
|
| 164 |
+
SALARY: O
|
| 165 |
+
IPV4: O # ๊ณ ๊ฐ IP๋ ํ2 ํญ๋ชฉ์ด๋ ko 2๊ฑด - 1์ฐจ regex(ํ1 IP์ฃผ์) ์ ๋ด
|
| 166 |
+
JOBTITLE: O
|
| 167 |
+
HOSPITALNAME: O
|
| 168 |
+
ALLERGIES: O
|
| 169 |
+
WEIGHT: O # en ์ ์ฉ ๋ผ๋ฒจ (ko 0๊ฑด) - 2026-07-13 en ์ ์ ๊ฒ์ฆ์์ ๋ฐ๊ฒฌ, ์ ์ฑ
์ธ
|
| 170 |
+
HEIGHT: O # validation ์ ์ฉ ํฌ์ ๋ผ๋ฒจ (ko 1๊ฑด + en 1๊ฑด) - 2026-07-22 refine fail-fast๋ก ๋ฐ๊ฒฌ, ์ ์ฑ
์ธ
|
| 171 |
+
|
| 172 |
+
# -----------------------------------------------------------------------------
|
| 173 |
+
# 3. ๋ณํฉ ๊ท์น (์ ์ ์คํฌ๋ฆฝํธ 2๋จ๊ณ - ์ธ์ ์คํฌ ๋ณํฉ, koยทen ๊ณตํต)
|
| 174 |
+
# * ๋ณํฉ์ ์ธ์ด ๊ณตํต (en "John Smith"๋ ๋จ์ผ ์คํฌ์ด์ด์ผ ํ2 ์๋ฌธ ์ฑ๋ช
๊ท์น ์ฑ๋ฆฝ)
|
| 175 |
+
# * ko ์ ์ฉ์ ๋ณํฉ์ด ์๋๋ผ ๊ทธ ๋ค์์ "์์ฐํ"(์ฑ+๋ช
๋ถ์ฌ์ฐ๊ธฐ - ์ ๏ฟฝ๏ฟฝ๋ฌธ ยง3.4.2 (1) 2๋จ๊ณ)
|
| 176 |
+
# * ์์ ๊ฐ์ ๊ธ์ง: ko ์ฃผ์๋ ํฐ -> ์, en ์ฃผ์๋ ์ -> ํฐ ์ญ์ - ์ธ์ ์ฑ๋ง ์กฐ๊ฑด
|
| 177 |
+
#
|
| 178 |
+
# * gap_allowed : ๋ ์ํฐํฐ ์ฌ์ด์ ์ธ์ยทํ์ฉ์ด ๊ฐ๋ฅํ ๊ตฌ์กฐ ๋ฐ ํจํด
|
| 179 |
+
# - whitespace (๊ณต๋ฐฑยทํญ)
|
| 180 |
+
# - punct (๊ตฌ๋์ : `, . - ยท / ( )` ๋ฑ ๋ฌธ์ฅ ๋ถํธ)
|
| 181 |
+
# -----------------------------------------------------------------------------
|
| 182 |
+
merge_rules: # <merge_rules>
|
| 183 |
+
person:
|
| 184 |
+
source_labels: [GIVENNAME, SURNAME]
|
| 185 |
+
max_gap_chars: 4
|
| 186 |
+
gap_allowed: whitespace_or_punct
|
| 187 |
+
output_label: PERSON
|
| 188 |
+
address:
|
| 189 |
+
source_labels: [CITY, STREET, BUILDINGNUM]
|
| 190 |
+
max_gap_chars: 4
|
| 191 |
+
gap_allowed: whitespace_or_punct
|
| 192 |
+
output_label: ADDRESS
|
| 193 |
+
|
| 194 |
+
# -----------------------------------------------------------------------------
|
| 195 |
+
# 4. 1์ฐจ regex ์ ๋ด ํญ๋ชฉ (๋ชจ๋ธ ๋ผ๋ฒจ ์ ์ธ - ๋ก๊น
์คํค๋ง ํค์๋ ํฌํจ)
|
| 196 |
+
# * ํ1 ์ ํ ํจํด recognizer๊ฐ ๊ฒ์ถ, ์นํ ์ ์ฑ
์ ํ2 ์ค์ฉ
|
| 197 |
+
# -----------------------------------------------------------------------------
|
| 198 |
+
regex_only:
|
| 199 |
+
- key: CI
|
| 200 |
+
policy_ref: "ํ1 CI (86์+`==` ๊ณ ์ , lookaround ๊ฒฝ๊ณ - ๊ฒ์ ๋ณด๊ฐ 2026-07-21) / ํ2 CI (์ 7์๋ฆฌ ๋
ธ์ถ)"
|
| 201 |
+
# SHA-512 base64 ๋ํ ๊ณผํ ํ์ฉ - ์ ๋ฐ๋ ํ์์ ciยท์ฐ๊ณ์ ๋ณด ํค์๋ ๊ฐ์
|
| 202 |
+
- key: IP_ADDRESS
|
| 203 |
+
policy_ref: "ํ1 IP์ฃผ์ (์ฅํ
0~255 ์๊ฒฉํ - ๊ฒ์ ๋ณด๊ฐ 2026-07-21) / ํ2 ๊ณ ๊ฐ์ IP์ฃผ์ (์ 3์๋ฆฌ = ์ฒซ ์ฅํ
๋ง์คํน ํด์, IPv4 ํ์ )"
|
| 204 |
+
|
| 205 |
+
# -----------------------------------------------------------------------------
|
| 206 |
+
# 4-1. 1์ฐจ regex ๋ณํ (์ด์ค ๋ ์ธ) - ๋ชจ๋ธ ๋ผ๋ฒจ์ด๋ฉด์ ํค์๋ regex๋ ๋ณํ
|
| 207 |
+
# * 2026-07-21 ๋ชจ๋ธ ์น๊ฒฉ 3์ข
: ํค์๋ regex(๊ณ ์ ๋ฐ ์ recall - ๋ช
์ ๋ฌธํ) + ๋ชจ๋ธ(๋ฌดํค์๋
|
| 208 |
+
# ๋งฅ๋ฝ recall) union - ๋ฌธ๋งฅ ์์กด ๊ฒ์ถ์ ๋ชจ๋ธ ๋ ์ธ์ ์กด์ฌ ์ด์
|
| 209 |
+
# * ํจํด ์์ง ์ ์ : Python re (lookbehind ์ฌ์ฉ - RE2/Hyperscan ๊ณ์ด ๋นํธํ)
|
| 210 |
+
# * ์นํ์ ๊ฐ ์บก์ฒ๊ทธ๋ฃน๋ง (ํค์๋ ๋ณด์กด = ์ถ์ ์ฑ)
|
| 211 |
+
# -----------------------------------------------------------------------------
|
| 212 |
+
regex_assist:
|
| 213 |
+
- key: CARD_EXPIRY
|
| 214 |
+
patterns:
|
| 215 |
+
keyword: '(?i)(์ ํจ\s*๊ธฐ[๊ฐํ]|expir\w*|valid\s*thru)\D{0,12}(0[1-9]|1[0-2])\s*[/.\-]\s*((?:20)?\d\d)(?!\d)'
|
| 216 |
+
pan_adjacent: '(0[1-9]|1[0-2])\s*/\s*\d{2}(?!\d)' # ์นด๋๋ฒํธ ๋งค์น ์งํ \D{0,20} ์๋์ฐ ๋ด์์๋ง ์ ์ฉ
|
| 217 |
+
- key: CVC
|
| 218 |
+
patterns:
|
| 219 |
+
keyword: '(?i)(\b(?:cv[vc]2?|security\s*code)\b|์นด๋\s*๊ฒ์ฆ\s*(?:๋ฒํธ|์ฝ๋|๊ฐ)?|๋ณด์\s*์ฝ๋)\W{0,6}(?!(?:19|20)\d\d(?!\d))(\d{3,4})(?!\d)'
|
| 220 |
+
# CIDยทCSC ํค์๋ ๊ธฐ๋ณธ ์ ์ธ (correlation ID ์ถฉ๋). ์ ๋ฐ๋ ์ต์
: PAN co-occurrence ๊ฒ์ดํธ
|
| 221 |
+
- key: IPIN
|
| 222 |
+
patterns:
|
| 223 |
+
keyword: '(?i)(์์ดํ|i[-\s]?pin)\s*(?:๋ฒํธ|no\.?)?\D{0,8}(\d{6}[-\s]?\d{7})(?!\d)'
|
| 224 |
+
# ์ฃผ๋ฏผ๋ฒํธ ๊ท์น ์ ํ ์ ์ฉ ํ ์์ฌ๋ถ๋ง IPIN. ๊ฐ ๊ท๊ฒฉ(13์๋ฆฌ ๊ฐ์ ) ํ์ธ ํ์ (pending)
|
| 225 |
+
|
| 226 |
+
# -----------------------------------------------------------------------------
|
| 227 |
+
# 5. ์ค์ฝํ ์ธ - ํ
์คํธ ๊ฒ์ดํธ์จ์ด๊ฐ ๋ค๋ฃจ์ง ์๋ ํ2 ํญ๋ชฉ (์ ์ธ์ ๊ธฐ๋ก)
|
| 228 |
+
# -----------------------------------------------------------------------------
|
| 229 |
+
out_of_scope:
|
| 230 |
+
- key: VIDEO_PERSONAL_INFO
|
| 231 |
+
policy_ref: "ํ2 ๊ฐ์ธ์์์ ๋ณด (๊ฒ์ ๋ชฉ์ ์ธ ์ฒ๋ฆฌ ๊ธ์ง)"
|
| 232 |
+
reason: "ํ
์คํธ ์ํฐํฐ๊ฐ ์๋ ๋ชจ๋ฌ๋ฆฌํฐ(์ด๋ฏธ์งยท์์) - ๋ฉํฐ๋ชจ๋ฌ ์
๋ ฅ ๊ฒฝ๋ก๊ฐ ์ด๋ฆฌ๋ฉด
|
| 233 |
+
ํ
์คํธ ํํฐ๋ฅผ ์ฐํํ๋ฏ๋ก ๋ณ๋ ํต์ (์
๋ ฅ ์ฐจ๋จ or ๋น์ ํํฐ) ํ์"
|
| 234 |
+
|
| 235 |
+
# -----------------------------------------------------------------------------
|
| 236 |
+
# 6. ๋ฏธ๊ฒฐ - ์ ์ฑ
ํ ์ปจํ ํญ๋ชฉ, TBD
|
| 237 |
+
# -----------------------------------------------------------------------------
|
| 238 |
+
pending_confirmation:
|
| 239 |
+
- "๋๋กญ ๋ฆฌ์คํธ(O ๋งคํ) ์ ์ฒด = ๋นPII ์ ์ธ - ํนํ ORGANISATIONยทAMOUNTยทSALARY"
|
| 240 |
+
- "IPIN ๊ฐ ๊ท๊ฒฉ (13์๋ฆฌ ๊ฐ์ ) - ์ ๊ณต๊ธฐ๊ด ๊ณ์ฝ ํ์ธ (CVC ๊ฒ์ถ ๊ท์น์ 2026-07-21 ํค์๋ ๋๋ฐ ํจํด ์ฑํ์ผ๋ก ํด์)"
|
| 241 |
+
- "SECRET ์ ์ค ์ฑํ (2026-07-13) - ํ2 ์ฒ๋ฆฌ๊ธ์ง๋ฅ์ '๊ฒ์ดํธ์จ์ด ์ ์ฒด ๋ง์คํน' ํด์์
|
| 242 |
+
์ ์ฑ
ํ ์ฌํ ์ปจํ ๋์"
|
model_quantized.onnx
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2f9e709e0e9825dcd2d42e7f7bad9e2dcc7087cc3962db46787b9a4b123f5f74
|
| 3 |
+
size 151493
|
model_quantized.onnx_data
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3c86220d2388b60740a7ec824dd94e6f3152804e96f758d9c2b9a34dd5c97886
|
| 3 |
+
size 1618085352
|
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,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"backend": "tokenizers",
|
| 3 |
+
"eos_token": "<|endoftext|>",
|
| 4 |
+
"is_local": false,
|
| 5 |
+
"local_files_only": false,
|
| 6 |
+
"model_input_names": [
|
| 7 |
+
"input_ids",
|
| 8 |
+
"attention_mask"
|
| 9 |
+
],
|
| 10 |
+
"model_max_length": 128000,
|
| 11 |
+
"pad_token": "<|endoftext|>",
|
| 12 |
+
"tokenizer_class": "TokenizersBackend"
|
| 13 |
+
}
|
viterbi_calibration.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"operating_points": {
|
| 3 |
+
"default": {
|
| 4 |
+
"biases": {
|
| 5 |
+
"transition_bias_background_stay": 0.0,
|
| 6 |
+
"transition_bias_background_to_start": 0.0,
|
| 7 |
+
"transition_bias_end_to_background": 0.0,
|
| 8 |
+
"transition_bias_end_to_start": 0.0,
|
| 9 |
+
"transition_bias_inside_to_continue": 0.0,
|
| 10 |
+
"transition_bias_inside_to_end": 0.0
|
| 11 |
+
}
|
| 12 |
+
}
|
| 13 |
+
}
|
| 14 |
+
}
|