TRENDSHIFT 일간 #4 · 2026-06-10

OpenMed 딥다이브
— 환자 데이터가 기기를 떠나지 않는 의료 AI

OpenMed는 의무기록 같은 임상 텍스트코드 한 줄로 구조화된 정보로 바꾸는 오픈소스 의료 AI 라이브러리입니다. 질병·약물·유전자 같은 의료 개체명 인식(NER)과 이름·주민번호·전화 같은 개인정보(PII) 비식별화를, HuggingFace에 올라온 1,000개 이상의 전용 의료 모델로 수행합니다. 핵심은 전부 내 기기·내 서버 안에서 돈다는 것 — CPU·CUDA는 물론 Apple Silicon(MLX)과 아이폰/맥 네이티브 앱(OpenMedKit)까지. 클라우드 API에 환자 데이터를 보내지 않습니다. (maziyarpanahi/openmed · Python 3.10+ & Swift · Apache-2.0 · 12개 언어 · 247개 PII 체크포인트 · arXiv 2508.01630)
목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트
  7. 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

무엇을 하는 프로젝트인가

병원·연구소에는 "사람이 쓴 글"로 된 의료 데이터가 산더미입니다 — 퇴원 요약지, 처방전, 검사 소견. 이걸 컴퓨터가 다루려면 먼저 "이 단어는 병명, 저 단어는 약 이름"처럼 의미를 붙여야 하고, 동시에 "이 이름·주민번호는 가려야 한다"는 개인정보 보호도 해야 합니다. 보통은 이걸 클라우드 의료 API에 보내 처리하는데, 그 순간 환자 정보가 외부 서버로 나갑니다.

OpenMed는 이 두 가지(의료 개체 추출 + 개인정보 비식별화)를 내 컴퓨터 안에서 끝냅니다. analyze_text("...") 한 줄이면 질병·약물·해부학·유전자 같은 개체를 뽑아 주고, deidentify("...") 한 줄이면 이름·날짜·주민번호를 가려 줍니다. 모델은 HuggingFace의 OpenMed 조직에 공개된 1,000개 이상에서 골라 쓰고, 네트워크 없이 로컬 폴더만 가리켜도 동작합니다.

from openmed import analyze_text

result = analyze_text(
    # 만성 골수성 백혈병에 imatinib을 시작했다는 임상 문장
    "Patient started on imatinib for chronic myeloid leukemia.",
    model_name="disease_detection_superclinical",
)
# DISEASE   chronic myeloid leukemia   0.98
# DRUG      imatinib                   0.95
한 장으로 이해하기

"병원 안에 상주하는 전속 판독 전문가"와 같다

지금까지는 환자 차트를 봉투에 넣어 외부 판독 센터(클라우드 API)로 보내고, 결과를 받아 봤습니다. 빠르지만 차트가 건물 밖으로 나가고, 보낼 때마다 비용이 듭니다.

OpenMed는 그 전문가를 병원 안에 직접 들이는 것입니다. 차트는 건물 밖으로 한 발짝도 나가지 않고, 판독은 그 자리에서 끝나며, 횟수당 요금도 없습니다. 게다가 이 전문가는 질병·약물·유전자별로 1,000명이 대기 중이고, 12개 언어를 합니다.

용어
NER (Named Entity Recognition · 개체명 인식)
문장에서 "이 토막은 무엇을 가리키는 이름인가"를 찾아 꼬리표를 붙이는 일. 일반 NER이 사람·장소·조직을 찾는다면, 의료 NER은 질병(DISEASE)·약물(DRUG)·해부학(ANATOMY)·유전자(GENE) 같은 임상 개체를 찾는다. OpenMed의 출력 단위인 entity텍스트·라벨·신뢰도를 담는다.
용어
PII 비식별화 (De-identification)
PII(개인 식별 정보 — 이름·주민번호·전화·주소 등)를 텍스트에서 찾아 가리거나 가짜로 바꿔, 누구인지 알 수 없게 만드는 처리. 미국 의료법 HIPAA는 18가지 "Safe Harbor 식별자"를 정해 두는데, OpenMed는 이 18종을 모두 다룬다. 가리는 방식은 마스킹·가짜치환·해시·날짜이동 4가지.
용어
로컬 우선 / 온디바이스 (Local-first / On-device)
데이터를 외부 서버로 보내지 않고 자기 기기·자기 서버에서 모든 계산을 끝내는 설계. 망 분리(air-gapped) 환경에서도 돌고, 프라이버시·규제 대응에 강하다. OpenMed는 같은 모델 이름 하나로 CPU·GPU·Apple MLX·아이폰까지 모두 온디바이스로 실행한다.

