↓ 본문으로 건너뛰기
Veil-PII-Ko-Lite — 경량 한국어 PII 모델 개발 리포트
  1. 글/

Veil-PII-Ko-Lite — 경량 한국어 PII 모델 개발 리포트

작성자
Kim Won Tae
고객의 현장에서 업무 구조와 환경, 그리고 잠재된 불편함을 분석하고, 사용자 경험을 개선할 수 있는 도메인 특화 AI 서비스 및 에이전트를 개발합니다.
목차

이 글은 CPU만으로 돌릴 수 있는 경량 한국어 PII(개인정보) 탐지 모델 Veil-PII-Ko-Lite를 개발한 과정과 결과를 정리한 리포트입니다.

1. 개발 동기
#

  • 매 프로젝트마다 폐쇄망 환경에서의 PII 모델 적용은 필수 요소. But 아쉬운 한국어 PII 성능
  • 폐쇄망에서 GPU 없이 가볍게 구동할 수 있는 PII 모델 필요
  • 다양한 한국어 PII Category에 대한 탐지 기능 필요
  • 좋은 PII 성능을 보이는 것으로 알려진 모델들을 후보군으로 두고 탐색
후보내용적용 한계
BCCard MoAI-Privacy-Filter (2026-08)openai/privacy-filter(1.4B) 한국어 파인튜닝, 29 라벨, Apache 2.01.4B 규모로 CPU 서빙 부담. 모델카드가 상업 사용 시 고지를 요구. / 실제 대화체(KDPII)에서는 F1 0.45로 낮은 탐지 성능
FrameByFrame privacy-filter-korean (2026-04)동일 1.4B 백본, KDPII 학습, 9 라벨주민번호·카드·사업자번호 등 금융 필수 라벨이 없음.
Azure AI Language PII관리형 API, 한국어 지원한국어 주소 F1 0.08, 계좌 미검출 등 한국어 PII 탐지 성능 낮음
Microsoft Presidio규칙 + NER 프레임워크대체재가 아니라 NER 모델을 끼워 쓰는 프레임워크 개념. 한국어 인식 기능이 있긴 하지만 정형 카테고리 5종만 탐지를 지원함. 전후처리에 특화되어 있어 PII 모델과 패키징에 활용 예정

결론적으로 “경량 · 한국어 강함 · 카테고리 넓음 · 라이선스 부담 없음” 네 조건을 동시에 만족하는 공개 모델이 없어 직접 개발하기로 하였습니다.


2. 개발 목표
#

목표정량기준결과
정확도공개 벤치 및 합성데이터 3종의 평가결과가(KDPII test · BCCard validation · 자체 합성 데이터) BCCard PII 모델 이상의 성능을 보일 것 · BCCard의 PII 모델을 목표모델로 설정한 이유는, 해당 모델이 현재 한국어 PII 모델 중 가장 많은 Category를 커버하면서도 높은 성능을 보이기에 (다만 크기가 큼..), 경량 모델로 해당 모델 이상의 성능을 달성하는 것을 목표로 설정하였습니다.달성
경량성파라미터 ≤ 150M, 배포 파일 ≤ 150MB, 정확도 손실 없이 INT8달성 — 110M · 143MB · 무손실
카테고리BCCard가 제공하는(현재 기준 가장 많음, 29개) 카테고리 수준으로 지원할 것달성 — 32종 (차량번호·가입번호·단말 S/N 추가)
라이선스고지 의무 없는 상업 사용달성 — 백본·데이터 모두 Apache 2.0

3. Backbone 선택
#

작은 크기 및 한국어를 지원하는 PII backbone 모델 5종을 비교분석하였습니다.

후보 5종을 같은 데이터(2종 - KDPII, BCCard val 데이터), 같은 하이퍼파라미터로 2 epoch로 학습하여 비교하였습니다.

최종 판단 기준은 F1 Score 기준 정확도 및 모델의 크기를 가장 중요한 요소로 두어 평가하였고, 최종적으로 ‘ko-electra-base-v3’ 모델을 최종 backbone 모델로 선택하였습니다.

백본에 대해 PII 탐지(라벨을 인식할 수 있도록)가 가능하도록 동일 조건으로 fine-tuning 진행했고, train loss는 동일하게 떨어졌습니다.
다만, validation set에 대해서는 아래와 같이 Ko-Electra-base-v3 모델이 가장 좋은 성능을 보였습니다.

백본파라미터라이선스KDPII test F1BCCard val F1판정
monologg/koelectra-base-v3110MApache 2.00.87890.9613채택 — 가장 작고 KDPII 스코어는 최고 득점
kakaobank/kf-deberta-base185MMIT0.87980.9661+0.1~0.5pt 이나 INT8 245MB로 크기 목표 초과
lucid/deberta-v3-base-korean185MApache 2.00.85330.9527탈락
beomi/KcELECTRA-base110MMITKoELECTRA 하회탈락 (구어체 특화 이점 확인 안 됨)
microsoft/mdeberta-v3-base276MMITexact 0.39 → 오프셋 보정 후 회복탈락 — 크기 2.5배, SentencePiece 선행공백 오프셋 문제로 디코더 보정 필요했음

