MONAI에서 MLLM용 데이터 전처리 파이프라인 구성 방법[pe]
관련된
MONAI에서 MLLM용 데이터 전처리 파이프라인 구성 방법[pe]
MONAI에서 MLLM용 데이터 전처리 파이프라인을 짜는 핵심은 “이미지는 MONAI, 텍스트는 별도, 마지막에 둘을 한 번에 묶는다”로 정리할 수 있다.
아래 흐름대로 만들면, 나중에 어떤 MLLM을 올려도 견딜 수 있는 구조가 된다.
전체 그림: 왜 “딕셔너리 파이프라인”이 답인가
MLLM은 기본적으로 “이미지 텐서 + 텍스트 토큰”을 함께 받으므로, 데이터 레벨에서는 한 샘플이 {image: ..., text: ...} 형태의 딕셔너리로 흘러가도록 만들어야 한다.
MONAI는 딕셔너리 기반 변환(LoadImaged, Spacingd, NormalizeIntensityd…)을 지원하기 때문에, 같은 파이프라인 안에서 이미지와 텍스트를 동시에 다루기 좋다.
핵심 아이디어
이미지 변환은 MONAI의 transforms로 처리.
텍스트는 “건드리지 않고 옆에 들고 가거나”, 필요하면 간단한 람다/사용자 정의 transform으로 미리 정리.
최종 DataLoader에서 한 배치가 “이미지 텐서 + 텍스트 문자열” 2종을 내보내도록 만들면, MLLM 쪽에서 바로 연결할 수 있다.
데이터 구조 설계: 한 샘플에 무엇을 넣을 것인가
먼저, 파이프라인을 만들기 전에 “한 샘플”의 구조를 명확하게 잡는 게 중요하다.
샘플 딕셔너리 예시
예를 들어, 흉부 X-ray + 판독 보고서라면 한 샘플을 이렇게 정의할 수 있다.
{
"image": 이미지 경로 또는 DICOM/NIfTI 파일 경로,
"report": 텍스트 보고서 문자열,
"id": 스터디 ID,
"label": (필요하다면) 질환 라벨
}
나중에 MLLM 입력으로 갈 때는
image → 비전 인코더
report → LLM target(생성할 문장) 또는 prompt 일부
로 역할이 분리된다.
인덱스 파일(메타데이터) 만들기
CSV 또는 JSONL로 이런 식의 메타를 만들어 두면 편하다.
study_id, image_path, report_path
0001, /data/cxr/0001.dcm, /data/reports/0001.txt
…
나중에 monai.data.Dataset 또는 CacheDataset을 만들 때, 이 메타를 그대로 불러와서 dict 리스트로 변환하면 된다.
MONAI transforms로 이미지 파이프라인 만들기 (MLLM 공통 뼈대)
여기서 말하는 “전처리 파이프라인”은 대략 다음 단계로 생각하면 된다.
로딩 단계
DICOM/NIfTI를 읽어서 메모리에 올리는 단계.
2D(X-ray)면 LoadImaged, 3D(CT/MRI)면 LoadImaged + EnsureChannelFirstd 조합을 기본으로 쓴다.
기하학적 정규화
Spacingd: 픽셀 간 거리 통일 (CT/MRI에서 특히 중요).
Orientationd: 좌/우, A/P, S/I 방향을 통일해서 모델이 혼란을 덜 느끼게 한다.
강도 정규화
ScaleIntensityd, NormalizeIntensityd: 윈도우 레벨/윈도우 너비 기반 정규화 또는 min-max/표준화.
CT의 경우, HU 범위를 잘라서 [-1000, 400] 같은 범위만 남기는 식으로 자주 쓴다.
리사이즈/크롭
ResizeWithPadOrCropd, RandSpatialCropd: 모델이 요구하는 입력 크기로 맞춰준다.
2D: (H, W) → 예: 512x512
3D: (D, H, W) → 예: 128x128x128
텐서 변환
ToTensord 또는 ToDeviced: PyTorch 텐서로 변환, GPU 디바이스에 올릴 준비를 한다.
이 모든 과정이 “image” 키에 대해 작동하도록, d가 붙은 딕셔너리 변환들을 연결하면 된다.
텍스트 파트 전처리: 최대한 “가볍게” 가져가기
MLLM 파이프라인에서는 텍스트 전처리를 두 가지 스타일 중 하나로 많이 처리한다.
텍스트를 “그대로 들고 가기” 방식
MONAI에서는 텍스트를 거의 건드리지 않고, Dataset에서 “report” 필드에 문자열로만 들고 다니고,
배치가 모델로 들어가기 직전에 토크나이저(예: Hugging Face tokenizer)로 변환하는 방식.
장점
MONAI 쪽은 이미지에 집중하고, 텍스트는 MLLM/LLM 쪽 코드에서 일괄 처리할 수 있어 역할 분리가 명확하다.
간단한 텍스트 정리 transform 추가
예를 들어,
너무 긴 보고서는 앞에서 3~5 문장만 남기기,
특수문자 제거,
특정 섹션만 추출(“Impression”만 남기기)
이런 작업을 MONAI transform의 Lambdad 또는 사용자 정의 transform 클래스로 수행 가능하다.
주의할 점
텍스트 길이를 강제로 줄일 때는, 모델이 필요로 하는 핵심 정보를 잃지 않도록 카테고리별 전략을 세우는 것이 좋다.
예: 교육용 MLLM이면 “설명 친절도”를 위해 좀 길게, 보고서 생성 모델이면 “핵심 소견 위주”로 짧게.
MLLM용 “멀티모달” 파이프라인 설계 포인트 5가지
키 이름을 명확하게
image, report, question, label 같은 키를 일관되게 사용하면, 나중에 collate_fn이나 모델에서 구조를 쉽게 다룰 수 있다.
2D·3D 구분
2D(엑스레이/Vision-Language QA)와 3D(CT/MRI/PET)의 입력 형태가 다르므로, transform에서 차원 수와 스페이싱 처리 전략을 분리해서 설계하는 게 좋다.
3D를 2D 슬라이스로 쪼개서 MLLM에 넣는 경우, “어느 슬라이스를 썼는지”를 텍스트에 같이 기록해 두면 디버깅이 편해진다.
학습/검증/테스트 파이프라인 분리
학습용(monai.transforms.Rand*) 변환: 랜덤 크롭, 랜덤 플립, 밝기/대비 변화 등 데이터 증강 포함.
검증/테스트용: 결정적(deterministic) 변환만 사용해 재현성을 확보.
batch 단위 collate 함수
한 배치가 {“image”: Tensor(B,C,H,W), “report”: [문자열 리스트]} 형태가 되도록 collate_fn을 직접 짜 주면, MLLM 측에서 “이미지 임베딩 + 텍스트 토큰 생성”을 한 번에 돌리기 쉽다.
로깅·버전 관리
같은 의료 데이터라도 병원·프로토콜마다 전처리 조건이 다르면 모델이 완전히 다른 데이터를 본 것처럼 느낀다.
따라서 전처리 파이프라인(transform 리스트)을 코드 + 설정 파일(yaml)로 버전 관리하는 것이 나중에 재현성을 담보하는 핵심이다.
실행 순서 정리 (실제 구현용 체크리스트)
데이터 메타 파일(csv/json)로 “이미지 경로 + 텍스트 경로/내용”을 정리한다.
이 메타를 읽어 {“image”: 경로, “report”: 텍스트} 딕셔너리 리스트를 만든다.
MONAI 딕셔너리 transform으로 이미지 전처리 파이프라인을 구성한다 (Load → Spacing → Normalize → Resize → ToTensor).
텍스트는 일단 그대로 두거나, 간단한 람다 transform으로 길이/섹션을 정리한다.
monai.data.Dataset / CacheDataset에 (딕셔너리 리스트, transform)를 넘겨 Dataset을 생성한다.
DataLoader에서 collate_fn을 정의해 “이미지 텐서 + 텍스트 리스트” 구조로 배치가 나오게 만든다.
MLLM/LLM 쪽에서 이 배치를 받아,
이미지 텐서는 비전 인코더로,
텍스트는 토크나이저로,
를 각각 흘려보낸 뒤, 멀티모달 브릿지에서 다시 합친다.
이렇게 만들어두면, 나중에 VILA-M3, M3, LLaVA-Med 같은 다양한 MLLM 구조를 얹어도 데이터 쪽은 그대로 재사용할 수 있다.
요약
MONAI에서 MLLM용 전처리 파이프라인을 짤 때는 “딕셔너리 기반 transform”을 활용해 이미지와 텍스트를 한 샘플로 묶는 것이 핵심이다.
이미지 쪽은 MONAI의 Load/Spacing/Normalize/Resize/ToTensor 파이프라인으로 정규화하고, 텍스트는 필요 최소한만 정리해서 나중에 MLLM 토크나이저에서 처리하는 구조가 가장 안정적이다.
데이터 메타 파일 → 딕셔너리 리스트 → MONAI Dataset/CacheDataset → DataLoader(collate_fn) → MLLM 순으로 흐름을 잡으면, 구조가 깔끔하고 재현성이 높아진다.
댓글
댓글 쓰기