2왜 주목받는가

트렌딩 이유 · 클라우드 의료 API 대비 장점

주목 이유는 크게 셋입니다. ① 규제·프라이버시 압박 — 환자 정보(PHI)를 외부 클라우드로 보내는 것 자체가 HIPAA·GDPR 리스크라, "데이터를 안 내보내는" 도구 수요가 큽니다. ② 모델 생태계 — 1,000개 이상의 전용 의료 모델을 하나의 API로 묶었고, 다수가 독점 스택을 능가하는 SOTA(최첨단) 성능을 냅니다. ③ 온디바이스 가속 — Apple Silicon에서 MLX로 CPU 대비 24~33배 빨라져, 아이폰에서도 실시간 비식별화가 돕니다.

클라우드 의료 API와의 비교

항목클라우드 의료 APIOpenMed
실행 위치벤더 서버○ 내 기기 / 내 서버
환자 데이터 전송벤더로 전송됨○ 절대 나가지 않음
비용호출당 과금○ 무료 · 오픈소스
전용 의료 모델제한적○ 1,000개+
지원 언어제각각○ 12개 언어
오프라인 / 망분리○ 완전 오프라인 가능
Apple Silicon(MLX)해당 없음○ 24~33배 가속
네이티브 iOS/macOS 앱○ OpenMedKit
벤더 종속있음○ 없음(Apache-2.0)

핵심 차별점 셋

차별점 ①

"모델 이름 하나로 어디서나" — MLX↔PyTorch 자동 대체

같은 모델 이름을 적어도, Apple Silicon에서는 MLX 가속 체크포인트로, 그 외 하드웨어에서는 자동으로 똑같은 PyTorch 체크포인트로 대체되어 돕니다(한 번 경고만 띄우고). 개발자는 "어디서 돌릴지"를 신경 쓰지 않고 한 줄만 쓰면 됩니다. CoreML 폴백 경로까지 있어 iOS 앱에도 그대로 들어갑니다.

차별점 ②

"가린 자리를 진짜처럼" — 형식 보존 가짜 치환

비식별화는 단순히 [NAME]으로 지우는 것 말고도, Faker 기반으로 같은 형식의 그럴듯한 가짜 값으로 바꿀 수 있습니다. 게다가 브라질 CPF/CNPJ, 네덜란드 BSN, 프랑스 NIR, 이탈리아 Codice Fiscale, 인도 Aadhaar, 독일 Steuer-ID, 미국 NPI 같은 국가별 임상 식별자 생성기를 내장해, 다운스트림 시스템이 깨지지 않는 "현실적인 가짜 데이터셋"을 만듭니다.

차별점 ③

"12개 언어 · 247개 PII 체크포인트" — 진짜 다국어

영어뿐 아니라 fr·de·it·es·nl·hi·te·pt·ar·ja·tr까지 12개 언어로 PII 추출·비식별화가 됩니다. extract_pii(text, lang="pt")처럼 언어만 바꾸면 포르투갈어 CPF·전화번호를 알아서 잡습니다. 언어×개체 조합으로 247개 체크포인트가 준비되어 있습니다.

한 줄 요약

OpenMed가 화제인 이유는 "성능 좋은 의료 모델"이어서가 아니라, "규제가 가장 까다로운 데이터(환자 정보)를 외부로 안 보내고도 최첨단 처리를 가능하게 했다"는 점이다. 프라이버시(온디바이스)와 성능(SOTA 모델·MLX 가속)을 동시에 잡은 것이 핵심이다.

3기술 스택 전체 지도