4. 학습 데이터
#

학습셋 구성 (행 수, full 셋 기준 · 총 128k)

출처행 수비고
BCCard57,851ko 43k · en 15k
KDPII40,109 문장 + 3,664 대화
합성 (자체)26,540템플릿 4.7k × 생성기

막대 길이 = 행 수 비례. 학습 시 반복 가중 ×2를 쓴 출처(BCCard)는 epoch당 실효 256k 행.

4-1. BCCard/privacy-filter-openpii-masking (CC-BY-4.0) - 약 72,400행
#

  • 데이터 설명
    • 아래 세 가지 출처의 데이터에 대한 통합본으로 확인
      • openpii-1.5m-ko/none 26,268행 (ai4privacy 영문 데이터의 한국어 번역본)
      • openpii-1.5m-ko/perturbation 16,268행 (위 데이터를 한국 포맷으로 변경, 생성한 데이터)
      • domain/synthesis 11,170행 (BC카드 자체 합성데이터)

<데이터 샘플>

  • 원문 : 연락을 위해 jimin3292@webmail.example.net 또는 공오일 일일구 공육육육 로 문의해 주세요.

  • 정답 : EMAIL jimin3292@webmail.example.net · PHONE 공오일 일일구 공육육육

  • 수집 사유

    • 한국어 PII Category 29개의 라벨을 기준으로, 공개된 가장 큰 데이터이며, 비교 대상(BCCard 모델)과 같은 분포로 학습 후 평가해야 BCCard validation 비교가 공정해지기에, 해당 데이터를 사용하게 되었습니다.
  • 데이터 품질 검수

    • 학습 이전에, 데이터 품질이 적합한지에 대한 전수 검사를 실시
    • 탐지된 문제점
      • 주민번호·전화·카드·면허·여권·사업자번호 등 21종 포맷 검증기로 행 단위 감사(정규표현식)를 수행했으며, 세 하위 출처 중 openpii-1.5m-ko (ai4privacy 번역본 21k)는 35% 행이 불량이었음
        • 운전면허 라벨의 61%가 0W4SB7XAR4 같은 랜덤 대문자열
        • 이름의 13%가 선임Blattnig 같은 혼합 문자.
        • 한국 포맷으로 변경 전 데이터라, 당연한 결과로 보이며 BC Card에서 해당 데이터를 왜 학습에 포함했는지 이유는 모르겠으나, 해당 데이터 포함 시 모델 성능이 하락하는 것을 확인하였고 포맷검증기에서 확인된 문제 데이터는 모두 제거함.
      • BCCard 모델 Description에서 언급된, 스스로 약하다고 밝힌 ACCOUNT_NUMBER·ZIPCODE·PORT의 원인이 “랜덤 문자열 = 식별자” 데이터를 제거하지 않고 학습한 결과로 예상.
      • 처리: 불량 행을 제외한 clean 셋과 전체 full 셋을 모두 만들어 절제 실험으로 비교했음(6절).

<불량 데이터 예시>

  • 정상 : DRIVER_LICENSE = 11-23-456789-01
  • 불량 : DRIVER_LICENSE = 0W4SB7XAR4

4-2. KDPII (고려대, CC-BY-4.0) — 약 40,000개 문장 · 3,664 대화
#

  • 데이터 설명
    • 실제 구어체 대화 기반의 유일한 한국어 PII 실데이터입니다.

<데이터 샘플>

  • 원문 : 나 캐나다에서 태어나서 5년 전 17살에 한국 왔어.

  • 정답 : LCP_COUNTRY 캐나다 · QT_AGE 17살 · LC_ADDRESS 한국 → 매핑 후: ADDRESS 한국 (라벨에서 LCP_COUNTRY와 같은 국가 개념은 잡을 필요없는 데이터이기에 학습데이터에서 제거했음)

  • 수집 사유

    • 공식 train/valid/test 분할이 있어 외부 비교 기준이 되며, 문장 평균 25자로 짧은 데이터로 구성되어 있습니다.
  • 처리

    • 33개의 KDPII category 중 키·몸무게·혈액형·종교 등 우리 모델에서 탐지하지 않는 카테고리들은 비 라벨로 처리하고 우리 모델에서 탐지하는 16개의 라벨로 매핑. 카드·계좌 스팬에 붙은 은행명은 숫자 구간만 남기도록 정규화하여 BCCard 데이터셋의 포맷과 일치시킴.

4-3. 합성 데이터 (자체) — 26,500행
#

  • 데이터 설명
    • 위 수집한 데이터에서 미비된 라벨에 대한 데이터는 gpt-5.4 모델을 활용하여 생성하여 채웠습니다.
    • 데이터는 원본에서 빈칸을 맞추는(PII를 맞추는 위의 데이터들과 같은 형식) 데이터와 빈

