차등 프라이버시, PII 마스킹, 멤버십 추론 공격 방어, 유사도 필터, 규제 대응 전략과 프라이버시-유용성 트레이드오프를 다룹니다.
합성 데이터의 가장 큰 약속 중 하나는 프라이버시 보호입니다. 그러나 합성 데이터라고 해서 자동으로 프라이버시가 보장되는 것은 아닙니다. 생성 모델이 원본 데이터의 특정 레코드를 "기억"하고 그대로 재현할 수 있기 때문입니다. 이를 기억 현상(Memorization)이라 합니다.
"합성 데이터 = 프라이버시 안전"이라는 가정은 위험합니다. 프라이버시 보장은 자동으로 주어지는 것이 아니라, 적극적으로 설계하고 검증해야 하는 속성입니다.
차등 프라이버시(DP)는 데이터 프라이버시에 대한 수학적 보장을 제공하는 프레임워크입니다. 핵심 아이디어는 단순합니다: 데이터셋에 특정 개인이 포함되었는지 여부와 관계없이, 분석 결과가 거의 동일해야 한다는 것입니다.
차등 프라이버시의 공식 정의는 다음과 같습니다. 랜덤화된 메커니즘 M이 epsilon-차등 프라이버시를 만족한다는 것은, 최대 한 개의 레코드가 다른 임의의 두 인접 데이터셋 D1, D2에 대해 다음이 성립하는 것입니다:
Pr[M(D1) in S] <= exp(epsilon) * Pr[M(D2) in S]
여기서 epsilon은 프라이버시 예산(Privacy Budget)이라 불리며, 값이 작을수록 프라이버시 보호가 강력합니다.
| epsilon 값 | 프라이버시 수준 | 유용성 | 일반적 용도 |
|---|---|---|---|
| 0.1~1.0 | 매우 강함 | 낮음 | 민감한 의료/금융 데이터 |
| 1.0~5.0 | 강함 | 중간 | 일반적인 프라이버시 보호 |
| 5.0~10.0 | 보통 | 높음 | 덜 민감한 데이터 |
| 10.0+ | 약함 | 매우 높음 | 형식적 보호 |
DP-SGD(Differentially Private Stochastic Gradient Descent)는 모델 학습 과정에서 차등 프라이버시를 적용하는 방법입니다. 그래디언트에 노이즈를 추가하여 개별 학습 샘플의 영향을 제한합니다.
import numpy as np
from dataclasses import dataclass
@dataclass
class DPConfig:
epsilon: float = 1.0 # 프라이버시 예산
delta: float = 1e-5 # 실패 확률
max_grad_norm: float = 1.0 # 그래디언트 클리핑 노름
noise_multiplier: float = 1.1 # 노이즈 배수
num_epochs: int = 50
batch_size: int = 256
def add_dp_noise(
gradients: np.ndarray,
config: DPConfig,
) -> np.ndarray:
"""그래디언트에 차등 프라이버시 노이즈를 추가합니다."""
# 1단계: 그래디언트 클리핑
grad_norm = np.linalg.norm(gradients)
if grad_norm > config.max_grad_norm:
gradients = gradients * (config.max_grad_norm / grad_norm)
# 2단계: 가우시안 노이즈 추가
noise_scale = config.noise_multiplier * config.max_grad_norm
noise = np.random.normal(0, noise_scale, gradients.shape)
return gradients + noise
def compute_privacy_budget(
noise_multiplier: float,
num_steps: int,
batch_size: int,
dataset_size: int,
delta: float = 1e-5,
) -> float:
"""Renyi DP 기반 프라이버시 예산을 계산합니다."""
# 실제 구현에서는 opacus 또는 dp-accounting 라이브러리 사용
sampling_rate = batch_size / dataset_size
# 근사값 (정확한 계산은 라이브러리 필요)
epsilon_estimate = (
noise_multiplier
* np.sqrt(2 * np.log(1.25 / delta))
* sampling_rate
* np.sqrt(num_steps)
)
return epsilon_estimate실전에서는 PyTorch의 Opacus 라이브러리를 활용하면 DP-SGD를 쉽게 적용할 수 있습니다. Opacus는 자동으로 그래디언트 클리핑, 노이즈 추가, 프라이버시 예산 추적을 수행합니다. 차등 프라이버시가 적용된 모델로 생성한 합성 데이터는 실제 데이터 대비 96.8% vs 97.2%의 정확도 차이만 보여줍니다.
PII(Personally Identifiable Information)는 개인을 식별할 수 있는 모든 정보를 말합니다. 합성 데이터에 원본의 PII가 유출되면 프라이버시 보호의 의미가 없어집니다.
import re
from dataclasses import dataclass
from enum import Enum
class PIIType(Enum):
PHONE = "phone"
EMAIL = "email"
SSN = "ssn" # 주민등록번호
CREDIT_CARD = "credit_card"
NAME = "name"
ADDRESS = "address"
IP_ADDRESS = "ip_address"
@dataclass
class PIIEntity:
text: str
pii_type: PIIType
start: int
end: int
confidence: float
# 한국어 PII 패턴
PII_PATTERNS = {
PIIType.PHONE: [
r"01[016789]-?\d{3,4}-?\d{4}",
r"02-?\d{3,4}-?\d{4}",
r"0\d{1,2}-?\d{3,4}-?\d{4}",
],
PIIType.EMAIL: [
r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}",
],
PIIType.SSN: [
r"\d{6}-?[1-4]\d{6}",
],
PIIType.CREDIT_CARD: [
r"\d{4}-?\d{4}-?\d{4}-?\d{4}",
],
PIIType.IP_ADDRESS: [
r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}",
],
}
def detect_pii_regex(text: str) -> list[PIIEntity]:
"""정규식 기반으로 PII를 탐지합니다."""
entities = []
for pii_type, patterns in PII_PATTERNS.items():
for pattern in patterns:
for match in re.finditer(pattern, text):
entities.append(PIIEntity(
text=match.group(),
pii_type=pii_type,
start=match.start(),
end=match.end(),
confidence=0.9,
))
return entities
def mask_pii(text: str, entities: list[PIIEntity]) -> str:
"""탐지된 PII를 마스킹합니다."""
# 뒤에서부터 치환하여 인덱스 밀림 방지
sorted_entities = sorted(entities, key=lambda e: e.start, reverse=True)
masked = text
for entity in sorted_entities:
mask_token = f"[{entity.pii_type.value.upper()}]"
masked = masked[:entity.start] + mask_token + masked[entity.end:]
return masked정규식으로 탐지할 수 없는 이름, 주소 등은 NER 모델을 활용합니다.
def detect_pii_with_llm(text: str, model_fn) -> list[PIIEntity]:
"""LLM을 활용하여 PII를 탐지합니다."""
prompt = f"""다음 텍스트에서 개인 식별 정보(PII)를 모두 찾아주세요.
PII 유형: 이름, 전화번호, 이메일, 주민등록번호, 주소,
신용카드번호, IP 주소, 계좌번호
텍스트: {text}
JSON 형식으로 출력:
[{{"text": "탐지된 PII", "type": "PII 유형", "start": 시작위치, "end": 끝위치}}]"""
result = model_fn(prompt)
# 파싱 및 PIIEntity 변환
return parse_pii_result(result)PII 탐지는 "정규식 + NER + LLM"을 3계층으로 조합하는 것이 가장 효과적입니다. 정규식이 명확한 패턴을, NER이 고유명사를, LLM이 문맥 의존적 PII를 각각 담당합니다. 단일 기법의 재현율은 70~85% 수준이지만, 3계층 조합은 95% 이상을 달성할 수 있습니다.
멤버십 추론 공격(Membership Inference Attack, MIA)은 특정 레코드가 모델의 학습 데이터에 포함되었는지를 판별하는 공격입니다. 합성 데이터의 프라이버시를 검증하는 핵심 도구이기도 합니다.
합성 데이터를 배포하기 전에, MIA를 자체적으로 수행하여 프라이버시 위험을 사전에 평가합니다.
import numpy as np
from sklearn.metrics import roc_auc_score
from sklearn.neighbors import NearestNeighbors
def membership_inference_test(
synthetic_data: np.ndarray,
training_data: np.ndarray,
holdout_data: np.ndarray,
k: int = 5,
) -> dict:
"""멤버십 추론 공격 시뮬레이션으로 프라이버시를 평가합니다."""
nn_model = NearestNeighbors(n_neighbors=k, metric="euclidean")
nn_model.fit(synthetic_data)
# 학습 데이터(멤버)의 최근접 거리
member_distances, _ = nn_model.kneighbors(training_data)
member_avg_dist = member_distances.mean(axis=1)
# 홀드아웃 데이터(비멤버)의 최근접 거리
nonmember_distances, _ = nn_model.kneighbors(holdout_data)
nonmember_avg_dist = nonmember_distances.mean(axis=1)
# 라벨: 멤버=1, 비멤버=0
labels = np.concatenate([
np.ones(len(member_avg_dist)),
np.zeros(len(nonmember_avg_dist)),
])
# 거리가 짧을수록 멤버일 가능성이 높으므로 부호 반전
scores = np.concatenate([
-member_avg_dist,
-nonmember_avg_dist,
])
# AUC 계산: 0.5에 가까울수록 안전
auc = roc_auc_score(labels, scores)
return {
"mia_auc": auc,
"privacy_risk": "high" if auc > 0.6 else "low",
"member_mean_distance": member_avg_dist.mean(),
"nonmember_mean_distance": nonmember_avg_dist.mean(),
}MIA AUC가 0.5에 가까울수록 공격자가 멤버와 비멤버를 구분할 수 없음을 의미하며, 프라이버시가 잘 보호되고 있다는 뜻입니다. 일반적으로 AUC가 0.55 이하이면 안전한 것으로 간주합니다. 0.6을 초과하면 프라이버시 위험을 재검토해야 합니다.
합성 데이터에서 원본과 지나치게 유사한 레코드를 사전에 제거하는 필터입니다.
import numpy as np
from sklearn.neighbors import NearestNeighbors
def similarity_filter(
synthetic: np.ndarray,
real: np.ndarray,
min_distance: float = 0.1,
) -> tuple[np.ndarray, np.ndarray]:
"""원본과 너무 유사한 합성 데이터를 필터링합니다."""
nn = NearestNeighbors(n_neighbors=1, metric="euclidean")
nn.fit(real)
distances, indices = nn.kneighbors(synthetic)
distances = distances.flatten()
# 최소 거리 이상인 데이터만 유지
safe_mask = distances >= min_distance
safe_synthetic = synthetic[safe_mask]
filtered_synthetic = synthetic[~safe_mask]
print(
f"필터링 결과: {safe_mask.sum()}/{len(synthetic)} 유지 "
f"({(~safe_mask).sum()}건 제거)"
)
return safe_synthetic, filtered_syntheticGDPR에서 합성 데이터의 법적 지위는 아직 완전히 확립되지 않았지만, 다음 원칙이 적용됩니다.
규제 대응에서 기술적 조치만으로는 충분하지 않습니다. 법적 검토, 프라이버시 영향 평가(PIA), 문서화가 반드시 동반되어야 합니다. 특히 의료, 금융 등 규제가 엄격한 도메인에서는 법무팀과의 긴밀한 협업이 필수입니다.
프라이버시와 유용성은 본질적으로 트레이드오프 관계에 있습니다. 프라이버시 보호를 강화하면 데이터의 유용성이 감소하고, 유용성을 높이면 프라이버시 위험이 증가합니다.
from dataclasses import dataclass
@dataclass
class PrivacyUtilityResult:
epsilon: float
tstr_score: float
mia_auc: float
pii_leak_rate: float
def find_optimal_privacy_level(
real_data,
epsilon_candidates: list[float] = [0.1, 0.5, 1.0, 2.0, 5.0, 10.0],
min_tstr_threshold: float = 0.90,
max_mia_auc_threshold: float = 0.55,
) -> PrivacyUtilityResult | None:
"""최적의 프라이버시 수준을 탐색합니다."""
results: list[PrivacyUtilityResult] = []
for epsilon in epsilon_candidates:
# 1. DP 적용 합성 데이터 생성
synthetic = generate_dp_synthetic(real_data, epsilon)
# 2. 유용성 평가
tstr = evaluate_tstr(synthetic, real_data)
# 3. 프라이버시 평가
mia = membership_inference_test(synthetic, real_data)
pii_rate = detect_pii_leak_rate(synthetic, real_data)
results.append(PrivacyUtilityResult(
epsilon=epsilon,
tstr_score=tstr,
mia_auc=mia["mia_auc"],
pii_leak_rate=pii_rate,
))
# 조건을 만족하는 결과 중 가장 강한 프라이버시 선택
valid = [
r for r in results
if r.tstr_score >= min_tstr_threshold
and r.mia_auc <= max_mia_auc_threshold
]
if valid:
return min(valid, key=lambda r: r.epsilon)
return None프라이버시-유용성 트레이드오프에서 "정답"은 없습니다. 중요한 것은 트레이드오프를 명시적으로 측정하고, 도메인의 규제 요구사항과 비즈니스 요구사항을 균형 있게 반영하는 것입니다. 의료 데이터라면 프라이버시를, A/B 테스트 데이터라면 유용성을 우선시하는 것이 합리적입니다.
이 장에서는 합성 데이터의 프라이버시 보존 기법을 체계적으로 다루었습니다.
다음 장에서는 도메인 특화 합성 데이터셋 구축을 다룹니다. 의료, 법률, 금융, 코드 등 각 전문 분야에서 합성 데이터를 효과적으로 만드는 고유한 전략과 실전 사례를 살펴봅니다.
이 글이 도움이 되셨나요?
의료, 법률, 금융, 코드 도메인별 합성 데이터 접근법, 전문가 시드 데이터 설계, InstructLab 택소노미 방식, 도메인 검증 전략을 다룹니다.
전통적 텍스트 증강부터 LLM 기반 증강, 어려운 예제 생성, 엣지 케이스 증강, 증강 비율 최적화까지 실전 데이터 증강 기법을 다룹니다.
TSTR 방법론, 다양성 메트릭, 분포 비교, 다운스트림 성능 측정, 합성 vs 실제 데이터 비교 실험, 벤치마크 설계 방법을 다룹니다.