언어 · 백엔드 · 패키지 · 인프라를 각각 뜯어본다

OpenMed의 설계 철학은 "얇은 핵심 + 갈아끼우는 백엔드 + 선택적 확장"입니다. 코어는 의존성이 단 2개(pysbd, faker)뿐이고, 무거운 ML 런타임(transformers·mlx·coreml)은 전부 선택 설치(extras)로 빠져 있습니다. 필요한 백엔드만 골라 깔면 됩니다.

언어 / 빌드

항목내용
주 언어Python 3.10+ (라이브러리·REST 서비스) + Swift (네이티브 앱 OpenMedKit)
빌드 백엔드hatchling — 버전은 openmed/__about__.py에서 동적으로 읽음
패키지 배포PyPI openmed + Swift Package Manager(SPM)
핵심 의존성단 2개 — pysbd(문장 경계 분할), faker(가짜 데이터 생성)
코어 외 모든 것선택 설치(extras): hf · service · gliner · mlx · coreml · docs
라이선스Apache-2.0 (상업 이용·재배포 자유)

선택 설치(extras) — 필요한 만큼만

extra설치 명령들어오는 것
hfpip install "openmed[hf]"transformers · huggingface-hub · accelerate · tokenizers (기본 추론 런타임)
service"openmed[hf,service]"fastapi · uvicorn (REST API 서버)
mlx"openmed[mlx]"mlx · tiktoken · safetensors (Apple Silicon 가속)
gliner"openmed[gliner]"gliner · torch (제로샷 NER)
coreml"openmed[coreml]"coremltools · torch (iOS/macOS용 모델 변환)
docs"openmed[docs]"mkdocs-material (문서 사이트 빌드)

4개 추론 백엔드 (갈아끼우는 엔진)

백엔드역할
PyTorch (torch/)기본 엔진 — CPU·CUDA GPU. transformers 토큰 분류 파이프라인
MLX (mlx/)Apple Silicon 전용 가속 — CPU 대비 24~33배. PII·Privacy Filter 계열
CoreML (coreml/)iOS/macOS 네이티브 런타임 변환 — OpenMedKit의 폴백 경로
GLiNER (zero_shot/)학습 없이 라벨만 주면 잡는 제로샷 NER (실험적)
설계 포인트
"코어는 가볍게, 무게는 extras로"

pip install openmed만 하면 transformers·torch 같은 수 GB짜리 의존성이 안 깔린다. 코어는 문장 분할(pysbd)과 가짜 생성(faker)만 안다. 실제 모델을 돌릴 때 비로소 [hf][mlx]를 더한다. 덕분에 "비식별화 후처리 로직만 쓰고 싶은 사람"과 "GPU로 대량 추론하는 사람"이 같은 패키지를 다른 무게로 쓸 수 있다.

인프라 — REST 서비스 & Docker

라이브러리를 넘어 FastAPI 기반 REST 서비스로도 돌릴 수 있습니다. Docker 이미지는 python:3.11-slim 베이스에 CPU 전용 PyTorch를 깔고, uvicorn으로 openmed.service.app을 8080 포트에 띄웁니다. HEALTHCHECK/health를 주기 점검하고, OPENMED_SERVICE_KEEP_ALIVE 환경변수로 유휴 모델을 자동 내려 메모리를 회수합니다.

# 서비스 실행
uvicorn openmed.service.app:app --host 0.0.0.0 --port 8080

# 또는 Docker로
docker build -t openmed:1.5.5 .
docker run --rm -p 8080:8080 -e OPENMED_PROFILE=prod openmed:1.5.5

# 엔드포인트: /health  /analyze  /pii/extract  /pii/deidentify
#            /models/loaded  /models/unload (모델 생명주기 관리)

Apple 생태계 — Swift / MLX / OpenMedKit

같은 모델을 아이폰·아이패드·맥 앱에 그대로 넣을 수 있는 게 큰 강점입니다. swift/ 아래에 SPM 패키지 OpenMedKit과 데모 앱 2개(OpenMedDemo, OpenMedScanDemo)가 있습니다. 앱에 다음 한 줄로 의존성을 추가하면, PII 탐지·임상 추출이 완전 오프라인으로 기기 안에서 돕니다.