<데이터 샘플>

  • 원문 : 연규도우 과장님 고객님, 문의하신 4918-5036-****-3258 카드 승인번호 55276357 건은 등록 계좌 587918-37-599711 로 1995.07.15 환불됩니다. 요금제 5G 프리미어 80입니다.

  • 정답 : PERSON 연규도우 · CARD_NUMBER 4918-5036-****-3258 · TRANSACTION_APPROVAL_ID 55276357 · ACCOUNT_NUMBER 587918-37-599711 · DATE 1995.07.15 (뒤의 “요금제 5G 프리미어 80"은 삽입된 hard-negative)

  • 수집 사유

    • 공개 데이터에 없는 라벨(차량번호·가입번호·단말 S/N)과 부족한 도메인(금융·통신·보험 상담문)을 보강하고, 주문번호·상품코드·금액 같은 hard-negative를 정답과 같은 빈도로 넣어 “숫자면 다 잡는” 과탐을 억제하는 효과를 주었습니다.
  • 방식

    • BC Card에 잘못된 포맷의 데이터가 들어가서 데이터 품질을 떨어뜨렸던 사례를 참고하여, LLM이 아래와 같은 원문을 생성하되, 원문 내에 들어가는 pii 카테고리 데이터에 대해서는 로직 기반으로 채우도록 하여, 환각으로 인한 잘못된 label 데이터가 포함되는 사례를 방지하였습니다.
  • LLM생성 : {PERSON} 고객님, 문의하신 {CARD_NUMBER} 카드 승인번호 {TRANSACTION_APPROVAL_ID} 건은 등록 계좌 {ACCOUNT_NUMBER} 로 {DATE} 환불됩니다.

  • 위 category별 삽입되는 데이터는 프로그래미틱하게 생성 반영


5. 학습
#

5-1. 학습방식 → Full Fine-Tuning
#

  • Ko-Electra-base-v3 백본 모델의 경우, 기존 transformer encoder에 이진판별(토큰 간 동일여부)이 가능한 헤더가 붙어있었습니다. (768 → 1). 해당 헤더 부분을 PII category 분류 목적에 맞게, 768 → 129dim의 헤더로 변경하였습니다.
  • 그리고, 가중치 업데이트는 전체 모델 architecture에서 기본적으로 Embedding layer, Encoder layer를 학습합니다. (헤더만 학습하는 게 아니라, 전체 레이어에 대해 기울기 계산을 진행하여 백본 전체를 갱신함!!)
  • 그리고 위에서 언급한 토큰 분류헤더에 대해, 각 토큰별로 총 129개 라벨에 대한 확률값을 예측하는 형태로 학습을 진행하였습니다.
    • 라벨이 129개인 이유는, 총 32개의 카테고리 라벨이 있고, 각 라벨별로 ‘시작 B(Begin)’, ‘중간 I(Inside)’, ‘끝 E(End)’, ‘단일 S(그냥 혼자서 하나의 엔티티를 가지는 경우, Single)’ 총 4가지 정보로 분류되고, 마지막으로 엔티티가 아님에 해당하는 라벨까지 더해서, 32 x 4 + 1 = 129개의 예측해야 할 라벨이 발생합니다.
  • 다만, 모델의 output이 129개 라벨에 대한 토큰별 확률값이고, 각 토큰별 129개의 확률값 중 제일 높은 확률의 라벨을 고르는 방식(argmax)을 선택할 경우, 토큰의 시작-중간-끝 요렇게 문법(?)에 맞게 배치되어야 하는데, 단순 높은 확률값으로만 채택할 경우, 단일 토큰의 예측라벨이 IBBS…BBI, 뭐 이런 식으로 말도 안 되는 토큰 배치가 발생할 수 있습니다.
  • 이에, Viterbi 알고리즘을 적용하여, 앞단의 토큰의 라벨이 예측되었을 때, 뒷 토큰의 경우 그 자리에 올 수 있는 라벨 중에서 가장 높은 확률을 가진 라벨을 채택하는 방식으로 보정하여 분류하였습니다.
  • Tuning Params
    • Loss Function : nn.CrossEntropyLoss
    • Label Smoothing : 0.05 (v1~v3a) → 0 (v3b·v4)
    • Optimizer : AdamW
      • weight decay : 0.01
      • dropout : 0.1
    • learning rate : 3e-5 → 5e-5 (v3b·v4)
    • warmup : 10%
    • epoch : 5→6
    • Loss 제외 토큰 반영(ignore_index=-100 처리)
      • padding, [CLS], [SEP] 토큰은 학습 제외

5-2. 학습과정
#

버전별 데이터셋

버전BCCard 공개 데이터KDPII 공개 데이터자체 생성합계버전 특이점
v157,85143,50417,231118,586같은 조건으로 두 벌을 학습 - 불량 데이터 제거 분(108,538) vs All(118,586)
v257,85143,49426,540 (+9,309)127,885BCCard, KDPII 데이터에는 없는 차량번호, 가입번호, 단말 S/N 데이터를 추가하여 총 합성 데이터를 1.5배로 증강
v3-157,85143,49426,540127,885데이터 변경 없음 / 학습 시, BCCard 부분만 데이터를 x2하여 같은 데이터를 강조 학습
v3-257,85143,49426,540127,885데이터 변경 없음. 학습률, label smoothing, epoch만 조정하여 학습
v4 / 최종57,85143,49826,875 / +335128,224합성 데이터 내 라벨 오류 수정 → “김철수, 홍길동, 이영희"가 정답 없이 박혀 있던 1,300여 곳을 개인정보로 정정하고, 이름이 문맥에 등장하는 문장 139개 추가 생성 반영

버전별 의도 및 결과

버전train set의도기대했던 효과결과
v1train_clean 108,538 / train_full 118,586같은 조건에서 불량 행 제외(clean) vs 전체(full) 두 벌 병렬로 학습 진행불량 데이터 제거한 데이터셋에서 더 높은 스코어 기대..반대로 나옴! / 원인은, BC Card 데이터에 불량데이터의 분포가 train, valid set 모두 동일한 분포로 포함되어 있었는데, train에서 제거하여, 해당 패턴을 학습하지 못한 상태에서 validation에서 해당 패턴의 데이터를 맞추지 못한 문제
v2train_*_v2 127,885다양한 category에 대한 추가 합성 데이터를 1.5배로 늘려서, 추가 category에 대한 학습 반영BCCard, KDPII에 없는 라벨(차량번호/가입번호/단말 S/N)을 채워 학습 카테고리 범위 확대KDPII, BCCard 두 벤치는 성능향상 없었고, 합성 데이터 한정 0.977 달성함.
v3atrain_full_v2 (v2와 동일)확인 결과 BCCard 데이터에 대한 성능이 좋지 않았고, 그 부분에 대한 강화 전략확인 결과, 데이터 자체에 문제는 없어 보여 강조 학습을 진행하면 좀 더 성능 향상을 얻을 수 있지 않을까..?효과 없음. BCCard val 0.980 (오히려 −0.2pt), KDPII 0.934 동일. 이미 충분히 보고 학습에 반영된 것으로 이해
v3btrain_full_v2 (v2와 동일)데이터 동일, 하이퍼파라미터만 수정 → lr 3e-5→5e-5, ls 0.05→0, epoch 6학습 파라미터 조정을 통해 최적화…성능 수렴 지점을 개선해보고자 함KDPII 0.935 (+0.1pt), BCCard 0.982. loss는 400배 내려갔으나 점수는 사실상 동률
v4 (최종)train_full_v3 128,224 / + 이름 문맥 템플릿 139행, 더미 이름 1,300건 라벨 수정합성 템플릿에 플레이스홀더 없이 박혀 있던 김철수, 홍길동, 이영희를 자동으로 {PERSON}으로 치환하고, 이름이 문맥에 등장하는 수작업 템플릿 추가v3b가 이 세 이름을 개인정보로 못 잡는 문제(O로 학습된 것 확인) 해결벤치는 v3b와 동률(KDPII 0.934 · BCCard 0.983)이나 테스트용 17문장 11/17 → 17/17로 향상. 실사용 성능 개선으로 이해

6. 학습 결과
#

exact-match span F1 · 같은 스코어러 · 같은 디코더

평가셋Veil-PII-Ko-Lite (110M)BCCard MoAI-PF-INT8 (1.4B)FrameByFrame (1.4B, 9라벨)Azure AI Language PII
KDPII test (4,891).934.453.516.463
BCCard val · ko (10,743).983.959n/a.403
합성 heldout v2 (670).965.533n/a.504

6-0. Veil-PII-Ko-Lite 모델 제공 32개 Label
#

Veil-PII-Ko-Lite 모델 제공 32개 Label 목록
#

라벨한글설명예시유형
사람·조직
PERSON사람 이름실명·호칭·서명. 성만 있어도 잡는다김철수 / 이영희 씨 / 홍길동 대리문맥
ORGANIZATION기관·회사명회사·학교·병원·관공서. 상호에 사람 이름이 섞이면 문맥으로 가른다대한항공 / 김민수 치과 / 강남구청문맥
USER_ID계정 아이디로그인 ID·닉네임·핸들wtkim89 / @veil_admin혼합
연락처·위치
ADDRESS주소도로명·지번·건물명. 행정구역만 있어도 대상서울 강남구 테헤란로 152 / 판교빌딩 3층문맥
EMAIL이메일 주소RFC 형식 주소hong@example.co.kr정형
PHONE전화번호휴대폰·유선·대표번호. 구분자가 없거나 점이어도 잡는다010-1234-5678 / 02)555-1234정형
IPADDRESSIP 주소IPv4·IPv6192.168.0.11 / 2001:db8::1정형
MACADDRESSMAC 주소네트워크 인터페이스 물리 주소00:1B:44:11:3A:B7정형
PORT포트 번호호스트 뒤에 붙는 서비스 포트:8443정형
URL웹 주소http(s)·www 로 시작하는 링크https://veil.example.com/u/1123정형
ZIPCODE우편번호5자리 신 우편번호, 6자리 구 번호06236 / 135-080정형
한국 신원
SSN해외 사회보장번호미국 SSN 등 국외 신원번호123-45-6789정형
RRN주민등록번호13자리. 생년월일 + 성별코드 + 검증번호900101-1234567정형
FRN외국인등록번호주민번호와 같은 자릿수, 성별코드가 5~8900101-5234567정형
BUSINESS_ID사업자등록번호3-2-5 자리123-45-67890정형
PASSPORT여권번호M/S/R/O + 8자리M12345678정형
DRIVER_LICENSE운전면허번호지역코드-연도-일련-검증11-22-123456-78정형
CI연계정보본인확인기관이 발급하는 88자 해시 식별자88자 Base64 문자열정형
IPIN아이핀 번호인터넷 개인식별번호13자리 영숫자정형
금융
CARD_NUMBER카드번호14~19자리. 발급사·BIN·검증번호 구조4111-1111-1111-1111정형
CARD_EXPIRY카드 유효기간MM/YY 또는 MM/YYYY12/28정형
CVC카드 검증코드카드 뒷면 3~4자리123정형
VIRTUAL_CARD_NUMBER가상 카드번호일회용·토큰화 카드번호실카드와 자릿수 동일정형
ACCOUNT_NUMBER계좌번호은행별 자릿수·구분자가 제각각110-234-567890정형
TRANSACTION_APPROVAL_ID거래 승인번호결제 승인 시 발급되는 식별자30123456정형
기기·가입
IMEI단말 식별번호휴대폰 15자리 고유번호356938035643809정형
VEHICLE_PLATE차량번호지역·분류·한글·일련번호12가 3456 / 서울 32나 1234정형
SUBSCRIBER_ID가입번호통신·서비스 가입 식별자가입자 관리번호혼합
DEVICE_SERIAL기기 일련번호셋톱·공유기 등 단말 시리얼SN-4F2A-90C1정형
기타
DATE날짜생년월일·가입일 등 개인을 특정하는 날짜1996년 12월 8일 / 2026-09-23혼합
GENERIC_ID기타 식별자유형을 특정하기 어려운 식별자를 받는 자리주문번호 / 회원번호혼합
SECRET비밀값비밀번호·API 키·토큰sk-live-9f3a…혼합

