Pill-ID: CLIP와 Milvus를 활용한 약물 안전을 위한 Visual RAG 시스템 구축
Source: Dev.to
위 링크에 있는 전체 글을 번역하고 싶으시면, 번역할 텍스트(본문)를 그대로 복사해서 제공해 주세요.
코드 블록, URL, 마크다운 구문 등은 그대로 유지한 채로 한국어로 번역해 드리겠습니다.
소개
약물 오류는 조용한 위기이지만, Visual Retrieval‑Augmented Generation (Visual RAG)과 멀티모달 AI를 활용하면 실시간으로 약을 “보고” 검증하는 시스템을 구축할 수 있습니다. 이번 튜토리얼에서는 Pill‑ID라는 교차 검증 시스템을 만들 것입니다. 이 시스템은 컴퓨터 비전과 벡터 데이터베이스를 이용해 사진에서 알약을 식별하고 전자 처방전과 대조합니다. 우리는 다음을 활용합니다:
- CLIP – 멀티모달 임베딩
- Milvus – 고속 유사도 검색
- FastAPI – 검증 API 제공
전통적인 RAG가 텍스트에 초점을 맞추는 반면, Visual RAG는 이미지 특징을 사용해 데이터베이스를 질의합니다—특정 알약의 형태, 색상, 질감을 나타내는 벡터를 검색하는 방식입니다.
graph TD
A[User Takes Photo] --> B[OpenCV: Image Preprocessing]
B --> C[CLIP: Generate Image Embedding]
C --> D[Milvus: Vector Similarity Search]
D --> E[Retrieve Metadata: Pill Name, Dosage]
E --> F[FastAPI: Cross‑check with Prescription]
F --> G{Match Found?}
G -- Yes --> H[🚀 Safety Verified]
G -- No --> I[⚠️ Warning: Dosage Mismatch]
기술 스택
- Python 3.9+
- OpenCV – 이미지 조작
- CLIP (OpenAI) – 텍스트와 이미지 사이의 다리
- Milvus – 고성능 벡터 데이터베이스
- FastAPI – 초고속 API 프레임워크
1. Milvus 설정 (시각적 지문)
Milvus는 CLIP이 생성한 512‑차원 벡터를 저장합니다.
# pymilvus setup
from pymilvus import connections, FieldSchema, CollectionSchema, DataType, Collection
# Connect to Milvus
connections.connect("default", host="localhost", port="19530")
# Define schema: primary key, image vector, and metadata
fields = [
FieldSchema(name="pk", dtype=DataType.INT64, is_primary=True, auto_id=True),
FieldSchema(name="pill_vector", dtype=DataType.FLOAT_VECTOR, dim=512),
FieldSchema(name="pill_name", dtype=DataType.VARCHAR, max_length=200),
FieldSchema(name="dosage_mg", dtype=DataType.INT64)
]
schema = CollectionSchema(fields, "Pill identification collection")
pill_collection = Collection("pill_registry", schema)
2. CLIP을 사용한 이미지 임베딩 생성
우리는 CLIP(ViT‑B‑32)을 위한 sentence‑transformers 래퍼를 사용합니다.
import torch
from PIL import Image
from sentence_transformers import SentenceTransformer
# Load the CLIP model
model = SentenceTransformer('clip-ViT-B-32')
def get_image_embedding(image_path):
"""이미지를 512 차원 벡터로 인코딩합니다."""
img = Image.open(image_path)
embedding = model.encode(img)
return embedding.tolist()
3. OpenCV를 사용한 알약 이미지 전처리
원본 사진에는 배경 잡음이 포함되는 경우가 많습니다. 이 함수는 알약을 잘라내고 배경을 제거합니다.
import cv2
import numpy as np
def preprocess_pill_image(image_bytes):
"""Return a cropped image focusing on the pill."""
nparr = np.frombuffer(image_bytes, np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
# Convert to grayscale and apply threshold
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV)
# Find the largest contour (assumed to be the pill)
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
if contours:
c = max(contours, key=cv2.contourArea)
x, y, w, h = cv2.boundingRect(c)
cropped_pill = img[y:y+h, x:x+w]
return cropped_pill
return img
4. FastAPI 검증 엔드포인트
이 엔드포인트는 처방전 이름과 사진을 받아 교차 검증을 수행합니다.
from fastapi import FastAPI, UploadFile, File
app = FastAPI()
@app.post("/verify-medication/")
async def verify_medication(prescribed_name: str, file: UploadFile = File(...)):
# 1. Preprocess and embed the image
image_bytes = await file.read()
processed_img = preprocess_pill_image(image_bytes)
vector = get_image_embedding(processed_img)
# 2. Search Milvus for the closest match
search_params = {"metric_type": "L2", "params": {"nprobe": 10}}
results = pill_collection.search(
data=[vector],
anns_field="pill_vector",
param=search_params,
limit=1,
output_fields=["pill_name"]
)
detected_name = results[0][0].entity.get("pill_name")
# 3. Cross‑check logic
if detected_name.lower() == prescribed_name.lower():
return {"status": "MATCH", "message": f"Verified: {detected_name} identified."}
else:
return {
"status": "WARNING",
"message": f"Possible Mismatch! Found {detected_name} but prescription says {prescribed_name}."
}
프로덕션 고려 사항
Proof‑of‑concept은 간단하지만, 프로덕션 수준의 헬스케어 솔루션은 다음을 필요로 합니다:
- 엄격한 검증 및 신뢰도 점수 매기기
- 새로운 알약 이미지를 지속적으로 수집하기 위한 견고한 데이터 파이프라인
- 보건 데이터 규정 준수 (예: HIPAA)
멀티모달 모델의 더 깊은 아키텍처 패턴 및 클라우드 네이티브 스케일링에 대해 자세히 알아보려면 WellAlly Tech Blog의 기술 심층 분석을 참고하세요.
다음 단계는?
- 블리스터‑팩 감지 지원 추가
- 실제 처방 데이터용 FHIR (Fast Healthcare Interoperability Resources) API와 통합
- 더 빠른 엣지 추론을 위해 ONNX를 사용해 모델 배포
벡터 검색이나 CLIP 구현에 대해 질문이 있으면 아래에 댓글을 남겨 주세요!