// Swift Package에 OpenMedKit 추가
dependencies: [
    .package(url: "https://github.com/maziyarpanahi/openmed.git", from: "1.5.5"),
]

4아키텍처 심화 분석

시스템 구조도 + 핵심 설계 패턴

OpenMed의 진짜 배울 점은 "임상 텍스트 → 토큰 분류 → 개체 디코딩/병합 → 출력"의 파이프라인을, 백엔드와 언어에 독립적으로 추상화한 방식입니다. 어떤 엔진(torch/mlx/coreml)을 쓰든, 어떤 언어든, 같은 analyze_text() / extract_pii() 진입점으로 흐릅니다.

전체 데이터 흐름도

[입력] [전처리] [백엔드 라우팅] [추론] 임상 텍스트 ──▶ pysbd 문장분할 ──▶ backends.py ──┬──▶ torch (CPU/CUDA) model_registry │ ├──▶ mlx (Apple) 이름→체크포인트 │ ├──▶ coreml (iOS/macOS) │ └──▶ gliner (제로샷) ▼ 토큰 분류 (라벨 + 신뢰도) │ ┌────────────────────────┼────────────────────────┐ ▼ ▼ ▼ pii_entity_merger 개체 디코딩 anonymizer/ (조각난 토큰 재조립) DISEASE/DRUG/... mask·replace· │ │ hash·shift_dates ▼ ▼ ▼ PII 개체 목록 의료 개체 목록 비식별화된 텍스트 ★ 모든 화살표는 내 기기 안에서만 일어난다 (네트워크 호출 0 · 모델은 로컬 캐시)

설계 패턴 ① — 백엔드 추상화 (한 이름, 모든 하드웨어)

core/backends.py가 "어느 엔진으로 돌릴지"를 한 곳에서 결정합니다. 사용자가 MLX 모델 이름을 적었는데 Apple Silicon이 아니면, 같은 가중치의 PyTorch 체크포인트로 자동 대체합니다. 개발자 코드는 그대로 두고 실행 환경만 바뀌어도 동작하는 "write once, run anywhere"의 ML 버전입니다.

용어
MLX
Apple이 만든 Apple Silicon(M1~M4) 전용 머신러닝 프레임워크. 통합 메모리 구조를 활용해 맥·아이폰에서 모델을 빠르게 돌린다. OpenMed는 PII·Privacy Filter 계열을 MLX로 돌려 CPU PyTorch 대비 24~33배 빠른 지연시간을 낸다. 8비트 양자화 버전(-mlx-8bit)도 제공한다.

설계 패턴 ② — 모델 레지스트리 (1,000개를 친근한 이름으로)

HuggingFace의 긴 체크포인트 경로를 매번 외울 수는 없습니다. core/model_registry.py(약 22KB)는 disease_detection_superclinical 같은 친근한 별명 → 실제 HF 체크포인트 매핑을 큐레이션해 둡니다. 처음 쓸 때 모델을 내려받아 로컬 캐시에 두고, 그다음부터는 네트워크 없이 씁니다.

모델 별명전문 분야개체 타입크기
disease_detection_superclinical질병·상태DISEASE, CONDITION, DIAGNOSIS434M
pharma_detection_superclinical약물DRUG, MEDICATION, TREATMENT434M
pii_superclinical_large개인정보NAME, DATE, SSN, PHONE, EMAIL...434M
anatomy_detection_electramed해부학ANATOMY, ORGAN, BODY_PART109M
gene_detection_genecorpus유전자·단백질GENE, PROTEIN109M

망 분리 환경이라면 model_id="./models/..."처럼 로컬 디렉토리를 가리켜 HF Hub에 접속하지 않고 로드할 수 있습니다.

설계 패턴 ③ — 스마트 개체 병합 (토큰 조각 재조립)

Transformer는 단어를 서브워드 토큰으로 쪼개 처리합니다. 그래서 01/15/1970 같은 날짜가 01, /, 15... 로 흩어지기 쉽습니다. core/pii_entity_merger.py(약 28KB)는 이렇게 조각난 토큰을 다시 하나의 개체로 붙여, 날짜·주민번호가 토막 나지 않게 합니다. 비식별화 품질을 좌우하는 숨은 핵심입니다.