6-1. 모델별 F1-Score
#

평가셋nVeil INT8Veil fp32BCCard 1.4BFrameByFrameAzure PII
KDPII test4,8910.93270.93330.45330.51560.4631
KDPII · 대화 단위4580.94200.94230.4661—0.4626
BCCard validation · ko10,7430.98250.98200.9594—0.4031
BCCard validation · en3,7810.96970.97000.9653—0.5295
합성 heldout v26700.96430.96520.5328—0.5035
  • FrameByFrame의 경우, 벤치를 측정하지 않은 이유는, 해당 모델이 9개 카테고리밖에 지원하지 않아, 직접적 비교가 힘들어, 제외 처리함.

“PII의 경우, 오답의 리스크가 크기 때문에, Recall 및 Precision도 중요하며, 제공하는 카테고리가 많아졌기 때문에 카테고리별 스코어도 확인할 필요가 있었습니다.”

6-2. 각 모델별 전체 라벨에 대한 Recall Score
#

1) KDPII test set 기준 Recall (라벨 17개 보유)
#

라벨nVeil INT8Veil fp32BCCard 1.4BAzure PIIFrameByFrame정규식
ORGANIZATION4670.8860.8890.0060.3920.0000.000
PERSON2740.9120.9090.3070.6710.7920.000
ADDRESS2080.8990.8990.0820.0480.4470.000
PHONE1241.0001.0001.0000.9271.0000.218
EMAIL811.0001.0000.9751.0001.0001.000
CARD_NUMBER781.0001.0001.0000.0770.0000.000
ACCOUNT_NUMBER771.0001.0000.3640.0000.0000.416
DATE700.9710.9710.9140.9430.9860.000
USER_ID611.0001.0000.6560.0001.0000.000
VEHICLE_PLATE521.0001.0000.0000.0000.0000.000
URL391.0001.0000.7950.9741.0000.744
RRN180.9440.9441.0000.2780.0000.000
PASSPORT181.0001.0000.8890.0000.0000.278
DRIVER_LICENSE171.0001.0001.0000.0000.0000.000
IPADDRESS111.0001.0000.9091.0001.0000.273
FRN91.0001.0000.0000.0000.0000.000
micro1,6040.93700.93700.37970.43580.43330.1103

2) BCCard-val-ko set 기준 Recall (라벨 29개 보유)
#

라벨nVeil INT8Veil fp32BCCard 1.4BAzure PII정규식
PERSON8,2140.9830.9800.9690.5220.000
DATE7,9100.9970.9970.9980.7570.000
ADDRESS7,2010.9910.9920.9320.1710.000
EMAIL4,5351.0001.0000.9680.5280.531
PHONE3,7230.9650.9650.9370.5280.154
CARD_NUMBER2,8511.0001.0000.9990.0020.000
ZIPCODE2,6080.9950.9950.9960.0000.000
GENERIC_ID2,0210.9050.9030.8420.0000.000
SSN1,8160.9580.9580.9580.0000.000
RRN1,7430.9980.9980.9970.3320.000
DRIVER_LICENSE1,7230.9110.9100.8670.0000.000
PASSPORT1,4750.9990.9990.9200.0000.002
ORGANIZATION4670.9810.9810.9040.5590.000
IPADDRESS2411.0001.0001.0000.9960.373
TRANSACTION_APPROVAL_ID2331.0001.0001.0000.0000.000
USER_ID2250.9960.9960.9870.0000.000
ACCOUNT_NUMBER2100.9520.9520.9290.0000.409
BUSINESS_ID2070.9610.9610.9420.0000.000
URL1641.0001.0000.9880.8480.305
CI1631.0001.0000.9940.0000.000
PORT1630.9320.9320.8960.0000.000
SECRET1580.9870.9870.9810.0000.000
IPIN1510.9870.9870.9800.0000.000
MACADDRESS1481.0001.0001.0000.0000.277
FRN1201.0001.0000.9920.0000.000
IMEI1061.0001.0001.0000.0000.000
CARD_EXPIRY1041.0001.0001.0000.0000.000
VIRTUAL_CARD_NUMBER1021.0001.0001.0000.0000.000
CVC921.0001.0000.9780.0000.000
micro48,8740.98290.98230.95890.34970.0665