용어
서브워드 토큰화 · BIO 태깅
모델은 문장을 단어보다 작은 조각(서브워드)으로 나눠 본다. NER은 각 토큰에 B(개체 시작)·I(개체 내부)·O(개체 아님) 태그를 붙이는데, 이걸 다시 사람이 읽는 개체로 합치는 "디코딩/병합" 단계가 필요하다. 이 단계가 부실하면 "John"과 "Doe"가 따로 잡혀 이름이 반만 가려진다.

설계 패턴 ④ — 비식별화 4전략

core/anonymizer/는 찾아낸 PII를 어떻게 처리할지 4가지 방법을 제공합니다. 상황(연구용 공유, 로그 보관, 종단 추적)에 따라 고릅니다.

method동작쓰임새
mask[NAME], [DATE]로 라벨 치환가장 단순·안전한 가림
replaceFaker로 형식 보존 가짜값현실적 테스트 데이터셋
hash암호학적 해시로 치환같은 사람=같은 해시(연결 추적)
shift_dates날짜를 일정 일수만큼 이동시간 간격은 보존, 실제 날짜는 숨김

설계 패턴 ⑤ — Privacy Filter 계열 (같은 코드, 다른 가중치)

비식별화 모델 중 일부는 OpenAI Privacy Filter 아키텍처를 공유합니다. gpt-oss 계열의 희소 MoE 트랜스포머에 로컬 어텐션·sink 토큰·RoPE+YaRN·tiktoken o200k_base를 쓰는 구조입니다. 코드는 똑같고 학습 데이터(가중치)만 다른 3가지 변형이 있으며, 모두 같은 extract_pii() API로 부릅니다 — model_name=만 바꾸면 됩니다.

변형특징
OpenAI Privacy Filter원본 베이스라인
Nemotron-PII 파인튜닝NVIDIA Nemotron PII 데이터셋으로 미세조정
OpenMed Multilingual12개 언어 다국어 비식별화
용어
희소 MoE · RoPE · YaRN
MoE(Mixture of Experts)는 여러 전문가 신경망 중 일부만 골라 켜는 "희소" 구조로, 적은 연산으로 큰 용량을 낸다. RoPE는 토큰 위치를 회전으로 인코딩하는 방식, YaRN은 그 RoPE를 더 긴 문맥까지 늘리는 기법이다. 긴 임상 문서를 효율적으로 처리하려는 선택이다.

REST 서비스 내부 구조

파일역할
service/app.pyFastAPI 앱 — 엔드포인트 정의·에러 봉투 통일
service/runtime.py파이프라인 사전 로드·공유, 모델 적재/해제
service/keep_alive.py유휴 시간 지나면 모델 자동 언로드(메모리 회수)
service/schemas.py요청/응답 검증 스키마(Pydantic)

5디렉토리 구조 해부

주요 폴더/파일의 역할

"얇은 코어 + 백엔드별 폴더 + 서비스/앱 분리" 철학이 구조에 그대로 보입니다. 두뇌는 openmed/core/에 모여 있고, 엔진은 torch/ mlx/ coreml/ zero_shot/으로 갈라지며, 배포 형태(서비스·Swift 앱)는 바깥에 있습니다.