3) 자체 합성 데이터 set 기준 Recall (라벨 32개 보유)
#

라벨nVeil fp32BCCard 1.4BAzure PII
PERSON2080.9470.8270.870
ORGANIZATION1610.9810.0740.509
PHONE1570.9940.9870.796
DATE1500.9870.8000.767
ADDRESS1261.0000.7060.444
EMAIL1131.0000.9820.761
USER_ID411.0000.2440.000
SECRET401.0000.6500.000
IPADDRESS381.0001.0000.974
SUBSCRIBER_ID360.9720.0000.000
ACCOUNT_NUMBER351.0000.6860.000
URL331.0000.8180.970
GENERIC_ID320.7810.3130.000
DEVICE_SERIAL320.9690.0000.000
VEHICLE_PLATE291.0000.0000.000
ZIPCODE281.0000.4640.000
PASSPORT271.0000.9630.000
TRANSACTION_APPROVAL_ID271.0000.2590.000
RRN260.9230.9620.808
CI261.0000.8080.000
FRN221.0000.0000.000
VIRTUAL_CARD_NUMBER220.9090.2270.000
PORT210.9520.0480.000
IMEI211.0000.5240.000
DRIVER_LICENSE200.9500.7000.000
BUSINESS_ID191.0000.2630.000
MACADDRESS191.0000.7370.000
IPIN181.0000.0000.000
CVC170.9410.2940.000
SSN151.0001.0000.000
CARD_NUMBER150.9331.0000.933
CARD_EXPIRY121.0000.0000.000
micro1,5860.97860.61220.4723

6-3. 각 모델별 전체 라벨에 대한 Precision Score
#

1) KDPII test set 기준 Precision (라벨 17개 보유)
#

라벨nVeil INT8Veil fp32BCCard 1.4BAzure PIIFrameByFrame정규식
ORGANIZATION4670.9140.9120.3750.5180.0000.000
PERSON2740.8770.8860.2730.5700.6700.000
ADDRESS2080.8580.8580.1100.3450.8300.000
PHONE1241.0001.0000.8550.4121.0001.000
EMAIL811.0001.0000.9751.0001.0001.000
CARD_NUMBER781.0001.0000.7091.0000.0000.000
ACCOUNT_NUMBER771.0001.0000.9660.0000.0000.244
DATE700.9190.9190.7620.2291.0000.000
USER_ID610.9840.9840.9520.0000.9840.000
VEHICLE_PLATE520.9810.9810.0000.0000.0000.000
URL391.0001.0000.8380.9741.0000.744
RRN181.0001.0000.6670.8330.0000.000
PASSPORT181.0001.0000.8890.0000.0001.000
DRIVER_LICENSE171.0001.0000.8090.0000.0000.000
IPADDRESS111.0001.0000.9091.0001.0001.000
FRN90.9000.9000.0000.0000.0000.000
micro1,6040.92840.92950.56230.49400.63640.6189

2) BCCard-val-ko set 기준 Precision (라벨 29개 보유)
#

라벨nVeil INT8Veil fp32BCCard 1.4BAzure PII정규식
PERSON8,2140.9840.9800.9750.5200.000
DATE7,9100.9960.9960.9960.8150.000
ADDRESS7,2010.9880.9890.9310.1750.000
EMAIL4,5350.9990.9990.9680.8770.883
PHONE3,7230.9650.9650.9370.2500.892
CARD_NUMBER2,8510.9970.9970.9960.1140.000
ZIPCODE2,6080.9950.9950.9920.0000.000
GENERIC_ID2,0210.8850.8840.8330.0000.000
SSN1,8160.9680.9670.9580.0000.000
RRN1,7430.9990.9990.9970.9030.000
DRIVER_LICENSE1,7230.9220.9210.8730.0000.000
PASSPORT1,4750.9990.9990.9190.0001.000
ORGANIZATION4670.9850.9850.9440.1630.000
IPADDRESS2411.0001.0000.9920.9880.978
TRANSACTION_APPROVAL_ID2330.9960.9961.0000.0000.000
USER_ID2250.9960.9961.0000.0000.000
ACCOUNT_NUMBER2100.9950.9951.0000.0000.029
BUSINESS_ID2070.9710.9710.9700.0000.000
URL1640.9880.9880.9820.8370.301
CI1631.0001.0000.9940.0000.000
PORT1630.9500.9500.9360.0000.000
SECRET1581.0001.0001.0000.0000.000
IPIN1510.9870.9870.9930.0000.000
MACADDRESS1481.0001.0001.0000.0001.000
FRN1201.0001.0000.9840.0000.000
IMEI1061.0001.0000.9730.0000.000
CARD_EXPIRY1041.0001.0001.0000.0000.000
VIRTUAL_CARD_NUMBER1020.9710.9711.0000.0000.000
CVC920.9680.9681.0000.0000.000
micro48,8740.98220.98160.95990.47590.3880

3) 자체 합성 데이터 set 기준 Precision (라벨 32개 보유)
#

라벨nVeil fp32BCCard 1.4BAzure PII
PERSON2080.7910.6190.694
ORGANIZATION1610.9750.6000.506
PHONE1570.9870.9010.316
DATE1500.9870.6450.567
ADDRESS1260.9840.3150.409
EMAIL1131.0000.9820.761
USER_ID410.9760.5560.000
SECRET401.0000.8670.000
IPADDRESS381.0000.9270.974
SUBSCRIBER_ID360.9210.0000.000
ACCOUNT_NUMBER350.9720.5580.000
URL331.0000.8180.970
GENERIC_ID321.0000.1150.000
DEVICE_SERIAL320.9690.0000.000
VEHICLE_PLATE290.9670.0000.000
ZIPCODE280.9660.0760.000
PASSPORT271.0000.3770.000
TRANSACTION_APPROVAL_ID271.0000.1840.000
RRN260.9600.2070.750
CI261.0000.7780.000
FRN220.9170.0000.000
VIRTUAL_CARD_NUMBER220.9520.3850.000
PORT210.9091.0000.000
IMEI210.9551.0000.000
DRIVER_LICENSE201.0000.1190.000
BUSINESS_ID190.9051.0000.000
MACADDRESS191.0001.0000.000
IPIN180.8180.0000.000
CVC171.0000.4170.000
SSN151.0000.2630.000
CARD_NUMBER150.9330.1900.933
CARD_EXPIRY121.0000.0000.000
micro1,5860.94870.47160.5392

6-4. 양자화 및 Latency
#

  • Dynamic INT8로 양자화를 진행한 경우, 모델크기는 113까지 감소했으나, activation까지 양자화(정수)되면서 recall이 대폭 하락했습니다. 원인은 129개 라벨의 1,2등의 prediction score가 매우 근소한 차이라, 성능하락이 컸습니다.
  • 이에, weight는 int8로 양자화하고, activation은 fp32를 유지하여 성능은 유지하고, 모델크기는 143MB로 축소했습니다.
변형크기KDPII F14스레드 128 / 512 tok16스레드 512 tok판정
fp32 ONNX450MB0.933977 / 274 ms118 ms기준
동적 INT8113MB~0.8025 / 95 ms58 ms재현율 붕괴, 미채택
weight-only INT8 + fp16 emb143MB0.934261 / 237 ms108 ms
weight-only INT4 + fp16 emb100MB0.932167 / 261 ms119 ms실험값, 미공개

6-5. 종합 비교
#