openmed/ ← 저장소 루트 ├─ openmed/ ← 파이썬 패키지 (pip로 깔리는 본체) │ ├─ __init__.py 공개 API: analyze_text, extract_pii, deidentify... │ ├─ core/ ★ 두뇌 │ │ ├─ backends.py 백엔드 라우팅(torch↔mlx 자동 대체) │ │ ├─ model_registry.py 별명→HF 체크포인트 매핑(~22KB) │ │ ├─ models.py / labels.py 모델 로드·라벨 정의 │ │ ├─ pii.py PII 추출 핵심(~64KB) │ │ ├─ pii_entity_merger.py 조각난 토큰 재조립(~28KB) │ │ ├─ pii_i18n.py 12개 언어 PII 라우팅(~57KB) │ │ ├─ anonymizer/ mask·replace·hash·shift_dates │ │ ├─ decoding/ BIO 태그→개체 디코딩 │ │ ├─ config.py OpenMedConfig(device 등) │ │ └─ quality_gates.py 출력 품질 게이트 │ ├─ torch/ mlx/ coreml/ ← 백엔드별 구현 │ ├─ zero_shot/ GLiNER 제로샷 NER │ ├─ ner/ processing/ NER 파이프라인·후처리 │ ├─ service/ FastAPI REST(app·runtime·keep_alive·schemas) │ └─ utils/ 공통 유틸 ├─ swift/ ← Apple 생태계 │ ├─ OpenMedKit/ SPM 라이브러리(앱에 임포트) │ ├─ OpenMedDemo/ 데모 앱 │ └─ OpenMedScanDemo/ 카메라 스캔→비식별화 데모 ├─ examples/notebooks/ PII 가이드 등 주피터 노트북 ├─ tests/ pytest(integration·slow 마커) ├─ docs/ + mkdocs.yml 문서 사이트(openmed.life) ├─ Dockerfile CPU torch + FastAPI 서비스 이미지 ├─ pyproject.toml hatchling 빌드 + extras 정의 ├─ Package.swift Swift Package 매니페스트 └─ README.md (+ 13개 언어판) 다국어 README
읽기 좋은 순서

처음 본다면 READMEopenmed/__init__.py(어떤 함수가 공개 API인가) → core/model_registry.py(어떤 모델이 어떤 별명인가) → core/backends.py(엔진이 어떻게 갈리나) → core/pii.pypii_entity_merger.py(비식별화의 심장) → service/app.py(서비스로 어떻게 노출되나) 순서가 좋다.

6학습 포인트

이 레포에서 기술별로 배울 것 + 실습 아이디어

① 트랜스포머 토큰 분류로 하는 NER

"문장 → 토큰별 라벨 → 개체로 합치기"는 정보 추출의 기본기입니다. OpenMed는 의료 도메인으로 이걸 실전 수준까지 끌고 갑니다. transformers의 토큰 분류 파이프라인이 어떻게 NER이 되는지, 라벨 체계(DISEASE/DRUG...)가 어떻게 정의되는지 통째로 볼 수 있습니다.

실습: HuggingFace transformerspipeline("token-classification")으로 아무 영어 문장에서 사람·장소를 뽑아 보고, OpenMed의 analyze_text 결과와 출력 형태를 비교한다.

② 백엔드 독립성 — 한 번 짜고 어디서나

같은 모델을 CPU·GPU·MLX·CoreML로 돌리는 추상화는, 의존성 역전과 어댑터 패턴의 ML판입니다. backends.py 한 파일이 "어느 엔진을 고를지"를 캡슐화해, 상위 코드가 하드웨어를 몰라도 되게 합니다.

실습: 내 코드에서 "연산을 수행하는 부분"을 인터페이스 하나 뒤로 숨기고, 구현체를 2개(예: 느린 버전·빠른 버전) 만들어 런타임에 바꿔 끼워 본다.

③ PII 비식별화와 HIPAA

"무엇이 개인정보인가", "어떻게 가려야 재식별이 안 되나"는 실무에서 가장 까다로운 주제입니다. HIPAA의 18개 Safe Harbor 식별자, 마스킹 vs 가짜치환 vs 해시의 트레이드오프, 형식 보존의 필요성을 코드로 익힐 수 있습니다.

실습: 같은 임상 문장에 method="mask", "replace", "hash"를 각각 적용해 출력 차이를 비교하고, "어떤 상황에 무엇을 써야 하나"를 표로 정리한다.

④ 토큰화와 개체 병합의 함정

서브워드 토큰화 때문에 날짜·번호가 조각나는 문제는 NER 품질의 숨은 적입니다. pii_entity_merger.py는 이 "조각을 다시 붙이는" 후처리가 왜 필수인지, 어떻게 구현하는지 보여 주는 좋은 교본입니다.