항목Veil-PII-Ko-LiteBCCard MoAI-PFFrameByFrameAzure AI Language PII
최초 공개2026-092026-082026-042021 GA
파라미터 · 배포 크기110M · 143MB1.4B · INT8 수 GB1.4B · fp32 5.6GB— (API)
라벨 수3229913
KDPII test F10.9340.4530.5160.463
BCCard val(ko) F10.9830.959—0.403
폐쇄망 배포가능 (CPU ONNX)가능(but, 무거움)가능(but, 무거움)-
라이선스Apache 2.0Apache 2.0 + 고지 요구Apache 2.0-

7. 최종 결과 분석
#

7-1. 최종 결과
#

  • CPU 환경에서 운용이 가능한 110M의 작은 PII 모델 확보
  • 1.4B에 달하는 모델 대비 더 많은 Category를 지원(32개)
  • 경쟁 모델 대비 작은 크기(10배)로 더 높은 탐지 성능 확보

7-2. 매우 작은 모델로도 높은 성능을 낼 수 있었던 이유
#

  • PII detection 시, 비교모델(bccard)의 경우 autoregressive하게 생성하여 output을 도출하는 방식인데, veil 모델의 경우, 각 토큰에 PII 라벨을 찍는 token classification 방식으로 탐지합니다. 즉, veil에서 필요한 출력은 {start, end, label}로 단순하나, 비교모델은 문장을 생성한 뒤, 원문에 다시 맞추는 alignment 과정이 필요한데, 이 부분에서 mask token 길이가 원문과 다르거나, 조사, 공백, 어순이 틀어지는 현상으로 인해 낮은 성능을 보일 수밖에 없습니다.
  • openpii-1.5m-ko 데이터 전수검사를 통해 약 30%가량의 불량데이터를 검출하여 제거하여, 학습 노이즈를 최소화
  • 실제 대화체에 개인정보가 포함되는 형태의 학습데이터를 대거 추가하여, 구어체의 긴 문장이 포함된 벤치에서도 높은 성능을 보임.
  • 합성데이터를 LLM으로 형태만 맞추어 무작위 생성하지 않고, 각 데이터별 포맷 규칙(프로그래미틱하게 작성)하에 작성하여 최대한 리얼월드 데이터와 유사하게 생성하고, 할루시네이션 가능성을 차단하였습니다.
    • 예) Luhn 알고리즘 활용하여, 실제 카드번호와 동일한 형태로 생성 → ISO/IEC 7812 — 앞 6자리 BIN(발급사) + 계좌번호 + 마지막 체크디지트

7-3. 추후 보완사항
#

  • 새롭게 추가된 카테고리 중, S/N 기기단말번호 또는 가입번호와 같은 회사마다/도메인마다 정형화된 포맷이 아니라, 예측이 어려운 부분에 대해서도 학습에 추가했으나, 실제로 예측하지 못하는 케이스가 더러 발생했다.
  • 비정형 타입의 카테고리의 경우, 전후 맥락 및 토큰의 위치정보 등을 통해 최대한 예측했으나, 아래 실제 테스트 결과와 같이 아직 탐지하지 못하는 케이스들이 확인되었고, 전체 카테고리의 탐지성능을 균일하게 끌어올리는 것이 추후 과제로 보여진다. (물론 실제 고객 환경에 적용 시, 해당 문제가 발생할 경우 모델단이 아닌 presidio를 통한 후처리를 통해 domain specific한 부분들은 어느 정도 처리가 가능하긴 함)
  • 마지막으로, 실제 기업 내부 프로덕션에 올려서 실 데이터 기반으로 검증이 필요함.
입력결과평가
가입번호: KT469200698 (학습 포맷)SUBSCRIBER_ID 1.00정답
계약번호 884102993317SUBSCRIBER_ID 0.999정답
가입번호: SKT-99-AB-77312MACADDRESS 0.49위치는 잡았으나, 라벨 오답
증권번호 HW-LIFE-2024-88231GENERIC_ID 0.59위치는 잡았으나, 라벨 오답
단말 S/N RF5IC1T7P97DEVICE_SERIAL 1.00정답
공유기 시리얼 넘버 QX-88Z-41772-KRMACADDRESS 0.998문맥이 있어도 틀림…
884102993317RRN 0.985문맥이 없어 완전 틀려버림..

8. 사용방법
#

  1. HuggingFace
  2. DockerHub → 모델만 담아 패키징한 이미지와 presidio 내에 모델을 담아 패키징한 이미지를 아래 dockerhub에 올려두었습니다.
  3. PlayGround
    • https://20-249-59-7.sslip.io/
    • 직접 여러 모델과 비교해서 실행해보실 수 있게 플레이그라운드를 호스팅해두었습니다.
    • 해당 플레이그라운드에서는 아래 4개 모델의 PII 성능을 비교 확인하실 수 있게 구성해두었습니다.
      1. Veil-PII-Ko-Lite (우리 모델)
      2. MoAI-Privacy-Filter (BCCard 모델)
      3. FrameByFrame
      4. Azure AI Language PII