실습: 토크나이저로 "010-1234-5678"을 토큰화해 몇 조각으로 쪼개지는지 보고, 인접한 같은-라벨 토큰을 다시 합치는 작은 병합 함수를 직접 짠다.

⑤ ML을 서비스로 — FastAPI · 모델 생명주기 · Docker

모델을 "라이브러리"가 아니라 "API 서비스"로 만들 때 생기는 문제 — 사전 로드, 메모리 회수, 헬스체크, 컨테이너화 —를 한 레포에서 다룹니다. runtime.py의 파이프라인 공유와 keep_alive.py의 유휴 언로드가 특히 실전적입니다.

실습: OpenMed 서비스를 Docker로 띄우고 curl/pii/extract를 호출한 뒤, /models/loaded·/models/unload로 메모리에 올라온 모델을 직접 내려 본다.

7시스템 요구사항

무엇이 있어야 돌아가나
항목요구사항
파이썬Python 3.10+. 코어만이면 의존성 2개로 가벼움
추론(기본)openmed[hf] — transformers·torch. 434M 모델은 메모리 ~2GB 안팎 권장
Apple 가속openmed[mlx] + Apple Silicon(M1 이상). CPU 대비 24~33배
REST 서비스openmed[hf,service] 또는 Docker(python:3.11-slim, 8080 포트)
iOS / macOS 앱OpenMedKit(SPM), CoreML 변환 모델. iOS 17+ / macOS 14+ / 최신 Xcode
모델 다운로드최초 1회 HF Hub 접속(이후 로컬 캐시). 망분리 시 로컬 디렉토리 지정
네트워크모델만 받으면 추론은 완전 오프라인. 데이터는 절대 외부 전송 안 함
중요 · 안전/규제 고지

OpenMed는 텍스트 처리 도구이지 의료기기·법적 컴플라이언스 인증이 아니다. ① 자동 비식별화 출력은 모델의 예측이며 100% 재식별 방지를 보장하지 않는다 — 실제 환자 데이터에 쓰기 전 반드시 사람 검수와 기관 정책(IRB·DPO) 검토를 거쳐야 한다. ② NER 결과(질병·약물)는 진단·치료 판단의 근거가 아니라 추출 보조일 뿐이다. ③ HIPAA "Safe Harbor 18종 지원"은 기능 범위를 뜻하지, 특정 데이터셋이 법적으로 비식별되었음을 보증하지 않는다. 규제 데이터에 적용할 때는 법무·보안 검토를 함께 진행하라.

8직접 해볼 수 있는 실습 과제

난이도별 5개 — 직접 손을 움직여야 남는다
난이도 ★☆☆

1. 첫 추출 — analyze_text 한 줄

pip install "openmed[hf]" 후, 합성(가짜) 임상 문장 하나를 disease_detection_superclinical로 분석해 DISEASE·DRUG 개체와 신뢰도를 출력한다. 실제 환자 데이터가 아니라 합성 문장으로 시작하는 습관을 들인다.

난이도 ★☆☆

2. 비식별화 4전략 비교

"Patient: John Doe, DOB: 01/15/1970" 같은 합성 문장에 mask·replace·hash·shift_dates를 각각 적용해 출력을 나란히 본다. 어떤 게 "연구 공유용", 어떤 게 "로그 보관용"에 맞는지 한 줄씩 메모한다.

난이도 ★★☆

3. REST 서비스 띄우고 curl 호출

uvicorn openmed.service.app:app(또는 Docker)로 서비스를 띄우고 POST /pii/extract에 JSON을 보내 응답을 확인한다. 이어 /models/loaded로 적재된 모델을 보고 /models/unload로 내려 메모리 변화를 관찰한다.

난이도 ★★☆

4. 다국어 PII

extract_pii(text, lang="pt")로 포르투갈어 CPF·전화를, lang="ja"로 일본어 マイナンバー를 잡아 본다. 언어만 바꿨을 뿐인데 국가별 식별자를 인식하는 과정을 따라가며, pii_i18n.py가 어떻게 라우팅하는지 코드를 본다.

난이도 ★★★

5. 망분리(에어갭) 오프라인 추론

모델을 로컬 디렉토리로 내려받은 뒤, 네트워크를 끊고 model_id="./models/..." + OpenMedConfig(device="cpu")로 HF Hub 접속 없이 추론이 되는지 검증한다. "데이터도 모델도 안 나가는" 진짜 온디바이스 환경을 직접 만들어 본다.

9관련 기술 심화 학습 로드맵

주차별 4주 계획 — 의료 NLP + 온디바이스 추론
주차주제할 일
1주차트랜스포머 NER 기초토큰 분류·BIO 태깅 개념, HF pipeline으로 NER 실습, 라벨 체계 이해
2주차PII / 비식별화 / HIPAASafe Harbor 18종, mask/replace/hash 트레이드오프, Faker 형식 보존, 재식별 위험
3주차온디바이스 추론 · 이식성MLX·CoreML 변환, 8비트 양자화, 백엔드 추상화·자동 폴백 설계
4주차ML 서비스화 + SwiftFastAPI 서빙·모델 생명주기·Docker, OpenMedKit로 iOS 앱에 모델 임베드
학습 팁

이 레포는 "의료 NLP 모델을 어떻게 실전 제품으로 만드나"의 완결판이다. 모델 추론이라는 한 점이 아니라, 전처리→백엔드 선택→추론→개체 병합→비식별화→서빙→앱 임베드까지 한 줄로 꿰여 있다. 각 단계의 "입력과 출력"을 적어 가며 따라가면, 4주 뒤엔 다른 도메인(법률·금융 문서의 PII)으로도 같은 골격을 옮길 수 있다.

10핵심 키워드 사전

이 프로젝트에 등장하는 용어 빠른 정리
용어
HIPAA · Safe Harbor 18종
HIPAA는 미국의 의료정보 보호법. 그중 "Safe Harbor" 방식은 이름·지역·날짜·전화·이메일·주민번호·의료기록번호 등 18가지 식별자를 모두 제거하면 비식별로 본다는 기준이다. OpenMed는 이 18종을 모두 다루도록 설계됐지만, "다룬다"는 것이 법적 비식별 보증은 아니다.
용어
개체명 인식 (NER) · 토큰 분류
문장 속 토큰마다 "이게 어떤 개체의 일부인가"를 분류하는 작업. 의료 NER은 DISEASE·DRUG·GENE 같은 임상 라벨을 쓴다. OpenMed의 analyze_text가 돌려주는 entities는 각각 텍스트·라벨·신뢰도를 가진다.
용어
형식 보존 가짜 치환 (Format-preserving fake)
PII를 그냥 지우는 대신, 같은 형식의 그럴듯한 가짜로 바꾸는 것. 예: 실제 주민번호를 유효 형식의 가짜 번호로. 그래야 다운스트림 파서·검증 로직이 깨지지 않는 "현실적 테스트 데이터"가 된다. OpenMed는 Faker + 국가별 식별자(CPF·Aadhaar·NPI 등) 생성기로 구현한다.
용어
MLX · CoreML
둘 다 Apple 기기에서 모델을 빠르게 돌리는 길. MLX는 Apple Silicon용 ML 프레임워크(통합 메모리 활용), CoreML은 iOS/macOS 앱에 모델을 넣는 표준 런타임. OpenMed는 MLX로 가속하고, 변환이 안 되면 CoreML 또는 PyTorch로 폴백한다.
용어
제로샷 NER (GLiNER)
미리 학습한 라벨이 아니라, 실행 시점에 원하는 라벨을 말로 주면 그걸 찾아 주는 NER. 새 개체 타입이 생길 때 재학습 없이 바로 시도할 수 있다. OpenMed는 GLiNER 계열을 zero_shot/에 실험적으로 둔다.
용어
문장 경계 분할 (pysbd)
긴 텍스트를 모델에 넣기 전, "문장이 어디서 끝나나"를 정확히 자르는 일. 의료 텍스트는 약어(Dr., mg.)가 많아 마침표만으로 자르면 틀린다. OpenMed의 코어 의존성 pysbd가 규칙 기반으로 이 경계를 잡는다.

11참고 링크

더 깊이 파고들 곳